Add per-setting consequences page and surface impact/consequences in-app#10
Add per-setting consequences page and surface impact/consequences in-app#10
Conversation
Agent-Logs-Url: https://github.com/Kvikku/Windows-Security-Manager/sessions/dfd0e27d-77e4-4e3b-86ab-732f0e67292d Co-authored-by: Kvikku <85877485+Kvikku@users.noreply.github.com>
Agent-Logs-Url: https://github.com/Kvikku/Windows-Security-Manager/sessions/53ad349d-ae5b-4814-a498-b23924e5661a Co-authored-by: Kvikku <85877485+Kvikku@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Adds a per-setting “impact/consequences” catalog (mirroring new documentation) and surfaces that metadata throughout the CLI and interactive TUI so users can assess compatibility risk before applying settings or profiles.
Changes:
- Introduces
ImpactLevel, plusImpact/ConsequencesonSecuritySetting, and enriches settings from a centralizedSettingConsequencesCatalog. - Updates CLI commands (
list,detail,enable --dry-run,profile) and the interactive menu to display impact labels, consequences, and profile-level summaries. - Adds comprehensive docs page + cross-links, plus unit tests enforcing catalog coverage and “explicit values win” behavior.
Reviewed changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/WindowsSecurityManager.Tests/SettingDefinitionTests.cs | Adds tests to enforce that all built-in settings have impact + consequences metadata and that explicit values aren’t overridden. |
| src/WindowsSecurityManager/UI/InteractiveMenu.cs | Surfaces impact/consequences in list/detail/enable flows and adds profile impact summaries in the TUI. |
| src/WindowsSecurityManager/Commands/ProfileCommand.cs | Adds per-profile impact summaries and prints per-setting impact/consequences during dry-run/apply flows. |
| src/WindowsSecurityManager/Commands/ListCommand.cs | Shows impact and consequences in the CLI list output. |
| src/WindowsSecurityManager/Commands/ImpactFormatter.cs | Adds a shared formatter for impact labels in plain-text CLI output. |
| src/WindowsSecurityManager/Commands/EnableCommand.cs | Shows per-setting impact/consequences and prints an impact summary in dry-run output. |
| src/WindowsSecurityManager/Commands/DetailCommand.cs | Displays impact and consequences in detail output. |
| src/WindowsSecurityManager.Core/Services/SecuritySettingsManager.cs | Enriches settings with catalog-provided impact/consequences at manager construction. |
| src/WindowsSecurityManager.Core/Models/SecuritySetting.cs | Adds Impact and Consequences properties to the runtime setting model. |
| src/WindowsSecurityManager.Core/Models/ImpactLevel.cs | Introduces the ImpactLevel enum used across docs, CLI, and UI. |
| src/WindowsSecurityManager.Core/Definitions/SettingConsequencesCatalog.cs | Adds the centralized ID→(impact, consequences) catalog and enrichment helpers. |
| docs/security-setting-consequences.md | New per-setting consequences reference covering all built-in settings. |
| docs/security-profiles.md | Links to consequences page and adds “Likely side effects” notes per profile. |
| docs/getting-started.md | Adds guidance to review consequences before applying and links the new page. |
| docs/extending-settings.md | Documents new model fields and adds a rule requiring consequences catalog/doc updates for new settings. |
| docs/backup-and-restore.md | Links the new consequences page alongside backup/dry-run guidance. |
| README.md | Adds link to the consequences page in the docs/usage sections. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public static (ImpactLevel Impact, string Consequences) Get(string settingId) | ||
| { | ||
| if (settingId is not null && Entries.TryGetValue(settingId, out var entry)) | ||
| return entry; | ||
| return (ImpactLevel.Unknown, string.Empty); | ||
| } |
There was a problem hiding this comment.
With <Nullable>enable</Nullable>, Get(string settingId) declares settingId as non-nullable but then checks settingId is not null. Consider changing the parameter type to string? (or remove the null check) so the nullability contract matches the implementation and avoids redundant code / possible analyzer warnings.
| /// Unknown / not classified. Treated like Low for display purposes but indicates | ||
| /// the setting has not been categorised yet. |
There was a problem hiding this comment.
The XML doc for ImpactLevel.Unknown says it is "treated like Low for display purposes", but both CLI (ImpactFormatter) and TUI (FormatImpactMarkup) render it as an explicit "Unknown" label. Please align the documentation with the actual behavior, or update the formatters to match the documented behavior so users aren’t misled.
| /// Unknown / not classified. Treated like Low for display purposes but indicates | |
| /// the setting has not been categorised yet. | |
| /// Unknown / not classified. Displayed as <c>Unknown</c> and indicates the | |
| /// setting has not been categorised yet. |
| public static readonly IReadOnlyDictionary<string, (ImpactLevel Impact, string Consequences)> Entries = | ||
| new Dictionary<string, (ImpactLevel, string)>(StringComparer.OrdinalIgnoreCase) | ||
| { |
There was a problem hiding this comment.
SettingConsequencesCatalog.Entries is exposed as an IReadOnlyDictionary, but it is backed by a mutable Dictionary instance. External callers can cast it back to Dictionary<,> and mutate the catalog at runtime. Consider returning a ReadOnlyDictionary/ImmutableDictionary (or keeping the backing dictionary private and exposing only lookup APIs) to prevent accidental modification.
| if (setting.Impact != ImpactLevel.Unknown && !string.IsNullOrEmpty(setting.Consequences)) | ||
| continue; | ||
|
|
||
| var (impact, consequences) = Get(setting.Id); | ||
| if (setting.Impact == ImpactLevel.Unknown) | ||
| setting.Impact = impact; | ||
| if (string.IsNullOrEmpty(setting.Consequences)) |
There was a problem hiding this comment.
SettingConsequencesCatalog.Enrich treats only null/empty consequences as missing. If a provider accidentally sets Consequences to whitespace, enrichment won’t fill it from the catalog and the UI will show a blank note. Consider using string.IsNullOrWhiteSpace consistently for Consequences checks (and optionally skip null settings entries) to make enrichment more robust.
| if (setting.Impact != ImpactLevel.Unknown && !string.IsNullOrEmpty(setting.Consequences)) | |
| continue; | |
| var (impact, consequences) = Get(setting.Id); | |
| if (setting.Impact == ImpactLevel.Unknown) | |
| setting.Impact = impact; | |
| if (string.IsNullOrEmpty(setting.Consequences)) | |
| if (setting is null) | |
| continue; | |
| if (setting.Impact != ImpactLevel.Unknown && !string.IsNullOrWhiteSpace(setting.Consequences)) | |
| continue; | |
| var (impact, consequences) = Get(setting.Id); | |
| if (setting.Impact == ImpactLevel.Unknown) | |
| setting.Impact = impact; | |
| if (string.IsNullOrWhiteSpace(setting.Consequences)) |
| foreach (var change in changes) | ||
| { | ||
| string current = change.IsCurrentlyConfigured ? change.CurrentValue?.ToString() ?? "N/A" : "NOT SET"; | ||
| Console.WriteLine($" [{change.Setting.Id}] {change.Setting.Name}"); | ||
| Console.WriteLine($" [{change.Setting.Id}] {change.Setting.Name} ({ImpactFormatter.Format(change.Setting.Impact)})"); | ||
| Console.WriteLine($" {change.Setting.RegistryHive}\\{change.Setting.RegistryPath}\\{change.Setting.ValueName}"); | ||
| Console.WriteLine($" Current: {current} → New: {change.NewValue}"); | ||
| if (!string.IsNullOrWhiteSpace(change.Setting.Consequences)) | ||
| Console.WriteLine($" ⚠ {change.Setting.Consequences}"); | ||
| Console.WriteLine(); | ||
| } | ||
| Console.WriteLine($"Total: {changes.Count} settings would be changed."); | ||
| PrintImpactSummary(changes.Select(c => c.Setting)); | ||
| } |
There was a problem hiding this comment.
The new impact/consequences output in --dry-run isn’t covered by the existing command tests (they currently only assert IDs and totals). Consider adding/updating tests to assert that an impact label and (when present) a consequences line are printed, so regressions in this user-facing guidance are caught.
| if (high > 0 || medium > 0) | ||
| { | ||
| Console.WriteLine($"Impact: 🔴 {high} High | 🟡 {medium} Medium settings were enabled."); |
There was a problem hiding this comment.
Minor formatting/wording issue: Impact: 🔴 {high} High | 🟡 {medium} Medium settings were enabled. is inconsistent with the other impact summaries (missing a | separator and the Low count, and the "Medium settings" phrasing reads oddly). Consider using the same High | Medium | Low summary format here for consistency.
| if (high > 0 || medium > 0) | |
| { | |
| Console.WriteLine($"Impact: 🔴 {high} High | 🟡 {medium} Medium settings were enabled."); | |
| int low = settings.Count(s => s.Impact == ImpactLevel.Low); | |
| if (high > 0 || medium > 0) | |
| { | |
| Console.WriteLine($"Impact: 🔴 {high} High | 🟡 {medium} Medium | 🟢 {low} Low settings were enabled."); |
|
@copilot apply changes based on the comments in this thread |
…hiteSpace, profile summary, doc fix, dry-run test Agent-Logs-Url: https://github.com/Kvikku/Windows-Security-Manager/sessions/3d89f77d-f8f8-452d-85a7-277509e669cc Co-authored-by: Kvikku <85877485+Kvikku@users.noreply.github.com>
Applied all 6 review comments in 6442f75:
|
|
@copilot can you check the build fail and fix it? |
…yDictionary Agent-Logs-Url: https://github.com/Kvikku/Windows-Security-Manager/sessions/2a55a07d-0f57-457e-b765-3cbacd171e98 Co-authored-by: Kvikku <85877485+Kvikku@users.noreply.github.com>
CI failure was |
Users had no way to judge the compatibility risk of an individual setting or profile before applying it — neither in docs nor in the running tool.
Docs
docs/security-setting-consequences.md: every one of the 98 built-in settings tabulated by category with a consistent 🟢 Low / 🟡 Medium / 🔴 High impact label and a short "Potential Consequences" note.README.md,docs/getting-started.md,docs/security-profiles.md, anddocs/backup-and-restore.mdlink the new page near their dry-run / backup guidance.docs/security-profiles.mdgains a "Likely side effects" line per profile; the Maximum Security entry enumerates the specific 🔴 High-impact settings it pulls in.docs/extending-settings.mdadds a maintenance rule: every new setting must ship with a catalog entry (or explicitImpact/Consequences) in the same PR, enforced by a unit test.Runtime model
ImpactLevelenum andImpact/Consequencesproperties onSecuritySetting(plain settable, defaultUnknown/"").SettingConsequencesCatalogkeyed by setting ID, mirroring the docs page.SecuritySettingsManagerenriches every setting from the catalog at construction; explicit values on aSecuritySettingare preserved.CLI surfacing
listanddetailshow impact label and consequences per setting.enable --dry-runshows per-change consequences plus a 🔴/🟡/🟢 summary and a review-before-applying warning.profile --listshows a per-profile impact summary, e.g.Maximum Security … Impact: 🔴 5 High | 🟡 44 Medium | 🟢 49 Low.profile --apply [--dry-run]shows per-change consequences and prints a rollback hint when Medium/High settings were enabled.Interactive menu surfacing
Tests
SettingConsequencesCatalog_CoversEveryBuiltInSettingguards against missing entries for any built-in setting.SettingConsequencesCatalog_DoesNotOverrideExplicitImpactguards the "explicit wins" rule.Example CLI output: