diff --git a/package-lock.json b/package-lock.json index 892ea73..c2e50d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "6.1.1", "license": "MIT", "dependencies": { - "@actions/core": "^2.0.2", + "@actions/core": "^3.0.1", "@aws-sdk/client-sts": "^3.1038.0", "@smithy/node-http-handler": "^4.6.1", "proxy-agent": "^8.0.1" @@ -35,28 +35,28 @@ } }, "node_modules/@actions/core": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@actions/core/-/core-2.0.3.tgz", - "integrity": "sha512-Od9Thc3T1mQJYddvVPM4QGiLUewdh+3txmDYHHxoNdkqysR1MbCT+rFOtNUxYAz+7+6RIsqipVahY2GJqGPyxA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@actions/core/-/core-3.0.1.tgz", + "integrity": "sha512-a6d/Nwahm9fliVGRhdhofo40HjHQasUPusmc7vBfyky+7Z+P2A1J68zyFVaNcEclc/Se+eO595oAr5nwEIoIUA==", "license": "MIT", "dependencies": { - "@actions/exec": "^2.0.0", - "@actions/http-client": "^3.0.2" + "@actions/exec": "^3.0.0", + "@actions/http-client": "^4.0.0" } }, "node_modules/@actions/exec": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-2.0.0.tgz", - "integrity": "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@actions/exec/-/exec-3.0.0.tgz", + "integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==", "license": "MIT", "dependencies": { - "@actions/io": "^2.0.0" + "@actions/io": "^3.0.2" } }, "node_modules/@actions/http-client": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-3.0.2.tgz", - "integrity": "sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-4.0.1.tgz", + "integrity": "sha512-+Nvd1ImaOZBSoPbsUtEhv+1z99H12xzncCkz0a3RuehINE81FZSe2QTj3uvAPTcJX/SCzUQHQ0D1GrPMbrPitg==", "license": "MIT", "dependencies": { "tunnel": "^0.0.6", @@ -64,9 +64,9 @@ } }, "node_modules/@actions/io": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@actions/io/-/io-2.0.0.tgz", - "integrity": "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@actions/io/-/io-3.0.2.tgz", + "integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==", "license": "MIT" }, "node_modules/@aws-crypto/sha256-browser": { diff --git a/package.json b/package.json index 75caa25..1ee6fe7 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "vitest": "^4.1.5" }, "dependencies": { - "@actions/core": "^2.0.2", + "@actions/core": "^3.0.1", "@aws-sdk/client-sts": "^3.1038.0", "@smithy/node-http-handler": "^4.6.1", "proxy-agent": "^8.0.1" diff --git a/test/cleanup.test.ts b/test/cleanup.test.ts index 74da1e7..f7bd649 100644 --- a/test/cleanup.test.ts +++ b/test/cleanup.test.ts @@ -5,20 +5,15 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import { cleanup } from '../src/cleanup'; import mocks from './mockinputs.test'; +vi.mock('@actions/core'); + const mockedSTSClient = mockClient(STSClient); describe('Configure AWS Credentials cleanup', {}, () => { beforeEach(() => { - // Reset mock state - vi.restoreAllMocks(); + vi.resetAllMocks(); mockedSTSClient.reset(); - // Mock GitHub Actions core functions - vi.spyOn(core, 'exportVariable').mockImplementation((_n, _v) => {}); - vi.spyOn(core, 'setSecret').mockImplementation((_s) => {}); - vi.spyOn(core, 'setFailed').mockImplementation((_m) => {}); - vi.spyOn(core, 'setOutput').mockImplementation((_n, _v) => {}); - vi.spyOn(core, 'debug').mockImplementation((_m) => {}); - vi.spyOn(core, 'info').mockImplementation((_m) => {}); + vi.mocked(core.getInput).mockReturnValue(''); process.env = { ...mocks.envs, AWS_ACCESS_KEY_ID: 'CLEANUPTEST', @@ -39,7 +34,7 @@ describe('Configure AWS Credentials cleanup', {}, () => { expect(core.exportVariable).toHaveBeenCalledWith('AWS_REGION', ''); }); it('also clears AWS_PROFILE when aws-profile was set', {}, () => { - vi.spyOn(core, 'getInput').mockImplementation((name: string) => { + vi.mocked(core.getInput).mockImplementation((name: string) => { if (name === 'aws-profile') return 'my-profile'; if (name === 'output-env-credentials') return 'true'; return ''; @@ -50,7 +45,7 @@ describe('Configure AWS Credentials cleanup', {}, () => { expect(core.exportVariable).toHaveBeenCalledWith('AWS_PROFILE', ''); }); it('skips env cleanup when aws-profile is set without output-env-credentials', {}, () => { - vi.spyOn(core, 'getInput').mockImplementation((name: string) => { + vi.mocked(core.getInput).mockImplementation((name: string) => { if (name === 'aws-profile') return 'my-profile'; return ''; }); @@ -59,14 +54,14 @@ describe('Configure AWS Credentials cleanup', {}, () => { expect(core.exportVariable).toHaveBeenCalledTimes(0); }); it('handles errors', {}, () => { - vi.spyOn(core, 'exportVariable').mockImplementationOnce(() => { + vi.mocked(core.exportVariable).mockImplementationOnce(() => { throw new Error('Test error'); }); cleanup(); expect(core.setFailed).toHaveBeenCalled(); }); it(`doesn't export credentials as empty env variables if asked not to`, {}, () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.NO_ENV_CREDS_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.NO_ENV_CREDS_INPUTS)); cleanup(); expect(core.exportVariable).toHaveBeenCalledTimes(0); }); diff --git a/test/helpers.test.ts b/test/helpers.test.ts index 98f8b71..09e768a 100644 --- a/test/helpers.test.ts +++ b/test/helpers.test.ts @@ -2,10 +2,11 @@ import * as core from '@actions/core'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import * as helpers from '../src/helpers'; +vi.mock('@actions/core'); + describe('Configure AWS Credentials helpers', {}, () => { beforeEach(() => { - vi.restoreAllMocks(); - vi.spyOn(core, 'debug').mockImplementation(() => {}); + vi.resetAllMocks(); }); it('removes brackets from GitHub Actor', {}, () => { const actor = 'actor[bot]'; @@ -24,9 +25,6 @@ describe('Configure AWS Credentials helpers', {}, () => { expect(fn).toHaveBeenCalledTimes(1); }); it('can output creds when told to', {}, () => { - vi.spyOn(core, 'setOutput').mockImplementation(() => {}); - vi.spyOn(core, 'setSecret').mockImplementation(() => {}); - vi.spyOn(core, 'exportVariable').mockImplementation(() => {}); helpers.exportCredentials( { AccessKeyId: 'test', SecretAccessKey: 'test', SessionToken: 'test', Expiration: new Date(8640000000000000) }, true, @@ -47,9 +45,6 @@ describe('Configure AWS Credentials helpers', {}, () => { process.env = env; }); it(`won't output credentials to env if told not to`, {}, () => { - vi.spyOn(core, 'setOutput').mockImplementation(() => {}); - vi.spyOn(core, 'setSecret').mockImplementation(() => {}); - vi.spyOn(core, 'exportVariable').mockImplementation(() => {}); helpers.exportCredentials( { AccessKeyId: 'test', SecretAccessKey: 'test', SessionToken: 'test', Expiration: new Date(8640000000000000) }, true, @@ -77,22 +72,20 @@ describe('Configure AWS Credentials helpers', {}, () => { }); it('handles getBooleanInput correctly', {}, () => { - vi.spyOn(core, 'getInput').mockReturnValue('true'); + vi.mocked(core.getInput).mockReturnValue('true'); expect(helpers.getBooleanInput('test')).toBe(true); - - vi.spyOn(core, 'getInput').mockReturnValue('false'); + + vi.mocked(core.getInput).mockReturnValue('false'); expect(helpers.getBooleanInput('test')).toBe(false); - - vi.spyOn(core, 'getInput').mockReturnValue(''); + + vi.mocked(core.getInput).mockReturnValue(''); expect(helpers.getBooleanInput('test', { default: true })).toBe(true); - - vi.spyOn(core, 'getInput').mockReturnValue('invalid'); + + vi.mocked(core.getInput).mockReturnValue('invalid'); expect(() => helpers.getBooleanInput('test')).toThrow(); }); it('clears session token when not provided', {}, () => { - vi.spyOn(core, 'setSecret').mockImplementation(() => {}); - vi.spyOn(core, 'exportVariable').mockImplementation(() => {}); process.env.AWS_SESSION_TOKEN = 'old-token'; helpers.exportCredentials({ AccessKeyId: 'test', SecretAccessKey: 'test' }, false, true); expect(core.exportVariable).toHaveBeenCalledWith('AWS_SESSION_TOKEN', ''); diff --git a/test/index.test.ts b/test/index.test.ts index e44813e..f27ee13 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -13,23 +13,17 @@ import { run } from '../src/index'; import * as profileManager from '../src/profileManager'; import mocks from './mockinputs.test'; +vi.mock('@actions/core'); vi.mock('node:fs'); const mockedSTSClient = mockClient(STSClient); describe('Configure AWS Credentials', {}, () => { beforeEach(() => { - // Reset mock state - vi.restoreAllMocks(); + vi.resetAllMocks(); mockedSTSClient.reset(); - // Mock GitHub Actions core functions - vi.spyOn(core, 'exportVariable').mockImplementation((_n, _v) => {}); - vi.spyOn(core, 'setSecret').mockImplementation((_s) => {}); - vi.spyOn(core, 'setFailed').mockImplementation((_m) => {}); - vi.spyOn(core, 'setOutput').mockImplementation((_n, _v) => {}); - vi.spyOn(core, 'debug').mockImplementation((_m) => {}); - vi.spyOn(core, 'info').mockImplementation((_m) => {}); - vi.spyOn(core, 'notice').mockImplementation((_m) => {}); + vi.mocked(core.getInput).mockReturnValue(''); + vi.mocked(core.getMultilineInput).mockReturnValue([]); // Remove any existing environment variables before each test to prevent the // SDK from picking them up process.env = { ...mocks.envs }; @@ -38,8 +32,8 @@ describe('Configure AWS Credentials', {}, () => { describe('GitHub OIDC Authentication', {}, () => { beforeEach(() => { vi.clearAllMocks(); - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(GetCallerIdentityCommand).resolvesOnce({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; }); @@ -91,7 +85,7 @@ describe('Configure AWS Credentials', {}, () => { describe('IAM User Authentication', {}, () => { beforeEach(() => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); mockedSTSClient.on(GetCallerIdentityCommand).resolvesOnce({ ...mocks.outputs.GET_CALLER_IDENTITY }); // biome-ignore lint/suspicious/noExplicitAny: any required to mock private method vi.spyOn(CredentialsClient.prototype as any, 'loadCredentials').mockResolvedValueOnce({ @@ -118,7 +112,7 @@ describe('Configure AWS Credentials', {}, () => { describe('AssumeRole with IAM LTC', {}, () => { beforeEach(() => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.IAM_ASSUMEROLE_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_ASSUMEROLE_INPUTS)); mockedSTSClient.on(AssumeRoleCommand).resolvesOnce(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); // 3 times // biome-ignore lint/suspicious/noExplicitAny: any required to mock private method @@ -152,7 +146,7 @@ describe('Configure AWS Credentials', {}, () => { describe('AssumeRole with WebIdentityTokeFile', {}, () => { beforeEach(() => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.WEBIDENTITY_TOKEN_FILE_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.WEBIDENTITY_TOKEN_FILE_INPUTS)); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolvesOnce(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolvesOnce({ ...mocks.outputs.GET_CALLER_IDENTITY }); vol.reset(); @@ -187,7 +181,7 @@ describe('Configure AWS Credentials', {}, () => { process.env = { ...mocks.envs }; }); it('exports environment variables from env variables', async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.EXISTING_ROLE_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.EXISTING_ROLE_INPUTS)); process.env.AWS_ACCESS_KEY_ID = 'MYAWSACCESSKEYID'; process.env.AWS_SECRET_ACCESS_KEY = 'MYAWSSECRETACCESSKEY'; process.env.AWS_SESSION_TOKEN = 'MYAWSSESSIONTOKEN'; @@ -210,7 +204,7 @@ describe('Configure AWS Credentials', {}, () => { expect(core.setFailed).not.toHaveBeenCalled(); }); it('exports environment variables from inputs', {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.EXISTING_ROLE_INPUTS, 'aws-access-key-id': 'MYAWSACCESSKEYID', @@ -246,14 +240,14 @@ describe('Configure AWS Credentials', {}, () => { describe('Odd inputs', {}, () => { it('fails when github env vars are missing', {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); delete process.env.GITHUB_REPOSITORY; delete process.env.GITHUB_SHA; await run(); expect(core.setFailed).toHaveBeenCalled(); }); it('does not fail if GITHUB_REF is missing', {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); mockedSTSClient.on(GetCallerIdentityCommand).resolvesOnce({ ...mocks.outputs.GET_CALLER_IDENTITY }); // biome-ignore lint/suspicious/noExplicitAny: any required to mock private method vi.spyOn(CredentialsClient.prototype as any, 'loadCredentials').mockResolvedValueOnce({ @@ -264,12 +258,12 @@ describe('Configure AWS Credentials', {}, () => { expect(core.setFailed).not.toHaveBeenCalled(); }); it('fails with an invalid region', {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput({ 'aws-region': '$|<1B1D1 701L37' })); + vi.mocked(core.getInput).mockImplementation(mocks.getInput({ 'aws-region': '$|<1B1D1 701L37' })); await run(); expect(core.setFailed).toHaveBeenCalled(); }); it('fails if access key id is provided without secret access key', {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'aws-secret-access-key': '' }), ); await run(); @@ -277,14 +271,14 @@ describe('Configure AWS Credentials', {}, () => { }); it('handles improper retry-max-attempts input', {}, async () => { // This should mean we retry one time - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'retry-max-attempts': '-1', 'special-characters-workaround': 'false', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(GetCallerIdentityCommand).resolvesOnce({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; mockedSTSClient @@ -296,27 +290,27 @@ describe('Configure AWS Credentials', {}, () => { expect(core.setFailed).toHaveBeenCalled(); }); it('fails if doing OIDC without the ACTIONS_ID_TOKEN_REQUEST_TOKEN', {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); delete process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN; await run(); expect(core.setFailed).toHaveBeenCalled(); }); it("gets new creds if told to reuse existing but they're invalid", {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.USE_EXISTING_CREDENTIALS_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.USE_EXISTING_CREDENTIALS_INPUTS)); mockedSTSClient.on(GetCallerIdentityCommand).rejects(); await run(); expect(core.notice).toHaveBeenCalledWith('No valid credentials exist. Running as normal.'); }); it("doesn't get new creds if there are already valid ones and we said use them", {}, async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.USE_EXISTING_CREDENTIALS_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.USE_EXISTING_CREDENTIALS_INPUTS)); mockedSTSClient.on(GetCallerIdentityCommand).resolves(mocks.outputs.GET_CALLER_IDENTITY); await run(); expect(core.setFailed).not.toHaveBeenCalled(); }); it("doesn't export credentials as environment variables if told not to", {}, async () => { mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolvesOnce(mocks.outputs.STS_CREDENTIALS); - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.NO_ENV_CREDS_INPUTS)); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.NO_ENV_CREDS_INPUTS)); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; await run(); expect(core.setSecret).toHaveBeenCalledTimes(3); @@ -325,8 +319,8 @@ describe('Configure AWS Credentials', {}, () => { }); it('can export creds as step outputs without exporting as env variables', {}, async () => { mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolvesOnce(mocks.outputs.STS_CREDENTIALS); - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.STEP_BUT_NO_ENV_INPUTS)); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.STEP_BUT_NO_ENV_INPUTS)); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; await run(); expect(core.setSecret).toHaveBeenCalledTimes(3); @@ -343,13 +337,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('skips OIDC when force-skip-oidc is true with IAM credentials', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_ASSUMEROLE_INPUTS, 'force-skip-oidc': 'true', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); // biome-ignore lint/suspicious/noExplicitAny: any required to mock private method @@ -364,13 +358,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('skips OIDC when force-skip-oidc is true with web identity token file', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.WEBIDENTITY_TOKEN_FILE_INPUTS, 'force-skip-oidc': 'true', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -385,7 +379,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('fails when force-skip-oidc is true but no alternative credentials provided', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ 'role-to-assume': 'arn:aws:iam::111111111111:role/MY-ROLE', 'aws-region': 'fake-region-1', @@ -401,13 +395,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('allows force-skip-oidc without role-to-assume', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'force-skip-oidc': 'true', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); // biome-ignore lint/suspicious/noExplicitAny: any required to mock private method @@ -424,13 +418,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('uses OIDC when force-skip-oidc is false (default behavior)', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'force-skip-oidc': 'false', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -442,8 +436,8 @@ describe('Configure AWS Credentials', {}, () => { }); it('uses OIDC when force-skip-oidc is not set (default behavior)', async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -455,7 +449,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('works with role chaining when force-skip-oidc is true', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.EXISTING_ROLE_INPUTS, 'force-skip-oidc': 'true', @@ -463,7 +457,7 @@ describe('Configure AWS Credentials', {}, () => { 'aws-secret-access-key': 'MYAWSSECRETACCESSKEY', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); // biome-ignore lint/suspicious/noExplicitAny: any required to mock private method @@ -485,7 +479,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('succeeds when account ID matches allowed list', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'allowed-account-ids': '111111111111', @@ -503,7 +497,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('succeeds with multiple allowed account IDs when account matches', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'allowed-account-ids': '999999999999,111111111111,222222222222', @@ -520,7 +514,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('fails when account ID does not match allowed list', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'allowed-account-ids': '999999999999', @@ -539,7 +533,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('fails when account ID does not match any in multiple allowed accounts', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'allowed-account-ids': '999999999999,888888888888', @@ -559,7 +553,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('works with assume role when account ID matches', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_ASSUMEROLE_INPUTS, 'allowed-account-ids': '111111111111', @@ -578,13 +572,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('works with OIDC when account ID matches', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'allowed-account-ids': '111111111111', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -595,7 +589,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('handles GetCallerIdentity API failure gracefully', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'allowed-account-ids': '111111111111', @@ -612,7 +606,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('ignores validation when allowed-account-ids is empty', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'allowed-account-ids': '', @@ -630,7 +624,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('handles whitespace in allowed-account-ids input', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'allowed-account-ids': ' 111111111111 , 222222222222 ', @@ -649,7 +643,7 @@ describe('Configure AWS Credentials', {}, () => { describe('Global Timeout Configuration', {}, () => { beforeEach(() => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.IAM_USER_INPUTS)); mockedSTSClient.on(GetCallerIdentityCommand).resolvesOnce({ ...mocks.outputs.GET_CALLER_IDENTITY }); // biome-ignore lint/suspicious/noExplicitAny: any required to mock private method vi.spyOn(CredentialsClient.prototype as any, 'loadCredentials').mockResolvedValueOnce({ @@ -660,8 +654,8 @@ describe('Configure AWS Credentials', {}, () => { it('sets timeout when action-timeout-s is provided', async () => { const setTimeoutSpy = vi.spyOn(global, 'setTimeout'); const clearTimeoutSpy = vi.spyOn(global, 'clearTimeout'); - const infoSpy = vi.spyOn(core, 'info'); - vi.spyOn(core, 'getInput').mockImplementation( + const infoSpy = vi.mocked(core.info); + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'action-timeout-s': '30', @@ -678,8 +672,8 @@ describe('Configure AWS Credentials', {}, () => { it('does not set timeout when action-timeout-s is 0', async () => { const setTimeoutSpy = vi.spyOn(global, 'setTimeout'); - const infoSpy = vi.spyOn(core, 'info'); - vi.spyOn(core, 'getInput').mockImplementation( + const infoSpy = vi.mocked(core.info); + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'action-timeout-s': '0', @@ -695,7 +689,7 @@ describe('Configure AWS Credentials', {}, () => { it('does not set timeout when action-timeout-s is not provided', async () => { const setTimeoutSpy = vi.spyOn(global, 'setTimeout'); - const infoSpy = vi.spyOn(core, 'info'); + const infoSpy = vi.mocked(core.info); await run(); @@ -707,7 +701,7 @@ describe('Configure AWS Credentials', {}, () => { it('timeout callback calls setFailed and exits process', async () => { const setTimeoutSpy = vi.spyOn(global, 'setTimeout'); const processExitSpy = vi.spyOn(process, 'exit').mockImplementation(() => undefined as never); - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'action-timeout-s': '5', @@ -729,16 +723,16 @@ describe('Configure AWS Credentials', {}, () => { describe('HTTP Proxy Configuration', {}, () => { beforeEach(() => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(GetCallerIdentityCommand).resolvesOnce({ ...mocks.outputs.GET_CALLER_IDENTITY }); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolvesOnce(mocks.outputs.STS_CREDENTIALS); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; }); it('configures proxy from http-proxy input', async () => { - const infoSpy = vi.spyOn(core, 'info'); - vi.spyOn(core, 'getInput').mockImplementation( + const infoSpy = vi.mocked(core.info); + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'http-proxy': 'http://proxy.example.com:8080', @@ -752,7 +746,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('configures proxy from HTTP_PROXY environment variable', async () => { - const infoSpy = vi.spyOn(core, 'info'); + const infoSpy = vi.mocked(core.info); process.env.HTTP_PROXY = 'http://proxy.example.com:8080'; await run(); @@ -762,7 +756,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('configures proxy from HTTPS_PROXY environment variable', async () => { - const infoSpy = vi.spyOn(core, 'info'); + const infoSpy = vi.mocked(core.info); process.env.HTTPS_PROXY = 'https://proxy.example.com:8080'; await run(); @@ -772,9 +766,9 @@ describe('Configure AWS Credentials', {}, () => { }); it('prioritizes http-proxy input over environment variables', async () => { - const infoSpy = vi.spyOn(core, 'info'); + const infoSpy = vi.mocked(core.info); process.env.HTTP_PROXY = 'http://env-proxy.example.com:8080'; - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'http-proxy': 'http://input-proxy.example.com:8080', @@ -788,9 +782,9 @@ describe('Configure AWS Credentials', {}, () => { }); it('properly configures proxy agent in STS client', async () => { - const infoSpy = vi.spyOn(core, 'info'); + const infoSpy = vi.mocked(core.info); - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'http-proxy': 'http://proxy.example.com:8080', @@ -804,7 +798,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('configures no-proxy setting', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'http-proxy': 'http://proxy.example.com:8080', @@ -832,13 +826,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('writes profile files with OIDC authentication', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'aws-profile': 'dev', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -861,7 +855,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('writes profile files with IAM user credentials', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_USER_INPUTS, 'aws-profile': 'production', @@ -891,7 +885,7 @@ describe('Configure AWS Credentials', {}, () => { }); it('writes profile files with IAM user role assumption', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.IAM_ASSUMEROLE_INPUTS, 'aws-profile': 'assumed-role', @@ -928,14 +922,14 @@ describe('Configure AWS Credentials', {}, () => { }); it('respects output-env-credentials=true with profiles', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'aws-profile': 'dev', 'output-env-credentials': 'true', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -958,8 +952,8 @@ describe('Configure AWS Credentials', {}, () => { }); it('maintains backward compatibility when aws-profile is not specified', async () => { - vi.spyOn(core, 'getInput').mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getInput).mockImplementation(mocks.getInput(mocks.GH_OIDC_INPUTS)); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -983,13 +977,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('handles default profile correctly', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'aws-profile': 'default', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; @@ -1004,13 +998,13 @@ describe('Configure AWS Credentials', {}, () => { }); it('rejects invalid profile names with whitespace', async () => { - vi.spyOn(core, 'getInput').mockImplementation( + vi.mocked(core.getInput).mockImplementation( mocks.getInput({ ...mocks.GH_OIDC_INPUTS, 'aws-profile': 'invalid profile', }), ); - vi.spyOn(core, 'getIDToken').mockResolvedValue('testoidctoken'); + vi.mocked(core.getIDToken).mockResolvedValue('testoidctoken'); mockedSTSClient.on(AssumeRoleWithWebIdentityCommand).resolves(mocks.outputs.STS_CREDENTIALS); mockedSTSClient.on(GetCallerIdentityCommand).resolves({ ...mocks.outputs.GET_CALLER_IDENTITY }); process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN = 'fake-token'; diff --git a/test/profileManager.test.ts b/test/profileManager.test.ts index c27f895..5bf665d 100644 --- a/test/profileManager.test.ts +++ b/test/profileManager.test.ts @@ -11,14 +11,13 @@ import { writeProfileFiles, } from '../src/profileManager'; +vi.mock('@actions/core'); vi.mock('node:fs'); describe('Profile Manager', {}, () => { beforeEach(() => { - vi.restoreAllMocks(); + vi.resetAllMocks(); vol.reset(); - vi.spyOn(core, 'debug').mockImplementation(() => {}); - vi.spyOn(core, 'info').mockImplementation(() => {}); }); describe('parseIni', {}, () => {