Add initial setup-codeql action

This commit is contained in:
Michael B. Gale
2025-10-12 13:59:51 +01:00
parent 17783bfb99
commit e72fd9acb1
4 changed files with 87921 additions and 0 deletions

87678
lib/setup-codeql-action.js generated Normal file

File diff suppressed because one or more lines are too long

39
setup-codeql/action.yml Normal file
View File

@@ -0,0 +1,39 @@
name: 'CodeQL: Setup'
description: 'Installs the CodeQL CLI'
author: 'GitHub'
inputs:
tools:
description: >-
By default, the Action will use the recommended version of the CodeQL
Bundle to analyze your project. You can override this choice using this
input. One of:
- A local path to a CodeQL Bundle tarball, or
- The URL of a CodeQL Bundle tarball GitHub release asset, or
- A special value `linked` which uses the version of the CodeQL tools
that the Action has been bundled with.
- A special value `nightly` which uses the latest nightly version of the
CodeQL tools. Note that this is unstable and not recommended for
production use.
If not specified, the Action will check in several places until it finds
the CodeQL tools.
required: false
token:
description: GitHub token to use for authenticating with this instance of GitHub. To download custom packs from multiple registries, use the registries input.
default: ${{ github.token }}
required: false
matrix:
default: ${{ toJson(matrix) }}
required: false
external-repository-token:
description: A token for fetching external config files and queries if they reside in a private repository in the same GitHub instance that is running this action.
required: false
outputs:
codeql-path:
description: The path of the CodeQL binary used for analysis
codeql-version:
description: The version of the CodeQL binary used for analysis
runs:
using: node24
main: '../lib/setup-codeql-action.js'

203
src/setup-codeql-action.ts Normal file
View File

@@ -0,0 +1,203 @@
import * as core from "@actions/core";
import { v4 as uuidV4 } from "uuid";
import {
getActionVersion,
getOptionalInput,
getRequiredInput,
getTemporaryDirectory,
} from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { CodeQL } from "./codeql";
import { EnvVar } from "./environment";
import { Features } from "./feature-flags";
import { initCodeQL } from "./init";
import { getActionsLogger, Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
import { ToolsSource } from "./setup-codeql";
import {
ActionName,
InitStatusReport,
createStatusReportBase,
getActionsStatus,
sendStatusReport,
} from "./status-report";
import { ToolsDownloadStatusReport } from "./tools-download";
import {
checkDiskUsage,
checkForTimeout,
checkGitHubVersionInRange,
getRequiredEnvParam,
initializeEnvironment,
ConfigurationError,
wrapError,
checkActionVersion,
getErrorMessage,
} from "./util";
/** Fields of the init status report populated when the tools source is `download`. */
interface InitToolsDownloadFields {
/** Time taken to download the bundle, in milliseconds. */
tools_download_duration_ms?: number;
/**
* Whether the relevant tools dotcom feature flags have been misconfigured.
* Only populated if we attempt to determine the default version based on the dotcom feature flags. */
tools_feature_flags_valid?: boolean;
}
/**
* Helper function to send a full status report for this action.
*/
async function sendCompletedStatusReport(
startedAt: Date,
toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined,
toolsFeatureFlagsValid: boolean | undefined,
toolsSource: ToolsSource,
toolsVersion: string,
logger: Logger,
error?: Error,
): Promise<void> {
const statusReportBase = await createStatusReportBase(
ActionName.SetupCodeQL,
getActionsStatus(error),
startedAt,
undefined,
await checkDiskUsage(logger),
logger,
error?.message,
error?.stack,
);
if (statusReportBase === undefined) {
return;
}
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || ToolsSource.Unknown,
workflow_languages: "",
};
const initToolsDownloadFields: InitToolsDownloadFields = {};
if (toolsDownloadStatusReport?.downloadDurationMs !== undefined) {
initToolsDownloadFields.tools_download_duration_ms =
toolsDownloadStatusReport.downloadDurationMs;
}
if (toolsFeatureFlagsValid !== undefined) {
initToolsDownloadFields.tools_feature_flags_valid = toolsFeatureFlagsValid;
}
await sendStatusReport({ ...initStatusReport, ...initToolsDownloadFields });
}
/** The main behaviour of this action. */
async function run(): Promise<void> {
const startedAt = new Date();
const logger = getActionsLogger();
initializeEnvironment(getActionVersion());
let codeql: CodeQL;
let toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined;
let toolsFeatureFlagsValid: boolean | undefined;
let toolsSource: ToolsSource;
let toolsVersion: string;
const apiDetails = {
auth: getRequiredInput("token"),
externalRepoAuth: getOptionalInput("external-repository-token"),
url: getRequiredEnvParam("GITHUB_SERVER_URL"),
apiURL: getRequiredEnvParam("GITHUB_API_URL"),
};
const gitHubVersion = await getGitHubVersion();
checkGitHubVersionInRange(gitHubVersion, logger);
checkActionVersion(getActionVersion(), gitHubVersion);
const repositoryNwo = getRepositoryNwo();
const features = new Features(
gitHubVersion,
repositoryNwo,
getTemporaryDirectory(),
logger,
);
const jobRunUuid = uuidV4();
logger.info(`Job run UUID is ${jobRunUuid}.`);
core.exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
try {
const statusReportBase = await createStatusReportBase(
ActionName.SetupCodeQL,
"starting",
startedAt,
undefined,
await checkDiskUsage(logger),
logger,
);
if (statusReportBase !== undefined) {
await sendStatusReport(statusReportBase);
}
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
gitHubVersion.type,
);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
codeQLDefaultVersionInfo,
features,
logger,
);
codeql = initCodeQLResult.codeql;
toolsDownloadStatusReport = initCodeQLResult.toolsDownloadStatusReport;
toolsVersion = initCodeQLResult.toolsVersion;
toolsSource = initCodeQLResult.toolsSource;
core.setOutput("codeql-path", codeql.getPath());
core.setOutput("codeql-version", (await codeql.getVersion()).version);
} catch (unwrappedError) {
const error = wrapError(unwrappedError);
core.setFailed(error.message);
const statusReportBase = await createStatusReportBase(
ActionName.SetupCodeQL,
error instanceof ConfigurationError ? "user-error" : "aborted",
startedAt,
undefined,
await checkDiskUsage(logger),
logger,
error.message,
error.stack,
);
if (statusReportBase !== undefined) {
await sendStatusReport(statusReportBase);
}
return;
}
await sendCompletedStatusReport(
startedAt,
toolsDownloadStatusReport,
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
logger,
);
}
/** Run the action and catch any unhandled errors. */
async function runWrapper(): Promise<void> {
try {
await run();
} catch (error) {
core.setFailed(`setup-codeql action failed: ${getErrorMessage(error)}`);
}
await checkForTimeout();
}
void runWrapper();

View File

@@ -41,6 +41,7 @@ export enum ActionName {
Init = "init",
InitPost = "init-post",
ResolveEnvironment = "resolve-environment",
SetupCodeQL = "setup-codeql",
StartProxy = "start-proxy",
UploadSarif = "upload-sarif",
}