feat: replay source evidence with safe review and recovery (TAB-22–29) - #49
Conversation
Plane-Work-Item: TAB-22 Entire-Checkpoint: 95aae876ef91
|
Linked to Plane Work Item(s) References This comment was auto-generated by Plane |
* feat: preserve safe source failure reasons in review packets Plane-Work-Item: TAB-23 Entire-Checkpoint: 95aae876ef91 * feat: exact-candidate packets, security, and review (TAB-24–29) (#51) * fix: enforce complete review packet bounds and candidate acceptance Plane-Work-Item: TAB-25 Validates TAB-24 candidate movement and unrelated-history rejection. Entire-Checkpoint: 7098fc8f9b88 * test: validate review packets with the native schema checker Plane-Work-Item: TAB-25 Entire-Checkpoint: 7098fc8f9b88 * feat: exact security evidence, review, and recovery (TAB-26–29) (#52) * feat: bind separate security checks to immutable review candidates Plane-Work-Item: TAB-26 Entire-Checkpoint: 3a4c8131eec1 * ci: require pinned provenance security scanners Plane-Work-Item: TAB-26 Entire-Checkpoint: 3a4c8131eec1 * feat: exact review results, safe publication, and recovery (TAB-27–29) (#53) * feat: show actionable provenance review and GitHub statuses Plane-Work-Item: TAB-27 Entire-Checkpoint: 3a4c8131eec1 * test: demonstrate failure recovery and secured review (TAB-28/TAB-29) (#54) * test: demonstrate provenance failure and clean-store recovery (TAB-28) Entire-Checkpoint: 3a4c8131eec1 * fix: review the secured lineage in the release demo (TAB-29) (#55) * test: generate unsafe token fixture at runtime (TAB-29) Entire-Checkpoint: 3a4c8131eec1 * fix: demonstrate review of the secured provenance lineage (TAB-29) Entire-Checkpoint: 3a4c8131eec1 --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co>
…48) * feat: normalize candidate-bound provenance source snapshots Plane-Work-Item: TAB-21 Entire-Checkpoint: 95aae876ef91 * fix: select comparison base for manual quality checks Plane-Work-Item: TAB-21 Entire-Checkpoint: 95aae876ef91 * feat: replay source evidence with safe review and recovery (TAB-22–29) (#49) * feat: rebuild provenance from pinned source snapshots Plane-Work-Item: TAB-22 Entire-Checkpoint: 95aae876ef91 * feat: explicit provenance verdicts and safe review (TAB-23–29) (#50) * feat: preserve safe source failure reasons in review packets Plane-Work-Item: TAB-23 Entire-Checkpoint: 95aae876ef91 * feat: exact-candidate packets, security, and review (TAB-24–29) (#51) * fix: enforce complete review packet bounds and candidate acceptance Plane-Work-Item: TAB-25 Validates TAB-24 candidate movement and unrelated-history rejection. Entire-Checkpoint: 7098fc8f9b88 * test: validate review packets with the native schema checker Plane-Work-Item: TAB-25 Entire-Checkpoint: 7098fc8f9b88 * feat: exact security evidence, review, and recovery (TAB-26–29) (#52) * feat: bind separate security checks to immutable review candidates Plane-Work-Item: TAB-26 Entire-Checkpoint: 3a4c8131eec1 * ci: require pinned provenance security scanners Plane-Work-Item: TAB-26 Entire-Checkpoint: 3a4c8131eec1 * feat: exact review results, safe publication, and recovery (TAB-27–29) (#53) * feat: show actionable provenance review and GitHub statuses Plane-Work-Item: TAB-27 Entire-Checkpoint: 3a4c8131eec1 * test: demonstrate failure recovery and secured review (TAB-28/TAB-29) (#54) * test: demonstrate provenance failure and clean-store recovery (TAB-28) Entire-Checkpoint: 3a4c8131eec1 * fix: review the secured lineage in the release demo (TAB-29) (#55) * test: generate unsafe token fixture at runtime (TAB-29) Entire-Checkpoint: 3a4c8131eec1 * fix: demonstrate review of the secured provenance lineage (TAB-29) Entire-Checkpoint: 3a4c8131eec1 --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co> --------- Co-authored-by: hudsonaikins-crown <hudson.aikins@blanoire.co>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 520cb3966e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically 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 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| function dependencyVersions(bytes) { | ||
| const manifest = JSON.parse(bytes.toString("utf8")); | ||
| return ["dependencies", "devDependencies", "optionalDependencies", "peerDependencies"].flatMap((key) => dependencyGroup(manifest, key)); |
There was a problem hiding this comment.
Reject non-object package manifests before passing dependency scan
When a tracked package.json contains valid JSON whose root is a primitive or array (for example, "not-an-object" or []), this function accepts it and each dependency lookup yields an empty group, so the dependency check reports passed; with otherwise-clean scanner outputs, the entire security review is incorrectly marked passed. Validate that the parsed manifest is a non-null, non-array object before inspecting its dependency groups so malformed manifests fail closed.
Useful? React with 👍 / 👎.
| const result = await execute("git", ["ls-tree", "-r", "-z", candidate.headCommit], { cwd: repo }); | ||
| if (result.exitCode !== 0) throw new Error("Candidate tree unavailable."); | ||
| const files = new Map(); | ||
| let totalBytes = 0; | ||
| for (const row of result.stdout.split("\0").filter(Boolean)) { |
There was a problem hiding this comment.
Reject undecodable Git paths before materializing the snapshot
On Linux, Git permits filenames containing invalid UTF-8 bytes, but this ls-tree output is decoded as UTF-8 before paths are parsed. Distinct byte paths such as 0x80.js and 0x81.js both become �.js, so the later blob overwrites the earlier one in the temporary directory and files map; security-sensitive content in the overwritten blob is never scanned, yet all checks can report passed. Read the NUL-delimited tree output as bytes and either preserve path bytes safely or fail closed on invalid encoding and decoded-path collisions.
Useful? React with 👍 / 👎.
| "checks": { | ||
| "type": "array", | ||
| "minItems": 4, | ||
| "maxItems": 4, | ||
| "items": { | ||
| "$ref": "#/$defs/check" | ||
| } |
There was a problem hiding this comment.
Require each security check category exactly once
When a consumer validates receipts solely against this published schema, a checks array containing four secrets entries is accepted even though the authorization, trust, and dependency checks are absent; the runtime importer requires the four categories in a fixed order, so the advertised contract disagrees with the actual security invariant. Constrain the array so each required category appears exactly once, for example with fixed prefixItems or per-category contains constraints.
Useful? React with 👍 / 👎.
| const attempt = await ledger.write(path, receipt, { expectedVersion: prior.version }); | ||
| const completed = { ...receipt, ...await sendStatuses({ repo, intent, base, head, publisher }) }; | ||
| await ledger.write(path, completed, { expectedVersion: attempt.version }); |
There was a problem hiding this comment.
Retry receipt completion after unrelated ledger writes
When two different approvals publish concurrently, both use the same refs/tabellio/provenance-statuses ref: after approval A reserves its path, approval B can reserve another path and advance the ref before A completes. A may then publish both GitHub statuses successfully but this write still uses A's old attempt.version, so it fails with a ledger conflict and leaves A permanently pending; subsequent attempts are blocked as uncertain. Complete the per-approval receipt with a CAS retry that reloads the latest ref and verifies that A's reserved entry is unchanged, or serialize all writers to this ledger.
Useful? React with 👍 / 👎.
TAB-22 through TAB-29: replay reconstructs provenance from source snapshots and real Git using an explicit evaluation time and expected digest. Changed or unavailable evidence returns blocked before persistence; accepted records and original sources remain intact. Git collection failures are isolated from healthy readers. Integrated child PRs add explicit evidence verdicts, bounded packets, separate security, safe review publication, and 11 failure/recovery demo cases.
Candidate
520cb3966e2fd59a9d974d905a7868016c102a10: required local validation, hosted product validation, and hosted Quality passed. Author review found no remaining code findings; the Plane bot reference is informational. PRs #50–55 are merged into this branch.Stacked on #48. Fixture and blocked-result demonstrations satisfy the documented acceptance without claiming complete live-provider provenance. Foundation Buildkite still blocks main integration; release and deployment remain separate decisions.