Skip to content

Commit aa511bf

Browse files
fix: use OIDC for Codecov (#266)
*Issue #, if available:* *Description of changes:* Code coverage broke due to GitHub separating repository secrets from Dependabot secrets. Use the OIDC token to write code coverage data to Codecov. By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice. --------- Co-authored-by: Simon Marty <martysi@amazon.com>
1 parent 3f3c975 commit aa511bf

File tree

10 files changed

+45959
-57378
lines changed

10 files changed

+45959
-57378
lines changed

.github/workflows/tests.yml

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,10 @@ jobs:
2323
npm ci
2424
npm run test
2525
- name: Codecov
26-
uses: codecov/codecov-action@v5.4.2
27-
env:
28-
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
26+
uses: codecov/codecov-action@v5
27+
with:
28+
fail_ci_if_error: true
29+
use_oidc: true
2930

3031
uppercase-transformation-integration-test:
3132
runs-on: ubuntu-latest
@@ -41,12 +42,12 @@ jobs:
4142
name-transformation: uppercase
4243
parse-json-secrets: true
4344
secret-ids: |
44-
SampleSecret1
45-
/special/chars/secret
46-
0/special/chars/secret
47-
PrefixSecret*
48-
JsonSecret
49-
SAMPLESECRET1_ALIAS, SampleSecret1
45+
SampleSecret1
46+
/special/chars/secret
47+
0/special/chars/secret
48+
PrefixSecret*
49+
JsonSecret
50+
SAMPLESECRET1_ALIAS, SampleSecret1
5051
- name: Assert
5152
run: npm run integration-test __integration_tests__/name_transformation/uppercase.test.ts
5253

@@ -64,12 +65,12 @@ jobs:
6465
name-transformation: lowercase
6566
parse-json-secrets: true
6667
secret-ids: |
67-
SampleSecret1
68-
/special/chars/secret
69-
0/special/chars/secret
70-
PrefixSecret*
71-
JsonSecret
72-
samplesecret1_alias, SampleSecret1
68+
SampleSecret1
69+
/special/chars/secret
70+
0/special/chars/secret
71+
PrefixSecret*
72+
JsonSecret
73+
samplesecret1_alias, SampleSecret1
7374
- name: Assert
7475
run: npm run integration-test __integration_tests__/name_transformation/lowercase.test.ts
7576

@@ -87,12 +88,12 @@ jobs:
8788
name-transformation: none
8889
parse-json-secrets: true
8990
secret-ids: |
90-
SampleSecret1
91-
/special/chars/secret
92-
0/special/chars/secret
93-
PrefixSecret*
94-
JsonSecret
95-
SampleSecret1_Alias, SampleSecret1
91+
SampleSecret1
92+
/special/chars/secret
93+
0/special/chars/secret
94+
PrefixSecret*
95+
JsonSecret
96+
SampleSecret1_Alias, SampleSecret1
9697
- name: Assert
9798
run: npm run integration-test __integration_tests__/name_transformation/none.test.ts
9899

@@ -109,12 +110,12 @@ jobs:
109110
with:
110111
parse-json-secrets: true
111112
secret-ids: |
112-
SampleSecret1
113-
/special/chars/secret
114-
0/special/chars/secret
115-
PrefixSecret*
116-
JsonSecret
117-
SAMPLESECRET1_ALIAS, SampleSecret1
113+
SampleSecret1
114+
/special/chars/secret
115+
0/special/chars/secret
116+
PrefixSecret*
117+
JsonSecret
118+
SAMPLESECRET1_ALIAS, SampleSecret1
118119
- name: Assert
119120
run: npm run integration-test __integration_tests__/name_transformation/uppercase.test.ts
120121

@@ -147,6 +148,6 @@ jobs:
147148
uses: ./
148149
with:
149150
secret-ids: JsonSecret
150-
auto-select-family-attempt-timeout: '2000'
151+
auto-select-family-attempt-timeout: "2000"
151152
- name: Assert
152153
run: npm run integration-test __integration_tests__/parse_json_secrets.test.ts

__tests__/index.test.ts

Lines changed: 63 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import * as core from '@actions/core'
22
import { mockClient } from "aws-sdk-client-mock";
33
import {
44
GetSecretValueCommand, ListSecretsCommand,
5+
ResourceNotFoundException,
56
SecretsManagerClient,
67
} from '@aws-sdk/client-secrets-manager';
78
import { run } from "../src";
@@ -62,24 +63,24 @@ jest.mock('@actions/core', () => {
6263
setFailed: jest.fn(),
6364
info: jest.fn(),
6465
debug: jest.fn(),
65-
exportVariable: jest.fn((name: string, val: string) => process.env[name] = val),
66-
setSecret: jest.fn(),
66+
exportVariable: jest.fn((name: string, val: string) => process.env[name] = val),
67+
setSecret: jest.fn(),
6768
};
6869
});
6970

7071
jest.mock('net', () => {
71-
return {
72-
setDefaultAutoSelectFamilyAttemptTimeout: jest.fn()
73-
}
74-
});
72+
return {
73+
setDefaultAutoSelectFamilyAttemptTimeout: jest.fn()
74+
}
75+
});
7576

7677
describe('Test main action', () => {
7778
const OLD_ENV = process.env;
7879

7980
beforeEach(() => {
8081
jest.clearAllMocks();
8182
smMockClient.reset();
82-
process.env = {...OLD_ENV, ...DEFAULT_TEST_ENV};
83+
process.env = { ...OLD_ENV, ...DEFAULT_TEST_ENV };
8384
});
8485

8586
afterEach(() => {
@@ -89,7 +90,7 @@ describe('Test main action', () => {
8990
test('Retrieves and sets the requested secrets as environment variables, parsing JSON', async () => {
9091
const getInputSpy = jest.spyOn(core, 'getInput');
9192
getInputSpy.mockImplementation((name) => {
92-
switch(name) {
93+
switch (name) {
9394
case 'auto-select-family-attempt-timeout':
9495
return DEFAULT_TIMEOUT;
9596
case 'name-transformation':
@@ -102,14 +103,14 @@ describe('Test main action', () => {
102103
const multilineInputSpy = jest.spyOn(core, "getMultilineInput").mockReturnValue(
103104
[TEST_NAME, TEST_INPUT_3, TEST_ARN_INPUT, BLANK_ALIAS_INPUT]
104105
);
105-
106+
106107

107108
// Mock all Secrets Manager calls
108109
smMockClient
109-
.on(GetSecretValueCommand, { SecretId: TEST_NAME_1})
110+
.on(GetSecretValueCommand, { SecretId: TEST_NAME_1 })
110111
.resolves({ Name: TEST_NAME_1, SecretString: SECRET_1 })
111-
.on(GetSecretValueCommand, {SecretId: TEST_NAME_2 })
112-
.resolves({ Name: TEST_NAME_2, SecretString: SECRET_2 })
112+
.on(GetSecretValueCommand, { SecretId: TEST_NAME_2 })
113+
.resolves({ Name: TEST_NAME_2, SecretString: SECRET_2 })
113114
.on(GetSecretValueCommand, { SecretId: TEST_NAME_3 })
114115
.resolves({ Name: TEST_NAME_3, SecretString: SECRET_3 })
115116
.on(GetSecretValueCommand, { // Retrieve arn secret
@@ -215,6 +216,33 @@ describe('Test main action', () => {
215216
multilineInputSpy.mockClear();
216217
});
217218

219+
test('Fails the action when Secrets Manager GetSecretValue fails', async () => {
220+
const booleanSpy = jest.spyOn(core, "getBooleanInput").mockReturnValue(true);
221+
const multilineInputSpy = jest.spyOn(core, "getMultilineInput").mockReturnValue(
222+
[TEST_NAME, TEST_INPUT_3, TEST_ARN_INPUT]
223+
);
224+
225+
smMockClient.on(ListSecretsCommand).resolves({
226+
SecretList: [
227+
{
228+
Name: TEST_NAME_1
229+
},
230+
{
231+
Name: TEST_NAME_2
232+
}
233+
]
234+
}).on(GetSecretValueCommand)
235+
.rejects(new ResourceNotFoundException({
236+
$metadata: {}, message: "Secrets Manager can't find the specified secret."
237+
}));
238+
239+
await run();
240+
expect(core.setFailed).toHaveBeenCalledWith(expect.stringContaining("Failed to fetch secret:"));
241+
242+
booleanSpy.mockClear();
243+
multilineInputSpy.mockClear();
244+
});
245+
218246
test('Fails the action when multiple secrets exported the same variable name', async () => {
219247
const booleanSpy = jest.spyOn(core, "getBooleanInput").mockReturnValue(true);
220248
const multilineInputSpy = jest.spyOn(core, "getMultilineInput").mockReturnValue(
@@ -223,9 +251,9 @@ describe('Test main action', () => {
223251
const nameTransformationSpy = jest.spyOn(core, 'getInput').mockReturnValue('uppercase');
224252

225253
smMockClient
226-
.on(GetSecretValueCommand, { SecretId: TEST_NAME_1})
254+
.on(GetSecretValueCommand, { SecretId: TEST_NAME_1 })
227255
.resolves({ Name: TEST_NAME_1, SecretString: SECRET_1 })
228-
.on(GetSecretValueCommand, {SecretId: TEST_NAME_2 })
256+
.on(GetSecretValueCommand, { SecretId: TEST_NAME_2 })
229257
.resolves({ Name: TEST_NAME_2, SecretString: SECRET_2 })
230258
.on(GetSecretValueCommand, { SecretId: TEST_NAME_3 })
231259
.resolves({ Name: TEST_NAME_3, SecretString: SECRET_3 })
@@ -237,7 +265,7 @@ describe('Test main action', () => {
237265
SecretString: SECRET_4
238266
})
239267
.on(GetSecretValueCommand) // default
240-
.resolves({Name: "DefaultName", SecretString: "Default"})
268+
.resolves({ Name: "DefaultName", SecretString: "Default" })
241269
.on(ListSecretsCommand)
242270
.resolves({
243271
SecretList: [
@@ -259,13 +287,13 @@ describe('Test main action', () => {
259287
});
260288

261289

262-
test('Keep existing cleanup list', async() => {
290+
test('Keep existing cleanup list', async () => {
263291
// Set existing cleanup list
264-
process.env = {...process.env, SECRETS_LIST_CLEAN_UP: JSON.stringify(["EXISTING_TEST_SECRET", "EXISTING_TEST_SECRET_DB_HOST"])};
292+
process.env = { ...process.env, SECRETS_LIST_CLEAN_UP: JSON.stringify(["EXISTING_TEST_SECRET", "EXISTING_TEST_SECRET_DB_HOST"]) };
265293

266294
const getInputSpy = jest.spyOn(core, 'getInput');
267295
getInputSpy.mockImplementation((name) => {
268-
switch(name) {
296+
switch (name) {
269297
case 'auto-select-family-attempt-timeout':
270298
return DEFAULT_TIMEOUT;
271299
case 'name-transformation':
@@ -283,10 +311,10 @@ describe('Test main action', () => {
283311

284312
// Mock all Secrets Manager calls
285313
smMockClient
286-
.on(GetSecretValueCommand, { SecretId: TEST_NAME_1})
314+
.on(GetSecretValueCommand, { SecretId: TEST_NAME_1 })
287315
.resolves({ Name: TEST_NAME_1, SecretString: SECRET_1 })
288-
.on(GetSecretValueCommand, {SecretId: TEST_NAME_2 })
289-
.resolves({ Name: TEST_NAME_2, SecretString: SECRET_2 })
316+
.on(GetSecretValueCommand, { SecretId: TEST_NAME_2 })
317+
.resolves({ Name: TEST_NAME_2, SecretString: SECRET_2 })
290318
.on(GetSecretValueCommand, { SecretId: TEST_NAME_3 })
291319
.resolves({ Name: TEST_NAME_3, SecretString: SECRET_3 })
292320
.on(GetSecretValueCommand, { // Retrieve arn secret
@@ -345,19 +373,19 @@ describe('Test main action', () => {
345373
multilineInputSpy.mockClear();
346374
getInputSpy.mockClear();
347375
})
348-
376+
349377
test('handles invalid timeout string', async () => {
350378
const timeoutSpy = jest.spyOn(core, 'getInput').mockReturnValue(INVALID_TIMEOUT_STRING);
351379

352380
smMockClient
353-
.on(GetSecretValueCommand)
354-
.resolves({ SecretString: 'test' });
355-
381+
.on(GetSecretValueCommand)
382+
.resolves({ SecretString: 'test' });
383+
356384
await run();
357-
385+
358386
expect(core.setFailed).toHaveBeenCalled();
359387

360-
388+
361389
timeoutSpy.mockClear();
362390

363391
});
@@ -366,24 +394,24 @@ describe('Test main action', () => {
366394
const timeoutSpy = jest.spyOn(core, 'getInput').mockReturnValue(VALID_TIMEOUT);
367395

368396
smMockClient
369-
.on(GetSecretValueCommand)
370-
.resolves({ SecretString: 'test' });
397+
.on(GetSecretValueCommand)
398+
.resolves({ SecretString: 'test' });
371399

372400
await run();
373-
401+
374402
expect(net.setDefaultAutoSelectFamilyAttemptTimeout).toHaveBeenCalledWith(3000);
375403

376-
404+
377405
timeoutSpy.mockClear();
378406
});
379-
407+
380408

381409
test('handles invalid timeout value', async () => {
382410
const timeoutSpy = jest.spyOn(core, 'getInput').mockReturnValue(INVALID_TIMEOUT);
383411

384412
smMockClient
385-
.on(GetSecretValueCommand)
386-
.resolves({ SecretString: 'test' });
413+
.on(GetSecretValueCommand)
414+
.resolves({ SecretString: 'test' });
387415

388416
await run();
389417

@@ -392,5 +420,5 @@ describe('Test main action', () => {
392420

393421
timeoutSpy.mockClear();
394422
})
395-
423+
396424
});

0 commit comments

Comments
 (0)