Problem
scripts/fetch-github-sbom.js caches GHCR bearer tokens for the lifetime of the process (module-level Map). GHCR bearer tokens expire in approximately 5 minutes.
The script processes 8 streams serially, each fetching up to 10 releases. On slow networks or with many new releases, a run can exceed 5 minutes, at which point GHCR requests start returning HTTP 401. The script has no token-expiry detection or refresh logic — 401 responses are treated as "attestation not found" rather than a transient auth failure.
The result: releases processed after ~5 minutes show attestationPresent: false incorrectly. CI exits 0 and the bad data is cached.
Fix
- Store a
fetchedAt timestamp alongside each cached token
- Before using a cached token, check if age > 4 minutes; re-fetch if so
- On HTTP 401, invalidate the cached token and retry once before treating as a genuine auth failure
Related
This interacts with serial stream processing — running streams concurrently (Promise.all) would reduce total run time and lower the probability of token expiry mid-run.
Problem
scripts/fetch-github-sbom.jscaches GHCR bearer tokens for the lifetime of the process (module-level Map). GHCR bearer tokens expire in approximately 5 minutes.The script processes 8 streams serially, each fetching up to 10 releases. On slow networks or with many new releases, a run can exceed 5 minutes, at which point GHCR requests start returning HTTP 401. The script has no token-expiry detection or refresh logic — 401 responses are treated as "attestation not found" rather than a transient auth failure.
The result: releases processed after ~5 minutes show
attestationPresent: falseincorrectly. CI exits 0 and the bad data is cached.Fix
fetchedAttimestamp alongside each cached tokenRelated
This interacts with serial stream processing — running streams concurrently (Promise.all) would reduce total run time and lower the probability of token expiry mid-run.