From afb1b15109756ea5cf9d8985a359d9095235ca2b Mon Sep 17 00:00:00 2001 From: Julien Goux Date: Thu, 24 Sep 2026 00:20:56 +0200 Subject: [PATCH] fix: allow registry fallback in supported CLI versions The action currently pins every recent CLI to GHCR, which disables the CLI's registry fallback and leaves image pulls exposed to GHCR throttling. Use the installed CLI version to keep the GHCR default for versions before v2.108.0 and allow fallback for newer versions. Preserve a caller's explicit registry choice. --- .github/workflows/e2e.yml | 2 ++ src/main.test.ts | 75 +++++++++++++++++++++++++++++++++++++++ src/main.ts | 15 +++++++- 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 0cc3d57..f754d1c 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -47,6 +47,8 @@ jobs: exclude: - version: 1.178.2 pg_major: 17 + - version: latest + pg_major: 14 steps: - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 with: diff --git a/src/main.test.ts b/src/main.test.ts index b830817..87b7340 100644 --- a/src/main.test.ts +++ b/src/main.test.ts @@ -12,6 +12,7 @@ const defaultEntrypoint = fileURLToPath(new URL("./main.ts", import.meta.url)); const CLI_CONFIG_REGISTRY = "SUPABASE_INTERNAL_IMAGE_REGISTRY"; const GITHUB_RELEASES_API = "https://api.github.com/repos/supabase/cli/releases/latest"; const GITHUB_TOKEN_ENV = "SUPABASE_CLI_GITHUB_TOKEN"; +const originalCliConfigRegistry = process.env[CLI_CONFIG_REGISTRY]; const originalWorkspace = process.env.GITHUB_WORKSPACE; const originalGithubToken = process.env[GITHUB_TOKEN_ENV]; const tempDirs = new Set(); @@ -25,6 +26,11 @@ afterEach(() => { } else { process.env[GITHUB_TOKEN_ENV] = originalGithubToken; } + if (originalCliConfigRegistry === undefined) { + delete process.env[CLI_CONFIG_REGISTRY]; + } else { + process.env[CLI_CONFIG_REGISTRY] = originalCliConfigRegistry; + } for (const dir of tempDirs) { rmSync(dir, { force: true, recursive: true }); @@ -516,6 +522,75 @@ test("explicit version overrides detected root lockfiles", async () => { expect(spies.setFailed).not.toHaveBeenCalled(); }); +test("keeps the GHCR registry pin through Supabase CLI v2.107.x", async () => { + const cliDir = createFakeCli("supabase 2.107.9"); + const spies = createActionSpies("2.107.9", cliDir, "/download/v2.107.9/supabase_"); + const { run } = await getMainModule(); + + await run(); + + expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io"); + expect(spies.setFailed).not.toHaveBeenCalled(); +}); + +test("keeps the GHCR registry pin starting with Supabase CLI v1.28.0", async () => { + const cliDir = createFakeCli("supabase 1.28.0"); + const spies = createActionSpies("1.28.0", cliDir, "/download/v1.28.0/supabase_"); + const { run } = await getMainModule(); + + await run(); + + expect(spies.exportVariable).toHaveBeenCalledWith(CLI_CONFIG_REGISTRY, "ghcr.io"); + expect(spies.setFailed).not.toHaveBeenCalled(); +}); + +test("uses the CLI built-in registry fallback starting with Supabase CLI v2.108.0", async () => { + const cliDir = createFakeCli("supabase 2.108.0"); + const spies = createActionSpies("2.108.0", cliDir, "/download/v2.108.0/supabase_"); + const { run } = await getMainModule(); + + await run(); + + expect(spies.exportVariable).not.toHaveBeenCalled(); + expect(spies.setFailed).not.toHaveBeenCalled(); +}); + +test("preserves an explicitly configured internal image registry", async () => { + process.env[CLI_CONFIG_REGISTRY] = "registry.example.test"; + const cliDir = createFakeCli("supabase 2.108.0"); + const spies = createActionSpies("2.108.0", cliDir, "/download/v2.108.0/supabase_"); + const { run } = await getMainModule(); + + await run(); + + expect(process.env[CLI_CONFIG_REGISTRY]).toBe("registry.example.test"); + expect(spies.exportVariable).not.toHaveBeenCalled(); +}); + +test("preserves a whitespace-only internal image registry", async () => { + process.env[CLI_CONFIG_REGISTRY] = " "; + const cliDir = createFakeCli("supabase 2.108.0"); + const spies = createActionSpies("2.108.0", cliDir, "/download/v2.108.0/supabase_"); + const { run } = await getMainModule(); + + await run(); + + expect(process.env[CLI_CONFIG_REGISTRY]).toBe(" "); + expect(spies.exportVariable).not.toHaveBeenCalled(); +}); + +test("uses the installed version to select the registry for latest", async () => { + mockLatestRelease("v2.108.0"); + const cliDir = createFakeCli("supabase 2.108.0"); + const spies = createActionSpies("latest", cliDir, "/download/v2.108.0/supabase_"); + const { run } = await getMainModule(); + + await run(); + + expect(spies.exportVariable).not.toHaveBeenCalled(); + expect(spies.setFailed).not.toHaveBeenCalled(); +}); + test("fails when the installed CLI does not report a version", async () => { process.env.GITHUB_WORKSPACE = createWorkspace({ "package-lock.json": createPackageLock("2.46.0"), diff --git a/src/main.ts b/src/main.ts index 1f59bfb..20acac6 100644 --- a/src/main.ts +++ b/src/main.ts @@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url"; export const CLI_CONFIG_REGISTRY = "SUPABASE_INTERNAL_IMAGE_REGISTRY"; const REGISTRY_VERSION = "1.28.0"; +const DEFAULT_REGISTRY_FALLBACK_VERSION = "2.108.0"; const VERSIONED_ARCHIVE_VERSION = "2.99.0"; const DEFAULT_VERSION = "latest"; const GITHUB_RELEASES_API = "https://api.github.com/repos/supabase/cli/releases/latest"; @@ -328,7 +329,19 @@ export async function run(): Promise { core.setOutput("version", installedVersion); core.addPath(cliPath); - if (version.toLowerCase() === "latest" || semver.order(version, REGISTRY_VERSION) >= 0) { + if (process.env[CLI_CONFIG_REGISTRY]) { + return; + } + + const installedVersionNumber = extractConcreteVersion(installedVersion); + if (!installedVersionNumber) { + throw new Error("Could not determine installed Supabase CLI version"); + } + + if ( + semver.order(installedVersionNumber, REGISTRY_VERSION) >= 0 && + semver.order(installedVersionNumber, DEFAULT_REGISTRY_FALLBACK_VERSION) === -1 + ) { core.exportVariable(CLI_CONFIG_REGISTRY, "ghcr.io"); } } catch (error) {