-
Notifications
You must be signed in to change notification settings - Fork 809
Add system-wide policy configuration for centralized update control #3313
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 19 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
702f681
Initial plan
Copilot a8853bc
Add system-wide config feature to disable update checks
Copilot 83dc909
Add documentation for system-wide config feature
Copilot 7dc158c
Fix documentation formatting in config README
Copilot 36e595c
Rename ConfigManager to PolicyManager to avoid naming conflict
Copilot 506e6bf
Add config.json.example to installation and UI for policy-managed set…
Copilot 1b12a86
Add localization string for policy-managed setting message
Copilot 9ed5c23
Improve accessibility with icon and add documentation to config example
Copilot 509ede8
Chore: Move config file to settings namespace
BornToBeRoot 247c4c5
Rename policy property to Update_CheckForUpdatesAtStartup and allow e…
Copilot 5180ca0
Chore: Minor color adjustments
BornToBeRoot 388c828
Merge branch 'main' into copilot/disable-update-check-all-users
BornToBeRoot 84434ef
Use direct pattern for policy check and remove helper property
Copilot a83ee1d
Add Docusaurus documentation for system-wide policies and remove old …
Copilot 65134b0
Fix changelog PR number placeholder
Copilot dbe56fe
Update system-wide-policies.md
BornToBeRoot 3100ee9
Move policy property details to settings/update.md to avoid duplication
Copilot c5840c6
Feature: System wide policy
BornToBeRoot f02c7be
Fix Docusaurus build error with react-image-gallery CSS import
Copilot bafdcf3
Update browserslist database to latest version
Copilot 6bd67c0
Add null-safety checks for PolicyManager deserialization
Copilot c08bb42
Fix react-image-gallery CSS import path for v2.0+
Copilot 02b2ee7
Fix React version mismatch - update react-dom to 19.2.4
Copilot 7967560
Update yarn.lock for react-dom version change
Copilot 81feeb8
Load PolicyManager in SettingsManager.Initialize() to fix reset setti…
Copilot ceb5a64
Move PolicyManager.Load() to App.xaml.cs to avoid duplicate calls
Copilot 8d40a49
Chore: Refactoring & dotnet format
BornToBeRoot 5664c46
Update MainWindow.xaml.cs
BornToBeRoot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
9 changes: 9 additions & 0 deletions
9
Source/NETworkManager.Localization/Resources/Strings.Designer.cs
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace NETworkManager.Settings; | ||
|
|
||
| /// <summary> | ||
| /// Class that represents system-wide policies that override user settings. | ||
| /// This configuration is loaded from a config.json file in the application directory. | ||
| /// </summary> | ||
| public class PolicyInfo | ||
| { | ||
| [JsonPropertyName("Update_CheckForUpdatesAtStartup")] | ||
| public bool? Update_CheckForUpdatesAtStartup { get; set; } | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| using log4net; | ||
| using System; | ||
| using System.IO; | ||
| using System.Text.Json; | ||
| using System.Text.Json.Serialization; | ||
|
|
||
| namespace NETworkManager.Settings; | ||
|
|
||
| /// <summary> | ||
| /// Manager for system-wide policies that are loaded from a config.json file | ||
| /// in the application directory. These policies override user settings. | ||
| /// </summary> | ||
| public static class PolicyManager | ||
| { | ||
| #region Variables | ||
|
|
||
| /// <summary> | ||
| /// Logger for logging. | ||
| /// </summary> | ||
| private static readonly ILog Log = LogManager.GetLogger(typeof(PolicyManager)); | ||
|
|
||
| /// <summary> | ||
| /// Config file name. | ||
| /// </summary> | ||
| private static string ConfigFileName => "config.json"; | ||
|
|
||
| /// <summary> | ||
| /// System-wide policies that are currently loaded. | ||
| /// </summary> | ||
| public static PolicyInfo Current { get; private set; } | ||
|
|
||
| /// <summary> | ||
| /// JSON serializer options for consistent serialization/deserialization. | ||
| /// </summary> | ||
| private static readonly JsonSerializerOptions JsonOptions = new() | ||
| { | ||
| WriteIndented = true, | ||
| PropertyNameCaseInsensitive = true, | ||
| DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, | ||
| Converters = { new JsonStringEnumConverter() } | ||
| }; | ||
|
|
||
| #endregion | ||
|
|
||
| #region Methods | ||
|
|
||
| /// <summary> | ||
| /// Method to get the config file path in the application directory. | ||
| /// </summary> | ||
| /// <returns>Config file path.</returns> | ||
| private static string GetConfigFilePath() | ||
| { | ||
| return Path.Combine(AssemblyManager.Current.Location, ConfigFileName); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Method to load the system-wide policies from config.json file in the application directory. | ||
| /// </summary> | ||
| public static void Load() | ||
| { | ||
| var filePath = GetConfigFilePath(); | ||
|
|
||
| // Check if config file exists | ||
| if (File.Exists(filePath)) | ||
| { | ||
| try | ||
| { | ||
| Log.Info($"Loading system-wide policies from: {filePath}"); | ||
|
|
||
| var jsonString = File.ReadAllText(filePath); | ||
| Current = JsonSerializer.Deserialize<PolicyInfo>(jsonString, JsonOptions); | ||
|
|
||
| Log.Info("System-wide policies loaded successfully."); | ||
|
|
||
| // Log enabled settings | ||
| Log.Info($"System-wide policy - Update_CheckForUpdatesAtStartup: {Current.Update_CheckForUpdatesAtStartup?.ToString() ?? "Not set"}"); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Log.Error($"Failed to load system-wide policies from: {filePath}", ex); | ||
| Current = new PolicyInfo(); | ||
| } | ||
| } | ||
| else | ||
| { | ||
| Log.Debug($"No system-wide policy file found at: {filePath}"); | ||
| Current = new PolicyInfo(); | ||
| } | ||
| } | ||
|
|
||
| #endregion | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| { | ||
| "Update_CheckForUpdatesAtStartup": false | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| --- | ||
| sidebar_position: 6 | ||
| --- | ||
|
|
||
| # System-Wide Policies | ||
|
|
||
| System-wide policies allow administrators to enforce specific settings for all users on a machine. These policies override user-specific settings and provide centralized control over application behavior in enterprise environments. | ||
|
|
||
| ## Overview | ||
|
|
||
| Policies are defined in a `config.json` file placed in the application installation directory (the same folder as `NETworkManager.exe`). When this file exists, the application loads the policies at startup and applies them with precedence over user settings. | ||
|
|
||
| Users will see a visual indicator in the Settings UI when a setting is controlled by a system-wide policy, showing them the administrator-enforced value and preventing them from changing it. | ||
|
|
||
|  | ||
|
|
||
| ## Configuration File | ||
|
|
||
| The `config.json` file uses a simple JSON structure to define policy values. An example file (`config.json.example`) is included in the application installation directory for reference. | ||
|
|
||
| **File Location:** | ||
| - **Installed version**: `C:\Program Files\NETworkManager\config.json` (or your custom installation path) | ||
| - **Portable version**: Same directory as `NETworkManager.exe` | ||
|
|
||
| **File Format:** | ||
|
|
||
| ```json | ||
| { | ||
| "Policy_Name1": true, | ||
| "Policy_Name2": "ExampleValue" | ||
| } | ||
| ``` | ||
|
|
||
|
|
||
| **Example:** | ||
|
|
||
| ```json | ||
| { | ||
| "Update_CheckForUpdatesAtStartup": false | ||
| } | ||
| ``` | ||
|
|
||
| Property names generally follow the pattern `Section_SettingName` (see each setting's documentation). Ensure values use the correct JSON type (boolean, string, number, etc.). | ||
|
|
||
| :::note | ||
|
|
||
| - The file must be named exactly `config.json` | ||
| - The file must contain valid JSON syntax | ||
| - Changes to the file require restarting the application to take effect | ||
| - If the file doesn't exist or contains invalid JSON, it will be ignored and user settings will apply | ||
|
|
||
| ::: | ||
|
|
||
| ## Deployment | ||
|
|
||
| For enterprise deployments: | ||
|
|
||
| 1. **Create the configuration file**: | ||
| - Use the `config.json.example` as a template | ||
| - Rename it to `config.json` | ||
| - Set your desired policy values (you find them in the corresponding setting's documentation) | ||
|
BornToBeRoot marked this conversation as resolved.
|
||
|
|
||
| 2. **Deploy to installation directory**: | ||
| - Place the `config.json` file in the same directory as `NETworkManager.exe` | ||
| - For MSI installations, this is typically `C:\Program Files\NETworkManager\` | ||
| - For portable installations, place it next to the executable | ||
|
|
||
| 3. **Deploy methods**: | ||
| - Group Policy — copy the `config.json` file to the installation directory (use Group Policy preferences or a startup script) | ||
| - Configuration management tools — SCCM/ConfigMgr, Microsoft Intune, Ansible, etc. | ||
| - Scripts and deployment toolkits — PowerShell scripts, PSAppDeployToolkit (recommended for scripted MSI/App deployments) | ||
| - Manual deployment — hand-copy for small-scale rollouts | ||
|
|
||
| 4. **Verification**: | ||
| - Launch the application | ||
| - Navigate to Settings > Update (e.g., "Check for updates at startup") | ||
| - Verify the shield icon and the administrator message appear and that the control is disabled | ||
| - Confirm the displayed value matches the policy | ||
|
|
||
| :::warning | ||
|
|
||
| Ensure the `config.json` file has appropriate permissions so that regular users cannot modify it. On standard installations in `Program Files`, this is automatically enforced by Windows file permissions. | ||
|
|
||
| ::: | ||
|
|
||
| ## Troubleshooting | ||
|
|
||
| **Policy not being applied:** | ||
| - Verify the file is named exactly `config.json` (not `config.json.txt`) | ||
| - Check that the JSON syntax is valid (use a JSON validator) | ||
| - Confirm the file is in the correct directory (same as `NETworkManager.exe`) | ||
| - Restart the application after creating or modifying the file | ||
| - Check the application logs for any error messages related to policy loading | ||
|
|
||
| **Policy values not showing in UI:** | ||
| - Ensure the property name matches exactly (see the corresponding setting's documentation for the property name) | ||
| - Verify the value is a boolean (`true` or `false`), not a string (`"true"` or `"false"`) | ||
| - Check that there are no syntax errors in the JSON file | ||
|
|
||
| ## Future Policies | ||
|
|
||
| Additional policy options will be added in future releases to provide more granular control over application behavior. If you have specific requirements for system-wide policies in your organization, please submit a feature request via the [GitHub issue tracker](https://github.com/BornToBeRoot/NETworkManager/issues/new/choose). | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JsonSerializer.Deserialize<PolicyInfo>(...)can returnnull(e.g., empty file or JSON literalnull). In that caseCurrentbecomes null and the subsequent access toCurrent.Update_CheckForUpdatesAtStartup(and any later callers) will throw aNullReferenceExceptionduring startup. Consider coalescing the result to a newPolicyInfo(and/or validating the JSON string) before logging/usingCurrentso an empty/invalid policy file is treated as "no policies" rather than crashing.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@copilot implement this if necessary and check for possible side effects due to this change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implemented in commit 6bd67c0.
Added null-safety checks to prevent
NullReferenceException:?? new PolicyInfo()) to handle cases where deserializer returns nullSide effects analysis:
PolicyManager.Currentalready safely handles null with?.operatorThe change is defensive programming that makes the policy loading more robust without affecting existing functionality.