diff --git a/base-action/action.yml b/base-action/action.yml index d2cd7aeab..29bdab0ad 100644 --- a/base-action/action.yml +++ b/base-action/action.yml @@ -145,7 +145,7 @@ runs: PATH_TO_CLAUDE_CODE_EXECUTABLE: ${{ inputs.path_to_claude_code_executable }} run: | if [ -z "$PATH_TO_CLAUDE_CODE_EXECUTABLE" ]; then - CLAUDE_CODE_VERSION="2.1.214" + CLAUDE_CODE_VERSION="2.1.220" echo "Installing Claude Code v${CLAUDE_CODE_VERSION}..." for attempt in 1 2 3; do echo "Installation attempt $attempt..." diff --git a/base-action/bun.lock b/base-action/bun.lock index 99a4c70b0..9658b5f35 100644 --- a/base-action/bun.lock +++ b/base-action/bun.lock @@ -6,7 +6,7 @@ "name": "@anthropic-ai/claude-code-base-action", "dependencies": { "@actions/core": "^1.10.1", - "@anthropic-ai/claude-agent-sdk": "^0.3.214", + "@anthropic-ai/claude-agent-sdk": "^0.3.220", "shell-quote": "^1.8.3", }, "devDependencies": { @@ -27,23 +27,23 @@ "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="], - "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.214", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.214", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.214", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.214", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.214" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-wt5ImwhU+p259Zt4K/Q9v5xVi6ruxYO5+KFICyJxnjs/QFEClAeSRqhcXx1J8jgGfatPW1faw09hkm66680UjA=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.220", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.220", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.220", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.220", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.220" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-glc7SdwPkOkLw8oxwLo9PKTdLJGqW/PIR4urWXFoRtX9YllwozsEVc5Tc1+EvLSkfrsxPJqQWqOgpjUOQXf1oA=="], - "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.214", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vAAOeVtlXs3p7MpFVfvfu9ja32eaKtB+MDZnPxCbdzxJk5nofCHlNsHa1UJwXHOsP9lOnFYNIccYztsZ4DNaJA=="], + "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.220", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7VxlbEosK7DODiOnsjoVd0DSJzbnaPrM2jelMHI0y8zx1UnLS3WC6EFUXbvy74F2sXqEznh2tzn7EKWInaRN6Q=="], - "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.214", "", { "os": "darwin", "cpu": "x64" }, "sha512-NTbV8U2yucxCWqEiDC7L0MUehNmd8x3Op8OGzLZRhMF3xmQBy2DxpXiNZgSwwKWNDC3HdgKmJM5ZBbT7XrF/0g=="], + "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.220", "", { "os": "darwin", "cpu": "x64" }, "sha512-X9RwDsSmbF6ultKZroaip+DL8WRgC64gHbrAwrRlAFSPNZV7zmJyP2ur8rW7KrxqmtuehdMMkw8+SAC/6hD2PA=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.214", "", { "os": "linux", "cpu": "arm64" }, "sha512-KBCf+BlusG0ZcgvpjjHwv1kh+6WiR8vJbPjpR2udwkrtcQgKLN+24l+FeaQEzO2TL+ExCmM1KC4tNPvnPpy+tw=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.220", "", { "os": "linux", "cpu": "arm64" }, "sha512-WkROPwWskqhKR9XgnmseHQ6rLi9zM9qt57IWoToIjL/eXOqDWipp7JXZ1L5ud+LrA42dunHPZfBwD/vXZ+A7LA=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.214", "", { "os": "linux", "cpu": "arm64" }, "sha512-i06wQRsmevE7spY1ryYfs+NP+xdZ1FwAyTjDaF0k/xG+cgtzZYghTFUemdYF3GVwgWgpcava9GiCFDT3DoHI6w=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.220", "", { "os": "linux", "cpu": "arm64" }, "sha512-OHoZOZ8Cf2TBr6oXIXPwyvUxj9jrq2w8E4poA8dMpacXszcPSPiCQCMuuOh4aWJzfeJE1+TtWxhKMVb2csXyZQ=="], - "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.214", "", { "os": "linux", "cpu": "x64" }, "sha512-vqadSceJkBKHaTUszxI35uTuECGWtsHWK/mOwIJ4b9DUtYYySz6EJEk4gHg4ccutisJ/oRVCpFXHIKFb+osrKw=="], + "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.220", "", { "os": "linux", "cpu": "x64" }, "sha512-tkTJFnpR9VifvWX2fmkCAPkT6+8Wk/gVu8B5jsVekKZPiZoWRHmMXO30BnZn+f0TZhgYP+82PSX3S8crH1kn+w=="], - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.214", "", { "os": "linux", "cpu": "x64" }, "sha512-948RstHDhs0E69h+2dKYWIAL1kcwEme4zvtgNUwP8XpKXzWOhrTKmd6MAokHn25zwfuSx5d+HE0XHfFH6R4hLg=="], + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.220", "", { "os": "linux", "cpu": "x64" }, "sha512-K+FWj+LcGhC1Z7wqeWoLxm1iemcba5xKpLLFVwYm4V6HyMx3ruYd/2r2TiQtjT+JWeNFWIys0ScHiItR6vWAiA=="], - "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.214", "", { "os": "win32", "cpu": "arm64" }, "sha512-CEKlPFCPv+ee79utQMEDSsgeo2f27ulhNHpjrKIt1jXz5G04J7lAWN/QwvPDv9XaLBkWpyfqZWiPXlRcwuaO/w=="], + "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.220", "", { "os": "win32", "cpu": "arm64" }, "sha512-rIwgq0UwQExWl6KrHUyC4w5KwpL9l6nd95aUTx6RitexaAuEw//xtfTVLnuE4hDDQZFkzEwpdKc3nxDWoGcUbA=="], - "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.214", "", { "os": "win32", "cpu": "x64" }, "sha512-cJMJfFoR9IWBZWnTtt9PnEm89hGOsZjoDNjOCEOF3+x+g/ANIXAjMJTcaQYv2HKh6MylWZ0AkxBASI+twkukaQ=="], + "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.220", "", { "os": "win32", "cpu": "x64" }, "sha512-MuOuXhbr66HlGaWXD2f3w0k2PsvmnbkwcUZ0dAe2poFLdl72GC2dapwwOBefxm9QmoNqk9+jmv/dSKGOVWyvLw=="], "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.93.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-q9vaSZQVFx6B/gPxetGYfLXSJD5v0sOmh0OpZDq7yCrTSA+Rscvrtyol7JJTW40wEpQB4U1B4JXzxQitbQ3CAA=="], diff --git a/base-action/package.json b/base-action/package.json index 872251642..15ff4a7df 100644 --- a/base-action/package.json +++ b/base-action/package.json @@ -11,7 +11,7 @@ }, "dependencies": { "@actions/core": "^1.10.1", - "@anthropic-ai/claude-agent-sdk": "^0.3.214", + "@anthropic-ai/claude-agent-sdk": "^0.3.220", "shell-quote": "^1.8.3" }, "devDependencies": { diff --git a/base-action/src/index.ts b/base-action/src/index.ts index e95c2f64a..2e4cd2571 100644 --- a/base-action/src/index.ts +++ b/base-action/src/index.ts @@ -75,7 +75,8 @@ async function run() { core.setOutput("conclusion", "failure"); process.exit(1); } finally { - // Stop refreshing the workload identity token file so the process can exit + // Stop refreshing the workload identity token file (so the process can + // exit) and delete the token material so it doesn't outlive this step workloadIdentity?.stop(); } } diff --git a/base-action/src/workload-identity.ts b/base-action/src/workload-identity.ts index 91266f32b..79ebaf50e 100644 --- a/base-action/src/workload-identity.ts +++ b/base-action/src/workload-identity.ts @@ -15,7 +15,8 @@ */ import * as core from "@actions/core"; -import { mkdirSync, writeFileSync } from "fs"; +import { createHash } from "crypto"; +import { mkdirSync, rmSync, writeFileSync } from "fs"; import { join } from "path"; import { retryWithBackoff } from "./retry"; @@ -50,6 +51,63 @@ async function fetchIdentityToken(audience: string) { return retryWithBackoff(() => core.getIDToken(audience)); } +/** + * Writes a profile config that switches federation resolution to the + * file-backed path. Resolving federation through a profile (rather than bare + * env vars) enables the SDK's on-disk credentials cache, so the several + * `claude` processes the action spawns (plugin installs, main query) share + * one exchanged access token instead of each re-exchanging the single-use + * GitHub OIDC token, which fails with 401 (`jti_reused`). + * + * The profile is intentionally minimal: the SDK gap-fills the federation + * fields (rule, organization, identity-token file, service account, base URL) + * from the ANTHROPIC_* env vars the action already exports, so the file only + * needs to exist to turn the cache on. + * + * The config dir name embeds a fingerprint of the federation inputs. The + * SDK's cache reuses a token on `expires_at` alone, with no record of the + * config that minted it, and the token's scope is bound at mint time — so a + * later action step in the same job (RUNNER_TEMP is per-job) with different + * federation inputs must land in a different dir or it would silently reuse + * the first step's token. + * + * Sharing the cache is only safe while the action spawns its `claude` + * subprocesses sequentially: the SDK cache is not cross-process serialized, + * and concurrent cache misses would each re-exchange the same single-use + * identity token. Parallelizing the plugin installs would reintroduce the + * `jti_reused` failures. + */ +function writeFederationProfile(baseDir: string): string { + // Every input that changes which credential the exchange mints must be in + // here; service_account_id and scope are sent in the exchange request body. + const fingerprint = createHash("sha256") + .update( + JSON.stringify([ + process.env.ANTHROPIC_FEDERATION_RULE_ID?.trim() ?? "", + process.env.ANTHROPIC_ORGANIZATION_ID?.trim() ?? "", + process.env.ANTHROPIC_SERVICE_ACCOUNT_ID?.trim() ?? "", + process.env.ANTHROPIC_WORKSPACE_ID?.trim() ?? "", + process.env.ANTHROPIC_BASE_URL?.trim() ?? "", + process.env.ANTHROPIC_SCOPE?.trim() ?? "", + ]), + ) + .digest("hex") + .slice(0, 16); + const configDir = join(baseDir, `config-${fingerprint}`); + + mkdirSync(join(configDir, "configs"), { recursive: true, mode: 0o700 }); + writeFileSync( + join(configDir, "configs", "default.json"), + JSON.stringify( + { version: "1.0", authentication: { type: "oidc_federation" } }, + null, + 2, + ), + { mode: 0o600 }, + ); + return configDir; +} + /** * Fetches a GitHub Actions OIDC token, writes it to a file in RUNNER_TEMP, * exports ANTHROPIC_IDENTITY_TOKEN_FILE, and starts a background refresh so @@ -57,7 +115,8 @@ async function fetchIdentityToken(audience: string) { * * Returns undefined when federation is not configured or is shadowed by a * higher-precedence credential. Callers must invoke stop() when execution - * finishes. + * finishes; it also deletes the identity token and any cached exchanged + * credential. */ export async function setupWorkloadIdentity(): Promise< WorkloadIdentityHandle | undefined @@ -101,6 +160,17 @@ export async function setupWorkloadIdentity(): Promise< } process.env.ANTHROPIC_IDENTITY_TOKEN_FILE = tokenFile; + if ( + process.env.ANTHROPIC_CONFIG_DIR?.trim() || + process.env.ANTHROPIC_PROFILE?.trim() + ) { + core.warning( + "ANTHROPIC_CONFIG_DIR or ANTHROPIC_PROFILE is already set, so the action will not write its own federation profile. Credential caching across the spawned Claude processes follows the existing profile configuration.", + ); + } else { + process.env.ANTHROPIC_CONFIG_DIR = writeFederationProfile(tokenDir); + process.env.ANTHROPIC_PROFILE = "default"; + } console.log( `Workload identity federation configured (rule: ${process.env.ANTHROPIC_FEDERATION_RULE_ID}, identity token file: ${tokenFile})`, ); @@ -115,6 +185,12 @@ export async function setupWorkloadIdentity(): Promise< return { tokenFile, - stop: () => clearInterval(refreshInterval), + stop: () => { + clearInterval(refreshInterval); + // RUNNER_TEMP is per-job, not per-step: remove the identity token, the + // profile, and the cached exchanged credential so they don't outlive + // this step. + rmSync(tokenDir, { recursive: true, force: true }); + }, }; } diff --git a/base-action/test/workload-identity.test.ts b/base-action/test/workload-identity.test.ts index e95f4e06d..5b7615caf 100644 --- a/base-action/test/workload-identity.test.ts +++ b/base-action/test/workload-identity.test.ts @@ -2,7 +2,14 @@ import { describe, test, expect, beforeEach, afterEach, spyOn } from "bun:test"; import * as core from "@actions/core"; -import { existsSync, mkdtempSync, readFileSync, rmSync, statSync } from "fs"; +import { + existsSync, + mkdtempSync, + readdirSync, + readFileSync, + rmSync, + statSync, +} from "fs"; import { tmpdir } from "os"; import { join } from "path"; import { @@ -27,6 +34,12 @@ describe("workload identity federation", () => { delete process.env.ANTHROPIC_ORGANIZATION_ID; delete process.env.ANTHROPIC_OIDC_AUDIENCE; delete process.env.ANTHROPIC_IDENTITY_TOKEN_FILE; + delete process.env.ANTHROPIC_SERVICE_ACCOUNT_ID; + delete process.env.ANTHROPIC_WORKSPACE_ID; + delete process.env.ANTHROPIC_BASE_URL; + delete process.env.ANTHROPIC_SCOPE; + delete process.env.ANTHROPIC_CONFIG_DIR; + delete process.env.ANTHROPIC_PROFILE; getIDTokenSpy = spyOn(core, "getIDToken").mockResolvedValue( "test-identity-token", @@ -123,5 +136,123 @@ describe("workload identity federation", () => { handle?.stop(); } }); + + test("writes a minimal federation profile and selects it", async () => { + process.env.ANTHROPIC_FEDERATION_RULE_ID = "fdrl_test"; + process.env.ANTHROPIC_ORGANIZATION_ID = + "00000000-0000-0000-0000-000000000000"; + process.env.ANTHROPIC_SERVICE_ACCOUNT_ID = "svac_test"; + process.env.ANTHROPIC_WORKSPACE_ID = "wrkspc_test"; + + const handle = await setupWorkloadIdentity(); + try { + const configDir = process.env.ANTHROPIC_CONFIG_DIR; + expect(configDir).toBeDefined(); + expect( + configDir!.startsWith( + join(tempDir, "claude-workload-identity", "config-"), + ), + ).toBe(true); + expect(process.env.ANTHROPIC_PROFILE).toBe("default"); + + const profilePath = join(configDir!, "configs", "default.json"); + expect(statSync(profilePath).mode & 0o777).toBe(0o600); + // Minimal on purpose: the SDK gap-fills the federation fields from + // the ANTHROPIC_* env vars the action exports. + expect(JSON.parse(readFileSync(profilePath, "utf-8"))).toEqual({ + version: "1.0", + authentication: { type: "oidc_federation" }, + }); + } finally { + handle?.stop(); + } + }); + + test("derives the config dir from the federation inputs", async () => { + process.env.ANTHROPIC_FEDERATION_RULE_ID = "fdrl_test"; + process.env.ANTHROPIC_ORGANIZATION_ID = + "00000000-0000-0000-0000-000000000000"; + process.env.ANTHROPIC_WORKSPACE_ID = "wrkspc_a"; + + (await setupWorkloadIdentity())?.stop(); + const firstConfigDir = process.env.ANTHROPIC_CONFIG_DIR; + expect(firstConfigDir).toBeDefined(); + + // A later step in the same job with a different workspace must not + // share the first step's credentials cache. + delete process.env.ANTHROPIC_CONFIG_DIR; + delete process.env.ANTHROPIC_PROFILE; + process.env.ANTHROPIC_WORKSPACE_ID = "wrkspc_b"; + + (await setupWorkloadIdentity())?.stop(); + const secondConfigDir = process.env.ANTHROPIC_CONFIG_DIR; + expect(secondConfigDir).toBeDefined(); + expect(secondConfigDir).not.toBe(firstConfigDir); + + // Same inputs land in the same dir, so an unchanged config can still + // reuse a cached token. + delete process.env.ANTHROPIC_CONFIG_DIR; + delete process.env.ANTHROPIC_PROFILE; + + (await setupWorkloadIdentity())?.stop(); + expect(process.env.ANTHROPIC_CONFIG_DIR).toBe(secondConfigDir!); + }); + + test("does not overwrite an operator-set ANTHROPIC_PROFILE", async () => { + process.env.ANTHROPIC_FEDERATION_RULE_ID = "fdrl_test"; + process.env.ANTHROPIC_ORGANIZATION_ID = + "00000000-0000-0000-0000-000000000000"; + process.env.ANTHROPIC_PROFILE = "operator"; + + const handle = await setupWorkloadIdentity(); + try { + expect(process.env.ANTHROPIC_PROFILE).toBe("operator"); + expect(process.env.ANTHROPIC_CONFIG_DIR).toBeUndefined(); + expect(warningSpy).toHaveBeenCalled(); + + const entries = readdirSync(join(tempDir, "claude-workload-identity")); + expect(entries.filter((e) => e.startsWith("config-"))).toEqual([]); + + // The identity token file is still provisioned for the operator's + // profile (or the env-var fallback) to consume. + expect(process.env.ANTHROPIC_IDENTITY_TOKEN_FILE).toBe( + handle!.tokenFile, + ); + } finally { + handle?.stop(); + } + }); + + test("does not overwrite an operator-set ANTHROPIC_CONFIG_DIR", async () => { + process.env.ANTHROPIC_FEDERATION_RULE_ID = "fdrl_test"; + process.env.ANTHROPIC_ORGANIZATION_ID = + "00000000-0000-0000-0000-000000000000"; + const operatorConfigDir = join(tempDir, "operator-config"); + process.env.ANTHROPIC_CONFIG_DIR = operatorConfigDir; + + const handle = await setupWorkloadIdentity(); + try { + expect(process.env.ANTHROPIC_CONFIG_DIR).toBe(operatorConfigDir); + expect(process.env.ANTHROPIC_PROFILE).toBeUndefined(); + expect(warningSpy).toHaveBeenCalled(); + } finally { + handle?.stop(); + } + }); + + test("stop removes the identity token and credential cache", async () => { + process.env.ANTHROPIC_FEDERATION_RULE_ID = "fdrl_test"; + process.env.ANTHROPIC_ORGANIZATION_ID = + "00000000-0000-0000-0000-000000000000"; + + const handle = await setupWorkloadIdentity(); + const tokenDir = join(tempDir, "claude-workload-identity"); + expect(existsSync(handle!.tokenFile)).toBe(true); + expect(existsSync(process.env.ANTHROPIC_CONFIG_DIR!)).toBe(true); + + handle!.stop(); + + expect(existsSync(tokenDir)).toBe(false); + }); }); }); diff --git a/bun.lock b/bun.lock index 698ec567f..31fa0a41d 100644 --- a/bun.lock +++ b/bun.lock @@ -7,7 +7,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.1", - "@anthropic-ai/claude-agent-sdk": "^0.3.214", + "@anthropic-ai/claude-agent-sdk": "^0.3.220", "@modelcontextprotocol/sdk": "^1.11.0", "@octokit/graphql": "^8.2.2", "@octokit/rest": "^21.1.1", @@ -37,23 +37,23 @@ "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="], - "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.214", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.214", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.214", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.214", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.214", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.214" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-wt5ImwhU+p259Zt4K/Q9v5xVi6ruxYO5+KFICyJxnjs/QFEClAeSRqhcXx1J8jgGfatPW1faw09hkm66680UjA=="], + "@anthropic-ai/claude-agent-sdk": ["@anthropic-ai/claude-agent-sdk@0.3.220", "", { "optionalDependencies": { "@anthropic-ai/claude-agent-sdk-darwin-arm64": "0.3.220", "@anthropic-ai/claude-agent-sdk-darwin-x64": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-arm64": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-x64": "0.3.220", "@anthropic-ai/claude-agent-sdk-linux-x64-musl": "0.3.220", "@anthropic-ai/claude-agent-sdk-win32-arm64": "0.3.220", "@anthropic-ai/claude-agent-sdk-win32-x64": "0.3.220" }, "peerDependencies": { "@anthropic-ai/sdk": ">=0.93.0", "@modelcontextprotocol/sdk": "^1.29.0", "zod": "^4.0.0" } }, "sha512-glc7SdwPkOkLw8oxwLo9PKTdLJGqW/PIR4urWXFoRtX9YllwozsEVc5Tc1+EvLSkfrsxPJqQWqOgpjUOQXf1oA=="], - "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.214", "", { "os": "darwin", "cpu": "arm64" }, "sha512-vAAOeVtlXs3p7MpFVfvfu9ja32eaKtB+MDZnPxCbdzxJk5nofCHlNsHa1UJwXHOsP9lOnFYNIccYztsZ4DNaJA=="], + "@anthropic-ai/claude-agent-sdk-darwin-arm64": ["@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.220", "", { "os": "darwin", "cpu": "arm64" }, "sha512-7VxlbEosK7DODiOnsjoVd0DSJzbnaPrM2jelMHI0y8zx1UnLS3WC6EFUXbvy74F2sXqEznh2tzn7EKWInaRN6Q=="], - "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.214", "", { "os": "darwin", "cpu": "x64" }, "sha512-NTbV8U2yucxCWqEiDC7L0MUehNmd8x3Op8OGzLZRhMF3xmQBy2DxpXiNZgSwwKWNDC3HdgKmJM5ZBbT7XrF/0g=="], + "@anthropic-ai/claude-agent-sdk-darwin-x64": ["@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.220", "", { "os": "darwin", "cpu": "x64" }, "sha512-X9RwDsSmbF6ultKZroaip+DL8WRgC64gHbrAwrRlAFSPNZV7zmJyP2ur8rW7KrxqmtuehdMMkw8+SAC/6hD2PA=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.214", "", { "os": "linux", "cpu": "arm64" }, "sha512-KBCf+BlusG0ZcgvpjjHwv1kh+6WiR8vJbPjpR2udwkrtcQgKLN+24l+FeaQEzO2TL+ExCmM1KC4tNPvnPpy+tw=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64": ["@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.220", "", { "os": "linux", "cpu": "arm64" }, "sha512-WkROPwWskqhKR9XgnmseHQ6rLi9zM9qt57IWoToIjL/eXOqDWipp7JXZ1L5ud+LrA42dunHPZfBwD/vXZ+A7LA=="], - "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.214", "", { "os": "linux", "cpu": "arm64" }, "sha512-i06wQRsmevE7spY1ryYfs+NP+xdZ1FwAyTjDaF0k/xG+cgtzZYghTFUemdYF3GVwgWgpcava9GiCFDT3DoHI6w=="], + "@anthropic-ai/claude-agent-sdk-linux-arm64-musl": ["@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.220", "", { "os": "linux", "cpu": "arm64" }, "sha512-OHoZOZ8Cf2TBr6oXIXPwyvUxj9jrq2w8E4poA8dMpacXszcPSPiCQCMuuOh4aWJzfeJE1+TtWxhKMVb2csXyZQ=="], - "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.214", "", { "os": "linux", "cpu": "x64" }, "sha512-vqadSceJkBKHaTUszxI35uTuECGWtsHWK/mOwIJ4b9DUtYYySz6EJEk4gHg4ccutisJ/oRVCpFXHIKFb+osrKw=="], + "@anthropic-ai/claude-agent-sdk-linux-x64": ["@anthropic-ai/claude-agent-sdk-linux-x64@0.3.220", "", { "os": "linux", "cpu": "x64" }, "sha512-tkTJFnpR9VifvWX2fmkCAPkT6+8Wk/gVu8B5jsVekKZPiZoWRHmMXO30BnZn+f0TZhgYP+82PSX3S8crH1kn+w=="], - "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.214", "", { "os": "linux", "cpu": "x64" }, "sha512-948RstHDhs0E69h+2dKYWIAL1kcwEme4zvtgNUwP8XpKXzWOhrTKmd6MAokHn25zwfuSx5d+HE0XHfFH6R4hLg=="], + "@anthropic-ai/claude-agent-sdk-linux-x64-musl": ["@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.220", "", { "os": "linux", "cpu": "x64" }, "sha512-K+FWj+LcGhC1Z7wqeWoLxm1iemcba5xKpLLFVwYm4V6HyMx3ruYd/2r2TiQtjT+JWeNFWIys0ScHiItR6vWAiA=="], - "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.214", "", { "os": "win32", "cpu": "arm64" }, "sha512-CEKlPFCPv+ee79utQMEDSsgeo2f27ulhNHpjrKIt1jXz5G04J7lAWN/QwvPDv9XaLBkWpyfqZWiPXlRcwuaO/w=="], + "@anthropic-ai/claude-agent-sdk-win32-arm64": ["@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.220", "", { "os": "win32", "cpu": "arm64" }, "sha512-rIwgq0UwQExWl6KrHUyC4w5KwpL9l6nd95aUTx6RitexaAuEw//xtfTVLnuE4hDDQZFkzEwpdKc3nxDWoGcUbA=="], - "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.214", "", { "os": "win32", "cpu": "x64" }, "sha512-cJMJfFoR9IWBZWnTtt9PnEm89hGOsZjoDNjOCEOF3+x+g/ANIXAjMJTcaQYv2HKh6MylWZ0AkxBASI+twkukaQ=="], + "@anthropic-ai/claude-agent-sdk-win32-x64": ["@anthropic-ai/claude-agent-sdk-win32-x64@0.3.220", "", { "os": "win32", "cpu": "x64" }, "sha512-MuOuXhbr66HlGaWXD2f3w0k2PsvmnbkwcUZ0dAe2poFLdl72GC2dapwwOBefxm9QmoNqk9+jmv/dSKGOVWyvLw=="], "@anthropic-ai/sdk": ["@anthropic-ai/sdk@0.93.0", "", { "dependencies": { "json-schema-to-ts": "^3.1.1" }, "peerDependencies": { "zod": "^3.25.0 || ^4.0.0" }, "optionalPeers": ["zod"], "bin": { "anthropic-ai-sdk": "bin/cli" } }, "sha512-q9vaSZQVFx6B/gPxetGYfLXSJD5v0sOmh0OpZDq7yCrTSA+Rscvrtyol7JJTW40wEpQB4U1B4JXzxQitbQ3CAA=="], diff --git a/package.json b/package.json index 768f0aa29..f0e441496 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dependencies": { "@actions/core": "^1.10.1", "@actions/github": "^6.0.1", - "@anthropic-ai/claude-agent-sdk": "^0.3.214", + "@anthropic-ai/claude-agent-sdk": "^0.3.220", "@modelcontextprotocol/sdk": "^1.11.0", "@octokit/graphql": "^8.2.2", "@octokit/rest": "^21.1.1", diff --git a/src/entrypoints/run.ts b/src/entrypoints/run.ts index 43f3df585..7f2c1692c 100644 --- a/src/entrypoints/run.ts +++ b/src/entrypoints/run.ts @@ -75,7 +75,7 @@ async function installClaudeCode(): Promise { return customExecutable; } - const claudeCodeVersion = "2.1.214"; + const claudeCodeVersion = "2.1.220"; console.log(`Installing Claude Code v${claudeCodeVersion}...`); for (let attempt = 1; attempt <= 3; attempt++) { @@ -318,7 +318,8 @@ async function run() { } finally { // Phase 4: Cleanup (always runs) - // Stop refreshing the workload identity token file + // Stop refreshing the workload identity token file and delete the token + // material so it doesn't outlive this step workloadIdentity?.stop(); // Update tracking comment