Repository navigation
fix(policy): keep an explicitly saved default as an enforceable system rule - #9039
Open
maia-andre wants to merge 3 commits into
Open
maia-andre wants to merge 3 commits into
maia-andre wants to merge 3 commits into
Conversation
…m rule An administrator could not enforce the built-in default of a policy. Saving the default with allowChildOverride = false deleted the system rule, and reading an explicit default always returned an overridable layer, so a group or user rule still changed the effective value. - PolicySource::saveSystemPolicy() stores every explicit value with its override flag, including a value equal to the default. - PolicySource::loadSystemPolicy() applies the stored flag to an explicit default. A default stored without a flag predates explicit defaults, when the API could not enforce one, so it stays overridable. - PolicyService::saveSystem() treats null as "no explicit system rule" and clears it, for single and compound writes. Policy Workbench already removes a rule this way, so it needs no change. The API documentation of both system write endpoints now states the difference between null and an explicit default. Resolves: LibreSign#8916 Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
Part of LibreSign#8916 Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
Saving a value equal to the default now keeps it as an explicit system rule, so the admin initial state scenarios and the validation access end-to-end test can no longer use the default value to clear the rule. They send null, which is how the workbench removes a system rule. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: André Maia <andrefnkmm@gmail.com>
This branch has not been deployed
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.
Resolves: #8916
📝 Summary
An administrator could not enforce the built-in default of a policy. Saving it with
allowChildOverride = falsewas lost on both sides:PolicySource::saveSystemPolicy()deleted the system rule when the value equaled the default and the override was disabled.PolicySource::loadSystemPolicy()returned an overridable layer for an explicit default, whatever its flag. A group or user rule still changed the effective value.What changes:
saveSystemPolicy()stores every explicit value with its override flag, including a value equal to the default. The special case that deleted the rule, including its JSON comparison, is gone.loadSystemPolicy()applies the stored flag to an explicit default. A default stored without a flag predates explicit defaults, when the API could not enforce one, so it stays overridable (as agreed in the issue).PolicyService::saveSystem():nullnow means "no explicit system rule" and clears it (clearSystem()), instead of being turned into the default and saved.nulland an explicit default differ there too. The composite validation already treatednullas the default, which is what the effective value becomes.value: null, so the frontend needs no change. Saving the default with "do not allow overrides" now just works.nullas removing the explicit rule. Before, they said it reset the value to its default.Direct reads and bulk loading share
loadSystemPolicy()(resolveMany()goes throughresolveCore()), so they stay consistent. Rule counts already come from the stored key, so an enforced default is counted (existingtestLoadAllRuleCountsCountsExplicitSystemRuleEvenWhenValueMatchesDefault).I also checked the internal callers of
saveSystem():AEngineHandler(enginenone) saves a value different from the default, which was already an enforced rule.SignatureTextService::save()has no production caller.Composition (2 commits): the fix is 70 lines of production code and 209 lines of tests. The regenerated OpenAPI/TypeScript commit is 16 lines, descriptions only.
🧪 How to test
POST /ocs/v2.php/apps/libresign/api/v1/policies/system/show_confetti_after_signingwithvalue = true,allowChildOverride = false(the default value, enforced).PUT …/policies/user/signer1/show_confetti_after_signingwithvalue = false.signer1,GET …/policies/effective:show_confetti_after_signingistruefromglobal. Onmainit isfalsefromuser_policy.POST …/policies/system/show_confetti_after_signingwithvalue = null, then the sameGETassigner1: nowfalsefromuser_policy.This is the new scenario in
features/policies/boolean_policy_layers.feature. It fails onmainat step 3.Validation evidence
PolicySourceTestresolves the issue's matrix throughDefaultPolicyResolver, against a conflicting group layer and a conflicting user layer, checking the effective value. The matrix covers no rule, an explicit default enforced or overridable, an explicit value enforced or overridable, and a legacy default without flag.PolicyServiceTest:nullclears and an explicit default saves, also in a compound write that mixes both.composer cs:checkis clean, and psalm adds no issue.features/policies/boolean_policy_layers.feature(4 scenarios) pass.⚙️ API / Back-end changes
nullremoves the explicit system rule (single and compound writes).composer openapiwhen necessary✅ Checklist
🤖 AI (if applicable)