From cbc705e00f63fc08770cf2c2b227d5e029ba7e8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Berg=C3=A9?= Date: Thu, 21 May 2026 14:43:28 +0200 Subject: [PATCH 1/2] fix(tokenless): fix tokenless with push event --- packages/core/mocks/oidc.ts | 16 ++--- packages/core/src/auth.test.ts | 4 +- packages/core/src/github-actions-oidc.test.ts | 4 +- .../core/src/github-actions-tokenless.test.ts | 65 ++----------------- packages/core/src/github-actions-tokenless.ts | 18 ++--- 5 files changed, 23 insertions(+), 84 deletions(-) diff --git a/packages/core/mocks/oidc.ts b/packages/core/mocks/oidc.ts index c3ea5c3a..8d429f82 100644 --- a/packages/core/mocks/oidc.ts +++ b/packages/core/mocks/oidc.ts @@ -8,7 +8,7 @@ export const MOCK_ARGOS_TOKEN = "mock-argos-token-returned"; export const MOCK_EXPIRES_AT = "2099-01-01T00:00:00.000Z"; export const MOCK_TOKENLESS_ARGOS_TOKEN = "mock-tokenless-argos-token-returned"; -export const oidcHandlers = [ +export const tokenExchangeHandlers = [ http.get(MOCK_OIDC_URL, ({ request }) => { const url = new URL(request.url); if (url.searchParams.get("audience") !== "https://api.argos-ci.com") { @@ -53,21 +53,21 @@ export const oidcHandlers = [ ), ]; -export const oidcServer = setupServer(...oidcHandlers); +export const tokenExchangeServer = setupServer(...tokenExchangeHandlers); /** - * Registers vitest lifecycle hooks to start/stop the OIDC mock server and + * Registers vitest lifecycle hooks to start/stop the token mock server and * reset handlers + env stubs between tests. Returns the server so individual * tests can override handlers via `server.use(...)`. */ -export function setupOidcServer() { - beforeAll(() => oidcServer.listen()); +export function setupTokenExchangeServer() { + beforeAll(() => tokenExchangeServer.listen()); afterEach(() => { - oidcServer.resetHandlers(); + tokenExchangeServer.resetHandlers(); vi.unstubAllEnvs(); }); - afterAll(() => oidcServer.close()); - return oidcServer; + afterAll(() => tokenExchangeServer.close()); + return tokenExchangeServer; } /** Stubs the env vars required for `isGitHubActionsOidcAvailable()` to return true. */ diff --git a/packages/core/src/auth.test.ts b/packages/core/src/auth.test.ts index fbbe7d4b..22481d09 100644 --- a/packages/core/src/auth.test.ts +++ b/packages/core/src/auth.test.ts @@ -7,7 +7,7 @@ import { MOCK_EXPIRES_AT, MOCK_OIDC_URL, MOCK_TOKENLESS_ARGOS_TOKEN, - setupOidcServer, + setupTokenExchangeServer, stubOidcEnv, } from "../mocks/oidc"; @@ -43,7 +43,7 @@ const baseConfig: Config = { subset: false, }; -const server = setupOidcServer(); +const server = setupTokenExchangeServer(); describe("resolveArgosToken", () => { beforeEach(() => { diff --git a/packages/core/src/github-actions-oidc.test.ts b/packages/core/src/github-actions-oidc.test.ts index 3427afc4..3c93775d 100644 --- a/packages/core/src/github-actions-oidc.test.ts +++ b/packages/core/src/github-actions-oidc.test.ts @@ -9,11 +9,11 @@ import { MOCK_OIDC_TOKEN, MOCK_ARGOS_TOKEN, MOCK_EXPIRES_AT, - setupOidcServer, + setupTokenExchangeServer, stubOidcEnv, } from "../mocks/oidc"; -const server = setupOidcServer(); +const server = setupTokenExchangeServer(); describe("isGitHubActionsOidcAvailable", () => { it("returns true when all OIDC env vars are present and ARGOS_TOKEN is absent", () => { diff --git a/packages/core/src/github-actions-tokenless.test.ts b/packages/core/src/github-actions-tokenless.test.ts index a29562ba..d17bacc8 100644 --- a/packages/core/src/github-actions-tokenless.test.ts +++ b/packages/core/src/github-actions-tokenless.test.ts @@ -1,70 +1,16 @@ -import { describe, it, expect, vi } from "vitest"; +import { describe, it, expect } from "vitest"; import { http, HttpResponse } from "msw"; -import { - isGitHubActionsTokenlessAvailable, - exchangeGitHubActionsTokenlessToken, -} from "./github-actions-tokenless"; +import { exchangeGitHubActionsTokenlessToken } from "./github-actions-tokenless"; import { MOCK_TOKENLESS_ARGOS_TOKEN, MOCK_EXPIRES_AT, - setupOidcServer, + setupTokenExchangeServer, } from "../mocks/oidc"; const base64Decode = (str: string): unknown => JSON.parse(Buffer.from(str, "base64").toString("utf8")); -const server = setupOidcServer(); - -describe("isGitHubActionsTokenlessAvailable", () => { - const prHeadCommit = "abc123def456abc123def456abc123def456abc1"; - - it("returns true when ciProvider is github-actions, prHeadCommit is set and ARGOS_TOKEN is absent", () => { - vi.stubEnv("ARGOS_TOKEN", ""); - expect( - isGitHubActionsTokenlessAvailable({ - ciProvider: "github-actions", - prHeadCommit, - }), - ).toBe(true); - }); - - it("returns false when ARGOS_TOKEN is set", () => { - vi.stubEnv("ARGOS_TOKEN", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); - expect( - isGitHubActionsTokenlessAvailable({ - ciProvider: "github-actions", - prHeadCommit, - }), - ).toBe(false); - }); - - it("returns false when ciProvider is not github-actions", () => { - vi.stubEnv("ARGOS_TOKEN", ""); - expect( - isGitHubActionsTokenlessAvailable({ - ciProvider: "gitlab-ci", - prHeadCommit, - }), - ).toBe(false); - }); - - it("returns false when ciProvider is null", () => { - vi.stubEnv("ARGOS_TOKEN", ""); - expect( - isGitHubActionsTokenlessAvailable({ ciProvider: null, prHeadCommit }), - ).toBe(false); - }); - - it("returns false when prHeadCommit is missing", () => { - vi.stubEnv("ARGOS_TOKEN", ""); - expect( - isGitHubActionsTokenlessAvailable({ - ciProvider: "github-actions", - prHeadCommit: null, - }), - ).toBe(false); - }); -}); +const server = setupTokenExchangeServer(); describe("exchangeGitHubActionsTokenlessToken", () => { const baseConfig = { @@ -72,7 +18,8 @@ describe("exchangeGitHubActionsTokenlessToken", () => { jobId: "job-1", runId: "run-42", prNumber: null, - prHeadCommit: "abc123def456abc123def456abc123def456abc1", + prHeadCommit: null, + commit: "abc123def456abc123def456abc123def456abc1", branch: "main", }; diff --git a/packages/core/src/github-actions-tokenless.ts b/packages/core/src/github-actions-tokenless.ts index 8c57cbbc..6294c621 100644 --- a/packages/core/src/github-actions-tokenless.ts +++ b/packages/core/src/github-actions-tokenless.ts @@ -8,13 +8,9 @@ const base64Encode = (obj: any) => * Check if GitHub Actions tokenless authentication is available for auto-detection. */ export function isGitHubActionsTokenlessAvailable( - config: Pick, + config: Pick, ): boolean { - return Boolean( - config.ciProvider === "github-actions" && - config.prHeadCommit && - !process.env.ARGOS_TOKEN, - ); + return config.ciProvider === "github-actions"; } /** @@ -55,15 +51,11 @@ export async function exchangeGitHubActionsTokenlessToken(args: { | "prNumber" | "branch" | "prHeadCommit" + | "commit" >; }): Promise { const { apiBaseUrl, config } = args; - - if (!config.prHeadCommit) { - throw new Error( - `GitHub PR head commit is required for tokenless authentication.`, - ); - } + const commit = config.prHeadCommit ?? config.commit; const tokenlessToken = getTokenlessBearerToken(config); @@ -74,7 +66,7 @@ export async function exchangeGitHubActionsTokenlessToken(args: { { body: { tokenlessToken, - commit: config.prHeadCommit, + commit, branch: config.branch, }, }, From e5460ae59bc21e034f99a4e121b6397b8bc43908 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Greg=20Berg=C3=A9?= Date: Thu, 21 May 2026 15:06:54 +0200 Subject: [PATCH 2/2] chore: fix tests --- packages/core/src/github-actions-tokenless.test.ts | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/packages/core/src/github-actions-tokenless.test.ts b/packages/core/src/github-actions-tokenless.test.ts index d17bacc8..a65254e8 100644 --- a/packages/core/src/github-actions-tokenless.test.ts +++ b/packages/core/src/github-actions-tokenless.test.ts @@ -58,17 +58,6 @@ describe("exchangeGitHubActionsTokenlessToken", () => { ).rejects.toThrow("Automatic GitHub Actions variables detection failed"); }); - it("throws when prHeadCommit is missing", async () => { - await expect( - exchangeGitHubActionsTokenlessToken({ - apiBaseUrl: "https://api.argos-ci.com/v2/", - config: { ...baseConfig, prHeadCommit: null }, - }), - ).rejects.toThrow( - "GitHub PR head commit is required for tokenless authentication", - ); - }); - it("throws when the Argos API exchange returns an error", async () => { server.use( http.post( @@ -104,7 +93,7 @@ describe("exchangeGitHubActionsTokenlessToken", () => { config: { ...baseConfig, prNumber: 99 }, }); - expect(capturedBody.commit).toBe(baseConfig.prHeadCommit); + expect(capturedBody.commit).toBe(baseConfig.commit); expect(capturedBody.branch).toBe(baseConfig.branch); expect(typeof capturedBody.tokenlessToken).toBe("string"); const bearer = capturedBody.tokenlessToken as string;