feat(settings): let an MDM profile set a minimum safe mode level - #2214
Merged
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Signed-off-by: Ngô Quốc Đạt <datlechin@gmail.com>
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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
The first piece of managed configuration: an administrator can set a minimum Safe Mode level through a macOS configuration profile, and the user cannot drop below it.
The mechanism is smaller than it sounds, on purpose
macOS already merges a configuration profile's values into
UserDefaultsat the highest priority, so a forced key simply wins with no special read path. The only thing the ordinary API cannot answer is whether a key was forced, andCFPreferences.hsays exactly what that is for:So this adds a flat key namespace and a reader, not a policy engine, an override chain, or a second settings store.
ManagedPolicyReader.isManagedexists to disable a control, not to fetch a value.Why a separate flat key rather than forcing an existing setting
The app's settings are stored as encoded structs under keys like
com.TablePro.settings.mcp. Forcing one of those would mean an administrator had to reproduce the entire struct in their profile, and it would break the first time a field was added. Policy keys are one primitive per decision:com.TablePro.policy.minimumSafeModeLevelcom.TablePro.policy.mcpServerDisabledcom.TablePro.policy.aiAssistantDisabledcom.TablePro.policy.pluginInstallDisabledOnly the first is enforced in this PR. The other three are declared because they are the same shape and the enum is the place a reviewer should see the intended set, but nothing reads them yet, so treat them as reserved rather than shipped.
Two behaviours worth reviewing
The policy is a floor, never a ceiling. A connection set stricter than the policy keeps its own level. Someone who put a production connection on Read-Only still gets Read-Only when the policy only asks for Alert.
ManagedPolicyResolverTestschecks every ordered pair of the six levels in both directions, so no pair can silently collapse to a tie.An unrecognised value imposes no floor at all. Not Read-Only, which would lock people out over a typo in a profile, and not Silent, which would drop the policy without saying so.
It is enforced at
ExecutionGateProvider'ssafeModeLevelResolver, which is the single place the gate learns a connection's level, so every caller including the AI assistant and the MCP tools goes through it.Scope
Safe Mode is a floor on TablePro's behaviour, not on the database. It stops the app issuing a write; it does not stop the same person connecting with
psql. The docs say so and point at the existing "Server Read-Only Is Not Safe Mode" section rather than implying more than it does.No UI change yet. A managed control should render as managed rather than merely preset, and
isManagedexists for exactly that, but Settings does not consume it in this PR.Verification
buildPASStestManagedPolicyResolverTests, ManagedPolicyReaderTests: 10 executed, 10 passedlint TablePro0 violationsTests use an isolated
UserDefaultssuite per case, so they need no profile installed and leave no state behind.