mirror of
https://github.com/github/codeql-action.git
synced 2025-12-06 07:48:17 +08:00
Auto-fix linting errors
This commit is contained in:
File diff suppressed because one or more lines are too long
3
lib/database-upload.test.js
generated
3
lib/database-upload.test.js
generated
@@ -93,7 +93,8 @@ async function mockHttpRequests(databaseUploadStatusCode) {
|
||||
const loggedMessages = [];
|
||||
await (0, database_upload_1.uploadDatabases)(testRepoName, getTestConfig(tmpDir), testApiDetails, (0, testing_utils_1.getRecordingLogger)(loggedMessages));
|
||||
t.assert(loggedMessages.find((v) => v.type === "debug" &&
|
||||
v.message === "Database upload disabled in workflow. Skipping upload.") !== undefined);
|
||||
v.message ===
|
||||
"Database upload disabled in workflow. Skipping upload.") !== undefined);
|
||||
});
|
||||
});
|
||||
(0, ava_1.default)("Abort database upload if running against GHES", async (t) => {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -132,7 +132,7 @@ test("getRef() throws an error if only `ref` is provided as an input", async (t)
|
||||
instanceOf: Error,
|
||||
message:
|
||||
"Both 'ref' and 'sha' are required if one of them is provided.",
|
||||
}
|
||||
},
|
||||
);
|
||||
getAdditionalInputStub.restore();
|
||||
});
|
||||
@@ -153,7 +153,7 @@ test("getRef() throws an error if only `sha` is provided as an input", async (t)
|
||||
instanceOf: Error,
|
||||
message:
|
||||
"Both 'ref' and 'sha' are required if one of them is provided.",
|
||||
}
|
||||
},
|
||||
);
|
||||
getAdditionalInputStub.restore();
|
||||
});
|
||||
@@ -162,51 +162,51 @@ test("getRef() throws an error if only `sha` is provided as an input", async (t)
|
||||
test("computeAutomationID()", async (t) => {
|
||||
let actualAutomationID = computeAutomationID(
|
||||
".github/workflows/codeql-analysis.yml:analyze",
|
||||
'{"language": "javascript", "os": "linux"}'
|
||||
'{"language": "javascript", "os": "linux"}',
|
||||
);
|
||||
t.deepEqual(
|
||||
actualAutomationID,
|
||||
".github/workflows/codeql-analysis.yml:analyze/language:javascript/os:linux/"
|
||||
".github/workflows/codeql-analysis.yml:analyze/language:javascript/os:linux/",
|
||||
);
|
||||
|
||||
// check the environment sorting
|
||||
actualAutomationID = computeAutomationID(
|
||||
".github/workflows/codeql-analysis.yml:analyze",
|
||||
'{"os": "linux", "language": "javascript"}'
|
||||
'{"os": "linux", "language": "javascript"}',
|
||||
);
|
||||
t.deepEqual(
|
||||
actualAutomationID,
|
||||
".github/workflows/codeql-analysis.yml:analyze/language:javascript/os:linux/"
|
||||
".github/workflows/codeql-analysis.yml:analyze/language:javascript/os:linux/",
|
||||
);
|
||||
|
||||
// check that an empty environment produces the right results
|
||||
actualAutomationID = computeAutomationID(
|
||||
".github/workflows/codeql-analysis.yml:analyze",
|
||||
"{}"
|
||||
"{}",
|
||||
);
|
||||
t.deepEqual(
|
||||
actualAutomationID,
|
||||
".github/workflows/codeql-analysis.yml:analyze/"
|
||||
".github/workflows/codeql-analysis.yml:analyze/",
|
||||
);
|
||||
|
||||
// check non string environment values
|
||||
actualAutomationID = computeAutomationID(
|
||||
".github/workflows/codeql-analysis.yml:analyze",
|
||||
'{"number": 1, "object": {"language": "javascript"}}'
|
||||
'{"number": 1, "object": {"language": "javascript"}}',
|
||||
);
|
||||
t.deepEqual(
|
||||
actualAutomationID,
|
||||
".github/workflows/codeql-analysis.yml:analyze/number:/object:/"
|
||||
".github/workflows/codeql-analysis.yml:analyze/number:/object:/",
|
||||
);
|
||||
|
||||
// check undefined environment
|
||||
actualAutomationID = computeAutomationID(
|
||||
".github/workflows/codeql-analysis.yml:analyze",
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
t.deepEqual(
|
||||
actualAutomationID,
|
||||
".github/workflows/codeql-analysis.yml:analyze/"
|
||||
".github/workflows/codeql-analysis.yml:analyze/",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -230,7 +230,7 @@ test("isAnalyzingDefaultBranch()", async (t) => {
|
||||
repository: {
|
||||
default_branch: "main",
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
process.env["GITHUB_EVENT_PATH"] = envFile;
|
||||
|
||||
@@ -248,7 +248,7 @@ test("isAnalyzingDefaultBranch()", async (t) => {
|
||||
envFile,
|
||||
JSON.stringify({
|
||||
schedule: "0 0 * * *",
|
||||
})
|
||||
}),
|
||||
);
|
||||
process.env["GITHUB_EVENT_NAME"] = "schedule";
|
||||
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||
@@ -288,14 +288,14 @@ test("createStatusReportBase", async (t) => {
|
||||
"failure",
|
||||
new Date("May 19, 2023 05:19:00"),
|
||||
"failure cause",
|
||||
"exception stack trace"
|
||||
"exception stack trace",
|
||||
);
|
||||
|
||||
t.assert(typeof statusReport.job_run_uuid === "string");
|
||||
t.assert(statusReport.workflow_run_id === 100);
|
||||
t.assert(statusReport.workflow_run_attempt === 2);
|
||||
t.assert(
|
||||
statusReport.workflow_name === (process.env["GITHUB_WORKFLOW"] || "")
|
||||
statusReport.workflow_name === (process.env["GITHUB_WORKFLOW"] || ""),
|
||||
);
|
||||
t.assert(statusReport.job_name === (process.env["GITHUB_JOB"] || ""));
|
||||
t.assert(statusReport.analysis_key === "analysis-key");
|
||||
@@ -304,11 +304,11 @@ test("createStatusReportBase", async (t) => {
|
||||
t.assert(statusReport.action_name === "init");
|
||||
t.assert(statusReport.action_oid === "unknown");
|
||||
t.assert(
|
||||
statusReport.started_at === process.env[EnvVar.WORKFLOW_STARTED_AT]
|
||||
statusReport.started_at === process.env[EnvVar.WORKFLOW_STARTED_AT],
|
||||
);
|
||||
t.assert(
|
||||
statusReport.action_started_at ===
|
||||
new Date("May 19, 2023 05:19:00").toISOString()
|
||||
new Date("May 19, 2023 05:19:00").toISOString(),
|
||||
);
|
||||
t.assert(statusReport.status === "failure");
|
||||
t.assert(statusReport.cause === "failure cause");
|
||||
|
||||
@@ -50,7 +50,7 @@ export function getTemporaryDirectory(): string {
|
||||
*/
|
||||
export const getCommitOid = async function (
|
||||
checkoutPath: string,
|
||||
ref = "HEAD"
|
||||
ref = "HEAD",
|
||||
): Promise<string> {
|
||||
// Try to use git to get the current commit SHA. If that fails then
|
||||
// log but otherwise silently fall back to using the SHA from the environment.
|
||||
@@ -75,12 +75,12 @@ export const getCommitOid = async function (
|
||||
},
|
||||
},
|
||||
cwd: checkoutPath,
|
||||
}
|
||||
},
|
||||
).exec();
|
||||
return commitOid.trim();
|
||||
} catch (e) {
|
||||
core.info(
|
||||
"Could not determine current commit SHA using git. Continuing with data from user input or environment."
|
||||
"Could not determine current commit SHA using git. Continuing with data from user input or environment.",
|
||||
);
|
||||
core.debug(`Reason: ${(e as Error).message}`);
|
||||
core.debug((e as Error).stack || "NO STACK");
|
||||
@@ -129,7 +129,7 @@ export const determineMergeBaseCommitOid = async function (): Promise<
|
||||
},
|
||||
},
|
||||
cwd: checkoutPath,
|
||||
}
|
||||
},
|
||||
).exec();
|
||||
|
||||
// Let's confirm our assumptions: We had a merge commit and the parsed parent data looks correct
|
||||
@@ -143,7 +143,7 @@ export const determineMergeBaseCommitOid = async function (): Promise<
|
||||
return undefined;
|
||||
} catch (e) {
|
||||
core.info(
|
||||
`Failed to call git to determine merge base. Continuing with data from environment: ${e}`
|
||||
`Failed to call git to determine merge base. Continuing with data from environment: ${e}`,
|
||||
);
|
||||
core.info((e as Error).stack || "NO STACK");
|
||||
return undefined;
|
||||
@@ -168,7 +168,7 @@ export async function getRef(): Promise<string> {
|
||||
// If one of 'ref' or 'sha' are provided, both are required
|
||||
if ((hasRefInput || hasShaInput) && !(hasRefInput && hasShaInput)) {
|
||||
throw new Error(
|
||||
"Both 'ref' and 'sha' are required if one of them is provided."
|
||||
"Both 'ref' and 'sha' are required if one of them is provided.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -201,13 +201,13 @@ export async function getRef(): Promise<string> {
|
||||
sha !== head &&
|
||||
(await getCommitOid(
|
||||
checkoutPath,
|
||||
ref.replace(/^refs\/pull\//, "refs/remotes/pull/")
|
||||
ref.replace(/^refs\/pull\//, "refs/remotes/pull/"),
|
||||
)) !== head;
|
||||
|
||||
if (hasChangedRef) {
|
||||
const newRef = ref.replace(pull_ref_regex, "refs/pull/$1/head");
|
||||
core.debug(
|
||||
`No longer on merge commit, rewriting ref from ${ref} to ${newRef}.`
|
||||
`No longer on merge commit, rewriting ref from ${ref} to ${newRef}.`,
|
||||
);
|
||||
return newRef;
|
||||
} else {
|
||||
@@ -346,7 +346,7 @@ export interface DatabaseCreationTimings {
|
||||
|
||||
export function getActionsStatus(
|
||||
error?: unknown,
|
||||
otherFailureCause?: string
|
||||
otherFailureCause?: string,
|
||||
): ActionStatus {
|
||||
if (error || otherFailureCause) {
|
||||
return error instanceof UserError ? "user-error" : "failure";
|
||||
@@ -397,7 +397,7 @@ function getWorkflowEvent(): any {
|
||||
return JSON.parse(fs.readFileSync(eventJsonFile, "utf-8"));
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unable to read workflow event JSON from ${eventJsonFile}: ${e}`
|
||||
`Unable to read workflow event JSON from ${eventJsonFile}: ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -450,7 +450,7 @@ export async function printDebugLogs(config: Config) {
|
||||
if (entry.isFile()) {
|
||||
const absolutePath = path.resolve(dir, entry.name);
|
||||
core.startGroup(
|
||||
`CodeQL Debug Logs - ${language} - ${entry.name} from file at path ${absolutePath}`
|
||||
`CodeQL Debug Logs - ${language} - ${entry.name} from file at path ${absolutePath}`,
|
||||
);
|
||||
process.stdout.write(fs.readFileSync(absolutePath));
|
||||
core.endGroup();
|
||||
@@ -482,7 +482,7 @@ export function getUploadValue(input: string | undefined): UploadKind {
|
||||
return "never";
|
||||
default:
|
||||
core.warning(
|
||||
`Unrecognized 'upload' input to 'analyze' Action: ${input}. Defaulting to 'always'.`
|
||||
`Unrecognized 'upload' input to 'analyze' Action: ${input}. Defaulting to 'always'.`,
|
||||
);
|
||||
return "always";
|
||||
}
|
||||
@@ -496,12 +496,12 @@ export function getWorkflowRunID(): number {
|
||||
const workflowRunID = parseInt(workflowRunIdString, 10);
|
||||
if (Number.isNaN(workflowRunID)) {
|
||||
throw new Error(
|
||||
`GITHUB_RUN_ID must define a non NaN workflow run ID. Current value is ${workflowRunIdString}`
|
||||
`GITHUB_RUN_ID must define a non NaN workflow run ID. Current value is ${workflowRunIdString}`,
|
||||
);
|
||||
}
|
||||
if (workflowRunID < 0) {
|
||||
throw new Error(
|
||||
`GITHUB_RUN_ID must be a non-negative integer. Current value is ${workflowRunIdString}`
|
||||
`GITHUB_RUN_ID must be a non-negative integer. Current value is ${workflowRunIdString}`,
|
||||
);
|
||||
}
|
||||
return workflowRunID;
|
||||
@@ -515,12 +515,12 @@ export function getWorkflowRunAttempt(): number {
|
||||
const workflowRunAttempt = parseInt(workflowRunAttemptString, 10);
|
||||
if (Number.isNaN(workflowRunAttempt)) {
|
||||
throw new Error(
|
||||
`GITHUB_RUN_ATTEMPT must define a non NaN workflow run attempt. Current value is ${workflowRunAttemptString}`
|
||||
`GITHUB_RUN_ATTEMPT must define a non NaN workflow run attempt. Current value is ${workflowRunAttemptString}`,
|
||||
);
|
||||
}
|
||||
if (workflowRunAttempt <= 0) {
|
||||
throw new Error(
|
||||
`GITHUB_RUN_ATTEMPT must be a positive integer. Current value is ${workflowRunAttemptString}`
|
||||
`GITHUB_RUN_ATTEMPT must be a positive integer. Current value is ${workflowRunAttemptString}`,
|
||||
);
|
||||
}
|
||||
return workflowRunAttempt;
|
||||
|
||||
@@ -68,7 +68,7 @@ test("nonEmptyPaths", async (t) => {
|
||||
t.is(process.env["LGTM_INDEX_EXCLUDE"], "path4\npath5");
|
||||
t.is(
|
||||
process.env["LGTM_INDEX_FILTERS"],
|
||||
"include:path1\ninclude:path2\ninclude:**/path3\nexclude:path4\nexclude:path5\nexclude:path6/**"
|
||||
"include:path1\ninclude:path2\ninclude:**/path3\nexclude:path4\nexclude:path5\nexclude:path6/**",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -27,7 +27,7 @@ function buildIncludeExcludeEnvVar(paths: string[]): string {
|
||||
|
||||
export function printPathFiltersWarning(
|
||||
config: configUtils.Config,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
// Index include/exclude/filters only work in javascript/python/ruby.
|
||||
// If any other languages are detected/configured then show a warning.
|
||||
@@ -36,7 +36,7 @@ export function printPathFiltersWarning(
|
||||
!config.languages.every(isInterpretedLanguage)
|
||||
) {
|
||||
logger.warning(
|
||||
'The "paths"/"paths-ignore" fields of the config only have effect for JavaScript, Python, and Ruby'
|
||||
'The "paths"/"paths-ignore" fields of the config only have effect for JavaScript, Python, and Ruby',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,14 +10,14 @@ export async function run(uploadSarifDebugArtifact: Function) {
|
||||
const config = await getConfig(actionsUtil.getTemporaryDirectory(), logger);
|
||||
if (config === undefined) {
|
||||
throw new Error(
|
||||
"Config file could not be found at expected location. Did the 'init' action fail to start?"
|
||||
"Config file could not be found at expected location. Did the 'init' action fail to start?",
|
||||
);
|
||||
}
|
||||
|
||||
// Upload Actions SARIF artifacts for debugging
|
||||
if (config?.debugMode) {
|
||||
core.info(
|
||||
"Debug mode is on. Uploading available SARIF files as Actions debugging artifact..."
|
||||
"Debug mode is on. Uploading available SARIF files as Actions debugging artifact...",
|
||||
);
|
||||
const outputDir = actionsUtil.getRequiredInput("output");
|
||||
await uploadSarifDebugArtifact(config, outputDir);
|
||||
|
||||
@@ -14,7 +14,7 @@ async function runWrapper() {
|
||||
await analyzeActionPostHelper.run(debugArtifacts.uploadSarifDebugArtifact);
|
||||
} catch (error) {
|
||||
core.setFailed(
|
||||
`analyze post-action step failed: ${wrapError(error).message}`
|
||||
`analyze post-action step failed: ${wrapError(error).message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,18 +55,18 @@ export async function sendStatusReport(
|
||||
trapCacheUploadTime: number | undefined,
|
||||
dbCreationTimings: DatabaseCreationTimings | undefined,
|
||||
didUploadTrapCaches: boolean,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
const status = actionsUtil.getActionsStatus(
|
||||
error,
|
||||
stats?.analyze_failure_language
|
||||
stats?.analyze_failure_language,
|
||||
);
|
||||
const statusReportBase = await api.createStatusReportBase(
|
||||
"finish",
|
||||
status,
|
||||
startedAt,
|
||||
error?.message,
|
||||
error?.stack
|
||||
error?.stack,
|
||||
);
|
||||
const statusReport: FinishStatusReport = {
|
||||
...statusReportBase,
|
||||
@@ -83,7 +83,7 @@ export async function sendStatusReport(
|
||||
...statusReport,
|
||||
trap_cache_upload_duration_ms: Math.round(trapCacheUploadTime || 0),
|
||||
trap_cache_upload_size_bytes: Math.round(
|
||||
await getTotalCacheSize(config.trapCaches, logger)
|
||||
await getTotalCacheSize(config.trapCaches, logger),
|
||||
),
|
||||
};
|
||||
await api.sendStatusReport(trapCacheUploadStatusReport);
|
||||
@@ -119,7 +119,7 @@ function doesGoExtractionOutputExist(config: Config): boolean {
|
||||
".trap.tar.gz",
|
||||
".trap.tar.br",
|
||||
".trap.tar",
|
||||
].some((ext) => fileName.endsWith(ext))
|
||||
].some((ext) => fileName.endsWith(ext)),
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -147,20 +147,20 @@ async function runAutobuildIfLegacyGoWorkflow(config: Config, logger: Logger) {
|
||||
}
|
||||
if (dbIsFinalized(config, Language.go, logger)) {
|
||||
logger.debug(
|
||||
"Won't run Go autobuild since there is already a finalized database for Go."
|
||||
"Won't run Go autobuild since there is already a finalized database for Go.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
// This captures whether a user has added manual build steps for Go
|
||||
if (doesGoExtractionOutputExist(config)) {
|
||||
logger.debug(
|
||||
"Won't run Go autobuild since at least one file of Go code has already been extracted."
|
||||
"Won't run Go autobuild since at least one file of Go code has already been extracted.",
|
||||
);
|
||||
// If the user has run the manual build step, and has set the `CODEQL_EXTRACTOR_GO_BUILD_TRACING`
|
||||
// variable, we suggest they remove it from their workflow.
|
||||
if ("CODEQL_EXTRACTOR_GO_BUILD_TRACING" in process.env) {
|
||||
logger.warning(
|
||||
`The CODEQL_EXTRACTOR_GO_BUILD_TRACING environment variable has no effect on workflows with manual build steps, so we recommend that you remove it from your workflow.`
|
||||
`The CODEQL_EXTRACTOR_GO_BUILD_TRACING environment variable has no effect on workflows with manual build steps, so we recommend that you remove it from your workflow.`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
@@ -182,7 +182,7 @@ async function run() {
|
||||
try {
|
||||
if (
|
||||
!(await api.sendStatusReport(
|
||||
await api.createStatusReportBase("finish", "starting", startedAt)
|
||||
await api.createStatusReportBase("finish", "starting", startedAt),
|
||||
))
|
||||
) {
|
||||
return;
|
||||
@@ -190,13 +190,13 @@ async function run() {
|
||||
config = await getConfig(actionsUtil.getTemporaryDirectory(), logger);
|
||||
if (config === undefined) {
|
||||
throw new Error(
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?"
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?",
|
||||
);
|
||||
}
|
||||
|
||||
if (hasBadExpectErrorInput()) {
|
||||
throw new Error(
|
||||
"`expect-error` input parameter is for internal use only. It should only be set by codeql-action or a fork."
|
||||
"`expect-error` input parameter is for internal use only. It should only be set by codeql-action or a fork.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -204,11 +204,11 @@ async function run() {
|
||||
const outputDir = actionsUtil.getRequiredInput("output");
|
||||
const threads = util.getThreadsFlag(
|
||||
actionsUtil.getOptionalInput("threads") || process.env["CODEQL_THREADS"],
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
const repositoryNwo = parseRepositoryNwo(
|
||||
util.getRequiredEnvParam("GITHUB_REPOSITORY")
|
||||
util.getRequiredEnvParam("GITHUB_REPOSITORY"),
|
||||
);
|
||||
|
||||
const gitHubVersion = await getGitHubVersion();
|
||||
@@ -217,12 +217,12 @@ async function run() {
|
||||
gitHubVersion,
|
||||
repositoryNwo,
|
||||
actionsUtil.getTemporaryDirectory(),
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
const memory = util.getMemoryFlag(
|
||||
actionsUtil.getOptionalInput("ram") || process.env["CODEQL_RAM"],
|
||||
await features.getValue(Feature.ScalingReservedRamEnabled)
|
||||
await features.getValue(Feature.ScalingReservedRamEnabled),
|
||||
);
|
||||
|
||||
await runAutobuildIfLegacyGoWorkflow(config, logger);
|
||||
@@ -233,7 +233,7 @@ async function run() {
|
||||
memory,
|
||||
config,
|
||||
logger,
|
||||
features
|
||||
features,
|
||||
);
|
||||
|
||||
if (actionsUtil.getRequiredInput("skip-queries") !== "true") {
|
||||
@@ -245,7 +245,7 @@ async function run() {
|
||||
actionsUtil.getOptionalInput("category"),
|
||||
config,
|
||||
logger,
|
||||
features
|
||||
features,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -253,7 +253,7 @@ async function run() {
|
||||
await runCleanup(
|
||||
config,
|
||||
actionsUtil.getOptionalInput("cleanup-level") || "brutal",
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -268,7 +268,7 @@ async function run() {
|
||||
outputDir,
|
||||
actionsUtil.getRequiredInput("checkout_path"),
|
||||
actionsUtil.getOptionalInput("category"),
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
core.setOutput("sarif-id", uploadResult.sarifID);
|
||||
} else {
|
||||
@@ -294,13 +294,13 @@ async function run() {
|
||||
await uploadLib.waitForProcessing(
|
||||
parseRepositoryNwo(util.getRequiredEnvParam("GITHUB_REPOSITORY")),
|
||||
uploadResult.sarifID,
|
||||
getActionsLogger()
|
||||
getActionsLogger(),
|
||||
);
|
||||
}
|
||||
// If we did not throw an error yet here, but we expect one, throw it.
|
||||
if (actionsUtil.getOptionalInput("expect-error") === "true") {
|
||||
core.setFailed(
|
||||
`expect-error input was set to true but no error was thrown.`
|
||||
`expect-error input was set to true but no error was thrown.`,
|
||||
);
|
||||
}
|
||||
core.exportVariable(EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY, "true");
|
||||
@@ -323,7 +323,7 @@ async function run() {
|
||||
trapCacheUploadTime,
|
||||
dbCreationTimings,
|
||||
didUploadTrapCaches,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
} else {
|
||||
await sendStatusReport(
|
||||
@@ -334,7 +334,7 @@ async function run() {
|
||||
trapCacheUploadTime,
|
||||
dbCreationTimings,
|
||||
didUploadTrapCaches,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -353,7 +353,7 @@ async function run() {
|
||||
trapCacheUploadTime,
|
||||
dbCreationTimings,
|
||||
didUploadTrapCaches,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
} else if (runStats) {
|
||||
await sendStatusReport(
|
||||
@@ -364,7 +364,7 @@ async function run() {
|
||||
trapCacheUploadTime,
|
||||
dbCreationTimings,
|
||||
didUploadTrapCaches,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
} else {
|
||||
await sendStatusReport(
|
||||
@@ -375,7 +375,7 @@ async function run() {
|
||||
trapCacheUploadTime,
|
||||
dbCreationTimings,
|
||||
didUploadTrapCaches,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,14 +50,14 @@ test("status report fields and search path setting", async (t) => {
|
||||
packDownload: async () => ({ packs: [] }),
|
||||
databaseRunQueries: async (
|
||||
_db: string,
|
||||
searchPath: string | undefined
|
||||
searchPath: string | undefined,
|
||||
) => {
|
||||
searchPathsUsed.push(searchPath);
|
||||
},
|
||||
databaseInterpretResults: async (
|
||||
_db: string,
|
||||
_queriesRun: string[],
|
||||
sarifFile: string
|
||||
sarifFile: string,
|
||||
) => {
|
||||
fs.writeFileSync(
|
||||
sarifFile,
|
||||
@@ -94,7 +94,7 @@ test("status report fields and search path setting", async (t) => {
|
||||
},
|
||||
{},
|
||||
],
|
||||
})
|
||||
}),
|
||||
);
|
||||
return "";
|
||||
},
|
||||
@@ -142,7 +142,7 @@ test("status report fields and search path setting", async (t) => {
|
||||
undefined,
|
||||
config,
|
||||
getRunnerLogger(true),
|
||||
createFeatures([Feature.QaTelemetryEnabled])
|
||||
createFeatures([Feature.QaTelemetryEnabled]),
|
||||
);
|
||||
const hasPacks = language in packs;
|
||||
const statusReportKeys = Object.keys(builtinStatusReport).sort();
|
||||
@@ -150,26 +150,26 @@ test("status report fields and search path setting", async (t) => {
|
||||
t.deepEqual(statusReportKeys.length, 4, statusReportKeys.toString());
|
||||
t.deepEqual(
|
||||
statusReportKeys[0],
|
||||
`analyze_builtin_queries_${language}_duration_ms`
|
||||
`analyze_builtin_queries_${language}_duration_ms`,
|
||||
);
|
||||
t.deepEqual(
|
||||
statusReportKeys[1],
|
||||
`analyze_custom_queries_${language}_duration_ms`
|
||||
`analyze_custom_queries_${language}_duration_ms`,
|
||||
);
|
||||
t.deepEqual(statusReportKeys[2], "event_reports");
|
||||
t.deepEqual(
|
||||
statusReportKeys[3],
|
||||
`interpret_results_${language}_duration_ms`
|
||||
`interpret_results_${language}_duration_ms`,
|
||||
);
|
||||
} else {
|
||||
t.deepEqual(
|
||||
statusReportKeys[0],
|
||||
`analyze_builtin_queries_${language}_duration_ms`
|
||||
`analyze_builtin_queries_${language}_duration_ms`,
|
||||
);
|
||||
t.deepEqual(statusReportKeys[1], "event_reports");
|
||||
t.deepEqual(
|
||||
statusReportKeys[2],
|
||||
`interpret_results_${language}_duration_ms`
|
||||
`interpret_results_${language}_duration_ms`,
|
||||
);
|
||||
}
|
||||
if (builtinStatusReport.event_reports) {
|
||||
@@ -201,11 +201,11 @@ test("status report fields and search path setting", async (t) => {
|
||||
undefined,
|
||||
config,
|
||||
getRunnerLogger(true),
|
||||
createFeatures([Feature.QaTelemetryEnabled])
|
||||
createFeatures([Feature.QaTelemetryEnabled]),
|
||||
);
|
||||
t.deepEqual(Object.keys(customStatusReport).length, 3);
|
||||
t.true(
|
||||
`analyze_custom_queries_${language}_duration_ms` in customStatusReport
|
||||
`analyze_custom_queries_${language}_duration_ms` in customStatusReport,
|
||||
);
|
||||
const expectedSearchPathsUsed = hasPacks
|
||||
? [undefined, undefined, "/1", "/2", undefined]
|
||||
@@ -245,12 +245,12 @@ test("status report fields and search path setting", async (t) => {
|
||||
function readContents(name: string) {
|
||||
const x = fs.readFileSync(
|
||||
path.join(tmpDir, "codeql_databases", name),
|
||||
"utf8"
|
||||
"utf8",
|
||||
);
|
||||
console.log(x);
|
||||
|
||||
return yaml.load(
|
||||
fs.readFileSync(path.join(tmpDir, "codeql_databases", name), "utf8")
|
||||
fs.readFileSync(path.join(tmpDir, "codeql_databases", name), "utf8"),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -294,7 +294,7 @@ function createBaseConfig(tmpDir: string): Config {
|
||||
|
||||
function createQueryConfig(
|
||||
builtin: string[],
|
||||
custom: string[]
|
||||
custom: string[],
|
||||
): { builtin: string[]; custom: QueriesWithSearchPath[] } {
|
||||
return {
|
||||
builtin,
|
||||
@@ -304,7 +304,7 @@ function createQueryConfig(
|
||||
|
||||
async function runQueriesWithConfig(
|
||||
config: Config,
|
||||
features: Feature[]
|
||||
features: Feature[],
|
||||
): Promise<QueriesStatusReport> {
|
||||
for (const language of config.languages) {
|
||||
fs.mkdirSync(util.getCodeQLDatabasePath(config, language), {
|
||||
@@ -319,7 +319,7 @@ async function runQueriesWithConfig(
|
||||
undefined,
|
||||
config,
|
||||
getRunnerLogger(true),
|
||||
createFeatures(features)
|
||||
createFeatures(features),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ test("optimizeForLastQueryRun for one language", async (t) => {
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true]
|
||||
[true],
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -355,7 +355,7 @@ test("optimizeForLastQueryRun for two languages", async (t) => {
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true, true]
|
||||
[true, true],
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -372,7 +372,7 @@ test("optimizeForLastQueryRun for two languages, with custom queries", async (t)
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[false, false, true, false, true]
|
||||
[false, false, true, false, true],
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -390,7 +390,7 @@ test("optimizeForLastQueryRun for two languages, with custom queries and packs",
|
||||
await runQueriesWithConfig(config, []);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[false, false, false, true, false, false, true]
|
||||
[false, false, false, true, false, false, true],
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -405,7 +405,7 @@ test("optimizeForLastQueryRun for one language, CliConfigFileEnabled", async (t)
|
||||
await runQueriesWithConfig(config, [Feature.CliConfigFileEnabled]);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true]
|
||||
[true],
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -420,7 +420,7 @@ test("optimizeForLastQueryRun for two languages, CliConfigFileEnabled", async (t
|
||||
await runQueriesWithConfig(config, [Feature.CliConfigFileEnabled]);
|
||||
t.deepEqual(
|
||||
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||
[true, true]
|
||||
[true, true],
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -466,14 +466,14 @@ test("validateQueryFilters", (t) => {
|
||||
},
|
||||
]);
|
||||
},
|
||||
{ message: /Query filter must have exactly one key/ }
|
||||
{ message: /Query filter must have exactly one key/ },
|
||||
);
|
||||
|
||||
t.throws(
|
||||
() => {
|
||||
return validateQueryFilters([{ xxx: "foo" } as any]);
|
||||
},
|
||||
{ message: /Only "include" or "exclude" filters are allowed/ }
|
||||
{ message: /Only "include" or "exclude" filters are allowed/ },
|
||||
);
|
||||
|
||||
t.throws(
|
||||
@@ -484,7 +484,7 @@ test("validateQueryFilters", (t) => {
|
||||
{
|
||||
message:
|
||||
/Query filters must be an array of "include" or "exclude" entries/,
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -581,7 +581,7 @@ test("createQuerySuiteContents", (t) => {
|
||||
{
|
||||
include: { "problem.severity": "recommendation" },
|
||||
},
|
||||
]
|
||||
],
|
||||
);
|
||||
const expected = `- query: query1.ql
|
||||
- query: query2.ql
|
||||
|
||||
@@ -91,7 +91,7 @@ export interface QueriesStatusReport {
|
||||
async function setupPythonExtractor(
|
||||
logger: Logger,
|
||||
features: FeatureEnablement,
|
||||
codeql: CodeQL
|
||||
codeql: CodeQL,
|
||||
) {
|
||||
const codeqlPython = process.env["CODEQL_PYTHON"];
|
||||
if (codeqlPython === undefined || codeqlPython.length === 0) {
|
||||
@@ -102,12 +102,12 @@ async function setupPythonExtractor(
|
||||
if (
|
||||
await features.getValue(
|
||||
Feature.DisablePythonDependencyInstallationEnabled,
|
||||
codeql
|
||||
codeql,
|
||||
)
|
||||
) {
|
||||
logger.warning(
|
||||
"We recommend that you remove the CODEQL_PYTHON environment variable from your workflow. This environment variable was originally used to specify a Python executable that included the dependencies of your Python code, however Python analysis no longer uses these dependencies." +
|
||||
"\nIf you used CODEQL_PYTHON to force the version of Python to analyze as, please use CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION instead, such as 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=2.7' or 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=3.11'."
|
||||
"\nIf you used CODEQL_PYTHON to force the version of Python to analyze as, please use CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION instead, such as 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=2.7' or 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=3.11'.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -126,7 +126,7 @@ async function setupPythonExtractor(
|
||||
await new toolrunner.ToolRunner(
|
||||
codeqlPython,
|
||||
[path.join(scriptsFolder, "find_site_packages.py")],
|
||||
options
|
||||
options,
|
||||
).exec();
|
||||
logger.info(`Setting LGTM_INDEX_IMPORT_PATH=${output}`);
|
||||
process.env["LGTM_INDEX_IMPORT_PATH"] = output;
|
||||
@@ -135,7 +135,7 @@ async function setupPythonExtractor(
|
||||
await new toolrunner.ToolRunner(
|
||||
codeqlPython,
|
||||
["-c", "import sys; print(sys.version_info[0])"],
|
||||
options
|
||||
options,
|
||||
).exec();
|
||||
logger.info(`Setting LGTM_PYTHON_SETUP_VERSION=${output}`);
|
||||
process.env["LGTM_PYTHON_SETUP_VERSION"] = output;
|
||||
@@ -145,7 +145,7 @@ export async function createdDBForScannedLanguages(
|
||||
codeql: CodeQL,
|
||||
config: configUtils.Config,
|
||||
logger: Logger,
|
||||
features: FeatureEnablement
|
||||
features: FeatureEnablement,
|
||||
) {
|
||||
// Insert the LGTM_INDEX_X env vars at this point so they are set when
|
||||
// we extract any scanned languages.
|
||||
@@ -171,17 +171,17 @@ export async function createdDBForScannedLanguages(
|
||||
export function dbIsFinalized(
|
||||
config: configUtils.Config,
|
||||
language: Language,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
const dbPath = util.getCodeQLDatabasePath(config, language);
|
||||
try {
|
||||
const dbInfo = yaml.load(
|
||||
fs.readFileSync(path.resolve(dbPath, "codeql-database.yml"), "utf8")
|
||||
fs.readFileSync(path.resolve(dbPath, "codeql-database.yml"), "utf8"),
|
||||
) as { inProgress?: boolean };
|
||||
return !("inProgress" in dbInfo);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Could not check whether database for ${language} was finalized. Assuming it is not.`
|
||||
`Could not check whether database for ${language} was finalized. Assuming it is not.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -192,7 +192,7 @@ async function finalizeDatabaseCreation(
|
||||
threadsFlag: string,
|
||||
memoryFlag: string,
|
||||
logger: Logger,
|
||||
features: FeatureEnablement
|
||||
features: FeatureEnablement,
|
||||
): Promise<DatabaseCreationTimings> {
|
||||
const codeql = await getCodeQL(config.codeQLCmd);
|
||||
|
||||
@@ -204,14 +204,14 @@ async function finalizeDatabaseCreation(
|
||||
for (const language of config.languages) {
|
||||
if (dbIsFinalized(config, language, logger)) {
|
||||
logger.info(
|
||||
`There is already a finalized database for ${language} at the location where the CodeQL Action places databases, so we did not create one.`
|
||||
`There is already a finalized database for ${language} at the location where the CodeQL Action places databases, so we did not create one.`,
|
||||
);
|
||||
} else {
|
||||
logger.startGroup(`Finalizing ${language}`);
|
||||
await codeql.finalizeDatabase(
|
||||
util.getCodeQLDatabasePath(config, language),
|
||||
threadsFlag,
|
||||
memoryFlag
|
||||
memoryFlag,
|
||||
);
|
||||
logger.endGroup();
|
||||
}
|
||||
@@ -233,7 +233,7 @@ export async function runQueries(
|
||||
automationDetailsId: string | undefined,
|
||||
config: configUtils.Config,
|
||||
logger: Logger,
|
||||
features: FeatureEnablement
|
||||
features: FeatureEnablement,
|
||||
): Promise<QueriesStatusReport> {
|
||||
const statusReport: QueriesStatusReport = {};
|
||||
|
||||
@@ -245,7 +245,7 @@ export async function runQueries(
|
||||
for (const language of config.languages) {
|
||||
const queries = config.queries[language];
|
||||
const queryFilters = validateQueryFilters(
|
||||
config.originalUserInput["query-filters"]
|
||||
config.originalUserInput["query-filters"],
|
||||
);
|
||||
const packsWithVersion = config.packs[language] || [];
|
||||
|
||||
@@ -273,7 +273,7 @@ export async function runQueries(
|
||||
language,
|
||||
undefined,
|
||||
sarifFile,
|
||||
config.debugMode
|
||||
config.debugMode,
|
||||
);
|
||||
endTimeInterpretResults = new Date();
|
||||
statusReport[`interpret_results_${language}_duration_ms`] =
|
||||
@@ -294,7 +294,7 @@ export async function runQueries(
|
||||
!hasPackWithCustomQueries
|
||||
) {
|
||||
throw new Error(
|
||||
`Unable to analyze ${language} as no queries were selected for this language`
|
||||
`Unable to analyze ${language} as no queries were selected for this language`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -315,8 +315,8 @@ export async function runQueries(
|
||||
"builtin",
|
||||
createQuerySuiteContents(queries.builtin, queryFilters),
|
||||
undefined,
|
||||
customQueryIndices.length === 0 && packsWithVersion.length === 0
|
||||
)) as string
|
||||
customQueryIndices.length === 0 && packsWithVersion.length === 0,
|
||||
)) as string,
|
||||
);
|
||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||
new Date().getTime() - startTimeBuiltIn;
|
||||
@@ -331,8 +331,8 @@ export async function runQueries(
|
||||
createQuerySuiteContents(queries.custom[i].queries, queryFilters),
|
||||
queries.custom[i].searchPath,
|
||||
i === customQueryIndices[customQueryIndices.length - 1] &&
|
||||
packsWithVersion.length === 0
|
||||
)) as string
|
||||
packsWithVersion.length === 0,
|
||||
)) as string,
|
||||
);
|
||||
ranCustom = true;
|
||||
}
|
||||
@@ -343,8 +343,8 @@ export async function runQueries(
|
||||
"packs",
|
||||
packsWithVersion,
|
||||
queryFilters,
|
||||
true
|
||||
)
|
||||
true,
|
||||
),
|
||||
);
|
||||
ranCustom = true;
|
||||
}
|
||||
@@ -359,7 +359,7 @@ export async function runQueries(
|
||||
language,
|
||||
querySuitePaths,
|
||||
sarifFile,
|
||||
config.debugMode
|
||||
config.debugMode,
|
||||
);
|
||||
endTimeInterpretResults = new Date();
|
||||
statusReport[`interpret_results_${language}_duration_ms`] =
|
||||
@@ -397,7 +397,7 @@ export async function runQueries(
|
||||
statusReport.analyze_failure_language = language;
|
||||
throw new CodeQLAnalysisError(
|
||||
statusReport,
|
||||
`Error running analysis for ${language}: ${e}`
|
||||
`Error running analysis for ${language}: ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -408,7 +408,7 @@ export async function runQueries(
|
||||
language: Language,
|
||||
queries: string[] | undefined,
|
||||
sarifFile: string,
|
||||
enableDebugLogging: boolean
|
||||
enableDebugLogging: boolean,
|
||||
): Promise<string> {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
return await codeql.databaseInterpretResults(
|
||||
@@ -421,18 +421,18 @@ export async function runQueries(
|
||||
automationDetailsId,
|
||||
config,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
/** Get an object with all queries and their counts parsed from a SARIF file path. */
|
||||
function getPerQueryAlertCounts(
|
||||
sarifPath: string,
|
||||
log: Logger
|
||||
log: Logger,
|
||||
): Record<string, number> {
|
||||
validateSarifFileSchema(sarifPath, log);
|
||||
const sarifObject = JSON.parse(
|
||||
fs.readFileSync(sarifPath, "utf8")
|
||||
fs.readFileSync(sarifPath, "utf8"),
|
||||
) as util.SarifFile;
|
||||
// We do not need to compute fingerprints because we are not sending data based off of locations.
|
||||
|
||||
@@ -463,7 +463,7 @@ export async function runQueries(
|
||||
type: string,
|
||||
querySuiteContents: string | undefined,
|
||||
searchPath: string | undefined,
|
||||
optimizeForLastQueryRun: boolean
|
||||
optimizeForLastQueryRun: boolean,
|
||||
): Promise<string | undefined> {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
// Pass the queries to codeql using a file instead of using the command
|
||||
@@ -474,7 +474,7 @@ export async function runQueries(
|
||||
if (querySuiteContents && querySuitePath) {
|
||||
fs.writeFileSync(querySuitePath, querySuiteContents);
|
||||
logger.debug(
|
||||
`Query suite file for ${language}-${type}...\n${querySuiteContents}`
|
||||
`Query suite file for ${language}-${type}...\n${querySuiteContents}`,
|
||||
);
|
||||
}
|
||||
await codeql.databaseRunQueries(
|
||||
@@ -482,7 +482,7 @@ export async function runQueries(
|
||||
searchPath,
|
||||
querySuitePath,
|
||||
queryFlags,
|
||||
optimizeForLastQueryRun
|
||||
optimizeForLastQueryRun,
|
||||
);
|
||||
|
||||
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
||||
@@ -493,7 +493,7 @@ export async function runQueries(
|
||||
type: string,
|
||||
packs: string[],
|
||||
queryFilters: configUtils.QueryFilter[],
|
||||
optimizeForLastQueryRun: boolean
|
||||
optimizeForLastQueryRun: boolean,
|
||||
): Promise<string> {
|
||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||
|
||||
@@ -516,7 +516,7 @@ export async function runQueries(
|
||||
undefined,
|
||||
querySuitePath,
|
||||
queryFlags,
|
||||
optimizeForLastQueryRun
|
||||
optimizeForLastQueryRun,
|
||||
);
|
||||
|
||||
return querySuitePath;
|
||||
@@ -524,7 +524,7 @@ export async function runQueries(
|
||||
}
|
||||
|
||||
export function convertPackToQuerySuiteEntry(
|
||||
packStr: string
|
||||
packStr: string,
|
||||
): configUtils.QuerySuitePackEntry {
|
||||
const pack = configUtils.parsePacksSpecification(packStr);
|
||||
return {
|
||||
@@ -542,10 +542,10 @@ export function convertPackToQuerySuiteEntry(
|
||||
|
||||
export function createQuerySuiteContents(
|
||||
queries: string[],
|
||||
queryFilters: configUtils.QueryFilter[]
|
||||
queryFilters: configUtils.QueryFilter[],
|
||||
) {
|
||||
return yaml.dump(
|
||||
queries.map((q: string) => ({ query: q })).concat(queryFilters as any[])
|
||||
queries.map((q: string) => ({ query: q })).concat(queryFilters as any[]),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -555,7 +555,7 @@ export async function runFinalize(
|
||||
memoryFlag: string,
|
||||
config: configUtils.Config,
|
||||
logger: Logger,
|
||||
features: FeatureEnablement
|
||||
features: FeatureEnablement,
|
||||
): Promise<DatabaseCreationTimings> {
|
||||
try {
|
||||
await del(outputDir, { force: true });
|
||||
@@ -571,7 +571,7 @@ export async function runFinalize(
|
||||
threadsFlag,
|
||||
memoryFlag,
|
||||
logger,
|
||||
features
|
||||
features,
|
||||
);
|
||||
|
||||
// WARNING: This does not _really_ end tracing, as the tracer will restore its
|
||||
@@ -587,7 +587,7 @@ export async function runFinalize(
|
||||
export async function runCleanup(
|
||||
config: configUtils.Config,
|
||||
cleanupLevel: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
logger.startGroup("Cleaning up databases");
|
||||
for (const language of config.languages) {
|
||||
@@ -606,7 +606,7 @@ export function validateQueryFilters(queryFilters?: configUtils.QueryFilter[]) {
|
||||
|
||||
if (!Array.isArray(queryFilters)) {
|
||||
throw new Error(
|
||||
`Query filters must be an array of "include" or "exclude" entries. Found ${typeof queryFilters}`
|
||||
`Query filters must be an array of "include" or "exclude" entries. Found ${typeof queryFilters}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -615,14 +615,14 @@ export function validateQueryFilters(queryFilters?: configUtils.QueryFilter[]) {
|
||||
const keys = Object.keys(qf);
|
||||
if (keys.length !== 1) {
|
||||
errors.push(
|
||||
`Query filter must have exactly one key: ${JSON.stringify(qf)}`
|
||||
`Query filter must have exactly one key: ${JSON.stringify(qf)}`,
|
||||
);
|
||||
}
|
||||
if (!["exclude", "include"].includes(keys[0])) {
|
||||
errors.push(
|
||||
`Only "include" or "exclude" filters are allowed:\n${JSON.stringify(
|
||||
qf
|
||||
)}`
|
||||
qf,
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,12 +36,12 @@ test("getApiClient", async (t) => {
|
||||
baseUrl: "http://api.github.localhost",
|
||||
log: sinon.match.any,
|
||||
userAgent: `CodeQL-Action/${actionsUtil.getActionVersion()}`,
|
||||
})
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
function mockGetMetaVersionHeader(
|
||||
versionHeader: string | undefined
|
||||
versionHeader: string | undefined,
|
||||
): sinon.SinonStub<any, any> {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
const client = github.getOctokit("123");
|
||||
@@ -67,7 +67,7 @@ test("getGitHubVersion for Dotcom", async (t) => {
|
||||
sinon.stub(api, "getApiDetails").returns(apiDetails);
|
||||
const v = await api.getGitHubVersionFromApi(
|
||||
github.getOctokit("123"),
|
||||
apiDetails
|
||||
apiDetails,
|
||||
);
|
||||
t.deepEqual(util.GitHubVariant.DOTCOM, v.type);
|
||||
});
|
||||
@@ -81,7 +81,7 @@ test("getGitHubVersion for GHES", async (t) => {
|
||||
});
|
||||
t.deepEqual(
|
||||
{ type: util.GitHubVariant.GHES, version: "2.0" } as util.GitHubVersion,
|
||||
v2
|
||||
v2,
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ export interface GitHubApiExternalRepoDetails {
|
||||
|
||||
function createApiClientWithDetails(
|
||||
apiDetails: GitHubApiCombinedDetails,
|
||||
{ allowExternal = false } = {}
|
||||
{ allowExternal = false } = {},
|
||||
) {
|
||||
const auth =
|
||||
(allowExternal && apiDetails.externalRepoAuth) || apiDetails.auth;
|
||||
@@ -64,7 +64,7 @@ function createApiClientWithDetails(
|
||||
baseUrl: apiDetails.apiURL,
|
||||
userAgent: `CodeQL-Action/${getActionVersion()}`,
|
||||
log: consoleLogLevel({ level: "debug" }),
|
||||
})
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ export function getApiClient() {
|
||||
}
|
||||
|
||||
export function getApiClientWithExternalAuth(
|
||||
apiDetails: GitHubApiCombinedDetails
|
||||
apiDetails: GitHubApiCombinedDetails,
|
||||
) {
|
||||
return createApiClientWithDetails(apiDetails, { allowExternal: true });
|
||||
}
|
||||
@@ -90,7 +90,7 @@ let cachedGitHubVersion: GitHubVersion | undefined = undefined;
|
||||
|
||||
export async function getGitHubVersionFromApi(
|
||||
apiClient: any,
|
||||
apiDetails: GitHubApiDetails
|
||||
apiDetails: GitHubApiDetails,
|
||||
): Promise<GitHubVersion> {
|
||||
// We can avoid making an API request in the standard dotcom case
|
||||
if (parseGitHubUrl(apiDetails.url) === GITHUB_DOTCOM_URL) {
|
||||
@@ -130,7 +130,7 @@ export async function getGitHubVersion(): Promise<GitHubVersion> {
|
||||
if (cachedGitHubVersion === undefined) {
|
||||
cachedGitHubVersion = await getGitHubVersionFromApi(
|
||||
getApiClient(),
|
||||
getApiDetails()
|
||||
getApiDetails(),
|
||||
);
|
||||
}
|
||||
return cachedGitHubVersion;
|
||||
@@ -150,7 +150,7 @@ export async function createStatusReportBase(
|
||||
status: ActionStatus,
|
||||
actionStartedAt: Date,
|
||||
cause?: string,
|
||||
exception?: string
|
||||
exception?: string,
|
||||
): Promise<StatusReportBase> {
|
||||
const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || "";
|
||||
const ref = await getRef();
|
||||
@@ -248,7 +248,7 @@ const INCOMPATIBLE_MSG =
|
||||
* Returns whether sending the status report was successful of not.
|
||||
*/
|
||||
export async function sendStatusReport<S extends StatusReportBase>(
|
||||
statusReport: S
|
||||
statusReport: S,
|
||||
): Promise<boolean> {
|
||||
const statusReportJSON = JSON.stringify(statusReport);
|
||||
core.debug(`Sending status report: ${statusReportJSON}`);
|
||||
@@ -269,7 +269,7 @@ export async function sendStatusReport<S extends StatusReportBase>(
|
||||
owner,
|
||||
repo,
|
||||
data: statusReportJSON,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return true;
|
||||
@@ -286,7 +286,7 @@ export async function sendStatusReport<S extends StatusReportBase>(
|
||||
'Workflows triggered by Dependabot on the "push" event run with read-only access. ' +
|
||||
"Uploading Code Scanning results requires write access. " +
|
||||
'To use Code Scanning with Dependabot, please ensure you are using the "pull_request" event for this workflow and avoid triggering on the "push" event for Dependabot branches. ' +
|
||||
"See https://docs.github.com/en/code-security/secure-coding/configuring-code-scanning#scanning-on-push for more information on how to configure these events."
|
||||
"See https://docs.github.com/en/code-security/secure-coding/configuring-code-scanning#scanning-on-push for more information on how to configure these events.",
|
||||
);
|
||||
} else {
|
||||
core.setFailed(e.message || GENERIC_403_MSG);
|
||||
@@ -311,7 +311,7 @@ export async function sendStatusReport<S extends StatusReportBase>(
|
||||
// something else has gone wrong and the request/response will be logged by octokit
|
||||
// it's possible this is a transient error and we should continue scanning
|
||||
core.error(
|
||||
"An unexpected error occurred when sending code scanning status report."
|
||||
"An unexpected error occurred when sending code scanning status report.",
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -333,7 +333,7 @@ export async function getWorkflowRelativePath(): Promise<string> {
|
||||
owner,
|
||||
repo,
|
||||
run_id,
|
||||
}
|
||||
},
|
||||
);
|
||||
const workflowUrl = runsResponse.data.workflow_url;
|
||||
|
||||
@@ -374,7 +374,7 @@ export async function getAutomationID(): Promise<string> {
|
||||
|
||||
export function computeAutomationID(
|
||||
analysis_key: string,
|
||||
environment: string | undefined
|
||||
environment: string | undefined,
|
||||
): string {
|
||||
let automationID = `${analysis_key}/`;
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ async function sendCompletedStatusReport(
|
||||
startedAt: Date,
|
||||
allLanguages: string[],
|
||||
failingLanguage?: string,
|
||||
cause?: Error
|
||||
cause?: Error,
|
||||
) {
|
||||
initializeEnvironment(getActionVersion());
|
||||
|
||||
@@ -44,7 +44,7 @@ async function sendCompletedStatusReport(
|
||||
status,
|
||||
startedAt,
|
||||
cause?.message,
|
||||
cause?.stack
|
||||
cause?.stack,
|
||||
);
|
||||
const statusReport: AutobuildStatusReport = {
|
||||
...statusReportBase,
|
||||
@@ -62,7 +62,7 @@ async function run() {
|
||||
try {
|
||||
if (
|
||||
!(await sendStatusReport(
|
||||
await createStatusReportBase("autobuild", "starting", startedAt)
|
||||
await createStatusReportBase("autobuild", "starting", startedAt),
|
||||
))
|
||||
) {
|
||||
return;
|
||||
@@ -74,7 +74,7 @@ async function run() {
|
||||
const config = await configUtils.getConfig(getTemporaryDirectory(), logger);
|
||||
if (config === undefined) {
|
||||
throw new Error(
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?"
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ async function run() {
|
||||
const workingDirectory = getOptionalInput("working-directory");
|
||||
if (workingDirectory) {
|
||||
logger.info(
|
||||
`Changing autobuilder working directory to ${workingDirectory}`
|
||||
`Changing autobuilder working directory to ${workingDirectory}`,
|
||||
);
|
||||
process.chdir(workingDirectory);
|
||||
}
|
||||
@@ -98,13 +98,13 @@ async function run() {
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
core.setFailed(
|
||||
`We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error.message}`
|
||||
`We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error.message}`,
|
||||
);
|
||||
await sendCompletedStatusReport(
|
||||
startedAt,
|
||||
languages ?? [],
|
||||
currentLanguage,
|
||||
error
|
||||
error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5,19 +5,19 @@ import { Logger } from "./logging";
|
||||
|
||||
export async function determineAutobuildLanguages(
|
||||
config: configUtils.Config,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Language[] | undefined> {
|
||||
// Attempt to find a language to autobuild
|
||||
// We want pick the dominant language in the repo from the ones we're able to build
|
||||
// The languages are sorted in order specified by user or by lines of code if we got
|
||||
// them from the GitHub API, so try to build the first language on the list.
|
||||
const autobuildLanguages = config.languages.filter((l) =>
|
||||
isTracedLanguage(l)
|
||||
isTracedLanguage(l),
|
||||
);
|
||||
|
||||
if (!autobuildLanguages) {
|
||||
logger.info(
|
||||
"None of the languages in this project require extra build steps"
|
||||
"None of the languages in this project require extra build steps",
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -50,7 +50,7 @@ export async function determineAutobuildLanguages(
|
||||
* version of the CodeQL Action.
|
||||
*/
|
||||
const autobuildLanguagesWithoutGo = autobuildLanguages.filter(
|
||||
(l) => l !== Language.go
|
||||
(l) => l !== Language.go,
|
||||
);
|
||||
|
||||
const languages: Language[] = [];
|
||||
@@ -77,14 +77,14 @@ export async function determineAutobuildLanguages(
|
||||
if (autobuildLanguagesWithoutGo.length > 1) {
|
||||
logger.warning(
|
||||
`We will only automatically build ${languages.join(
|
||||
" and "
|
||||
" and ",
|
||||
)} code. If you wish to scan ${autobuildLanguagesWithoutGo
|
||||
.slice(1)
|
||||
.join(
|
||||
" and "
|
||||
" and ",
|
||||
)}, you must replace the autobuild step of your workflow with custom build steps. ` +
|
||||
"For more information, see " +
|
||||
"https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language"
|
||||
"https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-the-codeql-workflow-for-compiled-languages#adding-build-steps-for-a-compiled-language",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ export async function determineAutobuildLanguages(
|
||||
export async function runAutobuild(
|
||||
language: Language,
|
||||
config: configUtils.Config,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
logger.startGroup(`Attempting to automatically build ${language} code`);
|
||||
const codeQL = await getCodeQL(config.codeQLCmd);
|
||||
|
||||
@@ -93,7 +93,7 @@ async function installIntoToolcache({
|
||||
? { cliVersion, tagName }
|
||||
: SAMPLE_DEFAULT_CLI_VERSION,
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ test("downloads and caches explicitly requested bundles that aren't in the toolc
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
t.assert(toolcache.find("CodeQL", `0.0.0-${version}`));
|
||||
@@ -185,7 +185,7 @@ test("downloads an explicitly requested bundle even if a different version is ca
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
t.assert(toolcache.find("CodeQL", "0.0.0-20200610"));
|
||||
t.deepEqual(result.toolsVersion, "0.0.0-20200610");
|
||||
@@ -235,7 +235,7 @@ for (const {
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
t.assert(releaseApiMock.isDone(), "Releases API should have been called");
|
||||
t.assert(toolcache.find("CodeQL", expectedToolcacheVersion));
|
||||
@@ -272,13 +272,13 @@ for (const toolcacheVersion of [
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
t.is(result.toolsVersion, SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
|
||||
t.is(result.toolsSource, ToolsSource.Toolcache);
|
||||
t.is(result.toolsDownloadDurationMs, undefined);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -303,7 +303,7 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
t.deepEqual(result.toolsVersion, "0.0.0-20200601");
|
||||
t.is(result.toolsSource, ToolsSource.Toolcache);
|
||||
@@ -337,7 +337,7 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
t.deepEqual(result.toolsVersion, defaults.cliVersion);
|
||||
t.is(result.toolsSource, ToolsSource.Download);
|
||||
@@ -369,7 +369,7 @@ test('downloads bundle if "latest" tools specified but not cached', async (t) =>
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
t.deepEqual(result.toolsVersion, defaults.cliVersion);
|
||||
t.is(result.toolsSource, ToolsSource.Download);
|
||||
@@ -404,7 +404,7 @@ for (const isBundleVersionInUrl of [true, false]) {
|
||||
|
||||
nock("https://example.githubenterprise.com")
|
||||
.get(
|
||||
`/api/v3/enterprise/code-scanning/codeql-bundle/find/${defaults.bundleVersion}`
|
||||
`/api/v3/enterprise/code-scanning/codeql-bundle/find/${defaults.bundleVersion}`,
|
||||
)
|
||||
.reply(200, {
|
||||
assets: { [codeQLBundleName]: bundleAssetID },
|
||||
@@ -412,7 +412,7 @@ for (const isBundleVersionInUrl of [true, false]) {
|
||||
|
||||
nock("https://example.githubenterprise.com")
|
||||
.get(
|
||||
`/api/v3/enterprise/code-scanning/codeql-bundle/download/${bundleAssetID}`
|
||||
`/api/v3/enterprise/code-scanning/codeql-bundle/download/${bundleAssetID}`,
|
||||
)
|
||||
.reply(200, {
|
||||
url: eventualDownloadUrl,
|
||||
@@ -422,12 +422,12 @@ for (const isBundleVersionInUrl of [true, false]) {
|
||||
.get(
|
||||
eventualDownloadUrl.replace(
|
||||
"https://example.githubenterprise.com",
|
||||
""
|
||||
)
|
||||
"",
|
||||
),
|
||||
)
|
||||
.replyWithFile(
|
||||
200,
|
||||
path.join(__dirname, `/../src/testdata/codeql-bundle-pinned.tar.gz`)
|
||||
path.join(__dirname, `/../src/testdata/codeql-bundle-pinned.tar.gz`),
|
||||
);
|
||||
|
||||
mockApiDetails(sampleGHAEApiDetails);
|
||||
@@ -444,7 +444,7 @@ for (const isBundleVersionInUrl of [true, false]) {
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
t.is(result.toolsSource, ToolsSource.Download);
|
||||
@@ -479,7 +479,7 @@ test("bundle URL from another repo is cached as 0.0.0-bundleVersion", async (t)
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
getRunnerLogger(true),
|
||||
false
|
||||
false,
|
||||
);
|
||||
|
||||
t.is(result.toolsVersion, "0.0.0-20230203");
|
||||
@@ -501,7 +501,7 @@ test("getExtraOptions works for explicit paths", (t) => {
|
||||
|
||||
t.deepEqual(
|
||||
codeql.getExtraOptions({ foo: { bar: [42] } }, ["foo", "bar"], []),
|
||||
["42"]
|
||||
["42"],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -530,8 +530,8 @@ test("getExtraOptions throws for bad content", (t) => {
|
||||
codeql.getExtraOptions(
|
||||
{ "*": [42], foo: { "*": 87, bar: [99] } },
|
||||
["foo", "bar"],
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -559,13 +559,13 @@ test("databaseInitCluster() without injected codescanning config", async (t) =>
|
||||
undefined,
|
||||
createFeatures([]),
|
||||
"/path/to/qlconfig.yml",
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
const args = runnerConstructorStub.firstCall.args[1];
|
||||
// should NOT have used an config file
|
||||
const configArg = args.find((arg: string) =>
|
||||
arg.startsWith("--codescanning-config=")
|
||||
arg.startsWith("--codescanning-config="),
|
||||
);
|
||||
t.falsy(configArg, "Should NOT have injected a codescanning config");
|
||||
});
|
||||
@@ -577,7 +577,7 @@ const injectedConfigMacro = test.macro({
|
||||
t: ExecutionContext<unknown>,
|
||||
augmentationProperties: AugmentationProperties,
|
||||
configOverride: Partial<Config>,
|
||||
expectedConfig: any
|
||||
expectedConfig: any,
|
||||
) => {
|
||||
await util.withTmpDir(async (tempDir) => {
|
||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||
@@ -599,13 +599,13 @@ const injectedConfigMacro = test.macro({
|
||||
undefined,
|
||||
createFeatures([Feature.CliConfigFileEnabled]),
|
||||
undefined,
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
const args = runnerConstructorStub.firstCall.args[1] as string[];
|
||||
// should have used an config file
|
||||
const configArg = args.find((arg: string) =>
|
||||
arg.startsWith("--codescanning-config=")
|
||||
arg.startsWith("--codescanning-config="),
|
||||
);
|
||||
t.truthy(configArg, "Should have injected a codescanning config");
|
||||
const configFile = configArg!.split("=")[1];
|
||||
@@ -629,7 +629,7 @@ test(
|
||||
packsInputCombines: false,
|
||||
},
|
||||
{},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -643,7 +643,7 @@ test(
|
||||
{},
|
||||
{
|
||||
packs: ["codeql/javascript-experimental-atm-queries@~0.4.0"],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -666,7 +666,7 @@ test(
|
||||
"codeql/javascript-experimental-atm-queries@~0.4.0",
|
||||
],
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -687,7 +687,7 @@ test(
|
||||
cpp: ["codeql/something-else"],
|
||||
javascript: ["codeql/javascript-experimental-atm-queries@~0.4.0"],
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -702,7 +702,7 @@ test(
|
||||
{},
|
||||
{
|
||||
packs: ["xxx", "yyy"],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -725,7 +725,7 @@ test(
|
||||
packs: {
|
||||
cpp: ["codeql/something-else", "xxx", "yyy"],
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -746,7 +746,7 @@ test(
|
||||
},
|
||||
{
|
||||
packs: ["xxx", "yyy"],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -767,7 +767,7 @@ test(
|
||||
},
|
||||
{
|
||||
packs: ["xxx", "yyy", "codeql/javascript-experimental-atm-queries@~0.4.0"],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
// similar, but with queries
|
||||
@@ -790,7 +790,7 @@ test(
|
||||
uses: "yyy",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -816,7 +816,7 @@ test(
|
||||
uses: "yyy",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -845,7 +845,7 @@ test(
|
||||
uses: "yyy",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -867,7 +867,7 @@ test(
|
||||
uses: "yyy",
|
||||
},
|
||||
],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
@@ -886,7 +886,7 @@ test(
|
||||
queries: [],
|
||||
},
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
|
||||
test("does not pass a code scanning config or qlconfig file to the CLI when CLI config passing is disabled", async (t: ExecutionContext<unknown>) => {
|
||||
@@ -902,19 +902,19 @@ test("does not pass a code scanning config or qlconfig file to the CLI when CLI
|
||||
undefined,
|
||||
createFeatures([]),
|
||||
"/path/to/qlconfig.yml",
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
const args = runnerConstructorStub.firstCall.args[1];
|
||||
// should not have used a config file
|
||||
const hasConfigArg = args.some((arg: string) =>
|
||||
arg.startsWith("--codescanning-config=")
|
||||
arg.startsWith("--codescanning-config="),
|
||||
);
|
||||
t.false(hasConfigArg, "Should NOT have injected a codescanning config");
|
||||
|
||||
// should not have passed a qlconfig file
|
||||
const hasQlconfigArg = args.some((arg: string) =>
|
||||
arg.startsWith("--qlconfig-file=")
|
||||
arg.startsWith("--qlconfig-file="),
|
||||
);
|
||||
t.false(hasQlconfigArg, "Should NOT have passed a qlconfig file");
|
||||
});
|
||||
@@ -934,19 +934,19 @@ test("passes a code scanning config AND qlconfig to the CLI when CLI config pass
|
||||
undefined,
|
||||
createFeatures([Feature.CliConfigFileEnabled]),
|
||||
"/path/to/qlconfig.yml",
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
const args = runnerConstructorStub.firstCall.args[1];
|
||||
// should have used a config file
|
||||
const hasCodeScanningConfigArg = args.some((arg: string) =>
|
||||
arg.startsWith("--codescanning-config=")
|
||||
arg.startsWith("--codescanning-config="),
|
||||
);
|
||||
t.true(hasCodeScanningConfigArg, "Should have injected a qlconfig");
|
||||
|
||||
// should have passed a qlconfig file
|
||||
const hasQlconfigArg = args.some((arg: string) =>
|
||||
arg.startsWith("--qlconfig-file=")
|
||||
arg.startsWith("--qlconfig-file="),
|
||||
);
|
||||
t.truthy(hasQlconfigArg, "Should have injected a codescanning config");
|
||||
});
|
||||
@@ -964,22 +964,22 @@ test("passes a code scanning config BUT NOT a qlconfig to the CLI when CLI confi
|
||||
undefined,
|
||||
createFeatures([Feature.CliConfigFileEnabled]),
|
||||
"/path/to/qlconfig.yml",
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
const args = runnerConstructorStub.firstCall.args[1] as any[];
|
||||
// should have used a config file
|
||||
const hasCodeScanningConfigArg = args.some((arg: string) =>
|
||||
arg.startsWith("--codescanning-config=")
|
||||
arg.startsWith("--codescanning-config="),
|
||||
);
|
||||
t.true(
|
||||
hasCodeScanningConfigArg,
|
||||
"Should have injected a codescanning config"
|
||||
"Should have injected a codescanning config",
|
||||
);
|
||||
|
||||
// should not have passed a qlconfig file
|
||||
const hasQlconfigArg = args.some((arg: string) =>
|
||||
arg.startsWith("--qlconfig-file=")
|
||||
arg.startsWith("--qlconfig-file="),
|
||||
);
|
||||
t.false(hasQlconfigArg, "should NOT have injected a qlconfig");
|
||||
});
|
||||
@@ -999,12 +999,12 @@ test("does not pass a qlconfig to the CLI when it is undefined", async (t: Execu
|
||||
undefined,
|
||||
createFeatures([Feature.CliConfigFileEnabled]),
|
||||
undefined, // undefined qlconfigFile
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
const args = runnerConstructorStub.firstCall.args[1] as any[];
|
||||
const hasQlconfigArg = args.some((arg: string) =>
|
||||
arg.startsWith("--qlconfig-file=")
|
||||
arg.startsWith("--qlconfig-file="),
|
||||
);
|
||||
t.false(hasQlconfigArg, "should NOT have injected a qlconfig");
|
||||
});
|
||||
@@ -1026,13 +1026,13 @@ test("databaseInterpretResults() sets --sarif-add-baseline-file-info for 2.11.3"
|
||||
"",
|
||||
stubConfig,
|
||||
createFeatures([]),
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.true(
|
||||
runnerConstructorStub.firstCall.args[1].includes(
|
||||
"--sarif-add-baseline-file-info"
|
||||
"--sarif-add-baseline-file-info",
|
||||
),
|
||||
"--sarif-add-baseline-file-info should be present, but it is absent"
|
||||
"--sarif-add-baseline-file-info should be present, but it is absent",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1052,13 +1052,13 @@ test("databaseInterpretResults() does not set --sarif-add-baseline-file-info for
|
||||
"",
|
||||
stubConfig,
|
||||
createFeatures([]),
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.false(
|
||||
runnerConstructorStub.firstCall.args[1].includes(
|
||||
"--sarif-add-baseline-file-info"
|
||||
"--sarif-add-baseline-file-info",
|
||||
),
|
||||
"--sarif-add-baseline-file-info must be absent, but it is present"
|
||||
"--sarif-add-baseline-file-info must be absent, but it is present",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1113,23 +1113,23 @@ for (const {
|
||||
"",
|
||||
stubConfig,
|
||||
createFeatures(featureEnabled ? [Feature.NewAnalysisSummaryEnabled] : []),
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.is(
|
||||
runnerConstructorStub.firstCall.args[1].includes(
|
||||
"--new-analysis-summary"
|
||||
"--new-analysis-summary",
|
||||
),
|
||||
flagPassed,
|
||||
`--new-analysis-summary should${flagPassed ? "" : "n't"} be passed`
|
||||
`--new-analysis-summary should${flagPassed ? "" : "n't"} be passed`,
|
||||
);
|
||||
t.is(
|
||||
runnerConstructorStub.firstCall.args[1].includes(
|
||||
"--no-new-analysis-summary"
|
||||
"--no-new-analysis-summary",
|
||||
),
|
||||
negativeFlagPassed,
|
||||
`--no-new-analysis-summary should${
|
||||
negativeFlagPassed ? "" : "n't"
|
||||
} be passed`
|
||||
} be passed`,
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1140,7 +1140,7 @@ test("database finalize recognises JavaScript no code found error on CodeQL 2.11
|
||||
`2020-09-07T17:39:53.9050522Z [2020-09-07 17:39:53] [build] Done extracting /opt/hostedtoolcache/CodeQL/0.0.0-20200630/x64/codeql/javascript/tools/data/externs/web/ie_vml.js (3 ms)
|
||||
2020-09-07T17:39:53.9051849Z [2020-09-07 17:39:53] [build-err] No JavaScript or TypeScript code found.
|
||||
2020-09-07T17:39:53.9052444Z [2020-09-07 17:39:53] [build-err] No JavaScript or TypeScript code found.
|
||||
2020-09-07T17:39:53.9251124Z [2020-09-07 17:39:53] [ERROR] Spawned process exited abnormally (code 255; tried to run: [/opt/hostedtoolcache/CodeQL/0.0.0-20200630/x64/codeql/javascript/tools/autobuild.sh])`
|
||||
2020-09-07T17:39:53.9251124Z [2020-09-07 17:39:53] [ERROR] Spawned process exited abnormally (code 255; tried to run: [/opt/hostedtoolcache/CodeQL/0.0.0-20200630/x64/codeql/javascript/tools/autobuild.sh])`,
|
||||
);
|
||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||
sinon.stub(codeqlObject, "getVersion").resolves("2.11.6");
|
||||
@@ -1153,7 +1153,7 @@ test("database finalize recognises JavaScript no code found error on CodeQL 2.11
|
||||
message:
|
||||
"No code found during the build. Please see: " +
|
||||
"https://gh.io/troubleshooting-code-scanning/no-source-code-seen-during-build",
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1170,7 +1170,7 @@ test("database finalize overrides no code found error on CodeQL 2.11.6", async (
|
||||
message:
|
||||
"No code found during the build. Please see: " +
|
||||
"https://gh.io/troubleshooting-code-scanning/no-source-code-seen-during-build",
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1191,7 +1191,7 @@ test("database finalize does not override no code found error on CodeQL 2.12.4",
|
||||
message:
|
||||
'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
|
||||
`Exit code was 32 and error was: ${cliMessage}`,
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1216,13 +1216,13 @@ test("runTool summarizes several fatal errors", async (t) => {
|
||||
message:
|
||||
'Encountered a fatal error while running "codeql-for-testing database finalize --finalize-dataset --threads=2 --ram=2048 db". ' +
|
||||
`Exit code was 32 and error was: ${datasetImportError}. Context: ${heapError}.`,
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
export function stubToolRunnerConstructor(
|
||||
exitCode: number = 0,
|
||||
stderr?: string
|
||||
stderr?: string,
|
||||
): sinon.SinonStub<any[], toolrunner.ToolRunner> {
|
||||
const runnerObjectStub = sinon.createStubInstance(toolrunner.ToolRunner);
|
||||
const runnerConstructorStub = sinon.stub(toolrunner, "ToolRunner");
|
||||
|
||||
138
src/codeql.ts
138
src/codeql.ts
@@ -49,14 +49,14 @@ export class CommandInvocationError extends Error {
|
||||
args: string[],
|
||||
public exitCode: number,
|
||||
public error: string,
|
||||
public output: string
|
||||
public output: string,
|
||||
) {
|
||||
const prettyCommand = [cmd, ...args]
|
||||
.map((x) => (x.includes(" ") ? `'${x}'` : x))
|
||||
.join(" ");
|
||||
super(
|
||||
`Encountered a fatal error while running "${prettyCommand}". ` +
|
||||
`Exit code was ${exitCode} and error was: ${error.trim()}`
|
||||
`Exit code was ${exitCode} and error was: ${error.trim()}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ export interface CodeQL {
|
||||
processName: string | undefined,
|
||||
features: FeatureEnablement,
|
||||
qlconfigFile: string | undefined,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Runs the autobuilder for the given language.
|
||||
@@ -100,7 +100,7 @@ export interface CodeQL {
|
||||
finalizeDatabase(
|
||||
databasePath: string,
|
||||
threadsFlag: string,
|
||||
memoryFlag: string
|
||||
memoryFlag: string,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Run 'codeql resolve languages'.
|
||||
@@ -115,14 +115,14 @@ export interface CodeQL {
|
||||
*/
|
||||
resolveQueries(
|
||||
queries: string[],
|
||||
extraSearchPath: string | undefined
|
||||
extraSearchPath: string | undefined,
|
||||
): Promise<ResolveQueriesOutput>;
|
||||
/**
|
||||
* Run 'codeql resolve build-environment'
|
||||
*/
|
||||
resolveBuildEnvironment(
|
||||
workingDir: string | undefined,
|
||||
language: Language
|
||||
language: Language,
|
||||
): Promise<ResolveBuildEnvironmentOutput>;
|
||||
|
||||
/**
|
||||
@@ -130,7 +130,7 @@ export interface CodeQL {
|
||||
*/
|
||||
packDownload(
|
||||
packs: string[],
|
||||
qlconfigFile: string | undefined
|
||||
qlconfigFile: string | undefined,
|
||||
): Promise<PackDownloadOutput>;
|
||||
|
||||
/**
|
||||
@@ -143,7 +143,7 @@ export interface CodeQL {
|
||||
databaseBundle(
|
||||
databasePath: string,
|
||||
outputFilePath: string,
|
||||
dbName: string
|
||||
dbName: string,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Run 'codeql database run-queries'.
|
||||
@@ -159,7 +159,7 @@ export interface CodeQL {
|
||||
extraSearchPath: string | undefined,
|
||||
querySuitePath: string | undefined,
|
||||
flags: string[],
|
||||
optimizeForLastQueryRun: boolean
|
||||
optimizeForLastQueryRun: boolean,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Run 'codeql database interpret-results'.
|
||||
@@ -174,7 +174,7 @@ export interface CodeQL {
|
||||
automationDetailsId: string | undefined,
|
||||
config: Config,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<string>;
|
||||
/**
|
||||
* Run 'codeql database print-baseline'.
|
||||
@@ -191,7 +191,7 @@ export interface CodeQL {
|
||||
sarifFile: string,
|
||||
automationDetailsId: string | undefined,
|
||||
tempDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<void>;
|
||||
/**
|
||||
* Run 'codeql diagnostics export'.
|
||||
@@ -199,7 +199,7 @@ export interface CodeQL {
|
||||
diagnosticsExport(
|
||||
sarifFile: string,
|
||||
automationDetailsId: string | undefined,
|
||||
config: Config
|
||||
config: Config,
|
||||
): Promise<void>;
|
||||
/** Get the location of an extractor for the specified language. */
|
||||
resolveExtractor(language: Language): Promise<string>;
|
||||
@@ -215,7 +215,7 @@ export interface BetterResolveLanguagesOutput {
|
||||
{
|
||||
extractor_root: string;
|
||||
extractor_options?: any;
|
||||
}
|
||||
},
|
||||
];
|
||||
};
|
||||
}
|
||||
@@ -338,7 +338,7 @@ export async function setupCodeQL(
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
logger: Logger,
|
||||
checkVersion: boolean
|
||||
checkVersion: boolean,
|
||||
): Promise<{
|
||||
codeql: CodeQL;
|
||||
toolsDownloadDurationMs?: number;
|
||||
@@ -353,7 +353,7 @@ export async function setupCodeQL(
|
||||
tempDir,
|
||||
variant,
|
||||
defaultCliVersion,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql");
|
||||
if (process.platform === "win32") {
|
||||
@@ -371,7 +371,7 @@ export async function setupCodeQL(
|
||||
};
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unable to download and extract CodeQL CLI: ${wrapError(e).message}`
|
||||
`Unable to download and extract CodeQL CLI: ${wrapError(e).message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -389,7 +389,7 @@ export async function getCodeQL(cmd: string): Promise<CodeQL> {
|
||||
function resolveFunction<T>(
|
||||
partialCodeql: Partial<CodeQL>,
|
||||
methodName: string,
|
||||
defaultImplementation?: T
|
||||
defaultImplementation?: T,
|
||||
): T {
|
||||
if (typeof partialCodeql[methodName] !== "function") {
|
||||
if (defaultImplementation !== undefined) {
|
||||
@@ -415,25 +415,25 @@ export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
|
||||
getVersion: resolveFunction(
|
||||
partialCodeql,
|
||||
"getVersion",
|
||||
() => new Promise((resolve) => resolve("1.0.0"))
|
||||
() => new Promise((resolve) => resolve("1.0.0")),
|
||||
),
|
||||
printVersion: resolveFunction(partialCodeql, "printVersion"),
|
||||
databaseInitCluster: resolveFunction(partialCodeql, "databaseInitCluster"),
|
||||
runAutobuild: resolveFunction(partialCodeql, "runAutobuild"),
|
||||
extractScannedLanguage: resolveFunction(
|
||||
partialCodeql,
|
||||
"extractScannedLanguage"
|
||||
"extractScannedLanguage",
|
||||
),
|
||||
finalizeDatabase: resolveFunction(partialCodeql, "finalizeDatabase"),
|
||||
resolveLanguages: resolveFunction(partialCodeql, "resolveLanguages"),
|
||||
betterResolveLanguages: resolveFunction(
|
||||
partialCodeql,
|
||||
"betterResolveLanguages"
|
||||
"betterResolveLanguages",
|
||||
),
|
||||
resolveQueries: resolveFunction(partialCodeql, "resolveQueries"),
|
||||
resolveBuildEnvironment: resolveFunction(
|
||||
partialCodeql,
|
||||
"resolveBuildEnvironment"
|
||||
"resolveBuildEnvironment",
|
||||
),
|
||||
packDownload: resolveFunction(partialCodeql, "packDownload"),
|
||||
databaseCleanup: resolveFunction(partialCodeql, "databaseCleanup"),
|
||||
@@ -441,15 +441,15 @@ export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
|
||||
databaseRunQueries: resolveFunction(partialCodeql, "databaseRunQueries"),
|
||||
databaseInterpretResults: resolveFunction(
|
||||
partialCodeql,
|
||||
"databaseInterpretResults"
|
||||
"databaseInterpretResults",
|
||||
),
|
||||
databasePrintBaseline: resolveFunction(
|
||||
partialCodeql,
|
||||
"databasePrintBaseline"
|
||||
"databasePrintBaseline",
|
||||
),
|
||||
databaseExportDiagnostics: resolveFunction(
|
||||
partialCodeql,
|
||||
"databaseExportDiagnostics"
|
||||
"databaseExportDiagnostics",
|
||||
),
|
||||
diagnosticsExport: resolveFunction(partialCodeql, "diagnosticsExport"),
|
||||
resolveExtractor: resolveFunction(partialCodeql, "resolveExtractor"),
|
||||
@@ -477,7 +477,7 @@ export function getCachedCodeQL(): CodeQL {
|
||||
* should also stub the toolrunner.ToolRunner constructor.
|
||||
*/
|
||||
export async function getCodeQLForTesting(
|
||||
cmd = "codeql-for-testing"
|
||||
cmd = "codeql-for-testing",
|
||||
): Promise<CodeQL> {
|
||||
return getCodeQLForCmd(cmd, false);
|
||||
}
|
||||
@@ -492,7 +492,7 @@ export async function getCodeQLForTesting(
|
||||
*/
|
||||
export async function getCodeQLForCmd(
|
||||
cmd: string,
|
||||
checkVersion: boolean
|
||||
checkVersion: boolean,
|
||||
): Promise<CodeQL> {
|
||||
const codeql: CodeQL = {
|
||||
getPath() {
|
||||
@@ -515,10 +515,10 @@ export async function getCodeQLForCmd(
|
||||
processName: string | undefined,
|
||||
features: FeatureEnablement,
|
||||
qlconfigFile: string | undefined,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
const extraArgs = config.languages.map(
|
||||
(language) => `--language=${language}`
|
||||
(language) => `--language=${language}`,
|
||||
);
|
||||
if (config.languages.filter((l) => isTracedLanguage(l)).length > 0) {
|
||||
extraArgs.push("--begin-tracing");
|
||||
@@ -530,14 +530,14 @@ export async function getCodeQLForCmd(
|
||||
// when tracing Go on Windows on these CodeQL versions.
|
||||
(await util.codeQlVersionAbove(
|
||||
this,
|
||||
CODEQL_VERSION_LUA_TRACER_CONFIG
|
||||
CODEQL_VERSION_LUA_TRACER_CONFIG,
|
||||
)) &&
|
||||
config.languages.includes(Language.go) &&
|
||||
isTracedLanguage(Language.go) &&
|
||||
process.platform === "win32" &&
|
||||
!(await util.codeQlVersionAbove(
|
||||
this,
|
||||
CODEQL_VERSION_LUA_TRACING_GO_WINDOWS_FIXED
|
||||
CODEQL_VERSION_LUA_TRACING_GO_WINDOWS_FIXED,
|
||||
))
|
||||
) {
|
||||
extraArgs.push("--no-internal-use-lua-tracing");
|
||||
@@ -549,7 +549,7 @@ export async function getCodeQLForCmd(
|
||||
codeql,
|
||||
config,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
// Only pass external repository token if a config file is going to be parsed by the CLI.
|
||||
let externalRepositoryToken: string | undefined;
|
||||
@@ -578,14 +578,14 @@ export async function getCodeQLForCmd(
|
||||
...extraArgs,
|
||||
...getExtraOptionsFromEnv(["database", "init"]),
|
||||
],
|
||||
{ stdin: externalRepositoryToken }
|
||||
{ stdin: externalRepositoryToken },
|
||||
);
|
||||
},
|
||||
async runAutobuild(language: Language) {
|
||||
const autobuildCmd = path.join(
|
||||
await this.resolveExtractor(language),
|
||||
"tools",
|
||||
process.platform === "win32" ? "autobuild.cmd" : "autobuild.sh"
|
||||
process.platform === "win32" ? "autobuild.cmd" : "autobuild.sh",
|
||||
);
|
||||
|
||||
// Update JAVA_TOOL_OPTIONS to contain '-Dhttp.keepAlive=false'
|
||||
@@ -624,7 +624,7 @@ export async function getCodeQLForCmd(
|
||||
const traceCommand = path.resolve(
|
||||
await this.resolveExtractor(language),
|
||||
"tools",
|
||||
`autobuild${ext}`
|
||||
`autobuild${ext}`,
|
||||
);
|
||||
// Run trace command
|
||||
await runTool(cmd, [
|
||||
@@ -640,7 +640,7 @@ export async function getCodeQLForCmd(
|
||||
async finalizeDatabase(
|
||||
databasePath: string,
|
||||
threadsFlag: string,
|
||||
memoryFlag: string
|
||||
memoryFlag: string,
|
||||
) {
|
||||
const args = [
|
||||
"database",
|
||||
@@ -658,13 +658,13 @@ export async function getCodeQLForCmd(
|
||||
e instanceof CommandInvocationError &&
|
||||
!(await util.codeQlVersionAbove(
|
||||
this,
|
||||
CODEQL_VERSION_BETTER_NO_CODE_ERROR_MESSAGE
|
||||
CODEQL_VERSION_BETTER_NO_CODE_ERROR_MESSAGE,
|
||||
)) &&
|
||||
isNoCodeFoundError(e)
|
||||
) {
|
||||
throw new util.UserError(
|
||||
"No code found during the build. Please see: " +
|
||||
"https://gh.io/troubleshooting-code-scanning/no-source-code-seen-during-build"
|
||||
"https://gh.io/troubleshooting-code-scanning/no-source-code-seen-during-build",
|
||||
);
|
||||
}
|
||||
throw e;
|
||||
@@ -683,7 +683,7 @@ export async function getCodeQLForCmd(
|
||||
return JSON.parse(output);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unexpected output from codeql resolve languages: ${e}`
|
||||
`Unexpected output from codeql resolve languages: ${e}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -701,13 +701,13 @@ export async function getCodeQLForCmd(
|
||||
return JSON.parse(output);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`
|
||||
`Unexpected output from codeql resolve languages with --format=betterjson: ${e}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
async resolveQueries(
|
||||
queries: string[],
|
||||
extraSearchPath: string | undefined
|
||||
extraSearchPath: string | undefined,
|
||||
) {
|
||||
const codeqlArgs = [
|
||||
"resolve",
|
||||
@@ -729,7 +729,7 @@ export async function getCodeQLForCmd(
|
||||
},
|
||||
async resolveBuildEnvironment(
|
||||
workingDir: string | undefined,
|
||||
language: Language
|
||||
language: Language,
|
||||
) {
|
||||
const codeqlArgs = [
|
||||
"resolve",
|
||||
@@ -746,7 +746,7 @@ export async function getCodeQLForCmd(
|
||||
return JSON.parse(output);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Unexpected output from codeql resolve build-environment: ${e} in\n${output}`
|
||||
`Unexpected output from codeql resolve build-environment: ${e} in\n${output}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
@@ -755,7 +755,7 @@ export async function getCodeQLForCmd(
|
||||
extraSearchPath: string | undefined,
|
||||
querySuitePath: string | undefined,
|
||||
flags: string[],
|
||||
optimizeForLastQueryRun: boolean
|
||||
optimizeForLastQueryRun: boolean,
|
||||
): Promise<void> {
|
||||
const codeqlArgs = [
|
||||
"database",
|
||||
@@ -790,11 +790,11 @@ export async function getCodeQLForCmd(
|
||||
automationDetailsId: string | undefined,
|
||||
config: Config,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<string> {
|
||||
const shouldExportDiagnostics = await features.getValue(
|
||||
Feature.ExportDiagnosticsEnabled,
|
||||
this
|
||||
this,
|
||||
);
|
||||
// Update this to take into account the CodeQL version when we have a version with the fix.
|
||||
const shouldWorkaroundInvalidNotifications = shouldExportDiagnostics;
|
||||
@@ -822,7 +822,7 @@ export async function getCodeQLForCmd(
|
||||
if (
|
||||
await util.codeQlVersionAbove(
|
||||
this,
|
||||
CODEQL_VERSION_FILE_BASELINE_INFORMATION
|
||||
CODEQL_VERSION_FILE_BASELINE_INFORMATION,
|
||||
)
|
||||
) {
|
||||
codeqlArgs.push("--sarif-add-baseline-file-info");
|
||||
@@ -877,7 +877,7 @@ export async function getCodeQLForCmd(
|
||||
*/
|
||||
async packDownload(
|
||||
packs: string[],
|
||||
qlconfigFile: string | undefined
|
||||
qlconfigFile: string | undefined,
|
||||
): Promise<PackDownloadOutput> {
|
||||
const qlconfigArg = qlconfigFile
|
||||
? [`--qlconfig-file=${qlconfigFile}`]
|
||||
@@ -910,13 +910,13 @@ export async function getCodeQLForCmd(
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Attempted to download specified packs but got an error:\n${output}\n${e}`
|
||||
`Attempted to download specified packs but got an error:\n${output}\n${e}`,
|
||||
);
|
||||
}
|
||||
},
|
||||
async databaseCleanup(
|
||||
databasePath: string,
|
||||
cleanupLevel: string
|
||||
cleanupLevel: string,
|
||||
): Promise<void> {
|
||||
const codeqlArgs = [
|
||||
"database",
|
||||
@@ -930,7 +930,7 @@ export async function getCodeQLForCmd(
|
||||
async databaseBundle(
|
||||
databasePath: string,
|
||||
outputFilePath: string,
|
||||
databaseName: string
|
||||
databaseName: string,
|
||||
): Promise<void> {
|
||||
const args = [
|
||||
"database",
|
||||
@@ -947,7 +947,7 @@ export async function getCodeQLForCmd(
|
||||
sarifFile: string,
|
||||
automationDetailsId: string | undefined,
|
||||
tempDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
// Update this to take into account the CodeQL version when we have a version with the fix.
|
||||
const shouldWorkaroundInvalidNotifications = true;
|
||||
@@ -978,7 +978,7 @@ export async function getCodeQLForCmd(
|
||||
async diagnosticsExport(
|
||||
sarifFile: string,
|
||||
automationDetailsId: string | undefined,
|
||||
config: Config
|
||||
config: Config,
|
||||
): Promise<void> {
|
||||
const args = [
|
||||
"diagnostics",
|
||||
@@ -1016,7 +1016,7 @@ export async function getCodeQLForCmd(
|
||||
process.stderr.write(data);
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
).exec();
|
||||
return JSON.parse(extractorPath);
|
||||
},
|
||||
@@ -1034,7 +1034,7 @@ export async function getCodeQLForCmd(
|
||||
!(await util.codeQlVersionAbove(codeql, CODEQL_MINIMUM_VERSION))
|
||||
) {
|
||||
throw new Error(
|
||||
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${await codeql.getVersion()}`
|
||||
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${await codeql.getVersion()}`,
|
||||
);
|
||||
} else if (
|
||||
checkVersion &&
|
||||
@@ -1051,7 +1051,7 @@ export async function getCodeQLForCmd(
|
||||
"Alternatively, if you want to continue using CodeQL CLI version " +
|
||||
`${await codeql.getVersion()}, you can replace 'github/codeql-action/*@v2' by ` +
|
||||
"'github/codeql-action/*@v2.20.4' in your code scanning workflow to ensure you continue " +
|
||||
"using this version of the CodeQL Action."
|
||||
"using this version of the CodeQL Action.",
|
||||
);
|
||||
core.exportVariable(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING, "true");
|
||||
}
|
||||
@@ -1077,7 +1077,7 @@ function asExtraOptions(options: any, pathInfo: string[]): string[] {
|
||||
}
|
||||
if (!Array.isArray(options)) {
|
||||
const msg = `The extra options for '${pathInfo.join(
|
||||
"."
|
||||
".",
|
||||
)}' ('${JSON.stringify(options)}') are not in an array.`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
@@ -1085,7 +1085,7 @@ function asExtraOptions(options: any, pathInfo: string[]): string[] {
|
||||
const t = typeof o;
|
||||
if (t !== "string" && t !== "number" && t !== "boolean") {
|
||||
const msg = `The extra option for '${pathInfo.join(
|
||||
"."
|
||||
".",
|
||||
)}' ('${JSON.stringify(o)}') is not a primitive value.`;
|
||||
throw new Error(msg);
|
||||
}
|
||||
@@ -1104,7 +1104,7 @@ function asExtraOptions(options: any, pathInfo: string[]): string[] {
|
||||
export function getExtraOptions(
|
||||
options: any,
|
||||
paths: string[],
|
||||
pathInfo: string[]
|
||||
pathInfo: string[],
|
||||
): string[] {
|
||||
const all = asExtraOptions(options?.["*"], pathInfo.concat("*"));
|
||||
const specific =
|
||||
@@ -1113,7 +1113,7 @@ export function getExtraOptions(
|
||||
: getExtraOptions(
|
||||
options?.[paths[0]],
|
||||
paths?.slice(1),
|
||||
pathInfo.concat(paths[0])
|
||||
pathInfo.concat(paths[0]),
|
||||
);
|
||||
return all.concat(specific);
|
||||
}
|
||||
@@ -1131,7 +1131,7 @@ const maxErrorSize = 20_000;
|
||||
async function runTool(
|
||||
cmd: string,
|
||||
args: string[] = [],
|
||||
opts: { stdin?: string } = {}
|
||||
opts: { stdin?: string } = {},
|
||||
) {
|
||||
let output = "";
|
||||
let error = "";
|
||||
@@ -1235,7 +1235,7 @@ async function generateCodeScanningConfig(
|
||||
codeql: CodeQL,
|
||||
config: Config,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<string | undefined> {
|
||||
if (!(await useCodeScanningConfigInCli(codeql, features))) {
|
||||
return;
|
||||
@@ -1249,7 +1249,7 @@ async function generateCodeScanningConfig(
|
||||
if (config.augmentationProperties.queriesInput) {
|
||||
if (config.augmentationProperties.queriesInputCombines) {
|
||||
augmentedConfig.queries = (augmentedConfig.queries || []).concat(
|
||||
config.augmentationProperties.queriesInput
|
||||
config.augmentationProperties.queriesInput,
|
||||
);
|
||||
} else {
|
||||
augmentedConfig.queries = config.augmentationProperties.queriesInput;
|
||||
@@ -1265,7 +1265,7 @@ async function generateCodeScanningConfig(
|
||||
// At this point, we already know that this is a single-language analysis
|
||||
if (Array.isArray(augmentedConfig.packs)) {
|
||||
augmentedConfig.packs = (augmentedConfig.packs || []).concat(
|
||||
config.augmentationProperties.packsInput
|
||||
config.augmentationProperties.packsInput,
|
||||
);
|
||||
} else if (!augmentedConfig.packs) {
|
||||
augmentedConfig.packs = config.augmentationProperties.packsInput;
|
||||
@@ -1299,7 +1299,7 @@ async function generateCodeScanningConfig(
|
||||
}
|
||||
}
|
||||
logger.info(
|
||||
`Writing augmented user configuration file to ${codeScanningConfigFile}`
|
||||
`Writing augmented user configuration file to ${codeScanningConfigFile}`,
|
||||
);
|
||||
logger.startGroup("Augmented user configuration file contents");
|
||||
logger.info(yaml.dump(augmentedConfig));
|
||||
@@ -1321,14 +1321,14 @@ function cloneObject<T>(obj: T): T {
|
||||
*/
|
||||
async function getCodeScanningConfigExportArguments(
|
||||
config: Config,
|
||||
codeql: CodeQL
|
||||
codeql: CodeQL,
|
||||
): Promise<string[]> {
|
||||
const codeScanningConfigPath = getGeneratedCodeScanningConfigPath(config);
|
||||
if (
|
||||
fs.existsSync(codeScanningConfigPath) &&
|
||||
(await util.codeQlVersionAbove(
|
||||
codeql,
|
||||
CODEQL_VERSION_EXPORT_CODE_SCANNING_CONFIG
|
||||
CODEQL_VERSION_EXPORT_CODE_SCANNING_CONFIG,
|
||||
))
|
||||
) {
|
||||
return ["--sarif-codescanning-config", codeScanningConfigPath];
|
||||
@@ -1340,19 +1340,19 @@ async function getCodeScanningConfigExportArguments(
|
||||
const TRAP_CACHE_SIZE_MB = 1024;
|
||||
|
||||
export async function getTrapCachingExtractorConfigArgs(
|
||||
config: Config
|
||||
config: Config,
|
||||
): Promise<string[]> {
|
||||
const result: string[][] = [];
|
||||
for (const language of config.languages)
|
||||
result.push(
|
||||
await getTrapCachingExtractorConfigArgsForLang(config, language)
|
||||
await getTrapCachingExtractorConfigArgsForLang(config, language),
|
||||
);
|
||||
return result.flat();
|
||||
}
|
||||
|
||||
export async function getTrapCachingExtractorConfigArgsForLang(
|
||||
config: Config,
|
||||
language: Language
|
||||
language: Language,
|
||||
): Promise<string[]> {
|
||||
const cacheDir = config.trapCaches[language];
|
||||
if (cacheDir === undefined) return [];
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -292,7 +292,7 @@ const DISABLED_BUILTIN_QUERIES: { [language: string]: string[] } = {
|
||||
|
||||
function queryIsDisabled(language, query): boolean {
|
||||
return (DISABLED_BUILTIN_QUERIES[language] || []).some((disabledQuery) =>
|
||||
query.endsWith(disabledQuery)
|
||||
query.endsWith(disabledQuery),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -308,20 +308,20 @@ function validateQueries(resolvedQueries: ResolveQueriesOutput) {
|
||||
`${
|
||||
"The following queries do not declare a language. " +
|
||||
"Their qlpack.yml files are either missing or is invalid.\n"
|
||||
}${noDeclaredLanguageQueries.join("\n")}`
|
||||
}${noDeclaredLanguageQueries.join("\n")}`,
|
||||
);
|
||||
}
|
||||
|
||||
const multipleDeclaredLanguages = resolvedQueries.multipleDeclaredLanguages;
|
||||
const multipleDeclaredLanguagesQueries = Object.keys(
|
||||
multipleDeclaredLanguages
|
||||
multipleDeclaredLanguages,
|
||||
);
|
||||
if (multipleDeclaredLanguagesQueries.length !== 0) {
|
||||
throw new UserError(
|
||||
`${
|
||||
"The following queries declare multiple languages. " +
|
||||
"Their qlpack.yml files are either missing or is invalid.\n"
|
||||
}${multipleDeclaredLanguagesQueries.join("\n")}`
|
||||
}${multipleDeclaredLanguagesQueries.join("\n")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -338,11 +338,11 @@ async function runResolveQueries(
|
||||
codeQL: CodeQL,
|
||||
resultMap: Queries,
|
||||
toResolve: string[],
|
||||
extraSearchPath: string | undefined
|
||||
extraSearchPath: string | undefined,
|
||||
) {
|
||||
const resolvedQueries = await codeQL.resolveQueries(
|
||||
toResolve,
|
||||
extraSearchPath
|
||||
extraSearchPath,
|
||||
);
|
||||
|
||||
if (extraSearchPath !== undefined) {
|
||||
@@ -350,7 +350,7 @@ async function runResolveQueries(
|
||||
}
|
||||
|
||||
for (const [language, queryPaths] of Object.entries(
|
||||
resolvedQueries.byLanguage
|
||||
resolvedQueries.byLanguage,
|
||||
)) {
|
||||
if (resultMap[language] === undefined) {
|
||||
resultMap[language] = {
|
||||
@@ -359,7 +359,7 @@ async function runResolveQueries(
|
||||
};
|
||||
}
|
||||
const queries = Object.keys(queryPaths).filter(
|
||||
(q) => !queryIsDisabled(language, q)
|
||||
(q) => !queryIsDisabled(language, q),
|
||||
);
|
||||
if (extraSearchPath !== undefined) {
|
||||
resultMap[language].custom.push({
|
||||
@@ -378,7 +378,7 @@ async function runResolveQueries(
|
||||
async function addDefaultQueries(
|
||||
codeQL: CodeQL,
|
||||
languages: string[],
|
||||
resultMap: Queries
|
||||
resultMap: Queries,
|
||||
) {
|
||||
const suites = languages.map((l) => `${l}-code-scanning.qls`);
|
||||
await runResolveQueries(codeQL, resultMap, suites, undefined);
|
||||
@@ -403,7 +403,7 @@ async function addBuiltinSuiteQueries(
|
||||
packs: Packs,
|
||||
suiteName: string,
|
||||
features: FeatureEnablement,
|
||||
configFile?: string
|
||||
configFile?: string,
|
||||
): Promise<boolean> {
|
||||
let injectedMlQueries = false;
|
||||
const found = builtinSuites.find((suite) => suite === suiteName);
|
||||
@@ -414,13 +414,13 @@ async function addBuiltinSuiteQueries(
|
||||
suiteName === "security-experimental" &&
|
||||
!(await codeQlVersionAbove(
|
||||
codeQL,
|
||||
CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE
|
||||
CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE,
|
||||
))
|
||||
) {
|
||||
throw new UserError(
|
||||
`The 'security-experimental' suite is not supported on CodeQL CLI versions earlier than
|
||||
${CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE}. Please upgrade to CodeQL CLI version
|
||||
${CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE} or later.`
|
||||
${CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE} or later.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -459,7 +459,7 @@ async function addLocalQueries(
|
||||
resultMap: Queries,
|
||||
localQueryPath: string,
|
||||
workspacePath: string,
|
||||
configFile?: string
|
||||
configFile?: string,
|
||||
) {
|
||||
// Resolve the local path against the workspace so that when this is
|
||||
// passed to codeql it resolves to exactly the path we expect it to resolve to.
|
||||
@@ -476,11 +476,11 @@ async function addLocalQueries(
|
||||
// Check the local path doesn't jump outside the repo using '..' or symlinks
|
||||
if (
|
||||
!(absoluteQueryPath + path.sep).startsWith(
|
||||
fs.realpathSync(workspacePath) + path.sep
|
||||
fs.realpathSync(workspacePath) + path.sep,
|
||||
)
|
||||
) {
|
||||
throw new UserError(
|
||||
getLocalPathOutsideOfRepository(configFile, localQueryPath)
|
||||
getLocalPathOutsideOfRepository(configFile, localQueryPath),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -490,7 +490,7 @@ async function addLocalQueries(
|
||||
codeQL,
|
||||
resultMap,
|
||||
[absoluteQueryPath],
|
||||
extraSearchPath
|
||||
extraSearchPath,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -504,7 +504,7 @@ async function addRemoteQueries(
|
||||
tempDir: string,
|
||||
apiDetails: api.GitHubApiExternalRepoDetails,
|
||||
logger: Logger,
|
||||
configFile?: string
|
||||
configFile?: string,
|
||||
) {
|
||||
let tok = queryUses.split("@");
|
||||
if (tok.length !== 2) {
|
||||
@@ -532,7 +532,7 @@ async function addRemoteQueries(
|
||||
ref,
|
||||
apiDetails,
|
||||
tempDir,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
const queryPath =
|
||||
@@ -567,7 +567,7 @@ async function parseQueryUses(
|
||||
apiDetails: api.GitHubApiExternalRepoDetails,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
configFile?: string
|
||||
configFile?: string,
|
||||
): Promise<boolean> {
|
||||
queryUses = queryUses.trim();
|
||||
if (queryUses === "") {
|
||||
@@ -581,7 +581,7 @@ async function parseQueryUses(
|
||||
resultMap,
|
||||
queryUses.slice(2),
|
||||
workspacePath,
|
||||
configFile
|
||||
configFile,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -595,7 +595,7 @@ async function parseQueryUses(
|
||||
packs,
|
||||
queryUses,
|
||||
features,
|
||||
configFile
|
||||
configFile,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -610,7 +610,7 @@ async function parseQueryUses(
|
||||
tempDir,
|
||||
apiDetails,
|
||||
logger,
|
||||
configFile
|
||||
configFile,
|
||||
);
|
||||
}
|
||||
return false;
|
||||
@@ -631,7 +631,7 @@ export function validateAndSanitisePath(
|
||||
originalPath: string,
|
||||
propertyName: string,
|
||||
configFile: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): string {
|
||||
// Take a copy so we don't modify the original path, so we can still construct error messages
|
||||
let newPath = originalPath;
|
||||
@@ -653,8 +653,8 @@ export function validateAndSanitisePath(
|
||||
configFile,
|
||||
propertyName,
|
||||
`"${originalPath}" is not an invalid path. ` +
|
||||
`It is not necessary to include it, and it is not allowed to exclude it.`
|
||||
)
|
||||
`It is not necessary to include it, and it is not allowed to exclude it.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -665,8 +665,8 @@ export function validateAndSanitisePath(
|
||||
configFile,
|
||||
propertyName,
|
||||
`"${originalPath}" contains an invalid "**" wildcard. ` +
|
||||
`They must be immediately preceded and followed by a slash as in "/**/", or come at the start or end.`
|
||||
)
|
||||
`They must be immediately preceded and followed by a slash as in "/**/", or come at the start or end.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -678,8 +678,8 @@ export function validateAndSanitisePath(
|
||||
configFile,
|
||||
propertyName,
|
||||
`"${originalPath}" contains an unsupported character. ` +
|
||||
`The filter pattern characters ?, +, [, ], ! are not supported and will be matched literally.`
|
||||
)
|
||||
`The filter pattern characters ?, +, [, ], ! are not supported and will be matched literally.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -692,8 +692,8 @@ export function validateAndSanitisePath(
|
||||
configFile,
|
||||
propertyName,
|
||||
`"${originalPath}" contains an "\\" character. These are not allowed in filters. ` +
|
||||
`If running on windows we recommend using "/" instead for path filters.`
|
||||
)
|
||||
`If running on windows we recommend using "/" instead for path filters.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -707,7 +707,7 @@ export function getNameInvalid(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
NAME_PROPERTY,
|
||||
"must be a non-empty string"
|
||||
"must be a non-empty string",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -715,7 +715,7 @@ export function getDisableDefaultQueriesInvalid(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
DISABLE_DEFAULT_QUERIES_PROPERTY,
|
||||
"must be a boolean"
|
||||
"must be a boolean",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -723,7 +723,7 @@ export function getQueriesInvalid(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
QUERIES_PROPERTY,
|
||||
"must be an array"
|
||||
"must be an array",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -731,22 +731,22 @@ export function getQueriesMissingUses(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
QUERIES_PROPERTY,
|
||||
"must be an array, with each entry having a 'uses' property"
|
||||
"must be an array, with each entry having a 'uses' property",
|
||||
);
|
||||
}
|
||||
|
||||
export function getQueryUsesInvalid(
|
||||
configFile: string | undefined,
|
||||
queryUses?: string
|
||||
queryUses?: string,
|
||||
): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
`${QUERIES_PROPERTY}.${QUERIES_USES_PROPERTY}`,
|
||||
`must be a built-in suite (${builtinSuites.join(
|
||||
" or "
|
||||
" or ",
|
||||
)}), a relative path, or be of the form "owner/repo[/path]@ref"${
|
||||
queryUses !== undefined ? `\n Found: ${queryUses}` : ""
|
||||
}`
|
||||
}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -754,7 +754,7 @@ export function getPathsIgnoreInvalid(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
PATHS_IGNORE_PROPERTY,
|
||||
"must be an array of non-empty strings"
|
||||
"must be an array of non-empty strings",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -762,7 +762,7 @@ export function getPathsInvalid(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
PATHS_PROPERTY,
|
||||
"must be an array of non-empty strings"
|
||||
"must be an array of non-empty strings",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -770,7 +770,7 @@ function getPacksRequireLanguage(lang: string, configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
PACKS_PROPERTY,
|
||||
`has "${lang}", but it is not a valid language.`
|
||||
`has "${lang}", but it is not a valid language.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -778,7 +778,7 @@ export function getPacksInvalidSplit(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
PACKS_PROPERTY,
|
||||
"must split packages by language"
|
||||
"must split packages by language",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -786,59 +786,59 @@ export function getPacksInvalid(configFile: string): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
PACKS_PROPERTY,
|
||||
"must be an array of non-empty strings"
|
||||
"must be an array of non-empty strings",
|
||||
);
|
||||
}
|
||||
|
||||
export function getPacksStrInvalid(
|
||||
packStr: string,
|
||||
configFile?: string
|
||||
configFile?: string,
|
||||
): string {
|
||||
return configFile
|
||||
? getConfigFilePropertyError(
|
||||
configFile,
|
||||
PACKS_PROPERTY,
|
||||
`"${packStr}" is not a valid pack`
|
||||
`"${packStr}" is not a valid pack`,
|
||||
)
|
||||
: `"${packStr}" is not a valid pack`;
|
||||
}
|
||||
|
||||
export function getLocalPathOutsideOfRepository(
|
||||
configFile: string | undefined,
|
||||
localPath: string
|
||||
localPath: string,
|
||||
): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
`${QUERIES_PROPERTY}.${QUERIES_USES_PROPERTY}`,
|
||||
`is invalid as the local path "${localPath}" is outside of the repository`
|
||||
`is invalid as the local path "${localPath}" is outside of the repository`,
|
||||
);
|
||||
}
|
||||
|
||||
export function getLocalPathDoesNotExist(
|
||||
configFile: string | undefined,
|
||||
localPath: string
|
||||
localPath: string,
|
||||
): string {
|
||||
return getConfigFilePropertyError(
|
||||
configFile,
|
||||
`${QUERIES_PROPERTY}.${QUERIES_USES_PROPERTY}`,
|
||||
`is invalid as the local path "${localPath}" does not exist in the repository`
|
||||
`is invalid as the local path "${localPath}" does not exist in the repository`,
|
||||
);
|
||||
}
|
||||
|
||||
export function getConfigFileOutsideWorkspaceErrorMessage(
|
||||
configFile: string
|
||||
configFile: string,
|
||||
): string {
|
||||
return `The configuration file "${configFile}" is outside of the workspace`;
|
||||
}
|
||||
|
||||
export function getConfigFileDoesNotExistErrorMessage(
|
||||
configFile: string
|
||||
configFile: string,
|
||||
): string {
|
||||
return `The configuration file "${configFile}" does not exist`;
|
||||
}
|
||||
|
||||
export function getConfigFileRepoFormatInvalidMessage(
|
||||
configFile: string
|
||||
configFile: string,
|
||||
): string {
|
||||
let error = `The configuration file "${configFile}" is not a supported remote file reference.`;
|
||||
error += " Expected format <owner>/<repository>/<file-path>@<ref>";
|
||||
@@ -857,7 +857,7 @@ export function getConfigFileDirectoryGivenMessage(configFile: string): string {
|
||||
function getConfigFilePropertyError(
|
||||
configFile: string | undefined,
|
||||
property: string,
|
||||
error: string
|
||||
error: string,
|
||||
): string {
|
||||
if (configFile === undefined) {
|
||||
return `The workflow property "${property}" is invalid: ${error}`;
|
||||
@@ -883,7 +883,7 @@ export function getUnknownLanguagesError(languages: string[]): string {
|
||||
*/
|
||||
export async function getLanguagesInRepo(
|
||||
repository: RepositoryNwo,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<LanguageOrAlias[]> {
|
||||
logger.debug(`GitHub repo ${repository.owner} ${repository.repo}`);
|
||||
const response = await api.getApiClient().rest.repos.listLanguages({
|
||||
@@ -921,13 +921,13 @@ export async function getLanguages(
|
||||
codeQL: CodeQL,
|
||||
languagesInput: string | undefined,
|
||||
repository: RepositoryNwo,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Language[]> {
|
||||
// Obtain languages without filtering them.
|
||||
const { rawLanguages, autodetected } = await getRawLanguages(
|
||||
languagesInput,
|
||||
repository,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
let languages = rawLanguages.map(resolveAlias);
|
||||
@@ -981,7 +981,7 @@ export async function getLanguages(
|
||||
export async function getRawLanguages(
|
||||
languagesInput: string | undefined,
|
||||
repository: RepositoryNwo,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
// Obtain from action input 'languages' if set
|
||||
let rawLanguages = (languagesInput || "")
|
||||
@@ -1010,7 +1010,7 @@ async function addQueriesAndPacksFromWorkflow(
|
||||
workspacePath: string,
|
||||
apiDetails: api.GitHubApiExternalRepoDetails,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
let injectedMlQueries = false;
|
||||
queriesInput = queriesInput.trim();
|
||||
@@ -1028,7 +1028,7 @@ async function addQueriesAndPacksFromWorkflow(
|
||||
workspacePath,
|
||||
apiDetails,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
injectedMlQueries = injectedMlQueries || didInject;
|
||||
}
|
||||
@@ -1067,13 +1067,13 @@ export async function getDefaultConfig(
|
||||
gitHubVersion: GitHubVersion,
|
||||
apiDetails: api.GitHubApiCombinedDetails,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Config> {
|
||||
const languages = await getLanguages(
|
||||
codeQL,
|
||||
languagesInput,
|
||||
repository,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
const queries: Queries = {};
|
||||
for (const language of languages) {
|
||||
@@ -1086,7 +1086,7 @@ export async function getDefaultConfig(
|
||||
const augmentationProperties = calculateAugmentation(
|
||||
rawPacksInput,
|
||||
rawQueriesInput,
|
||||
languages
|
||||
languages,
|
||||
);
|
||||
const packs = augmentationProperties.packsInput
|
||||
? {
|
||||
@@ -1105,7 +1105,7 @@ export async function getDefaultConfig(
|
||||
workspacePath,
|
||||
apiDetails,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1113,7 +1113,7 @@ export async function getDefaultConfig(
|
||||
trapCachingEnabled,
|
||||
codeQL,
|
||||
languages,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -1140,7 +1140,7 @@ async function downloadCacheWithTime(
|
||||
trapCachingEnabled: boolean,
|
||||
codeQL: CodeQL,
|
||||
languages: Language[],
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
trapCaches: Partial<Record<Language, string>>;
|
||||
trapCacheDownloadTime: number;
|
||||
@@ -1175,7 +1175,7 @@ async function loadConfig(
|
||||
gitHubVersion: GitHubVersion,
|
||||
apiDetails: api.GitHubApiCombinedDetails,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Config> {
|
||||
let parsedYAML: UserConfig;
|
||||
|
||||
@@ -1202,7 +1202,7 @@ async function loadConfig(
|
||||
codeQL,
|
||||
languagesInput,
|
||||
repository,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
const queries: Queries = {};
|
||||
@@ -1228,7 +1228,7 @@ async function loadConfig(
|
||||
const augmentationProperties = calculateAugmentation(
|
||||
rawPacksInput,
|
||||
rawQueriesInput,
|
||||
languages
|
||||
languages,
|
||||
);
|
||||
const packs = parsePacks(
|
||||
parsedYAML[PACKS_PROPERTY] ?? {},
|
||||
@@ -1236,7 +1236,7 @@ async function loadConfig(
|
||||
augmentationProperties.packsInputCombines,
|
||||
languages,
|
||||
configFile,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
// If queries were provided using `with` in the action configuration,
|
||||
@@ -1255,7 +1255,7 @@ async function loadConfig(
|
||||
workspacePath,
|
||||
apiDetails,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
if (
|
||||
@@ -1281,7 +1281,7 @@ async function loadConfig(
|
||||
apiDetails,
|
||||
features,
|
||||
logger,
|
||||
configFile
|
||||
configFile,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1299,8 +1299,8 @@ async function loadConfig(
|
||||
ignorePath,
|
||||
PATHS_IGNORE_PROPERTY,
|
||||
configFile,
|
||||
logger
|
||||
)
|
||||
logger,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1314,7 +1314,12 @@ async function loadConfig(
|
||||
throw new UserError(getPathsInvalid(configFile));
|
||||
}
|
||||
paths.push(
|
||||
validateAndSanitisePath(includePath, PATHS_PROPERTY, configFile, logger)
|
||||
validateAndSanitisePath(
|
||||
includePath,
|
||||
PATHS_PROPERTY,
|
||||
configFile,
|
||||
logger,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1323,7 +1328,7 @@ async function loadConfig(
|
||||
trapCachingEnabled,
|
||||
codeQL,
|
||||
languages,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -1368,18 +1373,18 @@ async function loadConfig(
|
||||
export function calculateAugmentation(
|
||||
rawPacksInput: string | undefined,
|
||||
rawQueriesInput: string | undefined,
|
||||
languages: Language[]
|
||||
languages: Language[],
|
||||
): AugmentationProperties {
|
||||
const packsInputCombines = shouldCombine(rawPacksInput);
|
||||
const packsInput = parsePacksFromInput(
|
||||
rawPacksInput,
|
||||
languages,
|
||||
packsInputCombines
|
||||
packsInputCombines,
|
||||
);
|
||||
const queriesInputCombines = shouldCombine(rawQueriesInput);
|
||||
const queriesInput = parseQueriesFromInput(
|
||||
rawQueriesInput,
|
||||
queriesInputCombines
|
||||
queriesInputCombines,
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -1393,7 +1398,7 @@ export function calculateAugmentation(
|
||||
|
||||
function parseQueriesFromInput(
|
||||
rawQueriesInput: string | undefined,
|
||||
queriesInputCombines: boolean
|
||||
queriesInputCombines: boolean,
|
||||
) {
|
||||
if (!rawQueriesInput) {
|
||||
return undefined;
|
||||
@@ -1407,8 +1412,8 @@ function parseQueriesFromInput(
|
||||
getConfigFilePropertyError(
|
||||
undefined,
|
||||
"queries",
|
||||
"A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs."
|
||||
)
|
||||
"A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs.",
|
||||
),
|
||||
);
|
||||
}
|
||||
return trimmedInput.split(",").map((query) => ({ uses: query.trim() }));
|
||||
@@ -1430,7 +1435,7 @@ export function parsePacksFromConfig(
|
||||
packsByLanguage: string[] | Record<string, string[]>,
|
||||
languages: Language[],
|
||||
configFile: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Packs {
|
||||
const packs = {};
|
||||
|
||||
@@ -1455,7 +1460,7 @@ export function parsePacksFromConfig(
|
||||
// This particular language is not being analyzed in this run.
|
||||
if (Language[lang as Language]) {
|
||||
logger.info(
|
||||
`Ignoring packs for ${lang} since this language is not being analyzed in this run.`
|
||||
`Ignoring packs for ${lang} since this language is not being analyzed in this run.`,
|
||||
);
|
||||
continue;
|
||||
} else {
|
||||
@@ -1465,7 +1470,7 @@ export function parsePacksFromConfig(
|
||||
}
|
||||
|
||||
packs[lang] = packsArr.map((packStr) =>
|
||||
validatePackSpecification(packStr, configFile)
|
||||
validatePackSpecification(packStr, configFile),
|
||||
);
|
||||
}
|
||||
return packs;
|
||||
@@ -1474,7 +1479,7 @@ export function parsePacksFromConfig(
|
||||
function parsePacksFromInput(
|
||||
rawPacksInput: string | undefined,
|
||||
languages: Language[],
|
||||
packsInputCombines: boolean
|
||||
packsInputCombines: boolean,
|
||||
): Packs | undefined {
|
||||
if (!rawPacksInput?.trim()) {
|
||||
return undefined;
|
||||
@@ -1482,11 +1487,11 @@ function parsePacksFromInput(
|
||||
|
||||
if (languages.length > 1) {
|
||||
throw new UserError(
|
||||
"Cannot specify a 'packs' input in a multi-language analysis. Use a codeql-config.yml file instead and specify packs by language."
|
||||
"Cannot specify a 'packs' input in a multi-language analysis. Use a codeql-config.yml file instead and specify packs by language.",
|
||||
);
|
||||
} else if (languages.length === 0) {
|
||||
throw new UserError(
|
||||
"No languages specified. Cannot process the packs input."
|
||||
"No languages specified. Cannot process the packs input.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1498,8 +1503,8 @@ function parsePacksFromInput(
|
||||
getConfigFilePropertyError(
|
||||
undefined,
|
||||
"packs",
|
||||
"A '+' was used in the 'packs' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs."
|
||||
)
|
||||
"A '+' was used in the 'packs' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs.",
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1532,7 +1537,7 @@ function parsePacksFromInput(
|
||||
*/
|
||||
export function parsePacksSpecification(
|
||||
packStr: string,
|
||||
configFile?: string
|
||||
configFile?: string,
|
||||
): Pack {
|
||||
if (typeof packStr !== "string") {
|
||||
throw new UserError(getPacksStrInvalid(packStr, configFile));
|
||||
@@ -1547,7 +1552,7 @@ export function parsePacksSpecification(
|
||||
const packEnd = Math.min(
|
||||
atIndex > 0 ? atIndex : Infinity,
|
||||
colonIndex > 0 ? colonIndex : Infinity,
|
||||
packStr.length
|
||||
packStr.length,
|
||||
);
|
||||
const versionEnd = versionStart
|
||||
? Math.min(colonIndex > 0 ? colonIndex : Infinity, packStr.length)
|
||||
@@ -1610,19 +1615,19 @@ export function parsePacks(
|
||||
packsInputCombines: boolean,
|
||||
languages: Language[],
|
||||
configFile: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Packs {
|
||||
const packsFomConfig = parsePacksFromConfig(
|
||||
rawPacksFromConfig,
|
||||
languages,
|
||||
configFile,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
const packsFromInput = parsePacksFromInput(
|
||||
rawPacksFromInput,
|
||||
languages,
|
||||
packsInputCombines
|
||||
packsInputCombines,
|
||||
);
|
||||
if (!packsFromInput) {
|
||||
return packsFomConfig;
|
||||
@@ -1689,7 +1694,7 @@ export function getMlPoweredJsQueriesStatus(config: Config): string {
|
||||
const mlPoweredJsQueryPacks = (config.packs.javascript || [])
|
||||
.map((p) => parsePacksSpecification(p))
|
||||
.filter(
|
||||
(pack) => pack.name === ML_POWERED_JS_QUERIES_PACK_NAME && !pack.path
|
||||
(pack) => pack.name === ML_POWERED_JS_QUERIES_PACK_NAME && !pack.path,
|
||||
);
|
||||
switch (mlPoweredJsQueryPacks.length) {
|
||||
case 1:
|
||||
@@ -1708,7 +1713,7 @@ export function getMlPoweredJsQueriesStatus(config: Config): string {
|
||||
|
||||
function dbLocationOrDefault(
|
||||
dbLocation: string | undefined,
|
||||
tempDir: string
|
||||
tempDir: string,
|
||||
): string {
|
||||
return dbLocation || path.resolve(tempDir, "codeql_databases");
|
||||
}
|
||||
@@ -1738,7 +1743,7 @@ export async function initConfig(
|
||||
gitHubVersion: GitHubVersion,
|
||||
apiDetails: api.GitHubApiCombinedDetails,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Config> {
|
||||
let config: Config;
|
||||
|
||||
@@ -1746,7 +1751,7 @@ export async function initConfig(
|
||||
if (configInput) {
|
||||
if (configFile) {
|
||||
logger.warning(
|
||||
`Both a config file and config input were provided. Ignoring config file.`
|
||||
`Both a config file and config input were provided. Ignoring config file.`,
|
||||
);
|
||||
}
|
||||
configFile = path.resolve(workspacePath, "user-config-from-action.yml");
|
||||
@@ -1773,7 +1778,7 @@ export async function initConfig(
|
||||
gitHubVersion,
|
||||
apiDetails,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
} else {
|
||||
config = await loadConfig(
|
||||
@@ -1793,7 +1798,7 @@ export async function initConfig(
|
||||
gitHubVersion,
|
||||
apiDetails,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1813,7 +1818,7 @@ export async function initConfig(
|
||||
if (!hasPacks && !hasBuiltinQueries && !hasCustomQueries) {
|
||||
throw new UserError(
|
||||
`Did not detect any queries to run for ${language}. ` +
|
||||
"Please make sure that the default queries are enabled, or you are specifying queries to run."
|
||||
"Please make sure that the default queries are enabled, or you are specifying queries to run.",
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1825,7 +1830,7 @@ export async function initConfig(
|
||||
apiDetails,
|
||||
registriesInput,
|
||||
config.tempDir,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1835,7 +1840,7 @@ export async function initConfig(
|
||||
}
|
||||
|
||||
function parseRegistries(
|
||||
registriesInput: string | undefined
|
||||
registriesInput: string | undefined,
|
||||
): RegistryConfigWithCredentials[] | undefined {
|
||||
try {
|
||||
return registriesInput
|
||||
@@ -1871,11 +1876,11 @@ function getLocalConfig(configFile: string, workspacePath: string): UserConfig {
|
||||
|
||||
async function getRemoteConfig(
|
||||
configFile: string,
|
||||
apiDetails: api.GitHubApiCombinedDetails
|
||||
apiDetails: api.GitHubApiCombinedDetails,
|
||||
): Promise<UserConfig> {
|
||||
// retrieve the various parts of the config location, and ensure they're present
|
||||
const format = new RegExp(
|
||||
"(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)"
|
||||
"(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)",
|
||||
);
|
||||
const pieces = format.exec(configFile);
|
||||
// 5 = 4 groups + the whole expression
|
||||
@@ -1902,7 +1907,7 @@ async function getRemoteConfig(
|
||||
}
|
||||
|
||||
return yaml.load(
|
||||
Buffer.from(fileContents, "base64").toString("binary")
|
||||
Buffer.from(fileContents, "base64").toString("binary"),
|
||||
) as UserConfig;
|
||||
}
|
||||
|
||||
@@ -1931,7 +1936,7 @@ async function saveConfig(config: Config, logger: Logger) {
|
||||
*/
|
||||
export async function getConfig(
|
||||
tempDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Config | undefined> {
|
||||
const configFile = getPathToParsedConfigFile(tempDir);
|
||||
if (!fs.existsSync(configFile)) {
|
||||
@@ -1950,14 +1955,14 @@ export async function downloadPacks(
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
registriesInput: string | undefined,
|
||||
tempDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
// This code path is only used when config parsing occurs in the Action.
|
||||
const { registriesAuthTokens, qlconfigFile } = await generateRegistries(
|
||||
registriesInput,
|
||||
codeQL,
|
||||
tempDir,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
await wrapEnvironment(
|
||||
{
|
||||
@@ -1973,13 +1978,13 @@ export async function downloadPacks(
|
||||
logger.info(`Downloading custom packs for ${language}`);
|
||||
const results = await codeQL.packDownload(
|
||||
packsWithVersion,
|
||||
qlconfigFile
|
||||
qlconfigFile,
|
||||
);
|
||||
numPacksDownloaded += results.packs.length;
|
||||
logger.info(
|
||||
`Downloaded: ${results.packs
|
||||
.map((r) => `${r.name}@${r.version || "latest"}`)
|
||||
.join(", ")}`
|
||||
.join(", ")}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1987,13 +1992,13 @@ export async function downloadPacks(
|
||||
logger.info(
|
||||
`Downloaded ${numPacksDownloaded} ${
|
||||
numPacksDownloaded === 1 ? "pack" : "packs"
|
||||
}`
|
||||
}`,
|
||||
);
|
||||
} else {
|
||||
logger.info("No packs to download");
|
||||
}
|
||||
logger.endGroup();
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2013,7 +2018,7 @@ export async function generateRegistries(
|
||||
registriesInput: string | undefined,
|
||||
codeQL: CodeQL,
|
||||
tempDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
const registries = parseRegistries(registriesInput);
|
||||
let registriesAuthTokens: string | undefined;
|
||||
@@ -2023,7 +2028,7 @@ export async function generateRegistries(
|
||||
!(await codeQlVersionAbove(codeQL, CODEQL_VERSION_GHES_PACK_DOWNLOAD))
|
||||
) {
|
||||
throw new UserError(
|
||||
`The 'registries' input is not supported on CodeQL CLI versions earlier than ${CODEQL_VERSION_GHES_PACK_DOWNLOAD}. Please upgrade to CodeQL CLI version ${CODEQL_VERSION_GHES_PACK_DOWNLOAD} or later.`
|
||||
`The 'registries' input is not supported on CodeQL CLI versions earlier than ${CODEQL_VERSION_GHES_PACK_DOWNLOAD}. Please upgrade to CodeQL CLI version ${CODEQL_VERSION_GHES_PACK_DOWNLOAD} or later.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2042,7 +2047,7 @@ export async function generateRegistries(
|
||||
|
||||
if (typeof process.env.CODEQL_REGISTRIES_AUTH === "string") {
|
||||
logger.debug(
|
||||
"Using CODEQL_REGISTRIES_AUTH environment variable to authenticate with registries."
|
||||
"Using CODEQL_REGISTRIES_AUTH environment variable to authenticate with registries.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2062,7 +2067,7 @@ function createRegistriesBlock(registries: RegistryConfigWithCredentials[]): {
|
||||
registries.some((r) => !r.url || !r.packages)
|
||||
) {
|
||||
throw new UserError(
|
||||
"Invalid 'registries' input. Must be an array of objects with 'url' and 'packages' properties."
|
||||
"Invalid 'registries' input. Must be an array of objects with 'url' and 'packages' properties.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2092,7 +2097,7 @@ function createRegistriesBlock(registries: RegistryConfigWithCredentials[]): {
|
||||
*/
|
||||
export async function wrapEnvironment(
|
||||
env: Record<string, string | undefined>,
|
||||
operation: Function
|
||||
operation: Function,
|
||||
) {
|
||||
// Remember the original env
|
||||
const oldEnv = { ...process.env };
|
||||
|
||||
@@ -74,7 +74,7 @@ async function mockHttpRequests(databaseUploadStatusCode: number) {
|
||||
databaseUploadSpy.resolves(undefined);
|
||||
} else {
|
||||
databaseUploadSpy.throws(
|
||||
new HTTPError("some error message", databaseUploadStatusCode)
|
||||
new HTTPError("some error message", databaseUploadStatusCode),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -95,14 +95,15 @@ test("Abort database upload if 'upload-database' input set to false", async (t)
|
||||
testRepoName,
|
||||
getTestConfig(tmpDir),
|
||||
testApiDetails,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
t.assert(
|
||||
loggedMessages.find(
|
||||
(v: LoggedMessage) =>
|
||||
v.type === "debug" &&
|
||||
v.message === "Database upload disabled in workflow. Skipping upload."
|
||||
) !== undefined
|
||||
v.message ===
|
||||
"Database upload disabled in workflow. Skipping upload.",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -124,14 +125,14 @@ test("Abort database upload if running against GHES", async (t) => {
|
||||
testRepoName,
|
||||
config,
|
||||
testApiDetails,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
t.assert(
|
||||
loggedMessages.find(
|
||||
(v: LoggedMessage) =>
|
||||
v.type === "debug" &&
|
||||
v.message === "Not running against github.com. Skipping upload."
|
||||
) !== undefined
|
||||
v.message === "Not running against github.com. Skipping upload.",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -153,14 +154,14 @@ test("Abort database upload if running against GHAE", async (t) => {
|
||||
testRepoName,
|
||||
config,
|
||||
testApiDetails,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
t.assert(
|
||||
loggedMessages.find(
|
||||
(v: LoggedMessage) =>
|
||||
v.type === "debug" &&
|
||||
v.message === "Not running against github.com. Skipping upload."
|
||||
) !== undefined
|
||||
v.message === "Not running against github.com. Skipping upload.",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -179,14 +180,14 @@ test("Abort database upload if not analyzing default branch", async (t) => {
|
||||
testRepoName,
|
||||
getTestConfig(tmpDir),
|
||||
testApiDetails,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
t.assert(
|
||||
loggedMessages.find(
|
||||
(v: LoggedMessage) =>
|
||||
v.type === "debug" &&
|
||||
v.message === "Not analyzing default branch. Skipping upload."
|
||||
) !== undefined
|
||||
v.message === "Not analyzing default branch. Skipping upload.",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -213,7 +214,7 @@ test("Don't crash if uploading a database fails", async (t) => {
|
||||
testRepoName,
|
||||
getTestConfig(tmpDir),
|
||||
testApiDetails,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
|
||||
t.assert(
|
||||
@@ -221,8 +222,8 @@ test("Don't crash if uploading a database fails", async (t) => {
|
||||
(v) =>
|
||||
v.type === "warning" &&
|
||||
v.message ===
|
||||
"Failed to upload database for javascript: Error: some error message"
|
||||
) !== undefined
|
||||
"Failed to upload database for javascript: Error: some error message",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -249,14 +250,14 @@ test("Successfully uploading a database to api.github.com", async (t) => {
|
||||
testRepoName,
|
||||
getTestConfig(tmpDir),
|
||||
testApiDetails,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
t.assert(
|
||||
loggedMessages.find(
|
||||
(v) =>
|
||||
v.type === "debug" &&
|
||||
v.message === "Successfully uploaded database for javascript"
|
||||
) !== undefined
|
||||
v.message === "Successfully uploaded database for javascript",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -283,14 +284,14 @@ test("Successfully uploading a database to uploads.github.com", async (t) => {
|
||||
testRepoName,
|
||||
getTestConfig(tmpDir),
|
||||
testApiDetails,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
t.assert(
|
||||
loggedMessages.find(
|
||||
(v) =>
|
||||
v.type === "debug" &&
|
||||
v.message === "Successfully uploaded database for javascript"
|
||||
) !== undefined
|
||||
v.message === "Successfully uploaded database for javascript",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -13,7 +13,7 @@ export async function uploadDatabases(
|
||||
repositoryNwo: RepositoryNwo,
|
||||
config: Config,
|
||||
apiDetails: GitHubApiDetails,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
if (actionsUtil.getRequiredInput("upload-database") !== "true") {
|
||||
logger.debug("Database upload disabled in workflow. Skipping upload.");
|
||||
@@ -58,7 +58,7 @@ export async function uploadDatabases(
|
||||
"Content-Type": "application/zip",
|
||||
"Content-Length": bundledDbSize,
|
||||
},
|
||||
}
|
||||
},
|
||||
);
|
||||
logger.debug(`Successfully uploaded database for ${language}`);
|
||||
} finally {
|
||||
|
||||
@@ -5,19 +5,19 @@ import * as debugArtifacts from "./debug-artifacts";
|
||||
test("sanitizeArifactName", (t) => {
|
||||
t.deepEqual(
|
||||
debugArtifacts.sanitizeArifactName("hello-world_"),
|
||||
"hello-world_"
|
||||
"hello-world_",
|
||||
);
|
||||
t.deepEqual(debugArtifacts.sanitizeArifactName("hello`world`"), "helloworld");
|
||||
t.deepEqual(debugArtifacts.sanitizeArifactName("hello===123"), "hello123");
|
||||
t.deepEqual(
|
||||
debugArtifacts.sanitizeArifactName("*m)a&n^y%i££n+v!a:l[i]d"),
|
||||
"manyinvalid"
|
||||
"manyinvalid",
|
||||
);
|
||||
});
|
||||
|
||||
test("uploadDebugArtifacts", async (t) => {
|
||||
// Test that no error is thrown if artifacts list is empty.
|
||||
await t.notThrowsAsync(
|
||||
debugArtifacts.uploadDebugArtifacts([], "rootDir", "artifactName")
|
||||
debugArtifacts.uploadDebugArtifacts([], "rootDir", "artifactName"),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -26,7 +26,7 @@ export function sanitizeArifactName(name: string): string {
|
||||
export async function uploadDebugArtifacts(
|
||||
toUpload: string[],
|
||||
rootDir: string,
|
||||
artifactName: string
|
||||
artifactName: string,
|
||||
) {
|
||||
if (toUpload.length === 0) {
|
||||
return;
|
||||
@@ -36,25 +36,25 @@ export async function uploadDebugArtifacts(
|
||||
if (matrix) {
|
||||
try {
|
||||
for (const [, matrixVal] of Object.entries(
|
||||
JSON.parse(matrix) as any[][]
|
||||
JSON.parse(matrix) as any[][],
|
||||
).sort())
|
||||
suffix += `-${matrixVal}`;
|
||||
} catch (e) {
|
||||
core.info(
|
||||
"Could not parse user-specified `matrix` input into JSON. The debug artifact will not be named with the user's `matrix` input."
|
||||
"Could not parse user-specified `matrix` input into JSON. The debug artifact will not be named with the user's `matrix` input.",
|
||||
);
|
||||
}
|
||||
}
|
||||
await artifact.create().uploadArtifact(
|
||||
sanitizeArifactName(`${artifactName}${suffix}`),
|
||||
toUpload.map((file) => path.normalize(file)),
|
||||
path.normalize(rootDir)
|
||||
path.normalize(rootDir),
|
||||
);
|
||||
}
|
||||
|
||||
export async function uploadSarifDebugArtifact(
|
||||
config: Config,
|
||||
outputDir: string
|
||||
outputDir: string,
|
||||
) {
|
||||
if (!doesDirectoryExist(outputDir)) {
|
||||
return;
|
||||
@@ -83,7 +83,7 @@ export async function uploadLogsDebugArtifact(config: Config) {
|
||||
// Multilanguage tracing: there are additional logs in the root of the cluster
|
||||
const multiLanguageTracingLogsDirectory = path.resolve(
|
||||
config.dbLocation,
|
||||
"log"
|
||||
"log",
|
||||
);
|
||||
if (doesDirectoryExist(multiLanguageTracingLogsDirectory)) {
|
||||
toUpload = toUpload.concat(listFolder(multiLanguageTracingLogsDirectory));
|
||||
@@ -92,7 +92,7 @@ export async function uploadLogsDebugArtifact(config: Config) {
|
||||
await uploadDebugArtifacts(
|
||||
toUpload,
|
||||
config.dbLocation,
|
||||
config.debugArtifactName
|
||||
config.debugArtifactName,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -103,15 +103,15 @@ export async function uploadLogsDebugArtifact(config: Config) {
|
||||
*/
|
||||
async function createPartialDatabaseBundle(
|
||||
config: Config,
|
||||
language: Language
|
||||
language: Language,
|
||||
): Promise<string> {
|
||||
const databasePath = getCodeQLDatabasePath(config, language);
|
||||
const databaseBundlePath = path.resolve(
|
||||
config.dbLocation,
|
||||
`${config.debugDatabaseName}-${language}-partial.zip`
|
||||
`${config.debugDatabaseName}-${language}-partial.zip`,
|
||||
);
|
||||
core.info(
|
||||
`${config.debugDatabaseName}-${language} is not finalized. Uploading partial database bundle at ${databaseBundlePath}...`
|
||||
`${config.debugDatabaseName}-${language} is not finalized. Uploading partial database bundle at ${databaseBundlePath}...`,
|
||||
);
|
||||
// See `bundleDb` for explanation behind deleting existing db bundle.
|
||||
if (fs.existsSync(databaseBundlePath)) {
|
||||
@@ -128,21 +128,21 @@ async function createPartialDatabaseBundle(
|
||||
*/
|
||||
async function createDatabaseBundleCli(
|
||||
config: Config,
|
||||
language: Language
|
||||
language: Language,
|
||||
): Promise<string> {
|
||||
// Otherwise run `codeql database bundle` command.
|
||||
const databaseBundlePath = await bundleDb(
|
||||
config,
|
||||
language,
|
||||
await getCodeQL(config.codeQLCmd),
|
||||
`${config.debugDatabaseName}-${language}`
|
||||
`${config.debugDatabaseName}-${language}`,
|
||||
);
|
||||
return databaseBundlePath;
|
||||
}
|
||||
|
||||
export async function uploadDatabaseBundleDebugArtifact(
|
||||
config: Config,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
for (const language of config.languages) {
|
||||
try {
|
||||
@@ -150,7 +150,7 @@ export async function uploadDatabaseBundleDebugArtifact(
|
||||
if (!dbIsFinalized(config, language, logger)) {
|
||||
databaseBundlePath = await createPartialDatabaseBundle(
|
||||
config,
|
||||
language
|
||||
language,
|
||||
);
|
||||
} else {
|
||||
databaseBundlePath = await createDatabaseBundleCli(config, language);
|
||||
@@ -158,11 +158,11 @@ export async function uploadDatabaseBundleDebugArtifact(
|
||||
await uploadDebugArtifacts(
|
||||
[databaseBundlePath],
|
||||
config.dbLocation,
|
||||
config.debugArtifactName
|
||||
config.debugArtifactName,
|
||||
);
|
||||
} catch (error) {
|
||||
core.info(
|
||||
`Failed to upload database debug bundle for ${config.debugDatabaseName}-${language}: ${error}`
|
||||
`Failed to upload database debug bundle for ${config.debugDatabaseName}-${language}: ${error}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ test("checkoutExternalQueries", async (t) => {
|
||||
stderr += data.toString();
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
).exec();
|
||||
} catch (e) {
|
||||
console.log(`Command failed: git ${command.join(" ")}`);
|
||||
@@ -91,7 +91,7 @@ test("checkoutExternalQueries", async (t) => {
|
||||
apiURL: undefined,
|
||||
},
|
||||
tmpDir,
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.true(fs.existsSync(path.join(tmpDir, repoName)));
|
||||
t.true(fs.existsSync(path.join(tmpDir, repoName, commit1Sha)));
|
||||
@@ -109,7 +109,7 @@ test("checkoutExternalQueries", async (t) => {
|
||||
apiURL: undefined,
|
||||
},
|
||||
tmpDir,
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.true(fs.existsSync(path.join(tmpDir, repoName, commit2Sha)));
|
||||
t.true(fs.existsSync(path.join(tmpDir, repoName, commit2Sha, "a")));
|
||||
@@ -124,7 +124,7 @@ test("buildCheckoutURL", (t) => {
|
||||
externalRepoAuth: undefined,
|
||||
apiURL: undefined,
|
||||
}),
|
||||
"https://github.com/foo/bar"
|
||||
"https://github.com/foo/bar",
|
||||
);
|
||||
t.deepEqual(
|
||||
externalQueries.buildCheckoutURL("foo/bar", {
|
||||
@@ -132,7 +132,7 @@ test("buildCheckoutURL", (t) => {
|
||||
externalRepoAuth: undefined,
|
||||
apiURL: undefined,
|
||||
}),
|
||||
"https://github.example.com/foo/bar"
|
||||
"https://github.example.com/foo/bar",
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -141,7 +141,7 @@ test("buildCheckoutURL", (t) => {
|
||||
externalRepoAuth: "abc",
|
||||
apiURL: undefined,
|
||||
}),
|
||||
"https://x-access-token:abc@github.com/foo/bar"
|
||||
"https://x-access-token:abc@github.com/foo/bar",
|
||||
);
|
||||
t.deepEqual(
|
||||
externalQueries.buildCheckoutURL("foo/bar", {
|
||||
@@ -149,6 +149,6 @@ test("buildCheckoutURL", (t) => {
|
||||
externalRepoAuth: "abc",
|
||||
apiURL: undefined,
|
||||
}),
|
||||
"https://x-access-token:abc@github.example.com/foo/bar"
|
||||
"https://x-access-token:abc@github.example.com/foo/bar",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -15,7 +15,7 @@ export async function checkoutExternalRepository(
|
||||
ref: string,
|
||||
apiDetails: GitHubApiExternalRepoDetails,
|
||||
tempDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<string> {
|
||||
logger.info(`Checking out ${repository}`);
|
||||
|
||||
@@ -24,7 +24,7 @@ export async function checkoutExternalRepository(
|
||||
if (!checkoutLocation.startsWith(tempDir)) {
|
||||
// this still permits locations that mess with sibling repositories in `tempDir`, but that is acceptable
|
||||
throw new Error(
|
||||
`'${repository}@${ref}' is not a valid repository and reference.`
|
||||
`'${repository}@${ref}' is not a valid repository and reference.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@ export async function checkoutExternalRepository(
|
||||
|
||||
export function buildCheckoutURL(
|
||||
repository: string,
|
||||
apiDetails: GitHubApiExternalRepoDetails
|
||||
apiDetails: GitHubApiExternalRepoDetails,
|
||||
): string {
|
||||
const repoCloneURL = new URL(apiDetails.url);
|
||||
if (apiDetails.externalRepoAuth !== undefined) {
|
||||
|
||||
@@ -50,13 +50,13 @@ for (const variant of ALL_FEATURES_DISABLED_VARIANTS) {
|
||||
const features = setUpFeatureFlagTests(
|
||||
tmpDir,
|
||||
getRecordingLogger(loggedMessages),
|
||||
variant.gitHubVersion
|
||||
variant.gitHubVersion,
|
||||
);
|
||||
|
||||
for (const feature of Object.values(Feature)) {
|
||||
t.deepEqual(
|
||||
await features.getValue(feature, includeCodeQlIfRequired(feature)),
|
||||
featureConfig[feature].defaultValue
|
||||
featureConfig[feature].defaultValue,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -65,8 +65,8 @@ for (const variant of ALL_FEATURES_DISABLED_VARIANTS) {
|
||||
(v: LoggedMessage) =>
|
||||
v.type === "debug" &&
|
||||
v.message ===
|
||||
"Not running against github.com. Disabling all toggleable features."
|
||||
) !== undefined
|
||||
"Not running against github.com. Disabling all toggleable features.",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -77,7 +77,7 @@ test("API response missing and features use default value", async (t) => {
|
||||
const loggedMessages: LoggedMessage[] = [];
|
||||
const features = setUpFeatureFlagTests(
|
||||
tmpDir,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
|
||||
mockFeatureFlagApiEndpoint(403, {});
|
||||
@@ -85,7 +85,7 @@ test("API response missing and features use default value", async (t) => {
|
||||
for (const feature of Object.values(Feature)) {
|
||||
t.assert(
|
||||
(await features.getValue(feature, includeCodeQlIfRequired(feature))) ===
|
||||
featureConfig[feature].defaultValue
|
||||
featureConfig[feature].defaultValue,
|
||||
);
|
||||
}
|
||||
assertAllFeaturesUndefinedInApi(t, loggedMessages);
|
||||
@@ -97,7 +97,7 @@ test("Features use default value if they're not returned in API response", async
|
||||
const loggedMessages: LoggedMessage[] = [];
|
||||
const features = setUpFeatureFlagTests(
|
||||
tmpDir,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
|
||||
mockFeatureFlagApiEndpoint(200, {});
|
||||
@@ -105,7 +105,7 @@ test("Features use default value if they're not returned in API response", async
|
||||
for (const feature of Object.values(Feature)) {
|
||||
t.assert(
|
||||
(await features.getValue(feature, includeCodeQlIfRequired(feature))) ===
|
||||
featureConfig[feature].defaultValue
|
||||
featureConfig[feature].defaultValue,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -123,12 +123,12 @@ test("Feature flags exception is propagated if the API request errors", async (t
|
||||
async () =>
|
||||
features.getValue(
|
||||
Feature.MlPoweredQueriesEnabled,
|
||||
includeCodeQlIfRequired(Feature.MlPoweredQueriesEnabled)
|
||||
includeCodeQlIfRequired(Feature.MlPoweredQueriesEnabled),
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Encountered an error while trying to determine feature enablement: Error: some error message",
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -150,7 +150,7 @@ for (const feature of Object.keys(featureConfig)) {
|
||||
for (const f of Object.keys(featureConfig)) {
|
||||
actualFeatureEnablement[f] = await features.getValue(
|
||||
f as Feature,
|
||||
includeCodeQlIfRequired(f)
|
||||
includeCodeQlIfRequired(f),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -170,8 +170,8 @@ for (const feature of Object.keys(featureConfig)) {
|
||||
t.assert(
|
||||
!(await features.getValue(
|
||||
feature as Feature,
|
||||
includeCodeQlIfRequired(feature)
|
||||
))
|
||||
includeCodeQlIfRequired(feature),
|
||||
)),
|
||||
);
|
||||
|
||||
// set env var to true and check that the feature is now enabled
|
||||
@@ -179,8 +179,8 @@ for (const feature of Object.keys(featureConfig)) {
|
||||
t.assert(
|
||||
await features.getValue(
|
||||
feature as Feature,
|
||||
includeCodeQlIfRequired(feature)
|
||||
)
|
||||
includeCodeQlIfRequired(feature),
|
||||
),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -196,8 +196,8 @@ for (const feature of Object.keys(featureConfig)) {
|
||||
t.assert(
|
||||
await features.getValue(
|
||||
feature as Feature,
|
||||
includeCodeQlIfRequired(feature)
|
||||
)
|
||||
includeCodeQlIfRequired(feature),
|
||||
),
|
||||
);
|
||||
|
||||
// set env var to false and check that the feature is now disabled
|
||||
@@ -205,8 +205,8 @@ for (const feature of Object.keys(featureConfig)) {
|
||||
t.assert(
|
||||
!(await features.getValue(
|
||||
feature as Feature,
|
||||
includeCodeQlIfRequired(feature)
|
||||
))
|
||||
includeCodeQlIfRequired(feature),
|
||||
)),
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -265,13 +265,13 @@ for (const feature of Object.keys(featureConfig)) {
|
||||
test("At least one feature has a minimum version specified", (t) => {
|
||||
t.assert(
|
||||
Object.values(featureConfig).some((f) => f.minimumVersion !== undefined),
|
||||
"At least one feature should have a minimum version specified"
|
||||
"At least one feature should have a minimum version specified",
|
||||
);
|
||||
|
||||
// An even less likely scenario is that we no longer have any features.
|
||||
t.assert(
|
||||
Object.values(featureConfig).length > 0,
|
||||
"There should be at least one feature"
|
||||
"There should be at least one feature",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -285,24 +285,24 @@ test("Feature flags are saved to disk", async (t) => {
|
||||
|
||||
t.false(
|
||||
fs.existsSync(cachedFeatureFlags),
|
||||
"Feature flag cached file should not exist before getting feature flags"
|
||||
"Feature flag cached file should not exist before getting feature flags",
|
||||
);
|
||||
|
||||
t.true(
|
||||
await features.getValue(
|
||||
Feature.CliConfigFileEnabled,
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled)
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled),
|
||||
),
|
||||
"Feature flag should be enabled initially"
|
||||
"Feature flag should be enabled initially",
|
||||
);
|
||||
|
||||
t.true(
|
||||
fs.existsSync(cachedFeatureFlags),
|
||||
"Feature flag cached file should exist after getting feature flags"
|
||||
"Feature flag cached file should exist after getting feature flags",
|
||||
);
|
||||
|
||||
const actualFeatureEnablement = JSON.parse(
|
||||
fs.readFileSync(cachedFeatureFlags, "utf8")
|
||||
fs.readFileSync(cachedFeatureFlags, "utf8"),
|
||||
);
|
||||
t.deepEqual(actualFeatureEnablement, expectedFeatureEnablement);
|
||||
|
||||
@@ -310,7 +310,7 @@ test("Feature flags are saved to disk", async (t) => {
|
||||
actualFeatureEnablement[Feature.CliConfigFileEnabled] = false;
|
||||
fs.writeFileSync(
|
||||
cachedFeatureFlags,
|
||||
JSON.stringify(actualFeatureEnablement)
|
||||
JSON.stringify(actualFeatureEnablement),
|
||||
);
|
||||
|
||||
// delete the in memory cache so that we are forced to use the cached file
|
||||
@@ -319,9 +319,9 @@ test("Feature flags are saved to disk", async (t) => {
|
||||
t.false(
|
||||
await features.getValue(
|
||||
Feature.CliConfigFileEnabled,
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled)
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled),
|
||||
),
|
||||
"Feature flag should be enabled after reading from cached file"
|
||||
"Feature flag should be enabled after reading from cached file",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -336,23 +336,23 @@ test("Environment variable can override feature flag cache", async (t) => {
|
||||
t.true(
|
||||
await features.getValue(
|
||||
Feature.CliConfigFileEnabled,
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled)
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled),
|
||||
),
|
||||
"Feature flag should be enabled initially"
|
||||
"Feature flag should be enabled initially",
|
||||
);
|
||||
|
||||
t.true(
|
||||
fs.existsSync(cachedFeatureFlags),
|
||||
"Feature flag cached file should exist after getting feature flags"
|
||||
"Feature flag cached file should exist after getting feature flags",
|
||||
);
|
||||
process.env.CODEQL_PASS_CONFIG_TO_CLI = "false";
|
||||
|
||||
t.false(
|
||||
await features.getValue(
|
||||
Feature.CliConfigFileEnabled,
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled)
|
||||
includeCodeQlIfRequired(Feature.CliConfigFileEnabled),
|
||||
),
|
||||
"Feature flag should be disabled after setting env var"
|
||||
"Feature flag should be disabled after setting env var",
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -384,7 +384,7 @@ test("selects CLI v2.20.1 on Dotcom when feature flags enable v2.20.0 and v2.20.
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
||||
GitHubVariant.DOTCOM
|
||||
GitHubVariant.DOTCOM,
|
||||
);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: "2.20.1",
|
||||
@@ -402,7 +402,7 @@ test("includes tag name when feature flags enable version greater than v2.13.4",
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
||||
GitHubVariant.DOTCOM
|
||||
GitHubVariant.DOTCOM,
|
||||
);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: "2.20.0",
|
||||
@@ -419,7 +419,7 @@ test(`selects CLI from defaults.json on Dotcom when no default version feature f
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
||||
GitHubVariant.DOTCOM
|
||||
GitHubVariant.DOTCOM,
|
||||
);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: defaults.cliVersion,
|
||||
@@ -438,7 +438,7 @@ test(`selects CLI from defaults.json on Dotcom when default version feature flag
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
||||
GitHubVariant.DOTCOM
|
||||
GitHubVariant.DOTCOM,
|
||||
);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: defaults.cliVersion,
|
||||
@@ -453,7 +453,7 @@ test("ignores invalid version numbers in default version feature flags", async (
|
||||
const loggedMessages = [];
|
||||
const features = setUpFeatureFlagTests(
|
||||
tmpDir,
|
||||
getRecordingLogger(loggedMessages)
|
||||
getRecordingLogger(loggedMessages),
|
||||
);
|
||||
const expectedFeatureEnablement = initializeFeatures(true);
|
||||
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
|
||||
@@ -463,7 +463,7 @@ test("ignores invalid version numbers in default version feature flags", async (
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
||||
GitHubVariant.DOTCOM
|
||||
GitHubVariant.DOTCOM,
|
||||
);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: "2.20.1",
|
||||
@@ -476,8 +476,8 @@ test("ignores invalid version numbers in default version feature flags", async (
|
||||
(v: LoggedMessage) =>
|
||||
v.type === "warning" &&
|
||||
v.message ===
|
||||
"Ignoring feature flag default_codeql_version_2_20_invalid_enabled as it does not specify a valid CodeQL version."
|
||||
) !== undefined
|
||||
"Ignoring feature flag default_codeql_version_2_20_invalid_enabled as it does not specify a valid CodeQL version.",
|
||||
) !== undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -486,14 +486,14 @@ test("feature flags should end with _enabled", async (t) => {
|
||||
for (const feature of Object.values(Feature)) {
|
||||
t.assert(
|
||||
feature.endsWith("_enabled"),
|
||||
`${feature} should end with '_enabled'`
|
||||
`${feature} should end with '_enabled'`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
function assertAllFeaturesUndefinedInApi(
|
||||
t: ExecutionContext<unknown>,
|
||||
loggedMessages: LoggedMessage[]
|
||||
loggedMessages: LoggedMessage[],
|
||||
) {
|
||||
for (const feature of Object.keys(featureConfig)) {
|
||||
t.assert(
|
||||
@@ -501,8 +501,8 @@ function assertAllFeaturesUndefinedInApi(
|
||||
(v) =>
|
||||
v.type === "debug" &&
|
||||
(v.message as string).includes(feature) &&
|
||||
(v.message as string).includes("undefined in API response")
|
||||
) !== undefined
|
||||
(v.message as string).includes("undefined in API response"),
|
||||
) !== undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -517,7 +517,7 @@ function initializeFeatures(initialValue: boolean) {
|
||||
function setUpFeatureFlagTests(
|
||||
tmpDir: string,
|
||||
logger = getRunnerLogger(true),
|
||||
gitHubVersion = { type: GitHubVariant.DOTCOM } as util.GitHubVersion
|
||||
gitHubVersion = { type: GitHubVariant.DOTCOM } as util.GitHubVersion,
|
||||
): FeatureEnablement {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ export interface CodeQLDefaultVersionInfo {
|
||||
export interface FeatureEnablement {
|
||||
/** Gets the default version of the CodeQL tools. */
|
||||
getDefaultCliVersion(
|
||||
variant: util.GitHubVariant
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo>;
|
||||
getValue(feature: Feature, codeql?: CodeQL): Promise<boolean>;
|
||||
}
|
||||
@@ -132,18 +132,18 @@ export class Features implements FeatureEnablement {
|
||||
gitHubVersion: util.GitHubVersion,
|
||||
repositoryNwo: RepositoryNwo,
|
||||
tempDir: string,
|
||||
private readonly logger: Logger
|
||||
private readonly logger: Logger,
|
||||
) {
|
||||
this.gitHubFeatureFlags = new GitHubFeatureFlags(
|
||||
gitHubVersion,
|
||||
repositoryNwo,
|
||||
path.join(tempDir, FEATURE_FLAGS_FILE_NAME),
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
async getDefaultCliVersion(
|
||||
variant: util.GitHubVariant
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
return await this.gitHubFeatureFlags.getDefaultCliVersion(variant);
|
||||
}
|
||||
@@ -163,7 +163,7 @@ export class Features implements FeatureEnablement {
|
||||
async getValue(feature: Feature, codeql?: CodeQL): Promise<boolean> {
|
||||
if (!codeql && featureConfig[feature].minimumVersion) {
|
||||
throw new Error(
|
||||
`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`
|
||||
`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ export class Features implements FeatureEnablement {
|
||||
// Do not use this feature if user explicitly disables it via an environment variable.
|
||||
if (envVar === "false") {
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is disabled via the environment variable ${featureConfig[feature].envVar}.`
|
||||
`Feature ${feature} is disabled via the environment variable ${featureConfig[feature].envVar}.`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
@@ -185,13 +185,13 @@ export class Features implements FeatureEnablement {
|
||||
if (!(await util.codeQlVersionAbove(codeql, minimumVersion))) {
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is disabled because the CodeQL CLI version is older than the minimum ` +
|
||||
`version ${minimumVersion}.`
|
||||
`version ${minimumVersion}.`,
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
this.logger.debug(
|
||||
`CodeQL CLI version ${await codeql.getVersion()} is newer than the minimum ` +
|
||||
`version ${minimumVersion} for feature ${feature}.`
|
||||
`version ${minimumVersion} for feature ${feature}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -199,7 +199,7 @@ export class Features implements FeatureEnablement {
|
||||
// Use this feature if user explicitly enables it via an environment variable.
|
||||
if (envVar === "true") {
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is enabled via the environment variable ${featureConfig[feature].envVar}.`
|
||||
`Feature ${feature} is enabled via the environment variable ${featureConfig[feature].envVar}.`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
@@ -210,7 +210,7 @@ export class Features implements FeatureEnablement {
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is ${
|
||||
apiValue ? "enabled" : "disabled"
|
||||
} via the GitHub API.`
|
||||
} via the GitHub API.`,
|
||||
);
|
||||
return apiValue;
|
||||
}
|
||||
@@ -219,7 +219,7 @@ export class Features implements FeatureEnablement {
|
||||
this.logger.debug(
|
||||
`Feature ${feature} is ${
|
||||
defaultValue ? "enabled" : "disabled"
|
||||
} due to its default value.`
|
||||
} due to its default value.`,
|
||||
);
|
||||
return defaultValue;
|
||||
}
|
||||
@@ -236,7 +236,7 @@ class GitHubFeatureFlags {
|
||||
private readonly gitHubVersion: util.GitHubVersion,
|
||||
private readonly repositoryNwo: RepositoryNwo,
|
||||
private readonly featureFlagsFile: string,
|
||||
private readonly logger: Logger
|
||||
private readonly logger: Logger,
|
||||
) {
|
||||
this.hasAccessedRemoteFeatureFlags = false; // Not accessed by default.
|
||||
}
|
||||
@@ -251,13 +251,13 @@ class GitHubFeatureFlags {
|
||||
const version = f
|
||||
.substring(
|
||||
DEFAULT_VERSION_FEATURE_FLAG_PREFIX.length,
|
||||
f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length
|
||||
f.length - DEFAULT_VERSION_FEATURE_FLAG_SUFFIX.length,
|
||||
)
|
||||
.replace(/_/g, ".");
|
||||
|
||||
if (!semver.valid(version)) {
|
||||
this.logger.warning(
|
||||
`Ignoring feature flag ${f} as it does not specify a valid CodeQL version.`
|
||||
`Ignoring feature flag ${f} as it does not specify a valid CodeQL version.`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -265,7 +265,7 @@ class GitHubFeatureFlags {
|
||||
}
|
||||
|
||||
async getDefaultCliVersion(
|
||||
variant: util.GitHubVariant
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
if (variant === util.GitHubVariant.DOTCOM) {
|
||||
return await this.getDefaultDotcomCliVersion();
|
||||
@@ -281,13 +281,13 @@ class GitHubFeatureFlags {
|
||||
|
||||
const enabledFeatureFlagCliVersions = Object.entries(response)
|
||||
.map(([f, isEnabled]) =>
|
||||
isEnabled ? this.getCliVersionFromFeatureFlag(f) : undefined
|
||||
isEnabled ? this.getCliVersionFromFeatureFlag(f) : undefined,
|
||||
)
|
||||
.filter(
|
||||
(f) =>
|
||||
f !== undefined &&
|
||||
// Only consider versions that have semantically versioned bundles.
|
||||
semver.gte(f, CODEQL_VERSION_BUNDLE_SEMANTICALLY_VERSIONED)
|
||||
semver.gte(f, CODEQL_VERSION_BUNDLE_SEMANTICALLY_VERSIONED),
|
||||
)
|
||||
.map((f) => f as string);
|
||||
|
||||
@@ -304,7 +304,7 @@ class GitHubFeatureFlags {
|
||||
// version that would have been specified by the feature flags before they were misconfigured.
|
||||
this.logger.warning(
|
||||
"Feature flags do not specify a default CLI version. Falling back to the CLI version " +
|
||||
`shipped with the Action. This is ${defaults.cliVersion}.`
|
||||
`shipped with the Action. This is ${defaults.cliVersion}.`,
|
||||
);
|
||||
const result: CodeQLDefaultVersionInfo = {
|
||||
cliVersion: defaults.cliVersion,
|
||||
@@ -319,10 +319,10 @@ class GitHubFeatureFlags {
|
||||
const maxCliVersion = enabledFeatureFlagCliVersions.reduce(
|
||||
(maxVersion, currentVersion) =>
|
||||
currentVersion > maxVersion ? currentVersion : maxVersion,
|
||||
enabledFeatureFlagCliVersions[0]
|
||||
enabledFeatureFlagCliVersions[0],
|
||||
);
|
||||
this.logger.debug(
|
||||
`Derived default CLI version of ${maxCliVersion} from feature flags.`
|
||||
`Derived default CLI version of ${maxCliVersion} from feature flags.`,
|
||||
);
|
||||
return {
|
||||
cliVersion: maxCliVersion,
|
||||
@@ -379,27 +379,27 @@ class GitHubFeatureFlags {
|
||||
try {
|
||||
if (fs.existsSync(this.featureFlagsFile)) {
|
||||
this.logger.debug(
|
||||
`Loading feature flags from ${this.featureFlagsFile}`
|
||||
`Loading feature flags from ${this.featureFlagsFile}`,
|
||||
);
|
||||
return JSON.parse(fs.readFileSync(this.featureFlagsFile, "utf8"));
|
||||
}
|
||||
} catch (e) {
|
||||
this.logger.warning(
|
||||
`Error reading cached feature flags file ${this.featureFlagsFile}: ${e}. Requesting from GitHub instead.`
|
||||
`Error reading cached feature flags file ${this.featureFlagsFile}: ${e}. Requesting from GitHub instead.`,
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private async writeLocalFlags(
|
||||
flags: GitHubFeatureFlagsApiResponse
|
||||
flags: GitHubFeatureFlagsApiResponse,
|
||||
): Promise<void> {
|
||||
try {
|
||||
this.logger.debug(`Writing feature flags to ${this.featureFlagsFile}`);
|
||||
fs.writeFileSync(this.featureFlagsFile, JSON.stringify(flags));
|
||||
} catch (e) {
|
||||
this.logger.warning(
|
||||
`Error writing cached feature flags file ${this.featureFlagsFile}: ${e}.`
|
||||
`Error writing cached feature flags file ${this.featureFlagsFile}: ${e}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -408,7 +408,7 @@ class GitHubFeatureFlags {
|
||||
// Do nothing when not running against github.com
|
||||
if (this.gitHubVersion.type !== util.GitHubVariant.DOTCOM) {
|
||||
this.logger.debug(
|
||||
"Not running against github.com. Disabling all toggleable features."
|
||||
"Not running against github.com. Disabling all toggleable features.",
|
||||
);
|
||||
this.hasAccessedRemoteFeatureFlags = false;
|
||||
return {};
|
||||
@@ -419,12 +419,12 @@ class GitHubFeatureFlags {
|
||||
{
|
||||
owner: this.repositoryNwo.owner,
|
||||
repo: this.repositoryNwo.repo,
|
||||
}
|
||||
},
|
||||
);
|
||||
const remoteFlags = response.data;
|
||||
this.logger.debug(
|
||||
"Loaded the following default values for the feature flags from the Code Scanning API: " +
|
||||
`${JSON.stringify(remoteFlags)}`
|
||||
`${JSON.stringify(remoteFlags)}`,
|
||||
);
|
||||
this.hasAccessedRemoteFeatureFlags = true;
|
||||
return remoteFlags;
|
||||
@@ -434,7 +434,7 @@ class GitHubFeatureFlags {
|
||||
"This run of the CodeQL Action does not have permission to access Code Scanning API endpoints. " +
|
||||
"As a result, it will not be opted into any experimental features. " +
|
||||
"This could be because the Action is running on a pull request from a fork. If not, " +
|
||||
`please ensure the Action has the 'security-events: write' permission. Details: ${e.message}`
|
||||
`please ensure the Action has the 'security-events: write' permission. Details: ${e.message}`,
|
||||
);
|
||||
this.hasAccessedRemoteFeatureFlags = false;
|
||||
return {};
|
||||
@@ -444,7 +444,7 @@ class GitHubFeatureFlags {
|
||||
// therefore lead to alert churn. As a result, we crash if we cannot determine the value of
|
||||
// the feature.
|
||||
throw new Error(
|
||||
`Encountered an error while trying to determine feature enablement: ${e}`
|
||||
`Encountered an error while trying to determine feature enablement: ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -457,7 +457,7 @@ class GitHubFeatureFlags {
|
||||
*/
|
||||
export async function useCodeScanningConfigInCli(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement
|
||||
features: FeatureEnablement,
|
||||
): Promise<boolean> {
|
||||
return await features.getValue(Feature.CliConfigFileEnabled, codeql);
|
||||
}
|
||||
@@ -465,15 +465,15 @@ export async function useCodeScanningConfigInCli(
|
||||
export async function logCodeScanningConfigInCli(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
if (await useCodeScanningConfigInCli(codeql, features)) {
|
||||
logger.info(
|
||||
"Code Scanning configuration file being processed in the codeql CLI."
|
||||
"Code Scanning configuration file being processed in the codeql CLI.",
|
||||
);
|
||||
} else {
|
||||
logger.info(
|
||||
"Code Scanning configuration file being processed in the codeql-action."
|
||||
"Code Scanning configuration file being processed in the codeql-action.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ setupTests(test);
|
||||
async function testHash(
|
||||
t: ava.Assertions,
|
||||
input: string,
|
||||
expectedHashes: string[]
|
||||
expectedHashes: string[],
|
||||
) {
|
||||
await util.withTmpDir(async (tmpDir) => {
|
||||
const tmpFile = path.resolve(tmpDir, "testfile");
|
||||
@@ -78,7 +78,7 @@ test("hash", async (t: ava.Assertions) => {
|
||||
"b3edc88f2938467e:1",
|
||||
"c8e28b0b4002a3a0:1",
|
||||
"c129715d7a2bc9a3:1",
|
||||
]
|
||||
],
|
||||
);
|
||||
await testHash(t, " hello; \t\nworld!!!\r\n\n\r \t\tGreetings\r End\r\n", [
|
||||
"e9496ae3ebfced30:1",
|
||||
@@ -117,7 +117,7 @@ test("hash", async (t: ava.Assertions) => {
|
||||
"2c644846cb18d53e:1",
|
||||
"f1b89f20de0d133:1",
|
||||
"c129715d7a2bc9a3:1",
|
||||
]
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
@@ -130,7 +130,7 @@ function testResolveUriToFile(uri: any, index: any, artifactsURIs: any[]) {
|
||||
location,
|
||||
artifacts,
|
||||
process.cwd(),
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -154,20 +154,20 @@ test("resolveUriToFile", (t) => {
|
||||
testResolveUriToFile(relativeFilepath, undefined, [])
|
||||
?.split(path.sep)
|
||||
.join("/"),
|
||||
filepath
|
||||
filepath,
|
||||
);
|
||||
t.is(
|
||||
testResolveUriToFile(`file://${relativeFilepath}`, undefined, [])
|
||||
?.split(path.sep)
|
||||
.join("/"),
|
||||
filepath
|
||||
filepath,
|
||||
);
|
||||
|
||||
// Absolute paths outside the src root are discarded
|
||||
t.is(testResolveUriToFile("/src/foo/bar.js", undefined, []), undefined);
|
||||
t.is(
|
||||
testResolveUriToFile("file:///src/foo/bar.js", undefined, []),
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
// Other schemes are discarded
|
||||
@@ -200,14 +200,14 @@ test("addFingerprints", async (t) => {
|
||||
const input = JSON.parse(
|
||||
fs
|
||||
.readFileSync(`${__dirname}/../src/testdata/fingerprinting.input.sarif`)
|
||||
.toString()
|
||||
.toString(),
|
||||
) as util.SarifFile;
|
||||
const expected = JSON.parse(
|
||||
fs
|
||||
.readFileSync(
|
||||
`${__dirname}/../src/testdata/fingerprinting.expected.sarif`
|
||||
`${__dirname}/../src/testdata/fingerprinting.expected.sarif`,
|
||||
)
|
||||
.toString()
|
||||
.toString(),
|
||||
);
|
||||
|
||||
// The URIs in the SARIF files resolve to files in the testdata directory
|
||||
@@ -217,9 +217,9 @@ test("addFingerprints", async (t) => {
|
||||
await fingerprints.addFingerprints(
|
||||
input,
|
||||
sourceRoot,
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
),
|
||||
expected
|
||||
expected,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -228,14 +228,14 @@ test("missingRegions", async (t) => {
|
||||
const input = JSON.parse(
|
||||
fs
|
||||
.readFileSync(`${__dirname}/../src/testdata/fingerprinting2.input.sarif`)
|
||||
.toString()
|
||||
.toString(),
|
||||
) as util.SarifFile;
|
||||
const expected = JSON.parse(
|
||||
fs
|
||||
.readFileSync(
|
||||
`${__dirname}/../src/testdata/fingerprinting2.expected.sarif`
|
||||
`${__dirname}/../src/testdata/fingerprinting2.expected.sarif`,
|
||||
)
|
||||
.toString()
|
||||
.toString(),
|
||||
);
|
||||
|
||||
// The URIs in the SARIF files resolve to files in the testdata directory
|
||||
@@ -245,8 +245,8 @@ test("missingRegions", async (t) => {
|
||||
await fingerprints.addFingerprints(
|
||||
input,
|
||||
sourceRoot,
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
),
|
||||
expected
|
||||
expected,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -139,7 +139,7 @@ export async function hash(callback: hashCallback, filepath: string) {
|
||||
function locationUpdateCallback(
|
||||
result: SarifResult,
|
||||
location: any,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): hashCallback {
|
||||
let locationStartLine = location.physicalLocation?.region?.startLine;
|
||||
if (locationStartLine === undefined) {
|
||||
@@ -166,7 +166,7 @@ function locationUpdateCallback(
|
||||
result.partialFingerprints.primaryLocationLineHash = hashValue;
|
||||
} else if (existingFingerprint !== hashValue) {
|
||||
logger.warning(
|
||||
`Calculated fingerprint of ${hashValue} for file ${location.physicalLocation.artifactLocation.uri} line ${lineNumber}, but found existing inconsistent fingerprint value ${existingFingerprint}`
|
||||
`Calculated fingerprint of ${hashValue} for file ${location.physicalLocation.artifactLocation.uri} line ${lineNumber}, but found existing inconsistent fingerprint value ${existingFingerprint}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
@@ -180,7 +180,7 @@ export function resolveUriToFile(
|
||||
location: any,
|
||||
artifacts: any[],
|
||||
sourceRoot: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): string | undefined {
|
||||
// This may be referencing an artifact
|
||||
if (!location.uri && location.index !== undefined) {
|
||||
@@ -217,7 +217,7 @@ export function resolveUriToFile(
|
||||
}
|
||||
if (uri.indexOf("://") !== -1) {
|
||||
logger.debug(
|
||||
`Ignoring location URI "${uri}" as the scheme is not recognised`
|
||||
`Ignoring location URI "${uri}" as the scheme is not recognised`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -226,7 +226,7 @@ export function resolveUriToFile(
|
||||
const srcRootPrefix = `${sourceRoot}/`;
|
||||
if (uri.startsWith("/") && !uri.startsWith(srcRootPrefix)) {
|
||||
logger.debug(
|
||||
`Ignoring location URI "${uri}" as it is outside of the src root`
|
||||
`Ignoring location URI "${uri}" as it is outside of the src root`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -257,7 +257,7 @@ export function resolveUriToFile(
|
||||
export async function addFingerprints(
|
||||
sarif: SarifFile,
|
||||
sourceRoot: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<SarifFile> {
|
||||
// Gather together results for the same file and construct
|
||||
// callbacks to accept hashes for that file and update the location
|
||||
@@ -272,8 +272,8 @@ export async function addFingerprints(
|
||||
if (!primaryLocation?.physicalLocation?.artifactLocation) {
|
||||
logger.debug(
|
||||
`Unable to compute fingerprint for invalid location: ${JSON.stringify(
|
||||
primaryLocation
|
||||
)}`
|
||||
primaryLocation,
|
||||
)}`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -287,7 +287,7 @@ export async function addFingerprints(
|
||||
primaryLocation.physicalLocation.artifactLocation,
|
||||
artifacts,
|
||||
sourceRoot,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
if (!filepath) {
|
||||
continue;
|
||||
@@ -296,7 +296,7 @@ export async function addFingerprints(
|
||||
callbacksByFile[filepath] = [];
|
||||
}
|
||||
callbacksByFile[filepath].push(
|
||||
locationUpdateCallback(result, primaryLocation, logger)
|
||||
locationUpdateCallback(result, primaryLocation, logger),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ test("post: init action with debug mode off", async (t) => {
|
||||
printDebugLogsSpy,
|
||||
parseRepositoryNwo("github/codeql-action"),
|
||||
createFeatures([]),
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
t.assert(uploadDatabaseBundleSpy.notCalled);
|
||||
@@ -74,7 +74,7 @@ test("post: init action with debug mode on", async (t) => {
|
||||
printDebugLogsSpy,
|
||||
parseRepositoryNwo("github/codeql-action"),
|
||||
createFeatures([]),
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
t.assert(uploadDatabaseBundleSpy.called);
|
||||
@@ -220,7 +220,7 @@ for (const { uploadInput, shouldUpload } of UPLOAD_INPUT_TEST_CASES) {
|
||||
if (!shouldUpload) {
|
||||
t.is(
|
||||
result.upload_failed_run_skipped_because,
|
||||
"SARIF upload is disabled"
|
||||
"SARIF upload is disabled",
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -280,7 +280,7 @@ test("uploading failed SARIF run fails when workflow uses a complex upload input
|
||||
t.is(
|
||||
result.upload_failed_run_error,
|
||||
"Could not get upload input to github/codeql-action/analyze since it contained an " +
|
||||
"unrecognized dynamic value."
|
||||
"unrecognized dynamic value.",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -297,13 +297,13 @@ test("uploading failed SARIF run fails when workflow does not reference github/c
|
||||
t.is(
|
||||
result.upload_failed_run_error,
|
||||
"Could not get upload input to github/codeql-action/analyze since the analyze job does not " +
|
||||
"call github/codeql-action/analyze."
|
||||
"call github/codeql-action/analyze.",
|
||||
);
|
||||
t.truthy(result.upload_failed_run_stack_trace);
|
||||
});
|
||||
|
||||
function createTestWorkflow(
|
||||
steps: workflow.WorkflowJobStep[]
|
||||
steps: workflow.WorkflowJobStep[],
|
||||
): workflow.Workflow {
|
||||
return {
|
||||
name: "CodeQL",
|
||||
@@ -340,7 +340,7 @@ async function testFailedSarifUpload(
|
||||
expectUpload?: boolean;
|
||||
exportDiagnosticsEnabled?: boolean;
|
||||
matrix?: { [key: string]: string };
|
||||
} = {}
|
||||
} = {},
|
||||
): Promise<initActionPostHelper.UploadFailedSarifResult> {
|
||||
const config = {
|
||||
codeQLCmd: "codeql",
|
||||
@@ -364,7 +364,7 @@ async function testFailedSarifUpload(
|
||||
sinon.stub(codeql, "getCodeQL").resolves(codeqlObject);
|
||||
const databaseExportDiagnosticsStub = sinon.stub(
|
||||
codeqlObject,
|
||||
"databaseExportDiagnostics"
|
||||
"databaseExportDiagnostics",
|
||||
);
|
||||
const diagnosticsExportStub = sinon.stub(codeqlObject, "diagnosticsExport");
|
||||
|
||||
@@ -386,7 +386,7 @@ async function testFailedSarifUpload(
|
||||
config,
|
||||
parseRepositoryNwo("github/codeql-action"),
|
||||
createFeatures(features),
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
if (expectUpload) {
|
||||
t.deepEqual(result, {
|
||||
@@ -400,18 +400,18 @@ async function testFailedSarifUpload(
|
||||
sinon.match.string,
|
||||
category,
|
||||
sinon.match.any,
|
||||
sinon.match.any
|
||||
sinon.match.any,
|
||||
),
|
||||
`Actual args were: ${databaseExportDiagnosticsStub.args}`
|
||||
`Actual args were: ${databaseExportDiagnosticsStub.args}`,
|
||||
);
|
||||
} else {
|
||||
t.true(
|
||||
diagnosticsExportStub.calledOnceWith(
|
||||
sinon.match.string,
|
||||
category,
|
||||
config
|
||||
config,
|
||||
),
|
||||
`Actual args were: ${diagnosticsExportStub.args}`
|
||||
`Actual args were: ${diagnosticsExportStub.args}`,
|
||||
);
|
||||
}
|
||||
t.true(
|
||||
@@ -419,14 +419,14 @@ async function testFailedSarifUpload(
|
||||
sinon.match.string,
|
||||
sinon.match.string,
|
||||
category,
|
||||
sinon.match.any
|
||||
sinon.match.any,
|
||||
),
|
||||
`Actual args were: ${uploadFromActions.args}`
|
||||
`Actual args were: ${uploadFromActions.args}`,
|
||||
);
|
||||
t.true(
|
||||
waitForProcessing.calledOnceWith(sinon.match.any, "42", sinon.match.any, {
|
||||
isUnsuccessfulExecution: true,
|
||||
})
|
||||
}),
|
||||
);
|
||||
} else {
|
||||
t.true(diagnosticsExportStub.notCalled);
|
||||
|
||||
@@ -31,7 +31,7 @@ export interface UploadFailedSarifResult extends uploadLib.UploadStatusReport {
|
||||
}
|
||||
|
||||
function createFailedUploadFailedSarifResult(
|
||||
error: unknown
|
||||
error: unknown,
|
||||
): UploadFailedSarifResult {
|
||||
const wrappedError = wrapError(error);
|
||||
return {
|
||||
@@ -48,7 +48,7 @@ async function maybeUploadFailedSarif(
|
||||
config: Config,
|
||||
repositoryNwo: RepositoryNwo,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<UploadFailedSarifResult> {
|
||||
if (!config.codeQLCmd) {
|
||||
return { upload_failed_run_skipped_because: "CodeQL command not found" };
|
||||
@@ -63,7 +63,7 @@ async function maybeUploadFailedSarif(
|
||||
const shouldUpload = getUploadInputOrThrow(workflow, jobName, matrix);
|
||||
if (
|
||||
!["always", "failure-only"].includes(
|
||||
actionsUtil.getUploadValue(shouldUpload)
|
||||
actionsUtil.getUploadValue(shouldUpload),
|
||||
) ||
|
||||
isInTestMode()
|
||||
) {
|
||||
@@ -88,7 +88,7 @@ async function maybeUploadFailedSarif(
|
||||
sarifFile,
|
||||
category,
|
||||
config.tempDir,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -97,13 +97,13 @@ async function maybeUploadFailedSarif(
|
||||
sarifFile,
|
||||
checkoutPath,
|
||||
category,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
await uploadLib.waitForProcessing(
|
||||
repositoryNwo,
|
||||
uploadResult.sarifID,
|
||||
logger,
|
||||
{ isUnsuccessfulExecution: true }
|
||||
{ isUnsuccessfulExecution: true },
|
||||
);
|
||||
return uploadResult?.statusReport ?? {};
|
||||
}
|
||||
@@ -112,7 +112,7 @@ export async function tryUploadSarifIfRunFailed(
|
||||
config: Config,
|
||||
repositoryNwo: RepositoryNwo,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<UploadFailedSarifResult> {
|
||||
if (process.env[EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY] !== "true") {
|
||||
try {
|
||||
@@ -120,11 +120,11 @@ export async function tryUploadSarifIfRunFailed(
|
||||
config,
|
||||
repositoryNwo,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
} catch (e) {
|
||||
logger.debug(
|
||||
`Failed to upload a SARIF file for this failed CodeQL code scanning run. ${e}`
|
||||
`Failed to upload a SARIF file for this failed CodeQL code scanning run. ${e}`,
|
||||
);
|
||||
return createFailedUploadFailedSarifResult(e);
|
||||
}
|
||||
@@ -142,12 +142,12 @@ export async function run(
|
||||
printDebugLogs: Function,
|
||||
repositoryNwo: RepositoryNwo,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
const config = await getConfig(actionsUtil.getTemporaryDirectory(), logger);
|
||||
if (config === undefined) {
|
||||
logger.warning(
|
||||
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any."
|
||||
"Debugging artifacts are unavailable since the 'init' Action failed before it could produce any.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -156,13 +156,13 @@ export async function run(
|
||||
config,
|
||||
repositoryNwo,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
if (uploadFailedSarifResult.upload_failed_run_skipped_because) {
|
||||
logger.debug(
|
||||
"Won't upload a failed SARIF file for this CodeQL code scanning run because: " +
|
||||
`${uploadFailedSarifResult.upload_failed_run_skipped_because}.`
|
||||
`${uploadFailedSarifResult.upload_failed_run_skipped_because}.`,
|
||||
);
|
||||
}
|
||||
// Throw an error if in integration tests, we expected to upload a SARIF file for a failed run
|
||||
@@ -174,14 +174,14 @@ export async function run(
|
||||
const error = JSON.stringify(uploadFailedSarifResult);
|
||||
throw new Error(
|
||||
"Expected to upload a failed SARIF file for this CodeQL code scanning run, " +
|
||||
`but the result was instead ${error}.`
|
||||
`but the result was instead ${error}.`,
|
||||
);
|
||||
}
|
||||
|
||||
// Upload appropriate Actions artifacts for debugging
|
||||
if (config.debugMode) {
|
||||
core.info(
|
||||
"Debug mode is on. Uploading available database bundles and logs as Actions debugging artifacts..."
|
||||
"Debug mode is on. Uploading available database bundles and logs as Actions debugging artifacts...",
|
||||
);
|
||||
await uploadDatabaseBundleDebugArtifact(config, logger);
|
||||
await uploadLogsDebugArtifact(config);
|
||||
|
||||
@@ -43,13 +43,13 @@ async function runWrapper() {
|
||||
checkGitHubVersionInRange(gitHubVersion, logger);
|
||||
|
||||
const repositoryNwo = parseRepositoryNwo(
|
||||
getRequiredEnvParam("GITHUB_REPOSITORY")
|
||||
getRequiredEnvParam("GITHUB_REPOSITORY"),
|
||||
);
|
||||
const features = new Features(
|
||||
gitHubVersion,
|
||||
repositoryNwo,
|
||||
getTemporaryDirectory(),
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
uploadFailedSarifResult = await initActionPostHelper.run(
|
||||
@@ -58,7 +58,7 @@ async function runWrapper() {
|
||||
printDebugLogs,
|
||||
repositoryNwo,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
@@ -70,15 +70,15 @@ async function runWrapper() {
|
||||
getActionsStatus(error),
|
||||
startedAt,
|
||||
error.message,
|
||||
error.stack
|
||||
)
|
||||
error.stack,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const statusReportBase = await createStatusReportBase(
|
||||
"init-post",
|
||||
"success",
|
||||
startedAt
|
||||
startedAt,
|
||||
);
|
||||
const statusReport: InitPostStatusReport = {
|
||||
...statusReportBase,
|
||||
|
||||
@@ -96,14 +96,14 @@ async function sendCompletedStatusReport(
|
||||
toolsSource: ToolsSource,
|
||||
toolsVersion: string,
|
||||
logger: Logger,
|
||||
error?: Error
|
||||
error?: Error,
|
||||
) {
|
||||
const statusReportBase = await createStatusReportBase(
|
||||
"init",
|
||||
getActionsStatus(error),
|
||||
startedAt,
|
||||
error?.message,
|
||||
error?.stack
|
||||
error?.stack,
|
||||
);
|
||||
|
||||
const workflowLanguages = getOptionalInput("languages");
|
||||
@@ -130,7 +130,7 @@ async function sendCompletedStatusReport(
|
||||
const languages = config.languages.join(",");
|
||||
const paths = (config.originalUserInput.paths || []).join(",");
|
||||
const pathsIgnore = (config.originalUserInput["paths-ignore"] || []).join(
|
||||
","
|
||||
",",
|
||||
);
|
||||
const disableDefaultQueries = config.originalUserInput[
|
||||
"disable-default-queries"
|
||||
@@ -142,7 +142,7 @@ async function sendCompletedStatusReport(
|
||||
let queriesInput = getOptionalInput("queries")?.trim();
|
||||
if (queriesInput === undefined || queriesInput.startsWith("+")) {
|
||||
queries.push(
|
||||
...(config.originalUserInput.queries || []).map((q) => q.uses)
|
||||
...(config.originalUserInput.queries || []).map((q) => q.uses),
|
||||
);
|
||||
}
|
||||
if (queriesInput !== undefined) {
|
||||
@@ -163,7 +163,7 @@ async function sendCompletedStatusReport(
|
||||
queries: queries.join(","),
|
||||
trap_cache_languages: Object.keys(config.trapCaches).join(","),
|
||||
trap_cache_download_size_bytes: Math.round(
|
||||
await getTotalCacheSize(config.trapCaches, logger)
|
||||
await getTotalCacheSize(config.trapCaches, logger),
|
||||
),
|
||||
trap_cache_download_duration_ms: Math.round(config.trapCacheDownloadTime),
|
||||
};
|
||||
@@ -199,7 +199,7 @@ async function run() {
|
||||
checkGitHubVersionInRange(gitHubVersion, logger);
|
||||
|
||||
const repositoryNwo = parseRepositoryNwo(
|
||||
getRequiredEnvParam("GITHUB_REPOSITORY")
|
||||
getRequiredEnvParam("GITHUB_REPOSITORY"),
|
||||
);
|
||||
|
||||
const registriesInput = getOptionalInput("registries");
|
||||
@@ -208,7 +208,7 @@ async function run() {
|
||||
gitHubVersion,
|
||||
repositoryNwo,
|
||||
getTemporaryDirectory(),
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
core.exportVariable(EnvVar.JOB_RUN_UUID, uuidV4());
|
||||
@@ -222,15 +222,15 @@ async function run() {
|
||||
"init",
|
||||
"starting",
|
||||
startedAt,
|
||||
workflowErrors
|
||||
)
|
||||
workflowErrors,
|
||||
),
|
||||
))
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
|
||||
gitHubVersion.type
|
||||
gitHubVersion.type,
|
||||
);
|
||||
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
|
||||
const initCodeQLResult = await initCodeQL(
|
||||
@@ -239,7 +239,7 @@ async function run() {
|
||||
getTemporaryDirectory(),
|
||||
gitHubVersion.type,
|
||||
codeQLDefaultVersionInfo,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
codeql = initCodeQLResult.codeql;
|
||||
toolsDownloadDurationMs = initCodeQLResult.toolsDownloadDurationMs;
|
||||
@@ -269,7 +269,7 @@ async function run() {
|
||||
gitHubVersion,
|
||||
apiDetails,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
if (
|
||||
@@ -279,7 +279,7 @@ async function run() {
|
||||
if (
|
||||
await features.getValue(
|
||||
Feature.DisablePythonDependencyInstallationEnabled,
|
||||
codeql
|
||||
codeql,
|
||||
)
|
||||
) {
|
||||
logger.info("Skipping python dependency installation");
|
||||
@@ -289,7 +289,7 @@ async function run() {
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
logger.warning(
|
||||
`${error.message} You can call this action with 'setup-python-dependencies: false' to disable this process`
|
||||
`${error.message} You can call this action with 'setup-python-dependencies: false' to disable this process`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -303,8 +303,8 @@ async function run() {
|
||||
error instanceof UserError ? "user-error" : "aborted",
|
||||
startedAt,
|
||||
error.message,
|
||||
error.stack
|
||||
)
|
||||
error.stack,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -315,7 +315,7 @@ async function run() {
|
||||
if (goFlags) {
|
||||
core.exportVariable("GOFLAGS", goFlags);
|
||||
core.warning(
|
||||
"Passing the GOFLAGS env parameter to the init action is deprecated. Please move this to the analyze action."
|
||||
"Passing the GOFLAGS env parameter to the init action is deprecated. Please move this to the analyze action.",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -329,12 +329,12 @@ async function run() {
|
||||
process.env["CODEQL_RAM"] ||
|
||||
getMemoryFlagValue(
|
||||
getOptionalInput("ram"),
|
||||
await features.getValue(Feature.ScalingReservedRamEnabled)
|
||||
).toString()
|
||||
await features.getValue(Feature.ScalingReservedRamEnabled),
|
||||
).toString(),
|
||||
);
|
||||
core.exportVariable(
|
||||
"CODEQL_THREADS",
|
||||
getThreadsFlagValue(getOptionalInput("threads"), logger).toString()
|
||||
getThreadsFlagValue(getOptionalInput("threads"), logger).toString(),
|
||||
);
|
||||
|
||||
// Disable Kotlin extractor if feature flag set
|
||||
@@ -346,18 +346,18 @@ async function run() {
|
||||
if (
|
||||
await features.getValue(
|
||||
Feature.DisablePythonDependencyInstallationEnabled,
|
||||
codeql
|
||||
codeql,
|
||||
)
|
||||
) {
|
||||
core.exportVariable(
|
||||
"CODEQL_EXTRACTOR_PYTHON_DISABLE_LIBRARY_EXTRACTION",
|
||||
"true"
|
||||
"true",
|
||||
);
|
||||
}
|
||||
|
||||
const sourceRoot = path.resolve(
|
||||
getRequiredEnvParam("GITHUB_WORKSPACE"),
|
||||
getOptionalInput("source-root") || ""
|
||||
getOptionalInput("source-root") || "",
|
||||
);
|
||||
|
||||
const tracerConfig = await runInit(
|
||||
@@ -368,7 +368,7 @@ async function run() {
|
||||
registriesInput,
|
||||
features,
|
||||
apiDetails,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
if (tracerConfig !== undefined) {
|
||||
for (const [key, value] of Object.entries(tracerConfig.env)) {
|
||||
@@ -388,7 +388,7 @@ async function run() {
|
||||
toolsSource,
|
||||
toolsVersion,
|
||||
logger,
|
||||
error
|
||||
error,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -399,7 +399,7 @@ async function run() {
|
||||
toolsFeatureFlagsValid,
|
||||
toolsSource,
|
||||
toolsVersion,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
22
src/init.ts
22
src/init.ts
@@ -25,7 +25,7 @@ export async function initCodeQL(
|
||||
tempDir: string,
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
codeql: CodeQL;
|
||||
toolsDownloadDurationMs?: number;
|
||||
@@ -41,7 +41,7 @@ export async function initCodeQL(
|
||||
variant,
|
||||
defaultCliVersion,
|
||||
logger,
|
||||
true
|
||||
true,
|
||||
);
|
||||
await codeql.printVersion();
|
||||
logger.endGroup();
|
||||
@@ -67,7 +67,7 @@ export async function initConfig(
|
||||
gitHubVersion: util.GitHubVersion,
|
||||
apiDetails: GitHubApiCombinedDetails,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<configUtils.Config> {
|
||||
logger.startGroup("Load language configuration");
|
||||
const config = await configUtils.initConfig(
|
||||
@@ -89,7 +89,7 @@ export async function initConfig(
|
||||
gitHubVersion,
|
||||
apiDetails,
|
||||
features,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
analysisPaths.printPathFiltersWarning(config, logger);
|
||||
logger.endGroup();
|
||||
@@ -104,7 +104,7 @@ export async function runInit(
|
||||
registriesInput: string | undefined,
|
||||
features: FeatureEnablement,
|
||||
apiDetails: GitHubApiCombinedDetails,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<TracerConfig | undefined> {
|
||||
fs.mkdirSync(config.dbLocation, { recursive: true });
|
||||
try {
|
||||
@@ -120,7 +120,7 @@ export async function runInit(
|
||||
registriesInput,
|
||||
codeql,
|
||||
config.tempDir,
|
||||
logger
|
||||
logger,
|
||||
));
|
||||
}
|
||||
await configUtils.wrapEnvironment(
|
||||
@@ -137,8 +137,8 @@ export async function runInit(
|
||||
processName,
|
||||
features,
|
||||
qlconfigFile,
|
||||
logger
|
||||
)
|
||||
logger,
|
||||
),
|
||||
);
|
||||
} catch (e) {
|
||||
throw processError(e);
|
||||
@@ -166,7 +166,7 @@ function processError(e: any): Error {
|
||||
e.message?.includes("exists and is not an empty directory.")
|
||||
) {
|
||||
return new util.UserError(
|
||||
`Is the "init" action called twice in the same job? ${e.message}`
|
||||
`Is the "init" action called twice in the same job? ${e.message}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ export async function installPythonDeps(codeql: CodeQL, logger: Logger) {
|
||||
]).exec();
|
||||
} else {
|
||||
await new toolrunner.ToolRunner(
|
||||
path.join(scriptsFolder, "install_tools.sh")
|
||||
path.join(scriptsFolder, "install_tools.sh"),
|
||||
).exec();
|
||||
}
|
||||
const script = "auto_install_packages.py";
|
||||
@@ -218,7 +218,7 @@ export async function installPythonDeps(codeql: CodeQL, logger: Logger) {
|
||||
`An error occurred while trying to automatically install Python dependencies: ${e}\n` +
|
||||
"Please make sure any necessary dependencies are installed before calling the codeql-action/analyze " +
|
||||
"step, and add a 'setup-python-dependencies: false' argument to this step to disable our automatic " +
|
||||
"dependency installation and avoid this warning."
|
||||
"dependency installation and avoid this warning.",
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ async function run() {
|
||||
try {
|
||||
if (
|
||||
!(await sendStatusReport(
|
||||
await createStatusReportBase(ACTION_NAME, "starting", startedAt)
|
||||
await createStatusReportBase(ACTION_NAME, "starting", startedAt),
|
||||
))
|
||||
) {
|
||||
return;
|
||||
@@ -41,7 +41,7 @@ async function run() {
|
||||
const config = await configUtils.getConfig(getTemporaryDirectory(), logger);
|
||||
if (config === undefined) {
|
||||
throw new Error(
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?"
|
||||
"Config file could not be found at expected location. Has the 'init' action been called?",
|
||||
);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ async function run() {
|
||||
config.codeQLCmd,
|
||||
logger,
|
||||
workingDirectory,
|
||||
language
|
||||
language,
|
||||
);
|
||||
core.setOutput(ENVIRONMENT_OUTPUT_NAME, result);
|
||||
} catch (unwrappedError) {
|
||||
@@ -61,12 +61,12 @@ async function run() {
|
||||
// we just return an empty JSON object and proceed with the workflow.
|
||||
core.setOutput(ENVIRONMENT_OUTPUT_NAME, {});
|
||||
logger.warning(
|
||||
`Failed to resolve a build environment suitable for automatically building your code. ${error.message}`
|
||||
`Failed to resolve a build environment suitable for automatically building your code. ${error.message}`,
|
||||
);
|
||||
} else {
|
||||
// For any other error types, something has more seriously gone wrong and we fail.
|
||||
core.setFailed(
|
||||
`Failed to resolve a build environment suitable for automatically building your code. ${error.message}`
|
||||
`Failed to resolve a build environment suitable for automatically building your code. ${error.message}`,
|
||||
);
|
||||
|
||||
await sendStatusReport(
|
||||
@@ -75,8 +75,8 @@ async function run() {
|
||||
getActionsStatus(error),
|
||||
startedAt,
|
||||
error.message,
|
||||
error.stack
|
||||
)
|
||||
error.stack,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@ async function run() {
|
||||
}
|
||||
|
||||
await sendStatusReport(
|
||||
await createStatusReportBase(ACTION_NAME, "success", startedAt)
|
||||
await createStatusReportBase(ACTION_NAME, "success", startedAt),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ export async function runResolveBuildEnvironment(
|
||||
cmd: string,
|
||||
logger: Logger,
|
||||
workingDir: string | undefined,
|
||||
language: Language
|
||||
language: Language,
|
||||
) {
|
||||
logger.startGroup(`Attempting to resolve build environment for ${language}`);
|
||||
|
||||
@@ -21,7 +21,7 @@ export async function runResolveBuildEnvironment(
|
||||
) {
|
||||
logger.warning(
|
||||
"Unsupported CodeQL CLI version for `resolve build-environment` command, " +
|
||||
"returning an empty configuration."
|
||||
"returning an empty configuration.",
|
||||
);
|
||||
} else {
|
||||
if (workingDir !== undefined) {
|
||||
|
||||
@@ -29,9 +29,9 @@ test.beforeEach(() => {
|
||||
test("parse codeql bundle url version", (t) => {
|
||||
t.deepEqual(
|
||||
setupCodeql.getCodeQLURLVersion(
|
||||
"https://github.com/.../codeql-bundle-20200601/..."
|
||||
"https://github.com/.../codeql-bundle-20200601/...",
|
||||
),
|
||||
"20200601"
|
||||
"20200601",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -49,7 +49,7 @@ test("convert to semver", (t) => {
|
||||
try {
|
||||
const parsedVersion = setupCodeql.convertToSemVer(
|
||||
version,
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(parsedVersion, expectedVersion);
|
||||
} catch (e) {
|
||||
@@ -86,7 +86,7 @@ test("getCodeQLSource sets CLI version for a semver tagged bundle", async (t) =>
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
getRunnerLogger(true)
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
t.is(source.sourceType, "download");
|
||||
|
||||
@@ -48,7 +48,7 @@ export function getCodeQLActionRepository(logger: Logger): string {
|
||||
// e.g. our integration tests which use the Action code from the current checkout.
|
||||
// In these cases, the GITHUB_ACTION_REPOSITORY environment variable is not set.
|
||||
logger.info(
|
||||
"The CodeQL Action is checked out locally. Using the default CodeQL Action repository."
|
||||
"The CodeQL Action is checked out locally. Using the default CodeQL Action repository.",
|
||||
);
|
||||
return CODEQL_DEFAULT_ACTION_REPOSITORY;
|
||||
}
|
||||
@@ -58,7 +58,7 @@ export function getCodeQLActionRepository(logger: Logger): string {
|
||||
|
||||
function tryGetCodeQLCliVersionForRelease(
|
||||
release,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): string | undefined {
|
||||
const cliVersionsFromMarkerFiles = release.assets
|
||||
.map((asset) => asset.name.match(/cli-version-(.*)\.txt/)?.[1])
|
||||
@@ -66,12 +66,12 @@ function tryGetCodeQLCliVersionForRelease(
|
||||
.map((v) => v as string);
|
||||
if (cliVersionsFromMarkerFiles.length > 1) {
|
||||
logger.warning(
|
||||
`Ignoring release ${release.tag_name} with multiple CLI version marker files.`
|
||||
`Ignoring release ${release.tag_name} with multiple CLI version marker files.`,
|
||||
);
|
||||
return undefined;
|
||||
} else if (cliVersionsFromMarkerFiles.length === 0) {
|
||||
logger.debug(
|
||||
`Failed to find the CodeQL CLI version for release ${release.tag_name}.`
|
||||
`Failed to find the CodeQL CLI version for release ${release.tag_name}.`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -80,11 +80,11 @@ function tryGetCodeQLCliVersionForRelease(
|
||||
|
||||
export async function tryFindCliVersionDotcomOnly(
|
||||
tagName: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<string | undefined> {
|
||||
try {
|
||||
logger.debug(
|
||||
`Fetching the GitHub Release for the CodeQL bundle tagged ${tagName}.`
|
||||
`Fetching the GitHub Release for the CodeQL bundle tagged ${tagName}.`,
|
||||
);
|
||||
const apiClient = api.getApiClient();
|
||||
const codeQLActionRepository = getCodeQLActionRepository(logger);
|
||||
@@ -98,7 +98,7 @@ export async function tryFindCliVersionDotcomOnly(
|
||||
logger.debug(
|
||||
`Failed to find the CLI version for the CodeQL bundle tagged ${tagName}. ${
|
||||
wrapError(e).message
|
||||
}`
|
||||
}`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
@@ -108,7 +108,7 @@ async function getCodeQLBundleDownloadURL(
|
||||
tagName: string,
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
variant: util.GitHubVariant,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<string> {
|
||||
const codeQLActionRepository = getCodeQLActionRepository(logger);
|
||||
const potentialDownloadSources = [
|
||||
@@ -124,7 +124,7 @@ async function getCodeQLBundleDownloadURL(
|
||||
const uniqueDownloadSources = potentialDownloadSources.filter(
|
||||
(source, index, self) => {
|
||||
return !self.slice(0, index).some((other) => deepEqual(source, other));
|
||||
}
|
||||
},
|
||||
);
|
||||
const codeQLBundleName = getCodeQLBundleName();
|
||||
if (variant === util.GitHubVariant.GHAE) {
|
||||
@@ -140,23 +140,23 @@ async function getCodeQLBundleDownloadURL(
|
||||
.getApiClient()
|
||||
.request(
|
||||
"GET /enterprise/code-scanning/codeql-bundle/download/{asset_id}",
|
||||
{ asset_id: assetID }
|
||||
{ asset_id: assetID },
|
||||
);
|
||||
const downloadURL = download.data.url;
|
||||
logger.info(
|
||||
`Found CodeQL bundle at GitHub AE endpoint with URL ${downloadURL}.`
|
||||
`Found CodeQL bundle at GitHub AE endpoint with URL ${downloadURL}.`,
|
||||
);
|
||||
return downloadURL;
|
||||
} else {
|
||||
logger.info(
|
||||
`Attempted to fetch bundle from GitHub AE endpoint but the bundle ${codeQLBundleName} was not found in the assets ${JSON.stringify(
|
||||
release.data.assets
|
||||
)}.`
|
||||
release.data.assets,
|
||||
)}.`,
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
logger.info(
|
||||
`Attempted to fetch bundle from GitHub AE endpoint but got error ${e}.`
|
||||
`Attempted to fetch bundle from GitHub AE endpoint but got error ${e}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -179,14 +179,14 @@ async function getCodeQLBundleDownloadURL(
|
||||
for (const asset of release.data.assets) {
|
||||
if (asset.name === codeQLBundleName) {
|
||||
logger.info(
|
||||
`Found CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} with URL ${asset.url}.`
|
||||
`Found CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} with URL ${asset.url}.`,
|
||||
);
|
||||
return asset.url;
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logger.info(
|
||||
`Looked for CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} but got error ${e}.`
|
||||
`Looked for CodeQL bundle in ${downloadSource[1]} on ${downloadSource[0]} but got error ${e}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -195,7 +195,7 @@ async function getCodeQLBundleDownloadURL(
|
||||
|
||||
function tryGetBundleVersionFromTagName(
|
||||
tagName: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): string | undefined {
|
||||
const match = tagName.match(/^codeql-bundle-(.*)$/);
|
||||
if (match === null || match.length < 2) {
|
||||
@@ -216,7 +216,7 @@ function tryGetTagNameFromUrl(url: string, logger: Logger): string | undefined {
|
||||
|
||||
export function tryGetBundleVersionFromUrl(
|
||||
url: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): string | undefined {
|
||||
const tagName = tryGetTagNameFromUrl(url, logger);
|
||||
if (tagName === undefined) {
|
||||
@@ -228,7 +228,7 @@ export function tryGetBundleVersionFromUrl(
|
||||
export function convertToSemVer(version: string, logger: Logger): string {
|
||||
if (!semver.valid(version)) {
|
||||
logger.debug(
|
||||
`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`
|
||||
`Bundle version ${version} is not in SemVer format. Will treat it as pre-release 0.0.0-${version}.`,
|
||||
);
|
||||
version = `0.0.0-${version}`;
|
||||
}
|
||||
@@ -270,7 +270,7 @@ type CodeQLToolsSource =
|
||||
*/
|
||||
async function findOverridingToolsInCache(
|
||||
humanReadableVersion: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<CodeQLToolsSource | undefined> {
|
||||
const candidates = toolcache
|
||||
.findAllVersions("CodeQL")
|
||||
@@ -284,7 +284,7 @@ async function findOverridingToolsInCache(
|
||||
if (candidates.length === 1) {
|
||||
const candidate = candidates[0];
|
||||
logger.debug(
|
||||
`CodeQL tools version ${candidate.version} in toolcache overriding version ${humanReadableVersion}.`
|
||||
`CodeQL tools version ${candidate.version} in toolcache overriding version ${humanReadableVersion}.`,
|
||||
);
|
||||
return {
|
||||
codeqlFolder: candidate.folder,
|
||||
@@ -293,12 +293,12 @@ async function findOverridingToolsInCache(
|
||||
};
|
||||
} else if (candidates.length === 0) {
|
||||
logger.debug(
|
||||
"Did not find any candidate pinned versions of the CodeQL tools in the toolcache."
|
||||
"Did not find any candidate pinned versions of the CodeQL tools in the toolcache.",
|
||||
);
|
||||
} else {
|
||||
logger.debug(
|
||||
"Could not use CodeQL tools from the toolcache since more than one candidate pinned " +
|
||||
"version was found in the toolcache."
|
||||
"version was found in the toolcache.",
|
||||
);
|
||||
}
|
||||
return undefined;
|
||||
@@ -309,7 +309,7 @@ export async function getCodeQLSource(
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
variant: util.GitHubVariant,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<CodeQLToolsSource> {
|
||||
if (toolsInput && toolsInput !== "latest" && !toolsInput.startsWith("http")) {
|
||||
return {
|
||||
@@ -330,7 +330,7 @@ export async function getCodeQLSource(
|
||||
if (forceShippedTools) {
|
||||
logger.info(
|
||||
"Overriding the version of the CodeQL tools by the version shipped with the Action since " +
|
||||
`"tools: latest" was requested.`
|
||||
`"tools: latest" was requested.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -379,7 +379,7 @@ export async function getCodeQLSource(
|
||||
"Attempting to obtain CodeQL tools. " +
|
||||
`CLI version: ${cliVersion ?? "unknown"}, ` +
|
||||
`bundle tag name: ${tagName ?? "unknown"}, ` +
|
||||
`URL: ${url ?? "unspecified"}.`
|
||||
`URL: ${url ?? "unspecified"}.`,
|
||||
);
|
||||
|
||||
let codeqlFolder: string | undefined;
|
||||
@@ -392,34 +392,34 @@ export async function getCodeQLSource(
|
||||
if (!codeqlFolder) {
|
||||
logger.debug(
|
||||
"Didn't find a version of the CodeQL tools in the toolcache with a version number " +
|
||||
`exactly matching ${cliVersion}.`
|
||||
`exactly matching ${cliVersion}.`,
|
||||
);
|
||||
const allVersions = toolcache.findAllVersions("CodeQL");
|
||||
logger.debug(
|
||||
`Found the following versions of the CodeQL tools in the toolcache: ${JSON.stringify(
|
||||
allVersions
|
||||
)}.`
|
||||
allVersions,
|
||||
)}.`,
|
||||
);
|
||||
// If there is exactly one version of the CodeQL tools in the toolcache, and that version is
|
||||
// the form `x.y.z-<tagName>`, then use it.
|
||||
const candidateVersions = allVersions.filter((version) =>
|
||||
version.startsWith(`${cliVersion}-`)
|
||||
version.startsWith(`${cliVersion}-`),
|
||||
);
|
||||
if (candidateVersions.length === 1) {
|
||||
logger.debug(
|
||||
`Exactly one version of the CodeQL tools starting with ${cliVersion} found in the ` +
|
||||
"toolcache, using that."
|
||||
"toolcache, using that.",
|
||||
);
|
||||
codeqlFolder = toolcache.find("CodeQL", candidateVersions[0]);
|
||||
} else if (candidateVersions.length === 0) {
|
||||
logger.debug(
|
||||
`Didn't find any versions of the CodeQL tools starting with ${cliVersion} ` +
|
||||
`in the toolcache. Trying next fallback method.`
|
||||
`in the toolcache. Trying next fallback method.`,
|
||||
);
|
||||
} else {
|
||||
logger.warning(
|
||||
`Found ${candidateVersions.length} versions of the CodeQL tools starting with ` +
|
||||
`${cliVersion} in the toolcache, but at most one was expected.`
|
||||
`${cliVersion} in the toolcache, but at most one was expected.`,
|
||||
);
|
||||
logger.debug("Trying next fallback method.");
|
||||
}
|
||||
@@ -431,25 +431,25 @@ export async function getCodeQLSource(
|
||||
const fallbackVersion = await tryGetFallbackToolcacheVersion(
|
||||
cliVersion,
|
||||
tagName,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
if (fallbackVersion) {
|
||||
codeqlFolder = toolcache.find("CodeQL", fallbackVersion);
|
||||
} else {
|
||||
logger.debug(
|
||||
"Could not determine a fallback toolcache version number for CodeQL tools version " +
|
||||
`${humanReadableVersion}.`
|
||||
`${humanReadableVersion}.`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (codeqlFolder) {
|
||||
logger.info(
|
||||
`Found CodeQL tools version ${humanReadableVersion} in the toolcache.`
|
||||
`Found CodeQL tools version ${humanReadableVersion} in the toolcache.`,
|
||||
);
|
||||
} else {
|
||||
logger.info(
|
||||
`Did not find CodeQL tools version ${humanReadableVersion} in the toolcache.`
|
||||
`Did not find CodeQL tools version ${humanReadableVersion} in the toolcache.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -471,7 +471,7 @@ export async function getCodeQLSource(
|
||||
) {
|
||||
const result = await findOverridingToolsInCache(
|
||||
humanReadableVersion,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
if (result !== undefined) {
|
||||
return result;
|
||||
@@ -483,7 +483,7 @@ export async function getCodeQLSource(
|
||||
tagName!,
|
||||
apiDetails,
|
||||
variant,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -503,7 +503,7 @@ export async function getCodeQLSource(
|
||||
export async function tryGetFallbackToolcacheVersion(
|
||||
cliVersion: string | undefined,
|
||||
tagName: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<string | undefined> {
|
||||
const bundleVersion = tryGetBundleVersionFromTagName(tagName, logger);
|
||||
if (!bundleVersion) {
|
||||
@@ -512,7 +512,7 @@ export async function tryGetFallbackToolcacheVersion(
|
||||
const fallbackVersion = convertToSemVer(bundleVersion, logger);
|
||||
logger.debug(
|
||||
`Computed a fallback toolcache version number of ${fallbackVersion} for CodeQL version ` +
|
||||
`${cliVersion ?? tagName}.`
|
||||
`${cliVersion ?? tagName}.`,
|
||||
);
|
||||
return fallbackVersion;
|
||||
}
|
||||
@@ -524,7 +524,7 @@ export async function downloadCodeQL(
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
variant: util.GitHubVariant,
|
||||
tempDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
toolsVersion: string;
|
||||
codeqlFolder: string;
|
||||
@@ -549,13 +549,13 @@ export async function downloadCodeQL(
|
||||
logger.debug("Downloading CodeQL tools without an authorization token.");
|
||||
}
|
||||
logger.info(
|
||||
`Downloading CodeQL tools from ${codeqlURL}. This may take a while.`
|
||||
`Downloading CodeQL tools from ${codeqlURL}. This may take a while.`,
|
||||
);
|
||||
|
||||
const dest = path.join(tempDir, uuidV4());
|
||||
const finalHeaders = Object.assign(
|
||||
{ "User-Agent": "CodeQL Action" },
|
||||
headers
|
||||
headers,
|
||||
);
|
||||
|
||||
const toolsDownloadStart = performance.now();
|
||||
@@ -563,10 +563,10 @@ export async function downloadCodeQL(
|
||||
codeqlURL,
|
||||
dest,
|
||||
authorization,
|
||||
finalHeaders
|
||||
finalHeaders,
|
||||
);
|
||||
const toolsDownloadDurationMs = Math.round(
|
||||
performance.now() - toolsDownloadStart
|
||||
performance.now() - toolsDownloadStart,
|
||||
);
|
||||
|
||||
logger.debug(`CodeQL bundle download to ${codeqlPath} complete.`);
|
||||
@@ -579,7 +579,7 @@ export async function downloadCodeQL(
|
||||
if (bundleVersion === undefined) {
|
||||
logger.debug(
|
||||
"Could not cache CodeQL tools because we could not determine the bundle version from the " +
|
||||
`URL ${codeqlURL}.`
|
||||
`URL ${codeqlURL}.`,
|
||||
);
|
||||
return {
|
||||
toolsVersion: maybeCliVersion ?? "unknown",
|
||||
@@ -596,7 +596,7 @@ export async function downloadCodeQL(
|
||||
) {
|
||||
maybeCliVersion = await tryFindCliVersionDotcomOnly(
|
||||
`codeql-bundle-${bundleVersion}`,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -617,7 +617,7 @@ export async function downloadCodeQL(
|
||||
codeqlFolder: await toolcache.cacheDir(
|
||||
codeqlExtracted,
|
||||
"CodeQL",
|
||||
toolcacheVersion
|
||||
toolcacheVersion,
|
||||
),
|
||||
toolsDownloadDurationMs,
|
||||
};
|
||||
@@ -627,7 +627,7 @@ export function getCodeQLURLVersion(url: string): string {
|
||||
const match = url.match(/\/codeql-bundle-(.*)\//);
|
||||
if (match === null || match.length < 2) {
|
||||
throw new Error(
|
||||
`Malformed tools url: ${url}. Version could not be inferred`
|
||||
`Malformed tools url: ${url}. Version could not be inferred`,
|
||||
);
|
||||
}
|
||||
return match[1];
|
||||
@@ -652,7 +652,7 @@ export async function setupCodeQLBundle(
|
||||
tempDir: string,
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
codeqlFolder: string;
|
||||
toolsDownloadDurationMs?: number;
|
||||
@@ -664,7 +664,7 @@ export async function setupCodeQLBundle(
|
||||
defaultCliVersion,
|
||||
apiDetails,
|
||||
variant,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
|
||||
let codeqlFolder: string;
|
||||
@@ -689,7 +689,7 @@ export async function setupCodeQLBundle(
|
||||
apiDetails,
|
||||
variant,
|
||||
tempDir,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
toolsVersion = result.toolsVersion;
|
||||
codeqlFolder = result.codeqlFolder;
|
||||
|
||||
@@ -43,7 +43,7 @@ function wrapOutput(context: TestContext) {
|
||||
return (
|
||||
chunk: Uint8Array | string,
|
||||
encoding?: string,
|
||||
cb?: (err?: Error) => void
|
||||
cb?: (err?: Error) => void,
|
||||
): boolean => {
|
||||
// Work out which method overload we are in
|
||||
if (cb === undefined && typeof encoding === "function") {
|
||||
@@ -88,7 +88,7 @@ export function setupTests(test: TestFn<any>) {
|
||||
// environment variable on Windows isn't preserved, i.e. `process.env.PATH`
|
||||
// is not the same as `process.env.Path`.
|
||||
const pathKeys = Object.keys(process.env).filter(
|
||||
(k) => k.toLowerCase() === "path"
|
||||
(k) => k.toLowerCase() === "path",
|
||||
);
|
||||
if (pathKeys.length > 0) {
|
||||
process.env.PATH = process.env[pathKeys[0]];
|
||||
@@ -161,7 +161,7 @@ export function getRecordingLogger(messages: LoggedMessage[]): Logger {
|
||||
/** Mock the HTTP request to the feature flags enablement API endpoint. */
|
||||
export function mockFeatureFlagApiEndpoint(
|
||||
responseStatusCode: number,
|
||||
response: { [flagName: string]: boolean }
|
||||
response: { [flagName: string]: boolean },
|
||||
) {
|
||||
// Passing an auth token is required, so we just use a dummy value
|
||||
const client = github.getOctokit("123");
|
||||
@@ -169,7 +169,7 @@ export function mockFeatureFlagApiEndpoint(
|
||||
const requestSpy = sinon.stub(client, "request");
|
||||
|
||||
const optInSpy = requestSpy.withArgs(
|
||||
"GET /repos/:owner/:repo/code-scanning/codeql-action/features"
|
||||
"GET /repos/:owner/:repo/code-scanning/codeql-action/features",
|
||||
);
|
||||
if (responseStatusCode < 300) {
|
||||
optInSpy.resolves({
|
||||
@@ -271,8 +271,8 @@ export function mockBundleDownloadApi({
|
||||
200,
|
||||
path.join(
|
||||
__dirname,
|
||||
`/../src/testdata/codeql-bundle${isPinned ? "-pinned" : ""}.tar.gz`
|
||||
)
|
||||
`/../src/testdata/codeql-bundle${isPinned ? "-pinned" : ""}.tar.gz`,
|
||||
),
|
||||
);
|
||||
|
||||
return `${baseUrl}${relativeUrl}`;
|
||||
|
||||
@@ -61,12 +61,12 @@ test("getCombinedTracerConfig - with start-tracing.json environment file", async
|
||||
const tracingEnvironmentDir = path.join(
|
||||
config.dbLocation,
|
||||
"temp",
|
||||
"tracingEnvironment"
|
||||
"tracingEnvironment",
|
||||
);
|
||||
fs.mkdirSync(tracingEnvironmentDir, { recursive: true });
|
||||
const startTracingJson = path.join(
|
||||
tracingEnvironmentDir,
|
||||
"start-tracing.json"
|
||||
"start-tracing.json",
|
||||
);
|
||||
fs.writeFileSync(startTracingJson, JSON.stringify(startTracingEnv));
|
||||
|
||||
@@ -78,17 +78,17 @@ test("getCombinedTracerConfig - with start-tracing.json environment file", async
|
||||
if (process.platform === "win32") {
|
||||
expectedEnv["CODEQL_RUNNER"] = path.join(
|
||||
bundlePath,
|
||||
"tools/win64/runner.exe"
|
||||
"tools/win64/runner.exe",
|
||||
);
|
||||
} else if (process.platform === "darwin") {
|
||||
expectedEnv["CODEQL_RUNNER"] = path.join(
|
||||
bundlePath,
|
||||
"tools/osx64/runner"
|
||||
"tools/osx64/runner",
|
||||
);
|
||||
} else {
|
||||
expectedEnv["CODEQL_RUNNER"] = path.join(
|
||||
bundlePath,
|
||||
"tools/linux64/runner"
|
||||
"tools/linux64/runner",
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,23 +9,23 @@ export type TracerConfig = {
|
||||
};
|
||||
|
||||
export async function endTracingForCluster(
|
||||
config: configUtils.Config
|
||||
config: configUtils.Config,
|
||||
): Promise<void> {
|
||||
// If there are no traced languages, we don't need to do anything.
|
||||
if (!config.languages.some((l) => isTracedLanguage(l))) return;
|
||||
|
||||
const envVariablesFile = path.resolve(
|
||||
config.dbLocation,
|
||||
"temp/tracingEnvironment/end-tracing.json"
|
||||
"temp/tracingEnvironment/end-tracing.json",
|
||||
);
|
||||
if (!fs.existsSync(envVariablesFile)) {
|
||||
throw new Error(
|
||||
`Environment file for ending tracing not found: ${envVariablesFile}`
|
||||
`Environment file for ending tracing not found: ${envVariablesFile}`,
|
||||
);
|
||||
}
|
||||
try {
|
||||
const endTracingEnvVariables: Map<string, string | null> = JSON.parse(
|
||||
fs.readFileSync(envVariablesFile, "utf8")
|
||||
fs.readFileSync(envVariablesFile, "utf8"),
|
||||
);
|
||||
for (const [key, value] of Object.entries(endTracingEnvVariables)) {
|
||||
if (value !== null) {
|
||||
@@ -36,22 +36,22 @@ export async function endTracingForCluster(
|
||||
}
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Failed to parse file containing end tracing environment variables: ${e}`
|
||||
`Failed to parse file containing end tracing environment variables: ${e}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export async function getTracerConfigForCluster(
|
||||
config: configUtils.Config
|
||||
config: configUtils.Config,
|
||||
): Promise<TracerConfig> {
|
||||
const tracingEnvVariables = JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.resolve(
|
||||
config.dbLocation,
|
||||
"temp/tracingEnvironment/start-tracing.json"
|
||||
"temp/tracingEnvironment/start-tracing.json",
|
||||
),
|
||||
"utf8"
|
||||
)
|
||||
"utf8",
|
||||
),
|
||||
);
|
||||
return {
|
||||
env: tracingEnvVariables,
|
||||
@@ -59,7 +59,7 @@ export async function getTracerConfigForCluster(
|
||||
}
|
||||
|
||||
export async function getCombinedTracerConfig(
|
||||
config: configUtils.Config
|
||||
config: configUtils.Config,
|
||||
): Promise<TracerConfig | undefined> {
|
||||
// Abort if there are no traced languages as there's nothing to do
|
||||
const tracedLanguages = config.languages.filter((l) => isTracedLanguage(l));
|
||||
@@ -78,7 +78,7 @@ export async function getCombinedTracerConfig(
|
||||
mainTracerConfig.env["CODEQL_DIST"],
|
||||
"tools",
|
||||
mainTracerConfig.env["CODEQL_PLATFORM"],
|
||||
runnerExeName
|
||||
runnerExeName,
|
||||
);
|
||||
|
||||
return mainTracerConfig;
|
||||
|
||||
@@ -126,7 +126,7 @@ test("check flags for JS, analyzing default branch", async (t) => {
|
||||
sinon.stub(actionsUtil, "isAnalyzingDefaultBranch").resolves(true);
|
||||
const result = await getTrapCachingExtractorConfigArgsForLang(
|
||||
config,
|
||||
Language.javascript
|
||||
Language.javascript,
|
||||
);
|
||||
t.deepEqual(result, [
|
||||
`-O=javascript.trap.cache.dir=${path.resolve(tmpDir, "jsCache")}`,
|
||||
@@ -158,7 +158,7 @@ test("get languages that support TRAP caching", async (t) => {
|
||||
const languagesSupportingCaching = await getLanguagesSupportingCaching(
|
||||
stubCodeql,
|
||||
[Language.javascript, Language.cpp],
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(languagesSupportingCaching, [Language.javascript]);
|
||||
});
|
||||
@@ -177,8 +177,8 @@ test("upload cache key contains right fields", async (t) => {
|
||||
sinon
|
||||
.match("somesha")
|
||||
.and(sinon.match("2.10.3"))
|
||||
.and(sinon.match("javascript"))
|
||||
)
|
||||
.and(sinon.match("javascript")),
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -200,12 +200,12 @@ test("download cache looks for the right key and creates dir", async (t) => {
|
||||
sha: "somesha",
|
||||
},
|
||||
},
|
||||
})
|
||||
}),
|
||||
);
|
||||
await downloadTrapCaches(
|
||||
stubCodeql,
|
||||
[Language.javascript, Language.cpp],
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
t.assert(
|
||||
stubRestore.calledOnceWith(
|
||||
@@ -215,8 +215,8 @@ test("download cache looks for the right key and creates dir", async (t) => {
|
||||
sinon
|
||||
.match("somesha")
|
||||
.and(sinon.match("2.10.3"))
|
||||
.and(sinon.match("javascript"))
|
||||
)
|
||||
.and(sinon.match("javascript")),
|
||||
),
|
||||
);
|
||||
t.assert(fs.existsSync(path.resolve(tmpDir, "trapCaches", "javascript")));
|
||||
});
|
||||
|
||||
@@ -38,22 +38,22 @@ const MAX_CACHE_OPERATION_MS = 120_000; // Two minutes
|
||||
export async function downloadTrapCaches(
|
||||
codeql: CodeQL,
|
||||
languages: Language[],
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Partial<Record<Language, string>>> {
|
||||
const result: Partial<Record<Language, string>> = {};
|
||||
const languagesSupportingCaching = await getLanguagesSupportingCaching(
|
||||
codeql,
|
||||
languages,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
logger.info(
|
||||
`Found ${languagesSupportingCaching.length} languages that support TRAP caching`
|
||||
`Found ${languagesSupportingCaching.length} languages that support TRAP caching`,
|
||||
);
|
||||
if (languagesSupportingCaching.length === 0) return result;
|
||||
|
||||
const cachesDir = path.join(
|
||||
actionsUtil.getTemporaryDirectory(),
|
||||
"trapCaches"
|
||||
"trapCaches",
|
||||
);
|
||||
for (const language of languagesSupportingCaching) {
|
||||
const cacheDir = path.join(cachesDir, language);
|
||||
@@ -63,7 +63,7 @@ export async function downloadTrapCaches(
|
||||
|
||||
if (await actionsUtil.isAnalyzingDefaultBranch()) {
|
||||
logger.info(
|
||||
"Analyzing default branch. Skipping downloading of TRAP caches."
|
||||
"Analyzing default branch. Skipping downloading of TRAP caches.",
|
||||
);
|
||||
return result;
|
||||
}
|
||||
@@ -83,7 +83,7 @@ export async function downloadTrapCaches(
|
||||
// The SHA from the base of the PR is the most similar commit we might have a cache for
|
||||
const preferredKey = await cacheKey(codeql, language, baseSha);
|
||||
logger.info(
|
||||
`Looking in Actions cache for TRAP cache with key ${preferredKey}`
|
||||
`Looking in Actions cache for TRAP cache with key ${preferredKey}`,
|
||||
);
|
||||
const found = await withTimeout(
|
||||
MAX_CACHE_OPERATION_MS,
|
||||
@@ -93,9 +93,9 @@ export async function downloadTrapCaches(
|
||||
]),
|
||||
() => {
|
||||
logger.info(
|
||||
`Timed out downloading cache for ${language}, will continue without it`
|
||||
`Timed out downloading cache for ${language}, will continue without it`,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
if (found === undefined) {
|
||||
// We didn't find a TRAP cache in the Actions cache, so the directory on disk is
|
||||
@@ -119,7 +119,7 @@ export async function downloadTrapCaches(
|
||||
export async function uploadTrapCaches(
|
||||
codeql: CodeQL,
|
||||
config: Config,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
if (!(await actionsUtil.isAnalyzingDefaultBranch())) return false; // Only upload caches from the default branch
|
||||
|
||||
@@ -129,20 +129,20 @@ export async function uploadTrapCaches(
|
||||
const trapFolderSize = await tryGetFolderBytes(cacheDir, logger);
|
||||
if (trapFolderSize === undefined) {
|
||||
logger.info(
|
||||
`Skipping upload of TRAP cache for ${language} as we couldn't determine its size`
|
||||
`Skipping upload of TRAP cache for ${language} as we couldn't determine its size`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (trapFolderSize < MINIMUM_CACHE_MB_TO_UPLOAD * 1_048_576) {
|
||||
logger.info(
|
||||
`Skipping upload of TRAP cache for ${language} as it is too small`
|
||||
`Skipping upload of TRAP cache for ${language} as it is too small`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
const key = await cacheKey(
|
||||
codeql,
|
||||
language,
|
||||
process.env.GITHUB_SHA || "unknown"
|
||||
process.env.GITHUB_SHA || "unknown",
|
||||
);
|
||||
logger.info(`Uploading TRAP cache to Actions cache with key ${key}`);
|
||||
await withTimeout(
|
||||
@@ -150,9 +150,9 @@ export async function uploadTrapCaches(
|
||||
cache.saveCache([cacheDir], key),
|
||||
() => {
|
||||
logger.info(
|
||||
`Timed out waiting for TRAP cache for ${language} to upload, will continue without uploading`
|
||||
`Timed out waiting for TRAP cache for ${language} to upload, will continue without uploading`,
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
return true;
|
||||
@@ -161,7 +161,7 @@ export async function uploadTrapCaches(
|
||||
export async function getLanguagesSupportingCaching(
|
||||
codeql: CodeQL,
|
||||
languages: Language[],
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<Language[]> {
|
||||
const result: Language[] = [];
|
||||
if (
|
||||
@@ -173,13 +173,13 @@ export async function getLanguagesSupportingCaching(
|
||||
const extractorsForLanguage = resolveResult.extractors[lang];
|
||||
if (extractorsForLanguage === undefined) {
|
||||
logger.info(
|
||||
`${lang} does not support TRAP caching (couldn't find an extractor)`
|
||||
`${lang} does not support TRAP caching (couldn't find an extractor)`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
if (extractorsForLanguage.length !== 1) {
|
||||
logger.info(
|
||||
`${lang} does not support TRAP caching (found multiple extractors)`
|
||||
`${lang} does not support TRAP caching (found multiple extractors)`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
@@ -188,14 +188,14 @@ export async function getLanguagesSupportingCaching(
|
||||
extractor.extractor_options?.trap?.properties?.cache?.properties;
|
||||
if (trapCacheOptions === undefined) {
|
||||
logger.info(
|
||||
`${lang} does not support TRAP caching (missing option group)`
|
||||
`${lang} does not support TRAP caching (missing option group)`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
for (const requiredOpt of ["dir", "bound", "write"]) {
|
||||
if (!(requiredOpt in trapCacheOptions)) {
|
||||
logger.info(
|
||||
`${lang} does not support TRAP caching (missing ${requiredOpt} option)`
|
||||
`${lang} does not support TRAP caching (missing ${requiredOpt} option)`,
|
||||
);
|
||||
continue outer;
|
||||
}
|
||||
@@ -207,12 +207,12 @@ export async function getLanguagesSupportingCaching(
|
||||
|
||||
export async function getTotalCacheSize(
|
||||
trapCaches: Partial<Record<Language, string>>,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<number> {
|
||||
const sizes = await Promise.all(
|
||||
Object.values(trapCaches).map((cacheDir) =>
|
||||
tryGetFolderBytes(cacheDir, logger)
|
||||
)
|
||||
tryGetFolderBytes(cacheDir, logger),
|
||||
),
|
||||
);
|
||||
return sizes.map((a) => a || 0).reduce((a, b) => a + b, 0);
|
||||
}
|
||||
@@ -220,14 +220,14 @@ export async function getTotalCacheSize(
|
||||
async function cacheKey(
|
||||
codeql: CodeQL,
|
||||
language: Language,
|
||||
baseSha: string
|
||||
baseSha: string,
|
||||
): Promise<string> {
|
||||
return `${await cachePrefix(codeql, language)}${baseSha}`;
|
||||
}
|
||||
|
||||
async function cachePrefix(
|
||||
codeql: CodeQL,
|
||||
language: Language
|
||||
language: Language,
|
||||
): Promise<string> {
|
||||
return `codeql-trap-${CACHE_VERSION}-${await codeql.getVersion()}-${language}-`;
|
||||
}
|
||||
|
||||
@@ -18,14 +18,14 @@ test.beforeEach(() => {
|
||||
test("validateSarifFileSchema - valid", (t) => {
|
||||
const inputFile = `${__dirname}/../src/testdata/valid-sarif.sarif`;
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateSarifFileSchema(inputFile, getRunnerLogger(true))
|
||||
uploadLib.validateSarifFileSchema(inputFile, getRunnerLogger(true)),
|
||||
);
|
||||
});
|
||||
|
||||
test("validateSarifFileSchema - invalid", (t) => {
|
||||
const inputFile = `${__dirname}/../src/testdata/invalid-sarif.sarif`;
|
||||
t.throws(() =>
|
||||
uploadLib.validateSarifFileSchema(inputFile, getRunnerLogger(true))
|
||||
uploadLib.validateSarifFileSchema(inputFile, getRunnerLogger(true)),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ test("validate correct payload used for push, PR merge commit, and PR head", asy
|
||||
"/opt/src",
|
||||
undefined,
|
||||
["CodeQL", "eslint"],
|
||||
"mergeBaseCommit"
|
||||
"mergeBaseCommit",
|
||||
);
|
||||
// Not triggered by a pull request
|
||||
t.falsy(pushPayload.base_ref);
|
||||
@@ -65,7 +65,7 @@ test("validate correct payload used for push, PR merge commit, and PR head", asy
|
||||
"/opt/src",
|
||||
undefined,
|
||||
["CodeQL", "eslint"],
|
||||
"mergeBaseCommit"
|
||||
"mergeBaseCommit",
|
||||
);
|
||||
// Uploads for a merge commit use the merge base
|
||||
t.deepEqual(prMergePayload.base_ref, "refs/heads/master");
|
||||
@@ -82,13 +82,13 @@ test("validate correct payload used for push, PR merge commit, and PR head", asy
|
||||
"/opt/src",
|
||||
undefined,
|
||||
["CodeQL", "eslint"],
|
||||
"mergeBaseCommit"
|
||||
"mergeBaseCommit",
|
||||
);
|
||||
// Uploads for the head use the PR base
|
||||
t.deepEqual(prHeadPayload.base_ref, "refs/heads/master");
|
||||
t.deepEqual(
|
||||
prHeadPayload.base_sha,
|
||||
"f95f852bd8fca8fcc58a9a2d6c842781e32a215e"
|
||||
"f95f852bd8fca8fcc58a9a2d6c842781e32a215e",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -113,7 +113,7 @@ test("finding SARIF files", async (t) => {
|
||||
fs.symlinkSync(
|
||||
path.join(tmpDir, "a.sarif"),
|
||||
path.join(tmpDir, "dir3", "symlink2.sarif"),
|
||||
"file"
|
||||
"file",
|
||||
);
|
||||
|
||||
const sarifFiles = uploadLib.findSarifFilesInDir(tmpDir);
|
||||
@@ -142,7 +142,7 @@ test("populateRunAutomationDetails", (t) => {
|
||||
sarif,
|
||||
"language:javascript/os:linux",
|
||||
analysisKey,
|
||||
'{"language": "other", "os": "other"}'
|
||||
'{"language": "other", "os": "other"}',
|
||||
);
|
||||
t.deepEqual(modifiedSarif, expectedSarif);
|
||||
|
||||
@@ -151,7 +151,7 @@ test("populateRunAutomationDetails", (t) => {
|
||||
sarif,
|
||||
"language:javascript/os:linux/",
|
||||
analysisKey,
|
||||
""
|
||||
"",
|
||||
);
|
||||
t.deepEqual(modifiedSarif, expectedSarif);
|
||||
|
||||
@@ -162,7 +162,7 @@ test("populateRunAutomationDetails", (t) => {
|
||||
sarif,
|
||||
undefined,
|
||||
analysisKey,
|
||||
'{"os": "linux", "language": "javascript"}'
|
||||
'{"os": "linux", "language": "javascript"}',
|
||||
);
|
||||
t.deepEqual(modifiedSarif, expectedSarif);
|
||||
|
||||
@@ -182,7 +182,7 @@ test("populateRunAutomationDetails", (t) => {
|
||||
sarif,
|
||||
undefined,
|
||||
analysisKey,
|
||||
'{"os": "linux", "language": "javascript"}'
|
||||
'{"os": "linux", "language": "javascript"}',
|
||||
);
|
||||
t.deepEqual(modifiedSarif, expectedSarif);
|
||||
});
|
||||
@@ -203,7 +203,7 @@ test("validateUniqueCategory for automation details id", (t) => {
|
||||
// Our category sanitization is not perfect. Here are some examples
|
||||
// of where we see false clashes
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc/def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc/def")),
|
||||
);
|
||||
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc@def")));
|
||||
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc_def")));
|
||||
@@ -211,69 +211,69 @@ test("validateUniqueCategory for automation details id", (t) => {
|
||||
|
||||
// this one is fine
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_ def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_ def")),
|
||||
);
|
||||
});
|
||||
|
||||
test("validateUniqueCategory for tool name", (t) => {
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "AbC"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "AbC")),
|
||||
);
|
||||
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "def")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "def")),
|
||||
);
|
||||
|
||||
// Our category sanitization is not perfect. Here are some examples
|
||||
// of where we see false clashes
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc/def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc/def")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc@def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc@def")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc_def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc_def")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif(undefined, "abc def")),
|
||||
);
|
||||
|
||||
// this one is fine
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_ def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_ def")),
|
||||
);
|
||||
});
|
||||
|
||||
test("validateUniqueCategory for automation details id and tool name", (t) => {
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc", "abc"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc", "abc")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc", "abc"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc", "abc")),
|
||||
);
|
||||
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_", "def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_", "def")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_", "def"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc_", "def")),
|
||||
);
|
||||
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("ghi", "_jkl")),
|
||||
);
|
||||
|
||||
// Our category sanitization is not perfect. Here are some examples
|
||||
@@ -282,15 +282,15 @@ test("validateUniqueCategory for automation details id and tool name", (t) => {
|
||||
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc", "_")));
|
||||
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc", "def__"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("abc", "def__")),
|
||||
);
|
||||
t.throws(() => uploadLib.validateUniqueCategory(createMockSarif("abc_def")));
|
||||
|
||||
t.notThrows(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("mno_", "pqr"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("mno_", "pqr")),
|
||||
);
|
||||
t.throws(() =>
|
||||
uploadLib.validateUniqueCategory(createMockSarif("mno", "_pqr"))
|
||||
uploadLib.validateUniqueCategory(createMockSarif("mno", "_pqr")),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -374,7 +374,7 @@ test("accept results with invalid artifactLocation.uri value", (t) => {
|
||||
t.deepEqual(loggedMessages.length, 1);
|
||||
t.deepEqual(
|
||||
loggedMessages[0],
|
||||
"Warning: 'not a valid URI' is not a valid URI in 'instance.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri'."
|
||||
"Warning: 'not a valid URI' is not a valid URI in 'instance.runs[0].results[0].locations[0].physicalLocation.artifactLocation.uri'.",
|
||||
);
|
||||
});
|
||||
const affectedCodeQLVersion = {
|
||||
|
||||
@@ -27,14 +27,14 @@ function combineSarifFiles(sarifFiles: string[]): SarifFile {
|
||||
|
||||
for (const sarifFile of sarifFiles) {
|
||||
const sarifObject = JSON.parse(
|
||||
fs.readFileSync(sarifFile, "utf8")
|
||||
fs.readFileSync(sarifFile, "utf8"),
|
||||
) as SarifFile;
|
||||
// Check SARIF version
|
||||
if (combinedSarif.version === null) {
|
||||
combinedSarif.version = sarifObject.version;
|
||||
} else if (combinedSarif.version !== sarifObject.version) {
|
||||
throw new Error(
|
||||
`Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}`
|
||||
`Different SARIF versions encountered: ${combinedSarif.version} and ${sarifObject.version}`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ export function populateRunAutomationDetails(
|
||||
sarif: SarifFile,
|
||||
category: string | undefined,
|
||||
analysis_key: string,
|
||||
environment: string | undefined
|
||||
environment: string | undefined,
|
||||
): SarifFile {
|
||||
const automationID = getAutomationID(category, analysis_key, environment);
|
||||
|
||||
@@ -70,7 +70,7 @@ export function populateRunAutomationDetails(
|
||||
function getAutomationID(
|
||||
category: string | undefined,
|
||||
analysis_key: string,
|
||||
environment: string | undefined
|
||||
environment: string | undefined,
|
||||
): string | undefined {
|
||||
if (category !== undefined) {
|
||||
let automationID = category;
|
||||
@@ -88,7 +88,7 @@ function getAutomationID(
|
||||
async function uploadPayload(
|
||||
payload: any,
|
||||
repositoryNwo: RepositoryNwo,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
logger.info("Uploading results");
|
||||
|
||||
@@ -96,10 +96,10 @@ async function uploadPayload(
|
||||
if (util.isInTestMode()) {
|
||||
const payloadSaveFile = path.join(
|
||||
actionsUtil.getTemporaryDirectory(),
|
||||
"payload.json"
|
||||
"payload.json",
|
||||
);
|
||||
logger.info(
|
||||
`In test mode. Results are not uploaded. Saving to ${payloadSaveFile}`
|
||||
`In test mode. Results are not uploaded. Saving to ${payloadSaveFile}`,
|
||||
);
|
||||
logger.info(`Payload: ${JSON.stringify(payload, null, 2)}`);
|
||||
fs.writeFileSync(payloadSaveFile, JSON.stringify(payload, null, 2));
|
||||
@@ -114,7 +114,7 @@ async function uploadPayload(
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
data: payload,
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
logger.debug(`response status: ${response.status}`);
|
||||
@@ -161,7 +161,7 @@ export async function uploadFromActions(
|
||||
sarifPath: string,
|
||||
checkoutPath: string,
|
||||
category: string | undefined,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<UploadResult> {
|
||||
return await uploadFiles(
|
||||
getSarifFilePaths(sarifPath),
|
||||
@@ -175,7 +175,7 @@ export async function uploadFromActions(
|
||||
actionsUtil.getWorkflowRunAttempt(),
|
||||
checkoutPath,
|
||||
actionsUtil.getRequiredInput("matrix"),
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -204,7 +204,7 @@ function countResultsInSarif(sarif: string): number {
|
||||
parsedSarif = JSON.parse(sarif);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Invalid SARIF. JSON syntax error: ${wrapError(e).message}`
|
||||
`Invalid SARIF. JSON syntax error: ${wrapError(e).message}`,
|
||||
);
|
||||
}
|
||||
if (!Array.isArray(parsedSarif.runs)) {
|
||||
@@ -230,15 +230,15 @@ export function validateSarifFileSchema(sarifFilePath: string, logger: Logger) {
|
||||
// Filter errors related to invalid URIs in the artifactLocation field as this
|
||||
// is a breaking change. See https://github.com/github/codeql-action/issues/1703
|
||||
const errors = (result.errors || []).filter(
|
||||
(err) => err.argument !== "uri-reference"
|
||||
(err) => err.argument !== "uri-reference",
|
||||
);
|
||||
const warnings = (result.errors || []).filter(
|
||||
(err) => err.argument === "uri-reference"
|
||||
(err) => err.argument === "uri-reference",
|
||||
);
|
||||
|
||||
for (const warning of warnings) {
|
||||
logger.info(
|
||||
`Warning: '${warning.instance}' is not a valid URI in '${warning.property}'.`
|
||||
`Warning: '${warning.instance}' is not a valid URI in '${warning.property}'.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -255,8 +255,8 @@ export function validateSarifFileSchema(sarifFilePath: string, logger: Logger) {
|
||||
const sarifErrors = errors.map((e) => `- ${e.stack}`);
|
||||
throw new Error(
|
||||
`Unable to upload "${sarifFilePath}" as it is not valid SARIF:\n${sarifErrors.join(
|
||||
"\n"
|
||||
)}`
|
||||
"\n",
|
||||
)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -274,7 +274,7 @@ export function buildPayload(
|
||||
checkoutURI: string,
|
||||
environment: string | undefined,
|
||||
toolNames: string[],
|
||||
mergeBaseCommitOid: string | undefined
|
||||
mergeBaseCommitOid: string | undefined,
|
||||
) {
|
||||
const payloadObj = {
|
||||
commit_oid: commitOid,
|
||||
@@ -301,7 +301,7 @@ export function buildPayload(
|
||||
// and were able to determine the merge base.
|
||||
// So we use that as the most accurate base.
|
||||
payloadObj.base_ref = `refs/heads/${util.getRequiredEnvParam(
|
||||
"GITHUB_BASE_REF"
|
||||
"GITHUB_BASE_REF",
|
||||
)}`;
|
||||
payloadObj.base_sha = mergeBaseCommitOid;
|
||||
} else if (process.env.GITHUB_EVENT_PATH) {
|
||||
@@ -309,7 +309,7 @@ export function buildPayload(
|
||||
// or we could not determine the merge base.
|
||||
// Using the PR base is the only option here
|
||||
const githubEvent = JSON.parse(
|
||||
fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf8")
|
||||
fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf8"),
|
||||
);
|
||||
payloadObj.base_ref = `refs/heads/${githubEvent.pull_request.base.ref}`;
|
||||
payloadObj.base_sha = githubEvent.pull_request.base.sha;
|
||||
@@ -332,7 +332,7 @@ async function uploadFiles(
|
||||
workflowRunAttempt: number,
|
||||
sourceRoot: string,
|
||||
environment: string | undefined,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<UploadResult> {
|
||||
logger.startGroup("Uploading results");
|
||||
logger.info(`Processing sarif files: ${JSON.stringify(sarifFiles)}`);
|
||||
@@ -349,7 +349,7 @@ async function uploadFiles(
|
||||
sarif,
|
||||
category,
|
||||
analysisKey,
|
||||
environment
|
||||
environment,
|
||||
);
|
||||
|
||||
if (env["CODEQL_DISABLE_SARIF_PRUNING"] !== "true")
|
||||
@@ -373,7 +373,7 @@ async function uploadFiles(
|
||||
checkoutURI,
|
||||
environment,
|
||||
toolNames,
|
||||
await actionsUtil.determineMergeBaseCommitOid()
|
||||
await actionsUtil.determineMergeBaseCommitOid(),
|
||||
);
|
||||
|
||||
// Log some useful debug info about the info
|
||||
@@ -418,7 +418,7 @@ export async function waitForProcessing(
|
||||
logger: Logger,
|
||||
options: { isUnsuccessfulExecution: boolean } = {
|
||||
isUnsuccessfulExecution: false,
|
||||
}
|
||||
},
|
||||
): Promise<void> {
|
||||
logger.startGroup("Waiting for processing to finish");
|
||||
try {
|
||||
@@ -435,7 +435,7 @@ export async function waitForProcessing(
|
||||
// It's possible the analysis will eventually finish processing, but it's not worth spending more
|
||||
// Actions time waiting.
|
||||
logger.warning(
|
||||
"Timed out waiting for analysis to finish processing. Continuing."
|
||||
"Timed out waiting for analysis to finish processing. Continuing.",
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -447,11 +447,11 @@ export async function waitForProcessing(
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
sarif_id: sarifID,
|
||||
}
|
||||
},
|
||||
);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`An error occurred checking the status of the delivery. ${e} It should still be processed in the background, but errors that occur during processing may not be reported.`
|
||||
`An error occurred checking the status of the delivery. ${e} It should still be processed in the background, but errors that occur during processing may not be reported.`,
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -466,14 +466,14 @@ export async function waitForProcessing(
|
||||
handleProcessingResultForUnsuccessfulExecution(
|
||||
response,
|
||||
status,
|
||||
logger
|
||||
logger,
|
||||
);
|
||||
break;
|
||||
} else if (status === "complete") {
|
||||
break;
|
||||
} else if (status === "failed") {
|
||||
throw new Error(
|
||||
`Code Scanning could not process the submitted SARIF file:\n${response.data.errors}`
|
||||
`Code Scanning could not process the submitted SARIF file:\n${response.data.errors}`,
|
||||
);
|
||||
} else {
|
||||
util.assertNever(status);
|
||||
@@ -495,7 +495,7 @@ export async function waitForProcessing(
|
||||
function handleProcessingResultForUnsuccessfulExecution(
|
||||
response: OctokitResponse<any, number>,
|
||||
status: Exclude<ProcessingStatus, "pending">,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): void {
|
||||
if (
|
||||
status === "failed" &&
|
||||
@@ -505,12 +505,12 @@ function handleProcessingResultForUnsuccessfulExecution(
|
||||
) {
|
||||
logger.debug(
|
||||
"Successfully uploaded a SARIF file for the unsuccessful execution. Received expected " +
|
||||
'"unsuccessful execution" processing error, and no other errors.'
|
||||
'"unsuccessful execution" processing error, and no other errors.',
|
||||
);
|
||||
} else if (status === "failed") {
|
||||
logger.warning(
|
||||
`Failed to upload a SARIF file for the unsuccessful execution. Code scanning status ` +
|
||||
`information for the repository may be out of date as a result. Processing errors: ${response.data.errors}`
|
||||
`information for the repository may be out of date as a result. Processing errors: ${response.data.errors}`,
|
||||
);
|
||||
} else if (status === "complete") {
|
||||
// There is a known transient issue with the code scanning API where it sometimes reports
|
||||
@@ -518,7 +518,7 @@ function handleProcessingResultForUnsuccessfulExecution(
|
||||
logger.debug(
|
||||
"Uploaded a SARIF file for the unsuccessful execution, but did not receive the expected " +
|
||||
'"unsuccessful execution" processing error. This is a known transient issue with the ' +
|
||||
"code scanning API, and does not cause out of date code scanning status information."
|
||||
"code scanning API, and does not cause out of date code scanning status information.",
|
||||
);
|
||||
} else {
|
||||
util.assertNever(status);
|
||||
@@ -544,7 +544,7 @@ export function validateUniqueCategory(sarif: SarifFile): void {
|
||||
"Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job per tool/category. " +
|
||||
"The easiest fix is to specify a unique value for the `category` input. If .runs[].automationDetails.id is specified " +
|
||||
"in the sarif file, that will take precedence over your configured `category`. " +
|
||||
`Category: (${id ? id : "none"}) Tool: (${tool ? tool : "none"})`
|
||||
`Category: (${id ? id : "none"}) Tool: (${tool ? tool : "none"})`,
|
||||
);
|
||||
}
|
||||
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
|
||||
@@ -566,7 +566,7 @@ function sanitize(str?: string) {
|
||||
|
||||
export function pruneInvalidResults(
|
||||
sarif: SarifFile,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): SarifFile {
|
||||
let pruned = 0;
|
||||
const newRuns: SarifRun[] = [];
|
||||
@@ -597,7 +597,7 @@ export function pruneInvalidResults(
|
||||
}
|
||||
if (pruned > 0) {
|
||||
logger.info(
|
||||
`Pruned ${pruned} results believed to be invalid from SARIF file.`
|
||||
`Pruned ${pruned} results believed to be invalid from SARIF file.`,
|
||||
);
|
||||
}
|
||||
return { ...sarif, runs: newRuns };
|
||||
|
||||
@@ -19,12 +19,12 @@ interface UploadSarifStatusReport
|
||||
|
||||
async function sendSuccessStatusReport(
|
||||
startedAt: Date,
|
||||
uploadStats: upload_lib.UploadStatusReport
|
||||
uploadStats: upload_lib.UploadStatusReport,
|
||||
) {
|
||||
const statusReportBase = await createStatusReportBase(
|
||||
"upload-sarif",
|
||||
"success",
|
||||
startedAt
|
||||
startedAt,
|
||||
);
|
||||
const statusReport: UploadSarifStatusReport = {
|
||||
...statusReportBase,
|
||||
@@ -38,7 +38,7 @@ async function run() {
|
||||
initializeEnvironment(getActionVersion());
|
||||
if (
|
||||
!(await sendStatusReport(
|
||||
await createStatusReportBase("upload-sarif", "starting", startedAt)
|
||||
await createStatusReportBase("upload-sarif", "starting", startedAt),
|
||||
))
|
||||
) {
|
||||
return;
|
||||
@@ -49,7 +49,7 @@ async function run() {
|
||||
actionsUtil.getRequiredInput("sarif_file"),
|
||||
actionsUtil.getRequiredInput("checkout_path"),
|
||||
actionsUtil.getOptionalInput("category"),
|
||||
getActionsLogger()
|
||||
getActionsLogger(),
|
||||
);
|
||||
core.setOutput("sarif-id", uploadResult.sarifID);
|
||||
|
||||
@@ -60,7 +60,7 @@ async function run() {
|
||||
await upload_lib.waitForProcessing(
|
||||
parseRepositoryNwo(getRequiredEnvParam("GITHUB_REPOSITORY")),
|
||||
uploadResult.sarifID,
|
||||
getActionsLogger()
|
||||
getActionsLogger(),
|
||||
);
|
||||
}
|
||||
await sendSuccessStatusReport(startedAt, uploadResult.statusReport);
|
||||
@@ -75,8 +75,8 @@ async function run() {
|
||||
actionsUtil.getActionsStatus(error),
|
||||
startedAt,
|
||||
message,
|
||||
error.stack
|
||||
)
|
||||
error.stack,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -87,7 +87,7 @@ async function runWrapper() {
|
||||
await run();
|
||||
} catch (error) {
|
||||
core.setFailed(
|
||||
`codeql/upload-sarif action failed: ${wrapError(error).message}`
|
||||
`codeql/upload-sarif action failed: ${wrapError(error).message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ setupTests(test);
|
||||
test("getToolNames", (t) => {
|
||||
const input = fs.readFileSync(
|
||||
`${__dirname}/../src/testdata/tool-names.sarif`,
|
||||
"utf8"
|
||||
"utf8",
|
||||
);
|
||||
const toolNames = util.getToolNames(JSON.parse(input) as util.SarifFile);
|
||||
t.deepEqual(toolNames, ["CodeQL command-line toolchain", "ESLint"]);
|
||||
@@ -82,14 +82,14 @@ for (const {
|
||||
input,
|
||||
totalMemoryMb * 1024 * 1024,
|
||||
platform,
|
||||
withScaling
|
||||
withScaling,
|
||||
);
|
||||
t.deepEqual(
|
||||
flag,
|
||||
withScaling ? expectedMemoryValueWithScaling : expectedMemoryValue
|
||||
withScaling ? expectedMemoryValueWithScaling : expectedMemoryValue,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@@ -168,48 +168,48 @@ test("parseGitHubUrl", (t) => {
|
||||
t.deepEqual(util.parseGitHubUrl("https://github.com"), "https://github.com");
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://api.github.com"),
|
||||
"https://github.com"
|
||||
"https://github.com",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://github.com/foo/bar"),
|
||||
"https://github.com"
|
||||
"https://github.com",
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("github.example.com"),
|
||||
"https://github.example.com/"
|
||||
"https://github.example.com/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://github.example.com"),
|
||||
"https://github.example.com/"
|
||||
"https://github.example.com/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://api.github.example.com"),
|
||||
"https://github.example.com/"
|
||||
"https://github.example.com/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://github.example.com/api/v3"),
|
||||
"https://github.example.com/"
|
||||
"https://github.example.com/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://github.example.com:1234"),
|
||||
"https://github.example.com:1234/"
|
||||
"https://github.example.com:1234/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://api.github.example.com:1234"),
|
||||
"https://github.example.com:1234/"
|
||||
"https://github.example.com:1234/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://github.example.com:1234/api/v3"),
|
||||
"https://github.example.com:1234/"
|
||||
"https://github.example.com:1234/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://github.example.com/base/path"),
|
||||
"https://github.example.com/base/path/"
|
||||
"https://github.example.com/base/path/",
|
||||
);
|
||||
t.deepEqual(
|
||||
util.parseGitHubUrl("https://github.example.com/base/path/api/v3"),
|
||||
"https://github.example.com/base/path/"
|
||||
"https://github.example.com/base/path/",
|
||||
);
|
||||
|
||||
t.throws(() => util.parseGitHubUrl(""), {
|
||||
@@ -231,11 +231,11 @@ test("allowed API versions", async (t) => {
|
||||
t.is(util.apiVersionInRange("2.0.1", "1.33", "2.0"), undefined);
|
||||
t.is(
|
||||
util.apiVersionInRange("1.32.0", "1.33", "2.0"),
|
||||
util.DisallowedAPIVersionReason.ACTION_TOO_NEW
|
||||
util.DisallowedAPIVersionReason.ACTION_TOO_NEW,
|
||||
);
|
||||
t.is(
|
||||
util.apiVersionInRange("2.1.0", "1.33", "2.0"),
|
||||
util.DisallowedAPIVersionReason.ACTION_TOO_OLD
|
||||
util.DisallowedAPIVersionReason.ACTION_TOO_OLD,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -328,7 +328,7 @@ test("withTimeout doesn't call callback if promise resolves", async (t) => {
|
||||
});
|
||||
|
||||
function createMockSarifWithNotification(
|
||||
locations: util.SarifLocation[]
|
||||
locations: util.SarifLocation[],
|
||||
): util.SarifFile {
|
||||
return {
|
||||
runs: [
|
||||
@@ -364,7 +364,7 @@ test("fixInvalidNotifications leaves notifications with unique locations alone",
|
||||
const messages: LoggedMessage[] = [];
|
||||
const result = util.fixInvalidNotifications(
|
||||
createMockSarifWithNotification([stubLocation]),
|
||||
getRecordingLogger(messages)
|
||||
getRecordingLogger(messages),
|
||||
);
|
||||
t.deepEqual(result, createMockSarifWithNotification([stubLocation]));
|
||||
t.is(messages.length, 1);
|
||||
@@ -378,7 +378,7 @@ test("fixInvalidNotifications removes duplicate locations", (t) => {
|
||||
const messages: LoggedMessage[] = [];
|
||||
const result = util.fixInvalidNotifications(
|
||||
createMockSarifWithNotification([stubLocation, stubLocation]),
|
||||
getRecordingLogger(messages)
|
||||
getRecordingLogger(messages),
|
||||
);
|
||||
t.deepEqual(result, createMockSarifWithNotification([stubLocation]));
|
||||
t.is(messages.length, 1);
|
||||
|
||||
64
src/util.ts
64
src/util.ts
@@ -109,7 +109,7 @@ export function getExtraOptionsEnvParam(): object {
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
throw new Error(
|
||||
`${varName} environment variable is set, but does not contain valid JSON: ${error.message}`
|
||||
`${varName} environment variable is set, but does not contain valid JSON: ${error.message}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -136,7 +136,7 @@ export function getToolNames(sarif: SarifFile): string[] {
|
||||
// Creates a random temporary directory, runs the given body, and then deletes the directory.
|
||||
// Mostly intended for use within tests.
|
||||
export async function withTmpDir<T>(
|
||||
body: (tmpDir: string) => Promise<T>
|
||||
body: (tmpDir: string) => Promise<T>,
|
||||
): Promise<T> {
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "codeql-action-"));
|
||||
const result = await body(tmpDir);
|
||||
@@ -154,7 +154,7 @@ export async function withTmpDir<T>(
|
||||
function getSystemReservedMemoryMegaBytes(
|
||||
totalMemoryMegaBytes: number,
|
||||
platform: string,
|
||||
isScalingReservedRamEnabled: boolean
|
||||
isScalingReservedRamEnabled: boolean,
|
||||
): number {
|
||||
// Windows needs more memory for OS processes.
|
||||
const fixedAmount = 1024 * (platform === "win32" ? 1.5 : 1);
|
||||
@@ -180,7 +180,7 @@ export function getMemoryFlagValueForPlatform(
|
||||
userInput: string | undefined,
|
||||
totalMemoryBytes: number,
|
||||
platform: string,
|
||||
isScalingReservedRamEnabled: boolean
|
||||
isScalingReservedRamEnabled: boolean,
|
||||
): number {
|
||||
let memoryToUseMegaBytes: number;
|
||||
if (userInput) {
|
||||
@@ -193,7 +193,7 @@ export function getMemoryFlagValueForPlatform(
|
||||
const reservedMemoryMegaBytes = getSystemReservedMemoryMegaBytes(
|
||||
totalMemoryMegaBytes,
|
||||
platform,
|
||||
isScalingReservedRamEnabled
|
||||
isScalingReservedRamEnabled,
|
||||
);
|
||||
memoryToUseMegaBytes = totalMemoryMegaBytes - reservedMemoryMegaBytes;
|
||||
}
|
||||
@@ -209,13 +209,13 @@ export function getMemoryFlagValueForPlatform(
|
||||
*/
|
||||
export function getMemoryFlagValue(
|
||||
userInput: string | undefined,
|
||||
isScalingReservedRamEnabled: boolean
|
||||
isScalingReservedRamEnabled: boolean,
|
||||
): number {
|
||||
return getMemoryFlagValueForPlatform(
|
||||
userInput,
|
||||
os.totalmem(),
|
||||
process.platform,
|
||||
isScalingReservedRamEnabled
|
||||
isScalingReservedRamEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -228,7 +228,7 @@ export function getMemoryFlagValue(
|
||||
*/
|
||||
export function getMemoryFlag(
|
||||
userInput: string | undefined,
|
||||
isScalingReservedRamEnabled: boolean
|
||||
isScalingReservedRamEnabled: boolean,
|
||||
): string {
|
||||
const megabytes = getMemoryFlagValue(userInput, isScalingReservedRamEnabled);
|
||||
return `--ram=${megabytes}`;
|
||||
@@ -240,7 +240,7 @@ export function getMemoryFlag(
|
||||
* @returns string
|
||||
*/
|
||||
export function getAddSnippetsFlag(
|
||||
userInput: string | boolean | undefined
|
||||
userInput: string | boolean | undefined,
|
||||
): string {
|
||||
if (typeof userInput === "string") {
|
||||
// have to process specifically because any non-empty string is truthy
|
||||
@@ -259,7 +259,7 @@ export function getAddSnippetsFlag(
|
||||
*/
|
||||
export function getThreadsFlagValue(
|
||||
userInput: string | undefined,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): number {
|
||||
let numThreads: number;
|
||||
const maxThreads = os.cpus().length;
|
||||
@@ -270,14 +270,14 @@ export function getThreadsFlagValue(
|
||||
}
|
||||
if (numThreads > maxThreads) {
|
||||
logger.info(
|
||||
`Clamping desired number of threads (${numThreads}) to max available (${maxThreads}).`
|
||||
`Clamping desired number of threads (${numThreads}) to max available (${maxThreads}).`,
|
||||
);
|
||||
numThreads = maxThreads;
|
||||
}
|
||||
const minThreads = -maxThreads;
|
||||
if (numThreads < minThreads) {
|
||||
logger.info(
|
||||
`Clamping desired number of free threads (${numThreads}) to max available (${minThreads}).`
|
||||
`Clamping desired number of free threads (${numThreads}) to max available (${minThreads}).`,
|
||||
);
|
||||
numThreads = minThreads;
|
||||
}
|
||||
@@ -298,7 +298,7 @@ export function getThreadsFlagValue(
|
||||
*/
|
||||
export function getThreadsFlag(
|
||||
userInput: string | undefined,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): string {
|
||||
return `--threads=${getThreadsFlagValue(userInput, logger)}`;
|
||||
}
|
||||
@@ -372,7 +372,7 @@ export type GitHubVersion =
|
||||
|
||||
export function checkGitHubVersionInRange(
|
||||
version: GitHubVersion,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
) {
|
||||
if (hasBeenWarnedAboutVersion || version.type !== GitHubVariant.GHES) {
|
||||
return;
|
||||
@@ -381,21 +381,21 @@ export function checkGitHubVersionInRange(
|
||||
const disallowedAPIVersionReason = apiVersionInRange(
|
||||
version.version,
|
||||
apiCompatibility.minimumVersion,
|
||||
apiCompatibility.maximumVersion
|
||||
apiCompatibility.maximumVersion,
|
||||
);
|
||||
|
||||
if (
|
||||
disallowedAPIVersionReason === DisallowedAPIVersionReason.ACTION_TOO_OLD
|
||||
) {
|
||||
logger.warning(
|
||||
`The CodeQL Action version you are using is too old to be compatible with GitHub Enterprise ${version.version}. If you experience issues, please upgrade to a more recent version of the CodeQL Action.`
|
||||
`The CodeQL Action version you are using is too old to be compatible with GitHub Enterprise ${version.version}. If you experience issues, please upgrade to a more recent version of the CodeQL Action.`,
|
||||
);
|
||||
}
|
||||
if (
|
||||
disallowedAPIVersionReason === DisallowedAPIVersionReason.ACTION_TOO_NEW
|
||||
) {
|
||||
logger.warning(
|
||||
`GitHub Enterprise ${version.version} is too old to be compatible with this version of the CodeQL Action. If you experience issues, please upgrade to a more recent version of GitHub Enterprise or use an older version of the CodeQL Action.`
|
||||
`GitHub Enterprise ${version.version} is too old to be compatible with this version of the CodeQL Action. If you experience issues, please upgrade to a more recent version of GitHub Enterprise or use an older version of the CodeQL Action.`,
|
||||
);
|
||||
}
|
||||
hasBeenWarnedAboutVersion = true;
|
||||
@@ -410,7 +410,7 @@ export enum DisallowedAPIVersionReason {
|
||||
export function apiVersionInRange(
|
||||
version: string,
|
||||
minimumVersion: string,
|
||||
maximumVersion: string
|
||||
maximumVersion: string,
|
||||
): DisallowedAPIVersionReason | undefined {
|
||||
if (!semver.satisfies(version, `>=${minimumVersion}`)) {
|
||||
return DisallowedAPIVersionReason.ACTION_TOO_NEW;
|
||||
@@ -499,7 +499,7 @@ export function getCachedCodeQlVersion(): undefined | string {
|
||||
|
||||
export async function codeQlVersionAbove(
|
||||
codeql: CodeQL,
|
||||
requiredVersion: string
|
||||
requiredVersion: string,
|
||||
): Promise<boolean> {
|
||||
return semver.gte(await codeql.getVersion(), requiredVersion);
|
||||
}
|
||||
@@ -509,7 +509,7 @@ export async function bundleDb(
|
||||
config: Config,
|
||||
language: Language,
|
||||
codeql: CodeQL,
|
||||
dbName: string
|
||||
dbName: string,
|
||||
) {
|
||||
const databasePath = getCodeQLDatabasePath(config, language);
|
||||
const databaseBundlePath = path.resolve(config.dbLocation, `${dbName}.zip`);
|
||||
@@ -532,7 +532,7 @@ export async function bundleDb(
|
||||
*/
|
||||
export async function delay(
|
||||
milliseconds: number,
|
||||
{ allowProcessExit }: { allowProcessExit: boolean }
|
||||
{ allowProcessExit }: { allowProcessExit: boolean },
|
||||
) {
|
||||
return new Promise((resolve) => {
|
||||
const timer = setTimeout(resolve, milliseconds);
|
||||
@@ -552,7 +552,7 @@ export function isGoodVersion(versionSpec: string) {
|
||||
* Checks whether the CodeQL CLI supports the `--expect-discarded-cache` command-line flag.
|
||||
*/
|
||||
export async function supportExpectDiscardedCache(
|
||||
codeQL: CodeQL
|
||||
codeQL: CodeQL,
|
||||
): Promise<boolean> {
|
||||
return codeQlVersionAbove(codeQL, "2.12.1");
|
||||
}
|
||||
@@ -607,7 +607,7 @@ export function listFolder(dir: string): string[] {
|
||||
*/
|
||||
export async function tryGetFolderBytes(
|
||||
cacheDir: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<number | undefined> {
|
||||
try {
|
||||
return await promisify<string, number>(getFolderSize)(cacheDir);
|
||||
@@ -642,7 +642,7 @@ let hadTimeout = false;
|
||||
export async function withTimeout<T>(
|
||||
timeoutMs: number,
|
||||
promise: Promise<T>,
|
||||
onTimeout: () => void
|
||||
onTimeout: () => void,
|
||||
): Promise<T | undefined> {
|
||||
let finished = false;
|
||||
const mainTask = async () => {
|
||||
@@ -674,7 +674,7 @@ export async function withTimeout<T>(
|
||||
export async function checkForTimeout() {
|
||||
if (hadTimeout === true) {
|
||||
core.info(
|
||||
"A timeout occurred, force exiting the process after 30 seconds to prevent hanging."
|
||||
"A timeout occurred, force exiting the process after 30 seconds to prevent hanging.",
|
||||
);
|
||||
await delay(30_000, { allowProcessExit: true });
|
||||
process.exit();
|
||||
@@ -703,7 +703,7 @@ export function isHostedRunner() {
|
||||
}
|
||||
|
||||
export function parseMatrixInput(
|
||||
matrixInput: string | undefined
|
||||
matrixInput: string | undefined,
|
||||
): { [key: string]: string } | undefined {
|
||||
if (matrixInput === undefined || matrixInput === "null") {
|
||||
return undefined;
|
||||
@@ -725,7 +725,7 @@ function removeDuplicateLocations(locations: SarifLocation[]): SarifLocation[] {
|
||||
|
||||
export function fixInvalidNotifications(
|
||||
sarif: SarifFile,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): SarifFile {
|
||||
if (!Array.isArray(sarif.runs)) {
|
||||
return sarif;
|
||||
@@ -759,7 +759,7 @@ export function fixInvalidNotifications(
|
||||
return notification;
|
||||
}
|
||||
const newLocations = removeDuplicateLocations(
|
||||
notification.locations
|
||||
notification.locations,
|
||||
);
|
||||
numDuplicateLocationsRemoved +=
|
||||
notification.locations.length - newLocations.length;
|
||||
@@ -777,7 +777,7 @@ export function fixInvalidNotifications(
|
||||
if (numDuplicateLocationsRemoved > 0) {
|
||||
logger.info(
|
||||
`Removed ${numDuplicateLocationsRemoved} duplicate locations from SARIF notification ` +
|
||||
"objects."
|
||||
"objects.",
|
||||
);
|
||||
} else {
|
||||
logger.debug("No duplicate locations found in SARIF notification objects.");
|
||||
@@ -798,12 +798,12 @@ export function fixInvalidNotifications(
|
||||
export function fixInvalidNotificationsInFile(
|
||||
inputPath: string,
|
||||
outputPath: string,
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): void {
|
||||
if (process.env[EnvVar.DISABLE_DUPLICATE_LOCATION_FIX] === "true") {
|
||||
logger.info(
|
||||
"SARIF notification object duplicate location fix disabled by the " +
|
||||
`${EnvVar.DISABLE_DUPLICATE_LOCATION_FIX} environment variable.`
|
||||
`${EnvVar.DISABLE_DUPLICATE_LOCATION_FIX} environment variable.`,
|
||||
);
|
||||
fs.renameSync(inputPath, outputPath);
|
||||
} else {
|
||||
@@ -825,7 +825,7 @@ export const ML_POWERED_JS_QUERIES_PACK_NAME =
|
||||
* queries beta.
|
||||
*/
|
||||
export async function getMlPoweredJsQueriesPack(
|
||||
codeQL: CodeQL
|
||||
codeQL: CodeQL,
|
||||
): Promise<string> {
|
||||
let version;
|
||||
if (await codeQlVersionAbove(codeQL, "2.11.3")) {
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
|
||||
function errorCodes(
|
||||
actual: CodedError[],
|
||||
expected: CodedError[]
|
||||
expected: CodedError[],
|
||||
): [string[], string[]] {
|
||||
return [actual.map(({ code }) => code), expected.map(({ code }) => code)];
|
||||
}
|
||||
@@ -78,7 +78,7 @@ test("getWorkflowErrors() when on.push is correct with empty objects", (t) => {
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
);
|
||||
|
||||
t.deepEqual(...errorCodes(errors, []));
|
||||
@@ -104,8 +104,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
pull_request: 1,
|
||||
},
|
||||
} as Workflow),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -113,8 +113,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
getWorkflowErrors({
|
||||
on: 1,
|
||||
} as Workflow),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -124,8 +124,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: 1,
|
||||
} as any),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -135,8 +135,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: [1],
|
||||
} as any),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -145,8 +145,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: { 1: 1 },
|
||||
} as Workflow),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -155,8 +155,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: { test: 1 },
|
||||
} as Workflow),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -165,8 +165,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: { test: [1] },
|
||||
} as Workflow),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -176,8 +176,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: { test: { steps: 1 } },
|
||||
} as any),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -187,8 +187,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: { test: { steps: [{ notrun: "git checkout HEAD^2" }] } },
|
||||
} as any),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -197,8 +197,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
on: 1,
|
||||
jobs: { test: [undefined] },
|
||||
} as Workflow),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(...errorCodes(getWorkflowErrors(1 as Workflow), []));
|
||||
@@ -216,8 +216,8 @@ test("getWorkflowErrors() for a range of malformed workflows", (t) => {
|
||||
},
|
||||
},
|
||||
} as any),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -293,7 +293,7 @@ test("patternIsSuperset()", (t) => {
|
||||
t.false(patternIsSuperset("a/main-**/c", "a/**/c"));
|
||||
t.true(patternIsSuperset("/robin/*/release/*", "/robin/moose/release/goose"));
|
||||
t.false(
|
||||
patternIsSuperset("/robin/moose/release/goose", "/robin/*/release/*")
|
||||
patternIsSuperset("/robin/moose/release/goose", "/robin/*/release/*"),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -306,7 +306,7 @@ test("getWorkflowErrors() when branches contain dots", (t) => {
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [4.1, master]
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
);
|
||||
|
||||
t.deepEqual(...errorCodes(errors, []));
|
||||
@@ -322,7 +322,7 @@ test("getWorkflowErrors() when on.push has a trailing comma", (t) => {
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
);
|
||||
|
||||
t.deepEqual(...errorCodes(errors, []));
|
||||
@@ -351,7 +351,7 @@ test("getWorkflowErrors() should only report the current job's CheckoutWrongHead
|
||||
|
||||
test3:
|
||||
steps: []
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
);
|
||||
|
||||
t.deepEqual(...errorCodes(errors, [WorkflowErrors.CheckoutWrongHead]));
|
||||
@@ -380,7 +380,7 @@ test("getWorkflowErrors() should not report a different job's CheckoutWrongHead"
|
||||
|
||||
test3:
|
||||
steps: []
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
);
|
||||
|
||||
t.deepEqual(...errorCodes(errors, []));
|
||||
@@ -390,7 +390,7 @@ test("getWorkflowErrors() when on is missing", (t) => {
|
||||
const errors = getWorkflowErrors(
|
||||
yaml.load(`
|
||||
name: "CodeQL"
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
);
|
||||
|
||||
t.deepEqual(...errorCodes(errors, []));
|
||||
@@ -403,10 +403,10 @@ test("getWorkflowErrors() with a different on setup", (t) => {
|
||||
yaml.load(`
|
||||
name: "CodeQL"
|
||||
on: "workflow_dispatch"
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -415,10 +415,10 @@ test("getWorkflowErrors() with a different on setup", (t) => {
|
||||
yaml.load(`
|
||||
name: "CodeQL"
|
||||
on: [workflow_dispatch]
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -428,10 +428,10 @@ test("getWorkflowErrors() with a different on setup", (t) => {
|
||||
name: "CodeQL"
|
||||
on:
|
||||
workflow_dispatch: {}
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -444,10 +444,10 @@ test("getWorkflowErrors() should not report an error if PRs are totally unconfig
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
|
||||
t.deepEqual(
|
||||
@@ -456,10 +456,10 @@ test("getWorkflowErrors() should not report an error if PRs are totally unconfig
|
||||
yaml.load(`
|
||||
name: "CodeQL"
|
||||
on: ["push"]
|
||||
`) as Workflow
|
||||
`) as Workflow,
|
||||
),
|
||||
[]
|
||||
)
|
||||
[],
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -479,9 +479,9 @@ test("getCategoryInputOrThrow returns category for simple workflow with category
|
||||
category: some-category
|
||||
`) as Workflow,
|
||||
"analysis",
|
||||
{}
|
||||
{},
|
||||
),
|
||||
"some-category"
|
||||
"some-category",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -499,9 +499,9 @@ test("getCategoryInputOrThrow returns undefined for simple workflow without cate
|
||||
- uses: github/codeql-action/analyze@v2
|
||||
`) as Workflow,
|
||||
"analysis",
|
||||
{}
|
||||
{},
|
||||
),
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
@@ -531,9 +531,9 @@ test("getCategoryInputOrThrow returns category for workflow with multiple jobs",
|
||||
category: bar-category
|
||||
`) as Workflow,
|
||||
"bar",
|
||||
{}
|
||||
{},
|
||||
),
|
||||
"bar-category"
|
||||
"bar-category",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -558,9 +558,9 @@ test("getCategoryInputOrThrow finds category for workflow with language matrix",
|
||||
category: "/language:\${{ matrix.language }}"
|
||||
`) as Workflow,
|
||||
"analysis",
|
||||
{ language: "javascript" }
|
||||
{ language: "javascript" },
|
||||
),
|
||||
"/language:javascript"
|
||||
"/language:javascript",
|
||||
);
|
||||
});
|
||||
|
||||
@@ -580,13 +580,13 @@ test("getCategoryInputOrThrow throws error for workflow with dynamic category",
|
||||
category: "\${{ github.workflow }}"
|
||||
`) as Workflow,
|
||||
"analysis",
|
||||
{}
|
||||
{},
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Could not get category input to github/codeql-action/analyze since it contained " +
|
||||
"an unrecognized dynamic value.",
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -610,12 +610,12 @@ test("getCategoryInputOrThrow throws error for workflow with multiple calls to a
|
||||
category: another-category
|
||||
`) as Workflow,
|
||||
"analysis",
|
||||
{}
|
||||
{},
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Could not get category input to github/codeql-action/analyze since the analysis job " +
|
||||
"calls github/codeql-action/analyze multiple times.",
|
||||
}
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -70,7 +70,7 @@ function patternToRegExp(value) {
|
||||
}
|
||||
return arr;
|
||||
}, [])
|
||||
.join("")}$`
|
||||
.join("")}$`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -88,10 +88,13 @@ export interface CodedError {
|
||||
function toCodedErrors(errors: {
|
||||
[code: string]: string;
|
||||
}): Record<string, CodedError> {
|
||||
return Object.entries(errors).reduce((acc, [code, message]) => {
|
||||
acc[code] = { message, code };
|
||||
return acc;
|
||||
}, {} as Record<string, CodedError>);
|
||||
return Object.entries(errors).reduce(
|
||||
(acc, [code, message]) => {
|
||||
acc[code] = { message, code };
|
||||
return acc;
|
||||
},
|
||||
{} as Record<string, CodedError>,
|
||||
);
|
||||
}
|
||||
|
||||
// code to send back via status report
|
||||
@@ -144,7 +147,7 @@ export function getWorkflowErrors(doc: Workflow): CodedError[] {
|
||||
const hasPush = Object.prototype.hasOwnProperty.call(doc.on, "push");
|
||||
const hasPullRequest = Object.prototype.hasOwnProperty.call(
|
||||
doc.on,
|
||||
"pull_request"
|
||||
"pull_request",
|
||||
);
|
||||
|
||||
if (!hasPush && hasPullRequest) {
|
||||
@@ -160,7 +163,7 @@ export function getWorkflowErrors(doc: Workflow): CodedError[] {
|
||||
}
|
||||
|
||||
export async function validateWorkflow(
|
||||
logger: Logger
|
||||
logger: Logger,
|
||||
): Promise<undefined | string> {
|
||||
let workflow: Workflow;
|
||||
try {
|
||||
@@ -210,10 +213,10 @@ export async function getWorkflow(logger: Logger): Promise<Workflow> {
|
||||
const maybeWorkflow = process.env["CODE_SCANNING_WORKFLOW_FILE"];
|
||||
if (maybeWorkflow) {
|
||||
logger.debug(
|
||||
"Using the workflow specified by the CODE_SCANNING_WORKFLOW_FILE environment variable."
|
||||
"Using the workflow specified by the CODE_SCANNING_WORKFLOW_FILE environment variable.",
|
||||
);
|
||||
return yaml.load(
|
||||
zlib.gunzipSync(Buffer.from(maybeWorkflow, "base64")).toString()
|
||||
zlib.gunzipSync(Buffer.from(maybeWorkflow, "base64")).toString(),
|
||||
) as Workflow;
|
||||
}
|
||||
|
||||
@@ -228,12 +231,12 @@ async function getWorkflowAbsolutePath(logger: Logger): Promise<string> {
|
||||
const relativePath = await api.getWorkflowRelativePath();
|
||||
const absolutePath = path.join(
|
||||
getRequiredEnvParam("GITHUB_WORKSPACE"),
|
||||
relativePath
|
||||
relativePath,
|
||||
);
|
||||
|
||||
if (fs.existsSync(absolutePath)) {
|
||||
logger.debug(
|
||||
`Derived the following absolute path for the currently executing workflow: ${absolutePath}.`
|
||||
`Derived the following absolute path for the currently executing workflow: ${absolutePath}.`,
|
||||
);
|
||||
return absolutePath;
|
||||
}
|
||||
@@ -241,23 +244,23 @@ async function getWorkflowAbsolutePath(logger: Logger): Promise<string> {
|
||||
throw new Error(
|
||||
`Expected to find a code scanning workflow file at ${absolutePath}, but no such file existed. ` +
|
||||
"This can happen if the currently running workflow checks out a branch that doesn't contain " +
|
||||
"the corresponding workflow file."
|
||||
"the corresponding workflow file.",
|
||||
);
|
||||
}
|
||||
|
||||
function getStepsCallingAction(
|
||||
job: WorkflowJob,
|
||||
actionName: string
|
||||
actionName: string,
|
||||
): WorkflowJobStep[] {
|
||||
if (job.uses) {
|
||||
throw new Error(
|
||||
`Could not get steps calling ${actionName} since the job calls a reusable workflow.`
|
||||
`Could not get steps calling ${actionName} since the job calls a reusable workflow.`,
|
||||
);
|
||||
}
|
||||
const steps = job.steps;
|
||||
if (!Array.isArray(steps)) {
|
||||
throw new Error(
|
||||
`Could not get steps calling ${actionName} since job.steps was not an array.`
|
||||
`Could not get steps calling ${actionName} since job.steps was not an array.`,
|
||||
);
|
||||
}
|
||||
return steps.filter((step) => step.uses?.includes(actionName));
|
||||
@@ -278,7 +281,7 @@ function getInputOrThrow(
|
||||
jobName: string,
|
||||
actionName: string,
|
||||
inputName: string,
|
||||
matrixVars: { [key: string]: string } | undefined
|
||||
matrixVars: { [key: string]: string } | undefined,
|
||||
) {
|
||||
const preamble = `Could not get ${inputName} input to ${actionName} since`;
|
||||
if (!workflow.jobs) {
|
||||
@@ -290,16 +293,16 @@ function getInputOrThrow(
|
||||
|
||||
const stepsCallingAction = getStepsCallingAction(
|
||||
workflow.jobs[jobName],
|
||||
actionName
|
||||
actionName,
|
||||
);
|
||||
|
||||
if (stepsCallingAction.length === 0) {
|
||||
throw new Error(
|
||||
`${preamble} the ${jobName} job does not call ${actionName}.`
|
||||
`${preamble} the ${jobName} job does not call ${actionName}.`,
|
||||
);
|
||||
} else if (stepsCallingAction.length > 1) {
|
||||
throw new Error(
|
||||
`${preamble} the ${jobName} job calls ${actionName} multiple times.`
|
||||
`${preamble} the ${jobName} job calls ${actionName} multiple times.`,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -315,7 +318,7 @@ function getInputOrThrow(
|
||||
}
|
||||
if (input !== undefined && input.includes("${{")) {
|
||||
throw new Error(
|
||||
`Could not get ${inputName} input to ${actionName} since it contained an unrecognized dynamic value.`
|
||||
`Could not get ${inputName} input to ${actionName} since it contained an unrecognized dynamic value.`,
|
||||
);
|
||||
}
|
||||
return input;
|
||||
@@ -349,14 +352,14 @@ function getAnalyzeActionName() {
|
||||
export function getCategoryInputOrThrow(
|
||||
workflow: Workflow,
|
||||
jobName: string,
|
||||
matrixVars: { [key: string]: string } | undefined
|
||||
matrixVars: { [key: string]: string } | undefined,
|
||||
): string | undefined {
|
||||
return getInputOrThrow(
|
||||
workflow,
|
||||
jobName,
|
||||
getAnalyzeActionName(),
|
||||
"category",
|
||||
matrixVars
|
||||
matrixVars,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -372,14 +375,14 @@ export function getCategoryInputOrThrow(
|
||||
export function getUploadInputOrThrow(
|
||||
workflow: Workflow,
|
||||
jobName: string,
|
||||
matrixVars: { [key: string]: string } | undefined
|
||||
matrixVars: { [key: string]: string } | undefined,
|
||||
): string | undefined {
|
||||
return getInputOrThrow(
|
||||
workflow,
|
||||
jobName,
|
||||
getAnalyzeActionName(),
|
||||
"upload",
|
||||
matrixVars
|
||||
matrixVars,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -395,7 +398,7 @@ export function getUploadInputOrThrow(
|
||||
export function getCheckoutPathInputOrThrow(
|
||||
workflow: Workflow,
|
||||
jobName: string,
|
||||
matrixVars: { [key: string]: string } | undefined
|
||||
matrixVars: { [key: string]: string } | undefined,
|
||||
): string {
|
||||
return (
|
||||
getInputOrThrow(
|
||||
@@ -403,7 +406,7 @@ export function getCheckoutPathInputOrThrow(
|
||||
jobName,
|
||||
getAnalyzeActionName(),
|
||||
"checkout_path",
|
||||
matrixVars
|
||||
matrixVars,
|
||||
) || getRequiredEnvParam("GITHUB_WORKSPACE") // if unspecified, checkout_path defaults to ${{ github.workspace }}
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user