security: externalize policy bundle authority input - #21
Merged
Merged
Conversation
stacknil
marked this pull request as ready for review
September 16, 2026 10:38
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.
Problem The v1 controller compiled the expected policy-bundle digest into controller source. Protecting that controller in a v2 bundle would create a digest cycle:
text controller bytes -> protected manifest -> bundle digest -> controller constantThis PR introduces only the non-self-referential policy-input protocol and v2 compatibility plumbing. Production authority remains inactive. ## Invariant - The controller fixes selectorv2, epochrepo-sentinel-authority-v2, and relative rootpolicy/repo-sentinel-authority/v2. - The only externally supplied policy identity is an exact 64-character lowercase hexadecimal digest. - The same validated digest flows unchanged through worker construction, bundle verification, worker-result validation, and the controller envelope. - Callers cannot choose a policy path, schema, mirror root, mandatory-control set, scanner identity, or selector-to-epoch mapping. -AUTHORITY_RESULTis semantic evaluation evidence, not authenticated publication authorization. ## Design decision An immutablePolicyBundleContractregistry defines exactly two supported contracts: historicalv1and candidate-compatiblev2. The v2 contract keeps bundle schema 1,portable-v1,commit-authoritative-v1, and the pinnedrepo-sentinel-lite 0.8.1artifact while changing only epoch, mirror root, mandatory controls, and controller protocol. The worker resolves a reviewed selector and derives mirror, protected-control, and coverage behavior from the verified contract. No final v2 bundle or digest is created here. ## Threat / failure model The implementation fails closed on malformed or unknown selectors, arbitrary selector/path composites, v1/v2 cross-wiring, wrong or modified bundle bytes, missing mandatory controls, unreviewed workflow/action members, wrong mirror roots, and worker result digest/epoch disagreement. The controller does not authenticate whether the supplied digest is authorized for production publication. A future dedicated signer must bind it through an immutable signer registry and server-side evaluation admission record before publishing a Commit Status. ## Rejected alternatives 1. Hardcode the v2 digest in controller source. Rejected because it recreates the protected-source self-reference cycle. 2. Accept arbitrary epoch/root pairs. Rejected because policy selection would become caller-controlled path selection. 3. Discover a latest policy directory. Rejected because filesystem ordering would become an authority decision. 4. Ignore allpolicy/**content. Rejected because it would hide historical or unexpected policy artifacts from coverage. 5. Put workflow, OIDC, ticket, or expiry fields inP_v(H). Rejected because those are operational authorization evidence, not commit-intrinsic policy. ## Compatibility -policy/repo-sentinel-authority/v1/**is byte-identical to trusted main. - The v1 bundle independently reproduces6f25ebb773ce1453e8de623bca5aaecc936f1f188288f8df20aedeadb3bf4612. - The v1 CLI default and public compatibility aliases remain intact. - Acquisition, reader, materializer, scanner semantics, report schemas, workflows, bootstrap, and branch/rules configuration are unchanged. - Nopolicy/repo-sentinel-authority/v2/**directory exists in this PR. ## Validation Focused suites under WSL CPython 3.12.3:text policy contracts: 7 passed controller: 21 passed worker + provenance: 42 passed acquisition: 13 passed reader + materializer: 39 passed full repository: 178 run, 3 skipped, 0 failedAdditional validation:text Ruff check: passed Ruff format --check: passed pre-commit configured hooks: passed Markdown/frontmatter: 157 files passed taxonomy render: current README snapshot: current pattern library: 8 stable / 13 total passed synthetic scanner PASS: passed synthetic scanner FAIL: passed scanner redaction: passed scanner import isolation: passed git diff --check: passed required mutation campaign: 10 / 10 killedThe existing changed-file Repo Sentinel gate reports 55 high-entropy findings in the seven changed files. Manual review classifies all 55 as false positives: policy paths, schema field names, deterministic test placeholders, and long test identifiers. No credential, token, key, or private identifier was found. The base baseline uses location-sensitive fingerprints, so line movement reopens these historical identifiers. This PR does not change.reposentinel.toml, the root baseline, or the protected v1 policy bundle merely to suppress that known gate limitation; independent Business B review remains required. The registry lifecycle review finding is closed by the normative design record. Future signer requirement: evaluations freeze the exact immutable registry revision at admission; later registry changes may reject but never reinterpret an issued evaluation. This PR does not implement or test that future signer service. ## Rollback Before authority activation, rollback is a normal revert of this PR. There is no signer, GitHub App, production workflow, status, branch-rule change, final v2 bundle, or production v2 digest to coordinate. After any future activation, rollback must be a new externally reviewed signer registry revision rather than silent fallback or directory discovery.