Skip to content

Commit fc7405d

Browse files
committed
Allow getCheckoutPathInputOrThrow to get root from config
1 parent b07d4ae commit fc7405d

4 files changed

Lines changed: 180 additions & 19 deletions

File tree

‎lib/entry-points.js‎

Lines changed: 20 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎src/init-action-post-helper.ts‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import {
4444
} from "./util";
4545
import {
4646
getCategoryInputOrThrow,
47-
getCheckoutPathInputOrThrow,
47+
getRepositoryRootOrThrow,
4848
getUploadInputOrThrow,
4949
getWorkflow,
5050
} from "./workflow";
@@ -144,7 +144,15 @@ async function prepareFailedSarif(
144144
});
145145
}
146146
const category = getCategoryInputOrThrow(workflow, jobName, matrix);
147-
const checkoutPath = getCheckoutPathInputOrThrow(workflow, jobName, matrix);
147+
148+
// Try to determine the path at which the repository that we failed to analyse is checked out at.
149+
// We need this to relativise the paths in the SARIF.
150+
const checkoutPath = getRepositoryRootOrThrow(
151+
workflow,
152+
jobName,
153+
matrix,
154+
config,
155+
);
148156

149157
const result = await generateFailedSarif(
150158
logger,

‎src/workflow.test.ts‎

Lines changed: 124 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@ import * as sinon from "sinon";
44

55
import * as actionsUtil from "./actions-util";
66
import { createStubCodeQL, getCodeQLForTesting } from "./codeql";
7-
import { EnvVar } from "./environment";
7+
import { ActionsEnvVars, EnvVar } from "./environment";
88
import {
99
checkExpectedLogMessages,
10+
createTestConfig,
1011
getRecordingLogger,
12+
getTestEnv,
1113
LoggedMessage,
1214
setupTests,
1315
} from "./testing-utils";
@@ -1002,3 +1004,124 @@ test.serial(
10021004
t.is(messages.length, 0);
10031005
},
10041006
);
1007+
1008+
test("getRepositoryRootOrThrow - gets root from config", async (t) => {
1009+
const expectedRoot = "/path/to/root";
1010+
const repositoryRoot = workflow.getRepositoryRootOrThrow(
1011+
{},
1012+
"testJob",
1013+
{},
1014+
createTestConfig({ repositoryRoot: expectedRoot }),
1015+
getTestEnv(),
1016+
);
1017+
1018+
t.is(repositoryRoot, expectedRoot);
1019+
});
1020+
1021+
test("getRepositoryRootOrThrow - gets root from workflow", async (t) => {
1022+
const expectedRoot = "/path/to/root";
1023+
const repositoryRoot = workflow.getRepositoryRootOrThrow(
1024+
{
1025+
jobs: {
1026+
testJob: {
1027+
steps: [
1028+
{
1029+
uses: "github/codeql-action/analyze",
1030+
with: { checkout_path: expectedRoot },
1031+
},
1032+
],
1033+
},
1034+
},
1035+
},
1036+
"testJob",
1037+
{},
1038+
createTestConfig({}),
1039+
getTestEnv(),
1040+
);
1041+
1042+
t.is(repositoryRoot, expectedRoot);
1043+
});
1044+
1045+
test("getRepositoryRootOrThrow - gets root from environment", async (t) => {
1046+
const expectedRoot = "/path/to/root";
1047+
const repositoryRoot = workflow.getRepositoryRootOrThrow(
1048+
{
1049+
jobs: { testJob: { steps: [{ uses: "github/codeql-action/analyze" }] } },
1050+
},
1051+
"testJob",
1052+
{},
1053+
createTestConfig({}),
1054+
getTestEnv({ [ActionsEnvVars.GITHUB_WORKSPACE]: expectedRoot }),
1055+
);
1056+
1057+
t.is(repositoryRoot, expectedRoot);
1058+
});
1059+
1060+
test("getRepositoryRootOrThrow - throws if there's no matching job", async (t) => {
1061+
t.throws(
1062+
() =>
1063+
workflow.getRepositoryRootOrThrow(
1064+
{
1065+
jobs: {
1066+
otherJob: {
1067+
steps: [
1068+
{
1069+
uses: "github/codeql-action/analyze",
1070+
with: { checkout_path: "/some/path" },
1071+
},
1072+
],
1073+
},
1074+
},
1075+
},
1076+
"testJob",
1077+
{},
1078+
createTestConfig({}),
1079+
getTestEnv(),
1080+
),
1081+
{ message: /since the workflow has no job named testJob./ },
1082+
);
1083+
});
1084+
1085+
test("getRepositoryRootOrThrow - throws if there's no analyze step", async (t) => {
1086+
t.throws(
1087+
() =>
1088+
workflow.getRepositoryRootOrThrow(
1089+
{
1090+
jobs: {
1091+
testJob: { steps: [] },
1092+
},
1093+
},
1094+
"testJob",
1095+
{},
1096+
createTestConfig({}),
1097+
getTestEnv(),
1098+
),
1099+
{ message: /since the testJob job does not call/ },
1100+
);
1101+
});
1102+
1103+
test("getRepositoryRootOrThrow - throws if the env var is not set", async (t) => {
1104+
t.throws(
1105+
() =>
1106+
workflow.getRepositoryRootOrThrow(
1107+
{
1108+
jobs: {
1109+
testJob: {
1110+
steps: [
1111+
{
1112+
uses: "github/codeql-action/analyze",
1113+
},
1114+
],
1115+
},
1116+
},
1117+
},
1118+
"testJob",
1119+
{},
1120+
createTestConfig({}),
1121+
getTestEnv(),
1122+
),
1123+
{
1124+
message: `${ActionsEnvVars.GITHUB_WORKSPACE} environment variable must be set`,
1125+
},
1126+
);
1127+
});

‎src/workflow.ts‎

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ import * as yaml from "js-yaml";
88
import { isDynamicWorkflow } from "./actions-util";
99
import * as api from "./api-client";
1010
import { CodeQL } from "./codeql";
11-
import { EnvVar } from "./environment";
11+
import type { Config } from "./config-utils";
12+
import { ActionsEnvVars, EnvVar, getEnv, ReadOnlyEnv } from "./environment";
1213
import { Logger } from "./logging";
1314
import {
1415
getRequiredEnvParam,
@@ -441,27 +442,45 @@ export function getUploadInputOrThrow(
441442
}
442443

443444
/**
444-
* Makes a best effort attempt to retrieve the checkout_path input for the
445-
* particular job, given a set of matrix variables.
445+
* Makes a best effort attempt to determine the root path of the repository that the analysis
446+
* relates to. We need that to make paths in SARIF files relative.
447+
*
448+
* - If available, we take the `repositoryRoot` from the `config`.
449+
* - If it isn't, we fall back to trying to extract a `checkout_path` input from the `workflow`.
450+
* - Finally, we fall back to the value of `GITHUB_WORKSPACE`.
446451
*
447452
* Typically you'll want to wrap this function in a try/catch block and handle the error.
448453
*
449-
* @returns the checkout_path input
450-
* @throws an error if the checkout_path input could not be determined
454+
* @param workflow The workflow specification of the currently running workflow.
455+
* @param jobName The name of the job that is currently running.
456+
* @param matrixVars The matrix variables, if any.
457+
* @param config The CodeQL Action configuration state.
458+
* @param env The environment variables.
459+
*
460+
* @returns The repository root path, or its best approximation.
461+
* @throws `Error` if the repository root could not be determined.
451462
*/
452-
export function getCheckoutPathInputOrThrow(
463+
export function getRepositoryRootOrThrow(
453464
workflow: Workflow,
454465
jobName: string,
455466
matrixVars: { [key: string]: string } | undefined,
467+
config: Config,
468+
env: ReadOnlyEnv = getEnv(),
456469
): string {
457470
return (
471+
// If the CodeQL Action already has a persisted repository root, then we can just use that.
472+
config.repositoryRoot ??
473+
// Otherwise, try to retrieve it from a `checkout_path` input in the workflow specification.
458474
getInputOrThrow(
459475
workflow,
460476
jobName,
461477
getAnalyzeActionName(),
462478
"checkout_path",
463479
matrixVars,
464-
) || getRequiredEnvParam("GITHUB_WORKSPACE") // if unspecified, checkout_path defaults to ${{ github.workspace }}
480+
) ??
481+
// Finally, if all of the above fail, just use the value of `GITHUB_WORKSPACE` since that
482+
// is what is used by default.
483+
env.getRequired(ActionsEnvVars.GITHUB_WORKSPACE)
465484
);
466485
}
467486

0 commit comments

Comments
 (0)