verify: verify.sh skips a timestamp entry with a non-string token that Package Verification rejects#1725

opened23d agobyBbirdbrain-agent

Defect: the two package verifiers disagree on a timestamp entry whose token is not text.

What: When a timestamp entry in an evidence package carries a token that is present but is not text, the shell verification script skips the entry and reports that the capture has no trusted-time claim, while the in-app package verification rejects the whole chain. A reader running only the script sees a clean pass with a missing timestamp where the app sees a broken package. Only someone holding the signing key, or a bug in the package writer, can produce such an entry.

It was kept out of the change that found it because that change was a restructuring that had to leave the script byte-identical, and the behaviour was already there before it.

Where it is and how to reproduce it

Where: src/main/services/verifyProcedure.ts:80 Reproduce: Traced from source during the review of PR #1723, not executed. Build a package, replace one content timestamp entry's tsaToken with a number or object and re-sign the chain, then run verify.sh and Package Verification on it.

  • signedTokenFilter selects only entries where (.tsaToken | type) == "string", so the script and the runbook step 6b command drop the entry and report no trusted-time claim.
  • ManifestEntrySchema requires tsaToken: z.string().optional() (src/shared/schemas.ts:557), so Package Verification fails the chain.
  • tests/main/services/verifyScriptTokenFilter.test.ts pins the filter; no conformance row in tests/helpers/verifyConformance.ts covers a non-string token.
Synced from GitHub

Maintainer ruling, 2026-10-04: the shell verification script must fail a package whose timestamp entry carries a token that is present but is not text, the same way the in-app package verification does. The two verifiers must not disagree on such a package. The maintainer also called this evidence-affecting.

Acceptance criteria, verification and starting files

Acceptance criteria

  1. verify.sh exits non-zero and names the malformed entry when a manifest entry of type timestamp has a tsaToken that is present and not a string. It no longer treats that entry as "no trusted-time claim".
  2. The command VERIFY.md prints for step 6b behaves the same way, or says that the script performs this check.
  3. A content timestamp entry with no tsaToken at all keeps today's behaviour.
  4. tests/helpers/verifyConformance.ts gains a row for the non-string token, naming the verdict each verifier must report, and both verifiers agree on it.
  5. The PR states that verify.sh and VERIFY.md bytes change for newly exported packages and that packages already exported keep theirs.

Verification path

pnpm preflight, and BIRDBRAIN_REQUIRE_OPENSSL=1 pnpm test tests/main/services/verifyRunbookExecution.test.ts tests/main/services/verifyScriptTokenFilter.test.ts.

Starting files

src/main/services/verifyProcedure.ts (signedTokenFilter, :80), src/main/services/verifyScript.ts (:664 and the trusted-time block after it), src/main/services/verifyRunbook.ts (:349), src/shared/schemas.ts (:557), tests/helpers/verifyConformance.ts, tests/main/services/verifyScriptTokenFilter.test.ts.

Evidence-affecting: yes, by the maintainer's call on 2026-10-04.

Synced from GitHub

Closed as not planned by the stale-agent-issues workflow: filed by the machine account and untouched for 14 days (ADR-0028).

Reopen it and apply queued to put it on the dispatch list.

Note

Written by claude-opus-5-5 via Claude Code on behalf of Matt.

Reopening. The automatic stale-issue cleanup closed this without a fix, and a check of the current code on 23 October found the defect still present. It is on the new delivery roadmap's defect list; it is not queued for an agent yet.

Where the roadmap lists it

docs/plans/2026-10-23-delivery-roadmap.md, Defect lane items 1 and 2 (PR #1959). The cleanup's rule change that exempts evidence and security issues is PR #1957.