Skip to content

Harden pre-merge evidence sessions - #1557

Open
Chris0Jeky wants to merge 9 commits into
mainfrom
issue-1547/evidence-successor
Open

Harden pre-merge evidence sessions#1557
Chris0Jeky wants to merge 9 commits into
mainfrom
issue-1547/evidence-successor

Conversation

@Chris0Jeky

@Chris0Jeky Chris0Jeky commented Aug 1, 2026

Copy link
Copy Markdown
Owner

Disposition

PARKED — not owner-ready. Exact-head CI and the local canaries are green, but four confirmed HIGH false-evidence paths remain intentionally unresolved under the two-round review ceiling:

  1. the state file is authenticated only on entry and then reread during collection, allowing a background rewrite to split the authenticated local head from the packet's later opening/closing identity;
  2. assume-unchanged or skip-worktree can conceal modified tracked bytes from the clean-worktree checks;
  3. Git replacement refs can redirect opening-base object reads and make changed Gitleaks definitions appear equal;
  4. passing the session token in process argv exposes it to a same-user background process left by PR-controlled checks.

Do not merge this head. A future successor must consume one immutable authenticated snapshot throughout finish, reject hidden index/replacement-ref state, and receive the token through protected stdin or a non-inherited descriptor.

Summary

  • replace the parked Make pre-merge evidence atomic #1555 implementation without modifying its branch or discussion
  • persist the evidence-session identity, PR selection, and state in a checkout-derived single-use path that survives genuinely separate shell processes
  • bind the complete canonical opening record to an operator-carried 256-bit session token; persist only its hash and token-bound digest so PR-controlled work cannot rewrite opening evidence undetected at session entry
  • print the validated token for retention in coordinator/operator context and pass it into later finish/abort processes without environment or checkout/Git-dir token files
  • require exact opening-base blob equality for the enforcing CI caller, its selected reusable Gitleaks workflow, .gitleaks.toml, and .gitleaksignore before emitting CLEAN
  • exercise missing, consumed, substituted, tampered, and cross-checkout state plus actual same-name/no-op caller and reusable-workflow replacements
  • require the matching token for finish or explicit checkout-bound abort before an expired, interrupted, or tampered evidence session can restart

Verification

  • Git Bash syntax checks for both collector scripts
  • scripts/github/test-collect-pre-merge-evidence.sh: 19/19 canaries passed at the final head
  • Red-before probe failed on replayed foundation afca675f; the repaired final harness passed
  • Direct pre-finish tamper canary rewrites repository, timestamp, base name/OID, and mergeability while preserving the state filename/path; finish rejects it and authenticated abort permits a clean restart
  • Static continuity canary forbids process-local token capture and requires explicit VALIDATED_SESSION_TOKEN finish/abort invocations
  • git diff --check origin/main...HEAD
  • DCO trailers: 9/9 commits
  • TOML parse
  • node scripts/check-docs-governance.mjs
  • node scripts/check-golden-principles.mjs
  • node scripts/check-github-ops-governance.mjs
  • Product backend/frontend/Playwright suites are not applicable; no product seam changed

Documentation

  • docs/STATUS.md — not required; this head is unmerged and parked
  • docs/IMPLEMENTATION_MASTERPLAN.md — not required; roadmap priorities are unchanged
  • docs/TESTING_GUIDE.md documents the changed evidence-gate verification flow

Tracking

Closes #1547

Related context: #1555, #1532, #1543, #1544.

CI Workflow Validation

  • Exact-head hosted rollup — 26 successes / 11 intentional skips / 0 pending / 0 failed; clean merge state
  • Merge eligibility — blocked by the four unresolved HIGH review threads above

Risk Notes

  • Security impact: the implemented token and scan-definition bindings close the original false-clean paths but remain bypassable through the four parked paths above.
  • Behavior/regression risk: decoy state files can also deadlock authenticated abort; this fails closed and was classified MEDIUM.
  • Follow-up tasks: reaction capture, harness-trigger wording, cross-platform jq, BSD mktemp, contributor wording, optional GraphQL shape hardening, and review-checklist consolidation remain deliberately out of scope.

Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>
Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>
Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>
Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>
Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>
Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>

@Chris0Jeky Chris0Jeky left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fresh-context adversarial review completed at 8f0a70c39310c87b12db062d13f664f88ce65fd8. I found no confirmed CRITICAL or HIGH correctness, security, or data-loss defect. The checkout-derived single-use state binds the exact PR/head/base across separate processes, and CLEAN now requires opening-base blob equality for the CI caller, selected reusable Gitleaks workflow, .gitleaks.toml, and .gitleaksignore. The direct canaries cover missing/consumed/substituted/cross-checkout state and independent same-name no-op replacements. Hosted CI remains a separate merge gate; this review does not recommend or perform a merge.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8f0a70c393

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread .claude/skills/pre-merge-gate/SKILL.md Outdated
Comment thread scripts/github/collect-pre-merge-evidence.sh Outdated
Comment thread docs/TESTING_GUIDE.md
@Chris0Jeky Chris0Jeky moved this from Pending to Review in Taskdeck Execution Aug 1, 2026
Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 2f2cc25367

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/github/collect-pre-merge-evidence.sh

@Chris0Jeky Chris0Jeky left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused fresh-context re-review completed for the review-fix delta at 2f2cc253675606f409cf7b8ab066e1cb29bd9bbf. Both confirmed HIGH defects are closed: diff inspection no longer relies on process-local pr_number, and an expired session can restart only after an explicit abort validates the checkout-bound state. Missing, ambiguous, substituted, and cross-checkout states still fail closed; finish still re-proves exact identities, feedback, checks, scan provenance, and definition equality before CLEAN. No new CRITICAL/HIGH defect was found. LOW only: abort does not fully revalidate every opening-snapshot field before discarding a path-matching local state; that cannot escape the evidence directory or emit false-clean evidence and does not reopen the bounded pipeline. Hosted exact-head CI remains separate; no merge is performed.

Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e87a7472a

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

--json number,headRefName,headRefOid,baseRefName,baseRefOid,mergeable,updatedAt,url \
>"$temp_dir/closing.json" || die "cannot resolve the closing PR identity"
validate_pr_snapshot "$temp_dir/closing.json"
"$jq_executable" '.opening' "$state_file" >"$temp_dir/opening.json"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Reauthenticate state immediately before closing

Fresh evidence after the earlier state-binding fix: finish authenticates the file only when entering load_opening_state, then rereads .opening here without authenticating that exact snapshot. If PR-controlled checks leave a background process running, it can wait until collection begins and rewrite the state with a newly pushed head and timestamp; the closing comparison then uses the modified values, while assert_clean_exact_checkout still uses the old opening_head local, allowing a COMPLETE packet for head B even though local checks ran at head A. Parse one immutable snapshot, authenticate that snapshot, and use it exclusively through comparison, emission, and consumption.

AGENTS.md reference: AGENTS.md:L93-L96

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed HIGH at final head. The token-bound digest is checked only on entry; later reads of the mutable state file can diverge from the authenticated locals. A PR-controlled background process can therefore create a head/timestamp split and let the packet describe a different PR head from the locally tested checkout. This arrived after the permitted focused reopen, so the two-round ceiling binds: #1557 is parked, not owner-ready, and this blocker remains intentionally unresolved.

Comment thread docs/tooling/CODEX_AUTONOMY_RUNBOOK.md
Comment on lines +177 to +179
worktree_status="$("$git_executable" status --porcelain=v1 --untracked-files=all)" ||
die "cannot inspect worktree status"
[[ -z "$worktree_status" ]] || die "exact-head evidence requires a clean worktree"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject hidden index flags before exact-head checks

When any tracked file is marked assume-unchanged or skip-worktree, git status --porcelain can remain empty even after that file's worktree bytes diverge from HEAD. A contributor with a locally hidden config file—or an untrusted check that sets the flag before modifying a later check's inputs—can therefore pass both calls to this function while the reported local tests did not run against the asserted exact head. Reject these index flags or compare the actual tracked worktree contents to the index before accepting the checkout as clean.

AGENTS.md reference: AGENTS.md:L93-L96

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed HIGH despite the P2 badge. assume-unchanged/skip-worktree can hide tracked-byte divergence from both clean-worktree checks, giving a direct path to report local exact-head tests that actually ran against modified bytes. This is a false-evidence path in the changed gate. The two-round ceiling now requires parking rather than another fix cascade, so this blocker remains intentionally unresolved.

Signed-off-by: Chris0Jeky <jeky.tck@gmail.com>

@Chris0Jeky Chris0Jeky left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Focused final-head adversarial review of 5ebf330: no remaining CRITICAL/HIGH finding. The full canonical opening record is authenticated by an operator-carried random token whose value is not persisted; state substitution cannot forge the token-bound digest, and finish validates it before consuming any opening identity. Token-authenticated abort remains fail-closed and restartable. The final operational instructions also keep the token visible across genuinely separate tool shells and forbid process-local/environment/checkout persistence; the 19th static canary directly enforces that continuity. Exact-head hosted CI remains the final owner-ready gate.

@Chris0Jeky Chris0Jeky left a comment

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correction to my earlier final-head review after the late connector threads were fetched: #1557 is PARKED, not owner-ready. Two confirmed HIGH false-evidence paths remain at this exact head: finish authenticates mutable state only once and later rereads it, permitting a background identity rewrite during collection; and hidden index flags can conceal tracked-byte divergence from both clean-worktree checks. Exact-head CI and the 19 local canaries are green, but they do not exercise those races. The review ceiling binds, so no further fix cascade is authorized in this PR; both blocker threads remain unresolved.

@Chris0Jeky Chris0Jeky moved this from Review to Blocked in Taskdeck Execution Aug 1, 2026

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ebf330e1f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/github/collect-pre-merge-evidence.sh
Comment on lines +452 to +454
base_blob="$("$git_executable" rev-parse "$opening_base:$path")" || return 1
head_blob="$("$git_executable" rev-parse "HEAD:$path")" || return 1
if [[ "$head_blob" != "$base_blob" ]]; then

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Disable replacement refs for definition binding

A PR-controlled check can run git replace <opening-base> <head> after local validation; replacement refs live only under the Git directory, so the checkout remains clean, but these ordinary object reads resolve every base path through the replacement and make changed Gitleaks workflows/configuration appear byte-identical to HEAD. A weakened scan can therefore pass hosted CI and still produce definitionsVerified: true and secrets.verdict: CLEAN; perform the exact-object reads with Git's documented --no-replace-objects option or reject replacement refs.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed HIGH. Git replacement refs live outside the clean-worktree surface and can redirect the opening-base object reads so changed scan definitions appear equal, directly restoring a false CLEAN secrets verdict. #1557 is already parked at the review ceiling; this blocker remains intentionally unresolved.

```bash
gh pr checks $ARGUMENTS
if ! evidence_packet="$(
bash scripts/github/collect-pre-merge-evidence.sh finish VALIDATED_SESSION_TOKEN

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Pass the session token outside process arguments

Fresh evidence beyond the existing post-load state race is that this command exposes the authentication token in the finish process's argv. A same-user background process left by PR-controlled checks can read /proc/<pid>/cmdline while finish starts, recover the token, and recompute a valid binding for rewritten state; this defeats the token boundary even if the later state reread is made immutable. Supply the token through protected stdin or a non-inherited file descriptor rather than a command-line argument.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed HIGH under the PR-controlled-background-process threat model already established by the state race. Passing the token in argv exposes it through same-user process inspection and permits forging a new valid state binding. #1557 remains parked; this blocker is intentionally unresolved.

Comment thread scripts/github/collect-pre-merge-evidence.sh
Comment thread docs/TESTING_GUIDE.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Blocked

Development

Successfully merging this pull request may close these issues.

[Gate] Make pre-merge evidence atomic across argument, feedback, and OID changes

1 participant