-
-
Notifications
You must be signed in to change notification settings - Fork 62
feat(sbom): add SBOM attestation cache pipeline #693
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2f92e38
98cb43d
f141652
9a69a63
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -159,8 +159,11 @@ | |
| try { | ||
| batch = await fetchJson(url); | ||
| } catch (err) { | ||
| console.warn(` Packages API page ${page} failed: ${err.message}`); | ||
| break; | ||
| // Rethrow so the caller (main) can preserve existing cache for this package | ||
| // rather than silently returning an empty result and clearing all releases. | ||
| throw new Error( | ||
| `Packages API page ${page} for ${org}/${pkg} failed: ${err.message}`, | ||
| ); | ||
| } | ||
| if (!Array.isArray(batch) || batch.length === 0) break; | ||
| versions.push(...batch); | ||
|
|
@@ -238,7 +241,7 @@ | |
| maxBuffer: 4 * 1024 * 1024, | ||
| }); | ||
| stdout = result.stdout; | ||
| stderr = result.stderr; | ||
| } catch (err) { | ||
| const msg = (err.stderr || err.message || "").toLowerCase(); | ||
| // cosign exits non-zero when no attestation exists | ||
|
|
@@ -254,16 +257,21 @@ | |
| error: "no attestation", | ||
| }; | ||
| } | ||
| // Unexpected tooling/registry/auth failure — do NOT claim present: true. | ||
| // Callers use present: false (no attestation) vs present: null (error/unknown) | ||
| // to distinguish absence from verification failure. | ||
| return { | ||
| present: true, | ||
| present: null, | ||
| verified: false, | ||
| predicateType: null, | ||
| errorKind: "tooling", | ||
| error: String(err.stderr || err.message), | ||
|
Comment on lines
+264
to
268
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The use of |
||
| }; | ||
| } | ||
|
|
||
| // cosign outputs NDJSON (one JSON object per line) | ||
| const lines = (stdout + stderr) | ||
| // cosign outputs NDJSON (one JSON object per line) on stdout only; | ||
| // stderr carries status messages ("Verification OK") that must not be parsed. | ||
| const lines = stdout | ||
| .split("\n") | ||
| .map((l) => l.trim()) | ||
| .filter((l) => l.startsWith("{")); | ||
|
|
@@ -547,6 +555,12 @@ | |
| const dateStr = extractDateFromTag(normalised); | ||
| if (!dateStr) continue; | ||
|
|
||
| // Enforce canonical tag: only exact `<streamPrefix>-YYYYMMDD` is accepted. | ||
| // Non-canonical variants like lts-hwe-testing-20260331 would normalise to | ||
| // lts-20260331 and silently overwrite valid canonical entries. | ||
| const expectedCanonical = `${spec.streamPrefix}-${dateStr}`; | ||
| if (normalised !== expectedCanonical) continue; | ||
|
|
||
| found.push({ | ||
| tag: normalised, | ||
| cacheKey: buildCacheKey(spec.streamPrefix, dateStr), | ||
|
|
@@ -577,7 +591,18 @@ | |
| */ | ||
| async function processStream(spec, allVersionsByPackage, existing) { | ||
| const pkgKey = `${spec.org}/${spec.package}`; | ||
| const allVersions = allVersionsByPackage.get(pkgKey) || []; | ||
| // If the key is absent the Packages API fetch failed — preserve existing cache. | ||
| if (!allVersionsByPackage.has(pkgKey)) { | ||
| if (existing?.streams?.[spec.id]) { | ||
| console.log( | ||
| ` ${spec.id}: Packages API unavailable — keeping existing cache`, | ||
| ); | ||
| return existing.streams[spec.id]; | ||
| } | ||
| // No existing cache to fall back to; return empty stream. | ||
| return { ...spec, releases: {} }; | ||
| } | ||
| const allVersions = allVersionsByPackage.get(pkgKey); | ||
| const recentTags = findRecentTagsForStream(allVersions, spec); | ||
|
|
||
| console.log( | ||
|
|
@@ -616,6 +641,9 @@ | |
| verified: attestation.verified, | ||
| predicateType: attestation.predicateType, | ||
| slsaType: SLSA_TYPE, | ||
| ...(attestation.errorKind !== undefined && { | ||
| errorKind: attestation.errorKind, | ||
| }), | ||
| error: attestation.error, | ||
| }; | ||
| } | ||
|
|
@@ -714,7 +742,8 @@ | |
| console.log(` ${versions.length} versions fetched`); | ||
| } catch (err) { | ||
| console.error(` Failed to fetch versions for ${key}: ${err.message}`); | ||
| allVersionsByPackage.set(key, []); | ||
| // Do NOT set an empty array — leave the key absent so processStream | ||
| // detects the fetch failure and preserves the existing cache instead. | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| /** | ||
| * Type declaration for the SBOM attestation cache data file. | ||
| * | ||
| * static/data/sbom-attestations.json is generated at CI time by | ||
| * scripts/fetch-github-sbom.js and restored from GitHub Actions cache before | ||
| * the build runs. It is gitignored and will not exist during local `tsc` | ||
| * typechecks — this ambient declaration satisfies the compiler without | ||
| * requiring the file to be present on disk. | ||
| */ | ||
|
|
||
| declare module "@site/static/data/sbom-attestations.json" { | ||
| import type { SbomAttestationsData } from "@site/src/types/sbom"; | ||
| const data: SbomAttestationsData; | ||
| export default data; | ||
| } |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment on line 162 states that rethrowing allows the caller to preserve the existing cache. However, the
mainfunction (at line 731) catches this error and sets the package versions to an empty array (allVersionsByPackage.set(key, [])). This causesprocessStreamto proceed with zero releases, effectively clearing the cache for all streams associated with that package. To achieve the stated goal of preserving the cache, themainfunction should be updated to skip processing or handle the error without clearing the package entry.