feat: bind security evidence to exact review and recovery (TAB-26–29) - #52
Conversation
Plane-Work-Item: TAB-26 Entire-Checkpoint: 3a4c8131eec1
Plane-Work-Item: TAB-26 Entire-Checkpoint: 3a4c8131eec1
|
Linked to Plane Work Item(s) References
This comment was auto-generated by Plane |
#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>
* 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>
* 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>
#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>
…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: 04341aebbd
ℹ️ 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 execute(command, args, { cwd, signal, binary = false } = {}) { | ||
| return new Promise((resolvePromise, reject) => { | ||
| execFile(command, args, { | ||
| cwd, signal, encoding: binary ? "buffer" : "utf8", timeout: 240000, maxBuffer: 4 * 1024 * 1024, |
There was a problem hiding this comment.
Allow blobs up to the declared scan bound
When a tracked regular file is larger than 4 MiB, git cat-file blob exceeds this shared maxBuffer and rejects with ERR_CHILD_PROCESS_STDIO_MAXBUFFER before snapshot can apply its declared 32 MiB aggregate limit. Consequently, an otherwise valid candidate containing a 4–32 MiB asset cannot produce a security receipt, and the newly required CI security validator blocks even though the candidate remains within the scanner's explicit size bound.
Useful? React with 👍 / 👎.
| } | ||
|
|
||
| function dependencyGroup(manifest, key) { | ||
| const dependencies = manifest[key] ?? {}; |
There was a problem hiding this comment.
When a manifest explicitly contains a malformed group such as "dependencies": null, the nullish fallback converts it to an empty object, so no declaration is recorded and scanDependencies reports passed if the other groups are absent. This contradicts the fail-closed handling of malformed dependency manifests and can produce successful dependency evidence for an invalid package manifest; only a genuinely absent property should receive the empty-object default.
Useful? React with 👍 / 👎.
| "minItems": 4, | ||
| "maxItems": 4, | ||
| "items": { | ||
| "$ref": "#/$defs/check" |
There was a problem hiding this comment.
Require every security category in the receipt schema
When a receipt is validated only against this published schema, the four entries may all use the same category because the array is constrained only by length. Such a schema-valid receipt can claim passed while omitting authorization, trust, and dependency checks entirely, despite the contract requiring four separate checks; encode each required category exactly once rather than accepting any four check objects.
Useful? React with 👍 / 👎.
| const target = join(directory, path); | ||
| await mkdir(dirname(target), { recursive: true }); | ||
| await writeFile(target, blob.stdout, { mode: 0o600 }); |
There was a problem hiding this comment.
Detect filesystem-colliding candidate paths
On a case-insensitive filesystem such as the default macOS setup supported by the installer, a Git tree containing distinct paths such as AUTH.js and auth.js writes both blobs to the same temporary file. The later write silently replaces the earlier content while both paths remain in the digest map, so a secret or unsafe construct in the overwritten blob is never scanned and the candidate can receive a false passing result; reject colliding paths or scan without materializing them onto a case-folding filesystem.
Useful? React with 👍 / 👎.
| "path": { | ||
| "$ref": "#/$defs/text" | ||
| }, |
There was a problem hiding this comment.
Constrain finding paths in the public schema
When downstream tooling uses the published JSON schema as its validation boundary, paths such as ../secret, /absolute/path, or backslash-based traversal are accepted because path references only the generic text definition. The runtime producer explicitly rejects these values, so the schema currently accepts receipts that runtime import rejects and permits external consumers to treat out-of-candidate locations as valid findings; give finding paths the same safe-relative-path constraints as finding().
Useful? React with 👍 / 👎.
| function securityDetails(lineage, receipt, policyDigest, now, repo) { | ||
| if (receipt === null) return { detailsState: "not_loaded", findings: [], checks: [] }; |
There was a problem hiding this comment.
Require a verified receipt before reporting security success
When a lineage reaches review or review-intent through the generic import path with an arbitrary tabellio security observation marked passed, this branch leaves the receipt unloaded while the security section and GitHub status still derive a green result from that observation. Because generic lineage integrity is only a recomputable hash, this bypasses attachSecurityReview entirely and allows publication of a successful security context without any of the four receipt checks; a missing verified receipt must keep security blocked or the store must retain proof that the observation was created by receipt verification.
Useful? React with 👍 / 👎.
| const packet = buildReviewPacket(lineage, { candidate, now }); | ||
| const binding = { candidateId: packet.candidate.id, packetDigest: packet.digest, policyDigest }; | ||
| const results = await Promise.all(SECURITY_CHECKS.map(async (category) => { |
There was a problem hiding this comment.
Reject review packets containing future evidence
When an input lineage contains a validation timestamp later than the security review time, buildReviewPacket correctly records that fact as stale, but runSecurityReview ignores the packet reasons and can still issue a passed receipt. After wall-clock time advances beyond the validation timestamp, attaching that receipt produces a lineage that evaluates as fully passed even though the security receipt claims to have consumed evidence that did not yet exist; reject packet reasons other than the expected missing-security reason, or explicitly enforce that the review follows its linked validation.
Useful? React with 👍 / 👎.
| if [[ -n "${TABELLIO_SECURITY_TOOLS_DIR:-}" ]]; then | ||
| security_tools_root="$TABELLIO_SECURITY_TOOLS_DIR" | ||
| else | ||
| security_tools_root="$(mktemp -d "${TMPDIR:-/tmp}/tabellio-security-tools.XXXXXX")" |
There was a problem hiding this comment.
Normalize the configured tools directory to an absolute path
When TABELLIO_SECURITY_TOOLS_DIR is configured as a relative reusable directory, the installer succeeds in the repository and exports relative PATH and TABELLIO_GITLEAKS entries, but scanner subprocesses later run with the temporary scan root as their working directory. Those relative executable paths then resolve under the temporary directory and every scan becomes unavailable, so documented cache configurations such as .cache/security-tools make the required validator block; canonicalize this directory to an absolute path before exporting it.
Useful? React with 👍 / 👎.
TAB-26 through TAB-29: provenance receives separate bounded secrets, authorization, trust, and dependency checks. Receipts bind the exact candidate, safe packet, and policy; missing/malformed/timed-out checks block, and findings exclude raw matches. Pinned scanner installation and required security checks run in CI. The integrated CLI/GitHub review keeps review and security distinct, protects publication with scoped approval and a durable reservation, and demonstrates 11 failure/recovery cases with clean-store replay. Final demo review uses its secured lineage. PRs #53–55 are merged into this branch.
Candidate
04341aebbdbb6b65afbc3cbd1385afce09414608: required local validation, hosted product validation, and hosted Quality passed. Author review found no remaining code findings; the Plane bot reference is informational.Scope is intentionally bounded: Gitleaks 8.30.1, ast-grep 0.45.1, listed JavaScript/TypeScript rules, and declared npm dependencies that block pending separate vulnerability evidence. This is not proof of absence of all security defects. Provider fixtures and the historical blocked live demonstration satisfy the stated TAB-21/TAB-27 acceptance; they do not claim complete live-provider provenance.
Stacked on #51. Foundation Buildkite still blocks main integration. Release and deployment remain separate decisions.