diff --git a/scripts/fetch-github-driver-versions.js b/scripts/fetch-github-driver-versions.js index 169f8685..ba50701f 100644 --- a/scripts/fetch-github-driver-versions.js +++ b/scripts/fetch-github-driver-versions.js @@ -34,6 +34,31 @@ const RELEASE_REPO_BY_STREAM = { "utah-testing": "projectbluefin/utah", }; +/** + * GHCR image tags for the LTS stream use an internal "lts-YYYYMMDD" cache key + * (see SBOM_STREAM_PREFIX below), but the projectbluefin/bluefin-lts repo + * publishes its GitHub Releases tagged "stable-YYYYMMDD". Map cache-key + * prefixes to the upstream release tag prefix actually used per-stream so + * releaseUrl links resolve instead of 404ing. + */ +const UPSTREAM_RELEASE_TAG_PREFIX_BY_STREAM = { + "bluefin-lts": "stable", +}; + +/** + * Translate a cache-key-derived tag (e.g. "lts-20260602") to the tag actually + * used by the stream's upstream GitHub Releases (e.g. "stable-20260602"). + * Streams without an entry in UPSTREAM_RELEASE_TAG_PREFIX_BY_STREAM, or tags + * that don't match the stream's known cache-key prefix, are returned as-is. + */ +function translateToUpstreamReleaseTag(streamId, tag) { + const upstreamPrefix = UPSTREAM_RELEASE_TAG_PREFIX_BY_STREAM[streamId]; + const cachePrefix = SBOM_STREAM_PREFIX[streamId]; + if (!upstreamPrefix || !cachePrefix || !tag) return tag; + if (!tag.startsWith(`${cachePrefix}-`)) return tag; + return `${upstreamPrefix}${tag.slice(cachePrefix.length)}`; +} + /** * Look up packageVersions from the SBOM cache for a specific stream + cacheKey. * cacheKey format matches fetch-github-sbom.js: e.g. "stable-20260331", "lts-20260331". @@ -171,9 +196,10 @@ function rowFromSbomRelease( title: releaseEntry?.tag || cacheKey, releaseUrl: (() => { const tag = releaseEntry?.tag || cacheKey; + const upstreamTag = translateToUpstreamReleaseTag(streamId, tag); const repo = RELEASE_REPO_BY_STREAM[streamId]; - return repo && tag - ? `https://github.com/${repo}/releases/tag/${tag}` + return repo && upstreamTag + ? `https://github.com/${repo}/releases/tag/${upstreamTag}` : RELEASE_URL_BY_STREAM[streamId] || null; })(), publishedAt, @@ -540,6 +566,7 @@ if (require.main === module) { module.exports = { buildUnavailableOutput, lookupSbomVersionsForTag, + translateToUpstreamReleaseTag, rowFromSbomRelease, buildStreamFromSbom, buildNvidiaMapFromSbomStream, diff --git a/scripts/fetch-github-driver-versions.test.js b/scripts/fetch-github-driver-versions.test.js index a1b07742..c889b818 100644 --- a/scripts/fetch-github-driver-versions.test.js +++ b/scripts/fetch-github-driver-versions.test.js @@ -6,6 +6,7 @@ const path = require("node:path"); const { lookupSbomVersionsForTag, + translateToUpstreamReleaseTag, rowFromSbomRelease, buildStreamFromSbom, buildNvidiaMapFromSbomStream, @@ -58,6 +59,42 @@ test("rowFromSbomRelease builds kernel/mesa/gnome from SBOM only", () => { assert.equal(row.versions.nvidia, "595.58.03-1"); }); +test("translateToUpstreamReleaseTag maps LTS cache keys to stable tags", () => { + assert.equal( + translateToUpstreamReleaseTag("bluefin-lts", "lts-20260602"), + "stable-20260602", + ); +}); + +test("translateToUpstreamReleaseTag leaves non-LTS tags unchanged", () => { + assert.equal( + translateToUpstreamReleaseTag("bluefin-stable", "stable-20260331"), + "stable-20260331", + ); + assert.equal( + translateToUpstreamReleaseTag("utah-testing", "testing-20260906"), + "testing-20260906", + ); +}); + +test("rowFromSbomRelease keeps the GHCR image tag but rewrites the LTS releaseUrl to the stable tag", () => { + const row = rowFromSbomRelease( + "bluefin-lts", + "lts-20260602", + { + tag: "lts-20260602", + packageVersions: { kernel: "6.12.0-233.el10" }, + }, + null, + ); + + assert.equal(row.tag, "lts-20260602"); + assert.equal( + row.releaseUrl, + "https://github.com/projectbluefin/bluefin-lts/releases/tag/stable-20260602", + ); +}); + test("buildStreamFromSbom sorts newest-first and marks source sbom", () => { const cache = { streams: {