Merge pull request #3481 from github/backport-v3.32.3-9e907b5e6

Merge releases/v4 into releases/v3
This commit is contained in:
Henry Mercer
2026-02-13 12:21:24 +00:00
committed by GitHub
28 changed files with 5086 additions and 3963 deletions
+1 -1
View File
@@ -56,7 +56,7 @@ jobs:
use-all-platform-bundle: 'false'
setup-kotlin: 'true'
- name: Set up Ruby
uses: ruby/setup-ruby@90be1154f987f4dc0fe0dd0feedac9e473aa4ba8 # v1.286.0
uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration
+4
View File
@@ -2,6 +2,10 @@
See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs.
## 3.32.3 - 13 Feb 2026
- Added experimental support for testing connections to [private package registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries). This feature is not currently enabled for any analysis. In the future, it may be enabled by default for Default Setup. [#3466](https://github.com/github/codeql-action/pull/3466)
## 3.32.2 - 05 Feb 2026
- Update default CodeQL bundle version to [2.24.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.1). [#3460](https://github.com/github/codeql-action/pull/3460)
+15 -3
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -160928,6 +160929,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -161695,6 +161702,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
+23 -4
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -106638,6 +106639,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -107763,6 +107770,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
@@ -108000,7 +108012,14 @@ var GitHubFeatureFlags = class {
async loadApiResponse() {
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
this.logger.debug(
"Not running against github.com. Disabling all toggleable features."
"Not running against github.com. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
}
if (isCCR()) {
this.logger.debug(
"Feature flags are not supported in Copilot Code Review. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+27 -4
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -103129,6 +103130,10 @@ function getWorkflowRunAttempt() {
function isSelfHostedRunner() {
return process.env.RUNNER_ENVIRONMENT === "self-hosted";
}
var CCR_KEY_PREFIX = "dynamic/copilot-pull-request-reviewer";
function isCCR() {
return process.env["CODEQL_ACTION_ANALYSIS_KEY" /* ANALYSIS_KEY */]?.startsWith(CCR_KEY_PREFIX) || false;
}
function prettyPrintInvocation(cmd, args) {
return [cmd, ...args].map((x) => x.includes(" ") ? `'${x}'` : x).join(" ");
}
@@ -103299,6 +103304,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -104096,6 +104107,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
@@ -104333,7 +104349,14 @@ var GitHubFeatureFlags = class {
async loadApiResponse() {
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
this.logger.debug(
"Not running against github.com. Disabling all toggleable features."
"Not running against github.com. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
}
if (isCCR()) {
this.logger.debug(
"Feature flags are not supported in Copilot Code Review. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+23 -4
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -164144,6 +164145,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -165089,6 +165096,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
@@ -165326,7 +165338,14 @@ var GitHubFeatureFlags = class {
async loadApiResponse() {
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
this.logger.debug(
"Not running against github.com. Disabling all toggleable features."
"Not running against github.com. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
}
if (isCCR()) {
this.logger.debug(
"Feature flags are not supported in Copilot Code Review. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+23 -4
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -103985,6 +103986,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -105296,6 +105303,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
@@ -105533,7 +105545,14 @@ var GitHubFeatureFlags = class {
async loadApiResponse() {
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
this.logger.debug(
"Not running against github.com. Disabling all toggleable features."
"Not running against github.com. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
}
if (isCCR()) {
this.logger.debug(
"Feature flags are not supported in Copilot Code Review. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+15 -3
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -103307,6 +103308,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -104087,6 +104094,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
+27 -4
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -103246,6 +103247,10 @@ function isSelfHostedRunner() {
function isDynamicWorkflow() {
return getWorkflowEventName() === "dynamic";
}
var CCR_KEY_PREFIX = "dynamic/copilot-pull-request-reviewer";
function isCCR() {
return process.env["CODEQL_ACTION_ANALYSIS_KEY" /* ANALYSIS_KEY */]?.startsWith(CCR_KEY_PREFIX) || false;
}
function prettyPrintInvocation(cmd, args) {
return [cmd, ...args].map((x) => x.includes(" ") ? `'${x}'` : x).join(" ");
}
@@ -103416,6 +103421,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -103997,6 +104008,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
@@ -104234,7 +104250,14 @@ var GitHubFeatureFlags = class {
async loadApiResponse() {
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
this.logger.debug(
"Not running against github.com. Disabling all toggleable features."
"Not running against github.com. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
}
if (isCCR()) {
this.logger.debug(
"Feature flags are not supported in Copilot Code Review. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+15 -3
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -160811,6 +160812,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -161101,6 +161108,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
+4347 -3860
View File
File diff suppressed because it is too large Load Diff
+15 -3
View File
@@ -47283,7 +47283,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -47323,6 +47323,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -47332,7 +47333,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -47353,7 +47354,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -106276,6 +106277,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -107156,6 +107163,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
+15 -3
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -160811,6 +160812,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -161263,6 +161270,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
+23 -4
View File
@@ -45986,7 +45986,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "3.32.2",
version: "3.32.3",
private: true,
description: "CodeQL action",
scripts: {
@@ -46026,6 +46026,7 @@ var require_package = __commonJS({
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
jsonschema: "1.4.1",
long: "^5.3.2",
@@ -46035,7 +46036,7 @@ var require_package = __commonJS({
},
devDependencies: {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -46056,7 +46057,7 @@ var require_package = __commonJS({
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
glob: "^11.1.0",
nock: "^14.0.10",
@@ -106322,6 +106323,12 @@ function createApiClientWithDetails(apiDetails, { allowExternal = false } = {})
info: core5.info,
warn: core5.warning,
error: core5.error
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451]
}
})
);
@@ -106951,6 +106958,11 @@ var featureConfig = {
// cannot be found when interpreting results.
minimumVersion: void 0
},
["start_proxy_connection_checks" /* StartProxyConnectionChecks */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: void 0
},
["upload_overlay_db_to_api" /* UploadOverlayDbToApi */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
@@ -107188,7 +107200,14 @@ var GitHubFeatureFlags = class {
async loadApiResponse() {
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
this.logger.debug(
"Not running against github.com. Disabling all toggleable features."
"Not running against github.com. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
}
if (isCCR()) {
this.logger.debug(
"Feature flags are not supported in Copilot Code Review. Using default values for all features."
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+17 -15
View File
@@ -1,12 +1,12 @@
{
"name": "codeql",
"version": "4.32.2",
"version": "4.32.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codeql",
"version": "4.32.2",
"version": "4.32.3",
"license": "MIT",
"dependencies": {
"@actions/artifact": "^5.0.3",
@@ -25,6 +25,7 @@
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
"jsonschema": "1.4.1",
"long": "^5.3.2",
@@ -34,7 +35,7 @@
},
"devDependencies": {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -55,7 +56,7 @@
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^11.1.0",
"nock": "^14.0.10",
@@ -1341,19 +1342,19 @@
}
},
"node_modules/@eslint/compat": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.1.tgz",
"integrity": "sha512-yl/JsgplclzuvGFNqwNYV4XNPhP3l62ZOP9w/47atNAdmDtIFCx6X7CSk/SlWUuBGkT4Et/5+UD+WyvX2iiIWA==",
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-2.0.2.tgz",
"integrity": "sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"@eslint/core": "^1.0.1"
"@eslint/core": "^1.1.0"
},
"engines": {
"node": "^20.19.0 || ^22.13.0 || >=24"
},
"peerDependencies": {
"eslint": "^8.40 || 9"
"eslint": "^8.40 || 9 || 10"
},
"peerDependenciesMeta": {
"eslint": {
@@ -1362,9 +1363,9 @@
}
},
"node_modules/@eslint/core": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.0.1.tgz",
"integrity": "sha512-r18fEAj9uCk+VjzGt2thsbOmychS+4kxI14spVNibUO2vqKX7obOG+ymZljAwuPZl+S3clPGwCwTDtrdqTiY6Q==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.1.0.tgz",
"integrity": "sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
@@ -4885,9 +4886,9 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
"version": "62.4.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.4.1.tgz",
"integrity": "sha512-HgX2iN4j104D/mCUqRbhtzSZbph+KO9jfMHiIJjJ19Q+IwLQ5Na2IqvOJYq4S+4kgvEk1w6KYF4vVus6H2wcHg==",
"version": "62.5.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-62.5.0.tgz",
"integrity": "sha512-D+1haMVDzW/ZMoPwOnsbXCK07rJtsq98Z1v+ApvDKxSzYTTcPgmFc/nyUDCGmxm2cP7g7hszyjYHO7Zodl/43w==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -5999,6 +6000,7 @@
"version": "7.0.6",
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
"license": "MIT",
"dependencies": {
"agent-base": "^7.1.2",
"debug": "4"
+4 -3
View File
@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "3.32.2",
"version": "3.32.3",
"private": true,
"description": "CodeQL action",
"scripts": {
@@ -40,6 +40,7 @@
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.15.11",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^4.1.1",
"jsonschema": "1.4.1",
"long": "^5.3.2",
@@ -49,7 +50,7 @@
},
"devDependencies": {
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.1",
"@eslint/compat": "^2.0.2",
"@eslint/eslintrc": "^3.3.3",
"@eslint/js": "^9.39.2",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
@@ -70,7 +71,7 @@
"eslint-plugin-filenames": "^1.3.2",
"eslint-plugin-github": "^5.1.8",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jsdoc": "^62.4.1",
"eslint-plugin-jsdoc": "^62.5.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^11.1.0",
"nock": "^14.0.10",
+1 -1
View File
@@ -4,7 +4,7 @@ description: "Tests using RuboCop to analyze a multi-language repository and the
versions: ["default"]
steps:
- name: Set up Ruby
uses: ruby/setup-ruby@90be1154f987f4dc0fe0dd0feedac9e473aa4ba8 # v1.286.0
uses: ruby/setup-ruby@09a7688d3b55cf0e976497ff046b70949eeaccfd # v1.288.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration
+3
View File
@@ -36,6 +36,9 @@ test("getApiClient", async (t) => {
baseUrl: "http://api.github.localhost",
log: sinon.match.any,
userAgent: `CodeQL-Action/${actionsUtil.getActionVersion()}`,
retry: {
doNotRetry: [400, 410, 422, 451],
},
}),
);
});
+6
View File
@@ -51,6 +51,12 @@ function createApiClientWithDetails(
warn: core.warning,
error: core.error,
},
retry: {
// The default is 400, 401, 403, 404, 410, 422, and 451. We have observed transient errors
// with authentication, so we remove 401, 403, and 404 from the default list to ensure that
// these errors are retried.
doNotRetry: [400, 410, 422, 451],
},
}),
);
}
+50 -15
View File
@@ -4,6 +4,7 @@ import * as path from "path";
import test, { ExecutionContext } from "ava";
import * as defaults from "./defaults.json";
import { EnvVar } from "./environment";
import {
Feature,
featureConfig,
@@ -37,29 +38,39 @@ test.beforeEach(() => {
const testRepositoryNwo = parseRepositoryNwo("github/example");
test(`All features are disabled if running against GHES`, async (t) => {
test(`All features use default values if running against GHES`, async (t) => {
await withTmpDir(async (tmpDir) => {
const loggedMessages = [];
const loggedMessages: LoggedMessage[] = [];
const features = setUpFeatureFlagTests(
tmpDir,
getRecordingLogger(loggedMessages),
{ type: GitHubVariant.GHES, version: "3.0.0" },
);
for (const feature of Object.values(Feature)) {
t.deepEqual(
await getFeatureIncludingCodeQlIfRequired(features, feature),
featureConfig[feature].defaultValue,
);
}
await assertAllFeaturesHaveDefaultValues(t, features);
assertLoggedMessage(
t,
loggedMessages,
"Not running against github.com. Using default values for all features.",
);
});
});
t.assert(
loggedMessages.find(
(v: LoggedMessage) =>
v.type === "debug" &&
v.message ===
"Not running against github.com. Disabling all toggleable features.",
) !== undefined,
test(`All features use default values if running in CCR`, async (t) => {
await withTmpDir(async (tmpDir) => {
const loggedMessages: LoggedMessage[] = [];
const features = setUpFeatureFlagTests(
tmpDir,
getRecordingLogger(loggedMessages),
);
process.env[EnvVar.ANALYSIS_KEY] = "dynamic/copilot-pull-request-reviewer";
await assertAllFeaturesHaveDefaultValues(t, features);
assertLoggedMessage(
t,
loggedMessages,
"Feature flags are not supported in Copilot Code Review. Using default values for all features.",
);
});
});
@@ -542,6 +553,30 @@ test("non-legacy feature flags should not start with codeql_action_", async (t)
}
});
async function assertAllFeaturesHaveDefaultValues(
t: ExecutionContext<unknown>,
features: FeatureEnablement,
) {
for (const feature of Object.values(Feature)) {
t.deepEqual(
await getFeatureIncludingCodeQlIfRequired(features, feature),
featureConfig[feature].defaultValue,
);
}
}
function assertLoggedMessage(
t: ExecutionContext<unknown>,
loggedMessages: LoggedMessage[],
expectedMessage: string,
) {
t.assert(
loggedMessages.find(
(v: LoggedMessage) => v.type === "debug" && v.message === expectedMessage,
) !== undefined,
);
}
function assertAllFeaturesUndefinedInApi(
t: ExecutionContext<unknown>,
loggedMessages: LoggedMessage[],
+15 -1
View File
@@ -3,6 +3,7 @@ import * as path from "path";
import * as semver from "semver";
import { isCCR } from "./actions-util";
import { getApiClient } from "./api-client";
import type { CodeQL } from "./codeql";
import * as defaults from "./defaults.json";
@@ -72,6 +73,7 @@ export enum Feature {
QaTelemetryEnabled = "qa_telemetry_enabled",
/** Note that this currently only disables baseline file coverage information. */
SkipFileCoverageOnPrs = "skip_file_coverage_on_prs",
StartProxyConnectionChecks = "start_proxy_connection_checks",
UploadOverlayDbToApi = "upload_overlay_db_to_api",
UseRepositoryProperties = "use_repository_properties",
ValidateDbConfig = "validate_db_config",
@@ -297,6 +299,11 @@ export const featureConfig = {
// cannot be found when interpreting results.
minimumVersion: undefined,
},
[Feature.StartProxyConnectionChecks]: {
defaultValue: false,
envVar: "CODEQL_ACTION_START_PROXY_CONNECTION_CHECKS",
minimumVersion: undefined,
},
[Feature.UploadOverlayDbToApi]: {
defaultValue: false,
envVar: "CODEQL_ACTION_UPLOAD_OVERLAY_DB_TO_API",
@@ -658,7 +665,14 @@ class GitHubFeatureFlags {
// Do nothing when not running against github.com
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
this.logger.debug(
"Not running against github.com. Disabling all toggleable features.",
"Not running against github.com. Using default values for all features.",
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
}
if (isCCR()) {
this.logger.debug(
"Feature flags are not supported in Copilot Code Review. Using default values for all features.",
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+37 -5
View File
@@ -5,18 +5,24 @@ import * as core from "@actions/core";
import { pki } from "node-forge";
import * as actionsUtil from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { Feature, Features } from "./feature-flags";
import { KnownLanguage } from "./languages";
import { getActionsLogger, Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
import {
Credential,
credentialToStr,
getCredentials,
getProxyBinaryPath,
getSafeErrorMessage,
parseLanguage,
ProxyInfo,
sendFailedStatusReport,
sendSuccessStatusReport,
Credential,
Registry,
} from "./start-proxy";
import { checkConnections } from "./start-proxy/reachability";
import { ActionName, sendUnhandledErrorStatusReport } from "./status-report";
import * as util from "./util";
@@ -34,6 +40,7 @@ type BasicAuthCredentials = {
};
type ProxyConfig = {
/** The validated configurations for the proxy. */
all_credentials: Credential[];
ca: CertificateAuthority;
proxy_auth?: BasicAuthCredentials;
@@ -92,6 +99,7 @@ async function run(startedAt: Date) {
// possible, and only use safe functions outside.
const logger = getActionsLogger();
let features: Features | undefined;
let language: KnownLanguage | undefined;
try {
@@ -103,9 +111,21 @@ async function run(startedAt: Date) {
const proxyLogFilePath = path.resolve(tempDir, "proxy.log");
core.saveState("proxy-log-file", proxyLogFilePath);
// Get the configuration options
// Initialise FFs.
const repositoryNwo = getRepositoryNwo();
const gitHubVersion = await getGitHubVersion();
features = new Features(
gitHubVersion,
repositoryNwo,
actionsUtil.getTemporaryDirectory(),
logger,
);
// Get the language input.
const languageInput = actionsUtil.getOptionalInput("language");
language = languageInput ? parseLanguage(languageInput) : undefined;
// Get the registry configurations from one of the inputs.
const credentials = getCredentials(
logger,
actionsUtil.getOptionalInput("registry_secrets"),
@@ -133,7 +153,17 @@ async function run(startedAt: Date) {
// Start the Proxy
const proxyBin = await getProxyBinaryPath(logger);
await startProxy(proxyBin, proxyConfig, proxyLogFilePath, logger);
const proxyInfo = await startProxy(
proxyBin,
proxyConfig,
proxyLogFilePath,
logger,
);
// Check that the private registries are reachable.
if (await features.getValue(Feature.StartProxyConnectionChecks)) {
await checkConnections(logger, proxyInfo);
}
// Report success if we have reached this point.
await sendSuccessStatusReport(
@@ -171,7 +201,7 @@ async function startProxy(
config: ProxyConfig,
logFilePath: string,
logger: Logger,
) {
): Promise<ProxyInfo> {
const host = "127.0.0.1";
let port = 49152;
let subprocess: ChildProcess | undefined = undefined;
@@ -214,13 +244,15 @@ async function startProxy(
core.setOutput("proxy_port", port.toString());
core.setOutput("proxy_ca_certificate", config.ca.cert);
const registry_urls = config.all_credentials
const registry_urls: Registry[] = config.all_credentials
.filter((credential) => credential.url !== undefined)
.map((credential) => ({
type: credential.type,
url: credential.url,
}));
core.setOutput("proxy_urls", JSON.stringify(registry_urls));
return { host, port, cert: config.ca.cert, registries: registry_urls };
}
void runWrapper();
+25 -2
View File
@@ -175,6 +175,27 @@ test("getCredentials throws error when credential is not an object", async (t) =
}
});
test("getCredentials throws error when credential is missing type", async (t) => {
const testCredentials = [[{ token: "abc", url: "https://localhost" }]].map(
toEncodedJSON,
);
for (const testCredential of testCredentials) {
t.throws(
() =>
startProxyExports.getCredentials(
getRunnerLogger(true),
undefined,
testCredential,
undefined,
),
{
message: "Invalid credentials - must have a type",
},
);
}
});
test("getCredentials throws error when credential missing host and url", async (t) => {
const testCredentials = [
[{ type: "npm_registry", token: "abc" }],
@@ -396,13 +417,14 @@ test("credentialToStr - hides passwords", (t) => {
const credential = {
type: "maven_credential",
password: secret,
url: "https://localhost",
};
const str = startProxyExports.credentialToStr(credential);
t.false(str.includes(secret));
t.is(
"Type: maven_credential; Host: undefined; Url: undefined Username: undefined; Password: true; Token: false",
"Type: maven_credential; Host: undefined; Url: https://localhost Username: undefined; Password: true; Token: false",
str,
);
});
@@ -412,13 +434,14 @@ test("credentialToStr - hides tokens", (t) => {
const credential = {
type: "maven_credential",
token: secret,
url: "https://localhost",
};
const str = startProxyExports.credentialToStr(credential);
t.false(str.includes(secret));
t.is(
"Type: maven_credential; Host: undefined; Url: undefined Username: undefined; Password: false; Token: true",
"Type: maven_credential; Host: undefined; Url: https://localhost Username: undefined; Password: false; Token: true",
str,
);
});
+42 -19
View File
@@ -13,6 +13,12 @@ import { Config } from "./config-utils";
import * as defaults from "./defaults.json";
import { KnownLanguage } from "./languages";
import { Logger } from "./logging";
import {
Address,
RawCredential,
Registry,
Credential,
} from "./start-proxy/types";
import {
ActionName,
createStatusReportBase,
@@ -23,6 +29,8 @@ import {
import * as util from "./util";
import { ConfigurationError, getErrorMessage, isDefined } from "./util";
export * from "./start-proxy/types";
/**
* Enumerates specific error types for which we have corresponding error messages that
* are safe to include in status reports.
@@ -161,15 +169,6 @@ export const UPDATEJOB_PROXY_VERSION = "v2.0.20250624110901";
const UPDATEJOB_PROXY_URL_PREFIX =
"https://github.com/github/codeql-action/releases/download/codeql-bundle-v2.22.0/";
export type Credential = {
type: string;
host?: string;
url?: string;
username?: string;
password?: string;
token?: string;
};
/*
* Language aliases supported by the start-proxy Action.
*
@@ -229,6 +228,31 @@ const LANGUAGE_TO_REGISTRY_TYPE: Partial<Record<KnownLanguage, string[]>> = {
go: ["goproxy_server", "git_source"],
} as const;
/**
* Extracts an `Address` value from the given `Registry` value by determining whether it has
* a `url` value, or no `url` value but a `host` value.
*
* @throws A `ConfigurationError` if the `Registry` value contains neither a `url` or `host` field.
*/
function getRegistryAddress(registry: Partial<Registry>): Address {
if (isDefined(registry.url)) {
return {
url: registry.url,
host: registry.host,
};
} else if (isDefined(registry.host)) {
return {
url: undefined,
host: registry.host,
};
} else {
// The proxy needs one of these to work. If both are defined, the url has the precedence.
throw new ConfigurationError(
"Invalid credentials - must specify host or url",
);
}
}
// getCredentials returns registry credentials from action inputs.
// It prefers `registries_credentials` over `registry_secrets`.
// If neither is set, it returns an empty array.
@@ -255,9 +279,9 @@ export function getCredentials(
}
// Parse and validate the credentials
let parsed: Credential[];
let parsed: RawCredential[];
try {
parsed = JSON.parse(credentialsStr) as Credential[];
parsed = JSON.parse(credentialsStr) as RawCredential[];
} catch {
// Don't log the error since it might contain sensitive information.
logger.error("Failed to parse the credentials data.");
@@ -277,6 +301,11 @@ export function getCredentials(
throw new ConfigurationError("Invalid credentials - must be an object");
}
// The configuration must have a type.
if (!isDefined(e.type)) {
throw new ConfigurationError("Invalid credentials - must have a type");
}
// Mask credentials to reduce chance of accidental leakage in logs.
if (isDefined(e.password)) {
core.setSecret(e.password);
@@ -285,12 +314,7 @@ export function getCredentials(
core.setSecret(e.token);
}
if (!isDefined(e.url) && !isDefined(e.host)) {
// The proxy needs one of these to work. If both are defined, the url has the precedence.
throw new ConfigurationError(
"Invalid credentials - must specify host or url",
);
}
const address = getRegistryAddress(e);
// Filter credentials based on language if specified. `type` is the registry type.
// E.g., "maven_feed" for Java/Kotlin, "nuget_repository" for C#.
@@ -333,11 +357,10 @@ export function getCredentials(
out.push({
type: e.type,
host: e.host,
url: e.url,
username: e.username,
password: e.password,
token: e.token,
...address,
});
}
return out;
+120
View File
@@ -0,0 +1,120 @@
import test from "ava";
import * as sinon from "sinon";
import {
checkExpectedLogMessages,
setupTests,
withRecordingLoggerAsync,
} from "./../testing-utils";
import {
checkConnections,
ReachabilityBackend,
ReachabilityError,
} from "./reachability";
import { ProxyInfo, Registry } from "./types";
setupTests(test);
class MockReachabilityBackend implements ReachabilityBackend {
public async checkConnection(_url: URL): Promise<number> {
return 200;
}
}
const mavenRegistry: Registry = {
type: "maven_registry",
url: "https://repo.maven.apache.org/maven2/",
};
const nugetFeed: Registry = {
type: "nuget_feed",
url: "https://api.nuget.org/v3/index.json",
};
const proxyInfo: ProxyInfo = {
host: "127.0.0.1",
port: 1080,
cert: "",
registries: [mavenRegistry, nugetFeed],
};
test("checkConnections - basic functionality", async (t) => {
const backend = new MockReachabilityBackend();
const messages = await withRecordingLoggerAsync(async (logger) => {
const reachable = await checkConnections(logger, proxyInfo, backend);
t.is(reachable.size, proxyInfo.registries.length);
t.true(reachable.has(mavenRegistry));
t.true(reachable.has(nugetFeed));
});
checkExpectedLogMessages(t, messages, [
`Testing connection to ${mavenRegistry.url}`,
`Successfully tested connection to ${mavenRegistry.url}`,
`Testing connection to ${nugetFeed.url}`,
`Successfully tested connection to ${nugetFeed.url}`,
`Finished testing connections`,
]);
});
test("checkConnections - excludes failed status codes", async (t) => {
const backend = new MockReachabilityBackend();
sinon
.stub(backend, "checkConnection")
.onSecondCall()
.throws(new ReachabilityError(400));
const messages = await withRecordingLoggerAsync(async (logger) => {
const reachable = await checkConnections(logger, proxyInfo, backend);
t.is(reachable.size, 1);
t.true(reachable.has(mavenRegistry));
});
checkExpectedLogMessages(t, messages, [
`Testing connection to ${mavenRegistry.url}`,
`Successfully tested connection to ${mavenRegistry.url}`,
`Testing connection to ${nugetFeed.url}`,
`Connection test to ${nugetFeed.url} failed. (400)`,
`Finished testing connections`,
]);
});
test("checkConnections - handles other exceptions", async (t) => {
const backend = new MockReachabilityBackend();
sinon
.stub(backend, "checkConnection")
.onSecondCall()
.throws(new Error("Some generic error"));
const messages = await withRecordingLoggerAsync(async (logger) => {
const reachable = await checkConnections(logger, proxyInfo, backend);
t.is(reachable.size, 1);
t.true(reachable.has(mavenRegistry));
});
checkExpectedLogMessages(t, messages, [
`Testing connection to ${mavenRegistry.url}`,
`Successfully tested connection to ${mavenRegistry.url}`,
`Testing connection to ${nugetFeed.url}`,
`Connection test to ${nugetFeed.url} failed: Some generic error`,
`Finished testing connections`,
]);
});
test("checkConnections - handles invalid URLs", async (t) => {
const backend = new MockReachabilityBackend();
const messages = await withRecordingLoggerAsync(async (logger) => {
const reachable = await checkConnections(
logger,
{
...proxyInfo,
registries: [
{
type: "nuget_feed",
url: "localhost",
},
],
},
backend,
);
t.is(reachable.size, 0);
});
checkExpectedLogMessages(t, messages, [
`Skipping check for localhost since it is not a valid URL.`,
`Finished testing connections`,
]);
});
+130
View File
@@ -0,0 +1,130 @@
import * as https from "https";
import { HttpsProxyAgent } from "https-proxy-agent";
import { Logger } from "../logging";
import { getErrorMessage } from "../util";
import { getAddressString, ProxyInfo, Registry } from "./types";
export class ReachabilityError extends Error {
constructor(public readonly statusCode?: number | undefined) {
super();
}
}
/**
* Abstracts over the backend for the reachability checks,
* to allow actual networking to be replaced with stubs.
*/
export interface ReachabilityBackend {
/**
* Performs a test HTTP request to the specified `url`. Resolves to the status code,
* if a successful status code was obtained. Otherwise throws
*
* @param url The URL of the registry to try and reach.
* @returns The successful status code (in the `<400` range).
*/
checkConnection: (url: URL) => Promise<number>;
}
class NetworkReachabilityBackend implements ReachabilityBackend {
private agent: https.Agent;
constructor(private readonly proxy: ProxyInfo) {
this.agent = new HttpsProxyAgent(`http://${proxy.host}:${proxy.port}`);
}
public async checkConnection(url: URL): Promise<number> {
return new Promise((resolve, reject) => {
const req = https.request(
url,
{
agent: this.agent,
method: "HEAD",
ca: this.proxy.cert,
timeout: 5 * 1000, // 5 seconds
},
(res) => {
res.destroy();
if (res.statusCode !== undefined && res.statusCode < 400) {
resolve(res.statusCode);
} else {
reject(new ReachabilityError(res.statusCode));
}
},
);
req.on("error", (e) => {
reject(e);
});
req.on("timeout", () => {
req.destroy();
reject(new Error("Connection timeout."));
});
req.end();
});
}
}
/**
* Determines which configured registries can be reached by performing test requests to them.
*
* @param logger The logger to use.
* @param proxy Information about the proxy, including the configured registries.
* @param backend Optionally for testing, a `ReachabilityBackend` to use.
* @returns The set of registries which passed the checks.
*/
export async function checkConnections(
logger: Logger,
proxy: ProxyInfo,
backend?: ReachabilityBackend,
): Promise<Set<Registry>> {
const result: Set<Registry> = new Set();
// Don't do anything if there are no registries.
if (proxy.registries.length === 0) return result;
try {
// Initialise a networking backend if no backend was provided.
if (backend === undefined) {
backend = new NetworkReachabilityBackend(proxy);
}
for (const registry of proxy.registries) {
const address = getAddressString(registry);
const url = URL.parse(address);
if (url === null) {
logger.info(
`Skipping check for ${address} since it is not a valid URL.`,
);
continue;
}
try {
logger.debug(`Testing connection to ${url}...`);
const statusCode = await backend.checkConnection(url);
logger.info(`Successfully tested connection to ${url} (${statusCode})`);
result.add(registry);
} catch (e) {
if (e instanceof ReachabilityError && e.statusCode !== undefined) {
logger.error(`Connection test to ${url} failed. (${e.statusCode})`);
} else {
logger.error(
`Connection test to ${url} failed: ${getErrorMessage(e)}`,
);
}
}
}
logger.debug(`Finished testing connections to private registries.`);
} catch (e) {
logger.error(
`Failed to test connections to private registries: ${getErrorMessage(e)}`,
);
}
return result;
}
+61
View File
@@ -0,0 +1,61 @@
/**
* After parsing configurations from JSON, we don't know whether all the keys we expect are
* present or not. This type is used to represent such values, which we expect to be
* `Credential` values, but haven't validated yet.
*/
export type RawCredential = Partial<Credential>;
/**
* A package registry configuration includes identifying information as well as
* authentication credentials.
*/
export type Credential = {
/** The username needed to authenticate to the package registry, if any. */
username?: string;
/** The password needed to authenticate to the package registry, if any. */
password?: string;
/** The token needed to authenticate to the package registry, if any. */
token?: string;
} & Registry;
/** A package registry is identified by its type and address. */
export type Registry = {
/** The type of the package registry. */
type: string;
} & Address;
// If a registry has an `url`, then that takes precedence over the `host` which may or may
// not be defined.
interface HasUrl {
url: string;
host?: string;
}
// If a registry does not have an `url`, then it must have a `host`.
interface WithoutUrl {
url: undefined;
host: string;
}
/**
* A valid `Registry` value must either have a `url` or a `host` value. If it has a `url` value,
* then that takes precedence over the `host` value. If there is no `url` value, then it must
* have a `host` value.
*/
export type Address = HasUrl | WithoutUrl;
/** Gets the address as a string. This will either be the `url` if present, or the `host` if not. */
export function getAddressString(address: Address): string {
if (address.url === undefined) {
return address.host;
} else {
return address.url;
}
}
export interface ProxyInfo {
host: string;
port: number;
cert: string;
registries: Registry[];
}
+2 -2
View File
@@ -19,8 +19,8 @@
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
/* Additional Checks */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
"noUnusedLocals": false, /* Report errors on unused locals. */
"noUnusedParameters": false, /* Report errors on unused parameters. */
"noImplicitReturns": true, /* Report error when not all code paths in function return a value. */
"noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */