Merge branch 'main' into update-bundle/codeql-bundle-v2.21.3

This commit is contained in:
Henry Mercer 2025-05-14 19:57:41 +01:00 committed by GitHub
commit e93b90025f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
27 changed files with 166 additions and 102 deletions

View file

@ -26,7 +26,6 @@ import { getRepositoryNwoFromEnv } from "./repository";
import { DatabaseCreationTimings, EventReport } from "./status-report";
import { ToolsFeature } from "./tools-features";
import { endTracingForCluster } from "./tracer-config";
import { validateSarifFileSchema } from "./upload-lib";
import * as util from "./util";
import { BuildMode } from "./util";
@ -630,7 +629,7 @@ export async function runQueries(
logger.info(analysisSummary);
if (await features.getValue(Feature.QaTelemetryEnabled)) {
const perQueryAlertCounts = getPerQueryAlertCounts(sarifFile, logger);
const perQueryAlertCounts = getPerQueryAlertCounts(sarifFile);
const perQueryAlertCountEventReport: EventReport = {
event: "codeql database interpret-results",
@ -682,11 +681,7 @@ export async function runQueries(
}
/** Get an object with all queries and their counts parsed from a SARIF file path. */
function getPerQueryAlertCounts(
sarifPath: string,
log: Logger,
): Record<string, number> {
validateSarifFileSchema(sarifPath, log);
function getPerQueryAlertCounts(sarifPath: string): Record<string, number> {
const sarifObject = JSON.parse(
fs.readFileSync(sarifPath, "utf8"),
) as util.SarifFile;

View file

@ -1 +1 @@
{"maximumVersion": "3.17", "minimumVersion": "3.12"}
{"maximumVersion": "3.17", "minimumVersion": "3.13"}

View file

@ -285,17 +285,17 @@ const CODEQL_MINIMUM_VERSION = "2.15.5";
/**
* This version will shortly become the oldest version of CodeQL that the Action will run with.
*/
const CODEQL_NEXT_MINIMUM_VERSION = "2.15.5";
const CODEQL_NEXT_MINIMUM_VERSION = "2.16.6";
/**
* This is the version of GHES that was most recently deprecated.
*/
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.11";
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.12";
/**
* This is the deprecation date for the version of GHES that was most recently deprecated.
*/
const GHES_MOST_RECENT_DEPRECATION_DATE = "2024-12-19";
const GHES_MOST_RECENT_DEPRECATION_DATE = "2025-04-03";
/** The CLI verbosity level to use for extraction in debug mode. */
const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";

View file

@ -547,7 +547,8 @@ async function run() {
);
core.exportVariable(
"CODEQL_THREADS",
getThreadsFlagValue(getOptionalInput("threads"), logger).toString(),
process.env["CODEQL_THREADS"] ||
getThreadsFlagValue(getOptionalInput("threads"), logger).toString(),
);
// Disable Kotlin extractor if feature flag set

View file

@ -29,6 +29,7 @@ import {
assertNever,
BuildMode,
getErrorMessage,
getTestingEnvironment,
} from "./util";
export enum ActionName {
@ -277,10 +278,10 @@ export async function createStatusReportBase(
const runnerOs = getRequiredEnvParam("RUNNER_OS");
const codeQlCliVersion = getCachedCodeQlVersion();
const actionRef = process.env["GITHUB_ACTION_REF"] || "";
const testingEnvironment = process.env[EnvVar.TESTING_ENVIRONMENT] || "";
const testingEnvironment = getTestingEnvironment();
// re-export the testing environment variable so that it is available to subsequent steps,
// even if it was only set for this step
if (testingEnvironment !== "") {
if (testingEnvironment) {
core.exportVariable(EnvVar.TESTING_ENVIRONMENT, testingEnvironment);
}
const isSteadyStateDefaultSetupRun =
@ -303,7 +304,7 @@ export async function createStatusReportBase(
started_at: workflowStartedAt,
status,
steady_state_default_setup: isSteadyStateDefaultSetupRun,
testing_environment: testingEnvironment,
testing_environment: testingEnvironment || "",
workflow_name: workflowName,
workflow_run_attempt: workflowRunAttempt,
workflow_run_id: workflowRunID,

View file

@ -17,14 +17,22 @@ test.beforeEach(() => {
test("validateSarifFileSchema - valid", (t) => {
const inputFile = `${__dirname}/../src/testdata/valid-sarif.sarif`;
t.notThrows(() =>
uploadLib.validateSarifFileSchema(inputFile, getRunnerLogger(true)),
uploadLib.validateSarifFileSchema(
uploadLib.readSarifFile(inputFile),
inputFile,
getRunnerLogger(true),
),
);
});
test("validateSarifFileSchema - invalid", (t) => {
const inputFile = `${__dirname}/../src/testdata/invalid-sarif.sarif`;
t.throws(() =>
uploadLib.validateSarifFileSchema(inputFile, getRunnerLogger(true)),
uploadLib.validateSarifFileSchema(
uploadLib.readSarifFile(inputFile),
inputFile,
getRunnerLogger(true),
),
);
});
@ -314,7 +322,11 @@ test("accept results with invalid artifactLocation.uri value", (t) => {
} as Logger;
const sarifFile = `${__dirname}/../src/testdata/with-invalid-uri.sarif`;
uploadLib.validateSarifFileSchema(sarifFile, mockLogger);
uploadLib.validateSarifFileSchema(
uploadLib.readSarifFile(sarifFile),
sarifFile,
mockLogger,
);
t.deepEqual(loggedMessages.length, 3);
t.deepEqual(

View file

@ -434,18 +434,35 @@ function countResultsInSarif(sarif: string): number {
return numResults;
}
// Validates that the given file path refers to a valid SARIF file.
// Throws an error if the file is invalid.
export function validateSarifFileSchema(sarifFilePath: string, logger: Logger) {
logger.info(`Validating ${sarifFilePath}`);
let sarif;
export function readSarifFile(sarifFilePath: string): SarifFile {
try {
sarif = JSON.parse(fs.readFileSync(sarifFilePath, "utf8")) as SarifFile;
return JSON.parse(fs.readFileSync(sarifFilePath, "utf8")) as SarifFile;
} catch (e) {
throw new InvalidSarifUploadError(
`Invalid SARIF. JSON syntax error: ${getErrorMessage(e)}`,
);
}
}
// Validates the given SARIF object and throws an error if the SARIF object is invalid.
// The file path is only used in error messages to improve clarity.
export function validateSarifFileSchema(
sarif: SarifFile,
sarifFilePath: string,
logger: Logger,
) {
if (
areAllRunsProducedByCodeQL([sarif]) &&
// We want to validate CodeQL SARIF in testing environments.
!util.getTestingEnvironment()
) {
logger.debug(
`Skipping SARIF schema validation for ${sarifFilePath} as all runs are produced by CodeQL.`,
);
return;
}
logger.info(`Validating ${sarifFilePath}`);
// eslint-disable-next-line @typescript-eslint/no-require-imports
const schema = require("../src/sarif-schema-2.1.0.json") as jsonschema.Schema;
@ -551,41 +568,44 @@ export function buildPayload(
}
/**
* Uploads a single SARIF file or a directory of SARIF files depending on what `sarifPath` refers
* Uploads a single SARIF file or a directory of SARIF files depending on what `inputSarifPath` refers
* to.
*/
export async function uploadFiles(
sarifPath: string,
inputSarifPath: string,
checkoutPath: string,
category: string | undefined,
features: FeatureEnablement,
logger: Logger,
): Promise<UploadResult> {
const sarifFiles = getSarifFilePaths(sarifPath);
const sarifPaths = getSarifFilePaths(inputSarifPath);
logger.startGroup("Uploading results");
logger.info(`Processing sarif files: ${JSON.stringify(sarifFiles)}`);
logger.info(`Processing sarif files: ${JSON.stringify(sarifPaths)}`);
const gitHubVersion = await getGitHubVersion();
try {
let sarif: SarifFile;
if (sarifPaths.length > 1) {
// Validate that the files we were asked to upload are all valid SARIF files
for (const file of sarifFiles) {
validateSarifFileSchema(file, logger);
for (const sarifPath of sarifPaths) {
const parsedSarif = readSarifFile(sarifPath);
validateSarifFileSchema(parsedSarif, sarifPath, logger);
}
} catch (e) {
if (e instanceof SyntaxError) {
throw new InvalidSarifUploadError(e.message);
}
throw e;
sarif = await combineSarifFilesUsingCLI(
sarifPaths,
gitHubVersion,
features,
logger,
);
} else {
const sarifPath = sarifPaths[0];
sarif = readSarifFile(sarifPath);
validateSarifFileSchema(sarif, sarifPath, logger);
}
let sarif = await combineSarifFilesUsingCLI(
sarifFiles,
gitHubVersion,
features,
logger,
);
sarif = filterAlertsByDiffRange(logger, sarif);
sarif = await fingerprints.addFingerprints(sarif, checkoutPath, logger);

View file

@ -750,8 +750,8 @@ export function isGoodVersion(versionSpec: string) {
return !BROKEN_VERSIONS.includes(versionSpec);
}
/*
* Returns whether we are in test mode.
/**
* Returns whether we are in test mode. This is used by CodeQL Action PR checks.
*
* In test mode, we don't upload SARIF results or status reports to the GitHub API.
*/
@ -759,7 +759,20 @@ export function isInTestMode(): boolean {
return process.env[EnvVar.TEST_MODE] === "true";
}
/*
/**
* Get the testing environment.
*
* This is set if the CodeQL Action is running in a non-production environment.
*/
export function getTestingEnvironment(): string | undefined {
const testingEnvironment = process.env[EnvVar.TESTING_ENVIRONMENT] || "";
if (testingEnvironment === "") {
return undefined;
}
return testingEnvironment;
}
/**
* Returns whether the path in the argument represents an existing directory.
*/
export function doesDirectoryExist(dirPath: string): boolean {

View file

@ -7,9 +7,12 @@ import * as yaml from "js-yaml";
import * as api from "./api-client";
import { CodeQL } from "./codeql";
import { EnvVar } from "./environment";
import { Logger } from "./logging";
import { getRequiredEnvParam, isInTestMode } from "./util";
import {
getRequiredEnvParam,
getTestingEnvironment,
isInTestMode,
} from "./util";
export interface WorkflowJobStep {
name?: string;
@ -358,10 +361,7 @@ function getInputOrThrow(
* This allows us to test workflow parsing functionality as a CodeQL Action PR check.
*/
function getAnalyzeActionName() {
if (
isInTestMode() ||
process.env[EnvVar.TESTING_ENVIRONMENT] === "codeql-action-pr-checks"
) {
if (isInTestMode() || getTestingEnvironment() === "codeql-action-pr-checks") {
return "./analyze";
} else {
return "github/codeql-action/analyze";