Skip to content

Commit f2dba72

Browse files
feat: add use_oidc option (#113)
the OIDC token was previously not being validated in shelter in the test results endpoint, but it should be from now on.
1 parent b51d7d8 commit f2dba72

File tree

9 files changed

+137
-46
lines changed

9 files changed

+137
-46
lines changed

.github/workflows/main.yml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ on: [pull_request]
33

44
jobs:
55
run:
6-
permissions: read-all
6+
permissions:
7+
id-token: write
8+
contents: read
79
runs-on: ${{ matrix.os }}
810
strategy:
911
fail-fast: false
@@ -24,6 +26,14 @@ jobs:
2426
flags: ${{ matrix.os }}
2527
verbose: true
2628
token: ${{ secrets.CODECOV_ORG_TOKEN }}
29+
- name: Upload test results to Codecov (calculator) (oidc)
30+
uses: ./
31+
with:
32+
use_oidc: true
33+
fail_ci_if_error: true
34+
files: ./demo/calculator/junit.xml
35+
flags: ${{ matrix.os }}
36+
verbose: true
2737
- name: Upload test results to Codecov (demo)
2838
uses: ./
2939
with:

README.md

Lines changed: 46 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -38,42 +38,59 @@ steps:
3838
env:
3939
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
4040
```
41-
>**Note**: This assumes that you've set your Codecov token inside *Settings > Secrets* as `CODECOV_TOKEN`. If not, you can [get an upload token](https://docs.codecov.io/docs/frequently-asked-questions#section-where-is-the-repository-upload-token-found-) for your specific repo on [codecov.io](https://www.codecov.io). Keep in mind that secrets are *not* available to forks of repositories.
41+
> [!IMPORTANT]
42+
> This assumes that you've set your Codecov token inside *Settings > Secrets* as `CODECOV_TOKEN`. If not, you can [get an upload token](https://docs.codecov.io/docs/frequently-asked-questions#section-where-is-the-repository-upload-token-found-) for your specific repo on [codecov.io](https://www.codecov.io).
43+
> Keep in mind that secrets are *not* available to forks of repositories.
44+
> View more information on tokenless uploads [here](https://docs.codecov.com/docs/codecov-tokens#uploading-without-a-token).
45+
46+
> [!NOTE]
47+
> If you are using OIDC, you will need to set the `use_oidc` input to `true`, and make sure to add the following to your workflow file:
48+
> ```yaml
49+
> permissions:
50+
> id-token: write
51+
> contents: read
52+
> ...
53+
> steps:
54+
> - uses: codecov/test-results-action@v1
55+
> with:
56+
> use_oidc: true
57+
> ```
4258

4359
## Arguments
4460

4561
Codecov's Action supports inputs from the user. These inputs, along with their descriptions and usage contexts, are listed in the table below:
4662

4763
| Input | Description | Required |
4864
| :--- | :--- | :---: |
49-
| `token` | Repository Codecov token. Used to authorize report uploads | *Required
50-
| `binary` | The file location of a pre-downloaded version of the CLI. If specified, integrity checking will be bypassed. | Optional
51-
| `codecov_yml_path` | Specify the path to the Codecov YML | Optional
52-
| `commit_parent` | Override to specify the parent commit SHA | Optional
53-
| `directory` | Directory to search for test result reports. | Optional
54-
| `disable_search` | Disable search for test result files. This is helpful when specifying what files you want to upload with the --file option. | Optional
55-
| `dry_run` | Don't upload files to Codecov | Optional
56-
| `env_vars` | Environment variables to tag the upload with (e.g. PYTHON \| OS,PYTHON) | Optional
57-
| `exclude` | Folders to exclude from search | Optional
58-
| `fail_ci_if_error` | Specify whether or not CI build should fail if Codecov runs into an error during upload | Optional
59-
| `file` | Path to test result file to upload | Optional
60-
| `files` | Comma-separated list of files to upload | Optional
61-
| `flags` | Flag upload to group test results (e.g. py3.10 | py3.11 | py3.12) | Optional
62-
| `handle_no_reports_found` | Raise no exceptions when no test result reports found | Optional
63-
| `name` | User defined upload name. Visible in Codecov UI | Optional
64-
| `os` | Override the assumed OS. Options are linux \| macos \| windows \| . | Optional
65-
| `override_branch` | Specify the branch name | Optional
66-
| `override_build` | Specify the build number | Optional
67-
| `override_build_url` | The URL of the build where this is running | Optional
68-
| `override_commit` | Specify the commit SHA | Optional
69-
| `override_pr` | Specify the pull request number | Optional
70-
| `report_code` | The code of the report. If unsure, do not include | Optional
71-
| `root_dir` | Used when not in git/hg project to identify project root directory | Optional
72-
| `slug` | Specify the slug manually (Enterprise use) | Optional
73-
| `url` | Specify the base url to upload (Enterprise use) | Optional
74-
| `verbose` | Specify whether the Codecov output should be verbose | Optional
75-
| `version` | Specify which version of the Codecov CLI should be used. Defaults to `latest` | Optional
76-
| `working-directory` | Directory in which to execute codecov.sh | Optional
65+
| `token` | Repository Codecov token. Used to authorize report uploads | *Required
66+
| `binary` | The file location of a pre-downloaded version of the CLI. If specified, integrity checking will be bypassed. | Optional
67+
| `codecov_yml_path` | Specify the path to the Codecov YML | Optional
68+
| `commit_parent` | Override to specify the parent commit SHA | Optional
69+
| `directory` | Directory to search for test result reports. | Optional
70+
| `disable_search` | Disable search for test result files. This is helpful when specifying what files you want to upload with the --file option. | Optional
71+
| `dry_run` | Don't upload files to Codecov | Optional
72+
| `env_vars` | Environment variables to tag the upload with (e.g. PYTHON \| OS,PYTHON) | Optional
73+
| `exclude` | Folders to exclude from search | Optional
74+
| `fail_ci_if_error` | Specify whether or not CI build should fail if Codecov runs into an error during upload | Optional
75+
| `file` | Path to test result file to upload | Optional
76+
| `files` | Comma-separated list of files to upload | Optional
77+
| `flags` | Flag upload to group test results (e.g. py3.10 | py3.11 | py3.12) | Optional
78+
| `handle_no_reports_found` | Raise no exceptions when no test result reports found | Optional
79+
| `name` | User defined upload name. Visible in Codecov UI | Optional
80+
| `os` | Override the assumed OS. Options are linux \| macos \| windows \| . | Optional
81+
| `override_branch` | Specify the branch name | Optional
82+
| `override_build` | Specify the build number | Optional
83+
| `override_build_url` | The URL of the build where this is running | Optional
84+
| `override_commit` | Specify the commit SHA | Optional
85+
| `override_pr` | Specify the pull request number | Optional
86+
| `report_code` | The code of the report. If unsure, do not include | Optional
87+
| `root_dir` | Used when not in git/hg project to identify project root directory | Optional
88+
| `slug` | Specify the slug manually (Enterprise use) | Optional
89+
| `url` | Specify the base url to upload (Enterprise use) | Optional
90+
| `use_oidc` | Use OIDC to authenticate with Codecov | Optional
91+
| `verbose` | Specify whether the Codecov output should be verbose | Optional
92+
| `version` | Specify which version of the Codecov CLI should be used. Defaults to `latest` | Optional
93+
| `working-directory` | Directory in which to execute codecov.sh | Optional
7794

7895
### Example `workflow.yml` with Codecov Action
7996

action.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ inputs:
7777
url:
7878
description: 'Specify the base url to upload (Enterprise use)'
7979
required: false
80+
use_oidc:
81+
description: 'Use OIDC to authenticate with Codecov'
82+
required: false
8083
verbose:
8184
description: 'Specify whether the Codecov output should be verbose'
8285
required: false

dist/index.js

Lines changed: 38 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32148,6 +32148,16 @@ const getCommand = (filename, generalArgs, command) => {
3214832148

3214932149
;// CONCATENATED MODULE: ./src/buildExec.ts
3215032150
/* eslint-disable @typescript-eslint/no-explicit-any */
32151+
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
32152+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
32153+
return new (P || (P = Promise))(function (resolve, reject) {
32154+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
32155+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
32156+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
32157+
step((generator = generator.apply(thisArg, _arguments || [])).next());
32158+
});
32159+
};
32160+
3215132161

3215232162

3215332163

@@ -32324,15 +32334,33 @@ const buildExecutionEnvironment = (token, envVars) => {
3232432334
}
3232532335
return uploadOptions;
3232632336
};
32327-
const buildExecutionOptions = (failCi, verbose) => {
32328-
const token = core.getInput('token');
32337+
const getToken = () => __awaiter(void 0, void 0, void 0, function* () {
32338+
let token = core.getInput('token');
32339+
let url = core.getInput('url');
32340+
const useOIDC = isTrue(core.getInput('use_oidc'));
32341+
if (useOIDC) {
32342+
if (!url) {
32343+
url = 'https://codecov.io';
32344+
}
32345+
try {
32346+
token = yield core.getIDToken(url);
32347+
return Promise.resolve(token);
32348+
}
32349+
catch (err) {
32350+
setFailure(`Codecov: Failed to get OIDC token with url: ${url}. ${err.message}`, true);
32351+
}
32352+
}
32353+
return token;
32354+
});
32355+
const buildExecutionOptions = (failCi, verbose) => __awaiter(void 0, void 0, void 0, function* () {
32356+
const token = yield getToken();
3232932357
const envVars = core.getInput('env_vars');
3233032358
const cleanedEnvVars = cleanEnvVars(envVars);
3233132359
const generalArgs = buildGeneralArgs(verbose);
3233232360
const { uploadExecArgs, uploadCommand } = buildUploadArgs(token, cleanedEnvVars, failCi);
3233332361
const executionEnvironment = buildExecutionEnvironment(token, cleanedEnvVars);
3233432362
return { generalArgs, uploadCommand, uploadExecArgs, executionEnvironment };
32335-
};
32363+
});
3233632364

3233732365

3233832366
;// CONCATENATED MODULE: external "node:child_process"
@@ -32346,7 +32374,7 @@ const external_node_path_namespaceObject = require("node:path");
3234632374
// EXTERNAL MODULE: ./node_modules/undici/index.js
3234732375
var undici = __nccwpck_require__(1773);
3234832376
;// CONCATENATED MODULE: ./src/validate.ts
32349-
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
32377+
var validate_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
3235032378
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3235132379
return new (P || (P = Promise))(function (resolve, reject) {
3235232380
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
@@ -32362,7 +32390,7 @@ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argume
3236232390

3236332391

3236432392

32365-
const verify = (filename, platform, version, verbose, failCi) => __awaiter(void 0, void 0, void 0, function* () {
32393+
const verify = (filename, platform, version, verbose, failCi) => validate_awaiter(void 0, void 0, void 0, function* () {
3236632394
try {
3236732395
const uploaderName = getUploaderName(platform);
3236832396
// Get SHASUM and SHASUM signature files
@@ -32379,8 +32407,8 @@ const verify = (filename, platform, version, verbose, failCi) => __awaiter(void
3237932407
console.log(`Received SHA256SUM signature ${shaSig}`);
3238032408
}
3238132409
yield external_node_fs_namespaceObject.writeFileSync(external_node_path_namespaceObject.join(__dirname, `${uploaderName}.SHA256SUM.sig`), shaSig);
32382-
const validateSha = () => __awaiter(void 0, void 0, void 0, function* () {
32383-
const calculateHash = (filename) => __awaiter(void 0, void 0, void 0, function* () {
32410+
const validateSha = () => validate_awaiter(void 0, void 0, void 0, function* () {
32411+
const calculateHash = (filename) => validate_awaiter(void 0, void 0, void 0, function* () {
3238432412
const stream = external_node_fs_namespaceObject.createReadStream(filename);
3238532413
const uploaderSha = external_node_crypto_namespaceObject.createHash(`sha256`);
3238632414
stream.pipe(uploaderSha);
@@ -32398,7 +32426,7 @@ const verify = (filename, platform, version, verbose, failCi) => __awaiter(void
3239832426
`uploader hash: ${hash}, public hash: ${shasum}`, failCi);
3239932427
}
3240032428
});
32401-
const verifySignature = () => __awaiter(void 0, void 0, void 0, function* () {
32429+
const verifySignature = () => validate_awaiter(void 0, void 0, void 0, function* () {
3240232430
const args = [
3240332431
'--logger-fd',
3240432432
'1',
@@ -32413,7 +32441,7 @@ const verify = (filename, platform, version, verbose, failCi) => __awaiter(void
3241332441
setFailure(`Codecov: Error verifying gpg signature: ${err.message}`, failCi);
3241432442
}
3241532443
});
32416-
const importKey = () => __awaiter(void 0, void 0, void 0, function* () {
32444+
const importKey = () => validate_awaiter(void 0, void 0, void 0, function* () {
3241732445
const args = [
3241832446
'--logger-fd',
3241932447
'1',
@@ -32488,7 +32516,7 @@ var src_awaiter = (undefined && undefined.__awaiter) || function (thisArg, _argu
3248832516

3248932517
let failCi;
3249032518
const invokeCLI = (filename, failCi, verbose) => src_awaiter(void 0, void 0, void 0, function* () {
32491-
const { generalArgs, uploadCommand, uploadExecArgs, executionEnvironment } = buildExecutionOptions(failCi, verbose);
32519+
const { generalArgs, uploadCommand, uploadExecArgs, executionEnvironment } = yield buildExecutionOptions(failCi, verbose);
3249232520
const doUploadTestResults = () => src_awaiter(void 0, void 0, void 0, function* () {
3249332521
yield exec.exec(getCommand(filename, generalArgs, uploadCommand).join(' '), uploadExecArgs, executionEnvironment);
3249432522
});

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

junit.xml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<testsuites name="jest tests" tests="2" failures="0" errors="0" time="0.985">
3+
<testsuite name="undefined" errors="0" failures="0" skipped="0" timestamp="2025-03-11T16:49:44" time="0.941" tests="2">
4+
<testcase classname=" test uncovered if" name=" test uncovered if" time="0.001">
5+
</testcase>
6+
<testcase classname=" fully covered" name=" fully covered" time="0">
7+
</testcase>
8+
</testsuite>
9+
</testsuites>

src/buildExec.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,11 +62,11 @@ describe('setting up cli invocation', () => {
6262
expect(uploaderVersion).toEqual('0.1.2');
6363
});
6464

65-
test('execution options', () => {
65+
test('execution options', async () => {
6666
const failCi = true;
6767
const verbose = false;
6868
const {generalArgs, uploadCommand, uploadExecArgs, executionEnvironment} =
69-
buildExecutionOptions(failCi, verbose);
69+
await buildExecutionOptions(failCi, verbose);
7070

7171
expect(uploadCommand).toEqual('do-upload');
7272

src/buildExec.ts

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ import {
88
getPlatform,
99
getUploaderName,
1010
} from './helpers';
11+
import {
12+
setFailure,
13+
} from './helpers';
1114

1215

1316
const context = github.context;
@@ -207,8 +210,29 @@ const buildExecutionEnvironment = (token: string, envVars) => {
207210
return uploadOptions;
208211
};
209212

210-
const buildExecutionOptions = (failCi: boolean, verbose: boolean) => {
211-
const token = core.getInput('token');
213+
const getToken = async (): Promise<string> => {
214+
let token = core.getInput('token');
215+
let url = core.getInput('url');
216+
const useOIDC = isTrue(core.getInput('use_oidc'));
217+
if (useOIDC) {
218+
if (!url) {
219+
url = 'https://codecov.io';
220+
}
221+
try {
222+
token = await core.getIDToken(url);
223+
return Promise.resolve(token);
224+
} catch (err) {
225+
setFailure(
226+
`Codecov: Failed to get OIDC token with url: ${url}. ${err.message}`,
227+
true,
228+
);
229+
}
230+
}
231+
return token;
232+
};
233+
234+
const buildExecutionOptions = async (failCi: boolean, verbose: boolean) => {
235+
const token = await getToken();
212236
const envVars = core.getInput('env_vars');
213237
const cleanedEnvVars = cleanEnvVars(envVars);
214238

src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ const invokeCLI = async (
2727
verbose: boolean,
2828
) => {
2929
const {generalArgs, uploadCommand, uploadExecArgs, executionEnvironment} =
30-
buildExecutionOptions(failCi, verbose);
30+
await buildExecutionOptions(failCi, verbose);
3131

3232
const doUploadTestResults = async () => {
3333
await exec.exec(

0 commit comments

Comments
 (0)