From cb4720a101be82942124306d34a12346cb54beb3 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Jun 2026 00:49:37 +0000 Subject: [PATCH 01/16] Update supported GitHub Enterprise Server versions --- lib/entry-points.js | 2 +- src/api-compatibility.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 006389be4..877f54d23 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -147686,7 +147686,7 @@ var semver = __toESM(require_semver2()); // src/api-compatibility.json var maximumVersion = "3.22"; -var minimumVersion = "3.16"; +var minimumVersion = "3.17"; // src/json/index.ts function parseString(data) { diff --git a/src/api-compatibility.json b/src/api-compatibility.json index 435f8f1d6..756944019 100644 --- a/src/api-compatibility.json +++ b/src/api-compatibility.json @@ -1 +1 @@ -{"maximumVersion": "3.22", "minimumVersion": "3.16"} +{"maximumVersion": "3.22", "minimumVersion": "3.17"} From 68ec727966f08457179452bd1ae90ba4e45e44ae Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Mon, 15 Jun 2026 17:43:18 +0200 Subject: [PATCH 02/16] Update constants --- lib/entry-points.js | 6 +++--- src/codeql.ts | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 877f54d23..568ed179e 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -153843,9 +153843,9 @@ async function getCombinedTracerConfig(codeql, config) { // src/codeql.ts var cachedCodeQL = void 0; var CODEQL_MINIMUM_VERSION = "2.19.4"; -var CODEQL_NEXT_MINIMUM_VERSION = "2.19.4"; -var GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.15"; -var GHES_MOST_RECENT_DEPRECATION_DATE = "2026-04-09"; +var CODEQL_NEXT_MINIMUM_VERSION = "2.20.7"; +var GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.16"; +var GHES_MOST_RECENT_DEPRECATION_DATE = "2026-06-25"; var EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++"; async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, rawLanguages, useOverlayAwareDefaultCliVersion, features, logger, checkVersion) { try { diff --git a/src/codeql.ts b/src/codeql.ts index 5d78337d2..cb6bef243 100644 --- a/src/codeql.ts +++ b/src/codeql.ts @@ -272,17 +272,17 @@ const CODEQL_MINIMUM_VERSION = "2.19.4"; /** * This version will shortly become the oldest version of CodeQL that the Action will run with. */ -const CODEQL_NEXT_MINIMUM_VERSION = "2.19.4"; +const CODEQL_NEXT_MINIMUM_VERSION = "2.20.7"; /** * This is the version of GHES that was most recently deprecated. */ -const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.15"; +const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.16"; /** * This is the deprecation date for the version of GHES that was most recently deprecated. */ -const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-04-09"; +const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-06-25"; /** The CLI verbosity level to use for extraction in debug mode. */ const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++"; From 1023397ae46b884b86a06dc6c3c63d7c3d1b84a2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Mon, 15 Jun 2026 17:46:01 +0200 Subject: [PATCH 03/16] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1c0d6f84e..e1a2926c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th ## [UNRELEASED] -No user facing changes. +- _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.20.6 and earlier. These versions of CodeQL were discontinued on 25 June 2026 alongside GitHub Enterprise Server 3.16, and will be unsupported by the next minor release of the CodeQL Action. [#3956](https://github.com/github/codeql-action/pull/3956) ## 4.36.2 - 04 Jun 2026 From 37ae669b8969d0b845eaa9cafa95b737f685066a Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 2 Jul 2026 11:04:03 +0100 Subject: [PATCH 04/16] Update deprecation date --- CHANGELOG.md | 2 +- lib/entry-points.js | 2 +- src/codeql.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1a2926c7..fa7709441 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th ## [UNRELEASED] -- _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.20.6 and earlier. These versions of CodeQL were discontinued on 25 June 2026 alongside GitHub Enterprise Server 3.16, and will be unsupported by the next minor release of the CodeQL Action. [#3956](https://github.com/github/codeql-action/pull/3956) +- _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.20.6 and earlier. These versions of CodeQL were discontinued on 1 July 2026 alongside GitHub Enterprise Server 3.16, and will be unsupported by the next minor release of the CodeQL Action. [#3956](https://github.com/github/codeql-action/pull/3956) ## 4.36.2 - 04 Jun 2026 diff --git a/lib/entry-points.js b/lib/entry-points.js index 568ed179e..83c0d5891 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -153845,7 +153845,7 @@ var cachedCodeQL = void 0; var CODEQL_MINIMUM_VERSION = "2.19.4"; var CODEQL_NEXT_MINIMUM_VERSION = "2.20.7"; var GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.16"; -var GHES_MOST_RECENT_DEPRECATION_DATE = "2026-06-25"; +var GHES_MOST_RECENT_DEPRECATION_DATE = "2026-07-01"; var EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++"; async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, rawLanguages, useOverlayAwareDefaultCliVersion, features, logger, checkVersion) { try { diff --git a/src/codeql.ts b/src/codeql.ts index cb6bef243..51fa9600f 100644 --- a/src/codeql.ts +++ b/src/codeql.ts @@ -282,7 +282,7 @@ const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.16"; /** * This is the deprecation date for the version of GHES that was most recently deprecated. */ -const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-06-25"; +const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-07-01"; /** The CLI verbosity level to use for extraction in debug mode. */ const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++"; From 1c42f210612566d6c5c566384feb2ad62f8e49ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:55:10 +0000 Subject: [PATCH 05/16] Bump the npm-minor group across 1 directory with 4 updates Bumps the npm-minor group with 4 updates in the / directory: [js-yaml](https://github.com/nodeca/js-yaml), [eslint-plugin-import-x](https://github.com/un-ts/eslint-plugin-import-x), [nock](https://github.com/nock/nock) and [typescript-eslint](https://github.com/typescript-eslint/typescript-eslint/tree/HEAD/packages/typescript-eslint). Updates `js-yaml` from 5.1.0 to 5.2.0 - [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md) - [Commits](https://github.com/nodeca/js-yaml/compare/5.1.0...5.2.0) Updates `eslint-plugin-import-x` from 4.17.0 to 4.17.1 - [Release notes](https://github.com/un-ts/eslint-plugin-import-x/releases) - [Changelog](https://github.com/un-ts/eslint-plugin-import-x/blob/master/CHANGELOG.md) - [Commits](https://github.com/un-ts/eslint-plugin-import-x/compare/v4.17.0...v4.17.1) Updates `nock` from 14.0.15 to 14.0.16 - [Release notes](https://github.com/nock/nock/releases) - [Changelog](https://github.com/nock/nock/blob/main/CHANGELOG.md) - [Commits](https://github.com/nock/nock/compare/v14.0.15...v14.0.16) Updates `typescript-eslint` from 8.62.0 to 8.62.1 - [Release notes](https://github.com/typescript-eslint/typescript-eslint/releases) - [Changelog](https://github.com/typescript-eslint/typescript-eslint/blob/main/packages/typescript-eslint/CHANGELOG.md) - [Commits](https://github.com/typescript-eslint/typescript-eslint/commits/v8.62.1/packages/typescript-eslint) --- updated-dependencies: - dependency-name: js-yaml dependency-version: 5.2.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: npm-minor - dependency-name: eslint-plugin-import-x dependency-version: 4.17.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: nock dependency-version: 14.0.16 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor - dependency-name: typescript-eslint dependency-version: 8.62.1 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: npm-minor ... Signed-off-by: dependabot[bot] --- package-lock.json | 148 +++++++++++++++++++++++----------------------- package.json | 8 +-- 2 files changed, 78 insertions(+), 78 deletions(-) diff --git a/package-lock.json b/package-lock.json index a580a2c5b..55c539a4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,7 +28,7 @@ "follow-redirects": "^1.16.0", "get-folder-size": "^5.0.0", "https-proxy-agent": "^7.0.6", - "js-yaml": "^5.1.0", + "js-yaml": "^5.2.0", "jsonschema": "1.5.0", "long": "^5.3.2", "node-forge": "^1.4.0", @@ -53,15 +53,15 @@ "eslint": "^9.39.4", "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-github": "^6.0.0", - "eslint-plugin-import-x": "^4.17.0", + "eslint-plugin-import-x": "^4.17.1", "eslint-plugin-jsdoc": "^62.9.0", "eslint-plugin-no-async-foreach": "^0.1.1", "glob": "^13.0.6", "globals": "^17.7.0", - "nock": "^14.0.15", + "nock": "^14.0.16", "sinon": "^22.0.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.62.0" + "typescript-eslint": "^8.62.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -2587,17 +2587,17 @@ "license": "MIT" }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.0.tgz", - "integrity": "sha512-o+mpz7EYiMzXoySXiKmzlabIvTVqUuK5yLrAedRPRDA0IpPFMUV1IXt6OqljIxX/kumN6EjUYp41Hqelh6p/Dw==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz", + "integrity": "sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.62.0", - "@typescript-eslint/type-utils": "8.62.0", - "@typescript-eslint/utils": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0", + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/type-utils": "8.62.1", + "@typescript-eslint/utils": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -2610,7 +2610,7 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.62.0", + "@typescript-eslint/parser": "^8.62.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } @@ -2626,16 +2626,16 @@ } }, "node_modules/@typescript-eslint/parser": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.0.tgz", - "integrity": "sha512-dzHeT2gySzZtLDsuqxU9AkYgIsQoHAHtRBpOqM+Ofzx1Bwrd2RcCjQJ+6iQbsHOIR6NS33bF2W1k3blN1zLDrA==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.62.1.tgz", + "integrity": "sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.62.0", - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0", + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", "debug": "^4.4.3" }, "engines": { @@ -2669,14 +2669,14 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.0.tgz", - "integrity": "sha512-wexnCqiTg7BOGtbLDftYpRWlmLq4xfoMd7BKFR6Y75sZS3QmRKLdN3yWLhmIYgqMmP/OXWpj3H8odkb5nGURCQ==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.62.1.tgz", + "integrity": "sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.62.0", - "@typescript-eslint/types": "^8.62.0", + "@typescript-eslint/tsconfig-utils": "^8.62.1", + "@typescript-eslint/types": "^8.62.1", "debug": "^4.4.3" }, "engines": { @@ -2709,14 +2709,14 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.0.tgz", - "integrity": "sha512-1lX38kNxXIRb8mEc3lbq5mdHq1Pf2+U0nFU65KfT18mtPxxl0fvjuEE92mHuXPuCtElJhOrddOpyMlM3Z0umEA==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz", + "integrity": "sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0" + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2727,9 +2727,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.0.tgz", - "integrity": "sha512-y2GAdB6ykaXUvuspbYnizQc4oDDz0Tz/Yc7iWrXf9mx8vm/L/0vLHCe0tS2boG96Zy+DivnVDQ9ZUEWoHqqx1g==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz", + "integrity": "sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==", "dev": true, "license": "MIT", "engines": { @@ -2744,15 +2744,15 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.0.tgz", - "integrity": "sha512-+g5O3j0w2ldzC86Pv6fvbO/xhAonbJFIdf/MKQ1d30gndlsVzUOE83ldfSE15Qrl9fhFjK6AovHs5Wpp6vx86w==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz", + "integrity": "sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0", - "@typescript-eslint/utils": "8.62.0", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/utils": "8.62.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -2787,9 +2787,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.0.tgz", - "integrity": "sha512-KvAclkktORPvM54TgLgA4z9HIV1M8zOgw9ZVNXl9f/8dLYfXYX1wkMXP7qmabpijQRV5bHJLOmoyGQbLMaUYeg==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.62.1.tgz", + "integrity": "sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==", "dev": true, "license": "MIT", "engines": { @@ -2801,16 +2801,16 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.0.tgz", - "integrity": "sha512-+hVbNxtW64pIcZWDPGbyaKF7vp2IBTVY5ma1blwwksrjdsbdqqEKvJWMGbBofei4F6Dovx1M0RJgoFeNu2279A==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz", + "integrity": "sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.62.0", - "@typescript-eslint/tsconfig-utils": "8.62.0", - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/visitor-keys": "8.62.0", + "@typescript-eslint/project-service": "8.62.1", + "@typescript-eslint/tsconfig-utils": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/visitor-keys": "8.62.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -2886,16 +2886,16 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.0.tgz", - "integrity": "sha512-82r66fi9zYwZ+mTq3vKgwjbZ1PVk/DJzrXFLpG6RnBbdvH8TEGVHIs9H4d2drhkOzf0syZuD/OZvvlu6GDbP4g==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.62.1.tgz", + "integrity": "sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.62.0", - "@typescript-eslint/types": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0" + "@typescript-eslint/scope-manager": "8.62.1", + "@typescript-eslint/types": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -2910,13 +2910,13 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.0.tgz", - "integrity": "sha512-CY3uyFSRbcQv3nnSv8S0+lDftMVz6P963PoRlxrV7ew/Md564g9ut60PYzdLM5qW4jFn93GBF+Soi90ISAN+GQ==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz", + "integrity": "sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.62.0", + "@typescript-eslint/types": "8.62.1", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -5125,9 +5125,9 @@ } }, "node_modules/eslint-plugin-import-x": { - "version": "4.17.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.17.0.tgz", - "integrity": "sha512-aM7V25Bg6YuYxtEhwjafzfS0NTMds1D2PMQI0K4KqJxQJRtkP4CO+MQTWRdBq2qAnmPxTxLevhXUBtByxJqS1w==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.17.1.tgz", + "integrity": "sha512-4cdstYkKCyjumM2Q9NSI03K8D2a9F4Ssz33K2lv2hQa4KmR9jPLwk3uWGtNvclfqBrPGfGuMBwsGMbe6dMRbfg==", "dev": true, "license": "MIT", "dependencies": { @@ -6978,9 +6978,9 @@ } }, "node_modules/js-yaml": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.1.0.tgz", - "integrity": "sha512-s8VA5jkR8f22S3NAXmhKPFqGUduqZGlsufabVOgN14iTdw/RXcym7bKkbwjxLK9Yw2lEvvmJjFp119+KPeo8Kg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.2.0.tgz", + "integrity": "sha512-YeLUMlvR4Ou1B119LIaM0r65JvbOBooJDc9yEu0dClb/uSC5P4FrLU8OCCz/HXWvtPoIrR0dRzABTjo1sTN9Bw==", "funding": [ { "type": "github", @@ -7443,9 +7443,9 @@ "license": "MIT" }, "node_modules/nock": { - "version": "14.0.15", - "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.15.tgz", - "integrity": "sha512-S0a47C9pLvcYx/Ugf0H30BVBEcUgMMBDk9VJIDlJ8XGrfH2QDUD4Tgdp45qDIiHttokBG+IbsOtsvIjGR/j3bg==", + "version": "14.0.16", + "resolved": "https://registry.npmjs.org/nock/-/nock-14.0.16.tgz", + "integrity": "sha512-8r4KEc6nT1D/fdLD/R1BO1CPaVEL8o40u/guFRJlXabN7vr3RmMqyjsY5Krt0nMwhsOAwXQ/mtN5vy5Jh3aErg==", "dev": true, "license": "MIT", "dependencies": { @@ -9317,16 +9317,16 @@ } }, "node_modules/typescript-eslint": { - "version": "8.62.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.0.tgz", - "integrity": "sha512-8QxXi+ZACKX0kaqO4gY8kn0RSD9gFfaHDWwjqtEN48aWCBkX4MJaufWN+c3BzlrXLOxfywDL8CaoqUwcRq4j4Q==", + "version": "8.62.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.62.1.tgz", + "integrity": "sha512-vymnnM5g0AKQDSAyfP12nMIBvgwgA42syg74kkuZ4x1VuTzwQKwc5h9rGxeShCjny5o+zWAb6OEoz7XLgrIkIw==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/eslint-plugin": "8.62.0", - "@typescript-eslint/parser": "8.62.0", - "@typescript-eslint/typescript-estree": "8.62.0", - "@typescript-eslint/utils": "8.62.0" + "@typescript-eslint/eslint-plugin": "8.62.1", + "@typescript-eslint/parser": "8.62.1", + "@typescript-eslint/typescript-estree": "8.62.1", + "@typescript-eslint/utils": "8.62.1" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" diff --git a/package.json b/package.json index 46fb37e98..4b60d0dc8 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "follow-redirects": "^1.16.0", "get-folder-size": "^5.0.0", "https-proxy-agent": "^7.0.6", - "js-yaml": "^5.1.0", + "js-yaml": "^5.2.0", "jsonschema": "1.5.0", "long": "^5.3.2", "node-forge": "^1.4.0", @@ -61,15 +61,15 @@ "eslint": "^9.39.4", "eslint-import-resolver-typescript": "^4.4.5", "eslint-plugin-github": "^6.0.0", - "eslint-plugin-import-x": "^4.17.0", + "eslint-plugin-import-x": "^4.17.1", "eslint-plugin-jsdoc": "^62.9.0", "eslint-plugin-no-async-foreach": "^0.1.1", "glob": "^13.0.6", "globals": "^17.7.0", - "nock": "^14.0.15", + "nock": "^14.0.16", "sinon": "^22.0.0", "typescript": "^6.0.3", - "typescript-eslint": "^8.62.0" + "typescript-eslint": "^8.62.1" }, "overrides": { "@actions/tool-cache": { From d8168ab6553574ff9ac06f90714b0325bf5136dc Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 8 Jul 2026 17:57:12 +0000 Subject: [PATCH 06/16] Rebuild --- lib/entry-points.js | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 406916cf6..664f590f7 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -141750,7 +141750,7 @@ var intCoreTag = defineScalarTag("tag:yaml.org,2002:int", { ..."0123456789" ], resolve: resolveYamlInteger$2, - identify: (object) => Object.prototype.toString.call(object) === "[object Number]" && object % 1 === 0 && !Object.is(object, -0), + identify: (object) => Number.isInteger(object) && !Object.is(object, -0) && object.toString(10).indexOf("e") < 0, represent: (object) => object.toString(10) }); var YAML_INTEGER_IMPLICIT_PATTERN = /* @__PURE__ */ new RegExp("^-?(?:0|[1-9][0-9]*)$"); @@ -141778,7 +141778,7 @@ var intJsonTag = defineScalarTag("tag:yaml.org,2002:int", { implicit: true, implicitFirstChars: ["-", ..."0123456789"], resolve: resolveYamlInteger$1, - identify: (object) => Object.prototype.toString.call(object) === "[object Number]" && object % 1 === 0 && !Object.is(object, -0), + identify: (object) => Number.isInteger(object) && !Object.is(object, -0) && object.toString(10).indexOf("e") < 0, represent: (object) => object.toString(10) }); var YAML_INTEGER_PATTERN = /* @__PURE__ */ new RegExp("^(?:[-+]?0b[0-1_]+|[-+]?0[0-7_]+|[-+]?0x[0-9a-fA-F_]+|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+|[-+]?(?:0|[1-9][0-9_]*))$"); @@ -141812,7 +141812,7 @@ var intYaml11Tag = defineScalarTag("tag:yaml.org,2002:int", { ..."0123456789" ], resolve: resolveYamlInteger, - identify: (object) => Object.prototype.toString.call(object) === "[object Number]" && object % 1 === 0 && !Object.is(object, -0), + identify: (object) => Number.isInteger(object) && !Object.is(object, -0) && object.toString(10).indexOf("e") < 0, represent: (object) => object.toString(10) }); var YAML_FLOAT_PATTERN$1 = /* @__PURE__ */ new RegExp("^(?:[-+]?[0-9]+(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?|[-+]?\\.[0-9]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"); @@ -141845,7 +141845,7 @@ var floatCoreTag = defineScalarTag("tag:yaml.org,2002:float", { ..."0123456789" ], resolve: resolveYamlFloat$2, - identify: (object) => Object.prototype.toString.call(object) === "[object Number]" && (object % 1 !== 0 || Object.is(object, -0)), + identify: (object) => typeof object === "number" && (!Number.isInteger(object) || Object.is(object, -0) || object.toString(10).indexOf("e") >= 0), represent: representYamlFloat$2 }); var YAML_FLOAT_IMPLICIT_PATTERN = /* @__PURE__ */ new RegExp("^-?(?:0|[1-9][0-9]*)(?:\\.[0-9]*)?(?:[eE][-+]?[0-9]+)?$"); @@ -141878,7 +141878,7 @@ var floatJsonTag = defineScalarTag("tag:yaml.org,2002:float", { implicit: true, implicitFirstChars: ["-", ..."0123456789"], resolve: resolveYamlFloat$1, - identify: (object) => Object.prototype.toString.call(object) === "[object Number]" && (object % 1 !== 0 || Object.is(object, -0)), + identify: (object) => typeof object === "number" && (!Number.isInteger(object) || Object.is(object, -0) || object.toString(10).indexOf("e") >= 0), represent: representYamlFloat$1 }); var YAML_FLOAT_PATTERN = /* @__PURE__ */ new RegExp("^(?:[-+]?(?:(?:[0-9][0-9_]*)?\\.[0-9_]*)(?:[eE][-+][0-9]+)?|[-+]?[0-9][0-9_]*(?::[0-5]?[0-9])+\\.[0-9_]*|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$"); @@ -141915,7 +141915,7 @@ var floatYaml11Tag = defineScalarTag("tag:yaml.org,2002:float", { ..."0123456789" ], resolve: resolveYamlFloat, - identify: (object) => Object.prototype.toString.call(object) === "[object Number]" && (object % 1 !== 0 || Object.is(object, -0)), + identify: (object) => typeof object === "number" && (!Number.isInteger(object) || Object.is(object, -0) || object.toString(10).indexOf("e") >= 0), represent: representYamlFloat }); var mergeTag = defineScalarTag("tag:yaml.org,2002:merge", { @@ -142614,7 +142614,8 @@ var DEFAULT_CONSTRUCTOR_OPTIONS = { filename: "", schema: CORE_SCHEMA, json: false, - maxMergeSeqLength: 20 + maxTotalMergeKeys: 1e4, + maxAliases: -1 }; function eventPosition$1(event) { if ("tagStart" in event && event.tagStart !== NO_RANGE$2) return event.tagStart; @@ -142702,6 +142703,7 @@ function isMappingTag(tag) { } function mergeKeys(state, frame, source, sourceTag) { for (const sourceKey of sourceTag.keys(source)) { + if (state.maxTotalMergeKeys !== -1 && ++state.totalMergeKeys > state.maxTotalMergeKeys) throwError$1(state, `merge keys exceeded maxTotalMergeKeys (${state.maxTotalMergeKeys})`); if (frame.tag.has(frame.value, sourceKey)) continue; const err = frame.tag.addPair(frame.value, sourceKey, sourceTag.get(source, sourceKey)); if (err) throwError$1(state, err); @@ -142711,14 +142713,8 @@ function mergeKeys(state, frame, source, sourceTag) { function mergeSource(state, frame, source, sourceTag) { state.position = frame.keyPosition; if (isMappingTag(sourceTag)) mergeKeys(state, frame, source, sourceTag); - else if (sourceTag.nodeKind === "sequence" && Array.isArray(source)) { - const seen = /* @__PURE__ */ new Set(); - for (const element of source) { - if (seen.has(element)) continue; - seen.add(element); - mergeKeys(state, frame, element, frame.tag); - } - } else throwError$1(state, "cannot merge mappings; the provided source object is unacceptable"); + else if (sourceTag.nodeKind === "sequence" && Array.isArray(source)) for (const element of source) mergeKeys(state, frame, element, frame.tag); + else throwError$1(state, "cannot merge mappings; the provided source object is unacceptable"); } function addMappingValue(state, frame, key, value, tag) { state.position = frame.keyPosition; @@ -142739,7 +142735,6 @@ function addValue(state, value, tag) { } else if (frame.kind === "sequence") { if (frame.merge) { if (!isMappingTag(tag)) throwError$1(state, "cannot merge mappings; the provided source object is unacceptable"); - if (frame.index >= state.maxMergeSeqLength) throwError$1(state, `merge sequence length exceeded maxMergeSeqLength (${state.maxMergeSeqLength})`); } const err = frame.tag.addItem(frame.value, value, frame.index++); if (err) throwError$1(state, err); @@ -142776,7 +142771,9 @@ function constructFromEvents(events, options) { position: 0, frames: [], anchors: /* @__PURE__ */ new Map(), - tagHandlers: /* @__PURE__ */ Object.create(null) + tagHandlers: /* @__PURE__ */ Object.create(null), + totalMergeKeys: 0, + aliasCount: 0 }; while (state.eventIndex < state.events.length) { const event = state.events[state.eventIndex++]; @@ -142784,6 +142781,7 @@ function constructFromEvents(events, options) { switch (event.type) { case 1: state.anchors = /* @__PURE__ */ new Map(); + state.aliasCount = 0; state.tagHandlers = /* @__PURE__ */ Object.create(null); for (const directive of event.directives) if (directive.kind === "tag") state.tagHandlers[directive.handle] = directive.prefix; state.frames.push({ @@ -142834,6 +142832,7 @@ function constructFromEvents(events, options) { break; } case 5: { + if (state.maxAliases !== -1 && ++state.aliasCount > state.maxAliases) throwError$1(state, `aliases exceeded maxAliases (${state.maxAliases})`); const name = state.source.slice(event.anchorStart, event.anchorEnd); const anchor = state.anchors.get(name); if (!anchor) throwError$1(state, `unidentified alias "${name}"`); @@ -162682,7 +162681,7 @@ tmp/lib/tmp.js: *) js-yaml/dist/js-yaml.mjs: - (*! js-yaml 5.1.0 https://github.com/nodeca/js-yaml @license MIT *) + (*! js-yaml 5.2.0 https://github.com/nodeca/js-yaml @license MIT *) long/index.js: (** From 8d2450759287d43b29b439b77121b516fdc83123 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Mon, 6 Jul 2026 12:55:07 +0100 Subject: [PATCH 07/16] Allow `env` input for relevant functions in `actions-util.ts` --- lib/entry-points.js | 68 ++++++++++++++++++++-------------------- src/actions-util.ts | 76 +++++++++++++++++++++++++-------------------- src/environment.ts | 5 +++ src/util.ts | 1 + 4 files changed, 84 insertions(+), 66 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 406916cf6..e646bc5c4 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -144779,7 +144779,8 @@ function initializeEnvironment(version) { function getEnv(env = process.env) { return { getRequired: (name) => getRequiredEnvVar(env, name), - getOptional: (name) => getOptionalEnvVarFrom(env, name) + getOptional: (name) => getOptionalEnvVarFrom(env, name), + entries: () => Object.entries(env) }; } function getRequiredEnvVar(env, paramName) { @@ -145151,31 +145152,31 @@ var getOptionalInput = function(name) { const value = core3.getInput(name); return value.length > 0 ? value : void 0; }; -function getTemporaryDirectory() { - const value = process.env["CODEQL_ACTION_TEMP"]; - return value !== void 0 && value !== "" ? value : getRequiredEnvParam("RUNNER_TEMP" /* RUNNER_TEMP */); +function getTemporaryDirectory(env = getEnv()) { + const value = env.getOptional("CODEQL_ACTION_TEMP" /* TEMP */); + return value !== void 0 && value !== "" ? value : env.getRequired("RUNNER_TEMP" /* RUNNER_TEMP */); } var PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json"; -function getDiffRangesJsonFilePath() { - return path2.join(getTemporaryDirectory(), PR_DIFF_RANGE_JSON_FILENAME); +function getDiffRangesJsonFilePath(env = getEnv()) { + return path2.join(getTemporaryDirectory(env), PR_DIFF_RANGE_JSON_FILENAME); } function getActionVersion() { return "4.37.1"; } -function getWorkflowEventName() { - return getRequiredEnvParam("GITHUB_EVENT_NAME" /* GITHUB_EVENT_NAME */); +function getWorkflowEventName(env = getEnv()) { + return env.getRequired("GITHUB_EVENT_NAME" /* GITHUB_EVENT_NAME */); } -function isRunningLocalAction() { - const relativeScriptPath = getRelativeScriptPath(); +function isRunningLocalAction(env = getEnv()) { + const relativeScriptPath = getRelativeScriptPath(env); return relativeScriptPath.startsWith("..") || path2.isAbsolute(relativeScriptPath); } -function getRelativeScriptPath() { - const runnerTemp = getRequiredEnvParam("RUNNER_TEMP" /* RUNNER_TEMP */); +function getRelativeScriptPath(env) { + const runnerTemp = env.getRequired("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" /* GITHUB_EVENT_PATH */); +function getWorkflowEvent(env = getEnv()) { + const eventJsonFile = env.getRequired("GITHUB_EVENT_PATH" /* GITHUB_EVENT_PATH */); try { return JSON.parse(fs2.readFileSync(eventJsonFile, "utf-8")); } catch (e) { @@ -145231,8 +145232,8 @@ function getUploadValue(input) { return "always"; } } -function getWorkflowRunID() { - const workflowRunIdString = getRequiredEnvParam("GITHUB_RUN_ID" /* GITHUB_RUN_ID */); +function getWorkflowRunID(env = getEnv()) { + const workflowRunIdString = env.getRequired("GITHUB_RUN_ID" /* GITHUB_RUN_ID */); const workflowRunID = parseInt(workflowRunIdString, 10); if (Number.isNaN(workflowRunID)) { throw new Error( @@ -145246,8 +145247,8 @@ function getWorkflowRunID() { } return workflowRunID; } -function getWorkflowRunAttempt() { - const workflowRunAttemptString = getRequiredEnvParam( +function getWorkflowRunAttempt(env = getEnv()) { + const workflowRunAttemptString = env.getRequired( "GITHUB_RUN_ATTEMPT" /* GITHUB_RUN_ATTEMPT */ ); const workflowRunAttempt = parseInt(workflowRunAttemptString, 10); @@ -145300,14 +145301,14 @@ var getFileType = async (filePath) => { throw e; } }; -function isSelfHostedRunner() { - return process.env.RUNNER_ENVIRONMENT === "self-hosted"; +function isSelfHostedRunner(env = getEnv()) { + return env.getOptional("RUNNER_ENVIRONMENT") === "self-hosted"; } -function isDynamicWorkflow() { - return getWorkflowEventName() === "dynamic"; +function isDynamicWorkflow(env = getEnv()) { + return getWorkflowEventName(env) === "dynamic"; } -function isDefaultSetup() { - return isDynamicWorkflow(); +function isDefaultSetup(env = getEnv()) { + return isDynamicWorkflow(env); } function prettyPrintInvocation(cmd, args) { return [cmd, ...args].map((x) => x.includes(" ") ? `'${x}'` : x).join(" "); @@ -145371,8 +145372,9 @@ async function runTool(cmd, args = [], opts = {}) { return stdout; } var persistedInputsKey = "persisted_inputs"; -var persistInputs = function() { - const inputEnvironmentVariables = Object.entries(process.env).filter( +var persistInputs = function(env = getEnv()) { + const entries = env.entries(); + const inputEnvironmentVariables = entries.filter( ([name]) => name.startsWith("INPUT_") ); core3.saveState(persistedInputsKey, JSON.stringify(inputEnvironmentVariables)); @@ -145385,7 +145387,7 @@ var restoreInputs = function() { } } }; -function getPullRequestBranches() { +function getPullRequestBranches(env = getEnv()) { const pullRequest = github.context.payload.pull_request; if (pullRequest) { return { @@ -145396,8 +145398,8 @@ function getPullRequestBranches() { head: pullRequest.head.label }; } - const codeScanningRef = process.env.CODE_SCANNING_REF; - const codeScanningBaseBranch = process.env.CODE_SCANNING_BASE_BRANCH; + const codeScanningRef = env.getOptional("CODE_SCANNING_REF"); + const codeScanningBaseBranch = env.getOptional("CODE_SCANNING_BASE_BRANCH"); if (codeScanningRef && codeScanningBaseBranch) { return { base: codeScanningBaseBranch, @@ -145408,8 +145410,8 @@ function getPullRequestBranches() { } return void 0; } -function isAnalyzingPullRequest() { - return getPullRequestBranches() !== void 0; +function isAnalyzingPullRequest(env = getEnv()) { + return getPullRequestBranches(env) !== void 0; } var qualityCategoryMapping = { "c#": "csharp", @@ -145421,8 +145423,8 @@ var qualityCategoryMapping = { typescript: "javascript-typescript", kotlin: "java-kotlin" }; -function fixCodeQualityCategory(logger, category) { - if (category !== void 0 && isDefaultSetup() && category.startsWith("/language:")) { +function fixCodeQualityCategory(logger, category, env = getEnv()) { + if (category !== void 0 && isDefaultSetup(env) && category.startsWith("/language:")) { const language = category.substring("/language:".length); const mappedLanguage = qualityCategoryMapping[language]; if (mappedLanguage) { diff --git a/src/actions-util.ts b/src/actions-util.ts index d7fbacbf3..251e804e7 100644 --- a/src/actions-util.ts +++ b/src/actions-util.ts @@ -7,12 +7,13 @@ import * as github from "@actions/github"; import * as io from "@actions/io"; import type { Config } from "./config-utils"; +import { Env, EnvVar } from "./environment"; import { Logger } from "./logging"; import { doesDirectoryExist, getCodeQLDatabasePath, - getRequiredEnvParam, ConfigurationError, + getEnv, } from "./util"; /** @@ -83,17 +84,22 @@ export const getOptionalInput = function (name: string): string | undefined { return value.length > 0 ? value : undefined; }; -export function getTemporaryDirectory(): string { - const value = process.env["CODEQL_ACTION_TEMP"]; +/** + * Gets the temporary directory used by the CodeQL Action. This will either be the temporary + * directory that has been set in `CODEQL_ACTION_TEMP` by e.g. a previous step, or the + * value of `RUNNER_TEMP` otherwise. + */ +export function getTemporaryDirectory(env: Env = getEnv()): string { + const value = env.getOptional(EnvVar.TEMP); return value !== undefined && value !== "" ? value - : getRequiredEnvParam(ActionsEnvVars.RUNNER_TEMP); + : env.getRequired(ActionsEnvVars.RUNNER_TEMP); } const PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json"; -export function getDiffRangesJsonFilePath(): string { - return path.join(getTemporaryDirectory(), PR_DIFF_RANGE_JSON_FILENAME); +export function getDiffRangesJsonFilePath(env: Env = getEnv()): string { + return path.join(getTemporaryDirectory(env), PR_DIFF_RANGE_JSON_FILENAME); } export function getActionVersion(): string { @@ -105,16 +111,16 @@ export function getActionVersion(): string { * * This will be "dynamic" for default setup workflow runs. */ -export function getWorkflowEventName() { - return getRequiredEnvParam(ActionsEnvVars.GITHUB_EVENT_NAME); +export function getWorkflowEventName(env: Env = getEnv()) { + return env.getRequired(ActionsEnvVars.GITHUB_EVENT_NAME); } /** * Returns whether the current workflow is executing a local copy of the Action, e.g. we're running * a workflow on the codeql-action repo itself. */ -export function isRunningLocalAction(): boolean { - const relativeScriptPath = getRelativeScriptPath(); +export function isRunningLocalAction(env: Env = getEnv()): boolean { + const relativeScriptPath = getRelativeScriptPath(env); return ( relativeScriptPath.startsWith("..") || path.isAbsolute(relativeScriptPath) ); @@ -125,15 +131,15 @@ 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(ActionsEnvVars.RUNNER_TEMP); +function getRelativeScriptPath(env: Env): string { + const runnerTemp = env.getRequired(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(ActionsEnvVars.GITHUB_EVENT_PATH); +export function getWorkflowEvent(env: Env = getEnv()): any { + const eventJsonFile = env.getRequired(ActionsEnvVars.GITHUB_EVENT_PATH); try { return JSON.parse(fs.readFileSync(eventJsonFile, "utf-8")); } catch (e) { @@ -202,8 +208,8 @@ export function getUploadValue(input: string | undefined): UploadKind { /** * Get the workflow run ID. */ -export function getWorkflowRunID(): number { - const workflowRunIdString = getRequiredEnvParam(ActionsEnvVars.GITHUB_RUN_ID); +export function getWorkflowRunID(env: Env = getEnv()): number { + const workflowRunIdString = env.getRequired(ActionsEnvVars.GITHUB_RUN_ID); const workflowRunID = parseInt(workflowRunIdString, 10); if (Number.isNaN(workflowRunID)) { throw new Error( @@ -221,8 +227,8 @@ export function getWorkflowRunID(): number { /** * Get the workflow run attempt number. */ -export function getWorkflowRunAttempt(): number { - const workflowRunAttemptString = getRequiredEnvParam( +export function getWorkflowRunAttempt(env: Env = getEnv()): number { + const workflowRunAttemptString = env.getRequired( ActionsEnvVars.GITHUB_RUN_ATTEMPT, ); const workflowRunAttempt = parseInt(workflowRunAttemptString, 10); @@ -290,18 +296,18 @@ export const getFileType = async (filePath: string): Promise => { } }; -export function isSelfHostedRunner() { - return process.env.RUNNER_ENVIRONMENT === "self-hosted"; +export function isSelfHostedRunner(env: Env = getEnv()) { + return env.getOptional("RUNNER_ENVIRONMENT") === "self-hosted"; } /** Determines whether the workflow trigger is `dynamic`. */ -export function isDynamicWorkflow(): boolean { - return getWorkflowEventName() === "dynamic"; +export function isDynamicWorkflow(env: Env = getEnv()): boolean { + return getWorkflowEventName(env) === "dynamic"; } /** Determines whether we are running in default setup. */ -export function isDefaultSetup(): boolean { - return isDynamicWorkflow(); +export function isDefaultSetup(env: Env = getEnv()): boolean { + return isDynamicWorkflow(env); } export function prettyPrintInvocation(cmd: string, args: string[]): string { @@ -399,9 +405,10 @@ const persistedInputsKey = "persisted_inputs"; * This would be simplified if actions/runner#3514 is addressed. * https://github.com/actions/runner/issues/3514 */ -export const persistInputs = function () { - const inputEnvironmentVariables = Object.entries(process.env).filter( - ([name]) => name.startsWith("INPUT_"), +export const persistInputs = function (env: Env = getEnv()) { + const entries = env.entries(); + const inputEnvironmentVariables = entries.filter(([name]) => + name.startsWith("INPUT_"), ); core.saveState(persistedInputsKey, JSON.stringify(inputEnvironmentVariables)); }; @@ -429,7 +436,9 @@ export interface PullRequestBranches { * @returns the base and head branches of the pull request, or undefined if * we are not analyzing a pull request. */ -export function getPullRequestBranches(): PullRequestBranches | undefined { +export function getPullRequestBranches( + env: Env = getEnv(), +): PullRequestBranches | undefined { const pullRequest = github.context.payload.pull_request; if (pullRequest) { return { @@ -443,8 +452,8 @@ export function getPullRequestBranches(): PullRequestBranches | undefined { // PR analysis under Default Setup does not have the pull_request context, // but it should set CODE_SCANNING_REF and CODE_SCANNING_BASE_BRANCH. - const codeScanningRef = process.env.CODE_SCANNING_REF; - const codeScanningBaseBranch = process.env.CODE_SCANNING_BASE_BRANCH; + const codeScanningRef = env.getOptional("CODE_SCANNING_REF"); + const codeScanningBaseBranch = env.getOptional("CODE_SCANNING_BASE_BRANCH"); if (codeScanningRef && codeScanningBaseBranch) { return { base: codeScanningBaseBranch, @@ -459,8 +468,8 @@ export function getPullRequestBranches(): PullRequestBranches | undefined { /** * Returns whether we are analyzing a pull request. */ -export function isAnalyzingPullRequest(): boolean { - return getPullRequestBranches() !== undefined; +export function isAnalyzingPullRequest(env: Env = getEnv()): boolean { + return getPullRequestBranches(env) !== undefined; } /** @@ -484,13 +493,14 @@ const qualityCategoryMapping: Record = { export function fixCodeQualityCategory( logger: Logger, category?: string, + env: Env = getEnv(), ): string | undefined { // The `category` should always be set by Default Setup. We perform this check // to avoid potential issues if Code Quality supports Advanced Setup in the future // and before this workaround is removed. if ( category !== undefined && - isDefaultSetup() && + isDefaultSetup(env) && category.startsWith("/language:") ) { const language = category.substring("/language:".length); diff --git a/src/environment.ts b/src/environment.ts index c0ca050b0..9912f0382 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -83,6 +83,9 @@ export enum EnvVar { /** Whether to suppress the warning if the current CLI will soon be unsupported. */ SUPPRESS_DEPRECATED_SOON_WARNING = "CODEQL_ACTION_SUPPRESS_DEPRECATED_SOON_WARNING", + /** Used to dictate or persist the temporary directory used by the CodeQL Action. */ + TEMP = "CODEQL_ACTION_TEMP", + /** Whether to disable uploading SARIF results or status reports to the GitHub API */ TEST_MODE = "CODEQL_ACTION_TEST_MODE", @@ -167,4 +170,6 @@ export interface Env { getRequired(name: string): string; /** Gets the value for `name`, or `undefined` if it isn't set or empty. */ getOptional(name: string): string | undefined; + /** Gets the entries of the underlying `ProcessEnv`. */ + entries(): Array<[string, string | undefined]>; } diff --git a/src/util.ts b/src/util.ts index 7f5245660..1e79382f6 100644 --- a/src/util.ts +++ b/src/util.ts @@ -571,6 +571,7 @@ export function getEnv(env: NodeJS.ProcessEnv = process.env): Env { return { getRequired: (name) => getRequiredEnvVar(env, name), getOptional: (name) => getOptionalEnvVarFrom(env, name), + entries: () => Object.entries(env), }; } From 4c868b3e7e64e90d5dd85207c9a6412d99199b72 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Mon, 6 Jul 2026 13:06:23 +0100 Subject: [PATCH 08/16] Allow setting environment variables --- src/environment.ts | 2 ++ src/testing-utils.ts | 12 ++++++++++-- src/util.ts | 3 +++ 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/environment.ts b/src/environment.ts index 9912f0382..03d4870be 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -172,4 +172,6 @@ export interface Env { getOptional(name: string): string | undefined; /** Gets the entries of the underlying `ProcessEnv`. */ entries(): Array<[string, string | undefined]>; + /** Sets an environment variable. */ + set(name: string, value: string): void; } diff --git a/src/testing-utils.ts b/src/testing-utils.ts index 748ce40ea..c6ff0dbda 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -331,11 +331,19 @@ export type ActionVarOverrides = Partial< * excluding some that are expected to be set to paths. See `setupActionsVars`. * * @param overrides Overrides for the defaults. + * @param env The environment to set the variables for. */ -export function setupBaseActionsVars(overrides?: ActionVarOverrides) { +export function setupBaseActionsVars( + overrides?: ActionVarOverrides, + env?: Env, +) { const vars = { ...DEFAULT_ACTIONS_VARS, ...overrides }; for (const [key, value] of Object.entries(vars)) { - process.env[key] = value; + if (env) { + env.set(key, value); + } else { + process.env[key] = value; + } } } diff --git a/src/util.ts b/src/util.ts index 1e79382f6..36f0ce04b 100644 --- a/src/util.ts +++ b/src/util.ts @@ -572,6 +572,9 @@ export function getEnv(env: NodeJS.ProcessEnv = process.env): Env { getRequired: (name) => getRequiredEnvVar(env, name), getOptional: (name) => getOptionalEnvVarFrom(env, name), entries: () => Object.entries(env), + set: (name, value) => { + env[name] = value; + }, }; } From 1d0e1b20e5f0238c48d4a2bdb81a7e28cffd40e2 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 12:20:20 +0100 Subject: [PATCH 09/16] Move env var getters out of `util.ts` --- lib/entry-points.js | 59 ++++++++++++++++++++++++--------------------- src/environment.ts | 54 +++++++++++++++++++++++++++++++++++++++++ src/util.ts | 59 +++------------------------------------------ 3 files changed, 90 insertions(+), 82 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index e646bc5c4..705ce3f33 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -141462,6 +141462,38 @@ var toolrunner = __toESM(require_toolrunner()); var github = __toESM(require_github()); var io2 = __toESM(require_io()); +// src/environment.ts +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 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); +} +function getEnv(env = process.env) { + return { + getRequired: (name) => getRequiredEnvVar(env, name), + getOptional: (name) => getOptionalEnvVarFrom(env, name), + entries: () => Object.entries(env), + set: (name, value) => { + env[name] = value; + } + }; +} + // src/util.ts var fs = __toESM(require("fs")); var fsPromises = __toESM(require("fs/promises")); @@ -144776,33 +144808,6 @@ function initializeEnvironment(version) { core2.exportVariable("CODEQL_ACTION_FEATURE_WILL_UPLOAD" /* FEATURE_WILL_UPLOAD */, "true"); core2.exportVariable("CODEQL_ACTION_VERSION" /* VERSION */, version); } -function getEnv(env = process.env) { - return { - getRequired: (name) => getRequiredEnvVar(env, name), - getOptional: (name) => getOptionalEnvVarFrom(env, name), - entries: () => Object.entries(env) - }; -} -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 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) { diff --git a/src/environment.ts b/src/environment.ts index 03d4870be..e2cfe49e8 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -164,6 +164,60 @@ export enum EnvVar { RISK_ASSESSMENT_ID = "CODEQL_ACTION_RISK_ASSESSMENT_ID", } +/** + * Gets an environment variable, but throws an error if it is not set. + */ +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`); + } + return value; +} + +/** + * Get an environment parameter, but throw an error if it is not set. + */ +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); +} + +/** 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), + entries: () => Object.entries(env), + set: (name, value) => { + env[name] = value; + }, + }; +} + /** 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. */ diff --git a/src/util.ts b/src/util.ts index 36f0ce04b..b7d27afae 100644 --- a/src/util.ts +++ b/src/util.ts @@ -13,11 +13,14 @@ 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 { Env, EnvVar } from "./environment"; +import { EnvVar, getRequiredEnvParam } from "./environment"; import * as json from "./json"; import { Language } from "./languages"; import { Logger } from "./logging"; +// Re-export for backwards compatibility to avoid updating a lot of imports elsewhere. +export { getRequiredEnvParam, getOptionalEnvVar, getEnv } from "./environment"; + /** * The name of the file containing the base database OIDs, as stored in the * root of the database location. @@ -566,60 +569,6 @@ 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), - entries: () => Object.entries(env), - set: (name, value) => { - env[name] = value; - }, - }; -} - -/** - * Gets an environment variable, but throws an error if it is not set. - */ -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`); - } - return value; -} - -/** - * Get an environment parameter, but throw an error if it is not set. - */ -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; From 732911a2faf94a456db7b30e7d7d298ec0d6fee1 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 12:38:40 +0100 Subject: [PATCH 10/16] Turn `Env` into a class, and add `ReadOnlyEnv` --- lib/entry-points.js | 43 ++++++++++++++++++-------- src/api-client.test.ts | 23 +++++++------- src/api-client.ts | 12 ++++---- src/environment.ts | 68 +++++++++++++++++++++++++++--------------- 4 files changed, 93 insertions(+), 53 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 705ce3f33..c4bf3a3bd 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -141483,15 +141483,32 @@ function getOptionalEnvVarFrom(env, paramName) { function getOptionalEnvVar(paramName) { return getOptionalEnvVarFrom(process.env, paramName); } +var ReadOnlyEnv = class { + constructor(vars) { + this.vars = vars; + } + vars; + /** Tries to get the value for `name` and throws if there isn't one. */ + getRequired(name) { + return getRequiredEnvVar(this.vars, name); + } + /** Gets the value for `name`, or `undefined` if it isn't set or empty. */ + getOptional(name) { + return getOptionalEnvVarFrom(this.vars, name); + } + /** Gets the entries of the underlying `ProcessEnv`. */ + entries() { + return Object.entries(this.vars); + } +}; +var Env = class extends ReadOnlyEnv { + /** Sets an environment variable. */ + set(name, value) { + this.vars[name] = value; + } +}; function getEnv(env = process.env) { - return { - getRequired: (name) => getRequiredEnvVar(env, name), - getOptional: (name) => getOptionalEnvVarFrom(env, name), - entries: () => Object.entries(env), - set: (name, value) => { - env[name] = value; - } - }; + return new Env(env); } // src/util.ts @@ -145613,15 +145630,15 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {}) }) ); } -function getApiDetails() { +function getApiDetails(env = getEnv()) { return { auth: getRequiredInput("token"), - url: getRequiredEnvParam("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */), - apiURL: getRequiredEnvParam("GITHUB_API_URL" /* GITHUB_API_URL */) + url: env.getRequired("GITHUB_SERVER_URL" /* GITHUB_SERVER_URL */), + apiURL: env.getRequired("GITHUB_API_URL" /* GITHUB_API_URL */) }; } -function getApiClient() { - return createApiClientWithDetails(getApiDetails()); +function getApiClient(env = getEnv()) { + return createApiClientWithDetails(getApiDetails(env)); } function getApiClientWithExternalAuth(apiDetails) { return createApiClientWithDetails(apiDetails, { allowExternal: true }); diff --git a/src/api-client.test.ts b/src/api-client.test.ts index 29cad338f..affb5b894 100644 --- a/src/api-client.test.ts +++ b/src/api-client.test.ts @@ -6,7 +6,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import * as api from "./api-client"; import { DO_NOT_RETRY_STATUSES } from "./api-client"; -import { setupTests } from "./testing-utils"; +import { getTestEnv, setupTests } from "./testing-utils"; import * as util from "./util"; setupTests(test); @@ -20,16 +20,19 @@ test.serial("getApiClient", async (t) => { const githubStub: sinon.SinonStub = sinon.stub(); pluginStub.returns(githubStub); - sinon.stub(actionsUtil, "getRequiredInput").withArgs("token").returns("xyz"); - const requiredEnvParamStub = sinon.stub(util, "getRequiredEnvParam"); - requiredEnvParamStub - .withArgs("GITHUB_SERVER_URL") - .returns("http://github.localhost"); - requiredEnvParamStub - .withArgs("GITHUB_API_URL") - .returns("http://api.github.localhost"); + const env = getTestEnv(); + env.set( + actionsUtil.ActionsEnvVars.GITHUB_SERVER_URL, + "http://github.localhost", + ); + env.set( + actionsUtil.ActionsEnvVars.GITHUB_API_URL, + "http://api.github.localhost", + ); - api.getApiClient(); + sinon.stub(actionsUtil, "getRequiredInput").withArgs("token").returns("xyz"); + + api.getApiClient(env); t.assert( githubStub.calledOnceWithExactly({ diff --git a/src/api-client.ts b/src/api-client.ts index 16e4082e9..a4a80cd48 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -7,7 +7,7 @@ import { getActionVersion, getRequiredInput, } from "./actions-util"; -import { EnvVar } from "./environment"; +import { EnvVar, ReadOnlyEnv, getEnv } from "./environment"; import { Logger } from "./logging"; import { getRepositoryNwo, RepositoryNwo } from "./repository"; import { @@ -71,16 +71,16 @@ function createApiClientWithDetails( ); } -export function getApiDetails(): GitHubApiDetails { +export function getApiDetails(env: ReadOnlyEnv = getEnv()): GitHubApiDetails { return { auth: getRequiredInput("token"), - url: getRequiredEnvParam(ActionsEnvVars.GITHUB_SERVER_URL), - apiURL: getRequiredEnvParam(ActionsEnvVars.GITHUB_API_URL), + url: env.getRequired(ActionsEnvVars.GITHUB_SERVER_URL), + apiURL: env.getRequired(ActionsEnvVars.GITHUB_API_URL), }; } -export function getApiClient() { - return createApiClientWithDetails(getApiDetails()); +export function getApiClient(env: ReadOnlyEnv = getEnv()) { + return createApiClientWithDetails(getApiDetails(env)); } export function getApiClientWithExternalAuth( diff --git a/src/environment.ts b/src/environment.ts index e2cfe49e8..8240ee451 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -167,10 +167,7 @@ export enum EnvVar { /** * Gets an environment variable, but throws an error if it is not set. */ -export function getRequiredEnvVar( - env: NodeJS.ProcessEnv, - paramName: string, -): string { +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`); @@ -180,6 +177,8 @@ export function getRequiredEnvVar( /** * Get an environment parameter, but throw an error if it is not set. + * + * @deprecated Use `getRequired` of a `ReadOnlyEnv` or `Env` instance instead. */ export function getRequiredEnvParam(paramName: string): string { return getRequiredEnvVar(process.env, paramName); @@ -188,7 +187,7 @@ export function getRequiredEnvParam(paramName: string): string { /** * Gets an environment variable, but returns `undefined` if it is not set or empty. */ -export function getOptionalEnvVarFrom( +function getOptionalEnvVarFrom( env: NodeJS.ProcessEnv, paramName: string, ): string | undefined { @@ -201,31 +200,52 @@ export function getOptionalEnvVarFrom( /** * Get an environment variable, but return `undefined` if it is not set or empty. + * + * @deprecated Use `getOptional` of a `ReadOnlyEnv` or `Env` instance instead. */ export function getOptionalEnvVar(paramName: string): string | undefined { return getOptionalEnvVarFrom(process.env, paramName); } -/** 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), - entries: () => Object.entries(env), - set: (name, value) => { - env[name] = value; - }, - }; +/** + * An abstraction around read-only environment variables, to allow abstracting away from `process.env` + * in tests, while clearly signalling in regular code that the consumer of the `ReadOnlyEnv` instance + * will only read from it. + */ +export class ReadOnlyEnv { + constructor(protected readonly vars: Record) {} + + /** Tries to get the value for `name` and throws if there isn't one. */ + public getRequired(name: string): string { + return getRequiredEnvVar(this.vars, name); + } + + /** Gets the value for `name`, or `undefined` if it isn't set or empty. */ + public getOptional(name: string): string | undefined { + return getOptionalEnvVarFrom(this.vars, name); + } + + /** Gets the entries of the underlying `ProcessEnv`. */ + public entries(): Array<[string, T]> { + return Object.entries(this.vars); + } } -/** 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; - /** Gets the entries of the underlying `ProcessEnv`. */ - entries(): Array<[string, string | undefined]>; +/** + * A wrapper around an environment, to allow abstracting away from `process.env` in tests. + * Use `ReadOnlyEnv` instead if you only plan to read from the environment. + * This type allows writing to the environment. + */ +export class Env< + T extends string | undefined = string | undefined, +> extends ReadOnlyEnv { /** Sets an environment variable. */ - set(name: string, value: string): void; + public set(name: string, value: T): void { + this.vars[name] = value; + } +} + +/** Gets an `Env` instance for `env`, which is `process.env` by default. */ +export function getEnv(env: NodeJS.ProcessEnv = process.env): Env { + return new Env(env); } From be67a7be936375235abfe084bfe0bf4a1bd493f8 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 12:41:31 +0100 Subject: [PATCH 11/16] Add `hasChanged` method to `Env` --- lib/entry-points.js | 6 ++++++ src/environment.ts | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/lib/entry-points.js b/lib/entry-points.js index c4bf3a3bd..a84f452be 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -141502,9 +141502,15 @@ var ReadOnlyEnv = class { } }; var Env = class extends ReadOnlyEnv { + changed = false; /** Sets an environment variable. */ set(name, value) { this.vars[name] = value; + this.changed = true; + } + /** Gets a value indicating whether `set` was called at least once. */ + hasChanged() { + return this.changed; } }; function getEnv(env = process.env) { diff --git a/src/environment.ts b/src/environment.ts index 8240ee451..7bda149d5 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -239,9 +239,17 @@ export class ReadOnlyEnv { export class Env< T extends string | undefined = string | undefined, > extends ReadOnlyEnv { + private changed: boolean = false; + /** Sets an environment variable. */ public set(name: string, value: T): void { this.vars[name] = value; + this.changed = true; + } + + /** Gets a value indicating whether `set` was called at least once. */ + public hasChanged(): boolean { + return this.changed; } } From a440e35edaa7da26a99db2a8962be7a7db10153c Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 12:48:49 +0100 Subject: [PATCH 12/16] Move `ActionsEnvVars` to `environment.ts` --- src/actions-util.ts | 24 +----------------------- src/api-client.test.ts | 11 +++-------- src/api-client.ts | 8 ++------ src/config/remote-file.test.ts | 2 +- src/config/remote-file.ts | 3 +-- src/environment.ts | 25 +++++++++++++++++++++++++ src/testing-utils.ts | 4 ++-- 7 files changed, 35 insertions(+), 42 deletions(-) diff --git a/src/actions-util.ts b/src/actions-util.ts index 251e804e7..9782bfb5e 100644 --- a/src/actions-util.ts +++ b/src/actions-util.ts @@ -7,7 +7,7 @@ import * as github from "@actions/github"; import * as io from "@actions/io"; import type { Config } from "./config-utils"; -import { Env, EnvVar } from "./environment"; +import { Env, EnvVar, ActionsEnvVars } from "./environment"; import { Logger } from "./logging"; import { doesDirectoryExist, @@ -22,28 +22,6 @@ 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. diff --git a/src/api-client.test.ts b/src/api-client.test.ts index affb5b894..34a72f14e 100644 --- a/src/api-client.test.ts +++ b/src/api-client.test.ts @@ -6,6 +6,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import * as api from "./api-client"; import { DO_NOT_RETRY_STATUSES } from "./api-client"; +import { ActionsEnvVars } from "./environment"; import { getTestEnv, setupTests } from "./testing-utils"; import * as util from "./util"; @@ -21,14 +22,8 @@ test.serial("getApiClient", async (t) => { pluginStub.returns(githubStub); const env = getTestEnv(); - env.set( - actionsUtil.ActionsEnvVars.GITHUB_SERVER_URL, - "http://github.localhost", - ); - env.set( - actionsUtil.ActionsEnvVars.GITHUB_API_URL, - "http://api.github.localhost", - ); + env.set(ActionsEnvVars.GITHUB_SERVER_URL, "http://github.localhost"); + env.set(ActionsEnvVars.GITHUB_API_URL, "http://api.github.localhost"); sinon.stub(actionsUtil, "getRequiredInput").withArgs("token").returns("xyz"); diff --git a/src/api-client.ts b/src/api-client.ts index a4a80cd48..eafac7ec7 100644 --- a/src/api-client.ts +++ b/src/api-client.ts @@ -2,12 +2,8 @@ import * as core from "@actions/core"; import * as githubUtils from "@actions/github/lib/utils"; import * as retry from "@octokit/plugin-retry"; -import { - ActionsEnvVars, - getActionVersion, - getRequiredInput, -} from "./actions-util"; -import { EnvVar, ReadOnlyEnv, getEnv } from "./environment"; +import { getActionVersion, getRequiredInput } from "./actions-util"; +import { EnvVar, ReadOnlyEnv, ActionsEnvVars, getEnv } from "./environment"; import { Logger } from "./logging"; import { getRepositoryNwo, RepositoryNwo } from "./repository"; import { diff --git a/src/config/remote-file.test.ts b/src/config/remote-file.test.ts index c36637029..ac1492d90 100644 --- a/src/config/remote-file.test.ts +++ b/src/config/remote-file.test.ts @@ -1,7 +1,7 @@ import test from "ava"; import sinon from "sinon"; -import { ActionsEnvVars } from "../actions-util"; +import { ActionsEnvVars } from "../environment"; import * as errors from "../error-messages"; import { Feature } from "../feature-flags"; import { callee, getTestEnv } from "../testing-utils"; diff --git a/src/config/remote-file.ts b/src/config/remote-file.ts index 15990ed23..15b34af2b 100644 --- a/src/config/remote-file.ts +++ b/src/config/remote-file.ts @@ -1,6 +1,5 @@ import { ActionState } from "../action-common"; -import { ActionsEnvVars } from "../actions-util"; -import { Env } from "../environment"; +import { Env, ActionsEnvVars } from "../environment"; import * as errorMessages from "../error-messages"; import { Feature } from "../feature-flags"; import { ConfigurationError, Failure, Result, Success } from "../util"; diff --git a/src/environment.ts b/src/environment.ts index 7bda149d5..663a6396d 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -164,6 +164,31 @@ export enum EnvVar { RISK_ASSESSMENT_ID = "CODEQL_ACTION_RISK_ASSESSMENT_ID", } +/** + * 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", +} + +/** A type representing all known environment variables. */ +export type KnownEnvVar = EnvVar | ActionsEnvVars; + /** * Gets an environment variable, but throws an error if it is not set. */ diff --git a/src/testing-utils.ts b/src/testing-utils.ts index c6ff0dbda..e78d6a616 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -11,7 +11,7 @@ import nock from "nock"; import * as sinon from "sinon"; import { ActionState, StateFeature } from "./action-common"; -import { ActionsEnv, ActionsEnvVars, getActionVersion } from "./actions-util"; +import { ActionsEnv, getActionVersion } from "./actions-util"; import { AnalysisKind } from "./analyses"; import * as apiClient from "./api-client"; import { GitHubApiDetails } from "./api-client"; @@ -19,7 +19,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 { Env, ActionsEnvVars } from "./environment"; import { CodeQLDefaultVersionInfo, Feature, From 80dcb7ccdf33e958fc80b56bab2efeeef1133ddc Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 14:31:08 +0100 Subject: [PATCH 13/16] Add `RUNNER_ENVIRONMENT` to `ActionsEnvVars` --- lib/entry-points.js | 4 ++-- src/actions-util.ts | 2 +- src/autobuild.ts | 4 ++-- src/environment.ts | 1 + src/init.test.ts | 3 ++- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index a84f452be..19e45627c 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -145330,7 +145330,7 @@ var getFileType = async (filePath) => { } }; function isSelfHostedRunner(env = getEnv()) { - return env.getOptional("RUNNER_ENVIRONMENT") === "self-hosted"; + return env.getOptional("RUNNER_ENVIRONMENT" /* RUNNER_ENVIRONMENT */) === "self-hosted"; } function isDynamicWorkflow(env = getEnv()) { return getWorkflowEventName(env) === "dynamic"; @@ -151679,7 +151679,7 @@ async function setupCppAutobuild(codeql, logger) { logger ); if (await features.getValue("cpp_dependency_installation_enabled" /* CppDependencyInstallation */, codeql)) { - if (process.env["RUNNER_ENVIRONMENT"] === "self-hosted" && process.env[envVar] !== "true") { + if (process.env["RUNNER_ENVIRONMENT" /* RUNNER_ENVIRONMENT */] === "self-hosted" && process.env[envVar] !== "true") { logger.info( `Disabling ${featureName} as we are on a self-hosted runner.${getWorkflowEventName() !== "dynamic" ? ` To override this, set the ${envVar} environment variable to 'true' in your workflow. See ${"https://docs.github.com/en/actions/learn-github-actions/variables#defining-environment-variables-for-a-single-workflow" /* DEFINE_ENV_VARIABLES */} for more information.` : ""}` ); diff --git a/src/actions-util.ts b/src/actions-util.ts index 9782bfb5e..12af438fb 100644 --- a/src/actions-util.ts +++ b/src/actions-util.ts @@ -275,7 +275,7 @@ export const getFileType = async (filePath: string): Promise => { }; export function isSelfHostedRunner(env: Env = getEnv()) { - return env.getOptional("RUNNER_ENVIRONMENT") === "self-hosted"; + return env.getOptional(ActionsEnvVars.RUNNER_ENVIRONMENT) === "self-hosted"; } /** Determines whether the workflow trigger is `dynamic`. */ diff --git a/src/autobuild.ts b/src/autobuild.ts index fc4983f4e..7ec6ba987 100644 --- a/src/autobuild.ts +++ b/src/autobuild.ts @@ -5,7 +5,7 @@ import { getGitHubVersion } from "./api-client"; import { CodeQL, getCodeQL } from "./codeql"; import * as configUtils from "./config-utils"; import { DocUrl } from "./doc-url"; -import { EnvVar } from "./environment"; +import { ActionsEnvVars, EnvVar } from "./environment"; import { Feature, featureConfig, initFeatures } from "./feature-flags"; import { BuiltInLanguage, Language } from "./languages"; import { Logger } from "./logging"; @@ -126,7 +126,7 @@ export async function setupCppAutobuild(codeql: CodeQL, logger: Logger) { if (await features.getValue(Feature.CppDependencyInstallation, codeql)) { // disable autoinstall on self-hosted runners unless explicitly requested if ( - process.env["RUNNER_ENVIRONMENT"] === "self-hosted" && + process.env[ActionsEnvVars.RUNNER_ENVIRONMENT] === "self-hosted" && process.env[envVar] !== "true" ) { logger.info( diff --git a/src/environment.ts b/src/environment.ts index 663a6396d..7b007d652 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -181,6 +181,7 @@ export enum ActionsEnvVars { GITHUB_SERVER_URL = "GITHUB_SERVER_URL", GITHUB_SHA = "GITHUB_SHA", GITHUB_WORKFLOW = "GITHUB_WORKFLOW", + RUNNER_ENVIRONMENT = "RUNNER_ENVIRONMENT", RUNNER_NAME = "RUNNER_NAME", RUNNER_OS = "RUNNER_OS", RUNNER_TEMP = "RUNNER_TEMP", diff --git a/src/init.test.ts b/src/init.test.ts index 88ad0c9b1..1f0d2c701 100644 --- a/src/init.test.ts +++ b/src/init.test.ts @@ -8,6 +8,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import { createStubCodeQL } from "./codeql"; +import { ActionsEnvVars } from "./environment"; import { Feature } from "./feature-flags"; import { checkPacksForOverlayCompatibility, @@ -84,7 +85,7 @@ for (const { runnerEnv, ErrorConstructor, message } of [ `cleanupDatabaseClusterDirectory throws a ${ErrorConstructor.name} when cleanup fails on ${runnerEnv} runner`, async (t) => { await withTmpDir(async (tmpDir: string) => { - process.env["RUNNER_ENVIRONMENT"] = runnerEnv; + process.env[ActionsEnvVars.RUNNER_ENVIRONMENT] = runnerEnv; const dbLocation = path.resolve(tmpDir, "dbs"); fs.mkdirSync(dbLocation, { recursive: true }); From 3f2a29899f809e77bc387c986dd9410c09ec426e Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 14:33:36 +0100 Subject: [PATCH 14/16] Default to `getEnv` in `setupBaseActionsVars` --- src/testing-utils.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/testing-utils.ts b/src/testing-utils.ts index e78d6a616..ec518853f 100644 --- a/src/testing-utils.ts +++ b/src/testing-utils.ts @@ -335,15 +335,11 @@ export type ActionVarOverrides = Partial< */ export function setupBaseActionsVars( overrides?: ActionVarOverrides, - env?: Env, + env: Env = getEnv(), ) { const vars = { ...DEFAULT_ACTIONS_VARS, ...overrides }; for (const [key, value] of Object.entries(vars)) { - if (env) { - env.set(key, value); - } else { - process.env[key] = value; - } + env.set(key, value); } } From 97b52d19da4858e08d9ab458078e9fdc27f2e15c Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 14:41:56 +0100 Subject: [PATCH 15/16] Simplify `getTemporaryDirectory` --- lib/entry-points.js | 3 +-- src/actions-util.ts | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 19e45627c..7cbac6160 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -145181,8 +145181,7 @@ var getOptionalInput = function(name) { return value.length > 0 ? value : void 0; }; function getTemporaryDirectory(env = getEnv()) { - const value = env.getOptional("CODEQL_ACTION_TEMP" /* TEMP */); - return value !== void 0 && value !== "" ? value : env.getRequired("RUNNER_TEMP" /* RUNNER_TEMP */); + return env.getOptional("CODEQL_ACTION_TEMP" /* TEMP */) ?? env.getRequired("RUNNER_TEMP" /* RUNNER_TEMP */); } var PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json"; function getDiffRangesJsonFilePath(env = getEnv()) { diff --git a/src/actions-util.ts b/src/actions-util.ts index 12af438fb..52340c06b 100644 --- a/src/actions-util.ts +++ b/src/actions-util.ts @@ -68,10 +68,9 @@ export const getOptionalInput = function (name: string): string | undefined { * value of `RUNNER_TEMP` otherwise. */ export function getTemporaryDirectory(env: Env = getEnv()): string { - const value = env.getOptional(EnvVar.TEMP); - return value !== undefined && value !== "" - ? value - : env.getRequired(ActionsEnvVars.RUNNER_TEMP); + return ( + env.getOptional(EnvVar.TEMP) ?? env.getRequired(ActionsEnvVars.RUNNER_TEMP) + ); } const PR_DIFF_RANGE_JSON_FILENAME = "pr-diff-range.json"; From 4b164dbc174df46e004e3284afa05e569e8b9134 Mon Sep 17 00:00:00 2001 From: "Michael B. Gale" Date: Thu, 9 Jul 2026 14:47:32 +0100 Subject: [PATCH 16/16] Add `CODE_SCANNING_*` vars to `EnvVar` enum --- lib/entry-points.js | 6 ++++-- src/actions-util.ts | 6 ++++-- src/environment.ts | 12 ++++++++++++ src/setup-codeql.test.ts | 5 +++-- 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/lib/entry-points.js b/lib/entry-points.js index 7cbac6160..e89711f22 100644 --- a/lib/entry-points.js +++ b/lib/entry-points.js @@ -145425,8 +145425,10 @@ function getPullRequestBranches(env = getEnv()) { head: pullRequest.head.label }; } - const codeScanningRef = env.getOptional("CODE_SCANNING_REF"); - const codeScanningBaseBranch = env.getOptional("CODE_SCANNING_BASE_BRANCH"); + const codeScanningRef = env.getOptional("CODE_SCANNING_REF" /* CODE_SCANNING_REF */); + const codeScanningBaseBranch = env.getOptional( + "CODE_SCANNING_BASE_BRANCH" /* CODE_SCANNING_BASE_BRANCH */ + ); if (codeScanningRef && codeScanningBaseBranch) { return { base: codeScanningBaseBranch, diff --git a/src/actions-util.ts b/src/actions-util.ts index 52340c06b..5fd1ebc4f 100644 --- a/src/actions-util.ts +++ b/src/actions-util.ts @@ -429,8 +429,10 @@ export function getPullRequestBranches( // PR analysis under Default Setup does not have the pull_request context, // but it should set CODE_SCANNING_REF and CODE_SCANNING_BASE_BRANCH. - const codeScanningRef = env.getOptional("CODE_SCANNING_REF"); - const codeScanningBaseBranch = env.getOptional("CODE_SCANNING_BASE_BRANCH"); + const codeScanningRef = env.getOptional(EnvVar.CODE_SCANNING_REF); + const codeScanningBaseBranch = env.getOptional( + EnvVar.CODE_SCANNING_BASE_BRANCH, + ); if (codeScanningRef && codeScanningBaseBranch) { return { base: codeScanningBaseBranch, diff --git a/src/environment.ts b/src/environment.ts index 7b007d652..6ea0e87e4 100644 --- a/src/environment.ts +++ b/src/environment.ts @@ -17,6 +17,18 @@ export enum EnvVar { */ CLI_VERBOSITY = "CODEQL_VERBOSITY", + /** + * Set by Default Setup to the base branch of the PR being analysed, if analysing a PR. + * This is needed because the `pull_request` context is not available for `dynamic` events. + */ + CODE_SCANNING_BASE_BRANCH = "CODE_SCANNING_BASE_BRANCH", + + /** + * Set by Default Setup to the full ref being analysed, if analysing a PR. + * This is needed because the `pull_request` context is not available for `dynamic` events. + */ + CODE_SCANNING_REF = "CODE_SCANNING_REF", + /** * `PersistedVersionInfo` for the CodeQL CLI, so later Actions steps can reuse it instead of * invoking `codeql version` again. diff --git a/src/setup-codeql.test.ts b/src/setup-codeql.test.ts index 49d4d66aa..f2ba43c10 100644 --- a/src/setup-codeql.test.ts +++ b/src/setup-codeql.test.ts @@ -7,6 +7,7 @@ import * as sinon from "sinon"; import * as actionsUtil from "./actions-util"; import * as api from "./api-client"; +import { EnvVar } from "./environment"; import { Feature } from "./feature-flags"; import { getRunnerLogger } from "./logging"; import { getCacheRestoreKeyPrefix } from "./overlay/caching"; @@ -637,8 +638,8 @@ test.serial( async (t) => { await withTmpDir(async (tmpDir) => { setupActionsVars(tmpDir, tmpDir); - process.env["CODE_SCANNING_REF"] = "refs/heads/feature-branch"; - process.env["CODE_SCANNING_BASE_BRANCH"] = "main"; + process.env[EnvVar.CODE_SCANNING_REF] = "refs/heads/feature-branch"; + process.env[EnvVar.CODE_SCANNING_BASE_BRANCH] = "main"; sinon.stub(api, "getAutomationID").resolves("test/"); const listStub = sinon.stub(api, "listActionsCaches").resolves([