Merge branch 'main' into mbg/analyze/use-upload-sarif

This commit is contained in:
Michael B. Gale
2025-10-22 00:42:55 +01:00
committed by GitHub
77 changed files with 103352 additions and 3978 deletions
+55
View File
@@ -0,0 +1,55 @@
labeling:
applyCategoryLabels: true
categoryLabelPrefix: "size/"
commenting:
addCommentWhenScoreThresholdHasBeenExceeded: false
sizeup:
categories:
- name: extra small
lte: 25
label:
name: XS
description: Should be very easy to review
color: 3cbf00
- name: small
lte: 100
label:
name: S
description: Should be easy to review
color: 5d9801
- name: medium
lte: 250
label:
name: M
description: Should be of average difficulty to review
color: 7f7203
- name: large
lte: 500
label:
name: L
description: May be hard to review
color: a14c05
- name: extra large
lte: 1000
label:
name: XL
description: May be very hard to review
color: c32607
- name: extra extra large
label:
name: XXL
description: May be extremely hard to review
color: e50009
ignoredFilePatterns:
- ".github/workflows/__*"
- "lib/**/*"
- "package-lock.json"
testFilePatterns:
- "**/*.test.ts"
scoring:
# This formula and the aliases below it are written in prefix notation.
# For an explanation of how this works, please see:
# https://github.com/lerebear/sizeup-core/blob/main/README.md#prefix-notation
formula: "- - + additions deletions comments whitespace"
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -70,6 +80,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- uses: ./../action/init
with:
tools: ${{ steps.prepare-test.outputs.tools-url }}
+2 -3
View File
@@ -67,10 +67,9 @@ jobs:
if (allCodeqlVersions.length === 0) {
throw new Error(`CodeQL could not be found in the toolcache`);
}
- id: init
uses: ./../action/init
- id: setup-codeql
uses: ./../action/setup-codeql
with:
languages: javascript
tools: ${{ steps.prepare-test.outputs.tools-url }}
- name: Check CodeQL is installed within the toolcache
uses: actions/github-script@v8
+1 -1
View File
@@ -49,7 +49,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v5
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20.x
cache: npm
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -70,6 +80,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- name: Fetch latest CodeQL bundle
run: |
wget https://github.com/github/codeql-action/releases/latest/download/codeql-bundle-linux64.tar.zst
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -104,6 +114,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- name: Use Xcode 16
if: runner.os == 'macOS' && matrix.version != 'nightly-latest'
run: sudo xcode-select -s "/Applications/Xcode_16.app"
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -63,7 +73,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v5
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20.x
cache: npm
@@ -81,6 +91,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- uses: ./../action/init
with:
config-file: .github/codeql/codeql-config-packaging3.yml
+1 -1
View File
@@ -63,7 +63,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v5
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20.x
cache: npm
+1 -1
View File
@@ -63,7 +63,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v5
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20.x
cache: npm
+1 -1
View File
@@ -63,7 +63,7 @@ jobs:
- name: Check out repository
uses: actions/checkout@v5
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 20.x
cache: npm
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -72,6 +82,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- uses: ./../action/init
with:
tools: ${{ steps.prepare-test.outputs.tools-url }}
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -72,6 +82,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- uses: ./../action/init
id: init
with:
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -70,6 +80,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- uses: ./../action/init
with:
tools: ${{ steps.prepare-test.outputs.tools-url }}
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -77,6 +87,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- uses: ./../action/init
with:
tools: ${{ steps.prepare-test.outputs.tools-url }}
+15
View File
@@ -27,6 +27,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
workflow_call:
inputs:
go-version:
@@ -34,6 +39,11 @@ on:
description: The version of Go to install
required: false
default: '>=1.21.0'
python-version:
type: string
description: The version of Python to install
required: false
default: '3.13'
defaults:
run:
shell: bash
@@ -70,6 +80,11 @@ jobs:
with:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Python
if: matrix.version != 'nightly-latest'
uses: actions/setup-python@v6
with:
python-version: ${{ inputs.python-version || '3.13' }}
- name: Delete original checkout
run: |
# delete the original checkout so we don't accidentally use it.
@@ -56,7 +56,7 @@ jobs:
uses: actions/checkout@v5
- name: Set up Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'npm'
+26
View File
@@ -0,0 +1,26 @@
name: Label PR with size
on:
pull_request:
types:
- opened
- synchronize
- reopened
- edited
- ready_for_review
permissions:
contents: read
pull-requests: write
jobs:
sizeup:
name: Label PR with size
runs-on: ubuntu-latest
steps:
- name: Run sizeup
uses: lerebear/sizeup-action@b7beb3dd273e36039e16e48e7bc690c189e61951 # 0.8.12
with:
token: "${{ secrets.GITHUB_TOKEN }}"
configuration-file-path: ".github/sizeup.yml"
+1 -1
View File
@@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@v5
with:
fetch-depth: 0 # ensure we have all tags and can push commits
- uses: actions/setup-node@v5
- uses: actions/setup-node@v6
- name: Update git config
run: |
+1 -1
View File
@@ -35,7 +35,7 @@ jobs:
- uses: actions/checkout@v5
- name: Set up Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
+1 -1
View File
@@ -32,7 +32,7 @@ jobs:
uses: actions/checkout@v5
- name: Install Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 24
cache: npm
+1 -1
View File
@@ -41,7 +41,7 @@ jobs:
git config --global user.name "github-actions[bot]"
- name: Set up Node.js
uses: actions/setup-node@v5
uses: actions/setup-node@v6
with:
node-version: 24
cache: 'npm'
+5
View File
@@ -6,6 +6,11 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
No user facing changes.
## 4.30.9 - 17 Oct 2025
- Update default CodeQL bundle version to 2.23.3. [#3205](https://github.com/github/codeql-action/pull/3205)
- Experimental: A new `setup-codeql` action has been added which is similar to `init`, except it only installs the CodeQL CLI and does not initialize a database. Do not use this in production as it is part of an internal experiment and subject to change at any time. [#3204](https://github.com/github/codeql-action/pull/3204)
## 4.30.8 - 10 Oct 2025
No user facing changes.
+1
View File
@@ -34,6 +34,7 @@ Actions with special purposes and unlikely to be used directly:
- `autobuild`: Attempts to automatically build the code. Only used for analyzing languages that require a build. Use the `build-mode: autobuild` input in the `init` action instead. For information about input parameters, see the [autobuild action definition](https://github.com/github/codeql-action/blob/main/autobuild/action.yml).
- `resolve-environment`: [Experimental] Attempts to infer a build environment suitable for automatic builds. For information about input parameters, see the [resolve-environment action definition](https://github.com/github/codeql-action/blob/main/resolve-environment/action.yml).
- `start-proxy`: [Experimental] Start the HTTP proxy server. Internal use only and will change without notice. For information about input parameters, see the [start-proxy action definition](https://github.com/github/codeql-action/blob/main/start-proxy/action.yml).
- `setup-codeql`: [Experimental] Similar to `init`, except it only installs the CodeQL CLI and does not initialize a database.
### Workflow Permissions
+1327 -21
View File
File diff suppressed because it is too large Load Diff
+1403 -1399
View File
File diff suppressed because it is too large Load Diff
+1351 -28
View File
File diff suppressed because it is too large Load Diff
+4 -4
View File
@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.23.2",
"cliVersion": "2.23.2",
"priorBundleVersion": "codeql-bundle-v2.23.1",
"priorCliVersion": "2.23.1"
"bundleVersion": "codeql-bundle-v2.23.3",
"cliVersion": "2.23.3",
"priorBundleVersion": "codeql-bundle-v2.23.2",
"priorCliVersion": "2.23.2"
}
+1413 -1407
View File
File diff suppressed because it is too large Load Diff
+1688 -152
View File
File diff suppressed because it is too large Load Diff
+1346 -24
View File
File diff suppressed because it is too large Load Diff
+88985
View File
File diff suppressed because one or more lines are too long
+1327 -21
View File
File diff suppressed because it is too large Load Diff
+1345 -26
View File
File diff suppressed because it is too large Load Diff
+104 -108
View File
@@ -20885,19 +20885,19 @@ var require_validator = __commonJS({
var SchemaError = helpers.SchemaError;
var SchemaContext = helpers.SchemaContext;
var anonymousBase = "/";
var Validator2 = function Validator3() {
this.customFormats = Object.create(Validator3.prototype.customFormats);
var Validator3 = function Validator4() {
this.customFormats = Object.create(Validator4.prototype.customFormats);
this.schemas = {};
this.unresolvedRefs = [];
this.types = Object.create(types);
this.attributes = Object.create(attribute.validators);
};
Validator2.prototype.customFormats = {};
Validator2.prototype.schemas = null;
Validator2.prototype.types = null;
Validator2.prototype.attributes = null;
Validator2.prototype.unresolvedRefs = null;
Validator2.prototype.addSchema = function addSchema(schema2, base) {
Validator3.prototype.customFormats = {};
Validator3.prototype.schemas = null;
Validator3.prototype.types = null;
Validator3.prototype.attributes = null;
Validator3.prototype.unresolvedRefs = null;
Validator3.prototype.addSchema = function addSchema(schema2, base) {
var self2 = this;
if (!schema2) {
return null;
@@ -20915,25 +20915,25 @@ var require_validator = __commonJS({
});
return this.schemas[ourUri];
};
Validator2.prototype.addSubSchemaArray = function addSubSchemaArray(baseuri, schemas) {
Validator3.prototype.addSubSchemaArray = function addSubSchemaArray(baseuri, schemas) {
if (!Array.isArray(schemas)) return;
for (var i = 0; i < schemas.length; i++) {
this.addSubSchema(baseuri, schemas[i]);
}
};
Validator2.prototype.addSubSchemaObject = function addSubSchemaArray(baseuri, schemas) {
Validator3.prototype.addSubSchemaObject = function addSubSchemaArray(baseuri, schemas) {
if (!schemas || typeof schemas != "object") return;
for (var p in schemas) {
this.addSubSchema(baseuri, schemas[p]);
}
};
Validator2.prototype.setSchemas = function setSchemas(schemas) {
Validator3.prototype.setSchemas = function setSchemas(schemas) {
this.schemas = schemas;
};
Validator2.prototype.getSchema = function getSchema(urn) {
Validator3.prototype.getSchema = function getSchema(urn) {
return this.schemas[urn];
};
Validator2.prototype.validate = function validate(instance, schema2, options, ctx) {
Validator3.prototype.validate = function validate(instance, schema2, options, ctx) {
if (typeof schema2 !== "boolean" && typeof schema2 !== "object" || schema2 === null) {
throw new SchemaError("Expected `schema` to be an object or boolean");
}
@@ -20971,7 +20971,7 @@ var require_validator = __commonJS({
if (typeof ref == "string") return ref;
return false;
}
Validator2.prototype.validateSchema = function validateSchema(instance, schema2, options, ctx) {
Validator3.prototype.validateSchema = function validateSchema(instance, schema2, options, ctx) {
var result = new ValidatorResult(instance, schema2, options, ctx);
if (typeof schema2 === "boolean") {
if (schema2 === true) {
@@ -21021,17 +21021,17 @@ var require_validator = __commonJS({
}
return result;
};
Validator2.prototype.schemaTraverser = function schemaTraverser(schemaobj, s) {
Validator3.prototype.schemaTraverser = function schemaTraverser(schemaobj, s) {
schemaobj.schema = helpers.deepMerge(schemaobj.schema, this.superResolve(s, schemaobj.ctx));
};
Validator2.prototype.superResolve = function superResolve(schema2, ctx) {
Validator3.prototype.superResolve = function superResolve(schema2, ctx) {
var ref = shouldResolve(schema2);
if (ref) {
return this.resolve(schema2, ref, ctx).subschema;
}
return schema2;
};
Validator2.prototype.resolve = function resolve6(schema2, switchSchema, ctx) {
Validator3.prototype.resolve = function resolve6(schema2, switchSchema, ctx) {
switchSchema = ctx.resolve(switchSchema);
if (ctx.schemas[switchSchema]) {
return { subschema: ctx.schemas[switchSchema], switchSchema };
@@ -21048,7 +21048,7 @@ var require_validator = __commonJS({
}
return { subschema, switchSchema };
};
Validator2.prototype.testType = function validateType(instance, schema2, options, ctx, type2) {
Validator3.prototype.testType = function validateType(instance, schema2, options, ctx, type2) {
if (type2 === void 0) {
return;
} else if (type2 === null) {
@@ -21063,7 +21063,7 @@ var require_validator = __commonJS({
}
return true;
};
var types = Validator2.prototype.types = {};
var types = Validator3.prototype.types = {};
types.string = function testString(instance) {
return typeof instance == "string";
};
@@ -21091,7 +21091,7 @@ var require_validator = __commonJS({
types.object = function testObject(instance) {
return instance && typeof instance === "object" && !Array.isArray(instance) && !(instance instanceof Date);
};
module2.exports = Validator2;
module2.exports = Validator3;
}
});
@@ -21099,7 +21099,7 @@ var require_validator = __commonJS({
var require_lib2 = __commonJS({
"node_modules/jsonschema/lib/index.js"(exports2, module2) {
"use strict";
var Validator2 = module2.exports.Validator = require_validator();
var Validator3 = module2.exports.Validator = require_validator();
module2.exports.ValidatorResult = require_helpers().ValidatorResult;
module2.exports.ValidatorResultError = require_helpers().ValidatorResultError;
module2.exports.ValidationError = require_helpers().ValidationError;
@@ -21107,7 +21107,7 @@ var require_lib2 = __commonJS({
module2.exports.SchemaScanResult = require_scan().SchemaScanResult;
module2.exports.scan = require_scan().scan;
module2.exports.validate = function(instance, schema2, options) {
var v = new Validator2();
var v = new Validator3();
return v.validate(instance, schema2, options);
};
}
@@ -21899,14 +21899,14 @@ var require_dist_node4 = __commonJS({
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export2(dist_src_exports, {
RequestError: () => RequestError2
RequestError: () => RequestError
});
module2.exports = __toCommonJS2(dist_src_exports);
var import_deprecation = require_dist_node3();
var import_once = __toESM2(require_once());
var logOnceCode = (0, import_once.default)((deprecation) => console.warn(deprecation));
var logOnceHeaders = (0, import_once.default)((deprecation) => console.warn(deprecation));
var RequestError2 = class extends Error {
var RequestError = class extends Error {
constructor(message, statusCode, options) {
super(message);
if (Error.captureStackTrace) {
@@ -21998,7 +21998,7 @@ var require_dist_node5 = __commonJS({
const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value);
}
var import_request_error2 = require_dist_node4();
var import_request_error = require_dist_node4();
function getBufferResponse(response) {
return response.arrayBuffer();
}
@@ -22050,7 +22050,7 @@ var require_dist_node5 = __commonJS({
if (status < 400) {
return;
}
throw new import_request_error2.RequestError(response.statusText, status, {
throw new import_request_error.RequestError(response.statusText, status, {
response: {
url: url2,
status,
@@ -22061,7 +22061,7 @@ var require_dist_node5 = __commonJS({
});
}
if (status === 304) {
throw new import_request_error2.RequestError("Not modified", status, {
throw new import_request_error.RequestError("Not modified", status, {
response: {
url: url2,
status,
@@ -22073,7 +22073,7 @@ var require_dist_node5 = __commonJS({
}
if (status >= 400) {
const data = await getResponseData(response);
const error2 = new import_request_error2.RequestError(toErrorMessage(data), status, {
const error2 = new import_request_error.RequestError(toErrorMessage(data), status, {
response: {
url: url2,
status,
@@ -22093,7 +22093,7 @@ var require_dist_node5 = __commonJS({
data
};
}).catch((error2) => {
if (error2 instanceof import_request_error2.RequestError)
if (error2 instanceof import_request_error.RequestError)
throw error2;
else if (error2.name === "AbortError")
throw error2;
@@ -22105,7 +22105,7 @@ var require_dist_node5 = __commonJS({
message = error2.cause;
}
}
throw new import_request_error2.RequestError(message, 500, {
throw new import_request_error.RequestError(message, 500, {
request: requestOptions
});
});
@@ -22547,14 +22547,14 @@ var require_dist_node7 = __commonJS({
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export2(dist_src_exports, {
RequestError: () => RequestError2
RequestError: () => RequestError
});
module2.exports = __toCommonJS2(dist_src_exports);
var import_deprecation = require_dist_node3();
var import_once = __toESM2(require_once());
var logOnceCode = (0, import_once.default)((deprecation) => console.warn(deprecation));
var logOnceHeaders = (0, import_once.default)((deprecation) => console.warn(deprecation));
var RequestError2 = class extends Error {
var RequestError = class extends Error {
constructor(message, statusCode, options) {
super(message);
if (Error.captureStackTrace) {
@@ -22646,7 +22646,7 @@ var require_dist_node8 = __commonJS({
const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value);
}
var import_request_error2 = require_dist_node7();
var import_request_error = require_dist_node7();
function getBufferResponse(response) {
return response.arrayBuffer();
}
@@ -22698,7 +22698,7 @@ var require_dist_node8 = __commonJS({
if (status < 400) {
return;
}
throw new import_request_error2.RequestError(response.statusText, status, {
throw new import_request_error.RequestError(response.statusText, status, {
response: {
url: url2,
status,
@@ -22709,7 +22709,7 @@ var require_dist_node8 = __commonJS({
});
}
if (status === 304) {
throw new import_request_error2.RequestError("Not modified", status, {
throw new import_request_error.RequestError("Not modified", status, {
response: {
url: url2,
status,
@@ -22721,7 +22721,7 @@ var require_dist_node8 = __commonJS({
}
if (status >= 400) {
const data = await getResponseData(response);
const error2 = new import_request_error2.RequestError(toErrorMessage(data), status, {
const error2 = new import_request_error.RequestError(toErrorMessage(data), status, {
response: {
url: url2,
status,
@@ -22741,7 +22741,7 @@ var require_dist_node8 = __commonJS({
data
};
}).catch((error2) => {
if (error2 instanceof import_request_error2.RequestError)
if (error2 instanceof import_request_error.RequestError)
throw error2;
else if (error2.name === "AbortError")
throw error2;
@@ -22753,7 +22753,7 @@ var require_dist_node8 = __commonJS({
message = error2.cause;
}
}
throw new import_request_error2.RequestError(message, 500, {
throw new import_request_error.RequestError(message, 500, {
request: requestOptions
});
});
@@ -33606,7 +33606,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "4.30.9",
version: "4.30.10",
private: true,
description: "CodeQL action",
scripts: {
@@ -33654,7 +33654,7 @@ var require_package = __commonJS({
jsonschema: "1.4.1",
long: "^5.3.2",
"node-forge": "^1.3.1",
octokit: "^5.0.3",
octokit: "^5.0.4",
semver: "^7.7.3",
uuid: "^13.0.0"
},
@@ -33662,7 +33662,7 @@ var require_package = __commonJS({
"@ava/typescript": "6.0.0",
"@eslint/compat": "^1.4.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.37.0",
"@eslint/js": "^9.38.0",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"@octokit/types": "^15.0.0",
"@types/archiver": "^6.0.3",
@@ -33673,10 +33673,10 @@ var require_package = __commonJS({
"@types/node-forge": "^1.3.14",
"@types/semver": "^7.7.1",
"@types/sinon": "^17.0.4",
"@typescript-eslint/eslint-plugin": "^8.46.0",
"@typescript-eslint/eslint-plugin": "^8.46.1",
"@typescript-eslint/parser": "^8.41.0",
ava: "^6.4.1",
esbuild: "^0.25.10",
esbuild: "^0.25.11",
eslint: "^8.57.1",
"eslint-import-resolver-typescript": "^3.8.7",
"eslint-plugin-filenames": "^1.3.2",
@@ -35065,14 +35065,14 @@ var require_dist_node14 = __commonJS({
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export2(dist_src_exports, {
RequestError: () => RequestError2
RequestError: () => RequestError
});
module2.exports = __toCommonJS2(dist_src_exports);
var import_deprecation = require_dist_node3();
var import_once = __toESM2(require_once());
var logOnceCode = (0, import_once.default)((deprecation) => console.warn(deprecation));
var logOnceHeaders = (0, import_once.default)((deprecation) => console.warn(deprecation));
var RequestError2 = class extends Error {
var RequestError = class extends Error {
constructor(message, statusCode, options) {
super(message);
if (Error.captureStackTrace) {
@@ -35174,7 +35174,7 @@ var require_dist_node15 = __commonJS({
throw error2;
}
var import_light = __toESM2(require_light());
var import_request_error2 = require_dist_node14();
var import_request_error = require_dist_node14();
async function wrapRequest(state, octokit, request, options) {
const limiter = new import_light.default();
limiter.on("failed", function(error2, info4) {
@@ -35195,7 +35195,7 @@ var require_dist_node15 = __commonJS({
if (response.data && response.data.errors && response.data.errors.length > 0 && /Something went wrong while executing your query/.test(
response.data.errors[0].message
)) {
const error2 = new import_request_error2.RequestError(response.data.errors[0].message, 500, {
const error2 = new import_request_error.RequestError(response.data.errors[0].message, 500, {
request: options,
response
});
@@ -80921,14 +80921,14 @@ var require_tool_cache = __commonJS({
var assert_1 = require("assert");
var exec_1 = require_exec();
var retry_helper_1 = require_retry_helper();
var HTTPError = class extends Error {
var HTTPError2 = class extends Error {
constructor(httpStatusCode) {
super(`Unexpected HTTP response: ${httpStatusCode}`);
this.httpStatusCode = httpStatusCode;
Object.setPrototypeOf(this, new.target.prototype);
}
};
exports2.HTTPError = HTTPError;
exports2.HTTPError = HTTPError2;
var IS_WINDOWS = process.platform === "win32";
var IS_MAC = process.platform === "darwin";
var userAgent = "actions/tool-cache";
@@ -80945,7 +80945,7 @@ var require_tool_cache = __commonJS({
return yield retryHelper.execute(() => __awaiter4(this, void 0, void 0, function* () {
return yield downloadToolAttempt(url2, dest || "", auth, headers);
}), (err) => {
if (err instanceof HTTPError && err.httpStatusCode) {
if (err instanceof HTTPError2 && err.httpStatusCode) {
if (err.httpStatusCode < 500 && err.httpStatusCode !== 408 && err.httpStatusCode !== 429) {
return false;
}
@@ -80972,7 +80972,7 @@ var require_tool_cache = __commonJS({
}
const response = yield http.get(url2, headers);
if (response.message.statusCode !== 200) {
const err = new HTTPError(response.message.statusCode);
const err = new HTTPError2(response.message.statusCode);
core12.debug(`Failed to download from "${url2}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
throw err;
}
@@ -84865,7 +84865,7 @@ var path14 = __toESM(require("path"));
var url = __toESM(require("url"));
var import_zlib = __toESM(require("zlib"));
var core11 = __toESM(require_core());
var jsonschema = __toESM(require_lib2());
var jsonschema2 = __toESM(require_lib2());
// src/actions-util.ts
var fs4 = __toESM(require("fs"));
@@ -88328,13 +88328,28 @@ function getRequiredEnvParam(paramName) {
}
return value;
}
var HTTPError = class extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
};
var ConfigurationError = class extends Error {
constructor(message) {
super(message);
}
};
function isHTTPError(arg) {
return arg?.status !== void 0 && Number.isInteger(arg.status);
function asHTTPError(arg) {
if (typeof arg !== "object" || arg === null || typeof arg.message !== "string") {
return void 0;
}
if (Number.isInteger(arg.status)) {
return new HTTPError(arg.message, arg.status);
}
if (Number.isInteger(arg.httpStatusCode)) {
return new HTTPError(arg.message, arg.httpStatusCode);
}
return void 0;
}
var cachedCodeQlVersion = void 0;
function cacheCodeQlVersion(version) {
@@ -88747,14 +88762,24 @@ function computeAutomationID(analysis_key, environment) {
return automationID;
}
function wrapApiConfigurationError(e) {
if (isHTTPError(e)) {
if (e.message.includes("API rate limit exceeded for installation") || e.message.includes("commit not found") || e.message.includes("Resource not accessible by integration") || /ref .* not found in this repository/.test(e.message)) {
return new ConfigurationError(e.message);
} else if (e.message.includes("Bad credentials") || e.message.includes("Not Found")) {
const httpError = asHTTPError(e);
if (httpError !== void 0) {
if ([
/API rate limit exceeded/,
/commit not found/,
/Resource not accessible by integration/,
/ref .* not found in this repository/
].some((pattern) => pattern.test(httpError.message))) {
return new ConfigurationError(httpError.message);
}
if (httpError.message.includes("Bad credentials") || httpError.message.includes("Not Found")) {
return new ConfigurationError(
"Please check that your token is valid and has the required permissions: contents: read, security-events: write"
);
}
if (httpError.status === 429) {
return new ConfigurationError("API rate limit exceeded");
}
}
return e;
}
@@ -88765,45 +88790,6 @@ var path12 = __toESM(require("path"));
var core10 = __toESM(require_core());
var toolrunner3 = __toESM(require_toolrunner());
// node_modules/@octokit/request-error/dist-src/index.js
var RequestError = class extends Error {
name;
/**
* http status code
*/
status;
/**
* Request options that lead to the error.
*/
request;
/**
* Response object if a response was received
*/
response;
constructor(message, statusCode, options) {
super(message);
this.name = "HttpError";
this.status = Number.parseInt(statusCode);
if (Number.isNaN(this.status)) {
this.status = 0;
}
if ("response" in options) {
this.response = options.response;
}
const requestCopy = Object.assign({}, options.request);
if (options.request.headers.authorization) {
requestCopy.headers = Object.assign({}, options.request.headers, {
authorization: options.request.headers.authorization.replace(
/(?<! ) .*$/,
" [REDACTED]"
)
});
}
requestCopy.url = requestCopy.url.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]").replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
this.request = requestCopy;
}
};
// src/cli-errors.ts
var SUPPORTED_PLATFORMS = [
["linux", "x64"],
@@ -88971,6 +88957,9 @@ var cliErrorsConfig = {
cliErrorMessageCandidates: [
new RegExp(
"Query pack .* cannot be found\\. Check the spelling of the pack\\."
),
new RegExp(
"is not a .ql file, .qls file, a directory, or a query pack specification."
)
]
},
@@ -89049,6 +89038,7 @@ var path9 = __toESM(require("path"));
var core6 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver2 = __toESM(require_semver2());
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
@@ -89065,8 +89055,8 @@ var path8 = __toESM(require("path"));
var semver4 = __toESM(require_semver2());
// src/defaults.json
var bundleVersion = "codeql-bundle-v2.23.2";
var cliVersion = "2.23.2";
var bundleVersion = "codeql-bundle-v2.23.3";
var cliVersion = "2.23.3";
// src/overlay-database-utils.ts
var fs5 = __toESM(require("fs"));
@@ -89530,6 +89520,11 @@ var featureConfig = {
defaultValue: false,
envVar: "CODEQL_ACTION_JAVA_MINIMIZE_DEPENDENCY_JARS",
minimumVersion: "2.23.0"
},
["validate_db_config" /* ValidateDbConfig */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_VALIDATE_DB_CONFIG",
minimumVersion: void 0
}
};
@@ -90598,9 +90593,9 @@ async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliV
toolsVersion,
zstdAvailability
};
} catch (e) {
const ErrorClass = e instanceof ConfigurationError || e instanceof Error && e.message.includes("ENOSPC") || // out of disk space
e instanceof RequestError && e.status === 429 ? ConfigurationError : Error;
} catch (rawError) {
const e = wrapApiConfigurationError(rawError);
const ErrorClass = e instanceof ConfigurationError || e instanceof Error && e.message.includes("ENOSPC") ? ConfigurationError : Error;
throw new ErrorClass(
`Unable to download and extract CodeQL CLI: ${getErrorMessage(e)}${e instanceof Error && e.stack ? `
@@ -92520,16 +92515,17 @@ async function uploadPayload(payload, repositoryNwo, logger, analysis) {
logger.info("Successfully uploaded results");
return response.data.id;
} catch (e) {
if (isHTTPError(e)) {
switch (e.status) {
const httpError = asHTTPError(e);
if (httpError !== void 0) {
switch (httpError.status) {
case 403:
core11.warning(e.message || GENERIC_403_MSG);
core11.warning(httpError.message || GENERIC_403_MSG);
break;
case 404:
core11.warning(e.message || GENERIC_404_MSG);
core11.warning(httpError.message || GENERIC_404_MSG);
break;
default:
core11.warning(e.message);
core11.warning(httpError.message);
break;
}
}
@@ -92651,7 +92647,7 @@ function validateSarifFileSchema(sarif, sarifFilePath, logger) {
}
logger.info(`Validating ${sarifFilePath}`);
const schema2 = require_sarif_schema_2_1_0();
const result = new jsonschema.Validator().validate(sarif, schema2);
const result = new jsonschema2.Validator().validate(sarif, schema2);
const warningAttributes = ["uri-reference", "uri"];
const errors = (result.errors ?? []).filter(
(err) => !(err.name === "format" && typeof err.argument === "string" && warningAttributes.includes(err.argument))
+1311 -5
View File
File diff suppressed because it is too large Load Diff
+112 -114
View File
@@ -20602,14 +20602,14 @@ var require_dist_node4 = __commonJS({
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export2(dist_src_exports, {
RequestError: () => RequestError2
RequestError: () => RequestError
});
module2.exports = __toCommonJS2(dist_src_exports);
var import_deprecation = require_dist_node3();
var import_once = __toESM2(require_once());
var logOnceCode = (0, import_once.default)((deprecation) => console.warn(deprecation));
var logOnceHeaders = (0, import_once.default)((deprecation) => console.warn(deprecation));
var RequestError2 = class extends Error {
var RequestError = class extends Error {
constructor(message, statusCode, options) {
super(message);
if (Error.captureStackTrace) {
@@ -20701,7 +20701,7 @@ var require_dist_node5 = __commonJS({
const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value);
}
var import_request_error2 = require_dist_node4();
var import_request_error = require_dist_node4();
function getBufferResponse(response) {
return response.arrayBuffer();
}
@@ -20753,7 +20753,7 @@ var require_dist_node5 = __commonJS({
if (status < 400) {
return;
}
throw new import_request_error2.RequestError(response.statusText, status, {
throw new import_request_error.RequestError(response.statusText, status, {
response: {
url: url2,
status,
@@ -20764,7 +20764,7 @@ var require_dist_node5 = __commonJS({
});
}
if (status === 304) {
throw new import_request_error2.RequestError("Not modified", status, {
throw new import_request_error.RequestError("Not modified", status, {
response: {
url: url2,
status,
@@ -20776,7 +20776,7 @@ var require_dist_node5 = __commonJS({
}
if (status >= 400) {
const data = await getResponseData(response);
const error2 = new import_request_error2.RequestError(toErrorMessage(data), status, {
const error2 = new import_request_error.RequestError(toErrorMessage(data), status, {
response: {
url: url2,
status,
@@ -20796,7 +20796,7 @@ var require_dist_node5 = __commonJS({
data
};
}).catch((error2) => {
if (error2 instanceof import_request_error2.RequestError)
if (error2 instanceof import_request_error.RequestError)
throw error2;
else if (error2.name === "AbortError")
throw error2;
@@ -20808,7 +20808,7 @@ var require_dist_node5 = __commonJS({
message = error2.cause;
}
}
throw new import_request_error2.RequestError(message, 500, {
throw new import_request_error.RequestError(message, 500, {
request: requestOptions
});
});
@@ -21250,14 +21250,14 @@ var require_dist_node7 = __commonJS({
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export2(dist_src_exports, {
RequestError: () => RequestError2
RequestError: () => RequestError
});
module2.exports = __toCommonJS2(dist_src_exports);
var import_deprecation = require_dist_node3();
var import_once = __toESM2(require_once());
var logOnceCode = (0, import_once.default)((deprecation) => console.warn(deprecation));
var logOnceHeaders = (0, import_once.default)((deprecation) => console.warn(deprecation));
var RequestError2 = class extends Error {
var RequestError = class extends Error {
constructor(message, statusCode, options) {
super(message);
if (Error.captureStackTrace) {
@@ -21349,7 +21349,7 @@ var require_dist_node8 = __commonJS({
const Ctor = Object.prototype.hasOwnProperty.call(proto, "constructor") && proto.constructor;
return typeof Ctor === "function" && Ctor instanceof Ctor && Function.prototype.call(Ctor) === Function.prototype.call(value);
}
var import_request_error2 = require_dist_node7();
var import_request_error = require_dist_node7();
function getBufferResponse(response) {
return response.arrayBuffer();
}
@@ -21401,7 +21401,7 @@ var require_dist_node8 = __commonJS({
if (status < 400) {
return;
}
throw new import_request_error2.RequestError(response.statusText, status, {
throw new import_request_error.RequestError(response.statusText, status, {
response: {
url: url2,
status,
@@ -21412,7 +21412,7 @@ var require_dist_node8 = __commonJS({
});
}
if (status === 304) {
throw new import_request_error2.RequestError("Not modified", status, {
throw new import_request_error.RequestError("Not modified", status, {
response: {
url: url2,
status,
@@ -21424,7 +21424,7 @@ var require_dist_node8 = __commonJS({
}
if (status >= 400) {
const data = await getResponseData(response);
const error2 = new import_request_error2.RequestError(toErrorMessage(data), status, {
const error2 = new import_request_error.RequestError(toErrorMessage(data), status, {
response: {
url: url2,
status,
@@ -21444,7 +21444,7 @@ var require_dist_node8 = __commonJS({
data
};
}).catch((error2) => {
if (error2 instanceof import_request_error2.RequestError)
if (error2 instanceof import_request_error.RequestError)
throw error2;
else if (error2.name === "AbortError")
throw error2;
@@ -21456,7 +21456,7 @@ var require_dist_node8 = __commonJS({
message = error2.cause;
}
}
throw new import_request_error2.RequestError(message, 500, {
throw new import_request_error.RequestError(message, 500, {
request: requestOptions
});
});
@@ -32309,7 +32309,7 @@ var require_package = __commonJS({
"package.json"(exports2, module2) {
module2.exports = {
name: "codeql",
version: "4.30.9",
version: "4.30.10",
private: true,
description: "CodeQL action",
scripts: {
@@ -32357,7 +32357,7 @@ var require_package = __commonJS({
jsonschema: "1.4.1",
long: "^5.3.2",
"node-forge": "^1.3.1",
octokit: "^5.0.3",
octokit: "^5.0.4",
semver: "^7.7.3",
uuid: "^13.0.0"
},
@@ -32365,7 +32365,7 @@ var require_package = __commonJS({
"@ava/typescript": "6.0.0",
"@eslint/compat": "^1.4.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.37.0",
"@eslint/js": "^9.38.0",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"@octokit/types": "^15.0.0",
"@types/archiver": "^6.0.3",
@@ -32376,10 +32376,10 @@ var require_package = __commonJS({
"@types/node-forge": "^1.3.14",
"@types/semver": "^7.7.1",
"@types/sinon": "^17.0.4",
"@typescript-eslint/eslint-plugin": "^8.46.0",
"@typescript-eslint/eslint-plugin": "^8.46.1",
"@typescript-eslint/parser": "^8.41.0",
ava: "^6.4.1",
esbuild: "^0.25.10",
esbuild: "^0.25.11",
eslint: "^8.57.1",
"eslint-import-resolver-typescript": "^3.8.7",
"eslint-plugin-filenames": "^1.3.2",
@@ -33768,14 +33768,14 @@ var require_dist_node14 = __commonJS({
var __toCommonJS2 = (mod) => __copyProps2(__defProp2({}, "__esModule", { value: true }), mod);
var dist_src_exports = {};
__export2(dist_src_exports, {
RequestError: () => RequestError2
RequestError: () => RequestError
});
module2.exports = __toCommonJS2(dist_src_exports);
var import_deprecation = require_dist_node3();
var import_once = __toESM2(require_once());
var logOnceCode = (0, import_once.default)((deprecation) => console.warn(deprecation));
var logOnceHeaders = (0, import_once.default)((deprecation) => console.warn(deprecation));
var RequestError2 = class extends Error {
var RequestError = class extends Error {
constructor(message, statusCode, options) {
super(message);
if (Error.captureStackTrace) {
@@ -33877,7 +33877,7 @@ var require_dist_node15 = __commonJS({
throw error2;
}
var import_light = __toESM2(require_light());
var import_request_error2 = require_dist_node14();
var import_request_error = require_dist_node14();
async function wrapRequest(state, octokit, request, options) {
const limiter = new import_light.default();
limiter.on("failed", function(error2, info4) {
@@ -33898,7 +33898,7 @@ var require_dist_node15 = __commonJS({
if (response.data && response.data.errors && response.data.errors.length > 0 && /Something went wrong while executing your query/.test(
response.data.errors[0].message
)) {
const error2 = new import_request_error2.RequestError(response.data.errors[0].message, 500, {
const error2 = new import_request_error.RequestError(response.data.errors[0].message, 500, {
request: options,
response
});
@@ -80374,19 +80374,19 @@ var require_validator2 = __commonJS({
var SchemaError = helpers.SchemaError;
var SchemaContext = helpers.SchemaContext;
var anonymousBase = "/";
var Validator2 = function Validator3() {
this.customFormats = Object.create(Validator3.prototype.customFormats);
var Validator3 = function Validator4() {
this.customFormats = Object.create(Validator4.prototype.customFormats);
this.schemas = {};
this.unresolvedRefs = [];
this.types = Object.create(types);
this.attributes = Object.create(attribute.validators);
};
Validator2.prototype.customFormats = {};
Validator2.prototype.schemas = null;
Validator2.prototype.types = null;
Validator2.prototype.attributes = null;
Validator2.prototype.unresolvedRefs = null;
Validator2.prototype.addSchema = function addSchema(schema2, base) {
Validator3.prototype.customFormats = {};
Validator3.prototype.schemas = null;
Validator3.prototype.types = null;
Validator3.prototype.attributes = null;
Validator3.prototype.unresolvedRefs = null;
Validator3.prototype.addSchema = function addSchema(schema2, base) {
var self2 = this;
if (!schema2) {
return null;
@@ -80404,25 +80404,25 @@ var require_validator2 = __commonJS({
});
return this.schemas[ourUri];
};
Validator2.prototype.addSubSchemaArray = function addSubSchemaArray(baseuri, schemas) {
Validator3.prototype.addSubSchemaArray = function addSubSchemaArray(baseuri, schemas) {
if (!Array.isArray(schemas)) return;
for (var i = 0; i < schemas.length; i++) {
this.addSubSchema(baseuri, schemas[i]);
}
};
Validator2.prototype.addSubSchemaObject = function addSubSchemaArray(baseuri, schemas) {
Validator3.prototype.addSubSchemaObject = function addSubSchemaArray(baseuri, schemas) {
if (!schemas || typeof schemas != "object") return;
for (var p in schemas) {
this.addSubSchema(baseuri, schemas[p]);
}
};
Validator2.prototype.setSchemas = function setSchemas(schemas) {
Validator3.prototype.setSchemas = function setSchemas(schemas) {
this.schemas = schemas;
};
Validator2.prototype.getSchema = function getSchema(urn) {
Validator3.prototype.getSchema = function getSchema(urn) {
return this.schemas[urn];
};
Validator2.prototype.validate = function validate(instance, schema2, options, ctx) {
Validator3.prototype.validate = function validate(instance, schema2, options, ctx) {
if (typeof schema2 !== "boolean" && typeof schema2 !== "object" || schema2 === null) {
throw new SchemaError("Expected `schema` to be an object or boolean");
}
@@ -80460,7 +80460,7 @@ var require_validator2 = __commonJS({
if (typeof ref == "string") return ref;
return false;
}
Validator2.prototype.validateSchema = function validateSchema(instance, schema2, options, ctx) {
Validator3.prototype.validateSchema = function validateSchema(instance, schema2, options, ctx) {
var result = new ValidatorResult(instance, schema2, options, ctx);
if (typeof schema2 === "boolean") {
if (schema2 === true) {
@@ -80510,17 +80510,17 @@ var require_validator2 = __commonJS({
}
return result;
};
Validator2.prototype.schemaTraverser = function schemaTraverser(schemaobj, s) {
Validator3.prototype.schemaTraverser = function schemaTraverser(schemaobj, s) {
schemaobj.schema = helpers.deepMerge(schemaobj.schema, this.superResolve(s, schemaobj.ctx));
};
Validator2.prototype.superResolve = function superResolve(schema2, ctx) {
Validator3.prototype.superResolve = function superResolve(schema2, ctx) {
var ref = shouldResolve(schema2);
if (ref) {
return this.resolve(schema2, ref, ctx).subschema;
}
return schema2;
};
Validator2.prototype.resolve = function resolve6(schema2, switchSchema, ctx) {
Validator3.prototype.resolve = function resolve6(schema2, switchSchema, ctx) {
switchSchema = ctx.resolve(switchSchema);
if (ctx.schemas[switchSchema]) {
return { subschema: ctx.schemas[switchSchema], switchSchema };
@@ -80537,7 +80537,7 @@ var require_validator2 = __commonJS({
}
return { subschema, switchSchema };
};
Validator2.prototype.testType = function validateType(instance, schema2, options, ctx, type2) {
Validator3.prototype.testType = function validateType(instance, schema2, options, ctx, type2) {
if (type2 === void 0) {
return;
} else if (type2 === null) {
@@ -80552,7 +80552,7 @@ var require_validator2 = __commonJS({
}
return true;
};
var types = Validator2.prototype.types = {};
var types = Validator3.prototype.types = {};
types.string = function testString(instance) {
return typeof instance == "string";
};
@@ -80580,7 +80580,7 @@ var require_validator2 = __commonJS({
types.object = function testObject(instance) {
return instance && typeof instance === "object" && !Array.isArray(instance) && !(instance instanceof Date);
};
module2.exports = Validator2;
module2.exports = Validator3;
}
});
@@ -80588,7 +80588,7 @@ var require_validator2 = __commonJS({
var require_lib2 = __commonJS({
"node_modules/jsonschema/lib/index.js"(exports2, module2) {
"use strict";
var Validator2 = module2.exports.Validator = require_validator2();
var Validator3 = module2.exports.Validator = require_validator2();
module2.exports.ValidatorResult = require_helpers3().ValidatorResult;
module2.exports.ValidatorResultError = require_helpers3().ValidatorResultError;
module2.exports.ValidationError = require_helpers3().ValidationError;
@@ -80596,7 +80596,7 @@ var require_lib2 = __commonJS({
module2.exports.SchemaScanResult = require_scan2().SchemaScanResult;
module2.exports.scan = require_scan2().scan;
module2.exports.validate = function(instance, schema2, options) {
var v = new Validator2();
var v = new Validator3();
return v.validate(instance, schema2, options);
};
}
@@ -80921,14 +80921,14 @@ var require_tool_cache = __commonJS({
var assert_1 = require("assert");
var exec_1 = require_exec();
var retry_helper_1 = require_retry_helper();
var HTTPError = class extends Error {
var HTTPError2 = class extends Error {
constructor(httpStatusCode) {
super(`Unexpected HTTP response: ${httpStatusCode}`);
this.httpStatusCode = httpStatusCode;
Object.setPrototypeOf(this, new.target.prototype);
}
};
exports2.HTTPError = HTTPError;
exports2.HTTPError = HTTPError2;
var IS_WINDOWS = process.platform === "win32";
var IS_MAC = process.platform === "darwin";
var userAgent = "actions/tool-cache";
@@ -80945,7 +80945,7 @@ var require_tool_cache = __commonJS({
return yield retryHelper.execute(() => __awaiter4(this, void 0, void 0, function* () {
return yield downloadToolAttempt(url2, dest || "", auth, headers);
}), (err) => {
if (err instanceof HTTPError && err.httpStatusCode) {
if (err instanceof HTTPError2 && err.httpStatusCode) {
if (err.httpStatusCode < 500 && err.httpStatusCode !== 408 && err.httpStatusCode !== 429) {
return false;
}
@@ -80972,7 +80972,7 @@ var require_tool_cache = __commonJS({
}
const response = yield http.get(url2, headers);
if (response.message.statusCode !== 200) {
const err = new HTTPError(response.message.statusCode);
const err = new HTTPError2(response.message.statusCode);
core14.debug(`Failed to download from "${url2}". Code(${response.message.statusCode}) Message(${response.message.statusMessage})`);
throw err;
}
@@ -88444,13 +88444,28 @@ function getRequiredEnvParam(paramName) {
}
return value;
}
var HTTPError = class extends Error {
constructor(message, status) {
super(message);
this.status = status;
}
};
var ConfigurationError = class extends Error {
constructor(message) {
super(message);
}
};
function isHTTPError(arg) {
return arg?.status !== void 0 && Number.isInteger(arg.status);
function asHTTPError(arg) {
if (typeof arg !== "object" || arg === null || typeof arg.message !== "string") {
return void 0;
}
if (Number.isInteger(arg.status)) {
return new HTTPError(arg.message, arg.status);
}
if (Number.isInteger(arg.httpStatusCode)) {
return new HTTPError(arg.message, arg.httpStatusCode);
}
return void 0;
}
var cachedCodeQlVersion = void 0;
function cacheCodeQlVersion(version) {
@@ -88958,14 +88973,24 @@ function computeAutomationID(analysis_key, environment) {
return automationID;
}
function wrapApiConfigurationError(e) {
if (isHTTPError(e)) {
if (e.message.includes("API rate limit exceeded for installation") || e.message.includes("commit not found") || e.message.includes("Resource not accessible by integration") || /ref .* not found in this repository/.test(e.message)) {
return new ConfigurationError(e.message);
} else if (e.message.includes("Bad credentials") || e.message.includes("Not Found")) {
const httpError = asHTTPError(e);
if (httpError !== void 0) {
if ([
/API rate limit exceeded/,
/commit not found/,
/Resource not accessible by integration/,
/ref .* not found in this repository/
].some((pattern) => pattern.test(httpError.message))) {
return new ConfigurationError(httpError.message);
}
if (httpError.message.includes("Bad credentials") || httpError.message.includes("Not Found")) {
return new ConfigurationError(
"Please check that your token is valid and has the required permissions: contents: read, security-events: write"
);
}
if (httpError.status === 429) {
return new ConfigurationError("API rate limit exceeded");
}
}
return e;
}
@@ -88976,8 +89001,8 @@ var path8 = __toESM(require("path"));
var semver3 = __toESM(require_semver2());
// src/defaults.json
var bundleVersion = "codeql-bundle-v2.23.2";
var cliVersion = "2.23.2";
var bundleVersion = "codeql-bundle-v2.23.3";
var cliVersion = "2.23.3";
// src/overlay-database-utils.ts
var fs5 = __toESM(require("fs"));
@@ -89446,6 +89471,11 @@ var featureConfig = {
defaultValue: false,
envVar: "CODEQL_ACTION_JAVA_MINIMIZE_DEPENDENCY_JARS",
minimumVersion: "2.23.0"
},
["validate_db_config" /* ValidateDbConfig */]: {
defaultValue: false,
envVar: "CODEQL_ACTION_VALIDATE_DB_CONFIG",
minimumVersion: void 0
}
};
var FEATURE_FLAGS_FILE_NAME = "cached-feature-flags.json";
@@ -89698,9 +89728,10 @@ var GitHubFeatureFlags = class {
this.hasAccessedRemoteFeatureFlags = true;
return remoteFlags;
} catch (e) {
if (isHTTPError(e) && e.status === 403) {
const httpError = asHTTPError(e);
if (httpError?.status === 403) {
this.logger.warning(
`This run of the CodeQL Action does not have permission to access Code Scanning API endpoints. As a result, it will not be opted into any experimental features. This could be because the Action is running on a pull request from a fork. If not, please ensure the Action has the 'security-events: write' permission. Details: ${e.message}`
`This run of the CodeQL Action does not have permission to access Code Scanning API endpoints. As a result, it will not be opted into any experimental features. This could be because the Action is running on a pull request from a fork. If not, please ensure the Action has the 'security-events: write' permission. Details: ${httpError.message}`
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
@@ -89725,6 +89756,7 @@ var path10 = __toESM(require("path"));
var core8 = __toESM(require_core());
// src/config/db-config.ts
var jsonschema = __toESM(require_lib2());
var semver4 = __toESM(require_semver2());
var PACK_IDENTIFIER_PATTERN = (function() {
const alphaNumeric = "[a-z0-9]";
@@ -89972,19 +90004,20 @@ async function sendStatusReport(statusReport) {
}
);
} catch (e) {
if (isHTTPError(e)) {
switch (e.status) {
const httpError = asHTTPError(e);
if (httpError !== void 0) {
switch (httpError.status) {
case 403:
if (getWorkflowEventName() === "push" && process.env["GITHUB_ACTOR"] === "dependabot[bot]") {
core9.warning(
`Workflows triggered by Dependabot on the "push" event run with read-only access. Uploading Code Scanning results requires write access. To use Code Scanning with Dependabot, please ensure you are using the "pull_request" event for this workflow and avoid triggering on the "push" event for Dependabot branches. See ${"https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#scanning-on-push" /* SCANNING_ON_PUSH */} for more information on how to configure these events.`
);
} else {
core9.warning(e.message);
core9.warning(httpError.message);
}
return;
case 404:
core9.warning(e.message);
core9.warning(httpError.message);
return;
case 422:
if (getRequiredEnvParam("GITHUB_SERVER_URL") !== GITHUB_DOTCOM_URL) {
@@ -90009,7 +90042,7 @@ var path15 = __toESM(require("path"));
var url = __toESM(require("url"));
var import_zlib = __toESM(require("zlib"));
var core12 = __toESM(require_core());
var jsonschema = __toESM(require_lib2());
var jsonschema2 = __toESM(require_lib2());
// src/codeql.ts
var fs12 = __toESM(require("fs"));
@@ -90017,45 +90050,6 @@ var path13 = __toESM(require("path"));
var core11 = __toESM(require_core());
var toolrunner3 = __toESM(require_toolrunner());
// node_modules/@octokit/request-error/dist-src/index.js
var RequestError = class extends Error {
name;
/**
* http status code
*/
status;
/**
* Request options that lead to the error.
*/
request;
/**
* Response object if a response was received
*/
response;
constructor(message, statusCode, options) {
super(message);
this.name = "HttpError";
this.status = Number.parseInt(statusCode);
if (Number.isNaN(this.status)) {
this.status = 0;
}
if ("response" in options) {
this.response = options.response;
}
const requestCopy = Object.assign({}, options.request);
if (options.request.headers.authorization) {
requestCopy.headers = Object.assign({}, options.request.headers, {
authorization: options.request.headers.authorization.replace(
/(?<! ) .*$/,
" [REDACTED]"
)
});
}
requestCopy.url = requestCopy.url.replace(/\bclient_secret=\w+/g, "client_secret=[REDACTED]").replace(/\baccess_token=\w+/g, "access_token=[REDACTED]");
this.request = requestCopy;
}
};
// src/cli-errors.ts
var SUPPORTED_PLATFORMS = [
["linux", "x64"],
@@ -90223,6 +90217,9 @@ var cliErrorsConfig = {
cliErrorMessageCandidates: [
new RegExp(
"Query pack .* cannot be found\\. Check the spelling of the pack\\."
),
new RegExp(
"is not a .ql file, .qls file, a directory, or a query pack specification."
)
]
},
@@ -91269,9 +91266,9 @@ async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliV
toolsVersion,
zstdAvailability
};
} catch (e) {
const ErrorClass = e instanceof ConfigurationError || e instanceof Error && e.message.includes("ENOSPC") || // out of disk space
e instanceof RequestError && e.status === 429 ? ConfigurationError : Error;
} catch (rawError) {
const e = wrapApiConfigurationError(rawError);
const ErrorClass = e instanceof ConfigurationError || e instanceof Error && e.message.includes("ENOSPC") ? ConfigurationError : Error;
throw new ErrorClass(
`Unable to download and extract CodeQL CLI: ${getErrorMessage(e)}${e instanceof Error && e.stack ? `
@@ -93191,16 +93188,17 @@ async function uploadPayload(payload, repositoryNwo, logger, analysis) {
logger.info("Successfully uploaded results");
return response.data.id;
} catch (e) {
if (isHTTPError(e)) {
switch (e.status) {
const httpError = asHTTPError(e);
if (httpError !== void 0) {
switch (httpError.status) {
case 403:
core12.warning(e.message || GENERIC_403_MSG);
core12.warning(httpError.message || GENERIC_403_MSG);
break;
case 404:
core12.warning(e.message || GENERIC_404_MSG);
core12.warning(httpError.message || GENERIC_404_MSG);
break;
default:
core12.warning(e.message);
core12.warning(httpError.message);
break;
}
}
@@ -93305,7 +93303,7 @@ function validateSarifFileSchema(sarif, sarifFilePath, logger) {
}
logger.info(`Validating ${sarifFilePath}`);
const schema2 = require_sarif_schema_2_1_0();
const result = new jsonschema.Validator().validate(sarif, schema2);
const result = new jsonschema2.Validator().validate(sarif, schema2);
const warningAttributes = ["uri-reference", "uri"];
const errors = (result.errors ?? []).filter(
(err) => !(err.name === "format" && typeof err.argument === "string" && warningAttributes.includes(err.argument))
+418 -540
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "4.30.9",
"version": "4.30.10",
"private": true,
"description": "CodeQL action",
"scripts": {
@@ -48,7 +48,7 @@
"jsonschema": "1.4.1",
"long": "^5.3.2",
"node-forge": "^1.3.1",
"octokit": "^5.0.3",
"octokit": "^5.0.4",
"semver": "^7.7.3",
"uuid": "^13.0.0"
},
@@ -56,7 +56,7 @@
"@ava/typescript": "6.0.0",
"@eslint/compat": "^1.4.0",
"@eslint/eslintrc": "^3.3.1",
"@eslint/js": "^9.37.0",
"@eslint/js": "^9.38.0",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"@octokit/types": "^15.0.0",
"@types/archiver": "^6.0.3",
@@ -67,10 +67,10 @@
"@types/node-forge": "^1.3.14",
"@types/semver": "^7.7.1",
"@types/sinon": "^17.0.4",
"@typescript-eslint/eslint-plugin": "^8.46.0",
"@typescript-eslint/eslint-plugin": "^8.46.1",
"@typescript-eslint/parser": "^8.41.0",
"ava": "^6.4.1",
"esbuild": "^0.25.10",
"esbuild": "^0.25.11",
"eslint": "^8.57.1",
"eslint-import-resolver-typescript": "^3.8.7",
"eslint-plugin-filenames": "^1.3.2",
+1
View File
@@ -2,6 +2,7 @@ name: "Analyze: 'ref' and 'sha' from inputs"
description: "Checks that specifying 'ref' and 'sha' as inputs works"
versions: ["default"]
installGo: true
installPython: true
steps:
- uses: ./../action/init
with:
+2 -3
View File
@@ -15,10 +15,9 @@ steps:
if (allCodeqlVersions.length === 0) {
throw new Error(`CodeQL could not be found in the toolcache`);
}
- id: init
uses: ./../action/init
- id: setup-codeql
uses: ./../action/setup-codeql
with:
languages: javascript
tools: ${{ steps.prepare-test.outputs.tools-url }}
- name: Check CodeQL is installed within the toolcache
uses: actions/github-script@v8
+1
View File
@@ -2,6 +2,7 @@ name: "Local CodeQL bundle"
description: "Tests using a CodeQL bundle from a local file rather than a URL"
versions: ["linked"]
installGo: true
installPython: true
steps:
- name: Fetch latest CodeQL bundle
run: |
@@ -4,6 +4,7 @@ operatingSystems: ["macos", "ubuntu"]
env:
CODEQL_ACTION_RESOLVE_SUPPORTED_LANGUAGES_USING_CLI: true
installGo: true
installPython: true
steps:
- name: Use Xcode 16
if: runner.os == 'macOS' && matrix.version != 'nightly-latest'
@@ -3,6 +3,7 @@ description: "Checks that specifying packages using a combination of a config fi
versions: ["linked", "default", "nightly-latest"] # This feature is not compatible with old CLIs
installGo: true
installNode: true
installPython: true
steps:
- uses: ./../action/init
with:
+1
View File
@@ -6,6 +6,7 @@ versions:
- linked
- nightly-latest
installGo: true
installPython: true
steps:
- uses: ./../action/init
with:
+1
View File
@@ -6,6 +6,7 @@ versions:
- linked
- nightly-latest
installGo: true
installPython: true
steps:
- uses: ./../action/init
id: init
@@ -2,6 +2,7 @@ name: "Upload-sarif: 'ref' and 'sha' from inputs"
description: "Checks that specifying 'ref' and 'sha' as inputs works"
versions: ["default"]
installGo: true
installPython: true
steps:
- uses: ./../action/init
with:
+1
View File
@@ -3,6 +3,7 @@ description: "Checks that uploading SARIFs to the code quality endpoint works"
versions: ["default"]
analysisKinds: ["code-scanning", "code-quality", "code-scanning,code-quality"]
installGo: true
installPython: true
steps:
- uses: ./../action/init
with:
+1
View File
@@ -2,6 +2,7 @@ name: "Use a custom `checkout_path`"
description: "Checks that a custom `checkout_path` will find the proper commit_oid"
versions: ["linked"]
installGo: true
installPython: true
steps:
# This ensures we don't accidentally use the original checkout for any part of the test.
- name: Delete original checkout
+21 -1
View File
@@ -117,7 +117,7 @@ for file in sorted((this_dir / 'checks').glob('*.yml')):
steps.extend([
{
'name': 'Install Node.js',
'uses': 'actions/setup-node@v5',
'uses': 'actions/setup-node@v6',
'with': {
'node-version': '20.x',
'cache': 'npm',
@@ -184,6 +184,26 @@ for file in sorted((this_dir / 'checks').glob('*.yml')):
}
})
installPython = is_truthy(checkSpecification.get('installPython', ''))
if installPython:
basePythonVersionExpr = '3.13'
workflowInputs['python-version'] = {
'type': 'string',
'description': 'The version of Python to install',
'required': False,
'default': basePythonVersionExpr,
}
steps.append({
'name': 'Install Python',
'if': 'matrix.version != \'nightly-latest\'',
'uses': 'actions/setup-python@v6',
'with': {
'python-version': '${{ inputs.python-version || \'' + basePythonVersionExpr + '\' }}'
}
})
# If container initialisation steps are present in the check specification,
# make sure to execute them first.
if 'container' in checkSpecification and 'container-init-steps' in checkSpecification:
+39
View File
@@ -0,0 +1,39 @@
name: 'CodeQL: Setup'
description: 'Installs the CodeQL CLI'
author: 'GitHub'
inputs:
tools:
description: >-
By default, the Action will use the recommended version of the CodeQL
Bundle to analyze your project. You can override this choice using this
input. One of:
- A local path to a CodeQL Bundle tarball, or
- The URL of a CodeQL Bundle tarball GitHub release asset, or
- A special value `linked` which uses the version of the CodeQL tools
that the Action has been bundled with.
- A special value `nightly` which uses the latest nightly version of the
CodeQL tools. Note that this is unstable and not recommended for
production use.
If not specified, the Action will check in several places until it finds
the CodeQL tools.
required: false
token:
description: GitHub token to use for authenticating with this instance of GitHub.
default: ${{ github.token }}
required: false
matrix:
default: ${{ toJson(matrix) }}
required: false
external-repository-token:
description: A token for fetching additional files from private repositories in the same GitHub instance that is running this action.
required: false
outputs:
codeql-path:
description: The path of the CodeQL binary that was installed.
codeql-version:
description: The version of the CodeQL binary that was installed.
runs:
using: node24
main: '../lib/setup-codeql-action.js'
+33
View File
@@ -1,12 +1,19 @@
import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import {
AnalysisKind,
getAnalysisKinds,
parseAnalysisKinds,
supportedAnalysisKinds,
} from "./analyses";
import { getRunnerLogger } from "./logging";
import { setupTests } from "./testing-utils";
import { ConfigurationError } from "./util";
setupTests(test);
test("All known analysis kinds can be parsed successfully", async (t) => {
for (const analysisKind of supportedAnalysisKinds) {
t.deepEqual(await parseAnalysisKinds(analysisKind), [analysisKind]);
@@ -34,3 +41,29 @@ test("Parsing analysis kinds requires at least one analysis kind", async (t) =>
instanceOf: ConfigurationError,
});
});
test("getAnalysisKinds - returns expected analysis kinds for `analysis-kinds` input", async (t) => {
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
requiredInputStub
.withArgs("analysis-kinds")
.returns("code-scanning,code-quality");
const result = await getAnalysisKinds(getRunnerLogger(true), true);
t.assert(result.includes(AnalysisKind.CodeScanning));
t.assert(result.includes(AnalysisKind.CodeQuality));
});
test("getAnalysisKinds - includes `code-quality` when deprecated `quality-queries` input is used", async (t) => {
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
requiredInputStub.withArgs("analysis-kinds").returns("code-scanning");
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
optionalInputStub.withArgs("quality-queries").returns("code-quality");
const result = await getAnalysisKinds(getRunnerLogger(true), true);
t.assert(result.includes(AnalysisKind.CodeScanning));
t.assert(result.includes(AnalysisKind.CodeQuality));
});
test("getAnalysisKinds - throws if `analysis-kinds` input is invalid", async (t) => {
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
requiredInputStub.withArgs("analysis-kinds").returns("no-such-thing");
await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true));
});
+54 -1
View File
@@ -1,4 +1,8 @@
import { fixCodeQualityCategory } from "./actions-util";
import {
fixCodeQualityCategory,
getOptionalInput,
getRequiredInput,
} from "./actions-util";
import { Logger } from "./logging";
import { ConfigurationError } from "./util";
@@ -41,6 +45,55 @@ export async function parseAnalysisKinds(
);
}
// Used to avoid re-parsing the input after we have done it once.
let cachedAnalysisKinds: AnalysisKind[] | undefined;
/**
* Initialises the analysis kinds for the analysis based on the `analysis-kinds` input.
* This function will also use the deprecated `quality-queries` input as an indicator to enable `code-quality`.
* If the `analysis-kinds` input cannot be parsed, a `ConfigurationError` is thrown.
*
* @param logger The logger to use.
* @param skipCache For testing, whether to ignore the cached values (default: false).
*
* @returns The array of enabled analysis kinds.
* @throws A `ConfigurationError` if the `analysis-kinds` input cannot be parsed.
*/
export async function getAnalysisKinds(
logger: Logger,
skipCache: boolean = false,
): Promise<AnalysisKind[]> {
if (!skipCache && cachedAnalysisKinds !== undefined) {
return cachedAnalysisKinds;
}
cachedAnalysisKinds = await parseAnalysisKinds(
getRequiredInput("analysis-kinds"),
);
// Warn that `quality-queries` is deprecated if there is an argument for it.
const qualityQueriesInput = getOptionalInput("quality-queries");
if (qualityQueriesInput !== undefined) {
logger.warning(
"The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. " +
"Use the `analysis-kinds` input to configure different analysis kinds instead.",
);
}
// For backwards compatibility, add Code Quality to the enabled analysis kinds
// if an input to `quality-queries` was specified. We should remove this once
// `quality-queries` is no longer used.
if (
!cachedAnalysisKinds.includes(AnalysisKind.CodeQuality) &&
qualityQueriesInput !== undefined
) {
cachedAnalysisKinds.push(AnalysisKind.CodeQuality);
}
return cachedAnalysisKinds;
}
/** The queries to use for Code Quality analyses. */
export const codeQualityQueries: string[] = ["code-quality"];
+17 -10
View File
@@ -7,12 +7,12 @@ import { getActionVersion, getRequiredInput } from "./actions-util";
import { Logger } from "./logging";
import { getRepositoryNwo, RepositoryNwo } from "./repository";
import {
asHTTPError,
ConfigurationError,
getRequiredEnvParam,
GITHUB_DOTCOM_URL,
GitHubVariant,
GitHubVersion,
isHTTPError,
parseGitHubUrl,
parseMatrixInput,
} from "./util";
@@ -280,22 +280,29 @@ export async function getRepositoryProperties(repositoryNwo: RepositoryNwo) {
}
export function wrapApiConfigurationError(e: unknown) {
if (isHTTPError(e)) {
const httpError = asHTTPError(e);
if (httpError !== undefined) {
if (
e.message.includes("API rate limit exceeded for installation") ||
e.message.includes("commit not found") ||
e.message.includes("Resource not accessible by integration") ||
/ref .* not found in this repository/.test(e.message)
[
/API rate limit exceeded/,
/commit not found/,
/Resource not accessible by integration/,
/ref .* not found in this repository/,
].some((pattern) => pattern.test(httpError.message))
) {
return new ConfigurationError(e.message);
} else if (
e.message.includes("Bad credentials") ||
e.message.includes("Not Found")
return new ConfigurationError(httpError.message);
}
if (
httpError.message.includes("Bad credentials") ||
httpError.message.includes("Not Found")
) {
return new ConfigurationError(
"Please check that your token is valid and has the required permissions: contents: read, security-events: write",
);
}
if (httpError.status === 429) {
return new ConfigurationError("API rate limit exceeded");
}
}
return e;
}
+14
View File
@@ -310,6 +310,20 @@ test("wrapCliConfigurationError - pack cannot be found", (t) => {
t.true(wrappedError instanceof ConfigurationError);
});
test("wrapCliConfigurationError - unknown query file", (t) => {
const commandError = new CommandInvocationError(
"codeql",
["database", "init"],
2,
"my-query-file is not a .ql file, .qls file, a directory, or a query pack specification. See the logs for more details.",
);
const cliError = new CliError(commandError);
const wrappedError = wrapCliConfigurationError(cliError);
t.true(wrappedError instanceof ConfigurationError);
});
test("wrapCliConfigurationError - pack missing auth", (t) => {
const commandError = new CommandInvocationError(
"codeql",
+3
View File
@@ -264,6 +264,9 @@ export const cliErrorsConfig: Record<
new RegExp(
"Query pack .* cannot be found\\. Check the spelling of the pack\\.",
),
new RegExp(
"is not a .ql file, .qls file, a directory, or a query pack specification.",
),
],
},
[CliConfigErrorCategory.PackMissingAuth]: {
+3 -4
View File
@@ -3,7 +3,6 @@ import * as path from "path";
import * as core from "@actions/core";
import * as toolrunner from "@actions/exec/lib/toolrunner";
import { RequestError } from "@octokit/request-error";
import * as yaml from "js-yaml";
import {
@@ -371,11 +370,11 @@ export async function setupCodeQL(
toolsVersion,
zstdAvailability,
};
} catch (e) {
} catch (rawError) {
const e = api.wrapApiConfigurationError(rawError);
const ErrorClass =
e instanceof util.ConfigurationError ||
(e instanceof Error && e.message.includes("ENOSPC")) || // out of disk space
(e instanceof RequestError && e.status === 429) // rate limited
(e instanceof Error && e.message.includes("ENOSPC")) // out of disk space
? util.ConfigurationError
: Error;
+18 -4
View File
@@ -49,10 +49,9 @@ function createTestInitConfigInputs(
return Object.assign(
{},
{
analysisKindsInput: "code-scanning",
analysisKinds: [AnalysisKind.CodeScanning],
languagesInput: undefined,
queriesInput: undefined,
qualityQueriesInput: undefined,
packsInput: undefined,
configFile: undefined,
dbLocation: undefined,
@@ -149,6 +148,7 @@ test("load empty config", async (t) => {
});
const config = await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput: languages,
repository: { owner: "github", repo: "example" },
@@ -188,8 +188,9 @@ test("load code quality config", async (t) => {
});
const config = await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
analysisKindsInput: "code-quality",
analysisKinds: [AnalysisKind.CodeQuality],
languagesInput: languages,
repository: { owner: "github", repo: "example" },
tempDir,
@@ -272,8 +273,9 @@ test("initActionState doesn't throw if there are queries configured in the repos
await t.notThrowsAsync(async () => {
const config = await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
analysisKindsInput: "code-quality",
analysisKinds: [AnalysisKind.CodeQuality],
languagesInput: languages,
repository: { owner: "github", repo: "example" },
tempDir,
@@ -310,6 +312,7 @@ test("loading a saved config produces the same config", async (t) => {
t.deepEqual(await configUtils.getConfig(tempDir, logger), undefined);
const config1 = await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput: "javascript,python",
tempDir,
@@ -361,6 +364,7 @@ test("loading config with version mismatch throws", async (t) => {
.returns("does-not-exist");
const config = await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput: "javascript,python",
tempDir,
@@ -389,6 +393,7 @@ test("load input outside of workspace", async (t) => {
return await withTmpDir(async (tempDir) => {
try {
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
configFile: "../input",
tempDir,
@@ -416,6 +421,7 @@ test("load non-local input with invalid repo syntax", async (t) => {
try {
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
configFile,
tempDir,
@@ -444,6 +450,7 @@ test("load non-existent input", async (t) => {
try {
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput,
configFile,
@@ -527,6 +534,7 @@ test("load non-empty input", async (t) => {
const configFilePath = createConfigFile(inputFileContents, tempDir);
const actualConfig = await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput,
buildModeInput: "none",
@@ -583,6 +591,7 @@ test("Using config input and file together, config input should be used.", async
const languagesInput = "javascript";
const config = await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput,
configFile: configFilePath,
@@ -633,6 +642,7 @@ test("API client used when reading remote config", async (t) => {
const languagesInput = "javascript";
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput,
configFile,
@@ -653,6 +663,7 @@ test("Remote config handles the case where a directory is provided", async (t) =
const repoReference = "octo-org/codeql-config/config.yaml@main";
try {
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
configFile: repoReference,
tempDir,
@@ -681,6 +692,7 @@ test("Invalid format of remote config handled correctly", async (t) => {
const repoReference = "octo-org/codeql-config/config.yaml@main";
try {
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
configFile: repoReference,
tempDir,
@@ -710,6 +722,7 @@ test("No detected languages", async (t) => {
try {
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
tempDir,
codeql,
@@ -732,6 +745,7 @@ test("Unknown languages", async (t) => {
try {
await configUtils.initConfig(
createFeatures([]),
createTestInitConfigInputs({
languagesInput,
tempDir,
+37 -24
View File
@@ -11,7 +11,6 @@ import {
CodeQuality,
codeQualityQueries,
CodeScanning,
parseAnalysisKinds,
} from "./analyses";
import * as api from "./api-client";
import { CachingKind, getCachingKind } from "./caching-utils";
@@ -20,6 +19,7 @@ import {
calculateAugmentation,
ExcludeQueryFilter,
generateCodeScanningConfig,
parseUserConfig,
UserConfig,
} from "./config/db-config";
import { shouldPerformDiffInformedAnalysis } from "./diff-informed-analysis-utils";
@@ -373,10 +373,8 @@ export async function getRawLanguages(
/** Inputs required to initialize a configuration. */
export interface InitConfigInputs {
analysisKindsInput: string;
languagesInput: string | undefined;
queriesInput: string | undefined;
qualityQueriesInput: string | undefined;
packsInput: string | undefined;
configFile: string | undefined;
dbLocation: string | undefined;
@@ -396,6 +394,7 @@ export interface InitConfigInputs {
apiDetails: api.GitHubApiCombinedDetails;
features: FeatureEnablement;
repositoryProperties: RepositoryProperties;
analysisKinds: AnalysisKind[];
logger: Logger;
}
@@ -405,10 +404,8 @@ export interface InitConfigInputs {
*/
export async function initActionState(
{
analysisKindsInput,
languagesInput,
queriesInput,
qualityQueriesInput,
packsInput,
buildModeInput,
dbLocation,
@@ -424,22 +421,11 @@ export async function initActionState(
githubVersion,
features,
repositoryProperties,
analysisKinds,
logger,
}: InitConfigInputs,
userConfig: UserConfig,
): Promise<Config> {
const analysisKinds = await parseAnalysisKinds(analysisKindsInput);
// For backwards compatibility, add Code Quality to the enabled analysis kinds
// if an input to `quality-queries` was specified. We should remove this once
// `quality-queries` is no longer used.
if (
!analysisKinds.includes(AnalysisKind.CodeQuality) &&
qualityQueriesInput !== undefined
) {
analysisKinds.push(AnalysisKind.CodeQuality);
}
const languages = await getLanguages(
codeql,
languagesInput,
@@ -540,10 +526,12 @@ async function downloadCacheWithTime(
}
async function loadUserConfig(
logger: Logger,
configFile: string,
workspacePath: string,
apiDetails: api.GitHubApiCombinedDetails,
tempDir: string,
validateConfig: boolean,
): Promise<UserConfig> {
if (isLocal(configFile)) {
if (configFile !== userConfigFromActionPath(tempDir)) {
@@ -556,9 +544,14 @@ async function loadUserConfig(
);
}
}
return getLocalConfig(configFile);
return getLocalConfig(logger, configFile, validateConfig);
} else {
return await getRemoteConfig(configFile, apiDetails);
return await getRemoteConfig(
logger,
configFile,
apiDetails,
validateConfig,
);
}
}
@@ -794,7 +787,10 @@ function hasQueryCustomisation(userConfig: UserConfig): boolean {
* This will parse the config from the user input if present, or generate
* a default config. The parsed config is then stored to a known location.
*/
export async function initConfig(inputs: InitConfigInputs): Promise<Config> {
export async function initConfig(
features: FeatureEnablement,
inputs: InitConfigInputs,
): Promise<Config> {
const { logger, tempDir } = inputs;
// if configInput is set, it takes precedence over configFile
@@ -814,11 +810,14 @@ export async function initConfig(inputs: InitConfigInputs): Promise<Config> {
logger.debug("No configuration file was provided");
} else {
logger.debug(`Using configuration file: ${inputs.configFile}`);
const validateConfig = await features.getValue(Feature.ValidateDbConfig);
userConfig = await loadUserConfig(
logger,
inputs.configFile,
inputs.workspacePath,
inputs.apiDetails,
tempDir,
validateConfig,
);
}
@@ -912,7 +911,11 @@ function isLocal(configPath: string): boolean {
return configPath.indexOf("@") === -1;
}
function getLocalConfig(configFile: string): UserConfig {
function getLocalConfig(
logger: Logger,
configFile: string,
validateConfig: boolean,
): UserConfig {
// Error if the file does not exist
if (!fs.existsSync(configFile)) {
throw new ConfigurationError(
@@ -920,12 +923,19 @@ function getLocalConfig(configFile: string): UserConfig {
);
}
return yaml.load(fs.readFileSync(configFile, "utf8")) as UserConfig;
return parseUserConfig(
logger,
configFile,
fs.readFileSync(configFile, "utf-8"),
validateConfig,
);
}
async function getRemoteConfig(
logger: Logger,
configFile: string,
apiDetails: api.GitHubApiCombinedDetails,
validateConfig: boolean,
): Promise<UserConfig> {
// retrieve the various parts of the config location, and ensure they're present
const format = new RegExp(
@@ -961,9 +971,12 @@ async function getRemoteConfig(
);
}
return yaml.load(
return parseUserConfig(
logger,
configFile,
Buffer.from(fileContents, "base64").toString("binary"),
) as UserConfig;
validateConfig,
);
}
/**
+115 -1
View File
@@ -2,7 +2,13 @@ import test, { ExecutionContext } from "ava";
import { RepositoryProperties } from "../feature-flags/properties";
import { KnownLanguage, Language } from "../languages";
import { prettyPrintPack } from "../util";
import { getRunnerLogger } from "../logging";
import {
checkExpectedLogMessages,
getRecordingLogger,
LoggedMessage,
} from "../testing-utils";
import { ConfigurationError, prettyPrintPack } from "../util";
import * as dbConfig from "./db-config";
@@ -391,3 +397,111 @@ test(
{},
/"a-pack-without-a-scope" is not a valid pack/,
);
test("parseUserConfig - successfully parses valid YAML", (t) => {
const result = dbConfig.parseUserConfig(
getRunnerLogger(true),
"test",
`
paths-ignore:
- "some/path"
queries:
- uses: foo
some-unknown-option: true
`,
true,
);
t.truthy(result);
if (t.truthy(result["paths-ignore"])) {
t.is(result["paths-ignore"].length, 1);
t.is(result["paths-ignore"][0], "some/path");
}
if (t.truthy(result["queries"])) {
t.is(result["queries"].length, 1);
t.deepEqual(result["queries"][0], { uses: "foo" });
}
});
test("parseUserConfig - throws a ConfigurationError if the file is not valid YAML", (t) => {
t.throws(
() =>
dbConfig.parseUserConfig(
getRunnerLogger(true),
"test",
`
paths-ignore:
- "some/path"
queries:
- foo
`,
true,
),
{
instanceOf: ConfigurationError,
},
);
});
test("parseUserConfig - validation isn't picky about `query-filters`", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
t.notThrows(() =>
dbConfig.parseUserConfig(
logger,
"test",
`
query-filters:
- something
- include: foo
- exclude: bar
`,
true,
),
);
});
test("parseUserConfig - throws a ConfigurationError if validation fails", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
t.throws(
() =>
dbConfig.parseUserConfig(
logger,
"test",
`
paths-ignore:
- "some/path"
queries: true
`,
true,
),
{
instanceOf: ConfigurationError,
message:
'The configuration file "test" is invalid: instance.queries is not of a type(s) array.',
},
);
const expectedMessages = ["instance.queries is not of a type(s) array"];
checkExpectedLogMessages(t, loggedMessages, expectedMessages);
});
test("parseUserConfig - throws no ConfigurationError if validation should fail, but feature is disabled", (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
t.notThrows(() =>
dbConfig.parseUserConfig(
logger,
"test",
`
paths-ignore:
- "some/path"
queries: true
`,
false,
),
);
});
+52
View File
@@ -1,5 +1,7 @@
import * as path from "path";
import * as yaml from "js-yaml";
import * as jsonschema from "jsonschema";
import * as semver from "semver";
import * as errorMessages from "../error-messages";
@@ -474,3 +476,53 @@ export function generateCodeScanningConfig(
return augmentedConfig;
}
/**
* Attempts to parse `contents` into a `UserConfig` value.
*
* @param logger The logger to use.
* @param pathInput The path to the file where `contents` was obtained from, for use in error messages.
* @param contents The string contents of a YAML file to try and parse as a `UserConfig`.
* @param validateConfig Whether to validate the configuration file against the schema.
* @returns The `UserConfig` corresponding to `contents`, if parsing was successful.
* @throws A `ConfigurationError` if parsing failed.
*/
export function parseUserConfig(
logger: Logger,
pathInput: string,
contents: string,
validateConfig: boolean,
): UserConfig {
try {
const schema =
// eslint-disable-next-line @typescript-eslint/no-require-imports
require("../../src/db-config-schema.json") as jsonschema.Schema;
const doc = yaml.load(contents);
if (validateConfig) {
const result = new jsonschema.Validator().validate(doc, schema);
if (result.errors.length > 0) {
for (const error of result.errors) {
logger.error(error.stack);
}
throw new ConfigurationError(
errorMessages.getInvalidConfigFileMessage(
pathInput,
result.errors.map((e) => e.stack),
),
);
}
}
return doc as UserConfig;
} catch (error) {
if (error instanceof yaml.YAMLException) {
throw new ConfigurationError(
errorMessages.getConfigFileParseErrorMessage(pathInput, error.message),
);
}
throw error;
}
}
+34
View File
@@ -5,6 +5,7 @@ import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import { AnalysisKind } from "./analyses";
import { GitHubApiDetails } from "./api-client";
import * as apiClient from "./api-client";
import { createStubCodeQL } from "./codeql";
@@ -108,6 +109,39 @@ test("Abort database upload if 'upload-database' input set to false", async (t)
});
});
test("Abort database upload if 'analysis-kinds: code-scanning' is not enabled", async (t) => {
await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
sinon
.stub(actionsUtil, "getRequiredInput")
.withArgs("upload-database")
.returns("true");
sinon.stub(gitUtils, "isAnalyzingDefaultBranch").resolves(true);
await mockHttpRequests(201);
const loggedMessages = [];
await uploadDatabases(
testRepoName,
getCodeQL(),
{
...getTestConfig(tmpDir),
analysisKinds: [AnalysisKind.CodeQuality],
},
testApiDetails,
getRecordingLogger(loggedMessages),
);
t.assert(
loggedMessages.find(
(v: LoggedMessage) =>
v.type === "debug" &&
v.message ===
"Not uploading database because 'analysis-kinds: code-scanning' is not enabled.",
) !== undefined,
);
});
});
test("Abort database upload if running against GHES", async (t) => {
await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
+8
View File
@@ -1,6 +1,7 @@
import * as fs from "fs";
import * as actionsUtil from "./actions-util";
import { AnalysisKind } from "./analyses";
import { getApiClient, GitHubApiDetails } from "./api-client";
import { type CodeQL } from "./codeql";
import { Config } from "./config-utils";
@@ -22,6 +23,13 @@ export async function uploadDatabases(
return;
}
if (!config.analysisKinds.includes(AnalysisKind.CodeScanning)) {
logger.debug(
`Not uploading database because 'analysis-kinds: ${AnalysisKind.CodeScanning}' is not enabled.`,
);
return;
}
if (util.isInTestMode()) {
logger.debug("In test mode. Skipping database upload.");
return;
+145
View File
@@ -0,0 +1,145 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "CodeQL Database Configuration",
"description": "Format of the config file supplied by the user for CodeQL analysis",
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Name of the configuration"
},
"disable-default-queries": {
"type": "boolean",
"description": "Whether to disable default queries"
},
"queries": {
"type": "array",
"description": "List of additional queries to run",
"items": {
"$ref": "#/definitions/QuerySpec"
}
},
"paths-ignore": {
"type": "array",
"description": "Paths to ignore during analysis",
"items": {
"type": "string"
}
},
"paths": {
"type": "array",
"description": "Paths to include in analysis",
"items": {
"type": "string"
}
},
"packs": {
"description": "Query packs to include. Can be a simple array for single-language analysis or an object with language-specific arrays for multi-language analysis",
"oneOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}
]
},
"query-filters": {
"type": "array",
"description": "Set of query filters to include and exclude extra queries based on CodeQL query suite include and exclude properties",
"items": {
"$ref": "#/definitions/QueryFilter"
}
}
},
"additionalProperties": true,
"definitions": {
"QuerySpec": {
"type": "object",
"description": "Detailed query specification object",
"properties": {
"name": {
"type": "string",
"description": "Optional name for the query"
},
"uses": {
"type": "string",
"description": "The query or query suite to use"
}
},
"required": ["uses"],
"additionalProperties": false
},
"QueryFilter": {
"description": "Query filter that can either include or exclude queries",
"oneOf": [
{
"$ref": "#/definitions/ExcludeQueryFilter"
},
{
"$ref": "#/definitions/IncludeQueryFilter"
},
{}
]
},
"ExcludeQueryFilter": {
"type": "object",
"description": "Filter to exclude queries",
"properties": {
"exclude": {
"type": "object",
"description": "Queries to exclude",
"additionalProperties": {
"oneOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "string"
}
]
}
}
},
"required": ["exclude"],
"additionalProperties": false
},
"IncludeQueryFilter": {
"type": "object",
"description": "Filter to include queries",
"properties": {
"include": {
"type": "object",
"description": "Queries to include",
"additionalProperties": {
"oneOf": [
{
"type": "array",
"items": {
"type": "string"
}
},
{
"type": "string"
}
]
}
}
},
"required": ["include"],
"additionalProperties": false
}
}
}
+4 -4
View File
@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.23.2",
"cliVersion": "2.23.2",
"priorBundleVersion": "codeql-bundle-v2.23.1",
"priorCliVersion": "2.23.1"
"bundleVersion": "codeql-bundle-v2.23.3",
"cliVersion": "2.23.3",
"priorBundleVersion": "codeql-bundle-v2.23.2",
"priorCliVersion": "2.23.2"
}
+3
View File
@@ -47,6 +47,9 @@ export enum EnvVar {
/** Whether the CodeQL Action has already warned the user about low disk space. */
HAS_WARNED_ABOUT_DISK_SPACE = "CODEQL_ACTION_HAS_WARNED_ABOUT_DISK_SPACE",
/** Whether the `setup-codeql` action has been run. */
SETUP_CODEQL_ACTION_HAS_RUN = "CODEQL_ACTION_SETUP_CODEQL_HAS_RUN",
/** Whether the init action has been run. */
INIT_ACTION_HAS_RUN = "CODEQL_ACTION_INIT_HAS_RUN",
+16
View File
@@ -14,6 +14,22 @@ export function getConfigFileDoesNotExistErrorMessage(
return `The configuration file "${configFile}" does not exist`;
}
export function getConfigFileParseErrorMessage(
configFile: string,
message: string,
): string {
return `Cannot parse "${configFile}": ${message}`;
}
export function getInvalidConfigFileMessage(
configFile: string,
messages: string[],
): string {
const andMore =
messages.length > 10 ? `, and ${messages.length - 10} more.` : ".";
return `The configuration file "${configFile}" is invalid: ${messages.slice(0, 10).join(", ")}${andMore}`;
}
export function getConfigFileRepoFormatInvalidMessage(
configFile: string,
): string {
+9 -2
View File
@@ -77,6 +77,7 @@ export enum Feature {
QaTelemetryEnabled = "qa_telemetry_enabled",
ResolveSupportedLanguagesUsingCli = "resolve_supported_languages_using_cli",
UseRepositoryProperties = "use_repository_properties",
ValidateDbConfig = "validate_db_config",
}
export const featureConfig: Record<
@@ -287,6 +288,11 @@ export const featureConfig: Record<
envVar: "CODEQL_ACTION_JAVA_MINIMIZE_DEPENDENCY_JARS",
minimumVersion: "2.23.0",
},
[Feature.ValidateDbConfig]: {
defaultValue: false,
envVar: "CODEQL_ACTION_VALIDATE_DB_CONFIG",
minimumVersion: undefined,
},
};
/**
@@ -651,12 +657,13 @@ class GitHubFeatureFlags {
this.hasAccessedRemoteFeatureFlags = true;
return remoteFlags;
} catch (e) {
if (util.isHTTPError(e) && e.status === 403) {
const httpError = util.asHTTPError(e);
if (httpError?.status === 403) {
this.logger.warning(
"This run of the CodeQL Action does not have permission to access Code Scanning API endpoints. " +
"As a result, it will not be opted into any experimental features. " +
"This could be because the Action is running on a pull request from a fork. If not, " +
`please ensure the Action has the 'security-events: write' permission. Details: ${e.message}`,
`please ensure the Action has the 'security-events: write' permission. Details: ${httpError.message}`,
);
this.hasAccessedRemoteFeatureFlags = false;
return {};
+24 -9
View File
@@ -2,6 +2,7 @@ import test, { ExecutionContext } from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import { AnalysisKind } from "./analyses";
import * as codeql from "./codeql";
import * as configUtils from "./config-utils";
import { Feature } from "./feature-flags";
@@ -28,12 +29,13 @@ test("post: init action with debug mode off", async (t) => {
const gitHubVersion: util.GitHubVersion = {
type: util.GitHubVariant.DOTCOM,
};
sinon.stub(configUtils, "getConfig").resolves({
debugMode: false,
gitHubVersion,
languages: [],
packs: [],
} as unknown as configUtils.Config);
sinon.stub(configUtils, "getConfig").resolves(
createTestConfig({
debugMode: false,
gitHubVersion,
languages: [],
}),
);
const uploadAllAvailableDebugArtifactsSpy = sinon.spy();
const printDebugLogsSpy = sinon.spy();
@@ -295,6 +297,17 @@ test("uploading failed SARIF run fails when workflow does not reference github/c
t.truthy(result.upload_failed_run_stack_trace);
});
test("not uploading failed SARIF when `code-scanning` is not an enabled analysis kind", async (t) => {
const result = await testFailedSarifUpload(t, createTestWorkflow([]), {
analysisKinds: [AnalysisKind.CodeQuality],
expectUpload: false,
});
t.is(
result.upload_failed_run_skipped_because,
"Code Scanning is not enabled.",
);
});
function createTestWorkflow(
steps: workflow.WorkflowJobStep[],
): workflow.Workflow {
@@ -327,20 +340,22 @@ async function testFailedSarifUpload(
expectUpload = true,
exportDiagnosticsEnabled = false,
matrix = {},
analysisKinds = [AnalysisKind.CodeScanning],
}: {
category?: string;
databaseExists?: boolean;
expectUpload?: boolean;
exportDiagnosticsEnabled?: boolean;
matrix?: { [key: string]: string };
analysisKinds?: AnalysisKind[];
} = {},
): Promise<initActionPostHelper.UploadFailedSarifResult> {
const config = {
const config = createTestConfig({
analysisKinds,
codeQLCmd: "codeql",
debugMode: true,
languages: [],
packs: [],
} as unknown as configUtils.Config;
});
if (databaseExists) {
config.dbLocation = "path/to/database";
}
+10 -1
View File
@@ -7,7 +7,7 @@ import * as actionsUtil from "./actions-util";
import { CodeScanning } from "./analyses";
import { getApiClient } from "./api-client";
import { CodeQL, getCodeQL } from "./codeql";
import { Config } from "./config-utils";
import { Config, isCodeScanningEnabled } from "./config-utils";
import * as dependencyCaching from "./dependency-caching";
import { EnvVar } from "./environment";
import { Feature, FeatureEnablement } from "./feature-flags";
@@ -139,6 +139,15 @@ export async function tryUploadSarifIfRunFailed(
EnvVar.JOB_STATUS,
process.env[EnvVar.JOB_STATUS] ?? JobStatus.ConfigErrorStatus,
);
// If the only enabled analysis kind is `code-quality`, then we shouldn't
// upload the failed SARIF to Code Scanning.
if (!isCodeScanningEnabled(config)) {
return {
upload_failed_run_skipped_because: "Code Scanning is not enabled.",
};
}
try {
return await maybeUploadFailedSarif(
config,
+52 -31
View File
@@ -15,6 +15,7 @@ import {
getTemporaryDirectory,
persistInputs,
} from "./actions-util";
import { AnalysisKind, getAnalysisKinds } from "./analyses";
import { getGitHubVersion } from "./api-client";
import {
getDependencyCachingEnabled,
@@ -56,6 +57,7 @@ import { ToolsSource } from "./setup-codeql";
import {
ActionName,
InitStatusReport,
InitToolsDownloadFields,
InitWithConfigStatusReport,
createInitWithConfigStatusReport,
createStatusReportBase,
@@ -86,14 +88,29 @@ import {
} from "./util";
import { validateWorkflow } from "./workflow";
/** Fields of the init status report populated when the tools source is `download`. */
interface InitToolsDownloadFields {
/** Time taken to download the bundle, in milliseconds. */
tools_download_duration_ms?: number;
/**
* Whether the relevant tools dotcom feature flags have been misconfigured.
* Only populated if we attempt to determine the default version based on the dotcom feature flags. */
tools_feature_flags_valid?: boolean;
/**
* Sends a status report indicating that the `init` Action is starting.
*
* @param startedAt
* @param config
* @param logger
*/
async function sendStartingStatusReport(
startedAt: Date,
config: Partial<configUtils.Config> | undefined,
logger: Logger,
) {
const statusReportBase = await createStatusReportBase(
ActionName.Init,
"starting",
startedAt,
config,
await checkDiskUsage(logger),
logger,
);
if (statusReportBase !== undefined) {
await sendStatusReport(statusReportBase);
}
}
async function sendCompletedStatusReport(
@@ -210,6 +227,7 @@ async function run() {
? await loadPropertiesFromApi(gitHubVersion, logger, repositoryNwo)
: {};
// Create a unique identifier for this run.
const jobRunUuid = uuidV4();
logger.info(`Job run UUID is ${jobRunUuid}.`);
core.exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
@@ -227,17 +245,30 @@ async function run() {
);
try {
const statusReportBase = await createStatusReportBase(
ActionName.Init,
"starting",
startedAt,
config,
await checkDiskUsage(logger),
logger,
);
if (statusReportBase !== undefined) {
await sendStatusReport(statusReportBase);
// Parsing the `analysis-kinds` input may throw a `ConfigurationError`, which we don't want before
// we have called `sendStartingStatusReport` below. However, we want the analysis kinds for that status
// report. To work around this, we ignore exceptions that are thrown here and then call `getAnalysisKinds`
// a second time later. The second call will then throw the exception again. If `getAnalysisKinds` is
// successful, the results are cached so that we don't duplicate the work in normal runs.
let analysisKinds: AnalysisKind[] | undefined;
try {
analysisKinds = await getAnalysisKinds(logger);
} catch (err) {
logger.debug(
`Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}`,
);
}
// Send a status report indicating that an analysis is starting.
await sendStartingStatusReport(startedAt, { analysisKinds }, logger);
// Throw a `ConfigurationError` if the `setup-codeql` action has been run.
if (process.env[EnvVar.SETUP_CODEQL_ACTION_HAS_RUN] === "true") {
throw new ConfigurationError(
`The 'init' action should not be run in the same workflow as 'setup-codeql'.`,
);
}
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
gitHubVersion.type,
);
@@ -293,21 +324,11 @@ async function run() {
}
}
// Warn that `quality-queries` is deprecated if there is an argument for it.
const qualityQueriesInput = getOptionalInput("quality-queries");
if (qualityQueriesInput !== undefined) {
logger.warning(
"The `quality-queries` input is deprecated and will be removed in a future version of the CodeQL Action. " +
"Use the `analysis-kinds` input to configure different analysis kinds instead.",
);
}
config = await initConfig({
analysisKindsInput: getRequiredInput("analysis-kinds"),
analysisKinds = await getAnalysisKinds(logger);
config = await initConfig(features, {
analysisKinds,
languagesInput: getOptionalInput("languages"),
queriesInput: getOptionalInput("queries"),
qualityQueriesInput,
packsInput: getOptionalInput("packs"),
buildModeInput: getOptionalInput("build-mode"),
configFile,
+2 -1
View File
@@ -61,10 +61,11 @@ export async function initCodeQL(
}
export async function initConfig(
features: FeatureEnablement,
inputs: configUtils.InitConfigInputs,
): Promise<configUtils.Config> {
return await withGroupAsync("Load language configuration", async () => {
return await configUtils.initConfig(inputs);
return await configUtils.initConfig(features, inputs);
});
}
+196
View File
@@ -0,0 +1,196 @@
import * as core from "@actions/core";
import { v4 as uuidV4 } from "uuid";
import {
getActionVersion,
getOptionalInput,
getRequiredInput,
getTemporaryDirectory,
} from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { CodeQL } from "./codeql";
import { EnvVar } from "./environment";
import { Features } from "./feature-flags";
import { initCodeQL } from "./init";
import { getActionsLogger, Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
import { ToolsSource } from "./setup-codeql";
import {
ActionName,
InitStatusReport,
InitToolsDownloadFields,
createStatusReportBase,
getActionsStatus,
sendStatusReport,
} from "./status-report";
import { ToolsDownloadStatusReport } from "./tools-download";
import {
checkDiskUsage,
checkForTimeout,
checkGitHubVersionInRange,
getRequiredEnvParam,
initializeEnvironment,
ConfigurationError,
wrapError,
checkActionVersion,
getErrorMessage,
} from "./util";
/**
* Helper function to send a full status report for this action.
*/
async function sendCompletedStatusReport(
startedAt: Date,
toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined,
toolsFeatureFlagsValid: boolean | undefined,
toolsSource: ToolsSource,
toolsVersion: string,
logger: Logger,
error?: Error,
): Promise<void> {
const statusReportBase = await createStatusReportBase(
ActionName.SetupCodeQL,
getActionsStatus(error),
startedAt,
undefined,
await checkDiskUsage(logger),
logger,
error?.message,
error?.stack,
);
if (statusReportBase === undefined) {
return;
}
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || ToolsSource.Unknown,
workflow_languages: "",
};
const initToolsDownloadFields: InitToolsDownloadFields = {};
if (toolsDownloadStatusReport?.downloadDurationMs !== undefined) {
initToolsDownloadFields.tools_download_duration_ms =
toolsDownloadStatusReport.downloadDurationMs;
}
if (toolsFeatureFlagsValid !== undefined) {
initToolsDownloadFields.tools_feature_flags_valid = toolsFeatureFlagsValid;
}
await sendStatusReport({ ...initStatusReport, ...initToolsDownloadFields });
}
/** The main behaviour of this action. */
async function run(): Promise<void> {
const startedAt = new Date();
const logger = getActionsLogger();
initializeEnvironment(getActionVersion());
let codeql: CodeQL;
let toolsDownloadStatusReport: ToolsDownloadStatusReport | undefined;
let toolsFeatureFlagsValid: boolean | undefined;
let toolsSource: ToolsSource;
let toolsVersion: string;
const apiDetails = {
auth: getRequiredInput("token"),
externalRepoAuth: getOptionalInput("external-repository-token"),
url: getRequiredEnvParam("GITHUB_SERVER_URL"),
apiURL: getRequiredEnvParam("GITHUB_API_URL"),
};
const gitHubVersion = await getGitHubVersion();
checkGitHubVersionInRange(gitHubVersion, logger);
checkActionVersion(getActionVersion(), gitHubVersion);
const repositoryNwo = getRepositoryNwo();
const features = new Features(
gitHubVersion,
repositoryNwo,
getTemporaryDirectory(),
logger,
);
const jobRunUuid = uuidV4();
logger.info(`Job run UUID is ${jobRunUuid}.`);
core.exportVariable(EnvVar.JOB_RUN_UUID, jobRunUuid);
try {
const statusReportBase = await createStatusReportBase(
ActionName.SetupCodeQL,
"starting",
startedAt,
undefined,
await checkDiskUsage(logger),
logger,
);
if (statusReportBase !== undefined) {
await sendStatusReport(statusReportBase);
}
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
gitHubVersion.type,
);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
codeQLDefaultVersionInfo,
features,
logger,
);
codeql = initCodeQLResult.codeql;
toolsDownloadStatusReport = initCodeQLResult.toolsDownloadStatusReport;
toolsVersion = initCodeQLResult.toolsVersion;
toolsSource = initCodeQLResult.toolsSource;
core.setOutput("codeql-path", codeql.getPath());
core.setOutput("codeql-version", (await codeql.getVersion()).version);
core.exportVariable(EnvVar.SETUP_CODEQL_ACTION_HAS_RUN, "true");
} catch (unwrappedError) {
const error = wrapError(unwrappedError);
core.setFailed(error.message);
const statusReportBase = await createStatusReportBase(
ActionName.SetupCodeQL,
error instanceof ConfigurationError ? "user-error" : "failure",
startedAt,
undefined,
await checkDiskUsage(logger),
logger,
error.message,
error.stack,
);
if (statusReportBase !== undefined) {
await sendStatusReport(statusReportBase);
}
return;
}
await sendCompletedStatusReport(
startedAt,
toolsDownloadStatusReport,
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
logger,
);
}
/** Run the action and catch any unhandled errors. */
async function runWrapper(): Promise<void> {
try {
await run();
} catch (error) {
core.setFailed(`setup-codeql action failed: ${getErrorMessage(error)}`);
}
await checkForTimeout();
}
void runWrapper();
+17 -5
View File
@@ -23,7 +23,6 @@ import { getRepositoryNwo } from "./repository";
import { ToolsSource } from "./setup-codeql";
import {
ConfigurationError,
isHTTPError,
getRequiredEnvParam,
getCachedCodeQlVersion,
isInTestMode,
@@ -33,6 +32,7 @@ import {
BuildMode,
getErrorMessage,
getTestingEnvironment,
asHTTPError,
} from "./util";
export enum ActionName {
@@ -41,6 +41,7 @@ export enum ActionName {
Init = "init",
InitPost = "init-post",
ResolveEnvironment = "resolve-environment",
SetupCodeQL = "setup-codeql",
StartProxy = "start-proxy",
UploadSarif = "upload-sarif",
}
@@ -428,8 +429,9 @@ export async function sendStatusReport<S extends StatusReportBase>(
},
);
} catch (e) {
if (isHTTPError(e)) {
switch (e.status) {
const httpError = asHTTPError(e);
if (httpError !== undefined) {
switch (httpError.status) {
case 403:
if (
getWorkflowEventName() === "push" &&
@@ -442,11 +444,11 @@ export async function sendStatusReport<S extends StatusReportBase>(
`See ${DocUrl.SCANNING_ON_PUSH} for more information on how to configure these events.`,
);
} else {
core.warning(e.message);
core.warning(httpError.message);
}
return;
case 404:
core.warning(e.message);
core.warning(httpError.message);
return;
case 422:
// schema incompatibility when reporting status
@@ -516,6 +518,16 @@ export interface InitWithConfigStatusReport extends InitStatusReport {
config_file: string;
}
/** Fields of the init status report populated when the tools source is `download`. */
export interface InitToolsDownloadFields {
/** Time taken to download the bundle, in milliseconds. */
tools_download_duration_ms?: number;
/**
* Whether the relevant tools dotcom feature flags have been misconfigured.
* Only populated if we attempt to determine the default version based on the dotcom feature flags. */
tools_feature_flags_valid?: boolean;
}
/**
* Composes a `InitWithConfigStatusReport` from the given values.
*
+18 -1
View File
@@ -2,7 +2,7 @@ import { TextDecoder } from "node:util";
import path from "path";
import * as github from "@actions/github";
import { TestFn } from "ava";
import { ExecutionContext, TestFn } from "ava";
import nock from "nock";
import * as sinon from "sinon";
@@ -180,6 +180,23 @@ export function getRecordingLogger(messages: LoggedMessage[]): Logger {
};
}
export function checkExpectedLogMessages(
t: ExecutionContext<any>,
messages: LoggedMessage[],
expectedMessages: string[],
) {
for (const expectedMessage of expectedMessages) {
t.assert(
messages.some(
(msg) =>
typeof msg.message === "string" &&
msg.message.includes(expectedMessage),
),
`Expected '${expectedMessage}' in the logger output, but didn't find it in:\n ${messages.map((m) => ` - '${m.message}'`).join("\n")}`,
);
}
}
/** Mock the HTTP request to the feature flags enablement API endpoint. */
export function mockFeatureFlagApiEndpoint(
responseStatusCode: number,
+2 -2
View File
@@ -13,8 +13,8 @@ import * as gitUtils from "./git-utils";
import { Language } from "./languages";
import { Logger } from "./logging";
import {
asHTTPError,
getErrorMessage,
isHTTPError,
tryGetFolderBytes,
waitForResultWithTimeLimit,
} from "./util";
@@ -236,7 +236,7 @@ export async function cleanupTrapCaches(
}
return { trap_cache_cleanup_size_bytes: totalBytesCleanedUp };
} catch (e) {
if (isHTTPError(e) && e.status === 403) {
if (asHTTPError(e)?.status === 403) {
logger.warning(
"Could not cleanup TRAP caches as the token did not have the required permissions. " +
'To clean up TRAP caches, ensure the token has the "actions:write" permission. ' +
+6 -5
View File
@@ -386,16 +386,17 @@ export async function uploadPayload(
logger.info("Successfully uploaded results");
return response.data.id as string;
} catch (e) {
if (util.isHTTPError(e)) {
switch (e.status) {
const httpError = util.asHTTPError(e);
if (httpError !== undefined) {
switch (httpError.status) {
case 403:
core.warning(e.message || GENERIC_403_MSG);
core.warning(httpError.message || GENERIC_403_MSG);
break;
case 404:
core.warning(e.message || GENERIC_404_MSG);
core.warning(httpError.message || GENERIC_404_MSG);
break;
default:
core.warning(e.message);
core.warning(httpError.message);
break;
}
}
+16 -2
View File
@@ -692,8 +692,22 @@ export class ConfigurationError extends Error {
}
}
export function isHTTPError(arg: any): arg is HTTPError {
return arg?.status !== undefined && Number.isInteger(arg.status);
export function asHTTPError(arg: any): HTTPError | undefined {
if (
typeof arg !== "object" ||
arg === null ||
typeof arg.message !== "string"
) {
return undefined;
}
if (Number.isInteger(arg.status)) {
return new HTTPError(arg.message as string, arg.status as number);
}
// See https://github.com/actions/toolkit/blob/acb230b99a46ed33a3f04a758cd68b47b9a82908/packages/tool-cache/src/tool-cache.ts#L19
if (Number.isInteger(arg.httpStatusCode)) {
return new HTTPError(arg.message as string, arg.httpStatusCode as number);
}
return undefined;
}
let cachedCodeQlVersion: undefined | VersionInfo = undefined;