Repository navigation
Bind PR head, merge-preview tree, input diff, and check attribution in evidence #222
Description
Why this is a release-relevant issue
Discovered by first-user audit, 15 October 2026. On pull_request, GitHub documents github.sha/GITHUB_SHA as the synthetic PR merge commit (refs/pull/N/merge); github.event.pull_request.head.sha is the contributor's actual PR head. See official GitHub Actions pull_request semantics.
The current action.yml (checked at main) correctly notices the two identifiers in its change-input step: OVK_EVENT_HEAD_SHA: ${{ github.event.pull_request.head.sha }} and OVK_GITHUB_SHA: ${{ github.sha }}. It constructs the default diff via git diff BASE_SHA HEAD_SHA. Later, however, five steps (Run OVK multi-lane verification, Run OVK check path, Emit OVK GitHub check (check/verify) and further downstream emission) pass OVK_HEAD_SHA: ${{ github.sha }}, giving the synthetic merge SHA as the evidence subject/check target.
This is a potential semantic/attestation binding ambiguity, not yet a demonstrated exploit. The default actions/checkout also checks out the merge commit, so github.sha can faithfully identify the checked-out merge tree; however, the extracted input diff is generated from the PR head and base. A transferable report cannot silently equate the merge tree, PR-head tree, diff target and reviewer-visible check identity. Base drift and conflicts can make the discrepancy material. Fixing one string without fixing the model can worsen the trust boundary.
Proposed contract and acceptance
- Define an explicit
SubjectIdentitycarrying PR base SHA, PR head SHA, evaluated checkout/tree SHA, comparison mode (HEAD/basevsMERGE/base), checker input-diff digest, source-profile digests and toolchain identity. - Choose/document a single coherent evaluation mode for the first supported product lane: either (A) check PR head and base with checkout matching head, or (B) check a merge-preview tree with an explicit merge-preview subject and explicitly related head. Do not conflate them in evidence.
- Record/validate both the actual checked-out tree and the diff source revision. Fail closed if event metadata, checkout and evidence subject conflict or if fetch/merge history does not support the intended comparison. Preserve bounded handling for fork PRs and untrusted PR code.
- Keep PR-check presentation anchored to a suitable GitHub head SHA for reviewers, while the evidence truthfully states exactly what tree was checked. If GitHub API requires separate check attribution, represent check presentation target separately from verified source subject and do not compromise freshness checks.
- Test a PR where
headandmergediffer; simulate base branch moving after the PR head, missing/nonfetchable SHA, fork PR, and replaying evidence for another base/head pair. Regression must reject false reuse and stale subject binding. - Do not switch to
pull_request_targetplus untrusted PR checkout. Minimize token write permissions and follow GitHub's documented fork-PR security boundaries. Do not execute PR-supplied scripts with elevated privileges. - No public shareable 'verified PR' receipt until the above source-identity semantics and provenance are qualified. Advisory reports can continue with explicit scope/unknown and no production reliance.
Priority: before expanding PR evidence distribution or GitHub App. This is more important for the North Star than another abstract dependency theorem: shareable evidence must be about the source revision actually evaluated. Related: #216, #221, #25, release-hardening draft #220, guarantee report draft #218.
Not an authorization to merge or release: this issue establishes a precise engineering investigation/acceptance gate only.
Activity
fraware commentedon Oct 15, 2026
P0 implementation checkpoint — 15 Oct 2026: Draft PR #223 now proposes a concrete, fail-closed identity contract for the Action's default PR input: require checkout commit == GitHub event
github.sha, require its raw two merge-parent SHAs == eventbase.shaandpull_request.head.sha, require the base commit object, then computegit diff BASE MERGEto match the evidence subject. Produce a JSON sidecar with checkout/tree, diff SHA-256, exact comparison, caller-bound/unbound marker and explicit no signed-envelope binding / no relying authority. Refusepull_request_target, SHA mismatch and strict caller-selected diffs. Automated GitHub Check / PR-comment publication is additionally suppressed for advisory caller-supplied unbound diffs.Real CI dogfood run 38818371087 successfully executed a genuine synthetic GitHub merge-preview comparison, printing
event_base_to_verified_merge_preview. The same first run's full unit job failed against an existing release-governance test that indiscriminately demanded PR-head checkout for all jobs. PR #223 now narrowly keeps the recorded PR head for source-validation/release jobs while allowing exactly the two Action-dogfood jobs to check out the merge preview with depth 2; a regression test preserves the distinction. This is a policy correction, not a waiver of release-head integrity.Exact head:
9d0cfd95ba1f8d002e20d564765a67efe632e6ca. CI 38819081731 and six-cell repro 38819081712 are queued, not accepted.Issue #222 remains open until the typed source identities and diff digest are bound into independently authenticated machine evidence; reviewer-visible GitHub check target is explicitly modeled separately; relevant fork/private shallow-checkout cases and real-source/profile semantics are qualified. This PR is a bounded correctness foundation, not a complete attested source-verification release. Keep draft and reconcile its
action.ymloverlap with separate release PR #220 under review, not by an untested merge.fraware commentedon Oct 16, 2026
Live dogfood-confirmed source/evidence mismatch — 2026-10-15; draft correction #227
Real GitHub Actions run 38830701134,
action_default_diff_dogfood, failed withOVK refusing unsupported job summary: evidence subject disagrees with the observed checkout. I downloaded artifactovk-evidence-artifacts-action_default_diff_dogfood(artifact id12017765340) and inspected both JSON files.ovk-source-binding.json:evaluated_checkout_commit_sha=6c706febb13c32b75ae9cd6ab13a2023b3daa961(synthetic merge preview),event_pr_head_sha=90f0a4492056149fd57c84502d2ebea80d2d8231;evidence_subject_sha=6c706febb13c32b75ae9cd6ab13a2023b3daa961; source diff hash6d4e37f5cb607cd5fbb8c13330c8176b9f7d8cf0068ba8f61096fa5ea71bb04b.ovk-evidence.jsonbundle subject.head_sha:90f0a4492056149fd57c84502d2ebea80d2d8231(contributor PR head), not the receipt's checked-out merge SHA.ovk.core.context.build_repository_contextoverwrites a caller-suppliedhead_shawith GitHub eventpull_request.head.sha. The Action passesgithub.shaonovk check, but that argument is overridden after source binding. Earlier CI and source-binding tests checked the receipt and source diff, not the resulting evidence bundle's subject.This invalidates the earlier narrative that the default Action always produces matching merge-bound evidence. There is no signed/relying guarantee; do not publicly display this evidence as merge-preview verified. The read-only renderer failed closed and a direct attempted Check emission from mismatched source may also be refused, depending on its emission target.
Draft #227 now includes:
ovk check --source-bindingstructural validation of current HEAD/tree, PR event base/head/repository, exact diff bytes, and requested merge subject.Status: draft candidate; CI not yet certified on final head; no main merge, release or external adoption.
fraware commentedon Oct 16, 2026
First independently inspected real-PR correction observation (development only)
At intermediate draft #227 commit
b7020afa50db8d6b25d52d7f1c697d2424f01cbd, the liveaction_default_diff_dogfoodjob in CI run 38839898034 completed SUCCESS after the CLI subject-selection correction. The job used the ordinary GitHub pull-request synthetic merge-preview checkout.I downloaded the actual GitHub artifact
ovk-evidence-artifacts-action_default_diff_dogfood(artifact id12021550038) and separately compared:evaluated_checkout_commit_sha=9af58527fa069420392cbb99aaa34b63199acfe8;evidence_subject_sha=9af58527fa069420392cbb99aaa34b63199acfe8;ovk-evidence.jsonsubject.head_sha=9af58527fa069420392cbb99aaa34b63199acfe8;event_pr_head_sha=b7020afa50db8d6b25d52d7f1c697d2424f01cbd(correctly distinct);79370539ca9b26a0a6b01f6ac6ab6923243f40f4.Result: one real workflow has established that the corrected local observed receipt and final evidence subject match. The earlier failed artifact and the corrected passing artifact are both retained as a before/after causal regression record, not a proof of GitHub event authenticity or source-to-IR completeness.
Important: this run is at an intermediate SHA; final draft #227 head has additional adversarial tests and documentation, and final-head CI, six-cell reproducibility, native-backend workflows, and independent review remain open. No main merge/release/strict authority.