Compare commits

...

46 Commits

Author SHA1 Message Date
Edoardo Pirovano
d00e8c09a3 Merge pull request #1107 from github/update-v2.1.13-31367d4e
Merge main into releases/v2
2022-06-21 10:41:43 +01:00
github-actions[bot]
8bd4419d1e Update changelog for v2.1.13 2022-06-21 08:59:28 +00:00
Edoardo Pirovano
31367d4e57 Merge pull request #1100 from github/edoardo/2.9.4-bump
Update default CodeQL version to 2.9.4
2022-06-20 14:46:48 +01:00
Edoardo Pirovano
ccf5d70ab3 Update default CodeQL version to 2.9.4 2022-06-20 09:39:11 +01:00
Andrew Eisenberg
30fe0a56d2 Merge pull request #1103 from github/aeisenberg/fix-required-checks-script
Ensure there are no duplicates when sending up required checks
2022-06-17 15:48:46 +02:00
Andrew Eisenberg
7adb33da1d Ensure there are no duplicates when sending up required checks
This breaks the API. Also, fix the checks that had duplicate names.
2022-06-16 20:31:29 -07:00
Andrew Eisenberg
2e111b27f7 Merge pull request #1102 from github/aeisenberg/fix-query-filters-test
Fix input to action
2022-06-17 03:56:40 +02:00
Andrew Eisenberg
c7785f6b91 Fix input to action 2022-06-16 18:34:04 -07:00
Andrew Eisenberg
2e80c74b1b Merge pull request #1096 from github/aeisenberg/check-sarif-action
Add the check-sarif action
2022-06-16 03:39:00 +02:00
Andrew Eisenberg
80ecdcdf69 Merge pull request #1098 from github/aeisenberg/remove-queries
Add capability to filter queries
2022-06-15 17:52:46 -07:00
Andrew Eisenberg
7c412c67ba Merge branch 'aeisenberg/check-sarif-action' into aeisenberg/remove-queries 2022-06-16 02:42:30 +02:00
Andrew Eisenberg
ee4575b213 Merge branch 'main' into aeisenberg/check-sarif-action 2022-06-16 02:39:30 +02:00
Henry Mercer
d2ab7a2abb Merge pull request #1086 from github/update-supported-enterprise-server-versions
Update supported GitHub Enterprise Server versions.
2022-06-16 01:37:12 +01:00
Andrew Eisenberg
d7459f0368 Merge branch 'aeisenberg/check-sarif-action' into aeisenberg/remove-queries 2022-06-16 02:22:34 +02:00
Andrew Eisenberg
6db77eec0d Merge remote-tracking branch 'upstream/main' into aeisenberg/remove-queries 2022-06-15 17:21:05 -07:00
Andrew Eisenberg
777b778409 Spelling, capitalization, and better descriptions 2022-06-15 17:18:35 -07:00
GitHub
97f9db4fb9 Update supported GitHub Enterprise Server versions. 2022-06-16 00:11:36 +00:00
Andrew Eisenberg
59ca9b59cb Extract query-filters test into a composite action
Removes duplicated yaml.

Also add some better typings.
2022-06-15 16:32:33 -07:00
Andrew Eisenberg
6834383903 Apply suggestions from code review
Co-authored-by: Henry Mercer <henrymercer@github.com>
2022-06-15 16:27:01 -07:00
Andrew Eisenberg
4918636a75 Clarify variable names in new action
Also simplify some computations.
2022-06-15 16:06:16 -07:00
Andrew Eisenberg
428caf0cf5 Update changelog 2022-06-15 14:11:03 -07:00
Tom Bolton
df05122fc6 Merge pull request #1087 from github/tombolton/update-ml-pack
Run ML-powered query pack `~0.3.0` on v2.9.3+ of the CLI
2022-06-15 15:55:43 +01:00
tombolton
a27dc4fee4 update security extended test for all platforms 2022-06-15 11:42:22 +01:00
tombolton
a568674c69 add tests for ML powered queries 0.3.0 and CLI 2.9.3 2022-06-15 11:42:22 +01:00
tombolton
f8f4c0b33e compile the modified TypeScript to Javascript 2022-06-15 11:42:22 +01:00
tombolton
79d8e4a43d fix lint errors 2022-06-15 11:42:22 +01:00
tombolton
0ece1d1000 add ml query pack 0.3.0 2022-06-15 11:42:22 +01:00
Andrew Eisenberg
81b419c908 Merge pull request #1097 from github/aeisenberg/js-yaml-typings 2022-06-15 05:56:07 +02:00
Andrew Eisenberg
eec34d5f05 Add integration tests for query filters 2022-06-14 14:10:08 -07:00
Andrew Eisenberg
06e27d3e3d Merge branch 'aeisenberg/js-yaml-typings' into aeisenberg/remove-queries 2022-06-14 12:08:16 -07:00
Andrew Eisenberg
40b280032c Add capability to filter queries
This change adds a `query-filters` property to the codeql-config file.

This property is an array of `exclude`/`include` entries for a query
suite. These filters are appended to the generated query suite files
and used to filter queries after they are selected.

A related change is that now, all pack references are run in a single
query suite, which has the query filters appended to them.
2022-06-14 12:07:49 -07:00
Andrew Eisenberg
bcb7fad5b3 Add the check-sarif action
Allows us to analyze and then check that certain queries were included
in the analysis and others were not.
2022-06-14 11:55:10 -07:00
Andrew Eisenberg
0efcf74ce0 Add typings for js-yaml 2022-06-14 07:50:47 -07:00
Andrew Eisenberg
29a2159db1 Merge pull request #1095 from github/aeisenberg/use-del
Avoid use of rmdir
2022-06-14 02:55:00 +02:00
Andrew Eisenberg
f7c46e5cbc Avoid use of rmdir
This is a deprecated method on node v16.
2022-06-13 22:40:09 +00:00
Andrew Eisenberg
ccf479d336 Merge pull request #1085 from github/swift-support
Add Swift as a possible traced language
2022-06-02 17:43:40 -07:00
Mathias Vorreiter Pedersen
1b5ea4afdc Merge branch 'main' into swift-support 2022-06-03 01:13:47 +01:00
Andrew Eisenberg
69e09909dc Merge pull request #1089 from github/mergeback/v2.1.12-to-main-27ea8f8f
Mergeback v2.1.12 refs/heads/releases/v2 into main
2022-06-01 13:39:46 -07:00
github-actions[bot]
632cc8efb3 Update checked-in dependencies 2022-06-01 18:35:33 +00:00
github-actions[bot]
57096f1d43 Update changelog and version after v2.1.12 2022-06-01 17:58:23 +00:00
Chuan-kai Lin
27ea8f8fe5 Merge pull request #1088 from github/update-v2.1.12-dbe6f211
Merge main into releases/v2
2022-06-01 10:56:48 -07:00
github-actions[bot]
3f00a1265f Update changelog for v2.1.12 2022-06-01 16:43:15 +00:00
Chuan-kai Lin
dbe6f211e6 Merge pull request #1084 from github/cklin/codeql-bundle-2.9.3
Update default CodeQL to 2.9.3
2022-05-31 09:20:46 -07:00
Mathias Vorreiter Pedersen
16c620dea4 Make the linter happy. 2022-05-31 13:55:23 +01:00
Chuan-kai Lin
b36688d5b7 Update default CodeQL to 2.9.3 2022-05-27 09:16:45 -07:00
Mathias Vorreiter Pedersen
bfe9d7da56 Add Swift as a supported language. 2022-05-27 16:29:13 +01:00
47 changed files with 1283 additions and 141 deletions

20
.github/check-sarif/action.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Check SARIF
description: Checks a SARIF file to see if certain queries were run and others were not run.
inputs:
sarif-file:
required: true
description: The SARIF file to check
queries-run:
required: true
description: |
Comma separated list of query ids that should be included in this SARIF file.
queries-not-run:
required: true
description: |
Comma separated list of query ids that should NOT be included in this SARIF file.
runs:
using: node12
main: index.js

43
.github/check-sarif/index.js vendored Normal file
View File

@@ -0,0 +1,43 @@
'use strict'
const core = require('@actions/core')
const fs = require('fs')
const sarif = JSON.parse(fs.readFileSync(core.getInput('sarif-file'), 'utf8'))
const rules = sarif.runs[0].tool.extensions.flatMap(ext => ext.rules || [])
const ruleIds = rules.map(rule => rule.id)
// Check that all the expected queries ran
const expectedQueriesRun = getQueryIdsInput('queries-run')
const queriesThatShouldHaveRunButDidNot = expectedQueriesRun.filter(queryId => !ruleIds.includes(queryId))
if (queriesThatShouldHaveRunButDidNot.length > 0) {
core.setFailed(`The following queries were expected to run but did not: ${queriesThatShouldHaveRunButDidNot.join(', ')}`)
}
// Check that all the unexpected queries did not run
const expectedQueriesNotRun = getQueryIdsInput('queries-not-run')
const queriesThatShouldNotHaveRunButDid = expectedQueriesNotRun.filter(queryId => ruleIds.includes(queryId))
if (queriesThatShouldNotHaveRunButDid.length > 0) {
core.setFailed(`The following queries were NOT expected to have run but did: ${queriesThatShouldNotHaveRunButDid.join(', ')}`)
}
core.startGroup('All queries run')
rules.forEach(rule => {
core.info(`${rule.id}: ${(rule.properties && rule.properties.name) || rule.name}`)
})
core.endGroup()
core.startGroup('Full SARIF')
core.info(JSON.stringify(sarif, null, 2))
core.endGroup()
function getQueryIdsInput(name) {
return core.getInput(name)
.split(',')
.map(q => q.trim())
.filter(q => q.length > 0)
}

52
.github/query-filter-test/action.yml vendored Normal file
View File

@@ -0,0 +1,52 @@
name: Query Filter Test
description: Runs a test of query filters using the check SARIF action
inputs:
sarif-file:
required: true
description: The SARIF file to check
queries-run:
required: true
description: |
Comma separated list of query ids that should be included in this SARIF file.
queries-not-run:
required: true
description: |
Comma separated list of query ids that should NOT be included in this SARIF file.
config-file:
required: true
description: |
The location of the codeql configuration file to use.
tools:
required: true
description: |
The url of codeql to use.
runs:
using: composite
steps:
- uses: ./../action/init
with:
languages: javascript
config-file: ${{ inputs.config-file }}
tools: ${{ inputs.tools }}
db-location: ${{ runner.temp }}/query-filter-test
- uses: ./../action/analyze
with:
output: ${{ runner.temp }}/results
upload-database: false
upload: false
env:
TEST_MODE: "true"
- name: Check SARIF
uses: ./../action/.github/check-sarif
with:
sarif-file: ${{ inputs.sarif-file }}
queries-run: ${{ inputs.queries-run}}
queries-not-run: ${{ inputs.queries-not-run}}
- name: Cleanup after test
shell: bash
run: rm -rf "$RUNNER_TEMP/results" "$RUNNER_TEMP//query-filter-test"

View File

@@ -0,0 +1,47 @@
name: Check queries that ran
on:
push:
branches:
- main
- releases/v1
- releases/v2
pull_request:
types:
- opened
- synchronize
- reopened
- ready_for_review
workflow_dispatch: {}
jobs:
expected-queries:
name: Expected Queries Tests
timeout-minutes: 45
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Prepare test
id: prepare-test
uses: ./.github/prepare-test
with:
version: latest
- uses: ./../action/init
with:
languages: javascript
tools: ${{ steps.prepare-test.outputs.tools-url }}
- uses: ./../action/analyze
with:
output: ${{ runner.temp }}/results
upload-database: false
upload: false
env:
TEST_MODE: true
- name: Check Sarif
uses: ./../action/.github/check-sarif
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: js/incomplete-hostname-regexp,js/path-injection
queries-not-run: foo,bar

56
.github/workflows/query-filters.yml vendored Normal file
View File

@@ -0,0 +1,56 @@
name: Query filters tests
on:
push:
branches:
- main
- releases/v1
- releases/v2
pull_request:
types:
- opened
- synchronize
- reopened
- ready_for_review
workflow_dispatch: {}
jobs:
query-filters:
name: Query Filters Tests
timeout-minutes: 45
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v3
- name: Prepare test
id: prepare-test
uses: ./.github/prepare-test
with:
version: latest
- name: Check SARIF for default queries with Single include, Single exclude
uses: ./../action/.github/query-filter-test
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: js/zipslip
queries-not-run: js/path-injection
config-file: ./.github/codeql/codeql-config-query-filters1.yml
tools: ${{ steps.prepare-test.outputs.tools-url }}
- name: Check SARIF for query packs with Single include, Single exclude
uses: ./../action/.github/query-filter-test
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: js/zipslip,javascript/example/empty-or-one-block
queries-not-run: js/path-injection
config-file: ./.github/codeql/codeql-config-query-filters2.yml
tools: ${{ steps.prepare-test.outputs.tools-url }}
- name: Check SARIF for query packs and local queries with Single include, Single exclude
uses: ./../action/.github/query-filter-test
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: js/zipslip,javascript/example/empty-or-one-block,inrepo-javascript-querypack/show-ifs
queries-not-run: js/path-injection,complex-python-querypack/show-ifs,complex-python-querypack/foo/bar/show-ifs
config-file: ./.github/codeql/codeql-config-query-filters3.yml
tools: ${{ steps.prepare-test.outputs.tools-url }}

View File

@@ -21,7 +21,7 @@ fi
echo "Getting checks for $GITHUB_SHA"
# Ignore any checks with "https://", CodeQL, LGTM, and Update checks.
CHECKS="$(gh api repos/github/codeql-action/commits/${GITHUB_SHA}/check-runs --paginate | jq --slurp --compact-output --raw-output '[.[].check_runs | .[].name | select(contains("https://") or . == "CodeQL" or . == "LGTM.com" or contains("Update") | not)] | sort')"
CHECKS="$(gh api repos/github/codeql-action/commits/${GITHUB_SHA}/check-runs --paginate | jq --slurp --compact-output --raw-output '[.[].check_runs | .[].name | select(contains("https://") or . == "CodeQL" or . == "LGTM.com" or contains("Update") | not)] | unique | sort')"
echo "$CHECKS" | jq

View File

@@ -1,8 +1,13 @@
# CodeQL Action Changelog
## [UNRELEASED]
## 2.1.13 - 21 Jun 2022
No user facing changes.
- Add the ability to filter queries from a code scanning run by using the `query-filters` option in the code scanning configuration file. [#1098](https://github.com/github/codeql-action/pull/1098)
- Update default CodeQL bundle version to 2.9.4. [#1100](https://github.com/github/codeql-action/pull/1100)
## 2.1.12 - 01 Jun 2022
- Update default CodeQL bundle version to 2.9.3. [#1084](https://github.com/github/codeql-action/pull/1084)
## 2.1.11 - 17 May 2022

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

78
lib/analyze.js generated
View File

@@ -18,14 +18,19 @@ var __importStar = (this && this.__importStar) || function (mod) {
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.runCleanup = exports.runFinalize = exports.runQueries = exports.CodeQLAnalysisError = void 0;
exports.validateQueryFilters = exports.runCleanup = exports.runFinalize = exports.createQuerySuiteContents = exports.convertPackToQuerySuiteEntry = exports.runQueries = exports.CodeQLAnalysisError = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
const del_1 = __importDefault(require("del"));
const yaml = __importStar(require("js-yaml"));
const analysisPaths = __importStar(require("./analysis-paths"));
const codeql_1 = require("./codeql");
const configUtils = __importStar(require("./config-utils"));
const count_loc_1 = require("./count-loc");
const languages_1 = require("./languages");
const sharedEnv = __importStar(require("./shared-environment"));
@@ -124,6 +129,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
}
for (const language of config.languages) {
const queries = config.queries[language];
const queryFilters = validateQueryFilters(config.originalUserInput["query-filters"]);
const packsWithVersion = config.packs[language] || [];
const hasBuiltinQueries = (queries === null || queries === void 0 ? void 0 : queries.builtin.length) > 0;
const hasCustomQueries = (queries === null || queries === void 0 ? void 0 : queries.custom.length) > 0;
@@ -146,7 +152,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
const querySuitePaths = [];
if (queries["builtin"].length > 0) {
const startTimeBuiltIn = new Date().getTime();
querySuitePaths.push(await runQueryGroup(language, "builtin", createQuerySuiteContents(queries["builtin"]), undefined));
querySuitePaths.push(await runQueryGroup(language, "builtin", createQuerySuiteContents(queries["builtin"], queryFilters), undefined));
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
new Date().getTime() - startTimeBuiltIn;
}
@@ -154,12 +160,12 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
let ranCustom = false;
for (let i = 0; i < queries["custom"].length; ++i) {
if (queries["custom"][i].queries.length > 0) {
querySuitePaths.push(await runQueryGroup(language, `custom-${i}`, createQuerySuiteContents(queries["custom"][i].queries), queries["custom"][i].searchPath));
querySuitePaths.push(await runQueryGroup(language, `custom-${i}`, createQuerySuiteContents(queries["custom"][i].queries, queryFilters), queries["custom"][i].searchPath));
ranCustom = true;
}
}
if (packsWithVersion.length > 0) {
querySuitePaths.push(...(await runQueryPacks(language, "packs", packsWithVersion, undefined)));
querySuitePaths.push(await runQueryPacks(language, "packs", packsWithVersion, queryFilters));
ranCustom = true;
}
if (ranCustom) {
@@ -217,23 +223,41 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
return querySuitePath;
}
async function runQueryPacks(language, type, packs, searchPath) {
async function runQueryPacks(language, type, packs, queryFilters) {
const databasePath = util.getCodeQLDatabasePath(config, language);
// Run the queries individually instead of all at once to avoid command
// line length restrictions, particularly on windows.
for (const pack of packs) {
logger.debug(`Running query pack for ${language}-${type}: ${pack}`);
const codeql = await (0, codeql_1.getCodeQL)(config.codeQLCmd);
await codeql.databaseRunQueries(databasePath, searchPath, pack, memoryFlag, threadsFlag);
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
}
return packs;
// combine the list of packs into a query suite in order to run them all simultaneously.
const querySuite = packs.map(convertPackToQuerySuiteEntry).concat(queryFilters);
const querySuitePath = `${databasePath}-queries-${type}.qls`;
fs.writeFileSync(querySuitePath, yaml.dump(querySuite));
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
const codeql = await (0, codeql_1.getCodeQL)(config.codeQLCmd);
await codeql.databaseRunQueries(databasePath, undefined, querySuitePath, memoryFlag, threadsFlag);
return querySuitePath;
}
}
exports.runQueries = runQueries;
function createQuerySuiteContents(queries) {
return queries.map((q) => `- query: ${q}`).join("\n");
function convertPackToQuerySuiteEntry(packStr) {
var _a, _b, _c, _d;
const pack = configUtils.parsePacksSpecification(packStr);
return {
qlpack: !pack.path ? pack.name : undefined,
from: pack.path ? pack.name : undefined,
version: pack.version,
query: ((_a = pack.path) === null || _a === void 0 ? void 0 : _a.endsWith(".ql")) ? pack.path : undefined,
queries: !((_b = pack.path) === null || _b === void 0 ? void 0 : _b.endsWith(".ql")) && !((_c = pack.path) === null || _c === void 0 ? void 0 : _c.endsWith(".qls"))
? pack.path
: undefined,
apply: ((_d = pack.path) === null || _d === void 0 ? void 0 : _d.endsWith(".qls")) ? pack.path : undefined,
};
}
exports.convertPackToQuerySuiteEntry = convertPackToQuerySuiteEntry;
function createQuerySuiteContents(queries, queryFilters) {
return yaml.dump(queries.map((q) => ({ query: q })).concat(queryFilters));
}
exports.createQuerySuiteContents = createQuerySuiteContents;
async function runFinalize(outputDir, threadsFlag, memoryFlag, config, logger) {
const codeql = await (0, codeql_1.getCodeQL)(config.codeQLCmd);
if (await util.codeQlVersionAbove(codeql, codeql_1.CODEQL_VERSION_NEW_TRACING)) {
@@ -244,13 +268,8 @@ async function runFinalize(outputDir, threadsFlag, memoryFlag, config, logger) {
// Delete the tracer config env var to avoid tracing ourselves
delete process.env[sharedEnv.ODASA_TRACER_CONFIGURATION];
}
// After switching to Node16, this entire block can be replaced with `await fs.promises.rm(outputDir, { recursive: true, force: true });`.
try {
await fs.promises.rmdir(outputDir, {
recursive: true,
maxRetries: 5,
retryDelay: 2000,
});
await (0, del_1.default)(outputDir, { force: true });
}
catch (error) {
if ((error === null || error === void 0 ? void 0 : error.code) !== "ENOENT") {
@@ -299,4 +318,25 @@ function printLinesOfCodeSummary(logger, language, lineCounts) {
logger.info(`Counted a baseline of ${lineCounts[language]} lines of code for ${language}.`);
}
}
// exported for testing
function validateQueryFilters(queryFilters) {
if (!queryFilters) {
return [];
}
const errors = [];
for (const qf of queryFilters) {
const keys = Object.keys(qf);
if (keys.length !== 1) {
errors.push(`Query filter must have exactly one key: ${JSON.stringify(qf)}`);
}
if (!["exclude", "include"].includes(keys[0])) {
errors.push(`Only "include" or "exclude" filters are allowed:\n${JSON.stringify(qf)}`);
}
}
if (errors.length) {
throw new Error(`Invalid query filter.\n${errors.join("\n")}`);
}
return queryFilters;
}
exports.validateQueryFilters = validateQueryFilters;
//# sourceMappingURL=analyze.js.map

File diff suppressed because one or more lines are too long

132
lib/analyze.test.js generated
View File

@@ -210,4 +210,136 @@ const util = __importStar(require("./util"));
}
}
});
(0, ava_1.default)("validateQueryFilters", (t) => {
t.notThrows(() => (0, analyze_1.validateQueryFilters)([]));
t.notThrows(() => (0, analyze_1.validateQueryFilters)(undefined));
t.notThrows(() => {
return (0, analyze_1.validateQueryFilters)([
{
exclude: {
"problem.severity": "recommendation",
},
},
{
exclude: {
"tags contain": ["foo", "bar"],
},
},
{
include: {
"problem.severity": "something-to-think-about",
},
},
{
include: {
"tags contain": ["baz", "bop"],
},
},
]);
});
t.throws(() => {
return (0, analyze_1.validateQueryFilters)([
{
exclude: {
"tags contain": ["foo", "bar"],
},
include: {
"tags contain": ["baz", "bop"],
},
},
]);
}, { message: /Query filter must have exactly one key/ });
t.throws(() => {
return (0, analyze_1.validateQueryFilters)([{ xxx: "foo" }]);
}, { message: /Only "include" or "exclude" filters are allowed/ });
});
const convertPackToQuerySuiteEntryMacro = ava_1.default.macro({
exec: (t, packSpec, suiteEntry) => t.deepEqual((0, analyze_1.convertPackToQuerySuiteEntry)(packSpec), suiteEntry),
title: (_providedTitle, packSpec) => `Query Suite Entry: ${packSpec}`,
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b", {
qlpack: "a/b",
from: undefined,
version: undefined,
query: undefined,
queries: undefined,
apply: undefined,
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3", {
qlpack: "a/b",
from: undefined,
version: "~1.2.3",
query: undefined,
queries: undefined,
apply: undefined,
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b:my/path", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: undefined,
queries: "my/path",
apply: undefined,
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: undefined,
queries: "my/path",
apply: undefined,
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b:my/path/query.ql", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: "my/path/query.ql",
queries: undefined,
apply: undefined,
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path/query.ql", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: "my/path/query.ql",
queries: undefined,
apply: undefined,
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b:my/path/suite.qls", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: undefined,
queries: undefined,
apply: "my/path/suite.qls",
});
(0, ava_1.default)(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path/suite.qls", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: undefined,
queries: undefined,
apply: "my/path/suite.qls",
});
(0, ava_1.default)("convertPackToQuerySuiteEntry Failure", (t) => {
t.throws(() => (0, analyze_1.convertPackToQuerySuiteEntry)("this-is-not-a-pack"));
});
(0, ava_1.default)("createQuerySuiteContents", (t) => {
const yamlResult = (0, analyze_1.createQuerySuiteContents)(["query1.ql", "query2.ql"], [
{
exclude: { "problem.severity": "recommendation" },
},
{
include: { "problem.severity": "recommendation" },
},
]);
const expected = `- query: query1.ql
- query: query2.ql
- exclude:
problem.severity: recommendation
- include:
problem.severity: recommendation
`;
t.deepEqual(yamlResult, expected);
});
//# sourceMappingURL=analyze.test.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
{ "maximumVersion": "3.5", "minimumVersion": "3.1" }
{ "maximumVersion": "3.6", "minimumVersion": "3.2" }

31
lib/config-utils.js generated
View File

@@ -19,7 +19,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.parsePacks = exports.validatePacksSpecification = exports.parsePacksFromConfig = exports.getDefaultConfig = exports.getUnknownLanguagesError = exports.getNoLanguagesError = exports.getConfigFileDirectoryGivenMessage = exports.getConfigFileFormatInvalidMessage = exports.getConfigFileRepoFormatInvalidMessage = exports.getConfigFileDoesNotExistErrorMessage = exports.getConfigFileOutsideWorkspaceErrorMessage = exports.getLocalPathDoesNotExist = exports.getLocalPathOutsideOfRepository = exports.getPacksStrInvalid = exports.getPacksInvalid = exports.getPacksInvalidSplit = exports.getPacksRequireLanguage = exports.getPathsInvalid = exports.getPathsIgnoreInvalid = exports.getQueryUsesInvalid = exports.getQueriesInvalid = exports.getDisableDefaultQueriesInvalid = exports.getNameInvalid = exports.validateAndSanitisePath = void 0;
exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.parsePacks = exports.validatePackSpecification = exports.prettyPrintPack = exports.parsePacksSpecification = exports.parsePacksFromConfig = exports.getDefaultConfig = exports.getUnknownLanguagesError = exports.getNoLanguagesError = exports.getConfigFileDirectoryGivenMessage = exports.getConfigFileFormatInvalidMessage = exports.getConfigFileRepoFormatInvalidMessage = exports.getConfigFileDoesNotExistErrorMessage = exports.getConfigFileOutsideWorkspaceErrorMessage = exports.getLocalPathDoesNotExist = exports.getLocalPathOutsideOfRepository = exports.getPacksStrInvalid = exports.getPacksInvalid = exports.getPacksInvalidSplit = exports.getPacksRequireLanguage = exports.getPathsInvalid = exports.getPathsIgnoreInvalid = exports.getQueryUsesInvalid = exports.getQueriesInvalid = exports.getDisableDefaultQueriesInvalid = exports.getNameInvalid = exports.validateAndSanitisePath = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const yaml = __importStar(require("js-yaml"));
@@ -150,9 +150,7 @@ async function addBuiltinSuiteQueries(languages, codeQL, resultMap, packs, suite
return injectedMlQueries;
}
function isMlPoweredJsQueriesPack(pack) {
return (pack === util_1.ML_POWERED_JS_QUERIES_PACK_NAME ||
pack.startsWith(`${util_1.ML_POWERED_JS_QUERIES_PACK_NAME}@`) ||
pack.startsWith(`${util_1.ML_POWERED_JS_QUERIES_PACK_NAME}:`));
return parsePacksSpecification(pack).name === util_1.ML_POWERED_JS_QUERIES_PACK_NAME;
}
/**
* Retrieve the set of queries at localQueryPath and add them to resultMap.
@@ -638,10 +636,7 @@ function parsePacksFromConfig(packsByLanguage, languages, configFile) {
if (!languages.includes(lang)) {
throw new Error(getPacksRequireLanguage(lang, configFile));
}
packs[lang] = [];
for (const packStr of packsArr) {
packs[lang].push(validatePacksSpecification(packStr, configFile));
}
packs[lang] = packsArr.map((packStr) => validatePackSpecification(packStr, configFile));
}
return packs;
}
@@ -665,7 +660,7 @@ function parsePacksFromInput(packsInput, languages) {
}
return {
[languages[0]]: packsInput.split(",").reduce((packs, pack) => {
packs.push(validatePacksSpecification(pack, ""));
packs.push(validatePackSpecification(pack));
return packs;
}, []),
};
@@ -688,7 +683,7 @@ function parsePacksFromInput(packsInput, languages) {
* @param packStr the package specification to verify.
* @param configFile Config file to use for error reporting
*/
function validatePacksSpecification(packStr, configFile) {
function parsePacksSpecification(packStr, configFile) {
if (typeof packStr !== "string") {
throw new Error(getPacksStrInvalid(packStr, configFile));
}
@@ -730,9 +725,21 @@ function validatePacksSpecification(packStr, configFile) {
// 0 length path
throw new Error(getPacksStrInvalid(packStr, configFile));
}
return (packName + (version ? `@${version}` : "") + (packPath ? `:${packPath}` : ""));
return {
name: packName,
version,
path: packPath,
};
}
exports.validatePacksSpecification = validatePacksSpecification;
exports.parsePacksSpecification = parsePacksSpecification;
function prettyPrintPack(pack) {
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${pack.path ? `:${pack.path}` : ""}`;
}
exports.prettyPrintPack = prettyPrintPack;
function validatePackSpecification(pack, configFile) {
return prettyPrintPack(parsePacksSpecification(pack, configFile));
}
exports.validatePackSpecification = validatePackSpecification;
// exported for testing
function parsePacks(rawPacksFromConfig, rawPacksInput, languages, configFile) {
const packsFromInput = parsePacksFromInput(rawPacksInput, languages);

File diff suppressed because one or more lines are too long

View File

@@ -828,6 +828,46 @@ const invalidPackNameMacro = ava_1.default.macro({
(0, ava_1.default)(invalidPackNameMacro, "c/d@../a");
(0, ava_1.default)(invalidPackNameMacro, "c/d@b/../a");
(0, ava_1.default)(invalidPackNameMacro, "c/d:z@1");
/**
* Test macro for pretty printing pack specs
*/
const packSpecPrettyPrintingMacro = ava_1.default.macro({
exec: (t, packStr, packObj) => {
const parsed = configUtils.parsePacksSpecification(packStr);
t.deepEqual(parsed, packObj, "parsed pack spec is correct");
const stringified = configUtils.prettyPrintPack(packObj);
t.deepEqual(stringified, packStr.trim(), "pretty-printed pack spec is correct");
t.deepEqual(configUtils.validatePackSpecification(packStr), packStr.trim(), "pack spec is valid");
},
title: (_providedTitle, packStr,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_packObj) => `Prettyprint pack spec: '${packStr}'`,
});
(0, ava_1.default)(packSpecPrettyPrintingMacro, "a/b", {
name: "a/b",
version: undefined,
path: undefined,
});
(0, ava_1.default)(packSpecPrettyPrintingMacro, "a/b@~1.2.3", {
name: "a/b",
version: "~1.2.3",
path: undefined,
});
(0, ava_1.default)(packSpecPrettyPrintingMacro, "a/b@~1.2.3:abc/def", {
name: "a/b",
version: "~1.2.3",
path: "abc/def",
});
(0, ava_1.default)(packSpecPrettyPrintingMacro, "a/b:abc/def", {
name: "a/b",
version: undefined,
path: "abc/def",
});
(0, ava_1.default)(packSpecPrettyPrintingMacro, " a/b:abc/def ", {
name: "a/b",
version: undefined,
path: "abc/def",
});
/**
* Test macro for testing the packs block and the packs input
*/
@@ -925,4 +965,10 @@ const mlPoweredQueriesMacro = ava_1.default.macro({
(0, ava_1.default)(mlPoweredQueriesMacro, "2.9.0", true, undefined, "security-and-quality", "~0.2.0");
// Test that we don't inject an ML-powered query pack if the user has already specified one.
(0, ava_1.default)(mlPoweredQueriesMacro, "2.9.0", true, "codeql/javascript-experimental-atm-queries@0.0.1", "security-and-quality", "0.0.1");
// Test that ML-powered queries are run on all platforms running `security-extended` on CodeQL
// CLI 2.9.3+.
(0, ava_1.default)(mlPoweredQueriesMacro, "2.9.3", true, undefined, "security-extended", "~0.3.0");
// Test that ML-powered queries are run on all platforms running `security-and-quality` on CodeQL
// CLI 2.9.3+.
(0, ava_1.default)(mlPoweredQueriesMacro, "2.9.3", true, undefined, "security-and-quality", "~0.3.0");
//# sourceMappingURL=config-utils.test.js.map

File diff suppressed because one or more lines are too long

View File

@@ -1,3 +1,3 @@
{
"bundleVersion": "codeql-bundle-20220512"
"bundleVersion": "codeql-bundle-20220615"
}

3
lib/languages.js generated
View File

@@ -11,6 +11,7 @@ var Language;
Language["javascript"] = "javascript";
Language["python"] = "python";
Language["ruby"] = "ruby";
Language["swift"] = "swift";
})(Language = exports.Language || (exports.Language = {}));
// Additional names for languages
const LANGUAGE_ALIASES = {
@@ -35,7 +36,7 @@ function parseLanguage(language) {
}
exports.parseLanguage = parseLanguage;
function isTracedLanguage(language) {
return (["cpp", "java", "csharp"].includes(language) ||
return (["cpp", "java", "csharp", "swift"].includes(language) ||
(process.env["CODEQL_EXTRACTOR_GO_BUILD_TRACING"] === "on" &&
language === Language.go));
}

View File

@@ -1 +1 @@
{"version":3,"file":"languages.js","sourceRoot":"","sources":["../src/languages.ts"],"names":[],"mappings":";;;AAAA,wCAAwC;AACxC,IAAY,QAQX;AARD,WAAY,QAAQ;IAClB,6BAAiB,CAAA;IACjB,uBAAW,CAAA;IACX,qBAAS,CAAA;IACT,yBAAa,CAAA;IACb,qCAAyB,CAAA;IACzB,6BAAiB,CAAA;IACjB,yBAAa,CAAA;AACf,CAAC,EARW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QAQnB;AAED,iCAAiC;AACjC,MAAM,gBAAgB,GAAiC;IACrD,CAAC,EAAE,QAAQ,CAAC,GAAG;IACf,KAAK,EAAE,QAAQ,CAAC,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAC,MAAM;IACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAChC,CAAC;AAEF,gGAAgG;AAChG,SAAgB,aAAa,CAAC,QAAgB;IAC5C,0BAA0B;IAC1B,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAElC,6BAA6B;IAC7B,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,OAAO,QAAoB,CAAC;KAC7B;IAED,yBAAyB;IACzB,IAAI,QAAQ,IAAI,gBAAgB,EAAE;QAChC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;KACnC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAfD,sCAeC;AAED,SAAgB,gBAAgB,CAAC,QAAkB;IACjD,OAAO,CACL,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAC5C,CAAC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,KAAK,IAAI;YACxD,QAAQ,KAAK,QAAQ,CAAC,EAAE,CAAC,CAC5B,CAAC;AACJ,CAAC;AAND,4CAMC;AAED,SAAgB,iBAAiB,CAAC,QAAkB;IAClD,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AAFD,8CAEC"}
{"version":3,"file":"languages.js","sourceRoot":"","sources":["../src/languages.ts"],"names":[],"mappings":";;;AAAA,wCAAwC;AACxC,IAAY,QASX;AATD,WAAY,QAAQ;IAClB,6BAAiB,CAAA;IACjB,uBAAW,CAAA;IACX,qBAAS,CAAA;IACT,yBAAa,CAAA;IACb,qCAAyB,CAAA;IACzB,6BAAiB,CAAA;IACjB,yBAAa,CAAA;IACb,2BAAe,CAAA;AACjB,CAAC,EATW,QAAQ,GAAR,gBAAQ,KAAR,gBAAQ,QASnB;AAED,iCAAiC;AACjC,MAAM,gBAAgB,GAAiC;IACrD,CAAC,EAAE,QAAQ,CAAC,GAAG;IACf,KAAK,EAAE,QAAQ,CAAC,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAC,MAAM;IACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAChC,CAAC;AAEF,gGAAgG;AAChG,SAAgB,aAAa,CAAC,QAAgB;IAC5C,0BAA0B;IAC1B,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IAElC,6BAA6B;IAC7B,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,OAAO,QAAoB,CAAC;KAC7B;IAED,yBAAyB;IACzB,IAAI,QAAQ,IAAI,gBAAgB,EAAE;QAChC,OAAO,gBAAgB,CAAC,QAAQ,CAAC,CAAC;KACnC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAfD,sCAeC;AAED,SAAgB,gBAAgB,CAAC,QAAkB;IACjD,OAAO,CACL,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;QACrD,CAAC,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,KAAK,IAAI;YACxD,QAAQ,KAAK,QAAQ,CAAC,EAAE,CAAC,CAC5B,CAAC;AACJ,CAAC;AAND,4CAMC;AAED,SAAgB,iBAAiB,CAAC,QAAkB;IAClD,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AAFD,8CAEC"}

24
lib/util.js generated
View File

@@ -33,6 +33,7 @@ const api = __importStar(require("./api-client"));
const api_client_1 = require("./api-client");
const apiCompatibility = __importStar(require("./api-compatibility.json"));
const codeql_1 = require("./codeql");
const config_utils_1 = require("./config-utils");
/**
* Specifies bundle versions that are known to be broken
* and will not be used if found in the toolcache.
@@ -552,10 +553,20 @@ exports.ML_POWERED_JS_QUERIES_PACK_NAME = "codeql/javascript-experimental-atm-qu
* queries beta.
*/
async function getMlPoweredJsQueriesPack(codeQL) {
if (await codeQlVersionAbove(codeQL, "2.8.4")) {
return `${exports.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.2.0`;
let version;
if (await codeQlVersionAbove(codeQL, "2.9.3")) {
version = `~0.3.0`;
}
return `${exports.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`;
else if (await codeQlVersionAbove(codeQL, "2.8.4")) {
version = `~0.2.0`;
}
else {
version = `~0.1.0`;
}
return (0, config_utils_1.prettyPrintPack)({
name: exports.ML_POWERED_JS_QUERIES_PACK_NAME,
version,
});
}
exports.getMlPoweredJsQueriesPack = getMlPoweredJsQueriesPack;
/**
@@ -581,9 +592,8 @@ exports.getMlPoweredJsQueriesPack = getMlPoweredJsQueriesPack;
*/
function getMlPoweredJsQueriesStatus(config) {
const mlPoweredJsQueryPacks = (config.packs.javascript || [])
.map((pack) => pack.split("@"))
.filter((packNameVersion) => packNameVersion[0] === "codeql/javascript-experimental-atm-queries" &&
packNameVersion.length <= 2);
.map((p) => (0, config_utils_1.parsePacksSpecification)(p))
.filter((pack) => pack.name === "codeql/javascript-experimental-atm-queries" && !pack.path);
switch (mlPoweredJsQueryPacks.length) {
case 1:
// We should always specify an explicit version string in `getMlPoweredJsQueriesPack`,
@@ -591,7 +601,7 @@ function getMlPoweredJsQueriesStatus(config) {
// with each version of the CodeQL Action. Therefore in practice we should only hit the
// `latest` case here when customers have explicitly added the ML-powered query pack to their
// CodeQL config.
return mlPoweredJsQueryPacks[0][1] || "latest";
return mlPoweredJsQueryPacks[0].version || "latest";
case 0:
return "false";
default:

File diff suppressed because one or more lines are too long

6
lib/util.test.js generated
View File

@@ -209,13 +209,13 @@ const ML_POWERED_JS_STATUS_TESTS = [
// If no packs are loaded, status is false.
[[], "false"],
// If another pack is loaded but not the ML-powered query pack, status is false.
[["someOtherPack"], "false"],
[["some-other/pack"], "false"],
// If the ML-powered query pack is loaded with a specific version, status is that version.
[[`${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`], "~0.1.0"],
// If the ML-powered query pack is loaded with a specific version and another pack is loaded, the
// status is the version of the ML-powered query pack.
[
["someOtherPack", `${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`],
["some-other/pack", `${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`],
"~0.1.0",
],
// If the ML-powered query pack is loaded without a version, the status is "latest".
@@ -230,7 +230,7 @@ const ML_POWERED_JS_STATUS_TESTS = [
],
// If the ML-powered query pack is loaded with no specific version, and another pack is loaded,
// the status is "latest".
[["someOtherPack", util.ML_POWERED_JS_QUERIES_PACK_NAME], "latest"],
[["some-other/pack", util.ML_POWERED_JS_QUERIES_PACK_NAME], "latest"],
];
for (const [packs, expectedStatus] of ML_POWERED_JS_STATUS_TESTS) {
const packDescriptions = `[${packs

File diff suppressed because one or more lines are too long

8
node_modules/.package-lock.json generated vendored
View File

@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "2.1.12",
"version": "2.1.13",
"lockfileVersion": 2,
"requires": true,
"packages": {
@@ -469,6 +469,12 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"node_modules/@types/js-yaml": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz",
"integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==",
"dev": true
},
"node_modules/@types/json-schema": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz",

21
node_modules/@types/js-yaml/LICENSE generated vendored Executable file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) Microsoft Corporation.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE

16
node_modules/@types/js-yaml/README.md generated vendored Executable file
View File

@@ -0,0 +1,16 @@
# Installation
> `npm install --save @types/js-yaml`
# Summary
This package contains type definitions for js-yaml (https://github.com/nodeca/js-yaml).
# Details
Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/js-yaml.
### Additional Details
* Last updated: Fri, 19 Nov 2021 18:01:12 GMT
* Dependencies: none
* Global values: `jsyaml`
# Credits
These definitions were written by [Bart van der Schoor](https://github.com/Bartvds), [Sebastian Clausen](https://github.com/sclausen), [ExE Boss](https://github.com/ExE-Boss), [Armaan Tobaccowalla](https://github.com/ArmaanT), and [Linus Unnebäck](https://github.com/LinusU).

2
node_modules/@types/js-yaml/index.d.mts generated vendored Executable file
View File

@@ -0,0 +1,2 @@
export * from "./index.js";
export { default } from "./index.js";

154
node_modules/@types/js-yaml/index.d.ts generated vendored Executable file
View File

@@ -0,0 +1,154 @@
// Type definitions for js-yaml 4.0
// Project: https://github.com/nodeca/js-yaml
// Definitions by: Bart van der Schoor <https://github.com/Bartvds>
// Sebastian Clausen <https://github.com/sclausen>
// ExE Boss <https://github.com/ExE-Boss>
// Armaan Tobaccowalla <https://github.com/ArmaanT>
// Linus Unnebäck <https://github.com/LinusU>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
// TypeScript Version: 2.2
export as namespace jsyaml;
export function load(str: string, opts?: LoadOptions): unknown;
export class Type {
constructor(tag: string, opts?: TypeConstructorOptions);
kind: 'sequence' | 'scalar' | 'mapping' | null;
resolve(data: any): boolean;
construct(data: any, type?: string): any;
instanceOf: object | null;
predicate: ((data: object) => boolean) | null;
represent: ((data: object) => any) | { [x: string]: (data: object) => any } | null;
representName: ((data: object) => any) | null;
defaultStyle: string | null;
multi: boolean;
styleAliases: { [x: string]: any };
}
export class Schema {
constructor(definition: SchemaDefinition | Type[] | Type);
extend(types: SchemaDefinition | Type[] | Type): Schema;
}
export function loadAll(str: string, iterator?: null, opts?: LoadOptions): unknown[];
export function loadAll(str: string, iterator: (doc: unknown) => void, opts?: LoadOptions): void;
export function dump(obj: any, opts?: DumpOptions): string;
export interface LoadOptions {
/** string to be used as a file path in error/warning messages. */
filename?: string | undefined;
/** function to call on warning messages. */
onWarning?(this: null, e: YAMLException): void;
/** specifies a schema to use. */
schema?: Schema | undefined;
/** compatibility with JSON.parse behaviour. */
json?: boolean | undefined;
/** listener for parse events */
listener?(this: State, eventType: EventType, state: State): void;
}
export type EventType = 'open' | 'close';
export interface State {
input: string;
filename: string | null;
schema: Schema;
onWarning: (this: null, e: YAMLException) => void;
json: boolean;
length: number;
position: number;
line: number;
lineStart: number;
lineIndent: number;
version: null | number;
checkLineBreaks: boolean;
kind: string;
result: any;
implicitTypes: Type[];
}
export interface DumpOptions {
/** indentation width to use (in spaces). */
indent?: number | undefined;
/** when true, will not add an indentation level to array elements */
noArrayIndent?: boolean | undefined;
/** do not throw on invalid types (like function in the safe schema) and skip pairs and single values with such types. */
skipInvalid?: boolean | undefined;
/** specifies level of nesting, when to switch from block to flow style for collections. -1 means block style everwhere */
flowLevel?: number | undefined;
/** Each tag may have own set of styles. - "tag" => "style" map. */
styles?: { [x: string]: any } | undefined;
/** specifies a schema to use. */
schema?: Schema | undefined;
/** if true, sort keys when dumping YAML. If a function, use the function to sort the keys. (default: false) */
sortKeys?: boolean | ((a: any, b: any) => number) | undefined;
/** set max line width. (default: 80) */
lineWidth?: number | undefined;
/** if true, don't convert duplicate objects into references (default: false) */
noRefs?: boolean | undefined;
/** if true don't try to be compatible with older yaml versions. Currently: don't quote "yes", "no" and so on, as required for YAML 1.1 (default: false) */
noCompatMode?: boolean | undefined;
/**
* if true flow sequences will be condensed, omitting the space between `key: value` or `a, b`. Eg. `'[a,b]'` or `{a:{b:c}}`.
* Can be useful when using yaml for pretty URL query params as spaces are %-encoded. (default: false).
*/
condenseFlow?: boolean | undefined;
/** strings will be quoted using this quoting style. If you specify single quotes, double quotes will still be used for non-printable characters. (default: `'`) */
quotingType?: "'" | '"' | undefined;
/** if true, all non-key strings will be quoted even if they normally don't need to. (default: false) */
forceQuotes?: boolean | undefined;
/** callback `function (key, value)` called recursively on each key/value in source object (see `replacer` docs for `JSON.stringify`). */
replacer?: ((key: string, value: any) => any) | undefined;
}
export interface TypeConstructorOptions {
kind?: 'sequence' | 'scalar' | 'mapping' | undefined;
resolve?: ((data: any) => boolean) | undefined;
construct?: ((data: any, type?: string) => any) | undefined;
instanceOf?: object | undefined;
predicate?: ((data: object) => boolean) | undefined;
represent?: ((data: object) => any) | { [x: string]: (data: object) => any } | undefined;
representName?: ((data: object) => any) | undefined;
defaultStyle?: string | undefined;
multi?: boolean | undefined;
styleAliases?: { [x: string]: any } | undefined;
}
export interface SchemaDefinition {
implicit?: Type[] | undefined;
explicit?: Type[] | undefined;
}
/** only strings, arrays and plain objects: http://www.yaml.org/spec/1.2/spec.html#id2802346 */
export let FAILSAFE_SCHEMA: Schema;
/** only strings, arrays and plain objects: http://www.yaml.org/spec/1.2/spec.html#id2802346 */
export let JSON_SCHEMA: Schema;
/** same as JSON_SCHEMA: http://www.yaml.org/spec/1.2/spec.html#id2804923 */
export let CORE_SCHEMA: Schema;
/** all supported YAML types */
export let DEFAULT_SCHEMA: Schema;
export interface Mark {
buffer: string;
column: number;
line: number;
name: string;
position: number;
snippet: string;
}
export class YAMLException extends Error {
constructor(reason?: string, mark?: Mark);
toString(compact?: boolean): string;
name: string;
reason: string;
message: string;
mark: Mark;
}

53
node_modules/@types/js-yaml/package.json generated vendored Executable file
View File

@@ -0,0 +1,53 @@
{
"name": "@types/js-yaml",
"version": "4.0.5",
"description": "TypeScript definitions for js-yaml",
"homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/js-yaml",
"license": "MIT",
"contributors": [
{
"name": "Bart van der Schoor",
"url": "https://github.com/Bartvds",
"githubUsername": "Bartvds"
},
{
"name": "Sebastian Clausen",
"url": "https://github.com/sclausen",
"githubUsername": "sclausen"
},
{
"name": "ExE Boss",
"url": "https://github.com/ExE-Boss",
"githubUsername": "ExE-Boss"
},
{
"name": "Armaan Tobaccowalla",
"url": "https://github.com/ArmaanT",
"githubUsername": "ArmaanT"
},
{
"name": "Linus Unnebäck",
"url": "https://github.com/LinusU",
"githubUsername": "LinusU"
}
],
"main": "",
"types": "index.d.ts",
"repository": {
"type": "git",
"url": "https://github.com/DefinitelyTyped/DefinitelyTyped.git",
"directory": "types/js-yaml"
},
"scripts": {},
"dependencies": {},
"typesPublisherContentHash": "6f40877154edac83ffa22d53a6aca74f151a0d094074c81ce7fb21df57ea5725",
"typeScriptVersion": "3.8",
"exports": {
".": {
"types": {
"import": "./index.d.mts",
"default": "./index.d.ts"
}
}
}
}

17
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "codeql",
"version": "2.1.12",
"version": "2.1.13",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "codeql",
"version": "2.1.12",
"version": "2.1.13",
"license": "MIT",
"dependencies": {
"@actions/artifact": "^1.0.0",
@@ -38,6 +38,7 @@
},
"devDependencies": {
"@ava/typescript": "3.0.1",
"@types/js-yaml": "^4.0.5",
"@types/long": "4.0.1",
"@types/node": "16.11.22",
"@types/semver": "^7.3.8",
@@ -521,6 +522,12 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"node_modules/@types/js-yaml": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz",
"integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==",
"dev": true
},
"node_modules/@types/json-schema": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz",
@@ -5885,6 +5892,12 @@
"integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==",
"dev": true
},
"@types/js-yaml": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz",
"integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==",
"dev": true
},
"@types/json-schema": {
"version": "7.0.8",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.8.tgz",

View File

@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "2.1.12",
"version": "2.1.13",
"private": true,
"description": "CodeQL action",
"scripts": {
@@ -53,6 +53,7 @@
],
"devDependencies": {
"@ava/typescript": "3.0.1",
"@types/js-yaml": "^4.0.5",
"@types/long": "4.0.1",
"@types/node": "16.11.22",
"@types/semver": "^7.3.8",

View File

@@ -269,7 +269,7 @@ test("getWorkflowErrors() when on.push is correct with empty objects", (t) => {
on:
push:
pull_request:
`)
`) as actionsutil.Workflow
);
t.deepEqual(...errorCodes(errors, []));
@@ -441,7 +441,7 @@ on:
push:
branches: ["main"]
pull_request:
`)
`) as actionsutil.Workflow
);
t.deepEqual(
@@ -559,7 +559,7 @@ test("getWorkflowErrors() when branches contain dots", (t) => {
pull_request:
# The branches below must be a subset of the branches above
branches: [4.1, master]
`)
`) as actionsutil.Workflow
);
t.deepEqual(...errorCodes(errors, []));
@@ -575,7 +575,7 @@ on:
pull_request:
# The branches below must be a subset of the branches above
branches: [master]
`)
`) as actionsutil.Workflow
);
t.deepEqual(...errorCodes(errors, []));
@@ -604,7 +604,7 @@ jobs:
test3:
steps: []
`)
`) as actionsutil.Workflow
);
t.deepEqual(
@@ -635,7 +635,7 @@ jobs:
test3:
steps: []
`)
`) as actionsutil.Workflow
);
t.deepEqual(...errorCodes(errors, []));
@@ -645,7 +645,7 @@ test("getWorkflowErrors() when on is missing", (t) => {
const errors = actionsutil.getWorkflowErrors(
yaml.load(`
name: "CodeQL"
`)
`) as actionsutil.Workflow
);
t.deepEqual(...errorCodes(errors, []));
@@ -658,7 +658,7 @@ test("getWorkflowErrors() with a different on setup", (t) => {
yaml.load(`
name: "CodeQL"
on: "workflow_dispatch"
`)
`) as actionsutil.Workflow
),
[]
)
@@ -670,7 +670,7 @@ on: "workflow_dispatch"
yaml.load(`
name: "CodeQL"
on: [workflow_dispatch]
`)
`) as actionsutil.Workflow
),
[]
)
@@ -683,7 +683,7 @@ on: [workflow_dispatch]
name: "CodeQL"
on:
workflow_dispatch: {}
`)
`) as actionsutil.Workflow
),
[]
)
@@ -699,7 +699,7 @@ name: "CodeQL"
on:
push:
branches: [master]
`)
`) as actionsutil.Workflow
),
[]
)
@@ -711,7 +711,7 @@ on:
yaml.load(`
name: "CodeQL"
on: ["push"]
`)
`) as actionsutil.Workflow
),
[]
)

View File

@@ -191,7 +191,7 @@ interface WorkflowTriggers {
pull_request?: WorkflowTrigger | null;
}
interface Workflow {
export interface Workflow {
jobs?: { [key: string]: WorkflowJob };
on?: string | string[] | WorkflowTriggers;
}
@@ -411,7 +411,7 @@ export async function getWorkflow(): Promise<Workflow> {
relativePath
);
return yaml.load(fs.readFileSync(absolutePath, "utf-8"));
return yaml.load(fs.readFileSync(absolutePath, "utf-8")) as Workflow;
}
/**

View File

@@ -1,11 +1,16 @@
import * as fs from "fs";
import * as path from "path";
import test from "ava";
import test, { ExecutionContext } from "ava";
import * as yaml from "js-yaml";
import * as sinon from "sinon";
import { runQueries } from "./analyze";
import {
convertPackToQuerySuiteEntry,
createQuerySuiteContents,
runQueries,
validateQueryFilters,
} from "./analyze";
import { setCodeQL } from "./codeql";
import { Config } from "./config-utils";
import * as count from "./count-loc";
@@ -249,3 +254,161 @@ test("status report fields and search path setting", async (t) => {
}
}
});
test("validateQueryFilters", (t) => {
t.notThrows(() => validateQueryFilters([]));
t.notThrows(() => validateQueryFilters(undefined));
t.notThrows(() => {
return validateQueryFilters([
{
exclude: {
"problem.severity": "recommendation",
},
},
{
exclude: {
"tags contain": ["foo", "bar"],
},
},
{
include: {
"problem.severity": "something-to-think-about",
},
},
{
include: {
"tags contain": ["baz", "bop"],
},
},
]);
});
t.throws(
() => {
return validateQueryFilters([
{
exclude: {
"tags contain": ["foo", "bar"],
},
include: {
"tags contain": ["baz", "bop"],
},
},
]);
},
{ message: /Query filter must have exactly one key/ }
);
t.throws(
() => {
return validateQueryFilters([{ xxx: "foo" } as any]);
},
{ message: /Only "include" or "exclude" filters are allowed/ }
);
});
const convertPackToQuerySuiteEntryMacro = test.macro({
exec: (t: ExecutionContext<unknown>, packSpec: string, suiteEntry: any) =>
t.deepEqual(convertPackToQuerySuiteEntry(packSpec), suiteEntry),
title: (_providedTitle, packSpec: string) => `Query Suite Entry: ${packSpec}`,
});
test(convertPackToQuerySuiteEntryMacro, "a/b", {
qlpack: "a/b",
from: undefined,
version: undefined,
query: undefined,
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3", {
qlpack: "a/b",
from: undefined,
version: "~1.2.3",
query: undefined,
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b:my/path", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: undefined,
queries: "my/path",
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: undefined,
queries: "my/path",
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b:my/path/query.ql", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: "my/path/query.ql",
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path/query.ql", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: "my/path/query.ql",
queries: undefined,
apply: undefined,
});
test(convertPackToQuerySuiteEntryMacro, "a/b:my/path/suite.qls", {
qlpack: undefined,
from: "a/b",
version: undefined,
query: undefined,
queries: undefined,
apply: "my/path/suite.qls",
});
test(convertPackToQuerySuiteEntryMacro, "a/b@~1.2.3:my/path/suite.qls", {
qlpack: undefined,
from: "a/b",
version: "~1.2.3",
query: undefined,
queries: undefined,
apply: "my/path/suite.qls",
});
test("convertPackToQuerySuiteEntry Failure", (t) => {
t.throws(() => convertPackToQuerySuiteEntry("this-is-not-a-pack"));
});
test("createQuerySuiteContents", (t) => {
const yamlResult = createQuerySuiteContents(
["query1.ql", "query2.ql"],
[
{
exclude: { "problem.severity": "recommendation" },
},
{
include: { "problem.severity": "recommendation" },
},
]
);
const expected = `- query: query1.ql
- query: query2.ql
- exclude:
problem.severity: recommendation
- include:
problem.severity: recommendation
`;
t.deepEqual(yamlResult, expected);
});

View File

@@ -2,6 +2,7 @@ import * as fs from "fs";
import * as path from "path";
import * as toolrunner from "@actions/exec/lib/toolrunner";
import del from "del";
import * as yaml from "js-yaml";
import * as analysisPaths from "./analysis-paths";
@@ -151,7 +152,7 @@ function dbIsFinalized(
try {
const dbInfo = yaml.load(
fs.readFileSync(path.resolve(dbPath, "codeql-database.yml"), "utf8")
);
) as { inProgress?: boolean };
return !("inProgress" in dbInfo);
} catch (e) {
logger.warning(
@@ -223,6 +224,9 @@ export async function runQueries(
for (const language of config.languages) {
const queries = config.queries[language];
const queryFilters = validateQueryFilters(
config.originalUserInput["query-filters"]
);
const packsWithVersion = config.packs[language] || [];
const hasBuiltinQueries = queries?.builtin.length > 0;
@@ -260,7 +264,7 @@ export async function runQueries(
await runQueryGroup(
language,
"builtin",
createQuerySuiteContents(queries["builtin"]),
createQuerySuiteContents(queries["builtin"], queryFilters),
undefined
)
);
@@ -275,7 +279,10 @@ export async function runQueries(
await runQueryGroup(
language,
`custom-${i}`,
createQuerySuiteContents(queries["custom"][i].queries),
createQuerySuiteContents(
queries["custom"][i].queries,
queryFilters
),
queries["custom"][i].searchPath
)
);
@@ -284,12 +291,7 @@ export async function runQueries(
}
if (packsWithVersion.length > 0) {
querySuitePaths.push(
...(await runQueryPacks(
language,
"packs",
packsWithVersion,
undefined
))
await runQueryPacks(language, "packs", packsWithVersion, queryFilters)
);
ranCustom = true;
}
@@ -391,32 +393,61 @@ export async function runQueries(
language: Language,
type: string,
packs: string[],
searchPath: string | undefined
): Promise<string[]> {
queryFilters: configUtils.QueryFilter[]
): Promise<string> {
const databasePath = util.getCodeQLDatabasePath(config, language);
// Run the queries individually instead of all at once to avoid command
// line length restrictions, particularly on windows.
for (const pack of packs) {
logger.debug(`Running query pack for ${language}-${type}: ${pack}`);
const codeql = await getCodeQL(config.codeQLCmd);
await codeql.databaseRunQueries(
databasePath,
searchPath,
pack,
memoryFlag,
threadsFlag
);
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
}
return packs;
// combine the list of packs into a query suite in order to run them all simultaneously.
const querySuite = (
packs.map(convertPackToQuerySuiteEntry) as configUtils.QuerySuiteEntry[]
).concat(queryFilters);
const querySuitePath = `${databasePath}-queries-${type}.qls`;
fs.writeFileSync(querySuitePath, yaml.dump(querySuite));
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
const codeql = await getCodeQL(config.codeQLCmd);
await codeql.databaseRunQueries(
databasePath,
undefined,
querySuitePath,
memoryFlag,
threadsFlag
);
return querySuitePath;
}
}
function createQuerySuiteContents(queries: string[]) {
return queries.map((q: string) => `- query: ${q}`).join("\n");
export function convertPackToQuerySuiteEntry(
packStr: string
): configUtils.QuerySuitePackEntry {
const pack = configUtils.parsePacksSpecification(packStr);
return {
qlpack: !pack.path ? pack.name : undefined,
from: pack.path ? pack.name : undefined,
version: pack.version,
query: pack.path?.endsWith(".ql") ? pack.path : undefined,
queries:
!pack.path?.endsWith(".ql") && !pack.path?.endsWith(".qls")
? pack.path
: undefined,
apply: pack.path?.endsWith(".qls") ? pack.path : undefined,
};
}
export function createQuerySuiteContents(
queries: string[],
queryFilters: configUtils.QueryFilter[]
) {
return yaml.dump(
queries.map((q: string) => ({ query: q })).concat(queryFilters as any)
);
}
export async function runFinalize(
@@ -435,13 +466,8 @@ export async function runFinalize(
delete process.env[sharedEnv.ODASA_TRACER_CONFIGURATION];
}
// After switching to Node16, this entire block can be replaced with `await fs.promises.rm(outputDir, { recursive: true, force: true });`.
try {
await fs.promises.rmdir(outputDir, {
recursive: true,
maxRetries: 5,
retryDelay: 2000,
} as any);
await del(outputDir, { force: true });
} catch (error: any) {
if (error?.code !== "ENOENT") {
throw error;
@@ -509,3 +535,33 @@ function printLinesOfCodeSummary(
);
}
}
// exported for testing
export function validateQueryFilters(queryFilters?: configUtils.QueryFilter[]) {
if (!queryFilters) {
return [];
}
const errors: string[] = [];
for (const qf of queryFilters) {
const keys = Object.keys(qf);
if (keys.length !== 1) {
errors.push(
`Query filter must have exactly one key: ${JSON.stringify(qf)}`
);
}
if (!["exclude", "include"].includes(keys[0])) {
errors.push(
`Only "include" or "exclude" filters are allowed:\n${JSON.stringify(
qf
)}`
);
}
}
if (errors.length) {
throw new Error(`Invalid query filter.\n${errors.join("\n")}`);
}
return queryFilters;
}

View File

@@ -1 +1 @@
{"maximumVersion": "3.5", "minimumVersion": "3.1"}
{"maximumVersion": "3.6", "minimumVersion": "3.2"}

View File

@@ -1572,6 +1572,60 @@ test(invalidPackNameMacro, "c/d@../a");
test(invalidPackNameMacro, "c/d@b/../a");
test(invalidPackNameMacro, "c/d:z@1");
/**
* Test macro for pretty printing pack specs
*/
const packSpecPrettyPrintingMacro = test.macro({
exec: (t: ExecutionContext, packStr: string, packObj: configUtils.Pack) => {
const parsed = configUtils.parsePacksSpecification(packStr);
t.deepEqual(parsed, packObj, "parsed pack spec is correct");
const stringified = configUtils.prettyPrintPack(packObj);
t.deepEqual(
stringified,
packStr.trim(),
"pretty-printed pack spec is correct"
);
t.deepEqual(
configUtils.validatePackSpecification(packStr),
packStr.trim(),
"pack spec is valid"
);
},
title: (
_providedTitle: string | undefined,
packStr: string,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_packObj: configUtils.Pack
) => `Prettyprint pack spec: '${packStr}'`,
});
test(packSpecPrettyPrintingMacro, "a/b", {
name: "a/b",
version: undefined,
path: undefined,
});
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3", {
name: "a/b",
version: "~1.2.3",
path: undefined,
});
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3:abc/def", {
name: "a/b",
version: "~1.2.3",
path: "abc/def",
});
test(packSpecPrettyPrintingMacro, "a/b:abc/def", {
name: "a/b",
version: undefined,
path: "abc/def",
});
test(packSpecPrettyPrintingMacro, " a/b:abc/def ", {
name: "a/b",
version: undefined,
path: "abc/def",
});
/**
* Test macro for testing the packs block and the packs input
*/
@@ -1865,3 +1919,23 @@ test(
"security-and-quality",
"0.0.1"
);
// Test that ML-powered queries are run on all platforms running `security-extended` on CodeQL
// CLI 2.9.3+.
test(
mlPoweredQueriesMacro,
"2.9.3",
true,
undefined,
"security-extended",
"~0.3.0"
);
// Test that ML-powered queries are run on all platforms running `security-and-quality` on CodeQL
// CLI 2.9.3+.
test(
mlPoweredQueriesMacro,
"2.9.3",
true,
undefined,
"security-and-quality",
"~0.3.0"
);

View File

@@ -49,8 +49,38 @@ export interface UserConfig {
// language. If this is a single language analysis, then no split by
// language is necessary.
packs?: Record<string, string[]> | string[];
// Set of query filters to include and exclude extra queries based on
// codeql query suite `include` and `exclude` properties
"query-filters"?: QueryFilter[];
}
export type QueryFilter = ExcludeQueryFilter | IncludeQueryFilter;
interface ExcludeQueryFilter {
exclude: Record<string, string[] | string>;
}
interface IncludeQueryFilter {
include: Record<string, string[] | string>;
}
export type QuerySuitePackEntry = {
version?: string;
} & (
| {
qlpack: string;
}
| {
from?: string;
query?: string;
queries?: string;
apply?: string;
}
);
export type QuerySuiteEntry = QuerySuitePackEntry | QueryFilter;
/**
* Lists of query files for each language.
* Will only contain .ql files and not other kinds of files,
@@ -157,6 +187,12 @@ export interface Config {
export type Packs = Partial<Record<Language, string[]>>;
export interface Pack {
name: string;
version?: string;
path?: string;
}
/**
* A list of queries from https://github.com/github/codeql that
* we don't want to run. Disabling them here is a quicker alternative to
@@ -319,11 +355,7 @@ async function addBuiltinSuiteQueries(
}
function isMlPoweredJsQueriesPack(pack: string) {
return (
pack === ML_POWERED_JS_QUERIES_PACK_NAME ||
pack.startsWith(`${ML_POWERED_JS_QUERIES_PACK_NAME}@`) ||
pack.startsWith(`${ML_POWERED_JS_QUERIES_PACK_NAME}:`)
);
return parsePacksSpecification(pack).name === ML_POWERED_JS_QUERIES_PACK_NAME;
}
/**
@@ -1170,10 +1202,10 @@ export function parsePacksFromConfig(
if (!languages.includes(lang as Language)) {
throw new Error(getPacksRequireLanguage(lang, configFile));
}
packs[lang] = [];
for (const packStr of packsArr) {
packs[lang].push(validatePacksSpecification(packStr, configFile));
}
packs[lang] = packsArr.map((packStr) =>
validatePackSpecification(packStr, configFile)
);
}
return packs;
}
@@ -1206,7 +1238,7 @@ function parsePacksFromInput(
return {
[languages[0]]: packsInput.split(",").reduce((packs, pack) => {
packs.push(validatePacksSpecification(pack, ""));
packs.push(validatePackSpecification(pack));
return packs;
}, [] as string[]),
};
@@ -1230,10 +1262,10 @@ function parsePacksFromInput(
* @param packStr the package specification to verify.
* @param configFile Config file to use for error reporting
*/
export function validatePacksSpecification(
export function parsePacksSpecification(
packStr: string,
configFile?: string
): string {
): Pack {
if (typeof packStr !== "string") {
throw new Error(getPacksStrInvalid(packStr, configFile));
}
@@ -1286,9 +1318,21 @@ export function validatePacksSpecification(
throw new Error(getPacksStrInvalid(packStr, configFile));
}
return (
packName + (version ? `@${version}` : "") + (packPath ? `:${packPath}` : "")
);
return {
name: packName,
version,
path: packPath,
};
}
export function prettyPrintPack(pack: Pack) {
return `${pack.name}${pack.version ? `@${pack.version}` : ""}${
pack.path ? `:${pack.path}` : ""
}`;
}
export function validatePackSpecification(pack: string, configFile?: string) {
return prettyPrintPack(parsePacksSpecification(pack, configFile));
}
// exported for testing
@@ -1448,7 +1492,7 @@ function getLocalConfig(configFile: string, workspacePath: string): UserConfig {
throw new Error(getConfigFileDoesNotExistErrorMessage(configFile));
}
return yaml.load(fs.readFileSync(configFile, "utf8"));
return yaml.load(fs.readFileSync(configFile, "utf8")) as UserConfig;
}
async function getRemoteConfig(
@@ -1483,7 +1527,9 @@ async function getRemoteConfig(
throw new Error(getConfigFileFormatInvalidMessage(configFile));
}
return yaml.load(Buffer.from(fileContents, "base64").toString("binary"));
return yaml.load(
Buffer.from(fileContents, "base64").toString("binary")
) as UserConfig;
}
/**

View File

@@ -1,3 +1,3 @@
{
"bundleVersion": "codeql-bundle-20220512"
"bundleVersion": "codeql-bundle-20220615"
}

View File

@@ -7,6 +7,7 @@ export enum Language {
javascript = "javascript",
python = "python",
ruby = "ruby",
swift = "swift",
}
// Additional names for languages
@@ -37,7 +38,7 @@ export function parseLanguage(language: string): Language | undefined {
export function isTracedLanguage(language: Language): boolean {
return (
["cpp", "java", "csharp"].includes(language) ||
["cpp", "java", "csharp", "swift"].includes(language) ||
(process.env["CODEQL_EXTRACTOR_GO_BUILD_TRACING"] === "on" &&
language === Language.go)
);

View File

@@ -298,13 +298,13 @@ const ML_POWERED_JS_STATUS_TESTS: Array<[string[], string]> = [
// If no packs are loaded, status is false.
[[], "false"],
// If another pack is loaded but not the ML-powered query pack, status is false.
[["someOtherPack"], "false"],
[["some-other/pack"], "false"],
// If the ML-powered query pack is loaded with a specific version, status is that version.
[[`${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`], "~0.1.0"],
// If the ML-powered query pack is loaded with a specific version and another pack is loaded, the
// status is the version of the ML-powered query pack.
[
["someOtherPack", `${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`],
["some-other/pack", `${util.ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`],
"~0.1.0",
],
// If the ML-powered query pack is loaded without a version, the status is "latest".
@@ -319,7 +319,7 @@ const ML_POWERED_JS_STATUS_TESTS: Array<[string[], string]> = [
],
// If the ML-powered query pack is loaded with no specific version, and another pack is loaded,
// the status is "latest".
[["someOtherPack", util.ML_POWERED_JS_QUERIES_PACK_NAME], "latest"],
[["some-other/pack", util.ML_POWERED_JS_QUERIES_PACK_NAME], "latest"],
];
for (const [packs, expectedStatus] of ML_POWERED_JS_STATUS_TESTS) {

View File

@@ -11,7 +11,11 @@ import * as api from "./api-client";
import { getApiClient, GitHubApiDetails } from "./api-client";
import * as apiCompatibility from "./api-compatibility.json";
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
import { Config } from "./config-utils";
import {
Config,
parsePacksSpecification,
prettyPrintPack,
} from "./config-utils";
import { Language } from "./languages";
import { Logger } from "./logging";
@@ -664,10 +668,18 @@ export const ML_POWERED_JS_QUERIES_PACK_NAME =
export async function getMlPoweredJsQueriesPack(
codeQL: CodeQL
): Promise<string> {
if (await codeQlVersionAbove(codeQL, "2.8.4")) {
return `${ML_POWERED_JS_QUERIES_PACK_NAME}@~0.2.0`;
let version;
if (await codeQlVersionAbove(codeQL, "2.9.3")) {
version = `~0.3.0`;
} else if (await codeQlVersionAbove(codeQL, "2.8.4")) {
version = `~0.2.0`;
} else {
version = `~0.1.0`;
}
return `${ML_POWERED_JS_QUERIES_PACK_NAME}@~0.1.0`;
return prettyPrintPack({
name: ML_POWERED_JS_QUERIES_PACK_NAME,
version,
});
}
/**
@@ -693,11 +705,10 @@ export async function getMlPoweredJsQueriesPack(
*/
export function getMlPoweredJsQueriesStatus(config: Config): string {
const mlPoweredJsQueryPacks = (config.packs.javascript || [])
.map((pack) => pack.split("@"))
.map((p) => parsePacksSpecification(p))
.filter(
(packNameVersion) =>
packNameVersion[0] === "codeql/javascript-experimental-atm-queries" &&
packNameVersion.length <= 2
(pack) =>
pack.name === "codeql/javascript-experimental-atm-queries" && !pack.path
);
switch (mlPoweredJsQueryPacks.length) {
case 1:
@@ -706,7 +717,7 @@ export function getMlPoweredJsQueriesStatus(config: Config): string {
// with each version of the CodeQL Action. Therefore in practice we should only hit the
// `latest` case here when customers have explicitly added the ML-powered query pack to their
// CodeQL config.
return mlPoweredJsQueryPacks[0][1] || "latest";
return mlPoweredJsQueryPacks[0].version || "latest";
case 0:
return "false";
default:

View File

@@ -0,0 +1,10 @@
name: "Check SARIF for default queries with Single include, Single exclude"
query-filters:
# This should run js/path-injection and js/zipslip
- include:
tags contain: external/cwe/cwe-022
# Removes js/path-injection
- exclude:
id: js/path-injection

View File

@@ -0,0 +1,21 @@
name: "Check SARIF for query packs with Single include, Single exclude"
disable-default-queries: true
packs:
javascript:
- codeql/javascript-queries
- dsp-testing/codeql-pack1@1.0.0
query-filters:
# This should run js/path-injection and js/zipslip
- include:
tags contain: external/cwe/cwe-022
# Removes js/path-injection
- exclude:
id: js/path-injection
# Query from extra pack
- include:
id: javascript/example/empty-or-one-block

View File

@@ -0,0 +1,35 @@
name: "Check SARIF for query packs and local queries with Single include, Single exclude"
disable-default-queries: true
queries:
# Local query
- name: Run an extra local query
uses: ./codeql-qlpacks/javascript-qlpack/show_ifs.ql
# These queries are ignored
- name: Ignored queries
uses: ./codeql-qlpacks/complex-python-qlpack/rootAndBar.qls
packs:
javascript:
- codeql/javascript-queries
- dsp-testing/codeql-pack1@1.0.0
query-filters:
# This should run js/path-injection and js/zipslip
- include:
tags contain: external/cwe/cwe-022
# Removes js/path-injection
- exclude:
id: js/path-injection
# Query from extra pack
- include:
id: javascript/example/empty-or-one-block
# Local query
- include:
id: inrepo-javascript-querypack/show-ifs