mirror of
https://github.com/github/codeql-action.git
synced 2025-12-16 12:29:14 +08:00
Compare commits
47 Commits
v4.30.8
...
mbg/errors
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0cf61911ea | ||
|
|
816fc30181 | ||
|
|
9ce56a247f | ||
|
|
2c8f4891d1 | ||
|
|
d7a8ae5fdd | ||
|
|
0822fb12e7 | ||
|
|
913cd47984 | ||
|
|
4f14649ced | ||
|
|
ac922ab562 | ||
|
|
66df0bc515 | ||
|
|
70205d3d12 | ||
|
|
697c209bfc | ||
|
|
1bd53ba38c | ||
|
|
cac4df0c79 | ||
|
|
77e5c0d0a2 | ||
|
|
97a4f751be | ||
|
|
2d5512b361 | ||
|
|
fa7bdf0559 | ||
|
|
57c7b0a884 | ||
|
|
4874f90a8d | ||
|
|
5a9e92afca | ||
|
|
9bd9b03572 | ||
|
|
3569065d7e | ||
|
|
c0e8887d5a | ||
|
|
3c8d00aea0 | ||
|
|
bc93b04b0c | ||
|
|
adf39dd33f | ||
|
|
000295122d | ||
|
|
2611d033d7 | ||
|
|
ee753b4724 | ||
|
|
db6938a4d0 | ||
|
|
d02f50ee62 | ||
|
|
f4237b7e76 | ||
|
|
302fc5e00d | ||
|
|
c77b3fb96e | ||
|
|
2a54ab5016 | ||
|
|
a60e5ce8ec | ||
|
|
8d0251c1f7 | ||
|
|
80220dcd46 | ||
|
|
e72fd9acb1 | ||
|
|
17783bfb99 | ||
|
|
3c764cd93a | ||
|
|
e1968324ff | ||
|
|
2a6736cca7 | ||
|
|
c8765c966b | ||
|
|
61789e2fdb | ||
|
|
5cd2d139cb |
8
.github/update-release-branch.py
vendored
8
.github/update-release-branch.py
vendored
@@ -371,10 +371,10 @@ def main():
|
||||
# releases.
|
||||
run_git('revert', vOlder_update_commits[0], '--no-edit')
|
||||
|
||||
# Also revert the "Update checked-in dependencies" commit created by Actions.
|
||||
update_dependencies_commit = run_git('log', '--grep', '^Update checked-in dependencies', '--format=%H').split()[0]
|
||||
print(f' Reverting {update_dependencies_commit}')
|
||||
run_git('revert', update_dependencies_commit, '--no-edit')
|
||||
# Also revert the "Rebuild" commit created by Actions.
|
||||
rebuild_commit = run_git('log', '--grep', '^Rebuild$', '--format=%H').split()[0]
|
||||
print(f' Reverting {rebuild_commit}')
|
||||
run_git('revert', rebuild_commit, '--no-edit')
|
||||
|
||||
else:
|
||||
print(' Nothing to revert.')
|
||||
|
||||
15
.github/workflows/__analyze-ref-input.yml
generated
vendored
15
.github/workflows/__analyze-ref-input.yml
generated
vendored
@@ -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 }}
|
||||
|
||||
5
.github/workflows/__bundle-from-toolcache.yml
generated
vendored
5
.github/workflows/__bundle-from-toolcache.yml
generated
vendored
@@ -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
|
||||
|
||||
15
.github/workflows/__local-bundle.yml
generated
vendored
15
.github/workflows/__local-bundle.yml
generated
vendored
@@ -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
.github/workflows/__multi-language-autodetect.yml
generated
vendored
15
.github/workflows/__multi-language-autodetect.yml
generated
vendored
@@ -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"
|
||||
|
||||
15
.github/workflows/__packaging-codescanning-config-inputs-js.yml
generated
vendored
15
.github/workflows/__packaging-codescanning-config-inputs-js.yml
generated
vendored
@@ -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
|
||||
@@ -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
|
||||
|
||||
15
.github/workflows/__remote-config.yml
generated
vendored
15
.github/workflows/__remote-config.yml
generated
vendored
@@ -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
.github/workflows/__unset-environment.yml
generated
vendored
15
.github/workflows/__unset-environment.yml
generated
vendored
@@ -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
.github/workflows/__upload-ref-sha-input.yml
generated
vendored
15
.github/workflows/__upload-ref-sha-input.yml
generated
vendored
@@ -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
.github/workflows/__upload-sarif.yml
generated
vendored
15
.github/workflows/__upload-sarif.yml
generated
vendored
@@ -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
.github/workflows/__with-checkout-path.yml
generated
vendored
15
.github/workflows/__with-checkout-path.yml
generated
vendored
@@ -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.
|
||||
|
||||
1
.github/workflows/post-release-mergeback.yml
vendored
1
.github/workflows/post-release-mergeback.yml
vendored
@@ -146,6 +146,7 @@ jobs:
|
||||
private-key: ${{ secrets.AUTOMATION_PRIVATE_KEY }}
|
||||
|
||||
- name: Create the GitHub release
|
||||
if: steps.check.outputs.exists != 'true'
|
||||
env:
|
||||
PARTIAL_CHANGELOG: "${{ runner.temp }}/partial_changelog.md"
|
||||
VERSION: "${{ steps.getVersion.outputs.version }}"
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs.
|
||||
|
||||
## [UNRELEASED]
|
||||
|
||||
- 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.
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
29
json-schemas.mjs
Normal file
29
json-schemas.mjs
Normal file
@@ -0,0 +1,29 @@
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import { globSync } from "glob";
|
||||
import { compileFromFile } from 'json-schema-to-typescript';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const SRC_DIR = path.join(__dirname, "schemas");
|
||||
const OUT_DIR = path.join(__dirname, "src");
|
||||
|
||||
async function generateTypings() {
|
||||
const schemas = globSync(`${SRC_DIR}/*.json`);
|
||||
for (const schema of schemas) {
|
||||
const outPath = path.join(
|
||||
OUT_DIR,
|
||||
`${path.basename(schema, ".json")}.d.ts`,
|
||||
);
|
||||
const ts = await compileFromFile(schema, {
|
||||
bannerComment:
|
||||
"/* This file was automatically generated by `npm run generate:schemas`. Do not edit by hand. */",
|
||||
});
|
||||
fs.writeFileSync(outPath, ts, "utf-8");
|
||||
}
|
||||
}
|
||||
|
||||
await generateTypings();
|
||||
1344
lib/analyze-action-post.js
generated
1344
lib/analyze-action-post.js
generated
File diff suppressed because it is too large
Load Diff
2635
lib/analyze-action.js
generated
2635
lib/analyze-action.js
generated
File diff suppressed because it is too large
Load Diff
1334
lib/autobuild-action.js
generated
1334
lib/autobuild-action.js
generated
File diff suppressed because it is too large
Load Diff
@@ -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"
|
||||
}
|
||||
|
||||
2657
lib/init-action-post.js
generated
2657
lib/init-action-post.js
generated
File diff suppressed because it is too large
Load Diff
1688
lib/init-action.js
generated
1688
lib/init-action.js
generated
File diff suppressed because it is too large
Load Diff
1330
lib/resolve-environment-action.js
generated
1330
lib/resolve-environment-action.js
generated
File diff suppressed because it is too large
Load Diff
88987
lib/setup-codeql-action.js
generated
Normal file
88987
lib/setup-codeql-action.js
generated
Normal file
File diff suppressed because one or more lines are too long
1344
lib/start-proxy-action-post.js
generated
1344
lib/start-proxy-action-post.js
generated
File diff suppressed because it is too large
Load Diff
1331
lib/start-proxy-action.js
generated
1331
lib/start-proxy-action.js
generated
File diff suppressed because it is too large
Load Diff
67
lib/upload-lib.js
generated
67
lib/upload-lib.js
generated
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -33606,7 +33606,7 @@ var require_package = __commonJS({
|
||||
"package.json"(exports2, module2) {
|
||||
module2.exports = {
|
||||
name: "codeql",
|
||||
version: "4.30.8",
|
||||
version: "4.30.9",
|
||||
private: true,
|
||||
description: "CodeQL action",
|
||||
scripts: {
|
||||
@@ -33618,7 +33618,8 @@ var require_package = __commonJS({
|
||||
ava: "npm run transpile && ava --serial --verbose",
|
||||
test: "npm run ava -- src/",
|
||||
"test-debug": "npm run test -- --timeout=20m",
|
||||
transpile: "tsc --build --verbose"
|
||||
transpile: "npm run generate:schemas && tsc --build --verbose",
|
||||
"generate:schemas": "node json-schemas.mjs"
|
||||
},
|
||||
ava: {
|
||||
typescript: {
|
||||
@@ -33684,6 +33685,7 @@ var require_package = __commonJS({
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
glob: "^11.0.3",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
nock: "^14.0.10",
|
||||
sinon: "^21.0.0",
|
||||
typescript: "^5.9.3"
|
||||
@@ -84865,7 +84867,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"));
|
||||
@@ -88971,6 +88973,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 +89054,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 +89071,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 +89536,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
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92651,7 +92662,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))
|
||||
|
||||
1312
lib/upload-sarif-action-post.js
generated
1312
lib/upload-sarif-action-post.js
generated
File diff suppressed because it is too large
Load Diff
67
lib/upload-sarif-action.js
generated
67
lib/upload-sarif-action.js
generated
@@ -32309,7 +32309,7 @@ var require_package = __commonJS({
|
||||
"package.json"(exports2, module2) {
|
||||
module2.exports = {
|
||||
name: "codeql",
|
||||
version: "4.30.8",
|
||||
version: "4.30.9",
|
||||
private: true,
|
||||
description: "CodeQL action",
|
||||
scripts: {
|
||||
@@ -32321,7 +32321,8 @@ var require_package = __commonJS({
|
||||
ava: "npm run transpile && ava --serial --verbose",
|
||||
test: "npm run ava -- src/",
|
||||
"test-debug": "npm run test -- --timeout=20m",
|
||||
transpile: "tsc --build --verbose"
|
||||
transpile: "npm run generate:schemas && tsc --build --verbose",
|
||||
"generate:schemas": "node json-schemas.mjs"
|
||||
},
|
||||
ava: {
|
||||
typescript: {
|
||||
@@ -32387,6 +32388,7 @@ var require_package = __commonJS({
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
glob: "^11.0.3",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
nock: "^14.0.10",
|
||||
sinon: "^21.0.0",
|
||||
typescript: "^5.9.3"
|
||||
@@ -80374,19 +80376,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 +80406,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 +80462,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 +80512,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 +80539,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 +80554,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 +80582,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 +80590,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 +80598,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);
|
||||
};
|
||||
}
|
||||
@@ -88976,8 +88978,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 +89448,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";
|
||||
@@ -89725,6 +89732,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]";
|
||||
@@ -90009,7 +90017,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"));
|
||||
@@ -90223,6 +90231,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."
|
||||
)
|
||||
]
|
||||
},
|
||||
@@ -93305,7 +93316,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))
|
||||
|
||||
61
package-lock.json
generated
61
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.30.8",
|
||||
"version": "4.30.9",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "codeql",
|
||||
"version": "4.30.8",
|
||||
"version": "4.30.9",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@actions/artifact": "^2.3.1",
|
||||
@@ -63,6 +63,7 @@
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
"glob": "^11.0.3",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
"nock": "^14.0.10",
|
||||
"sinon": "^21.0.0",
|
||||
"typescript": "^5.9.3"
|
||||
@@ -429,6 +430,24 @@
|
||||
"semver": "^6.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@apidevtools/json-schema-ref-parser": {
|
||||
"version": "11.9.3",
|
||||
"resolved": "https://registry.npmjs.org/@apidevtools/json-schema-ref-parser/-/json-schema-ref-parser-11.9.3.tgz",
|
||||
"integrity": "sha512-60vepv88RwcJtSHrD6MjIL6Ta3SOYbgfnkHb+ppAVK+o9mXprRtulx7VlRl3lN3bbvysAfCS7WMVfhUYemB0IQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@jsdevtools/ono": "^7.1.3",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"js-yaml": "^4.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/philsturgeon"
|
||||
}
|
||||
},
|
||||
"node_modules/@ava/typescript": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@ava/typescript/-/typescript-6.0.0.tgz",
|
||||
@@ -1525,6 +1544,13 @@
|
||||
"node": ">=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@jsdevtools/ono": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/@jsdevtools/ono/-/ono-7.1.3.tgz",
|
||||
"integrity": "sha512-4JQNk+3mVzK3xh2rqd6RB4J46qUR19azEHBneZyTZM+c456qOrbbM/5xcR8huNCCcbVt7+UmizG6GuUvPvKUYg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@mapbox/node-pre-gyp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-2.0.0.tgz",
|
||||
@@ -2644,6 +2670,13 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.17.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
|
||||
"integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz",
|
||||
@@ -6952,6 +6985,30 @@
|
||||
"node": ">=0.1.90"
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema-to-typescript": {
|
||||
"version": "15.0.4",
|
||||
"resolved": "https://registry.npmjs.org/json-schema-to-typescript/-/json-schema-to-typescript-15.0.4.tgz",
|
||||
"integrity": "sha512-Su9oK8DR4xCmDsLlyvadkXzX6+GGXJpbhwoLtOGArAG61dvbW4YQmSEno2y66ahpIdmLMg6YUf/QHLgiwvkrHQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@apidevtools/json-schema-ref-parser": "^11.5.5",
|
||||
"@types/json-schema": "^7.0.15",
|
||||
"@types/lodash": "^4.17.7",
|
||||
"is-glob": "^4.0.3",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"minimist": "^1.2.8",
|
||||
"prettier": "^3.2.5",
|
||||
"tinyglobby": "^0.2.9"
|
||||
},
|
||||
"bin": {
|
||||
"json2ts": "dist/src/cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/json-schema-traverse": {
|
||||
"version": "0.4.1",
|
||||
"dev": true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.30.8",
|
||||
"version": "4.30.9",
|
||||
"private": true,
|
||||
"description": "CodeQL action",
|
||||
"scripts": {
|
||||
@@ -12,7 +12,8 @@
|
||||
"ava": "npm run transpile && ava --serial --verbose",
|
||||
"test": "npm run ava -- src/",
|
||||
"test-debug": "npm run test -- --timeout=20m",
|
||||
"transpile": "tsc --build --verbose"
|
||||
"transpile": "npm run generate:schemas && tsc --build --verbose",
|
||||
"generate:schemas": "node json-schemas.mjs"
|
||||
},
|
||||
"ava": {
|
||||
"typescript": {
|
||||
@@ -78,6 +79,7 @@
|
||||
"eslint-plugin-import": "2.29.1",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
"glob": "^11.0.3",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
"nock": "^14.0.10",
|
||||
"sinon": "^21.0.0",
|
||||
"typescript": "^5.9.3"
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -6,6 +6,7 @@ versions:
|
||||
- linked
|
||||
- nightly-latest
|
||||
installGo: true
|
||||
installPython: true
|
||||
steps:
|
||||
- uses: ./../action/init
|
||||
with:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
145
schemas/db-config-schema.json
Normal file
145
schemas/db-config-schema.json
Normal file
@@ -0,0 +1,145 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"title": "UserConfig",
|
||||
"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
|
||||
}
|
||||
}
|
||||
}
|
||||
39
setup-codeql/action.yml
Normal file
39
setup-codeql/action.yml
Normal 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'
|
||||
@@ -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));
|
||||
});
|
||||
|
||||
@@ -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"];
|
||||
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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]: {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import * as path from "path";
|
||||
|
||||
import * as yaml from "js-yaml";
|
||||
import * as jsonschema from "jsonschema";
|
||||
import * as semver from "semver";
|
||||
|
||||
import type { UserConfig as DbConfig, QuerySpec } from "../db-config-schema";
|
||||
import * as errorMessages from "../error-messages";
|
||||
import {
|
||||
RepositoryProperties,
|
||||
@@ -11,6 +14,8 @@ import { Language } from "../languages";
|
||||
import { Logger } from "../logging";
|
||||
import { cloneObject, ConfigurationError, prettyPrintPack } from "../util";
|
||||
|
||||
export type { QuerySpec } from "../db-config-schema";
|
||||
|
||||
export interface ExcludeQueryFilter {
|
||||
exclude: Record<string, string[] | string>;
|
||||
}
|
||||
@@ -21,30 +26,14 @@ export interface IncludeQueryFilter {
|
||||
|
||||
export type QueryFilter = ExcludeQueryFilter | IncludeQueryFilter;
|
||||
|
||||
export interface QuerySpec {
|
||||
name?: string;
|
||||
uses: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Format of the config file supplied by the user.
|
||||
*/
|
||||
export interface UserConfig {
|
||||
name?: string;
|
||||
"disable-default-queries"?: boolean;
|
||||
queries?: QuerySpec[];
|
||||
"paths-ignore"?: string[];
|
||||
paths?: string[];
|
||||
|
||||
// If this is a multi-language analysis, then the packages must be split by
|
||||
// language. If this is a single language analysis, then no split by
|
||||
// language is necessary.
|
||||
packs?: Record<string, string[]> | string[];
|
||||
|
||||
export type UserConfig = DbConfig & {
|
||||
// Set of query filters to include and exclude extra queries based on
|
||||
// codeql query suite `include` and `exclude` properties
|
||||
"query-filters"?: QueryFilter[];
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents additional configuration data from a source other than
|
||||
@@ -474,3 +463,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("../../schemas/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;
|
||||
}
|
||||
}
|
||||
|
||||
53
src/db-config-schema.d.ts
vendored
Normal file
53
src/db-config-schema.d.ts
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/* This file was automatically generated by `npm run generate:schemas`. Do not edit by hand. */
|
||||
|
||||
/**
|
||||
* Format of the config file supplied by the user for CodeQL analysis
|
||||
*/
|
||||
export interface UserConfig {
|
||||
/**
|
||||
* Name of the configuration
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* Whether to disable default queries
|
||||
*/
|
||||
"disable-default-queries"?: boolean;
|
||||
/**
|
||||
* List of additional queries to run
|
||||
*/
|
||||
queries?: QuerySpec[];
|
||||
/**
|
||||
* Paths to ignore during analysis
|
||||
*/
|
||||
"paths-ignore"?: string[];
|
||||
/**
|
||||
* Paths to include in analysis
|
||||
*/
|
||||
paths?: string[];
|
||||
/**
|
||||
* Query packs to include. Can be a simple array for single-language analysis or an object with language-specific arrays for multi-language analysis
|
||||
*/
|
||||
packs?:
|
||||
| string[]
|
||||
| {
|
||||
[k: string]: string[];
|
||||
};
|
||||
/**
|
||||
* Set of query filters to include and exclude extra queries based on CodeQL query suite include and exclude properties
|
||||
*/
|
||||
"query-filters"?: unknown[];
|
||||
[k: string]: unknown;
|
||||
}
|
||||
/**
|
||||
* Detailed query specification object
|
||||
*/
|
||||
export interface QuerySpec {
|
||||
/**
|
||||
* Optional name for the query
|
||||
*/
|
||||
name?: string;
|
||||
/**
|
||||
* The query or query suite to use
|
||||
*/
|
||||
uses: string;
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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";
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
src/setup-codeql-action.ts
Normal file
196
src/setup-codeql-action.ts
Normal 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();
|
||||
@@ -41,6 +41,7 @@ export enum ActionName {
|
||||
Init = "init",
|
||||
InitPost = "init-post",
|
||||
ResolveEnvironment = "resolve-environment",
|
||||
SetupCodeQL = "setup-codeql",
|
||||
StartProxy = "start-proxy",
|
||||
UploadSarif = "upload-sarif",
|
||||
}
|
||||
@@ -516,6 +517,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.
|
||||
*
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user