Remove concept of Actions / runner mode

This commit is contained in:
Henry Mercer
2022-11-14 16:37:48 +00:00
parent 51abddb49b
commit b498c79130
45 changed files with 222 additions and 378 deletions

View File

@@ -7,7 +7,7 @@ import * as sinon from "sinon";
import * as actionsutil from "./actions-util";
import { setupActionsVars, setupTests } from "./testing-utils";
import { getMode, initializeEnvironment, Mode, withTmpDir } from "./util";
import { initializeEnvironment, withTmpDir } from "./util";
function errorCodes(
actual: actionsutil.CodedError[],
@@ -719,13 +719,8 @@ on: ["push"]
});
test("initializeEnvironment", (t) => {
initializeEnvironment(Mode.actions, "1.2.3");
t.deepEqual(getMode(), Mode.actions);
initializeEnvironment("1.2.3");
t.deepEqual(process.env.CODEQL_ACTION_VERSION, "1.2.3");
initializeEnvironment(Mode.runner, "4.5.6");
t.deepEqual(getMode(), Mode.runner);
t.deepEqual(process.env.CODEQL_ACTION_VERSION, "4.5.6");
});
test("isAnalyzingDefaultBranch()", async (t) => {

View File

@@ -14,7 +14,7 @@ import {
runFinalize,
runQueries,
} from "./analyze";
import { getApiDetails, getGitHubVersionActionsOnly } from "./api-client";
import { getApiDetails, getGitHubVersion } from "./api-client";
import { runAutobuild } from "./autobuild";
import { getCodeQL } from "./codeql";
import { Config, getConfig } from "./config-utils";
@@ -179,7 +179,7 @@ async function run() {
let trapCacheUploadTime: number | undefined = undefined;
let dbCreationTimings: DatabaseCreationTimings | undefined = undefined;
let didUploadTrapCaches = false;
util.initializeEnvironment(util.Mode.actions, pkg.version);
util.initializeEnvironment(pkg.version);
await util.checkActionVersion(pkg.version);
const logger = getActionsLogger();
@@ -208,10 +208,7 @@ async function run() {
);
}
await util.enrichEnvironment(
util.Mode.actions,
await getCodeQL(config.codeQLCmd)
);
await util.enrichEnvironment(await getCodeQL(config.codeQLCmd));
const apiDetails = getApiDetails();
const outputDir = actionsUtil.getRequiredInput("output");
@@ -227,7 +224,7 @@ async function run() {
util.getRequiredEnvParam("GITHUB_REPOSITORY")
);
const gitHubVersion = await getGitHubVersionActionsOnly();
const gitHubVersion = await getGitHubVersion();
const features = new Features(
gitHubVersion,

View File

@@ -4,7 +4,7 @@ import * as sinon from "sinon";
import { getApiClient } from "./api-client";
import { setupTests } from "./testing-utils";
import { Mode, initializeEnvironment } from "./util";
import { initializeEnvironment } from "./util";
// eslint-disable-next-line import/no-commonjs
const pkg = require("../package.json");
@@ -18,7 +18,7 @@ test.beforeEach(() => {
pluginStub = sinon.stub(githubUtils.GitHub, "plugin");
githubStub = sinon.stub();
pluginStub.returns(githubStub);
initializeEnvironment(Mode.actions, pkg.version);
initializeEnvironment(pkg.version);
});
test("Get the client API", async (t) => {

View File

@@ -6,7 +6,7 @@ import consoleLogLevel from "console-log-level";
import { getRequiredInput } from "./actions-util";
import * as util from "./util";
import { getMode, getRequiredEnvParam, GitHubVersion } from "./util";
import { getRequiredEnvParam, GitHubVersion } from "./util";
// eslint-disable-next-line import/no-commonjs
const pkg = require("../package.json");
@@ -42,7 +42,7 @@ export const getApiClient = function (
return new retryingOctokit(
githubUtils.getOctokitOptions(auth, {
baseUrl: apiURL,
userAgent: `CodeQL-${getMode()}/${pkg.version}`,
userAgent: `CodeQL-Action/${pkg.version}`,
log: consoleLogLevel({ level: "debug" }),
})
);
@@ -83,15 +83,11 @@ let cachedGitHubVersion: GitHubVersion | undefined = undefined;
/**
* Report the GitHub server version. This is a wrapper around
* util.getGitHubVersion() that automatically supplies GitHub API details using
* GitHub Action inputs. If you need to get the GitHub server version from the
* Runner, please call util.getGitHubVersion() instead.
* GitHub Action inputs.
*
* @returns GitHub version
*/
export async function getGitHubVersionActionsOnly(): Promise<GitHubVersion> {
if (!util.isActions()) {
throw new Error("getGitHubVersionActionsOnly() works only in an action");
}
export async function getGitHubVersion(): Promise<GitHubVersion> {
if (cachedGitHubVersion === undefined) {
cachedGitHubVersion = await util.getGitHubVersion(getApiDetails());
}

View File

@@ -8,7 +8,7 @@ import {
sendStatusReport,
StatusReportBase,
} from "./actions-util";
import { getApiDetails, getGitHubVersionActionsOnly } from "./api-client";
import { getApiDetails, getGitHubVersion } from "./api-client";
import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
import * as configUtils from "./config-utils";
import { Features } from "./feature-flags";
@@ -21,7 +21,6 @@ import {
checkGitHubVersionInRange,
getRequiredEnvParam,
initializeEnvironment,
Mode,
} from "./util";
// eslint-disable-next-line import/no-commonjs
@@ -40,7 +39,7 @@ async function sendCompletedStatusReport(
failingLanguage?: string,
cause?: Error
) {
initializeEnvironment(Mode.actions, pkg.version);
initializeEnvironment(pkg.version);
const status = getActionsStatus(cause, failingLanguage);
const statusReportBase = await createStatusReportBase(
@@ -73,8 +72,8 @@ async function run() {
return;
}
const gitHubVersion = await getGitHubVersionActionsOnly();
checkGitHubVersionInRange(gitHubVersion, logger, Mode.actions);
const gitHubVersion = await getGitHubVersion();
checkGitHubVersionInRange(gitHubVersion, logger);
const features = new Features(
gitHubVersion,

View File

@@ -18,7 +18,7 @@ import { Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { setupTests, setupActionsVars, createFeatures } from "./testing-utils";
import * as util from "./util";
import { Mode, initializeEnvironment } from "./util";
import { initializeEnvironment } from "./util";
setupTests(test);
@@ -39,7 +39,7 @@ const sampleGHAEApiDetails = {
let stubConfig: Config;
test.beforeEach(() => {
initializeEnvironment(Mode.actions, "1.2.3");
initializeEnvironment("1.2.3");
stubConfig = {
languages: [Language.cpp],
@@ -424,11 +424,7 @@ test("getExtraOptions throws for bad content", (t) => {
test("getCodeQLActionRepository", (t) => {
const logger = getRunnerLogger(true);
initializeEnvironment(Mode.runner, "1.2.3");
const repoActions = codeql.getCodeQLActionRepository(logger);
t.deepEqual(repoActions, "github/codeql-action");
initializeEnvironment(Mode.actions, "1.2.3");
initializeEnvironment("1.2.3");
// isRunningLocalAction() === true
delete process.env["GITHUB_ACTION_REPOSITORY"];

View File

@@ -304,14 +304,6 @@ function getCodeQLBundleName(): string {
}
export function getCodeQLActionRepository(logger: Logger): string {
if (!util.isActions()) {
return CODEQL_DEFAULT_ACTION_REPOSITORY;
} else {
return getActionsCodeQLActionRepository(logger);
}
}
function getActionsCodeQLActionRepository(logger: Logger): string {
if (process.env["GITHUB_ACTION_REPOSITORY"] !== undefined) {
return process.env["GITHUB_ACTION_REPOSITORY"];
}

View File

@@ -24,14 +24,13 @@ import {
GitHubVariant,
HTTPError,
initializeEnvironment,
Mode,
withTmpDir,
} from "./util";
setupTests(test);
test.beforeEach(() => {
initializeEnvironment(Mode.actions, "1.2.3");
initializeEnvironment("1.2.3");
});
const testRepoName: RepositoryNwo = { owner: "github", repo: "example" };

View File

@@ -18,12 +18,12 @@ import {
setupTests,
} from "./testing-utils";
import * as util from "./util";
import { GitHubVariant, initializeEnvironment, Mode, withTmpDir } from "./util";
import { GitHubVariant, initializeEnvironment, withTmpDir } from "./util";
setupTests(test);
test.beforeEach(() => {
initializeEnvironment(Mode.actions, "1.2.3");
initializeEnvironment("1.2.3");
});
const testApiDetails: GitHubApiDetails = {

View File

@@ -12,7 +12,7 @@ import {
StatusReportBase,
validateWorkflow,
} from "./actions-util";
import { getGitHubVersionActionsOnly } from "./api-client";
import { getGitHubVersion } from "./api-client";
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
import * as configUtils from "./config-utils";
import { Feature, FeatureEnablement, Features } from "./feature-flags";
@@ -40,7 +40,6 @@ import {
getThreadsFlagValue,
initializeEnvironment,
isHostedRunner,
Mode,
} from "./util";
// eslint-disable-next-line import/no-commonjs
@@ -137,7 +136,7 @@ async function sendSuccessStatusReport(
async function run() {
const startedAt = new Date();
const logger = getActionsLogger();
initializeEnvironment(Mode.actions, pkg.version);
initializeEnvironment(pkg.version);
await checkActionVersion(pkg.version);
let config: configUtils.Config;
@@ -151,8 +150,8 @@ async function run() {
apiURL: getRequiredEnvParam("GITHUB_API_URL"),
};
const gitHubVersion = await getGitHubVersionActionsOnly();
checkGitHubVersionInRange(gitHubVersion, logger, Mode.actions);
const gitHubVersion = await getGitHubVersion();
checkGitHubVersionInRange(gitHubVersion, logger);
const repositoryNwo = parseRepositoryNwo(
getRequiredEnvParam("GITHUB_REPOSITORY")
@@ -191,7 +190,7 @@ async function run() {
);
codeql = initCodeQLResult.codeql;
toolsVersion = initCodeQLResult.toolsVersion;
await enrichEnvironment(Mode.actions, codeql);
await enrichEnvironment(codeql);
config = await initConfig(
getOptionalInput("languages"),

View File

@@ -11,7 +11,6 @@ import {
GitHubVariant,
GitHubVersion,
initializeEnvironment,
Mode,
SarifFile,
withTmpDir,
} from "./util";
@@ -19,7 +18,7 @@ import {
setupTests(test);
test.beforeEach(() => {
initializeEnvironment(Mode.actions, "1.2.3");
initializeEnvironment("1.2.3");
});
test("validateSarifFileSchema - valid", (t) => {

View File

@@ -115,14 +115,14 @@ async function uploadPayload(
const client = api.getApiClient(apiDetails);
const reqURL = util.isActions()
? "PUT /repos/:owner/:repo/code-scanning/analysis"
: "POST /repos/:owner/:repo/code-scanning/sarifs";
const response = await client.request(reqURL, {
owner: repositoryNwo.owner,
repo: repositoryNwo.repo,
data: payload,
});
const response = await client.request(
"PUT /repos/:owner/:repo/code-scanning/analysis",
{
owner: repositoryNwo.owner,
repo: repositoryNwo.repo,
data: payload,
}
);
logger.debug(`response status: ${response.status}`);
logger.info("Successfully uploaded results");
@@ -305,61 +305,51 @@ export function buildPayload(
gitHubVersion: util.GitHubVersion,
mergeBaseCommitOid: string | undefined
) {
if (util.isActions()) {
const payloadObj = {
commit_oid: commitOid,
ref,
analysis_key: analysisKey,
analysis_name: analysisName,
sarif: zippedSarif,
workflow_run_id: workflowRunID,
checkout_uri: checkoutURI,
environment,
started_at: process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT],
tool_names: toolNames,
base_ref: undefined as undefined | string,
base_sha: undefined as undefined | string,
};
const payloadObj = {
commit_oid: commitOid,
ref,
analysis_key: analysisKey,
analysis_name: analysisName,
sarif: zippedSarif,
workflow_run_id: workflowRunID,
checkout_uri: checkoutURI,
environment,
started_at: process.env[sharedEnv.CODEQL_WORKFLOW_STARTED_AT],
tool_names: toolNames,
base_ref: undefined as undefined | string,
base_sha: undefined as undefined | string,
};
// This behaviour can be made the default when support for GHES 3.0 is discontinued.
if (
gitHubVersion.type !== util.GitHubVariant.GHES ||
semver.satisfies(gitHubVersion.version, `>=3.1`)
) {
if (actionsUtil.workflowEventName() === "pull_request") {
if (
commitOid === util.getRequiredEnvParam("GITHUB_SHA") &&
mergeBaseCommitOid
) {
// We're uploading results for the merge commit
// 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"
)}`;
payloadObj.base_sha = mergeBaseCommitOid;
} else if (process.env.GITHUB_EVENT_PATH) {
// Either we're not uploading results for the merge commit
// 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")
);
payloadObj.base_ref = `refs/heads/${githubEvent.pull_request.base.ref}`;
payloadObj.base_sha = githubEvent.pull_request.base.sha;
}
// This behaviour can be made the default when support for GHES 3.0 is discontinued.
if (
gitHubVersion.type !== util.GitHubVariant.GHES ||
semver.satisfies(gitHubVersion.version, `>=3.1`)
) {
if (actionsUtil.workflowEventName() === "pull_request") {
if (
commitOid === util.getRequiredEnvParam("GITHUB_SHA") &&
mergeBaseCommitOid
) {
// We're uploading results for the merge commit
// 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"
)}`;
payloadObj.base_sha = mergeBaseCommitOid;
} else if (process.env.GITHUB_EVENT_PATH) {
// Either we're not uploading results for the merge commit
// 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")
);
payloadObj.base_ref = `refs/heads/${githubEvent.pull_request.base.ref}`;
payloadObj.base_sha = githubEvent.pull_request.base.sha;
}
}
return payloadObj;
} else {
return {
commit_sha: commitOid,
ref,
sarif: zippedSarif,
checkout_uri: checkoutURI,
tool_name: toolNames[0],
};
}
return payloadObj;
}
// Uploads the given set of sarif files.
@@ -510,31 +500,28 @@ export async function waitForProcessing(
}
export function validateUniqueCategory(sarif: SarifFile): void {
// This check only works on actions as env vars don't persist between calls to the runner
if (util.isActions()) {
// duplicate categories are allowed in the same sarif file
// but not across multiple sarif files
const categories = {} as Record<string, { id?: string; tool?: string }>;
// duplicate categories are allowed in the same sarif file
// but not across multiple sarif files
const categories = {} as Record<string, { id?: string; tool?: string }>;
for (const run of sarif.runs) {
const id = run?.automationDetails?.id;
const tool = run.tool?.driver?.name;
const category = `${sanitize(id)}_${sanitize(tool)}`;
categories[category] = { id, tool };
}
for (const run of sarif.runs) {
const id = run?.automationDetails?.id;
const tool = run.tool?.driver?.name;
const category = `${sanitize(id)}_${sanitize(tool)}`;
categories[category] = { id, tool };
}
for (const [category, { id, tool }] of Object.entries(categories)) {
const sentinelEnvVar = `CODEQL_UPLOAD_SARIF_${category}`;
if (process.env[sentinelEnvVar]) {
throw new Error(
"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"})`
);
}
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
for (const [category, { id, tool }] of Object.entries(categories)) {
const sentinelEnvVar = `CODEQL_UPLOAD_SARIF_${category}`;
if (process.env[sentinelEnvVar]) {
throw new Error(
"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"})`
);
}
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
}
}

View File

@@ -1,7 +1,7 @@
import * as core from "@actions/core";
import * as actionsUtil from "./actions-util";
import { getApiDetails, getGitHubVersionActionsOnly } from "./api-client";
import { getApiDetails, getGitHubVersion } from "./api-client";
import { getActionsLogger } from "./logging";
import { parseRepositoryNwo } from "./repository";
import * as upload_lib from "./upload-lib";
@@ -10,7 +10,6 @@ import {
getRequiredEnvParam,
initializeEnvironment,
isInTestMode,
Mode,
} from "./util";
// eslint-disable-next-line import/no-commonjs
@@ -38,7 +37,7 @@ async function sendSuccessStatusReport(
async function run() {
const startedAt = new Date();
initializeEnvironment(Mode.actions, pkg.version);
initializeEnvironment(pkg.version);
await checkActionVersion(pkg.version);
if (
!(await actionsUtil.sendStatusReport(
@@ -54,7 +53,7 @@ async function run() {
try {
const apiDetails = getApiDetails();
const gitHubVersion = await getGitHubVersionActionsOnly();
const gitHubVersion = await getGitHubVersion();
const uploadResult = await upload_lib.uploadFromActions(
actionsUtil.getRequiredInput("sarif_file"),

View File

@@ -406,9 +406,8 @@ for (const [
test(`checkActionVersion ${reportWarningDescription} for ${versionsDescription}`, async (t) => {
const warningSpy = sinon.spy(core, "warning");
const versionStub = sinon
.stub(api, "getGitHubVersionActionsOnly")
.stub(api, "getGitHubVersion")
.resolves(githubVersion);
const isActionsStub = sinon.stub(util, "isActions").returns(true);
await util.checkActionVersion(version);
if (shouldReportWarning) {
t.true(
@@ -420,7 +419,6 @@ for (const [
t.false(warningSpy.called);
}
versionStub.restore();
isActionsStub.restore();
});
}

View File

@@ -348,8 +348,7 @@ export async function getGitHubVersion(
export function checkGitHubVersionInRange(
version: GitHubVersion,
logger: Logger,
toolName: Mode
logger: Logger
) {
if (hasBeenWarnedAboutVersion || version.type !== GitHubVariant.GHES) {
return;
@@ -365,20 +364,18 @@ export function checkGitHubVersionInRange(
disallowedAPIVersionReason === DisallowedAPIVersionReason.ACTION_TOO_OLD
) {
logger.warning(
`The CodeQL ${toolName} 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 ${toolName}.`
`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 ${toolName}. If you experience issues, please upgrade to a more recent version of GitHub Enterprise or use an older version of the CodeQL ${toolName}.`
`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;
if (isActions()) {
core.exportVariable(CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR, true);
}
core.exportVariable(CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR, true);
}
export enum DisallowedAPIVersionReason {
@@ -482,22 +479,12 @@ export function assertNever(value: never): never {
throw new ExhaustivityCheckingError(value);
}
export enum Mode {
actions = "Action",
runner = "Runner",
}
/**
* Environment variables to be set by codeql-action and used by the
* CLI. These environment variables are relevant for both the runner
* and the action.
*/
export enum EnvVar {
/**
* The mode of the codeql-action, either 'actions' or 'runner'.
*/
RUN_MODE = "CODEQL_ACTION_RUN_MODE",
/**
* Semver of the codeql-action as specified in package.json.
*/
@@ -529,55 +516,30 @@ export enum EnvVar {
FEATURE_SANDWICH = "CODEQL_ACTION_FEATURE_SANDWICH",
}
const exportVar = (mode: Mode, name: string, value: string) => {
if (mode === Mode.actions) {
core.exportVariable(name, value);
} else {
process.env[name] = value;
}
};
/**
* Set some initial environment variables that we can set even without
* knowing what version of CodeQL we're running.
*/
export function initializeEnvironment(mode: Mode, version: string) {
exportVar(mode, EnvVar.RUN_MODE, mode);
exportVar(mode, EnvVar.VERSION, version);
exportVar(mode, EnvVar.FEATURE_SARIF_COMBINE, "true");
exportVar(mode, EnvVar.FEATURE_WILL_UPLOAD, "true");
export function initializeEnvironment(version: string) {
core.exportVariable(EnvVar.VERSION, version);
core.exportVariable(EnvVar.FEATURE_SARIF_COMBINE, "true");
core.exportVariable(EnvVar.FEATURE_WILL_UPLOAD, "true");
}
/**
* Enrich the environment variables with further flags that we cannot
* know the value of until we know what version of CodeQL we're running.
*/
export async function enrichEnvironment(mode: Mode, codeql: CodeQL) {
export async function enrichEnvironment(codeql: CodeQL) {
if (await codeQlVersionAbove(codeql, CODEQL_VERSION_NEW_TRACING)) {
exportVar(mode, EnvVar.FEATURE_MULTI_LANGUAGE, "false");
exportVar(mode, EnvVar.FEATURE_SANDWICH, "false");
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "false");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "false");
} else {
exportVar(mode, EnvVar.FEATURE_MULTI_LANGUAGE, "true");
exportVar(mode, EnvVar.FEATURE_SANDWICH, "true");
core.exportVariable(EnvVar.FEATURE_MULTI_LANGUAGE, "true");
core.exportVariable(EnvVar.FEATURE_SANDWICH, "true");
}
}
export function getMode(): Mode {
// Make sure we fail fast if the env var is missing. This should
// only happen if there is a bug in our code and we neglected
// to set the mode early in the process.
const mode = getRequiredEnvParam(EnvVar.RUN_MODE);
if (mode !== Mode.actions && mode !== Mode.runner) {
throw new Error(`Unknown mode: ${mode}.`);
}
return mode;
}
export function isActions(): boolean {
return getMode() === Mode.actions;
}
/**
* Get an environment parameter, but throw an error if it is not set.
*/
@@ -739,7 +701,7 @@ export function getMlPoweredJsQueriesStatus(config: Config): string {
*/
export async function checkActionVersion(version: string) {
if (!semver.satisfies(version, ">=2")) {
const githubVersion = await api.getGitHubVersionActionsOnly();
const githubVersion = await api.getGitHubVersion();
// Only log a warning for versions of GHES that are compatible with CodeQL Action version 2.
//
// GHES 3.4 shipped without the v2 tag, but it also shipped without this warning message code.