security: batch 1 — DCI/Key admin privilege escalations, OAuth signing keys, GRM rule ACL (#327, #329, #265, #266) - #399
Open
gonzalesedwin1123 wants to merge 5 commits into
Open
Conversation
Bring the staging branch up to date with 19.0 before the batch lands, so the state that is tested is the state that ships. The 12 upstream commits touch no module in this batch.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## 19.0 #399 +/- ##
==========================================
+ Coverage 70.17% 75.20% +5.03%
==========================================
Files 205 407 +202
Lines 17751 29863 +12112
==========================================
+ Hits 12457 22459 +10002
- Misses 5294 7404 +2110
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
emjay0921
approved these changes
Aug 10, 2026
emjay0921
left a comment
Contributor
There was a problem hiding this comment.
LGTM — four correct, independently-verified security fixes. CI fully green (every module test job) with 100% patch coverage; migrations idempotent; tests genuinely adversarial (transitive-closure guards, migration replay + idempotency, positive/negative ACL paths). Exemplary security work.
Verified against the code:
- #327 DCI —
implied_ids → base.group_systemremoved (that grant escalated every PII-visibility holder to system admin); inverted sospp_security.group_spp_adminimpliesgroup_dci_admin. Group staysnoupdate; the implication sits outside thenoupdateblock so it re-applies on upgrade; migration strips the stale link + comment on existing DBs. - #329 Key mgmt — same escalation removed, admin now implies Key Operator. Confirmed the crux: every key model (
spp.encryption.key,spp.key.purpose,spp.key.provider.registry,spp.asymmetric.key) has its own explicitgroup_key_adminANDbase.group_systemACL rows, so removing the system implication strips nothing from key admins or real system admins. Menu correctly moved out of Settings. - #265 OAuth — removes the row widening
res.config.settingstobase.group_user, and guardsdefault_get()(readsconfig_parameterviasudo()with no ACL check) to strip the signing keys for non-system, non-su callers; honorsenv.su. Textbook fix. - #266 GRM — portal users dropped to read-only on the two rule models (no record rules → ACL was the only boundary; portal submission runs sudo). The
self.sudo().write()onescalation_countis a narrow, correct consequence, documented with nosemgrep.
Surfacing (not blockers):
- #265 operator action (must hit release notes): the deployed OAuth RSA keypair was readable by every internal user — rotate it and invalidate outstanding tokens; no code change fixes that retroactively.
- #265 → #114 ordering hazard:
OAUTH_KEY_FIELDSnames the current field names; when #114 (rename) rebases it must update those entries AND port the ACL test, or the guard silently points at dead names and reopens the leak with green tests. - Merge mechanics: merge commit (not squash); branch auto-deletes, so run
git show --remerge-diff <merge-sha>(andgit diffvs the branch) before it disappears; tag the release by the merge-commit SHA. - Minor —
spp_dcideps:dci_groups.xmlreferencesspp_security.group_spp_adminbut the manifestdependsis only["base","spp_registry"]; it resolves transitively (CI proves install) — recommend declaringspp_securityexplicitly so it can't break ifspp_registryever drops it. - Note:
encrypted_keyfield access widened togroup_key_admin— fine as KMS-wrapped ciphertext with operators still blocked (tested); rests on the assumption no provider stores plaintext there.
Leaving the merge to you given the merge-commit / tag-by-SHA requirements.
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.
Lands security batch 1 — four independent security fixes, validated together on a staging branch so
19.0was never exposed to an unverified intermediate state.What's in it
DCI Administratorno longer grants system administration (privilege escalation)spp_dci19.0.2.0.1 → 2.0.2 + migrationKey Management Adminno longer grants system administration (privilege escalation)spp_key_management19.0.2.0.0 → 2.0.1 + migrationspp_oauth19.0.2.0.0 → 2.0.1spp_grm_cel19.0.2.0.0 → 2.0.133 files. Every fix was individually adversarially reviewed, and #265/#266 were re-reviewed after rebasing because upstream had moved substantially under them.
⚠ Merge with a MERGE COMMIT — not squash
Squashing would collapse four distinct security fixes into one opaque commit. The merge commit preserves one commit per fix (each carrying its
(#NNN)reference) for bisect and attribution.Verification
Each PR was squash-merged into staging pinned with
--match-head-commit <reviewed sha>, so what merged is provably what was reviewed. Manifest:internal/plans/batch1-manifest.tsv.19.0is exactly 33 files, precisely the union of the 4 commits; no ridersci.ymldispatch on the staging head: green on all four module test jobs (run 31352167158)19.0advanced 12 commits after the batch merged;19.0was back-merged into staging (not rebased, which would have destroyed the audit trail above).git show --remerge-diffon the merge is empty — purely mechanical, nothing smuggled in. The drift touched none of the four modules.Upgrade test (
-u) — the gate CI does not provideCI only ever runs
-i(fresh install), so the upgrade path is untested by the pipeline. Run manually, seeded at current19.0(208d9758) → staging (07a0ad3a); exit 0, zero errors. Evidence:internal/plans/batch1-upgrade-test-evidence.md.Baseline confirmed all four vulnerabilities live on current
19.0, then after upgrade:ir_module_module.latest_versionmatches manifestsgroup_dci_admin/group_key_adminimplybase.group_systemspp_oauthwideningir.model.accessrowr,w,cBoth migrations fired with their audit warnings.
🔴 Release notes — required
base.group_systemto whoever administers the DCI server (tokens, sender registries, subscriptions, server keys, settings) — every one of those surfaces is system-gated.base.group_system.Both migrations log warnings, but upgrade-log warnings are easily missed — the notes are the real channel.
Ordering constraint that survives this merge
#265 must land before #114. #114 renames the exact fields #265's
default_getguard pops (oauth_priv_key/oauth_pub_key→oauth_private_key/oauth_public_key). Merging this PR satisfies the ordering, but #114's rebase must rename theOAUTH_KEY_FIELDSentries AND porttests/test_config_settings_acl.py— a naive conflict resolution leaves the guard pointing at dead field names and silently reopens the signing-key leak with green-looking code.After merging
git show --remerge-diff <merge-sha>should be empty, andgit diff <merge-sha> origin/19.0-staging-sec-batch1should be empty — check before the branch auto-deletes (delete_branch_on_mergeis on)19.0with its full fix set recorded on the PRPlan and checklist:
internal/plans/security-staging-merge-plan.md.