Skip to content

fix(triage): fetch tag-based attestation via oras; support cosign 3.x output#113

Merged
tobias-pfaffelmoser-aa merged 1 commit into
mainfrom
fix/triage-att-tag-without-cosign
Jun 15, 2026
Merged

fix(triage): fetch tag-based attestation via oras; support cosign 3.x output#113
tobias-pfaffelmoser-aa merged 1 commit into
mainfrom
fix/triage-att-tag-without-cosign

Conversation

@tobias-pfaffelmoser-aa

@tobias-pfaffelmoser-aa tobias-pfaffelmoser-aa commented Jun 12, 2026

Copy link
Copy Markdown

Problem

Run with cosign 3.x, retrieve-triage reports every JFrog image as having no triage — even ones that clearly have it:

🔍 No triage predicate in tag-based attestations for .../assistant-api:1.19.7
🚫 No triage found for .../assistant-api:1.19.7

Confirmed root cause (reproduced with cosign v3.0.5 vs v2.4.2): cosign 3.x changed the download attestation output format. It still returns all attestations (verified: 9 incl. the triage predicate), but as a sigstore bundle — the DSSE payload moved from top-level payload to dsseEnvelope.payload:

cosign download attestation line shape triage found by old parser?
2.x {"payload": <b64>, "signatures": […]} ✅ (reads .payload)
3.x {"mediaType": ".../bundle.v0.3+json", "dsseEnvelope": {"payload": <b64>}} ❌ (no top-level .payload)

So the result silently depended on the installed cosign version. (It is not the Referrers API — JFrog lacks Referrers discovery, but the .att is a plain tag that pulls fine.)

Change

  1. Primary: fetch the sha256-<digest>.att manifest directly with oras and decode its DSSE layers newest-first, stopping at the first triage match (one blob fetch for the common re-attested case). cosign-version-independent; plain registry reads JFrog supports.
  2. Fallback: keep cosign download attestation, now parsing both the bare-DSSE-envelope (.payload) and sigstore-bundle (.dsseEnvelope.payload) shapes.

Verification

  • cosign v3.0.5 (reported version), full 41-image list via the wrapper script: 41/41 via oras .att, 0 via cosign, 0 skips; report = 25 sections / 158 CVE rows, headers remapped to JFrog refs.
  • cosign stubbed to return nothing (worst case): 41/41, all via oras .att.
  • Fallback parser unit-checked against real v2.4.2 and v3.0.5 output — extracts triage from both.
  • Newest-first scan: oras blob fetches 390 → 41 over the list (~10m → ~3m), and diff -rq confirms the triage files and report are byte-identical to scanning all layers.

Works regardless of the installed cosign version.

@github-actions github-actions Bot added the fix label Jun 12, 2026
@tobias-pfaffelmoser-aa
tobias-pfaffelmoser-aa force-pushed the fix/triage-att-tag-without-cosign branch from d38ba80 to 8554a13 Compare June 15, 2026 08:03
@tobias-pfaffelmoser-aa tobias-pfaffelmoser-aa changed the title fix(triage): fetch tag-based attestation via oras .att tag, not cosign fix(triage): fetch tag-based attestation via oras; support cosign 3.x output Jun 15, 2026
… output

retrieve-triage reported every JFrog image as having no triage when run with
cosign 3.x. Two issues, both in the tag-based path:

1. cosign 3.x changed `download attestation` output from a bare DSSE envelope
   ({"payload": <b64>}) to a sigstore bundle ({"dsseEnvelope": {"payload": <b64>}}).
   The parser only read the top-level `payload`, so it found no triage predicate
   even though cosign returned the attestation. cosign 2.x still emits the old
   shape — the result silently depended on the installed cosign version.

2. Relying on `cosign download attestation` at all couples the result to the
   local cosign version.

Fix: fetch the `sha256-<digest>.att` manifest directly with oras and decode its
DSSE layers newest-first, stopping at the first triage match (one blob fetch for
the common re-attested case). This is cosign-version-independent; oras/crane are
already prerequisites and use plain registry reads JFrog supports (the .att tag,
not the Referrers API). Keep `cosign download attestation` as a fallback, now
parsing both the bare-envelope and bundle shapes.

Verified with cosign v3.0.5 (the reported version), v2.4.2, and a stubbed cosign
returning nothing: 41/41 fetched via the oras .att path in all cases. The
newest-first scan cuts oras blob fetches 390 -> 41 over the 41-image list (~10m
-> ~3m) and produces byte-identical triage files and report vs scanning all
layers.
@tobias-pfaffelmoser-aa
tobias-pfaffelmoser-aa force-pushed the fix/triage-att-tag-without-cosign branch from 8554a13 to 543dad1 Compare June 15, 2026 08:26
@tobias-pfaffelmoser-aa
tobias-pfaffelmoser-aa merged commit a20c590 into main Jun 15, 2026
7 checks passed
@tobias-pfaffelmoser-aa
tobias-pfaffelmoser-aa deleted the fix/triage-att-tag-without-cosign branch June 15, 2026 08:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant