Skip to content

Give private_branches one matcher for adjudication and export - #20

Merged
kridaydave merged 1 commit into
mainfrom
k5/pass-oot-one-branch-policy
Oct 7, 2026
Merged

kridaydave merged 1 commit into
mainfrom
k5/pass-oot-one-branch-policy

Conversation

@kridaydave

Copy link
Copy Markdown
Contributor

private_branches had two independent matchers. Export filtering (VisibilityPolicy::branch_is_private) required whole-segment equality. Adjudication (VisibilityPolicy::check) additionally matched the bare substring, and it trimmed the pattern where export did not. One policy file, two opposite answers for the same branch.

Reproduced on the pre-fix binary with private_branches = ["audit"] and branch feature/audit-fixes:

oot adjudicate ... --visibility vis.toml
  dispute-02: private branch audit referenced by t (branch:audit)    [visibility]
  verdict:    ▶ CLOAKED . cloaked
exit 1

oot export --out exported --visibility vis.toml
branch feature/audit-fixes -> 5766a7766bba751fc4a9b1c55a754365abbdca25
exit 0

The change was cloaked and the branch was published anyway. That fails open, on the governance spine.

The fix extracts branch_matches(candidate, pattern) and points both callers at it, so the dispute still names the pattern that fired and the two paths cannot drift again. Post-fix, the same commands give branch feature/audit-fixes omitted (private branch) and exit 1 on the adjudicate. The wildcard form private/* and the clean no-match case were both checked against a locally built binary and still behave as before.

Diff stat

 src/visibility.rs               | 41 ++++++++++++++----------
 tests/export_visibility_test.rs | 69 +++++++++++++++++++++++++++++++++++++
 2 files changed, 94 insertions(+), 16 deletions(-)

test_cloaked_branch_is_not_published_by_export drives both sides of the same policy file through the real binary: it asserts adjudication still cloaks (so the test cannot pass by a matcher that stopped matching) and that the ref is absent from the export.

Not shipped

  • src/store.rs:1691 and :2425 compare against EXPORT_LOG while iterating .oot/export/. The log lives at .oot/export-log.jsonl, one directory up, so both guards can never match. Safe today, misleading tomorrow. Separate PR.
  • src/visibility.rs path_is_private matches .pem only against a file literally named .pem, not server.pem. This repo's own visibility.toml lists .pem and gets nothing. Fixing it changes what existing policies withhold, which is an owner decision, not an audit one.
  • Patterns with two or more * never match, because matches_pattern splits on the first one only. VisibilityPolicy::load validates embargo_until but not patterns, so a typo yields a policy that silently never fires.
  • src/policy.rs:83,95 (requires_review, review_count) have no callers outside #[cfg(test)]. The docket uses Docket::review_count, which hardcodes Review and High, so review_on in a policy file does not affect the rendered verdict note.

@kridaydave
kridaydave merged commit ce33c22 into main Oct 7, 2026
5 checks passed
@kridaydave
kridaydave deleted the k5/pass-oot-one-branch-policy branch October 7, 2026 04:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant