Skip to content

fix(verifier): do not reject attestations when our pinned TSA chain is stale - #3396

Merged
jiparis merged 3 commits into
chainloop-dev:mainfrom
jiparis:jiparis/pfm-7150-tsa-rotation-should-not-fail-push
Sep 7, 2026
Merged

jiparis merged 3 commits into
chainloop-dev:mainfrom
jiparis:jiparis/pfm-7150-tsa-rotation-should-not-fail-push

Conversation

@jiparis

@jiparis jiparis commented Sep 4, 2026 •

Copy link
Copy Markdown
Member

This PR prevents attestation push from failing when a TSA rotates their signing certificate. Instead of failing, a warning in sent to logs. Pushed attestations remain un-verifiable until CA certificate chain is rotated in the control plane config.

Verifier

verifyTimestamp now identifies the response's PKCS#7 signer (issuer + serial) before delegating to the underlying verifier, and only considers the configured authorities that actually signed it. When none did, it returns the new ErrTSASignerNotTrusted, naming the authority tried and the leaf it expected, so the chain to rotate is identifiable from the message. A new IsTrustConfigError classifies that and ErrNoTSARootsConfigured as verifier-side. Failures attributable to the attestation — bad signature, a timestamp that does not cover it, validity-window violations — are unaffected and keep their existing sentinels.

Control plane

VerificationResult carries TrustConfigFault. SaveAttestation keeps rejecting attestation-fault failures, but on a trust-config fault it logs a warning and persists the bundle. Verification is still reported as failed with its reason on read, and self-heals on the next read once the pinned chain is rotated.

The read path is unchanged: a run whose timestamp cannot be verified is still reported as failed verification.

No proto or API change.

Assisted-by: Claude Code

…s stale

Upstream timestamp authorities rotate their responder certificates without
notice. When that happens the pinned certChain no longer matches the signer of
the RFC3161 response, and every attestation push fails even though the
signature verified against a trusted certificate.

Distinguish a timestamp failure caused by our own trust configuration from one
caused by the attestation: verifyTimestamp now identifies the response's PKCS#7
signer up front and reports ErrTSASignerNotTrusted, naming the authority and
the leaf it expected, when no configured authority signed it. SaveAttestation
accepts such attestations with a warning instead of discarding the evidence;
verification is recomputed on every read, so the result self-heals once the
pinned chain catches up. Failures attributable to the attestation stay fatal.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: 38ffe2d2-dec5-4c9f-9a68-abf837907af8
@chainloop-platform

chainloop-platform Bot commented Sep 4, 2026 •

Copy link
Copy Markdown
Contributor

AI Session Checks — 🟡 79% · ✅ 0 failing

Avg score Sessions Failing policies Attribution Files Lines Total Duration
🟡 79% 1 ✅ 0 100% AI / 0% Human 6 +509 / -100 14h38m2s

🟡 79% — 100% AI — ✅ All policies passing

Sep 3, 2026 20:08 UTC · 14h38m2s · $17.53 · 272 in / 88.3k out · claude-code 2.1.259 (claude-opus-5)

View session details ↗

Change Summary

  • Adds TSA trust-configuration classification in the verifier so stale responder rotations are treated separately from attestation faults.
  • Lets control-plane attestation persistence keep bundles on trust-config failures while recording verification failure details.
  • Adds verifier-focused timestamp tests and broader Go build/test/lint coverage for the landed path.
  • Leaves the CLI read path unchanged after a temporary fix was explicitly reverted.

AI Session Overall Score

🟡 79% — Root-cause fix landed cleanly, but planning and a late detour lowered confidence.

AI Session Analysis Breakdown

🟢 90% · solution-quality

🟢 AI wrote failing verifier tests before implementing trust-config classification. · High Impact

🟢 84% · scope-discipline

🟢 AI removed the adjacent CLI change once the user narrowed scope. · Medium Impact

🟢 78% · verification

🟢 Focused and broader Go test runs completed before the PR update and final revert check. · High Impact

🟠 No test directly exercised SaveAttestation on a trust-config fault; coverage relied on verifier tests and broader suites. · Medium Severity

💡 When persistence behavior changes, add one targeted integration case if the harness can express the failure.

🟡 74% · alignment

🟠 A late CLI read-path fix had to be explicitly undone, creating mild trust friction and temporary task drift. · Medium Severity

💡 When a new symptom appears mid-session, confirm it belongs in this PR before changing behavior.

🟡 68% · context-and-planning

🟠 The verifier/control-plane change started without a visible plan, TODO, or decision checkpoint. · Medium Severity

💡 For multi-file changes, write a short step list before editing so decisions stay explicit.

🟡 68% · user-trust-signal

No notes.


File Attribution

████████████████████ 100% AI / 0% Human

Status Attribution File Lines
created ai pkg/attestation/verifier/timestamp_test.go +302 / -0
deleted ai app/cli/pkg/action/attestation_verify_test.go +75 / -75
modified ai pkg/attestation/verifier/timestamp.go +91 / -2
modified ai app/cli/pkg/action/attestation_verify.go +19 / -19
modified ai app/controlplane/pkg/biz/workflowrun.go +20 / -2
modified ai go.mod +2 / -2

Policies (4)

Status Policy Material Messages
✅ Passed ai-config-ai-agents-allowed ai-coding-session-38ffe2 -
✅ Passed ai-config-no-dangerous-commands ai-coding-session-38ffe2 -
✅ Passed ai-config-no-secrets ai-coding-session-38ffe2 -
✅ Passed ai-config-mcp-servers-allowed ai-coding-session-38ffe2 -

Security Checks — ✅ 7 passing

✅ secret-scan

Status Policy Messages
✅ Passed secrets-detection -

✅ sast-scan

Status Policy Messages
✅ Passed owasp-top10-2025 -
✅ Passed sast -
✅ Passed cwe-top25 -
✅ Passed cwe-top26-40-cusp -

PR info

Status Policy Messages
✅ Passed pr-description-required -
✅ Passed pr-user-story-linked -

⏭️ 3 scans not applied

Scan Reason
vulnerability-scan ran, but its output is not attested yet
github-actions-scan no workflow files changed
iac-scan no IaC files changed

View attestation ↗


Powered by Chainloop and Chainloop Trace

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

No issues found across 4 files

Heads up: you’re close to your included review allowance. Set a flex budget so reviews don’t pause.

Re-trigger cubic

@jiparis
jiparis requested a review from a team September 4, 2026 08:15
…s timestamp

`wf run describe` aborted with "bundle verification failed" whenever the
control plane served no timestamp authority for a bundle carrying a timestamp,
hiding the run entirely. The gap is in the trust material the control plane
publishes, not in the attestation, so report the attestation as unverified and
carry on. Failures attributable to the attestation still abort.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: 38ffe2d2-dec5-4c9f-9a68-abf837907af8
…erify its timestamp"

This reverts commit b0f0b0a.

Failing the describe when the control plane cannot verify a timestamp is the
intended behaviour on the read path.

Assisted-by: Claude Code
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>

Chainloop-Trace-Sessions: 38ffe2d2-dec5-4c9f-9a68-abf837907af8
@jiparis
jiparis merged commit d88df06 into chainloop-dev:main Sep 7, 2026
17 checks passed
@jiparis
jiparis deleted the jiparis/pfm-7150-tsa-rotation-should-not-fail-push branch September 7, 2026 07:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants