diff --git a/lib/entry-points.js b/lib/entry-points.js index 6359bbbc83..44e510c1b7 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -144615,20 +144615,26 @@ function initializeEnvironment(version) { core2.exportVariable("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true"); core2.exportVariable("CODEQL_ACTION_VERSION" /* VERSION */, version); } -function getRequiredEnvParam(paramName) { - const value = process.env[paramName]; +function getRequiredEnvVar(env, paramName) { + const value = env[paramName]; if (value === void 0 || value.length === 0) { throw new Error(`${paramName} environment variable must be set`); } return value; } -function getOptionalEnvVar(paramName) { - const value = process.env[paramName]; +function getRequiredEnvParam(paramName) { + return getRequiredEnvVar(process.env, paramName); +} +function getOptionalEnvVarFrom(env, paramName) { + const value = env[paramName]; if (value?.trim().length === 0) { return void 0; } return value; } +function getOptionalEnvVar(paramName) { + return getOptionalEnvVarFrom(process.env, paramName); +} var HTTPError = class extends Error { status; constructor(message, status) { @@ -144980,7 +144986,7 @@ var getOptionalInput = function(name) { }; function getTemporaryDirectory() { const value = process.env["CODEQL_ACTION_TEMP"]; - return value !== void 0 && value !== "" ? value : getRequiredEnvParam("RUNNER_TEMP"); + return value !== void 0 && value !== "" ? value : getRequiredEnvParam("RUNNER_TEMP" /* RUNNER_TEMP */); } var PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json"; function getDiffRangesJsonFilePath() { @@ -144990,19 +144996,19 @@ function getActionVersion() { return "4.36.4"; } function getWorkflowEventName() { - return getRequiredEnvParam("GITHUB_EVENT_NAME"); + return getRequiredEnvParam("GITHUB_EVENT_NAME" /* GITHUB_EVENT_NAME */); } function isRunningLocalAction() { const relativeScriptPath = getRelativeScriptPath(); return relativeScriptPath.startsWith("..") || path2.isAbsolute(relativeScriptPath); } function getRelativeScriptPath() { - const runnerTemp = getRequiredEnvParam("RUNNER_TEMP"); + const runnerTemp = getRequiredEnvParam("RUNNER_TEMP" /* RUNNER_TEMP */); const actionsDirectory = path2.join(path2.dirname(runnerTemp), "_actions"); return path2.relative(actionsDirectory, __filename); } function getWorkflowEvent() { - const eventJsonFile = getRequiredEnvParam("GITHUB_EVENT_PATH"); + const eventJsonFile = getRequiredEnvParam("GITHUB_EVENT_PATH" /* GITHUB_EVENT_PATH */); try { return JSON.parse(fs2.readFileSync(eventJsonFile, "utf-8")); } catch (e) { @@ -145059,31 +145065,33 @@ function getUploadValue(input) { } } function getWorkflowRunID() { - const workflowRunIdString = getRequiredEnvParam("GITHUB_RUN_ID"); + const workflowRunIdString = getRequiredEnvParam("GITHUB_RUN_ID" /* GITHUB_RUN_ID */); 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" /* 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" /* GITHUB_RUN_ID */} must be a non-negative integer. Current value is ${workflowRunIdString}` ); } return workflowRunID; } function getWorkflowRunAttempt() { - const workflowRunAttemptString = getRequiredEnvParam("GITHUB_RUN_ATTEMPT"); + const workflowRunAttemptString = getRequiredEnvParam( + "GITHUB_RUN_ATTEMPT" /* GITHUB_RUN_ATTEMPT */ + ); 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" /* 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" /* GITHUB_RUN_ATTEMPT */} must be a positive integer. Current value is ${workflowRunAttemptString}` ); } return workflowRunAttempt; @@ -145394,8 +145402,8 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {}) function getApiDetails() { return { auth: getRequiredInput("token"), - url: getRequiredEnvParam("GITHUB_SERVER_URL"), - apiURL: getRequiredEnvParam("GITHUB_API_URL") + url: getRequiredEnvParam("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */), + apiURL: getRequiredEnvParam("GITHUB_API_URL" /* GITHUB_API_URL */) }; } function getApiClient() { diff --git a/src/actions-util.ts b/src/actions-util.ts index dea22d5c57..d7fbacbf3e 100644 --- a/src/actions-util.ts +++ b/src/actions-util.ts @@ -21,6 +21,28 @@ import { */ declare const __CODEQL_ACTION_VERSION__: string; +/** + * Enumerates known GitHub Actions environment variables that we expect + * to be set in a GitHub Actions environment. + */ +export enum ActionsEnvVars { + GITHUB_ACTION_REPOSITORY = "GITHUB_ACTION_REPOSITORY", + GITHUB_API_URL = "GITHUB_API_URL", + GITHUB_EVENT_NAME = "GITHUB_EVENT_NAME", + GITHUB_EVENT_PATH = "GITHUB_EVENT_PATH", + GITHUB_JOB = "GITHUB_JOB", + GITHUB_REF = "GITHUB_REF", + GITHUB_REPOSITORY = "GITHUB_REPOSITORY", + GITHUB_RUN_ATTEMPT = "GITHUB_RUN_ATTEMPT", + GITHUB_RUN_ID = "GITHUB_RUN_ID", + GITHUB_SERVER_URL = "GITHUB_SERVER_URL", + GITHUB_SHA = "GITHUB_SHA", + GITHUB_WORKFLOW = "GITHUB_WORKFLOW", + RUNNER_NAME = "RUNNER_NAME", + RUNNER_OS = "RUNNER_OS", + RUNNER_TEMP = "RUNNER_TEMP", +} + /** * Abstracts over GitHub Actions functions so that we do not have to stub * global functions in tests. @@ -65,7 +87,7 @@ export function getTemporaryDirectory(): string { const value = process.env["CODEQL_ACTION_TEMP"]; return value !== undefined && value !== "" ? value - : getRequiredEnvParam("RUNNER_TEMP"); + : getRequiredEnvParam(ActionsEnvVars.RUNNER_TEMP); } const PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json"; @@ -84,7 +106,7 @@ export function getActionVersion(): string { * This will be "dynamic" for default setup workflow runs. */ export function getWorkflowEventName() { - return getRequiredEnvParam("GITHUB_EVENT_NAME"); + return getRequiredEnvParam(ActionsEnvVars.GITHUB_EVENT_NAME); } /** @@ -104,14 +126,14 @@ export function isRunningLocalAction(): boolean { * This can be used to get the Action's name or tell if we're running a local Action. */ function getRelativeScriptPath(): string { - const runnerTemp = getRequiredEnvParam("RUNNER_TEMP"); + const runnerTemp = getRequiredEnvParam(ActionsEnvVars.RUNNER_TEMP); const actionsDirectory = path.join(path.dirname(runnerTemp), "_actions"); return path.relative(actionsDirectory, __filename); } /** Returns the contents of `GITHUB_EVENT_PATH` as a JSON object. */ export function getWorkflowEvent(): any { - const eventJsonFile = getRequiredEnvParam("GITHUB_EVENT_PATH"); + const eventJsonFile = getRequiredEnvParam(ActionsEnvVars.GITHUB_EVENT_PATH); try { return JSON.parse(fs.readFileSync(eventJsonFile, "utf-8")); } catch (e) { @@ -181,16 +203,16 @@ export function getUploadValue(input: string | undefined): UploadKind { * Get the workflow run ID. */ export function getWorkflowRunID(): number { - const workflowRunIdString = getRequiredEnvParam("GITHUB_RUN_ID"); + const workflowRunIdString = getRequiredEnvParam(ActionsEnvVars.GITHUB_RUN_ID); 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}`, + `${ActionsEnvVars.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}`, + `${ActionsEnvVars.GITHUB_RUN_ID} must be a non-negative integer. Current value is ${workflowRunIdString}`, ); } return workflowRunID; @@ -200,16 +222,18 @@ export function getWorkflowRunID(): number { * Get the workflow run attempt number. */ export function getWorkflowRunAttempt(): number { - const workflowRunAttemptString = getRequiredEnvParam("GITHUB_RUN_ATTEMPT"); + const workflowRunAttemptString = getRequiredEnvParam( + ActionsEnvVars.GITHUB_RUN_ATTEMPT, + ); 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}`, + `${ActionsEnvVars.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}`, + `${ActionsEnvVars.GITHUB_RUN_ATTEMPT} must be a positive integer. Current value is ${workflowRunAttemptString}`, ); } return workflowRunAttempt; diff --git a/src/api-client.ts b/src/api-client.ts index 333280f8e7..16e4082e90 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -2,7 +2,11 @@ import * as core from "@actions/core"; import * as githubUtils from "@actions/github/lib/utils"; import * as retry from "@octokit/plugin-retry"; -import { getActionVersion, getRequiredInput } from "./actions-util"; +import { + ActionsEnvVars, + getActionVersion, + getRequiredInput, +} from "./actions-util"; import { EnvVar } from "./environment"; import { Logger } from "./logging"; import { getRepositoryNwo, RepositoryNwo } from "./repository"; @@ -70,8 +74,8 @@ function createApiClientWithDetails( export function getApiDetails(): GitHubApiDetails { return { auth: getRequiredInput("token"), - url: getRequiredEnvParam("GITHUB_SERVER_URL"), - apiURL: getRequiredEnvParam("GITHUB_API_URL"), + url: getRequiredEnvParam(ActionsEnvVars.GITHUB_SERVER_URL), + apiURL: getRequiredEnvParam(ActionsEnvVars.GITHUB_API_URL), }; } diff --git a/src/environment.ts b/src/environment.ts index c3f54ebd27..c0ca050b03 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -160,3 +160,11 @@ export enum EnvVar { /** Used by Code Scanning Risk Assessment to communicate the assessment ID to the CodeQL Action. */ RISK_ASSESSMENT_ID = "CODEQL_ACTION_RISK_ASSESSMENT_ID", } + +/** A wrapper around an environment, to allow abstracting away from `process.env` in tests. */ +export interface Env { + /** Tries to get the value for `name` and throws if there isn't one. */ + getRequired(name: string): string; + /** Gets the value for `name`, or `undefined` if it isn't set or empty. */ + getOptional(name: string): string | undefined; +} diff --git a/src/testing-utils.ts b/src/testing-utils.ts index 2660c21a69..22ed1e21a5 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -10,7 +10,7 @@ import test, { import nock from "nock"; import * as sinon from "sinon"; -import { ActionsEnv, getActionVersion } from "./actions-util"; +import { ActionsEnv, ActionsEnvVars, getActionVersion } from "./actions-util"; import { AnalysisKind } from "./analyses"; import * as apiClient from "./api-client"; import { GitHubApiDetails } from "./api-client"; @@ -18,6 +18,7 @@ import { CachingKind } from "./caching-utils"; import * as codeql from "./codeql"; import { Config } from "./config-utils"; import * as defaults from "./defaults.json"; +import { Env } from "./environment"; import { CodeQLDefaultVersionInfo, Feature, @@ -29,6 +30,7 @@ import { OverlayDatabaseMode } from "./overlay/overlay-database-mode"; import { DEFAULT_DEBUG_ARTIFACT_NAME, DEFAULT_DEBUG_DATABASE_NAME, + getEnv, GitHubVariant, GitHubVersion, HTTPError, @@ -172,6 +174,11 @@ export function makeMacro( return wrapper; } +export function getTestEnv(): Env { + const testEnv: NodeJS.ProcessEnv = {}; + return getEnv(testEnv); +} + /** * Gets an `ActionsEnv` instance for use in tests. */ @@ -200,7 +207,7 @@ export const DEFAULT_ACTIONS_VARS = { GITHUB_WORKFLOW: "test-workflow", RUNNER_NAME: "my-runner", RUNNER_OS: "Linux", -} as const satisfies Record; +} as const satisfies Partial>; /** Partial mappings from GitHub Actions environment variables to values. */ export type ActionVarOverrides = Partial< diff --git a/src/util.ts b/src/util.ts index fc0553b1b7..7f52456608 100644 --- a/src/util.ts +++ b/src/util.ts @@ -13,7 +13,7 @@ import * as apiCompatibility from "./api-compatibility.json"; import type { CodeQL, VersionInfo } from "./codeql"; import type { Pack } from "./config/db-config"; import type { Config } from "./config-utils"; -import { EnvVar } from "./environment"; +import { Env, EnvVar } from "./environment"; import * as json from "./json"; import { Language } from "./languages"; import { Logger } from "./logging"; @@ -566,11 +566,22 @@ export function initializeEnvironment(version: string) { core.exportVariable(EnvVar.VERSION, version); } +/** Gets an `Env` instance for `env`, which is `process.env` by default. */ +export function getEnv(env: NodeJS.ProcessEnv = process.env): Env { + return { + getRequired: (name) => getRequiredEnvVar(env, name), + getOptional: (name) => getOptionalEnvVarFrom(env, name), + }; +} + /** - * Get an environment parameter, but throw an error if it is not set. + * Gets an environment variable, but throws an error if it is not set. */ -export function getRequiredEnvParam(paramName: string): string { - const value = process.env[paramName]; +export function getRequiredEnvVar( + env: NodeJS.ProcessEnv, + paramName: string, +): string { + const value = env[paramName]; if (value === undefined || value.length === 0) { throw new Error(`${paramName} environment variable must be set`); } @@ -578,16 +589,33 @@ export function getRequiredEnvParam(paramName: string): string { } /** - * Get an environment variable, but return `undefined` if it is not set or empty. + * Get an environment parameter, but throw an error if it is not set. */ -export function getOptionalEnvVar(paramName: string): string | undefined { - const value = process.env[paramName]; +export function getRequiredEnvParam(paramName: string): string { + return getRequiredEnvVar(process.env, paramName); +} + +/** + * Gets an environment variable, but returns `undefined` if it is not set or empty. + */ +export function getOptionalEnvVarFrom( + env: NodeJS.ProcessEnv, + paramName: string, +): string | undefined { + const value = env[paramName]; if (value?.trim().length === 0) { return undefined; } return value; } +/** + * Get an environment variable, but return `undefined` if it is not set or empty. + */ +export function getOptionalEnvVar(paramName: string): string | undefined { + return getOptionalEnvVarFrom(process.env, paramName); +} + export class HTTPError extends Error { public status: number;