mirror of
https://github.com/github/codeql-action.git
synced 2026-08-05 04:57:19 -05:00
Compare commits
54 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a589d4087e | |||
| 98d24e5629 | |||
| 903be79953 | |||
| 18ff14b615 | |||
| 36a249f5ae | |||
| 041757fc59 | |||
| 8f19113f88 | |||
| cf1855ae37 | |||
| 652709d1b9 | |||
| 32dc499307 | |||
| b742728ac2 | |||
| 237a258d2b | |||
| 5972e6d72e | |||
| 164027e682 | |||
| 736263f8fe | |||
| 3dde1f3512 | |||
| d7d7567b0e | |||
| 0e4e857bab | |||
| 08d1f21d4f | |||
| f3bd25eefa | |||
| 41f1810e52 | |||
| d87ad69338 | |||
| 8242edb8ed | |||
| 3095a09bb0 | |||
| e00cd12e3e | |||
| a25536bc80 | |||
| a2487fb969 | |||
| e187d074ed | |||
| 89c5165e5a | |||
| ba216f7d34 | |||
| 68f4f0d3bb | |||
| 12d9a244fa | |||
| 17573ee1cc | |||
| b6975b4b1a | |||
| b011dbdedf | |||
| 40babc141f | |||
| 5492b7d104 | |||
| 3c81243bb1 | |||
| e2f72f11e4 | |||
| 7ba5ed7eed | |||
| 21f3020df6 | |||
| b872c5adfd | |||
| 8775e86802 | |||
| a2ad80b966 | |||
| c4e22e9fce | |||
| db534af2ae | |||
| bbe8d375fd | |||
| 4369dda4ae | |||
| 4f08c2cf20 | |||
| 81644f35ff | |||
| 9ab6aa64a0 | |||
| 256973e279 | |||
| 59b25b480f | |||
| 39c954c513 |
@@ -33,6 +33,12 @@
|
|||||||
"alphabetize": {"order": "asc"},
|
"alphabetize": {"order": "asc"},
|
||||||
"newlines-between": "always"
|
"newlines-between": "always"
|
||||||
}],
|
}],
|
||||||
|
"max-len": ["error", {
|
||||||
|
"code": 120,
|
||||||
|
"ignoreUrls": true,
|
||||||
|
"ignoreStrings": true,
|
||||||
|
"ignoreTemplateLiterals": true
|
||||||
|
}],
|
||||||
"no-async-foreach/no-async-foreach": "error",
|
"no-async-foreach/no-async-foreach": "error",
|
||||||
"no-console": "off",
|
"no-console": "off",
|
||||||
"no-sequences": "error",
|
"no-sequences": "error",
|
||||||
|
|||||||
+42
@@ -25,6 +25,18 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
- os: ubuntu-latest
|
||||||
|
version: cached
|
||||||
|
- os: macos-latest
|
||||||
|
version: cached
|
||||||
|
- os: windows-latest
|
||||||
|
version: cached
|
||||||
|
- os: ubuntu-latest
|
||||||
|
version: latest
|
||||||
|
- os: macos-latest
|
||||||
|
version: latest
|
||||||
|
- os: windows-latest
|
||||||
|
version: latest
|
||||||
- os: ubuntu-latest
|
- os: ubuntu-latest
|
||||||
version: nightly-latest
|
version: nightly-latest
|
||||||
- os: macos-latest
|
- os: macos-latest
|
||||||
@@ -75,5 +87,35 @@ jobs:
|
|||||||
echo "::error $CODEQL_PACK1 pack was not installed."
|
echo "::error $CODEQL_PACK1 pack was not installed."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Verify qlconfig.yml file was created
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
QLCONFIG_PATH=$RUNNER_TEMP/qlconfig.yml
|
||||||
|
echo "Expected qlconfig.yml file to be created at $QLCONFIG_PATH"
|
||||||
|
if [[ -f $QLCONFIG_PATH ]]
|
||||||
|
then
|
||||||
|
echo "qlconfig.yml file was created."
|
||||||
|
else
|
||||||
|
echo "::error qlconfig.yml file was not created."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Verify contents of qlconfig.yml
|
||||||
|
# yq is not available on windows
|
||||||
|
if: runner.os != 'Windows'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
QLCONFIG_PATH=$RUNNER_TEMP/qlconfig.yml
|
||||||
|
cat $QLCONFIG_PATH | yq -e '.registries[] | select(.url == "https://ghcr.io/v2/") | select(.packages == "*/*")'
|
||||||
|
if [[ $? -eq 0 ]]
|
||||||
|
then
|
||||||
|
echo "Registry was added to qlconfig.yml file."
|
||||||
|
else
|
||||||
|
echo "::error Registry was not added to qlconfig.yml file."
|
||||||
|
echo "Contents of qlconfig.yml file:"
|
||||||
|
cat $QLCONFIG_PATH
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
env:
|
env:
|
||||||
CODEQL_ACTION_TEST_MODE: true
|
CODEQL_ACTION_TEST_MODE: true
|
||||||
|
|||||||
@@ -7,13 +7,9 @@ if [ ! -z "$(git status --porcelain)" ]; then
|
|||||||
>&2 echo "Failed: Repo should be clean before testing!"
|
>&2 echo "Failed: Repo should be clean before testing!"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
# When updating this, make sure to update the npm version in
|
|
||||||
# `.github/workflows/update-dependencies.yml` too.
|
"$(dirname "$0")/update-node-modules.sh" check-only
|
||||||
sudo npm install --force -g npm@9.2.0
|
|
||||||
# Reinstall modules and then clean to remove absolute paths
|
|
||||||
# Use 'npm ci' instead of 'npm install' as this is intended to be reproducible
|
|
||||||
npm ci
|
|
||||||
npm run removeNPMAbsolutePaths
|
|
||||||
# Check that repo is still clean
|
# Check that repo is still clean
|
||||||
if [ ! -z "$(git status --porcelain)" ]; then
|
if [ ! -z "$(git status --porcelain)" ]; then
|
||||||
# If we get a fail here then the PR needs attention
|
# If we get a fail here then the PR needs attention
|
||||||
|
|||||||
+18
@@ -0,0 +1,18 @@
|
|||||||
|
if [ "$1" != "update" && "$1" != "check-only" ]; then
|
||||||
|
>&2 echo "Failed: Invalid argument. Must be 'update' or 'check-only'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
sudo npm install --force -g npm@9.2.0
|
||||||
|
|
||||||
|
# clean the npm cache to ensure we don't have any files owned by root
|
||||||
|
sudo npm cache clean --force
|
||||||
|
|
||||||
|
if [ "$1" = "update" ]; then
|
||||||
|
npm install
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Reinstall modules and then clean to remove absolute paths
|
||||||
|
# Use 'npm ci' instead of 'npm install' as this is intended to be reproducible
|
||||||
|
npm ci
|
||||||
|
npm run removeNPMAbsolutePaths
|
||||||
@@ -27,12 +27,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
git fetch origin "$BRANCH" --depth=1
|
git fetch origin "$BRANCH" --depth=1
|
||||||
git checkout "origin/$BRANCH"
|
git checkout "origin/$BRANCH"
|
||||||
# When updating this, make sure to update the npm version in
|
.github/workflows/script/update-node-modules.sh update
|
||||||
# `.github/workflows/script/check-node-modules.sh` too.
|
|
||||||
sudo npm install --force -g npm@9.2.0
|
|
||||||
npm install
|
|
||||||
npm ci
|
|
||||||
npm run removeNPMAbsolutePaths
|
|
||||||
if [ ! -z "$(git status --porcelain)" ]; then
|
if [ ! -z "$(git status --porcelain)" ]; then
|
||||||
git config --global user.email "github-actions@github.com"
|
git config --global user.email "github-actions@github.com"
|
||||||
git config --global user.name "github-actions[bot]"
|
git config --global user.name "github-actions[bot]"
|
||||||
|
|||||||
@@ -1,5 +1,21 @@
|
|||||||
# CodeQL Action Changelog
|
# CodeQL Action Changelog
|
||||||
|
|
||||||
|
## [UNRELEASED]
|
||||||
|
|
||||||
|
No user facing changes.
|
||||||
|
|
||||||
|
## 2.2.5 - 24 Feb 2023
|
||||||
|
|
||||||
|
- Update default CodeQL bundle version to 2.12.3. [#1543](https://github.com/github/codeql-action/pull/1543)
|
||||||
|
|
||||||
|
## 2.2.4 - 10 Feb 2023
|
||||||
|
|
||||||
|
No user facing changes.
|
||||||
|
|
||||||
|
## 2.2.3 - 08 Feb 2023
|
||||||
|
|
||||||
|
- Update default CodeQL bundle version to 2.12.2. [#1518](https://github.com/github/codeql-action/pull/1518)
|
||||||
|
|
||||||
## 2.2.2 - 06 Feb 2023
|
## 2.2.2 - 06 Feb 2023
|
||||||
|
|
||||||
- Fix an issue where customers using the CodeQL Action with the [CodeQL Action sync tool](https://docs.github.com/en/enterprise-server@3.7/admin/code-security/managing-github-advanced-security-for-your-enterprise/configuring-code-scanning-for-your-appliance#configuring-codeql-analysis-on-a-server-without-internet-access) would not be able to obtain the CodeQL tools. [#1517](https://github.com/github/codeql-action/pull/1517)
|
- Fix an issue where customers using the CodeQL Action with the [CodeQL Action sync tool](https://docs.github.com/en/enterprise-server@3.7/admin/code-security/managing-github-advanced-security-for-your-enterprise/configuring-code-scanning-for-your-appliance#configuring-codeql-analysis-on-a-server-without-internet-access) would not be able to obtain the CodeQL tools. [#1517](https://github.com/github/codeql-action/pull/1517)
|
||||||
|
|||||||
+1
-5
@@ -67,12 +67,8 @@ Here are a few things you can do that will increase the likelihood of your pull
|
|||||||
This mergeback incorporates the changelog updates into `main`, tags the release using the merge commit of the "Merge main into releases/v2" pull request, and bumps the patch version of the CodeQL Action.
|
This mergeback incorporates the changelog updates into `main`, tags the release using the merge commit of the "Merge main into releases/v2" pull request, and bumps the patch version of the CodeQL Action.
|
||||||
|
|
||||||
Approve the mergeback PR and automerge it.
|
Approve the mergeback PR and automerge it.
|
||||||
1. When the "Merge main into releases/v2" pull request is merged into the `releases/v2` branch, the "Update release branch" workflow will create a "Merge releases/v2 into releases/v1" pull request to merge the changes since the last release into the `releases/v1` release branch.
|
|
||||||
This ensures we keep both the `releases/v1` and `releases/v2` release branches up to date and fully supported.
|
|
||||||
|
|
||||||
Review the checklist items in the pull request description.
|
Once the mergeback has been merged to `main`, the release is complete.
|
||||||
Once you've checked off all the items, approve the PR and automerge it.
|
|
||||||
1. Once the mergeback has been merged to `main` and the "Merge releases/v2 into releases/v1" PR has been merged to `releases/v1`, the release is complete.
|
|
||||||
|
|
||||||
## Keeping the PR checks up to date (admin access required)
|
## Keeping the PR checks up to date (admin access required)
|
||||||
|
|
||||||
|
|||||||
Generated
+19
-13
@@ -126,6 +126,7 @@ async function finalizeDatabaseCreation(config, threadsFlag, memoryFlag, logger)
|
|||||||
async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, automationDetailsId, config, logger, featureEnablement) {
|
async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag, automationDetailsId, config, logger, featureEnablement) {
|
||||||
const statusReport = {};
|
const statusReport = {};
|
||||||
const codeql = await (0, codeql_1.getCodeQL)(config.codeQLCmd);
|
const codeql = await (0, codeql_1.getCodeQL)(config.codeQLCmd);
|
||||||
|
const queryFlags = [memoryFlag, threadsFlag];
|
||||||
await util.logCodeScanningConfigInCli(codeql, featureEnablement, logger);
|
await util.logCodeScanningConfigInCli(codeql, featureEnablement, logger);
|
||||||
for (const language of config.languages) {
|
for (const language of config.languages) {
|
||||||
const queries = config.queries[language];
|
const queries = config.queries[language];
|
||||||
@@ -140,7 +141,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||||||
// another to interpret the results.
|
// another to interpret the results.
|
||||||
logger.startGroup(`Running queries for ${language}`);
|
logger.startGroup(`Running queries for ${language}`);
|
||||||
const startTimeBuiltIn = new Date().getTime();
|
const startTimeBuiltIn = new Date().getTime();
|
||||||
await runQueryGroup(language, "all", undefined, undefined);
|
await runQueryGroup(language, "all", undefined, undefined, true);
|
||||||
// TODO should not be using `builtin` here. We should be using `all` instead.
|
// TODO should not be using `builtin` here. We should be using `all` instead.
|
||||||
// The status report does not support `all` yet.
|
// The status report does not support `all` yet.
|
||||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||||
@@ -164,24 +165,29 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||||||
!hasPackWithCustomQueries) {
|
!hasPackWithCustomQueries) {
|
||||||
throw new Error(`Unable to analyze ${language} as no queries were selected for this language`);
|
throw new Error(`Unable to analyze ${language} as no queries were selected for this language`);
|
||||||
}
|
}
|
||||||
|
const customQueryIndices = [];
|
||||||
|
for (let i = 0; i < queries.custom.length; ++i) {
|
||||||
|
if (queries.custom[i].queries.length > 0) {
|
||||||
|
customQueryIndices.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
logger.startGroup(`Running queries for ${language}`);
|
logger.startGroup(`Running queries for ${language}`);
|
||||||
const querySuitePaths = [];
|
const querySuitePaths = [];
|
||||||
if (queries["builtin"].length > 0) {
|
if (queries.builtin.length > 0) {
|
||||||
const startTimeBuiltIn = new Date().getTime();
|
const startTimeBuiltIn = new Date().getTime();
|
||||||
querySuitePaths.push((await runQueryGroup(language, "builtin", createQuerySuiteContents(queries["builtin"], queryFilters), undefined)));
|
querySuitePaths.push((await runQueryGroup(language, "builtin", createQuerySuiteContents(queries.builtin, queryFilters), undefined, customQueryIndices.length === 0 && packsWithVersion.length === 0)));
|
||||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||||
new Date().getTime() - startTimeBuiltIn;
|
new Date().getTime() - startTimeBuiltIn;
|
||||||
}
|
}
|
||||||
const startTimeCustom = new Date().getTime();
|
const startTimeCustom = new Date().getTime();
|
||||||
let ranCustom = false;
|
let ranCustom = false;
|
||||||
for (let i = 0; i < queries["custom"].length; ++i) {
|
for (const i of customQueryIndices) {
|
||||||
if (queries["custom"][i].queries.length > 0) {
|
querySuitePaths.push((await runQueryGroup(language, `custom-${i}`, createQuerySuiteContents(queries.custom[i].queries, queryFilters), queries.custom[i].searchPath, i === customQueryIndices[customQueryIndices.length - 1] &&
|
||||||
querySuitePaths.push((await runQueryGroup(language, `custom-${i}`, createQuerySuiteContents(queries["custom"][i].queries, queryFilters), queries["custom"][i].searchPath)));
|
packsWithVersion.length === 0)));
|
||||||
ranCustom = true;
|
ranCustom = true;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (packsWithVersion.length > 0) {
|
if (packsWithVersion.length > 0) {
|
||||||
querySuitePaths.push(await runQueryPacks(language, "packs", packsWithVersion, queryFilters));
|
querySuitePaths.push(await runQueryPacks(language, "packs", packsWithVersion, queryFilters, true));
|
||||||
ranCustom = true;
|
ranCustom = true;
|
||||||
}
|
}
|
||||||
if (ranCustom) {
|
if (ranCustom) {
|
||||||
@@ -218,7 +224,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||||
return await codeql.databasePrintBaseline(databasePath);
|
return await codeql.databasePrintBaseline(databasePath);
|
||||||
}
|
}
|
||||||
async function runQueryGroup(language, type, querySuiteContents, searchPath) {
|
async function runQueryGroup(language, type, querySuiteContents, searchPath, optimizeForLastQueryRun) {
|
||||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||||
// Pass the queries to codeql using a file instead of using the command
|
// Pass the queries to codeql using a file instead of using the command
|
||||||
// line to avoid command line length restrictions, particularly on windows.
|
// line to avoid command line length restrictions, particularly on windows.
|
||||||
@@ -229,11 +235,11 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||||||
fs.writeFileSync(querySuitePath, querySuiteContents);
|
fs.writeFileSync(querySuitePath, querySuiteContents);
|
||||||
logger.debug(`Query suite file for ${language}-${type}...\n${querySuiteContents}`);
|
logger.debug(`Query suite file for ${language}-${type}...\n${querySuiteContents}`);
|
||||||
}
|
}
|
||||||
await codeql.databaseRunQueries(databasePath, searchPath, querySuitePath, memoryFlag, threadsFlag);
|
await codeql.databaseRunQueries(databasePath, searchPath, querySuitePath, queryFlags, optimizeForLastQueryRun);
|
||||||
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
||||||
return querySuitePath;
|
return querySuitePath;
|
||||||
}
|
}
|
||||||
async function runQueryPacks(language, type, packs, queryFilters) {
|
async function runQueryPacks(language, type, packs, queryFilters, optimizeForLastQueryRun) {
|
||||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||||
for (const pack of packs) {
|
for (const pack of packs) {
|
||||||
logger.debug(`Running query pack for ${language}-${type}: ${pack}`);
|
logger.debug(`Running query pack for ${language}-${type}: ${pack}`);
|
||||||
@@ -243,7 +249,7 @@ async function runQueries(sarifFolder, memoryFlag, addSnippetsFlag, threadsFlag,
|
|||||||
const querySuitePath = `${databasePath}-queries-${type}.qls`;
|
const querySuitePath = `${databasePath}-queries-${type}.qls`;
|
||||||
fs.writeFileSync(querySuitePath, yaml.dump(querySuite));
|
fs.writeFileSync(querySuitePath, yaml.dump(querySuite));
|
||||||
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
||||||
await codeql.databaseRunQueries(databasePath, undefined, querySuitePath, memoryFlag, threadsFlag);
|
await codeql.databaseRunQueries(databasePath, undefined, querySuitePath, queryFlags, optimizeForLastQueryRun);
|
||||||
return querySuitePath;
|
return querySuitePath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+122
@@ -30,8 +30,10 @@ const fs = __importStar(require("fs"));
|
|||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const ava_1 = __importDefault(require("ava"));
|
const ava_1 = __importDefault(require("ava"));
|
||||||
const yaml = __importStar(require("js-yaml"));
|
const yaml = __importStar(require("js-yaml"));
|
||||||
|
const sinon = __importStar(require("sinon"));
|
||||||
const analyze_1 = require("./analyze");
|
const analyze_1 = require("./analyze");
|
||||||
const codeql_1 = require("./codeql");
|
const codeql_1 = require("./codeql");
|
||||||
|
const feature_flags_1 = require("./feature-flags");
|
||||||
const languages_1 = require("./languages");
|
const languages_1 = require("./languages");
|
||||||
const logging_1 = require("./logging");
|
const logging_1 = require("./logging");
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
@@ -188,6 +190,126 @@ const util = __importStar(require("./util"));
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
function mockCodeQL() {
|
||||||
|
return {
|
||||||
|
getVersion: async () => "2.12.2",
|
||||||
|
databaseRunQueries: sinon.spy(),
|
||||||
|
databaseInterpretResults: async () => "",
|
||||||
|
databasePrintBaseline: async () => "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function createBaseConfig(tmpDir) {
|
||||||
|
return {
|
||||||
|
languages: [],
|
||||||
|
queries: {},
|
||||||
|
pathsIgnore: [],
|
||||||
|
paths: [],
|
||||||
|
originalUserInput: {},
|
||||||
|
tempDir: "tempDir",
|
||||||
|
codeQLCmd: "",
|
||||||
|
gitHubVersion: {
|
||||||
|
type: util.GitHubVariant.DOTCOM,
|
||||||
|
},
|
||||||
|
dbLocation: path.resolve(tmpDir, "codeql_databases"),
|
||||||
|
packs: {},
|
||||||
|
debugMode: false,
|
||||||
|
debugArtifactName: util.DEFAULT_DEBUG_ARTIFACT_NAME,
|
||||||
|
debugDatabaseName: util.DEFAULT_DEBUG_DATABASE_NAME,
|
||||||
|
augmentationProperties: {
|
||||||
|
injectedMlQueries: false,
|
||||||
|
packsInputCombines: false,
|
||||||
|
queriesInputCombines: false,
|
||||||
|
},
|
||||||
|
trapCaches: {},
|
||||||
|
trapCacheDownloadTime: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
function createQueryConfig(builtin, custom) {
|
||||||
|
return {
|
||||||
|
builtin,
|
||||||
|
custom: custom.map((c) => ({ searchPath: "/search", queries: [c] })),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async function runQueriesWithConfig(config, features) {
|
||||||
|
for (const language of config.languages) {
|
||||||
|
fs.mkdirSync(util.getCodeQLDatabasePath(config, language), {
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return (0, analyze_1.runQueries)("sarif-folder", "--memFlag", "--addSnippetsFlag", "--threadsFlag", undefined, config, (0, logging_1.getRunnerLogger)(true), (0, testing_utils_1.createFeatures)(features));
|
||||||
|
}
|
||||||
|
function getDatabaseRunQueriesCalls(mock) {
|
||||||
|
return mock.databaseRunQueries.getCalls();
|
||||||
|
}
|
||||||
|
(0, ava_1.default)("optimizeForLastQueryRun for one language", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
(0, codeql_1.setCodeQL)(codeql);
|
||||||
|
const config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [languages_1.Language.cpp];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("optimizeForLastQueryRun for two languages", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
(0, codeql_1.setCodeQL)(codeql);
|
||||||
|
const config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||||
|
config.queries.java = createQueryConfig(["bar.ql"], []);
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true, true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("optimizeForLastQueryRun for two languages, with custom queries", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
(0, codeql_1.setCodeQL)(codeql);
|
||||||
|
const config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||||
|
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [false, false, true, false, true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("optimizeForLastQueryRun for two languages, with custom queries and packs", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
(0, codeql_1.setCodeQL)(codeql);
|
||||||
|
const config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||||
|
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||||
|
config.packs.cpp = ["a/cpp-pack1@0.1.0"];
|
||||||
|
config.packs.java = ["b/java-pack1@0.2.0", "b/java-pack2@0.3.3"];
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [false, false, false, true, false, false, true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("optimizeForLastQueryRun for one language, CliConfigFileEnabled", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
(0, codeql_1.setCodeQL)(codeql);
|
||||||
|
const config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [languages_1.Language.cpp];
|
||||||
|
await runQueriesWithConfig(config, [feature_flags_1.Feature.CliConfigFileEnabled]);
|
||||||
|
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("optimizeForLastQueryRun for two languages, CliConfigFileEnabled", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
(0, codeql_1.setCodeQL)(codeql);
|
||||||
|
const config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [languages_1.Language.cpp, languages_1.Language.java];
|
||||||
|
await runQueriesWithConfig(config, [feature_flags_1.Feature.CliConfigFileEnabled]);
|
||||||
|
t.deepEqual(getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]), [true, true]);
|
||||||
|
});
|
||||||
|
});
|
||||||
(0, ava_1.default)("validateQueryFilters", (t) => {
|
(0, ava_1.default)("validateQueryFilters", (t) => {
|
||||||
t.notThrows(() => (0, analyze_1.validateQueryFilters)([]));
|
t.notThrows(() => (0, analyze_1.validateQueryFilters)([]));
|
||||||
t.notThrows(() => (0, analyze_1.validateQueryFilters)(undefined));
|
t.notThrows(() => (0, analyze_1.validateQueryFilters)(undefined));
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+29
-16
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.getExtraOptions = exports.getCodeQLForCmd = exports.getCodeQLForTesting = exports.getCachedCodeQL = exports.setCodeQL = exports.getCodeQL = exports.setupCodeQL = exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = exports.CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS = exports.CODEQL_VERSION_TRACING_GLIBC_2_34 = exports.CODEQL_VERSION_NEW_TRACING = exports.CODEQL_VERSION_GHES_PACK_DOWNLOAD = exports.CommandInvocationError = void 0;
|
exports.getExtraOptions = exports.getCodeQLForCmd = exports.getCodeQLForTesting = exports.getCachedCodeQL = exports.setCodeQL = exports.getCodeQL = exports.setupCodeQL = exports.CODEQL_VERSION_INIT_WITH_QLCONFIG = exports.CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE = exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = exports.CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS = exports.CODEQL_VERSION_TRACING_GLIBC_2_34 = exports.CODEQL_VERSION_NEW_TRACING = exports.CODEQL_VERSION_GHES_PACK_DOWNLOAD = exports.CommandInvocationError = void 0;
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
|
const toolrunner = __importStar(require("@actions/exec/lib/toolrunner"));
|
||||||
@@ -94,6 +94,14 @@ exports.CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS = "2.9.0";
|
|||||||
* --extractor-options-verbosity that we need.
|
* --extractor-options-verbosity that we need.
|
||||||
*/
|
*/
|
||||||
exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
|
exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
|
||||||
|
/**
|
||||||
|
* Versions 2.11.1+ of the CodeQL Bundle include a `security-experimental` built-in query suite for each language.
|
||||||
|
*/
|
||||||
|
exports.CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE = "2.12.1";
|
||||||
|
/**
|
||||||
|
* Versions 2.12.4+ of the CodeQL CLI support the `--qlconfig` flag in calls to `database init`.
|
||||||
|
*/
|
||||||
|
exports.CODEQL_VERSION_INIT_WITH_QLCONFIG = "2.12.4";
|
||||||
/**
|
/**
|
||||||
* Set up CodeQL CLI access.
|
* Set up CodeQL CLI access.
|
||||||
*
|
*
|
||||||
@@ -101,16 +109,15 @@ exports.CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
|
|||||||
* @param apiDetails
|
* @param apiDetails
|
||||||
* @param tempDir
|
* @param tempDir
|
||||||
* @param variant
|
* @param variant
|
||||||
* @param bypassToolcache
|
|
||||||
* @param defaultCliVersion
|
* @param defaultCliVersion
|
||||||
* @param logger
|
* @param logger
|
||||||
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
||||||
* version requirement. Must be set to true outside tests.
|
* version requirement. Must be set to true outside tests.
|
||||||
* @returns a { CodeQL, toolsVersion } object.
|
* @returns a { CodeQL, toolsVersion } object.
|
||||||
*/
|
*/
|
||||||
async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger, checkVersion) {
|
async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, logger, checkVersion) {
|
||||||
try {
|
try {
|
||||||
const { codeqlFolder, toolsDownloadDurationMs, toolsSource, toolsVersion } = await setupCodeql.setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger);
|
const { codeqlFolder, toolsDownloadDurationMs, toolsSource, toolsVersion } = await setupCodeql.setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, logger);
|
||||||
let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql");
|
let codeqlCmd = path.join(codeqlFolder, "codeql", "codeql");
|
||||||
if (process.platform === "win32") {
|
if (process.platform === "win32") {
|
||||||
codeqlCmd += ".exe";
|
codeqlCmd += ".exe";
|
||||||
@@ -299,7 +306,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
|||||||
...getExtraOptionsFromEnv(["database", "init"]),
|
...getExtraOptionsFromEnv(["database", "init"]),
|
||||||
]);
|
]);
|
||||||
},
|
},
|
||||||
async databaseInitCluster(config, sourceRoot, processName, featureEnablement, logger) {
|
async databaseInitCluster(config, sourceRoot, processName, featureEnablement, qlconfigFile, logger) {
|
||||||
const extraArgs = config.languages.map((language) => `--language=${language}`);
|
const extraArgs = config.languages.map((language) => `--language=${language}`);
|
||||||
if (config.languages.filter((l) => (0, languages_1.isTracedLanguage)(l)).length > 0) {
|
if (config.languages.filter((l) => (0, languages_1.isTracedLanguage)(l)).length > 0) {
|
||||||
extraArgs.push("--begin-tracing");
|
extraArgs.push("--begin-tracing");
|
||||||
@@ -317,17 +324,20 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
|||||||
extraArgs.push("--no-internal-use-lua-tracing");
|
extraArgs.push("--no-internal-use-lua-tracing");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// A config file is only generated if the CliConfigFileEnabled feature flag is enabled.
|
// A code scanning config file is only generated if the CliConfigFileEnabled feature flag is enabled.
|
||||||
const configLocation = await generateCodeScanningConfig(codeql, config, featureEnablement, logger);
|
const codeScanningConfigFile = await generateCodeScanningConfig(codeql, config, featureEnablement, logger);
|
||||||
// Only pass external repository token if a config file is going to be parsed by the CLI.
|
// Only pass external repository token if a config file is going to be parsed by the CLI.
|
||||||
let externalRepositoryToken;
|
let externalRepositoryToken;
|
||||||
if (configLocation) {
|
if (codeScanningConfigFile) {
|
||||||
extraArgs.push(`--codescanning-config=${configLocation}`);
|
|
||||||
externalRepositoryToken = (0, actions_util_1.getOptionalInput)("external-repository-token");
|
externalRepositoryToken = (0, actions_util_1.getOptionalInput)("external-repository-token");
|
||||||
|
extraArgs.push(`--codescanning-config=${codeScanningConfigFile}`);
|
||||||
if (externalRepositoryToken) {
|
if (externalRepositoryToken) {
|
||||||
extraArgs.push("--external-repository-token-stdin");
|
extraArgs.push("--external-repository-token-stdin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (await util.codeQlVersionAbove(this, exports.CODEQL_VERSION_INIT_WITH_QLCONFIG)) {
|
||||||
|
extraArgs.push(`--qlconfig=${qlconfigFile}`);
|
||||||
|
}
|
||||||
await runTool(cmd, [
|
await runTool(cmd, [
|
||||||
"database",
|
"database",
|
||||||
"init",
|
"init",
|
||||||
@@ -469,17 +479,20 @@ async function getCodeQLForCmd(cmd, checkVersion) {
|
|||||||
throw new Error(`Unexpected output from codeql resolve queries: ${e}`);
|
throw new Error(`Unexpected output from codeql resolve queries: ${e}`);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async databaseRunQueries(databasePath, extraSearchPath, querySuitePath, memoryFlag, threadsFlag) {
|
async databaseRunQueries(databasePath, extraSearchPath, querySuitePath, flags, optimizeForLastQueryRun) {
|
||||||
const codeqlArgs = [
|
const codeqlArgs = [
|
||||||
"database",
|
"database",
|
||||||
"run-queries",
|
"run-queries",
|
||||||
memoryFlag,
|
...flags,
|
||||||
threadsFlag,
|
|
||||||
databasePath,
|
databasePath,
|
||||||
"--min-disk-free=1024",
|
"--min-disk-free=1024",
|
||||||
"-v",
|
"-v",
|
||||||
...getExtraOptionsFromEnv(["database", "run-queries"]),
|
...getExtraOptionsFromEnv(["database", "run-queries"]),
|
||||||
];
|
];
|
||||||
|
if (optimizeForLastQueryRun &&
|
||||||
|
(await util.supportExpectDiscardedCache(this))) {
|
||||||
|
codeqlArgs.push("--expect-discarded-cache");
|
||||||
|
}
|
||||||
if (extraSearchPath !== undefined) {
|
if (extraSearchPath !== undefined) {
|
||||||
codeqlArgs.push("--additional-packs", extraSearchPath);
|
codeqlArgs.push("--additional-packs", extraSearchPath);
|
||||||
}
|
}
|
||||||
@@ -712,7 +725,7 @@ async function generateCodeScanningConfig(codeql, config, featureEnablement, log
|
|||||||
if (!(await util.useCodeScanningConfigInCli(codeql, featureEnablement))) {
|
if (!(await util.useCodeScanningConfigInCli(codeql, featureEnablement))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const configLocation = path.resolve(config.tempDir, "user-config.yaml");
|
const codeScanningConfigFile = path.resolve(config.tempDir, "user-config.yaml");
|
||||||
// make a copy so we can modify it
|
// make a copy so we can modify it
|
||||||
const augmentedConfig = cloneObject(config.originalUserInput);
|
const augmentedConfig = cloneObject(config.originalUserInput);
|
||||||
// Inject the queries from the input
|
// Inject the queries from the input
|
||||||
@@ -766,12 +779,12 @@ async function generateCodeScanningConfig(codeql, config, featureEnablement, log
|
|||||||
augmentedConfig.packs["javascript"].push(packString);
|
augmentedConfig.packs["javascript"].push(packString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info(`Writing augmented user configuration file to ${configLocation}`);
|
logger.info(`Writing augmented user configuration file to ${codeScanningConfigFile}`);
|
||||||
logger.startGroup("Augmented user configuration file contents");
|
logger.startGroup("Augmented user configuration file contents");
|
||||||
logger.info(yaml.dump(augmentedConfig));
|
logger.info(yaml.dump(augmentedConfig));
|
||||||
logger.endGroup();
|
logger.endGroup();
|
||||||
fs.writeFileSync(configLocation, yaml.dump(augmentedConfig));
|
fs.writeFileSync(codeScanningConfigFile, yaml.dump(augmentedConfig));
|
||||||
return configLocation;
|
return codeScanningConfigFile;
|
||||||
}
|
}
|
||||||
function cloneObject(obj) {
|
function cloneObject(obj) {
|
||||||
return JSON.parse(JSON.stringify(obj));
|
return JSON.parse(JSON.stringify(obj));
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+54
-31
@@ -114,7 +114,7 @@ function mockDownloadApi({ apiDetails = sampleApiDetails, isPinned, repo = "gith
|
|||||||
}
|
}
|
||||||
async function installIntoToolcache({ apiDetails = sampleApiDetails, cliVersion, isPinned, tagName, tmpDir, }) {
|
async function installIntoToolcache({ apiDetails = sampleApiDetails, cliVersion, isPinned, tagName, tmpDir, }) {
|
||||||
const url = mockDownloadApi({ apiDetails, isPinned, tagName });
|
const url = mockDownloadApi({ apiDetails, isPinned, tagName });
|
||||||
await codeql.setupCodeQL(cliVersion !== undefined ? undefined : url, apiDetails, tmpDir, util.GitHubVariant.GHES, false, cliVersion !== undefined
|
await codeql.setupCodeQL(cliVersion !== undefined ? undefined : url, apiDetails, tmpDir, util.GitHubVariant.GHES, cliVersion !== undefined
|
||||||
? { cliVersion, tagName, variant: util.GitHubVariant.GHES }
|
? { cliVersion, tagName, variant: util.GitHubVariant.GHES }
|
||||||
: SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
: SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
||||||
}
|
}
|
||||||
@@ -153,7 +153,7 @@ function mockApiDetails(apiDetails) {
|
|||||||
tagName: `codeql-bundle-${version}`,
|
tagName: `codeql-bundle-${version}`,
|
||||||
isPinned: false,
|
isPinned: false,
|
||||||
});
|
});
|
||||||
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
||||||
t.assert(toolcache.find("CodeQL", `0.0.0-${version}`));
|
t.assert(toolcache.find("CodeQL", `0.0.0-${version}`));
|
||||||
t.is(result.toolsVersion, `0.0.0-${version}`);
|
t.is(result.toolsVersion, `0.0.0-${version}`);
|
||||||
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
||||||
@@ -173,7 +173,7 @@ function mockApiDetails(apiDetails) {
|
|||||||
const url = mockDownloadApi({
|
const url = mockDownloadApi({
|
||||||
tagName: "codeql-bundle-20200610",
|
tagName: "codeql-bundle-20200610",
|
||||||
});
|
});
|
||||||
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
||||||
t.assert(toolcache.find("CodeQL", "0.0.0-20200610"));
|
t.assert(toolcache.find("CodeQL", "0.0.0-20200610"));
|
||||||
t.deepEqual(result.toolsVersion, "0.0.0-20200610");
|
t.deepEqual(result.toolsVersion, "0.0.0-20200610");
|
||||||
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
||||||
@@ -207,7 +207,7 @@ for (const { cliVersion, expectedToolcacheVersion, } of EXPLICITLY_REQUESTED_BUN
|
|||||||
const url = mockDownloadApi({
|
const url = mockDownloadApi({
|
||||||
tagName: "codeql-bundle-20200610",
|
tagName: "codeql-bundle-20200610",
|
||||||
});
|
});
|
||||||
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
||||||
t.assert(releaseApiMock.isDone(), "Releases API should have been called");
|
t.assert(releaseApiMock.isDone(), "Releases API should have been called");
|
||||||
t.assert(toolcache.find("CodeQL", expectedToolcacheVersion));
|
t.assert(toolcache.find("CodeQL", expectedToolcacheVersion));
|
||||||
t.deepEqual(result.toolsVersion, cliVersion);
|
t.deepEqual(result.toolsVersion, cliVersion);
|
||||||
@@ -256,7 +256,7 @@ for (const { githubReleases, toolcacheVersion } of [
|
|||||||
}))),
|
}))),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
||||||
t.is(result.toolsVersion, SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
|
t.is(result.toolsVersion, SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
|
||||||
t.is(result.toolsSource, init_1.ToolsSource.Toolcache);
|
t.is(result.toolsSource, init_1.ToolsSource.Toolcache);
|
||||||
t.is(result.toolsDownloadDurationMs, undefined);
|
t.is(result.toolsDownloadDurationMs, undefined);
|
||||||
@@ -272,7 +272,7 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
|
|||||||
isPinned: true,
|
isPinned: true,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
});
|
});
|
||||||
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, false, {
|
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, {
|
||||||
cliVersion: defaults.cliVersion,
|
cliVersion: defaults.cliVersion,
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
variant,
|
variant,
|
||||||
@@ -295,7 +295,7 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
|
|||||||
mockDownloadApi({
|
mockDownloadApi({
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
});
|
});
|
||||||
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, false, {
|
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, {
|
||||||
cliVersion: defaults.cliVersion,
|
cliVersion: defaults.cliVersion,
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
variant,
|
variant,
|
||||||
@@ -319,7 +319,7 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
|
|||||||
mockDownloadApi({
|
mockDownloadApi({
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
});
|
});
|
||||||
const result = await codeql.setupCodeQL("latest", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
const result = await codeql.setupCodeQL("latest", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
||||||
t.deepEqual(result.toolsVersion, defaults.cliVersion);
|
t.deepEqual(result.toolsVersion, defaults.cliVersion);
|
||||||
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
||||||
t.assert(Number.isInteger(result.toolsDownloadDurationMs));
|
t.assert(Number.isInteger(result.toolsDownloadDurationMs));
|
||||||
@@ -360,7 +360,7 @@ for (const isBundleVersionInUrl of [true, false]) {
|
|||||||
mockApiDetails(sampleGHAEApiDetails);
|
mockApiDetails(sampleGHAEApiDetails);
|
||||||
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
|
sinon.stub(actionsUtil, "isRunningLocalAction").returns(false);
|
||||||
process.env["GITHUB_ACTION_REPOSITORY"] = "github/codeql-action";
|
process.env["GITHUB_ACTION_REPOSITORY"] = "github/codeql-action";
|
||||||
const result = await codeql.setupCodeQL(undefined, sampleGHAEApiDetails, tmpDir, util.GitHubVariant.GHAE, false, {
|
const result = await codeql.setupCodeQL(undefined, sampleGHAEApiDetails, tmpDir, util.GitHubVariant.GHAE, {
|
||||||
cliVersion: defaults.cliVersion,
|
cliVersion: defaults.cliVersion,
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
variant: util.GitHubVariant.GHAE,
|
variant: util.GitHubVariant.GHAE,
|
||||||
@@ -386,7 +386,7 @@ for (const isBundleVersionInUrl of [true, false]) {
|
|||||||
platformSpecific: false,
|
platformSpecific: false,
|
||||||
tagName: "codeql-bundle-20230203",
|
tagName: "codeql-bundle-20230203",
|
||||||
});
|
});
|
||||||
const result = await codeql.setupCodeQL("https://github.com/dsp-testing/codeql-cli-nightlies/releases/download/codeql-bundle-20230203/codeql-bundle.tar.gz", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, false, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
const result = await codeql.setupCodeQL("https://github.com/dsp-testing/codeql-cli-nightlies/releases/download/codeql-bundle-20230203/codeql-bundle.tar.gz", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
|
||||||
t.is(result.toolsVersion, "0.0.0-20230203");
|
t.is(result.toolsVersion, "0.0.0-20230203");
|
||||||
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
t.is(result.toolsSource, init_1.ToolsSource.Download);
|
||||||
t.true(Number.isInteger(result.toolsDownloadDurationMs));
|
t.true(Number.isInteger(result.toolsDownloadDurationMs));
|
||||||
@@ -452,11 +452,11 @@ for (const isBundleVersionInUrl of [true, false]) {
|
|||||||
packsInputCombines: false,
|
packsInputCombines: false,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
await codeqlObject.databaseInitCluster(thisStubConfig, "", undefined, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
|
await codeqlObject.databaseInitCluster(thisStubConfig, "", undefined, (0, testing_utils_1.createFeatures)([]), "/path/to/qlconfig.yml", (0, logging_1.getRunnerLogger)(true));
|
||||||
const args = runnerConstructorStub.firstCall.args[1];
|
const args = runnerConstructorStub.firstCall.args[1];
|
||||||
// should NOT have used an config file
|
// should NOT have used an config file
|
||||||
const configArg = args.find((arg) => arg.startsWith("--codescanning-config="));
|
const configArg = args.find((arg) => arg.startsWith("--codescanning-config="));
|
||||||
t.falsy(configArg, "Should have injected a codescanning config");
|
t.falsy(configArg, "Should NOT have injected a codescanning config");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
// Test macro for ensuring different variants of injected augmented configurations
|
// Test macro for ensuring different variants of injected augmented configurations
|
||||||
@@ -474,7 +474,7 @@ const injectedConfigMacro = ava_1.default.macro({
|
|||||||
tempDir,
|
tempDir,
|
||||||
augmentationProperties,
|
augmentationProperties,
|
||||||
};
|
};
|
||||||
await codeqlObject.databaseInitCluster(thisStubConfig, "", undefined, (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CliConfigFileEnabled]), (0, logging_1.getRunnerLogger)(true));
|
await codeqlObject.databaseInitCluster(thisStubConfig, "", undefined, (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CliConfigFileEnabled]), undefined, (0, logging_1.getRunnerLogger)(true));
|
||||||
const args = runnerConstructorStub.firstCall.args[1];
|
const args = runnerConstructorStub.firstCall.args[1];
|
||||||
// should have used an config file
|
// should have used an config file
|
||||||
const configArg = args.find((arg) => arg.startsWith("--codescanning-config="));
|
const configArg = args.find((arg) => arg.startsWith("--codescanning-config="));
|
||||||
@@ -665,24 +665,47 @@ const injectedConfigMacro = ava_1.default.macro({
|
|||||||
queries: [],
|
queries: [],
|
||||||
},
|
},
|
||||||
}, {});
|
}, {});
|
||||||
(0, ava_1.default)("does not use injected config", async (t) => {
|
(0, ava_1.default)("does not pass a code scanning config or qlconfig file to the CLI when CLI config passing is disabled", async (t) => {
|
||||||
const origCODEQL_PASS_CONFIG_TO_CLI = process.env.CODEQL_PASS_CONFIG_TO_CLI;
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
process.env["CODEQL_PASS_CONFIG_TO_CLI"] = "false";
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
try {
|
// stubbed version doesn't matter. It just needs to be valid semver.
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
await codeqlObject.databaseInitCluster(stubConfig, "", undefined, (0, testing_utils_1.createFeatures)([]), "/path/to/qlconfig.yml", (0, logging_1.getRunnerLogger)(true));
|
||||||
sinon
|
const args = runnerConstructorStub.firstCall.args[1];
|
||||||
.stub(codeqlObject, "getVersion")
|
// should not have used a config file
|
||||||
.resolves(feature_flags_1.featureConfig[feature_flags_1.Feature.CliConfigFileEnabled].minimumVersion);
|
const hasConfigArg = args.some((arg) => arg.startsWith("--codescanning-config="));
|
||||||
await codeqlObject.databaseInitCluster(stubConfig, "", undefined, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
|
t.false(hasConfigArg, "Should NOT have injected a codescanning config");
|
||||||
const args = runnerConstructorStub.firstCall.args[1];
|
// should not have passed a qlconfig file
|
||||||
// should have used an config file
|
const hasQlconfigArg = args.some((arg) => arg.startsWith("--qlconfig="));
|
||||||
const configArg = args.find((arg) => arg.startsWith("--codescanning-config="));
|
t.false(hasQlconfigArg, "Should NOT have passed a qlconfig file");
|
||||||
t.falsy(configArg, "Should NOT have injected a codescanning config");
|
});
|
||||||
}
|
(0, ava_1.default)("passes a code scanning config AND qlconfig to the CLI when CLI config passing is enabled", async (t) => {
|
||||||
finally {
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
process.env["CODEQL_PASS_CONFIG_TO_CLI"] = origCODEQL_PASS_CONFIG_TO_CLI;
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
}
|
sinon
|
||||||
|
.stub(codeqlObject, "getVersion")
|
||||||
|
.resolves(codeql.CODEQL_VERSION_INIT_WITH_QLCONFIG);
|
||||||
|
await codeqlObject.databaseInitCluster(stubConfig, "", undefined, (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CliConfigFileEnabled]), "/path/to/qlconfig.yml", (0, logging_1.getRunnerLogger)(true));
|
||||||
|
const args = runnerConstructorStub.firstCall.args[1];
|
||||||
|
// should have used a config file
|
||||||
|
const hasCodeScanningConfigArg = args.some((arg) => arg.startsWith("--codescanning-config="));
|
||||||
|
t.true(hasCodeScanningConfigArg, "Should have injected a qlconfig");
|
||||||
|
// should have passed a qlconfig file
|
||||||
|
const hasQlconfigArg = args.some((arg) => arg.startsWith("--qlconfig="));
|
||||||
|
t.truthy(hasQlconfigArg, "Should have injected a codescanning config");
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("passes a code scanning config BUT NOT a qlconfig to the CLI when CLI config passing is enabled", async (t) => {
|
||||||
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
sinon.stub(codeqlObject, "getVersion").resolves("2.12.2");
|
||||||
|
await codeqlObject.databaseInitCluster(stubConfig, "", undefined, (0, testing_utils_1.createFeatures)([feature_flags_1.Feature.CliConfigFileEnabled]), "/path/to/qlconfig.yml", (0, logging_1.getRunnerLogger)(true));
|
||||||
|
const args = runnerConstructorStub.firstCall.args[1];
|
||||||
|
// should have used a config file
|
||||||
|
const hasCodeScanningConfigArg = args.some((arg) => arg.startsWith("--codescanning-config="));
|
||||||
|
t.true(hasCodeScanningConfigArg, "Should NOT have injected a qlconfig");
|
||||||
|
// should have passed a qlconfig file
|
||||||
|
const hasQlconfigArg = args.some((arg) => arg.startsWith("--qlconfig="));
|
||||||
|
t.false(hasQlconfigArg, "Should have injected a codescanning config");
|
||||||
});
|
});
|
||||||
(0, ava_1.default)("databaseInterpretResults() sets --sarif-add-baseline-file-info for 2.11.3", async (t) => {
|
(0, ava_1.default)("databaseInterpretResults() sets --sarif-add-baseline-file-info for 2.11.3", async (t) => {
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+65
-22
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.downloadPacks = exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.parsePacks = exports.validatePackSpecification = exports.prettyPrintPack = exports.parsePacksSpecification = exports.parsePacksFromConfig = exports.calculateAugmentation = exports.getDefaultConfig = exports.getRawLanguages = exports.getLanguages = exports.getLanguagesInRepo = 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.getPathsInvalid = exports.getPathsIgnoreInvalid = exports.getQueryUsesInvalid = exports.getQueriesMissingUses = exports.getQueriesInvalid = exports.getDisableDefaultQueriesInvalid = exports.getNameInvalid = exports.validateAndSanitisePath = exports.defaultAugmentationProperties = void 0;
|
exports.wrapEnvironment = exports.generateRegistries = exports.downloadPacks = exports.getConfig = exports.getPathToParsedConfigFile = exports.initConfig = exports.parsePacks = exports.validatePackSpecification = exports.prettyPrintPack = exports.parsePacksSpecification = exports.parsePacksFromConfig = exports.calculateAugmentation = exports.getDefaultConfig = exports.getRawLanguages = exports.getLanguages = exports.getLanguagesInRepo = 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.getPathsInvalid = exports.getPathsIgnoreInvalid = exports.getQueryUsesInvalid = exports.getQueriesMissingUses = exports.getQueriesInvalid = exports.getDisableDefaultQueriesInvalid = exports.getNameInvalid = exports.validateAndSanitisePath = exports.defaultAugmentationProperties = void 0;
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const perf_hooks_1 = require("perf_hooks");
|
const perf_hooks_1 = require("perf_hooks");
|
||||||
@@ -131,7 +131,11 @@ async function addDefaultQueries(codeQL, languages, resultMap) {
|
|||||||
await runResolveQueries(codeQL, resultMap, suites, undefined);
|
await runResolveQueries(codeQL, resultMap, suites, undefined);
|
||||||
}
|
}
|
||||||
// The set of acceptable values for built-in suites from the codeql bundle
|
// The set of acceptable values for built-in suites from the codeql bundle
|
||||||
const builtinSuites = ["security-extended", "security-and-quality"];
|
const builtinSuites = [
|
||||||
|
"security-experimental",
|
||||||
|
"security-extended",
|
||||||
|
"security-and-quality",
|
||||||
|
];
|
||||||
/**
|
/**
|
||||||
* Determine the set of queries associated with suiteName's suites and add them to resultMap.
|
* Determine the set of queries associated with suiteName's suites and add them to resultMap.
|
||||||
* Throws an error if suiteName is not a valid builtin suite.
|
* Throws an error if suiteName is not a valid builtin suite.
|
||||||
@@ -143,6 +147,12 @@ async function addBuiltinSuiteQueries(languages, codeQL, resultMap, packs, suite
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
throw new Error(getQueryUsesInvalid(configFile, suiteName));
|
throw new Error(getQueryUsesInvalid(configFile, suiteName));
|
||||||
}
|
}
|
||||||
|
if (suiteName === "security-experimental" &&
|
||||||
|
!(await (0, util_1.codeQlVersionAbove)(codeQL, codeql_1.CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE))) {
|
||||||
|
throw new Error(`The 'security-experimental' suite is not supported on CodeQL CLI versions earlier than
|
||||||
|
${codeql_1.CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE}. Please upgrade to CodeQL CLI version
|
||||||
|
${codeql_1.CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE} or later.`);
|
||||||
|
}
|
||||||
// If we're running the JavaScript security-extended analysis (or a superset of it), the repo is
|
// If we're running the JavaScript security-extended analysis (or a superset of it), the repo is
|
||||||
// opted into the ML-powered queries beta, and a user hasn't already added the ML-powered query
|
// opted into the ML-powered queries beta, and a user hasn't already added the ML-powered query
|
||||||
// pack, then add the ML-powered query pack so that we run ML-powered queries.
|
// pack, then add the ML-powered query pack so that we run ML-powered queries.
|
||||||
@@ -151,7 +161,9 @@ async function addBuiltinSuiteQueries(languages, codeQL, resultMap, packs, suite
|
|||||||
(process.platform !== "win32" ||
|
(process.platform !== "win32" ||
|
||||||
(await (0, util_1.codeQlVersionAbove)(codeQL, codeql_1.CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS))) &&
|
(await (0, util_1.codeQlVersionAbove)(codeQL, codeql_1.CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS))) &&
|
||||||
languages.includes("javascript") &&
|
languages.includes("javascript") &&
|
||||||
(found === "security-extended" || found === "security-and-quality") &&
|
(found === "security-experimental" ||
|
||||||
|
found === "security-extended" ||
|
||||||
|
found === "security-and-quality") &&
|
||||||
!packs.javascript?.some(isMlPoweredJsQueriesPack) &&
|
!packs.javascript?.some(isMlPoweredJsQueriesPack) &&
|
||||||
(await featureEnablement.getValue(feature_flags_1.Feature.MlPoweredQueriesEnabled, codeQL))) {
|
(await featureEnablement.getValue(feature_flags_1.Feature.MlPoweredQueriesEnabled, codeQL))) {
|
||||||
if (!packs.javascript) {
|
if (!packs.javascript) {
|
||||||
@@ -713,7 +725,7 @@ function parseQueriesFromInput(rawQueriesInput, queriesInputCombines) {
|
|||||||
}
|
}
|
||||||
const trimmedInput = queriesInputCombines
|
const trimmedInput = queriesInputCombines
|
||||||
? rawQueriesInput.trim().slice(1).trim()
|
? rawQueriesInput.trim().slice(1).trim()
|
||||||
: rawQueriesInput?.trim();
|
: rawQueriesInput?.trim() ?? "";
|
||||||
if (queriesInputCombines && trimmedInput.length === 0) {
|
if (queriesInputCombines && trimmedInput.length === 0) {
|
||||||
throw new Error(getConfigFilePropertyError(undefined, "queries", "A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs."));
|
throw new Error(getConfigFilePropertyError(undefined, "queries", "A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs."));
|
||||||
}
|
}
|
||||||
@@ -893,7 +905,8 @@ exports.parsePacks = parsePacks;
|
|||||||
* Without a '+', an input value will override the corresponding value in the config file.
|
* Without a '+', an input value will override the corresponding value in the config file.
|
||||||
*
|
*
|
||||||
* @param inputValue The input value to process.
|
* @param inputValue The input value to process.
|
||||||
* @returns true if the input value should replace the corresponding value in the config file, false if it should be appended.
|
* @returns true if the input value should replace the corresponding value in the config file,
|
||||||
|
* false if it should be appended.
|
||||||
*/
|
*/
|
||||||
function shouldCombine(inputValue) {
|
function shouldCombine(inputValue) {
|
||||||
return !!inputValue?.trim().startsWith("+");
|
return !!inputValue?.trim().startsWith("+");
|
||||||
@@ -946,8 +959,7 @@ async function initConfig(languagesInput, queriesInput, packsInput, registriesIn
|
|||||||
"Please make sure that the default queries are enabled, or you are specifying queries to run.");
|
"Please make sure that the default queries are enabled, or you are specifying queries to run.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const registries = parseRegistries(registriesInput);
|
await downloadPacks(codeQL, config.languages, config.packs, apiDetails, registriesInput, config.tempDir, logger);
|
||||||
await downloadPacks(codeQL, config.languages, config.packs, registries, apiDetails, config.tempDir, logger);
|
|
||||||
}
|
}
|
||||||
// Save the config so we can easily access it again in the future
|
// Save the config so we can easily access it again in the future
|
||||||
await saveConfig(config, logger);
|
await saveConfig(config, logger);
|
||||||
@@ -1043,21 +1055,9 @@ async function getConfig(tempDir, logger) {
|
|||||||
return JSON.parse(configString);
|
return JSON.parse(configString);
|
||||||
}
|
}
|
||||||
exports.getConfig = getConfig;
|
exports.getConfig = getConfig;
|
||||||
async function downloadPacks(codeQL, languages, packs, registries, apiDetails, tmpDir, logger) {
|
async function downloadPacks(codeQL, languages, packs, apiDetails, registriesInput, tempDir, logger) {
|
||||||
let qlconfigFile;
|
// This code path is only used when config parsing occurs in the Action.
|
||||||
let registriesAuthTokens;
|
const { registriesAuthTokens, qlconfigFile } = await generateRegistries(registriesInput, codeQL, tempDir, logger);
|
||||||
if (registries) {
|
|
||||||
if (!(await (0, util_1.codeQlVersionAbove)(codeQL, codeql_1.CODEQL_VERSION_GHES_PACK_DOWNLOAD))) {
|
|
||||||
throw new Error(`'registries' input is not supported on CodeQL versions less than ${codeql_1.CODEQL_VERSION_GHES_PACK_DOWNLOAD}.`);
|
|
||||||
}
|
|
||||||
// generate a qlconfig.yml file to hold the registry configs.
|
|
||||||
const qlconfig = createRegistriesBlock(registries);
|
|
||||||
qlconfigFile = path.join(tmpDir, "qlconfig.yml");
|
|
||||||
fs.writeFileSync(qlconfigFile, yaml.dump(qlconfig), "utf8");
|
|
||||||
registriesAuthTokens = registries
|
|
||||||
.map((registry) => `${registry.url}=${registry.token}`)
|
|
||||||
.join(",");
|
|
||||||
}
|
|
||||||
await wrapEnvironment({
|
await wrapEnvironment({
|
||||||
GITHUB_TOKEN: apiDetails.auth,
|
GITHUB_TOKEN: apiDetails.auth,
|
||||||
CODEQL_REGISTRIES_AUTH: registriesAuthTokens,
|
CODEQL_REGISTRIES_AUTH: registriesAuthTokens,
|
||||||
@@ -1085,6 +1085,48 @@ async function downloadPacks(codeQL, languages, packs, registries, apiDetails, t
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
exports.downloadPacks = downloadPacks;
|
exports.downloadPacks = downloadPacks;
|
||||||
|
/**
|
||||||
|
* Generate a `qlconfig.yml` file from the `registries` input.
|
||||||
|
* This file is used by the CodeQL CLI to list the registries to use for each
|
||||||
|
* pack.
|
||||||
|
*
|
||||||
|
* @param registriesInput The value of the `registries` input.
|
||||||
|
* @param codeQL a codeQL object, used only for checking the version of CodeQL.
|
||||||
|
* @param tempDir a temporary directory to store the generated qlconfig.yml file.
|
||||||
|
* @param logger a logger object.
|
||||||
|
* @returns The path to the generated `qlconfig.yml` file and the auth tokens to
|
||||||
|
* use for each registry.
|
||||||
|
*/
|
||||||
|
async function generateRegistries(registriesInput, codeQL, tempDir, logger) {
|
||||||
|
const registries = parseRegistries(registriesInput);
|
||||||
|
let registriesAuthTokens;
|
||||||
|
let qlconfigFile;
|
||||||
|
if (registries) {
|
||||||
|
if (!(await (0, util_1.codeQlVersionAbove)(codeQL, codeql_1.CODEQL_VERSION_GHES_PACK_DOWNLOAD))) {
|
||||||
|
throw new Error(`The 'registries' input is not supported on CodeQL CLI versions earlier than ${codeql_1.CODEQL_VERSION_GHES_PACK_DOWNLOAD}. Please upgrade to CodeQL CLI version ${codeql_1.CODEQL_VERSION_GHES_PACK_DOWNLOAD} or later.`);
|
||||||
|
}
|
||||||
|
// generate a qlconfig.yml file to hold the registry configs.
|
||||||
|
const qlconfig = createRegistriesBlock(registries);
|
||||||
|
qlconfigFile = path.join(tempDir, "qlconfig.yml");
|
||||||
|
const qlconfigContents = yaml.dump(qlconfig);
|
||||||
|
fs.writeFileSync(qlconfigFile, qlconfigContents, "utf8");
|
||||||
|
logger.debug("Generated qlconfig.yml:");
|
||||||
|
logger.debug(qlconfigContents);
|
||||||
|
registriesAuthTokens = registries
|
||||||
|
.map((registry) => `${registry.url}=${registry.token}`)
|
||||||
|
.join(",");
|
||||||
|
}
|
||||||
|
if (typeof process.env.CODEQL_REGISTRIES_AUTH === "string") {
|
||||||
|
logger.debug("Using CODEQL_REGISTRIES_AUTH environment variable to authenticate with registries.");
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
registriesAuthTokens:
|
||||||
|
// if the user has explicitly set the CODEQL_REGISTRIES_AUTH env var then use that
|
||||||
|
process.env.CODEQL_REGISTRIES_AUTH ?? registriesAuthTokens,
|
||||||
|
qlconfigFile,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
exports.generateRegistries = generateRegistries;
|
||||||
function createRegistriesBlock(registries) {
|
function createRegistriesBlock(registries) {
|
||||||
if (!Array.isArray(registries) ||
|
if (!Array.isArray(registries) ||
|
||||||
registries.some((r) => !r.url || !r.packages)) {
|
registries.some((r) => !r.url || !r.packages)) {
|
||||||
@@ -1134,4 +1176,5 @@ async function wrapEnvironment(env, operation) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
exports.wrapEnvironment = wrapEnvironment;
|
||||||
//# sourceMappingURL=config-utils.js.map
|
//# sourceMappingURL=config-utils.js.map
|
||||||
File diff suppressed because one or more lines are too long
Generated
+71
-14
@@ -1014,7 +1014,7 @@ const mlPoweredQueriesMacro = ava_1.default.macro({
|
|||||||
// Test that the ~0.1.0 version of ML-powered queries is run on v2.8.3 of the CLI.
|
// Test that the ~0.1.0 version of ML-powered queries is run on v2.8.3 of the CLI.
|
||||||
(0, ava_1.default)(mlPoweredQueriesMacro, "2.8.3", true, undefined, "security-extended", process.platform === "win32" ? undefined : "~0.1.0");
|
(0, ava_1.default)(mlPoweredQueriesMacro, "2.8.3", true, undefined, "security-extended", process.platform === "win32" ? undefined : "~0.1.0");
|
||||||
// Test that ML-powered queries aren't run when the user hasn't specified that we should run the
|
// Test that ML-powered queries aren't run when the user hasn't specified that we should run the
|
||||||
// `security-extended` or `security-and-quality` query suite.
|
// `security-extended`, `security-and-quality`, or `security-experimental` query suite.
|
||||||
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, undefined, undefined, undefined);
|
(0, ava_1.default)(mlPoweredQueriesMacro, "2.7.5", true, undefined, undefined, undefined);
|
||||||
// Test that ML-powered queries are run on non-Windows platforms running `security-extended` on
|
// Test that ML-powered queries are run on non-Windows platforms running `security-extended` on
|
||||||
// versions of the CodeQL CLI prior to 2.9.0.
|
// versions of the CodeQL CLI prior to 2.9.0.
|
||||||
@@ -1042,6 +1042,9 @@ const mlPoweredQueriesMacro = ava_1.default.macro({
|
|||||||
// Test that ML-powered queries are run on all platforms running `security-and-quality` on CodeQL
|
// Test that ML-powered queries are run on all platforms running `security-and-quality` on CodeQL
|
||||||
// CLI 2.11.3+.
|
// CLI 2.11.3+.
|
||||||
(0, ava_1.default)(mlPoweredQueriesMacro, "2.11.3", true, undefined, "security-and-quality", "~0.4.0");
|
(0, ava_1.default)(mlPoweredQueriesMacro, "2.11.3", true, undefined, "security-and-quality", "~0.4.0");
|
||||||
|
// Test that ML-powered queries are run on all platforms running `security-experimental` on CodeQL
|
||||||
|
// CLI 2.12.1+.
|
||||||
|
(0, ava_1.default)(mlPoweredQueriesMacro, "2.12.1", true, undefined, "security-experimental", "~0.4.0");
|
||||||
const calculateAugmentationMacro = ava_1.default.macro({
|
const calculateAugmentationMacro = ava_1.default.macro({
|
||||||
exec: async (t, _title, rawPacksInput, rawQueriesInput, languages, expectedAugmentationProperties) => {
|
exec: async (t, _title, rawPacksInput, rawQueriesInput, languages, expectedAugmentationProperties) => {
|
||||||
const actualAugmentationProperties = configUtils.calculateAugmentation(rawPacksInput, rawQueriesInput, languages);
|
const actualAugmentationProperties = configUtils.calculateAugmentation(rawPacksInput, rawQueriesInput, languages);
|
||||||
@@ -1111,8 +1114,8 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
java: ["a", "b"],
|
java: ["a", "b"],
|
||||||
go: ["c", "d"],
|
go: ["c", "d"],
|
||||||
python: ["e", "f"],
|
python: ["e", "f"],
|
||||||
}, undefined, // registries
|
}, sampleApiDetails, undefined, // registriesAuthTokens
|
||||||
sampleApiDetails, tmpDir, logger);
|
tmpDir, logger);
|
||||||
// Expecting packs to be downloaded once for java and once for python
|
// Expecting packs to be downloaded once for java and once for python
|
||||||
t.deepEqual(packDownloadStub.callCount, 2);
|
t.deepEqual(packDownloadStub.callCount, 2);
|
||||||
// no config file was created, so pass `undefined` as the config file path
|
// no config file was created, so pass `undefined` as the config file path
|
||||||
@@ -1125,9 +1128,9 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
// associated env vars
|
// associated env vars
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env.GITHUB_TOKEN = "not-a-token";
|
process.env.GITHUB_TOKEN = "not-a-token";
|
||||||
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
process.env.CODEQL_REGISTRIES_AUTH = undefined;
|
||||||
const logger = (0, logging_1.getRunnerLogger)(true);
|
const logger = (0, logging_1.getRunnerLogger)(true);
|
||||||
const registries = [
|
const registriesInput = yaml.dump([
|
||||||
{
|
{
|
||||||
// no slash
|
// no slash
|
||||||
url: "http://ghcr.io",
|
url: "http://ghcr.io",
|
||||||
@@ -1140,8 +1143,9 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
packages: "semmle/*",
|
packages: "semmle/*",
|
||||||
token: "still-not-a-token",
|
token: "still-not-a-token",
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
// append a slash to the first url
|
// append a slash to the first url
|
||||||
|
const registries = yaml.load(registriesInput);
|
||||||
const expectedRegistries = registries.map((r, i) => ({
|
const expectedRegistries = registries.map((r, i) => ({
|
||||||
packages: r.packages,
|
packages: r.packages,
|
||||||
url: i === 0 ? `${r.url}/` : r.url,
|
url: i === 0 ? `${r.url}/` : r.url,
|
||||||
@@ -1170,7 +1174,7 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
java: ["a", "b"],
|
java: ["a", "b"],
|
||||||
go: ["c", "d"],
|
go: ["c", "d"],
|
||||||
python: ["e", "f"],
|
python: ["e", "f"],
|
||||||
}, registries, sampleApiDetails, tmpDir, logger);
|
}, sampleApiDetails, registriesInput, tmpDir, logger);
|
||||||
// Same packs are downloaded as in previous test
|
// Same packs are downloaded as in previous test
|
||||||
t.deepEqual(packDownloadStub.callCount, 2);
|
t.deepEqual(packDownloadStub.callCount, 2);
|
||||||
t.deepEqual(packDownloadStub.firstCall.args, [
|
t.deepEqual(packDownloadStub.firstCall.args, [
|
||||||
@@ -1183,7 +1187,7 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
]);
|
]);
|
||||||
// Verify that the env vars were unset.
|
// Verify that the env vars were unset.
|
||||||
t.deepEqual(process.env.GITHUB_TOKEN, "not-a-token");
|
t.deepEqual(process.env.GITHUB_TOKEN, "not-a-token");
|
||||||
t.deepEqual(process.env.CODEQL_REGISTRIES_AUTH, "not-a-registries-auth");
|
t.deepEqual(process.env.CODEQL_REGISTRIES_AUTH, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
(0, ava_1.default)("downloadPacks-with-registries fails on 2.10.3", async (t) => {
|
(0, ava_1.default)("downloadPacks-with-registries fails on 2.10.3", async (t) => {
|
||||||
@@ -1193,7 +1197,7 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
process.env.GITHUB_TOKEN = "not-a-token";
|
process.env.GITHUB_TOKEN = "not-a-token";
|
||||||
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
||||||
const logger = (0, logging_1.getRunnerLogger)(true);
|
const logger = (0, logging_1.getRunnerLogger)(true);
|
||||||
const registries = [
|
const registriesInput = yaml.dump([
|
||||||
{
|
{
|
||||||
url: "http://ghcr.io",
|
url: "http://ghcr.io",
|
||||||
packages: ["codeql/*", "dsp-testing/*"],
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
@@ -1204,12 +1208,12 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
packages: "semmle/*",
|
packages: "semmle/*",
|
||||||
token: "still-not-a-token",
|
token: "still-not-a-token",
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
const codeQL = (0, codeql_1.setCodeQL)({
|
const codeQL = (0, codeql_1.setCodeQL)({
|
||||||
getVersion: () => Promise.resolve("2.10.3"),
|
getVersion: () => Promise.resolve("2.10.3"),
|
||||||
});
|
});
|
||||||
await t.throwsAsync(async () => {
|
await t.throwsAsync(async () => {
|
||||||
return await configUtils.downloadPacks(codeQL, [languages_1.Language.javascript, languages_1.Language.java, languages_1.Language.python], {}, registries, sampleApiDetails, tmpDir, logger);
|
return await configUtils.downloadPacks(codeQL, [languages_1.Language.javascript, languages_1.Language.java, languages_1.Language.python], {}, sampleApiDetails, registriesInput, tmpDir, logger);
|
||||||
}, { instanceOf: Error }, "'registries' input is not supported on CodeQL versions less than 2.10.4.");
|
}, { instanceOf: Error }, "'registries' input is not supported on CodeQL versions less than 2.10.4.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -1220,7 +1224,7 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
process.env.GITHUB_TOKEN = "not-a-token";
|
process.env.GITHUB_TOKEN = "not-a-token";
|
||||||
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
||||||
const logger = (0, logging_1.getRunnerLogger)(true);
|
const logger = (0, logging_1.getRunnerLogger)(true);
|
||||||
const registries = [
|
const registriesInput = yaml.dump([
|
||||||
{
|
{
|
||||||
// missing url property
|
// missing url property
|
||||||
packages: ["codeql/*", "dsp-testing/*"],
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
@@ -1231,15 +1235,68 @@ const calculateAugmentationErrorMacro = ava_1.default.macro({
|
|||||||
packages: "semmle/*",
|
packages: "semmle/*",
|
||||||
token: "still-not-a-token",
|
token: "still-not-a-token",
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
const codeQL = (0, codeql_1.setCodeQL)({
|
const codeQL = (0, codeql_1.setCodeQL)({
|
||||||
getVersion: () => Promise.resolve("2.10.4"),
|
getVersion: () => Promise.resolve("2.10.4"),
|
||||||
});
|
});
|
||||||
await t.throwsAsync(async () => {
|
await t.throwsAsync(async () => {
|
||||||
return await configUtils.downloadPacks(codeQL, [languages_1.Language.javascript, languages_1.Language.java, languages_1.Language.python], {}, registries, sampleApiDetails, tmpDir, logger);
|
return await configUtils.downloadPacks(codeQL, [languages_1.Language.javascript, languages_1.Language.java, languages_1.Language.python], {}, sampleApiDetails, registriesInput, tmpDir, logger);
|
||||||
}, { instanceOf: Error }, "Invalid 'registries' input. Must be an array of objects with 'url' and 'packages' properties.");
|
}, { instanceOf: Error }, "Invalid 'registries' input. Must be an array of objects with 'url' and 'packages' properties.");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
// the happy path for generateRegistries is already tested in downloadPacks.
|
||||||
|
// these following tests are for the error cases and when nothing is generated.
|
||||||
|
(0, ava_1.default)("no generateRegistries when CLI is too old", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const registriesInput = yaml.dump([
|
||||||
|
{
|
||||||
|
// no slash
|
||||||
|
url: "http://ghcr.io",
|
||||||
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
|
token: "not-a-token",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const codeQL = (0, codeql_1.setCodeQL)({
|
||||||
|
// Accepted CLI versions are 2.10.4 or higher
|
||||||
|
getVersion: () => Promise.resolve("2.10.3"),
|
||||||
|
});
|
||||||
|
const logger = (0, logging_1.getRunnerLogger)(true);
|
||||||
|
await t.throwsAsync(async () => await configUtils.generateRegistries(registriesInput, codeQL, tmpDir, logger), undefined, "'registries' input is not supported on CodeQL versions less than 2.10.4.");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("no generateRegistries when registries is undefined", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const registriesInput = undefined;
|
||||||
|
const codeQL = (0, codeql_1.setCodeQL)({
|
||||||
|
// Accepted CLI versions are 2.10.4 or higher
|
||||||
|
getVersion: () => Promise.resolve(codeql_1.CODEQL_VERSION_GHES_PACK_DOWNLOAD),
|
||||||
|
});
|
||||||
|
const logger = (0, logging_1.getRunnerLogger)(true);
|
||||||
|
const { registriesAuthTokens, qlconfigFile } = await configUtils.generateRegistries(registriesInput, codeQL, tmpDir, logger);
|
||||||
|
t.is(registriesAuthTokens, undefined);
|
||||||
|
t.is(qlconfigFile, undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
(0, ava_1.default)("generateRegistries prefers original CODEQL_REGISTRIES_AUTH", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
process.env.CODEQL_REGISTRIES_AUTH = "original";
|
||||||
|
const registriesInput = yaml.dump([
|
||||||
|
{
|
||||||
|
url: "http://ghcr.io",
|
||||||
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
|
token: "not-a-token",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const codeQL = (0, codeql_1.setCodeQL)({
|
||||||
|
// Accepted CLI versions are 2.10.4 or higher
|
||||||
|
getVersion: () => Promise.resolve(codeql_1.CODEQL_VERSION_GHES_PACK_DOWNLOAD),
|
||||||
|
});
|
||||||
|
const logger = (0, logging_1.getRunnerLogger)(true);
|
||||||
|
const { registriesAuthTokens, qlconfigFile } = await configUtils.generateRegistries(registriesInput, codeQL, tmpDir, logger);
|
||||||
|
t.is(registriesAuthTokens, "original");
|
||||||
|
t.is(qlconfigFile, path.join(tmpDir, "qlconfig.yml"));
|
||||||
|
});
|
||||||
|
});
|
||||||
// getLanguages
|
// getLanguages
|
||||||
const mockRepositoryNwo = (0, repository_1.parseRepositoryNwo)("owner/repo");
|
const mockRepositoryNwo = (0, repository_1.parseRepositoryNwo)("owner/repo");
|
||||||
// eslint-disable-next-line github/array-foreach
|
// eslint-disable-next-line github/array-foreach
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"bundleVersion": "codeql-bundle-20230120",
|
"bundleVersion": "codeql-bundle-20230217",
|
||||||
"cliVersion": "2.12.1",
|
"cliVersion": "2.12.3",
|
||||||
"priorBundleVersion": "codeql-bundle-20230105",
|
"priorBundleVersion": "codeql-bundle-20230207",
|
||||||
"priorCliVersion": "2.12.0"
|
"priorCliVersion": "2.12.2"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+10
-27
@@ -34,27 +34,12 @@ const DEFAULT_VERSION_FEATURE_FLAG_PREFIX = "default_codeql_version_";
|
|||||||
const DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled";
|
const DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled";
|
||||||
var Feature;
|
var Feature;
|
||||||
(function (Feature) {
|
(function (Feature) {
|
||||||
Feature["BypassToolcacheEnabled"] = "bypass_toolcache_enabled";
|
|
||||||
Feature["BypassToolcacheKotlinSwiftEnabled"] = "bypass_toolcache_kotlin_swift_enabled";
|
|
||||||
Feature["CliConfigFileEnabled"] = "cli_config_file_enabled";
|
Feature["CliConfigFileEnabled"] = "cli_config_file_enabled";
|
||||||
Feature["DisableKotlinAnalysisEnabled"] = "disable_kotlin_analysis_enabled";
|
Feature["DisableKotlinAnalysisEnabled"] = "disable_kotlin_analysis_enabled";
|
||||||
Feature["MlPoweredQueriesEnabled"] = "ml_powered_queries_enabled";
|
Feature["MlPoweredQueriesEnabled"] = "ml_powered_queries_enabled";
|
||||||
Feature["TrapCachingEnabled"] = "trap_caching_enabled";
|
|
||||||
Feature["UploadFailedSarifEnabled"] = "upload_failed_sarif_enabled";
|
Feature["UploadFailedSarifEnabled"] = "upload_failed_sarif_enabled";
|
||||||
})(Feature = exports.Feature || (exports.Feature = {}));
|
})(Feature = exports.Feature || (exports.Feature = {}));
|
||||||
exports.featureConfig = {
|
exports.featureConfig = {
|
||||||
[Feature.BypassToolcacheEnabled]: {
|
|
||||||
envVar: "CODEQL_BYPASS_TOOLCACHE",
|
|
||||||
// Cannot specify a minimum version because this flag is checked before we have
|
|
||||||
// access to the CodeQL instance.
|
|
||||||
minimumVersion: undefined,
|
|
||||||
},
|
|
||||||
[Feature.BypassToolcacheKotlinSwiftEnabled]: {
|
|
||||||
envVar: "CODEQL_BYPASS_TOOLCACHE_KOTLIN_SWIFT",
|
|
||||||
// Cannot specify a minimum version because this flag is checked before we have
|
|
||||||
// access to the CodeQL instance.
|
|
||||||
minimumVersion: undefined,
|
|
||||||
},
|
|
||||||
[Feature.DisableKotlinAnalysisEnabled]: {
|
[Feature.DisableKotlinAnalysisEnabled]: {
|
||||||
envVar: "CODEQL_DISABLE_KOTLIN_ANALYSIS",
|
envVar: "CODEQL_DISABLE_KOTLIN_ANALYSIS",
|
||||||
minimumVersion: undefined,
|
minimumVersion: undefined,
|
||||||
@@ -67,10 +52,6 @@ exports.featureConfig = {
|
|||||||
envVar: "CODEQL_ML_POWERED_QUERIES",
|
envVar: "CODEQL_ML_POWERED_QUERIES",
|
||||||
minimumVersion: "2.7.5",
|
minimumVersion: "2.7.5",
|
||||||
},
|
},
|
||||||
[Feature.TrapCachingEnabled]: {
|
|
||||||
envVar: "CODEQL_TRAP_CACHING",
|
|
||||||
minimumVersion: undefined,
|
|
||||||
},
|
|
||||||
[Feature.UploadFailedSarifEnabled]: {
|
[Feature.UploadFailedSarifEnabled]: {
|
||||||
envVar: "CODEQL_ACTION_UPLOAD_FAILED_SARIF",
|
envVar: "CODEQL_ACTION_UPLOAD_FAILED_SARIF",
|
||||||
minimumVersion: "2.11.3",
|
minimumVersion: "2.11.3",
|
||||||
@@ -105,10 +86,6 @@ class Features {
|
|||||||
if (!codeql && exports.featureConfig[feature].minimumVersion) {
|
if (!codeql && exports.featureConfig[feature].minimumVersion) {
|
||||||
throw new Error(`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`);
|
throw new Error(`Internal error: A minimum version is specified for feature ${feature}, but no instance of CodeQL was provided.`);
|
||||||
}
|
}
|
||||||
// Bypassing the toolcache is disabled in test mode.
|
|
||||||
if (feature === Feature.BypassToolcacheEnabled && util.isInTestMode()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
const envVar = (process.env[exports.featureConfig[feature].envVar] || "").toLocaleLowerCase();
|
const envVar = (process.env[exports.featureConfig[feature].envVar] || "").toLocaleLowerCase();
|
||||||
// Do not use this feature if user explicitly disables it via an environment variable.
|
// Do not use this feature if user explicitly disables it via an environment variable.
|
||||||
if (envVar === "false") {
|
if (envVar === "false") {
|
||||||
@@ -136,7 +113,7 @@ class GitHubFeatureFlags {
|
|||||||
this.repositoryNwo = repositoryNwo;
|
this.repositoryNwo = repositoryNwo;
|
||||||
this.featureFlagsFile = featureFlagsFile;
|
this.featureFlagsFile = featureFlagsFile;
|
||||||
this.logger = logger;
|
this.logger = logger;
|
||||||
/**/
|
this.hasAccessedRemoteFeatureFlags = false; // Not accessed by default.
|
||||||
}
|
}
|
||||||
getCliVersionFromFeatureFlag(f) {
|
getCliVersionFromFeatureFlag(f) {
|
||||||
if (!f.startsWith(DEFAULT_VERSION_FEATURE_FLAG_PREFIX) ||
|
if (!f.startsWith(DEFAULT_VERSION_FEATURE_FLAG_PREFIX) ||
|
||||||
@@ -157,7 +134,9 @@ class GitHubFeatureFlags {
|
|||||||
const defaultDotComCliVersion = await this.getDefaultDotcomCliVersion();
|
const defaultDotComCliVersion = await this.getDefaultDotcomCliVersion();
|
||||||
return {
|
return {
|
||||||
cliVersion: defaultDotComCliVersion.version,
|
cliVersion: defaultDotComCliVersion.version,
|
||||||
toolsFeatureFlagsValid: defaultDotComCliVersion.toolsFeatureFlagsValid,
|
toolsFeatureFlagsValid: this.hasAccessedRemoteFeatureFlags
|
||||||
|
? defaultDotComCliVersion.toolsFeatureFlagsValid
|
||||||
|
: undefined,
|
||||||
variant,
|
variant,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -188,7 +167,9 @@ class GitHubFeatureFlags {
|
|||||||
`shipped with the Action. This is ${defaults.cliVersion}.`);
|
`shipped with the Action. This is ${defaults.cliVersion}.`);
|
||||||
return {
|
return {
|
||||||
version: defaults.cliVersion,
|
version: defaults.cliVersion,
|
||||||
toolsFeatureFlagsValid: false,
|
toolsFeatureFlagsValid: this.hasAccessedRemoteFeatureFlags
|
||||||
|
? false
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
const maxCliVersion = enabledFeatureFlagCliVersions.reduce((maxVersion, currentVersion) => currentVersion > maxVersion ? currentVersion : maxVersion, enabledFeatureFlagCliVersions[0]);
|
const maxCliVersion = enabledFeatureFlagCliVersions.reduce((maxVersion, currentVersion) => currentVersion > maxVersion ? currentVersion : maxVersion, enabledFeatureFlagCliVersions[0]);
|
||||||
@@ -255,6 +236,7 @@ class GitHubFeatureFlags {
|
|||||||
// Do nothing when not running against github.com
|
// Do nothing when not running against github.com
|
||||||
if (this.gitHubVersion.type !== util.GitHubVariant.DOTCOM) {
|
if (this.gitHubVersion.type !== util.GitHubVariant.DOTCOM) {
|
||||||
this.logger.debug("Not running against github.com. Disabling all toggleable features.");
|
this.logger.debug("Not running against github.com. Disabling all toggleable features.");
|
||||||
|
this.hasAccessedRemoteFeatureFlags = false;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -265,6 +247,7 @@ class GitHubFeatureFlags {
|
|||||||
const remoteFlags = response.data;
|
const remoteFlags = response.data;
|
||||||
this.logger.debug("Loaded the following default values for the feature flags from the Code Scanning API: " +
|
this.logger.debug("Loaded the following default values for the feature flags from the Code Scanning API: " +
|
||||||
`${JSON.stringify(remoteFlags)}`);
|
`${JSON.stringify(remoteFlags)}`);
|
||||||
|
this.hasAccessedRemoteFeatureFlags = true;
|
||||||
return remoteFlags;
|
return remoteFlags;
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
@@ -273,6 +256,7 @@ class GitHubFeatureFlags {
|
|||||||
"As a result, it will not be opted into any experimental features. " +
|
"As a result, it will not be opted into any experimental features. " +
|
||||||
"This could be because the Action is running on a pull request from a fork. If not, " +
|
"This could be because the Action is running on a pull request from a fork. If not, " +
|
||||||
`please ensure the Action has the 'security-events: write' permission. Details: ${e}`);
|
`please ensure the Action has the 'security-events: write' permission. Details: ${e}`);
|
||||||
|
this.hasAccessedRemoteFeatureFlags = false;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -283,7 +267,6 @@ class GitHubFeatureFlags {
|
|||||||
throw new Error(`Encountered an error while trying to determine feature enablement: ${e}`);
|
throw new Error(`Encountered an error while trying to determine feature enablement: ${e}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//# sourceMappingURL=feature-flags.js.map
|
//# sourceMappingURL=feature-flags.js.map
|
||||||
File diff suppressed because one or more lines are too long
Generated
+14
-12
@@ -46,12 +46,13 @@ async function sendInitStatusReport(actionStatus, startedAt, config, toolsDownlo
|
|||||||
tools_source: toolsSource || init_1.ToolsSource.Unknown,
|
tools_source: toolsSource || init_1.ToolsSource.Unknown,
|
||||||
workflow_languages: workflowLanguages || "",
|
workflow_languages: workflowLanguages || "",
|
||||||
};
|
};
|
||||||
let initToolsDownloadFields = {};
|
const initToolsDownloadFields = {};
|
||||||
if (toolsSource === init_1.ToolsSource.Download) {
|
if (toolsDownloadDurationMs !== undefined) {
|
||||||
initToolsDownloadFields = {
|
initToolsDownloadFields.tools_download_duration_ms =
|
||||||
tools_download_duration_ms: toolsDownloadDurationMs,
|
toolsDownloadDurationMs;
|
||||||
tools_feature_flags_valid: toolsFeatureFlagsValid,
|
}
|
||||||
};
|
if (toolsFeatureFlagsValid !== undefined) {
|
||||||
|
initToolsDownloadFields.tools_feature_flags_valid = toolsFeatureFlagsValid;
|
||||||
}
|
}
|
||||||
if (config !== undefined) {
|
if (config !== undefined) {
|
||||||
const languages = config.languages.join(",");
|
const languages = config.languages.join(",");
|
||||||
@@ -112,6 +113,7 @@ async function run() {
|
|||||||
const gitHubVersion = await (0, api_client_1.getGitHubVersion)();
|
const gitHubVersion = await (0, api_client_1.getGitHubVersion)();
|
||||||
(0, util_1.checkGitHubVersionInRange)(gitHubVersion, logger);
|
(0, util_1.checkGitHubVersionInRange)(gitHubVersion, logger);
|
||||||
const repositoryNwo = (0, repository_1.parseRepositoryNwo)((0, util_1.getRequiredEnvParam)("GITHUB_REPOSITORY"));
|
const repositoryNwo = (0, repository_1.parseRepositoryNwo)((0, util_1.getRequiredEnvParam)("GITHUB_REPOSITORY"));
|
||||||
|
const registriesInput = (0, actions_util_1.getOptionalInput)("registries");
|
||||||
const features = new feature_flags_1.Features(gitHubVersion, repositoryNwo, (0, actions_util_1.getTemporaryDirectory)(), logger);
|
const features = new feature_flags_1.Features(gitHubVersion, repositoryNwo, (0, actions_util_1.getTemporaryDirectory)(), logger);
|
||||||
try {
|
try {
|
||||||
const workflowErrors = await (0, workflow_1.validateWorkflow)();
|
const workflowErrors = await (0, workflow_1.validateWorkflow)();
|
||||||
@@ -122,13 +124,13 @@ async function run() {
|
|||||||
if (codeQLDefaultVersionInfo.variant === util_1.GitHubVariant.DOTCOM) {
|
if (codeQLDefaultVersionInfo.variant === util_1.GitHubVariant.DOTCOM) {
|
||||||
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
|
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
|
||||||
}
|
}
|
||||||
const initCodeQLResult = await (0, init_1.initCodeQL)((0, actions_util_1.getOptionalInput)("tools"), apiDetails, (0, actions_util_1.getTemporaryDirectory)(), gitHubVersion.type, await (0, util_1.shouldBypassToolcache)(features, (0, actions_util_1.getOptionalInput)("tools"), (0, actions_util_1.getOptionalInput)("languages"), repositoryNwo, logger), codeQLDefaultVersionInfo, logger);
|
const initCodeQLResult = await (0, init_1.initCodeQL)((0, actions_util_1.getOptionalInput)("tools"), apiDetails, (0, actions_util_1.getTemporaryDirectory)(), gitHubVersion.type, codeQLDefaultVersionInfo, logger);
|
||||||
codeql = initCodeQLResult.codeql;
|
codeql = initCodeQLResult.codeql;
|
||||||
toolsDownloadDurationMs = initCodeQLResult.toolsDownloadDurationMs;
|
toolsDownloadDurationMs = initCodeQLResult.toolsDownloadDurationMs;
|
||||||
toolsVersion = initCodeQLResult.toolsVersion;
|
toolsVersion = initCodeQLResult.toolsVersion;
|
||||||
toolsSource = initCodeQLResult.toolsSource;
|
toolsSource = initCodeQLResult.toolsSource;
|
||||||
await (0, util_1.enrichEnvironment)(codeql);
|
await (0, util_1.enrichEnvironment)(codeql);
|
||||||
config = await (0, init_1.initConfig)((0, actions_util_1.getOptionalInput)("languages"), (0, actions_util_1.getOptionalInput)("queries"), (0, actions_util_1.getOptionalInput)("packs"), (0, actions_util_1.getOptionalInput)("registries"), (0, actions_util_1.getOptionalInput)("config-file"), (0, actions_util_1.getOptionalInput)("db-location"), await getTrapCachingEnabled(features),
|
config = await (0, init_1.initConfig)((0, actions_util_1.getOptionalInput)("languages"), (0, actions_util_1.getOptionalInput)("queries"), (0, actions_util_1.getOptionalInput)("packs"), registriesInput, (0, actions_util_1.getOptionalInput)("config-file"), (0, actions_util_1.getOptionalInput)("db-location"), getTrapCachingEnabled(),
|
||||||
// Debug mode is enabled if:
|
// Debug mode is enabled if:
|
||||||
// - The `init` Action is passed `debug: true`.
|
// - The `init` Action is passed `debug: true`.
|
||||||
// - Actions step debugging is enabled (e.g. by [enabling debug logging for a rerun](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow),
|
// - Actions step debugging is enabled (e.g. by [enabling debug logging for a rerun](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow),
|
||||||
@@ -172,7 +174,7 @@ async function run() {
|
|||||||
core.exportVariable("CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN", "true");
|
core.exportVariable("CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN", "true");
|
||||||
}
|
}
|
||||||
const sourceRoot = path.resolve((0, util_1.getRequiredEnvParam)("GITHUB_WORKSPACE"), (0, actions_util_1.getOptionalInput)("source-root") || "");
|
const sourceRoot = path.resolve((0, util_1.getRequiredEnvParam)("GITHUB_WORKSPACE"), (0, actions_util_1.getOptionalInput)("source-root") || "");
|
||||||
const tracerConfig = await (0, init_1.runInit)(codeql, config, sourceRoot, "Runner.Worker.exe", features, logger);
|
const tracerConfig = await (0, init_1.runInit)(codeql, config, sourceRoot, "Runner.Worker.exe", registriesInput, features, apiDetails, logger);
|
||||||
if (tracerConfig !== undefined) {
|
if (tracerConfig !== undefined) {
|
||||||
for (const [key, value] of Object.entries(tracerConfig.env)) {
|
for (const [key, value] of Object.entries(tracerConfig.env)) {
|
||||||
core.exportVariable(key, value);
|
core.exportVariable(key, value);
|
||||||
@@ -192,7 +194,7 @@ async function run() {
|
|||||||
}
|
}
|
||||||
await sendInitStatusReport("success", startedAt, config, toolsDownloadDurationMs, toolsFeatureFlagsValid, toolsSource, toolsVersion, logger);
|
await sendInitStatusReport("success", startedAt, config, toolsDownloadDurationMs, toolsFeatureFlagsValid, toolsSource, toolsVersion, logger);
|
||||||
}
|
}
|
||||||
async function getTrapCachingEnabled(featureEnablement) {
|
function getTrapCachingEnabled() {
|
||||||
// If the workflow specified something always respect that
|
// If the workflow specified something always respect that
|
||||||
const trapCaching = (0, actions_util_1.getOptionalInput)("trap-caching");
|
const trapCaching = (0, actions_util_1.getOptionalInput)("trap-caching");
|
||||||
if (trapCaching !== undefined)
|
if (trapCaching !== undefined)
|
||||||
@@ -200,8 +202,8 @@ async function getTrapCachingEnabled(featureEnablement) {
|
|||||||
// On self-hosted runners which may have slow network access, disable TRAP caching by default
|
// On self-hosted runners which may have slow network access, disable TRAP caching by default
|
||||||
if (!(0, util_1.isHostedRunner)())
|
if (!(0, util_1.isHostedRunner)())
|
||||||
return false;
|
return false;
|
||||||
// On hosted runners, respect the feature flag
|
// On hosted runners, enable TRAP caching by default
|
||||||
return await featureEnablement.getValue(feature_flags_1.Feature.TrapCachingEnabled);
|
return true;
|
||||||
}
|
}
|
||||||
async function runWrapper() {
|
async function runWrapper() {
|
||||||
try {
|
try {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+18
-4
@@ -41,9 +41,9 @@ var ToolsSource;
|
|||||||
ToolsSource["Toolcache"] = "TOOLCACHE";
|
ToolsSource["Toolcache"] = "TOOLCACHE";
|
||||||
ToolsSource["Download"] = "DOWNLOAD";
|
ToolsSource["Download"] = "DOWNLOAD";
|
||||||
})(ToolsSource = exports.ToolsSource || (exports.ToolsSource = {}));
|
})(ToolsSource = exports.ToolsSource || (exports.ToolsSource = {}));
|
||||||
async function initCodeQL(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger) {
|
async function initCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, logger) {
|
||||||
logger.startGroup("Setup CodeQL tools");
|
logger.startGroup("Setup CodeQL tools");
|
||||||
const { codeql, toolsDownloadDurationMs, toolsSource, toolsVersion } = await (0, codeql_1.setupCodeQL)(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger, true);
|
const { codeql, toolsDownloadDurationMs, toolsSource, toolsVersion } = await (0, codeql_1.setupCodeQL)(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, logger, true);
|
||||||
await codeql.printVersion();
|
await codeql.printVersion();
|
||||||
logger.endGroup();
|
logger.endGroup();
|
||||||
return { codeql, toolsDownloadDurationMs, toolsSource, toolsVersion };
|
return { codeql, toolsDownloadDurationMs, toolsSource, toolsVersion };
|
||||||
@@ -57,12 +57,26 @@ async function initConfig(languagesInput, queriesInput, packsInput, registriesIn
|
|||||||
return config;
|
return config;
|
||||||
}
|
}
|
||||||
exports.initConfig = initConfig;
|
exports.initConfig = initConfig;
|
||||||
async function runInit(codeql, config, sourceRoot, processName, featureEnablement, logger) {
|
async function runInit(codeql, config, sourceRoot, processName, registriesInput, featureEnablement, apiDetails, logger) {
|
||||||
fs.mkdirSync(config.dbLocation, { recursive: true });
|
fs.mkdirSync(config.dbLocation, { recursive: true });
|
||||||
try {
|
try {
|
||||||
if (await (0, util_1.codeQlVersionAbove)(codeql, codeql_1.CODEQL_VERSION_NEW_TRACING)) {
|
if (await (0, util_1.codeQlVersionAbove)(codeql, codeql_1.CODEQL_VERSION_NEW_TRACING)) {
|
||||||
|
// When parsing the codeql config in the CLI, we have not yet created the qlconfig file.
|
||||||
|
// So, create it now.
|
||||||
|
// If we are parsing the config file in the Action, then the qlconfig file was already created
|
||||||
|
// before the `pack download` command was invoked. It is not required for the init command.
|
||||||
|
let registriesAuthTokens;
|
||||||
|
let qlconfigFile;
|
||||||
|
if (await util.useCodeScanningConfigInCli(codeql, featureEnablement)) {
|
||||||
|
({ registriesAuthTokens, qlconfigFile } =
|
||||||
|
await configUtils.generateRegistries(registriesInput, codeql, config.tempDir, logger));
|
||||||
|
}
|
||||||
|
await configUtils.wrapEnvironment({
|
||||||
|
GITHUB_TOKEN: apiDetails.auth,
|
||||||
|
CODEQL_REGISTRIES_AUTH: registriesAuthTokens,
|
||||||
|
},
|
||||||
// Init a database cluster
|
// Init a database cluster
|
||||||
await codeql.databaseInitCluster(config, sourceRoot, processName, featureEnablement, logger);
|
async () => await codeql.databaseInitCluster(config, sourceRoot, processName, featureEnablement, qlconfigFile, logger));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
for (const language of config.languages) {
|
for (const language of config.languages) {
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
+1
-2
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.isScannedLanguage = exports.isTracedLanguage = exports.parseLanguage = exports.resolveAlias = exports.KOTLIN_SWIFT_BYPASS = exports.LANGUAGE_ALIASES = exports.Language = void 0;
|
exports.isScannedLanguage = exports.isTracedLanguage = exports.parseLanguage = exports.resolveAlias = exports.LANGUAGE_ALIASES = exports.Language = void 0;
|
||||||
// All the languages supported by CodeQL
|
// All the languages supported by CodeQL
|
||||||
var Language;
|
var Language;
|
||||||
(function (Language) {
|
(function (Language) {
|
||||||
@@ -21,7 +21,6 @@ exports.LANGUAGE_ALIASES = {
|
|||||||
kotlin: Language.java,
|
kotlin: Language.java,
|
||||||
typescript: Language.javascript,
|
typescript: Language.javascript,
|
||||||
};
|
};
|
||||||
exports.KOTLIN_SWIFT_BYPASS = ["kotlin", "swift"];
|
|
||||||
function resolveAlias(lang) {
|
function resolveAlias(lang) {
|
||||||
return exports.LANGUAGE_ALIASES[lang] || lang;
|
return exports.LANGUAGE_ALIASES[lang] || lang;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
{"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;AACpB,QAAA,gBAAgB,GAAiC;IAC5D,CAAC,EAAE,QAAQ,CAAC,GAAG;IACf,KAAK,EAAE,QAAQ,CAAC,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAC,MAAM;IACrB,MAAM,EAAE,QAAQ,CAAC,IAAI;IACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAChC,CAAC;AAIW,QAAA,mBAAmB,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;AAEvD,SAAgB,YAAY,CAAC,IAAqB;IAChD,OAAO,wBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AACxC,CAAC;AAFD,oCAEC;AAED;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,QAAgB;IAC5C,0BAA0B;IAC1B,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAEzC,6BAA6B;IAC7B,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,OAAO,QAAoB,CAAC;KAC7B;IAED,iEAAiE;IACjE,oCAAoC;IACpC,IAAI,QAAQ,IAAI,wBAAgB,EAAE;QAChC,OAAO,QAAQ,CAAC;KACjB;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAhBD,sCAgBC;AAED,SAAgB,gBAAgB,CAAC,QAAkB;IACjD,OAAO;QACL,QAAQ,CAAC,GAAG;QACZ,QAAQ,CAAC,MAAM;QACf,QAAQ,CAAC,EAAE;QACX,QAAQ,CAAC,IAAI;QACb,QAAQ,CAAC,KAAK;KACf,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACvB,CAAC;AARD,4CAQC;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;AACpB,QAAA,gBAAgB,GAAiC;IAC5D,CAAC,EAAE,QAAQ,CAAC,GAAG;IACf,KAAK,EAAE,QAAQ,CAAC,GAAG;IACnB,IAAI,EAAE,QAAQ,CAAC,MAAM;IACrB,MAAM,EAAE,QAAQ,CAAC,IAAI;IACrB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAChC,CAAC;AAIF,SAAgB,YAAY,CAAC,IAAqB;IAChD,OAAO,wBAAgB,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AACxC,CAAC;AAFD,oCAEC;AAED;;;;;;;;;GASG;AACH,SAAgB,aAAa,CAAC,QAAgB;IAC5C,0BAA0B;IAC1B,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAEzC,6BAA6B;IAC7B,IAAI,QAAQ,IAAI,QAAQ,EAAE;QACxB,OAAO,QAAoB,CAAC;KAC7B;IAED,iEAAiE;IACjE,oCAAoC;IACpC,IAAI,QAAQ,IAAI,wBAAgB,EAAE;QAChC,OAAO,QAAQ,CAAC;KACjB;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAhBD,sCAgBC;AAED,SAAgB,gBAAgB,CAAC,QAAkB;IACjD,OAAO;QACL,QAAQ,CAAC,GAAG;QACZ,QAAQ,CAAC,MAAM;QACf,QAAQ,CAAC,EAAE;QACX,QAAQ,CAAC,IAAI;QACb,QAAQ,CAAC,KAAK;KACf,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AACvB,CAAC;AARD,4CAQC;AAED,SAAgB,iBAAiB,CAAC,QAAkB;IAClD,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AAFD,8CAEC"}
|
||||||
Generated
+12
-20
@@ -277,7 +277,7 @@ async function findOverridingToolsInCache(humanReadableVersion, logger) {
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
async function getCodeQLSource(toolsInput, bypassToolcache, defaultCliVersion, apiDetails, variant, logger) {
|
async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, logger) {
|
||||||
if (toolsInput && toolsInput !== "latest" && !toolsInput.startsWith("http")) {
|
if (toolsInput && toolsInput !== "latest" && !toolsInput.startsWith("http")) {
|
||||||
return {
|
return {
|
||||||
codeqlTarPath: toolsInput,
|
codeqlTarPath: toolsInput,
|
||||||
@@ -285,24 +285,17 @@ async function getCodeQLSource(toolsInput, bypassToolcache, defaultCliVersion, a
|
|||||||
toolsVersion: "local",
|
toolsVersion: "local",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
/** The reason why the tools shipped with the Action have been forced. */
|
/**
|
||||||
const forceShippedToolsReason =
|
* Whether the tools shipped with the Action, i.e. those in `defaults.json`, have been forced.
|
||||||
// We use the special value of 'latest' to prioritize the version in the
|
*
|
||||||
// defaults over any pinned cached version.
|
* We use the special value of 'latest' to prioritize the version in `defaults.json` over the
|
||||||
toolsInput === "latest"
|
* version specified by the feature flags on Dotcom and over any pinned cached version on
|
||||||
? '"tools: latest" was requested'
|
* Enterprise Server.
|
||||||
: // If the user hasn't requested a particular CodeQL version, then bypass
|
*/
|
||||||
// the toolcache when the appropriate feature is enabled. This
|
const forceShippedTools = toolsInput === "latest";
|
||||||
// allows us to quickly rollback a broken bundle that has made its way
|
|
||||||
// into the toolcache.
|
|
||||||
toolsInput === undefined && bypassToolcache
|
|
||||||
? "a specific version of the CodeQL tools was not requested and the bypass toolcache feature is enabled"
|
|
||||||
: undefined;
|
|
||||||
/** Whether the tools shipped with the Action, i.e. those in `defaults.json`, have been forced. */
|
|
||||||
const forceShippedTools = forceShippedToolsReason !== undefined;
|
|
||||||
if (forceShippedTools) {
|
if (forceShippedTools) {
|
||||||
logger.info("Overriding the version of the CodeQL tools by the version shipped with the Action since " +
|
logger.info("Overriding the version of the CodeQL tools by the version shipped with the Action since " +
|
||||||
`${forceShippedToolsReason}.`);
|
`"tools: latest" was requested.`);
|
||||||
}
|
}
|
||||||
/** CLI version number, for example 2.12.1. */
|
/** CLI version number, for example 2.12.1. */
|
||||||
let cliVersion;
|
let cliVersion;
|
||||||
@@ -530,15 +523,14 @@ exports.getCodeQLURLVersion = getCodeQLURLVersion;
|
|||||||
* @param apiDetails
|
* @param apiDetails
|
||||||
* @param tempDir
|
* @param tempDir
|
||||||
* @param variant
|
* @param variant
|
||||||
* @param bypassToolcache
|
|
||||||
* @param defaultCliVersion
|
* @param defaultCliVersion
|
||||||
* @param logger
|
* @param logger
|
||||||
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
||||||
* version requirement. Must be set to true outside tests.
|
* version requirement. Must be set to true outside tests.
|
||||||
* @returns the path to the extracted bundle, and the version of the tools
|
* @returns the path to the extracted bundle, and the version of the tools
|
||||||
*/
|
*/
|
||||||
async function setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, bypassToolcache, defaultCliVersion, logger) {
|
async function setupCodeQLBundle(toolsInput, apiDetails, tempDir, variant, defaultCliVersion, logger) {
|
||||||
const source = await getCodeQLSource(toolsInput, bypassToolcache, defaultCliVersion, apiDetails, variant, logger);
|
const source = await getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, variant, logger);
|
||||||
let codeqlFolder;
|
let codeqlFolder;
|
||||||
let toolsVersion = source.toolsVersion;
|
let toolsVersion = source.toolsVersion;
|
||||||
let toolsDownloadDurationMs;
|
let toolsDownloadDurationMs;
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+5
-2
@@ -293,7 +293,8 @@ async function waitForProcessing(repositoryNwo, sarifID, logger, options = {
|
|||||||
if (Date.now() >
|
if (Date.now() >
|
||||||
statusCheckingStarted + STATUS_CHECK_TIMEOUT_MILLISECONDS) {
|
statusCheckingStarted + STATUS_CHECK_TIMEOUT_MILLISECONDS) {
|
||||||
// If the analysis hasn't finished processing in the allotted time, we continue anyway rather than failing.
|
// If the analysis hasn't finished processing in the allotted time, we continue anyway rather than failing.
|
||||||
// It's possible the analysis will eventually finish processing, but it's not worth spending more Actions time waiting.
|
// It's possible the analysis will eventually finish processing, but it's not worth spending more
|
||||||
|
// Actions time waiting.
|
||||||
logger.warning("Timed out waiting for analysis to finish processing. Continuing.");
|
logger.warning("Timed out waiting for analysis to finish processing. Continuing.");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -329,7 +330,9 @@ async function waitForProcessing(repositoryNwo, sarifID, logger, options = {
|
|||||||
else {
|
else {
|
||||||
util.assertNever(status);
|
util.assertNever(status);
|
||||||
}
|
}
|
||||||
await util.delay(STATUS_CHECK_FREQUENCY_MILLISECONDS);
|
await util.delay(STATUS_CHECK_FREQUENCY_MILLISECONDS, {
|
||||||
|
allowProcessExit: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Generated
+24
-47
@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|||||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.parseMatrixInput = exports.shouldBypassToolcache = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.enrichEnvironment = exports.initializeEnvironment = exports.EnvVar = exports.assertNever = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DID_AUTOBUILD_GO_ENV_VAR_NAME = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
exports.parseMatrixInput = exports.isHostedRunner = exports.checkForTimeout = exports.withTimeout = exports.tryGetFolderBytes = exports.listFolder = exports.doesDirectoryExist = exports.logCodeScanningConfigInCli = exports.useCodeScanningConfigInCli = exports.isInTestMode = exports.getMlPoweredJsQueriesStatus = exports.getMlPoweredJsQueriesPack = exports.ML_POWERED_JS_QUERIES_PACK_NAME = exports.supportExpectDiscardedCache = exports.isGoodVersion = exports.delay = exports.bundleDb = exports.codeQlVersionAbove = exports.getCachedCodeQlVersion = exports.cacheCodeQlVersion = exports.isHTTPError = exports.UserError = exports.HTTPError = exports.getRequiredEnvParam = exports.enrichEnvironment = exports.initializeEnvironment = exports.EnvVar = exports.assertNever = exports.apiVersionInRange = exports.DisallowedAPIVersionReason = exports.checkGitHubVersionInRange = exports.getGitHubVersion = exports.GitHubVariant = exports.parseGitHubUrl = exports.getCodeQLDatabasePath = exports.getThreadsFlag = exports.getThreadsFlagValue = exports.getAddSnippetsFlag = exports.getMemoryFlag = exports.getMemoryFlagValue = exports.withTmpDir = exports.getToolNames = exports.getExtraOptionsEnvParam = exports.DID_AUTOBUILD_GO_ENV_VAR_NAME = exports.DEFAULT_DEBUG_DATABASE_NAME = exports.DEFAULT_DEBUG_ARTIFACT_NAME = exports.GITHUB_DOTCOM_URL = void 0;
|
||||||
const fs = __importStar(require("fs"));
|
const fs = __importStar(require("fs"));
|
||||||
const os = __importStar(require("os"));
|
const os = __importStar(require("os"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
@@ -40,7 +40,6 @@ const apiCompatibility = __importStar(require("./api-compatibility.json"));
|
|||||||
const codeql_1 = require("./codeql");
|
const codeql_1 = require("./codeql");
|
||||||
const config_utils_1 = require("./config-utils");
|
const config_utils_1 = require("./config-utils");
|
||||||
const feature_flags_1 = require("./feature-flags");
|
const feature_flags_1 = require("./feature-flags");
|
||||||
const languages_1 = require("./languages");
|
|
||||||
const shared_environment_1 = require("./shared-environment");
|
const shared_environment_1 = require("./shared-environment");
|
||||||
/**
|
/**
|
||||||
* Specifies bundle versions that are known to be broken
|
* Specifies bundle versions that are known to be broken
|
||||||
@@ -456,16 +455,33 @@ async function bundleDb(config, language, codeql, dbName) {
|
|||||||
return databaseBundlePath;
|
return databaseBundlePath;
|
||||||
}
|
}
|
||||||
exports.bundleDb = bundleDb;
|
exports.bundleDb = bundleDb;
|
||||||
async function delay(milliseconds) {
|
/**
|
||||||
// Immediately `unref` the timer such that it only prevents the process from exiting if the
|
* @param milliseconds time to delay
|
||||||
// surrounding promise is being awaited.
|
* @param opts options
|
||||||
return new Promise((resolve) => setTimeout(resolve, milliseconds).unref());
|
* @param opts.allowProcessExit if true, the timer will not prevent the process from exiting
|
||||||
|
*/
|
||||||
|
async function delay(milliseconds, { allowProcessExit }) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const timer = setTimeout(resolve, milliseconds);
|
||||||
|
if (allowProcessExit) {
|
||||||
|
// Immediately `unref` the timer such that it only prevents the process from exiting if the
|
||||||
|
// surrounding promise is being awaited.
|
||||||
|
timer.unref();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
exports.delay = delay;
|
exports.delay = delay;
|
||||||
function isGoodVersion(versionSpec) {
|
function isGoodVersion(versionSpec) {
|
||||||
return !BROKEN_VERSIONS.includes(versionSpec);
|
return !BROKEN_VERSIONS.includes(versionSpec);
|
||||||
}
|
}
|
||||||
exports.isGoodVersion = isGoodVersion;
|
exports.isGoodVersion = isGoodVersion;
|
||||||
|
/**
|
||||||
|
* Checks whether the CodeQL CLI supports the `--expect-discarded-cache` command-line flag.
|
||||||
|
*/
|
||||||
|
async function supportExpectDiscardedCache(codeQL) {
|
||||||
|
return codeQlVersionAbove(codeQL, "2.12.1");
|
||||||
|
}
|
||||||
|
exports.supportExpectDiscardedCache = supportExpectDiscardedCache;
|
||||||
exports.ML_POWERED_JS_QUERIES_PACK_NAME = "codeql/javascript-experimental-atm-queries";
|
exports.ML_POWERED_JS_QUERIES_PACK_NAME = "codeql/javascript-experimental-atm-queries";
|
||||||
/**
|
/**
|
||||||
* Gets the ML-powered JS query pack to add to the analysis if a repo is opted into the ML-powered
|
* Gets the ML-powered JS query pack to add to the analysis if a repo is opted into the ML-powered
|
||||||
@@ -637,7 +653,7 @@ async function withTimeout(timeoutMs, promise, onTimeout) {
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
const timeoutTask = async () => {
|
const timeoutTask = async () => {
|
||||||
await delay(timeoutMs);
|
await delay(timeoutMs, { allowProcessExit: true });
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
// Workaround: While the promise racing below will allow the main code
|
// Workaround: While the promise racing below will allow the main code
|
||||||
// to continue, the process won't normally exit until the asynchronous
|
// to continue, the process won't normally exit until the asynchronous
|
||||||
@@ -660,7 +676,7 @@ exports.withTimeout = withTimeout;
|
|||||||
async function checkForTimeout() {
|
async function checkForTimeout() {
|
||||||
if (hadTimeout === true) {
|
if (hadTimeout === true) {
|
||||||
core.info("A timeout occurred, force exiting the process after 30 seconds to prevent hanging.");
|
core.info("A timeout occurred, force exiting the process after 30 seconds to prevent hanging.");
|
||||||
await delay(30000);
|
await delay(30000, { allowProcessExit: true });
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -685,45 +701,6 @@ function isHostedRunner() {
|
|||||||
process.env["RUNNER_TOOL_CACHE"]?.includes("hostedtoolcache"));
|
process.env["RUNNER_TOOL_CACHE"]?.includes("hostedtoolcache"));
|
||||||
}
|
}
|
||||||
exports.isHostedRunner = isHostedRunner;
|
exports.isHostedRunner = isHostedRunner;
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param featuresEnablement The features enabled for the current run
|
|
||||||
* @param languagesInput Languages input from the workflow
|
|
||||||
* @param repository The owner/name of the repository
|
|
||||||
* @param logger A logger
|
|
||||||
* @returns A boolean indicating whether or not the toolcache should be bypassed and the latest codeql should be downloaded.
|
|
||||||
*/
|
|
||||||
async function shouldBypassToolcache(featuresEnablement, codeqlUrl, languagesInput, repository, logger) {
|
|
||||||
// An explicit codeql url is specified, that means the toolcache will not be used.
|
|
||||||
if (codeqlUrl) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Check if the toolcache is disabled for all languages
|
|
||||||
if (await featuresEnablement.getValue(feature_flags_1.Feature.BypassToolcacheEnabled)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
// Check if the toolcache is disabled for kotlin and swift.
|
|
||||||
if (!(await featuresEnablement.getValue(feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled))) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Now check to see if kotlin or swift is one of the languages being analyzed.
|
|
||||||
const { rawLanguages, autodetected } = await (0, config_utils_1.getRawLanguages)(languagesInput, repository, logger);
|
|
||||||
let bypass = rawLanguages.some((lang) => languages_1.KOTLIN_SWIFT_BYPASS.includes(lang));
|
|
||||||
if (bypass) {
|
|
||||||
logger.info(`Bypassing toolcache for kotlin or swift. Languages: ${rawLanguages}`);
|
|
||||||
}
|
|
||||||
else if (!autodetected && rawLanguages.includes(languages_1.Language.java)) {
|
|
||||||
// special case: java was explicitly specified, but there might be
|
|
||||||
// some kotlin in the repository, so we need to make a request for that.
|
|
||||||
const langsInRepo = await (0, config_utils_1.getLanguagesInRepo)(repository, logger);
|
|
||||||
if (langsInRepo.includes("kotlin")) {
|
|
||||||
logger.info(`Bypassing toolcache for kotlin.`);
|
|
||||||
bypass = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bypass;
|
|
||||||
}
|
|
||||||
exports.shouldBypassToolcache = shouldBypassToolcache;
|
|
||||||
function parseMatrixInput(matrixInput) {
|
function parseMatrixInput(matrixInput) {
|
||||||
if (matrixInput === undefined || matrixInput === "null") {
|
if (matrixInput === undefined || matrixInput === "null") {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
Generated
-115
@@ -33,9 +33,7 @@ const github = __importStar(require("@actions/github"));
|
|||||||
const ava_1 = __importDefault(require("ava"));
|
const ava_1 = __importDefault(require("ava"));
|
||||||
const sinon = __importStar(require("sinon"));
|
const sinon = __importStar(require("sinon"));
|
||||||
const api = __importStar(require("./api-client"));
|
const api = __importStar(require("./api-client"));
|
||||||
const feature_flags_1 = require("./feature-flags");
|
|
||||||
const logging_1 = require("./logging");
|
const logging_1 = require("./logging");
|
||||||
const repository_1 = require("./repository");
|
|
||||||
const testing_utils_1 = require("./testing-utils");
|
const testing_utils_1 = require("./testing-utils");
|
||||||
const util = __importStar(require("./util"));
|
const util = __importStar(require("./util"));
|
||||||
(0, testing_utils_1.setupTests)(ava_1.default);
|
(0, testing_utils_1.setupTests)(ava_1.default);
|
||||||
@@ -325,117 +323,4 @@ const shortTime = 10;
|
|||||||
t.deepEqual(shortTaskTimedOut, false);
|
t.deepEqual(shortTaskTimedOut, false);
|
||||||
t.deepEqual(result, 99);
|
t.deepEqual(result, 99);
|
||||||
});
|
});
|
||||||
const mockRepositoryNwo = (0, repository_1.parseRepositoryNwo)("owner/repo");
|
|
||||||
// eslint-disable-next-line github/array-foreach
|
|
||||||
[
|
|
||||||
{
|
|
||||||
name: "disabled",
|
|
||||||
features: [],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "disabled even though swift kotlin bypassed",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "disabled even though swift kotlin analyzed",
|
|
||||||
features: [],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: " sWiFt , KoTlIn ",
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "toolcache bypass all",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "custom CodeQL",
|
|
||||||
features: [],
|
|
||||||
hasCustomCodeQL: true,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass swift",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: " sWiFt ,other",
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass kotlin",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "other, KoTlIn ",
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass kotlin language from repository",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "",
|
|
||||||
languagesInRepository: ["KoTlIn", "other"],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass swift language from repository",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "",
|
|
||||||
languagesInRepository: ["SwiFt", "other"],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass java from input if there is kotlin in repository",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "java",
|
|
||||||
languagesInRepository: ["kotlin", "other"],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "don't bypass java from input if there is no kotlin in repository",
|
|
||||||
features: [feature_flags_1.Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "java",
|
|
||||||
languagesInRepository: ["java", "other"],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
].forEach((args) => {
|
|
||||||
(0, ava_1.default)(`shouldBypassToolcache: ${args.name}`, async (t) => {
|
|
||||||
const mockRequest = (0, testing_utils_1.mockLanguagesInRepo)(args.languagesInRepository);
|
|
||||||
const mockLogger = (0, logging_1.getRunnerLogger)(true);
|
|
||||||
const featureEnablement = (0, testing_utils_1.createFeatures)(args.features);
|
|
||||||
const codeqlUrl = args.hasCustomCodeQL ? "custom-codeql-url" : undefined;
|
|
||||||
const actual = await util.shouldBypassToolcache(featureEnablement, codeqlUrl, args.languagesInput, mockRepositoryNwo, mockLogger);
|
|
||||||
t.deepEqual(actual, args.expected);
|
|
||||||
t.deepEqual(mockRequest.called, args.expectedApiCall);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
//# sourceMappingURL=util.test.js.map
|
//# sourceMappingURL=util.test.js.map
|
||||||
File diff suppressed because one or more lines are too long
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "2.2.2",
|
"version": "2.2.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "2.2.2",
|
"version": "2.2.6",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "2.2.2",
|
"version": "2.2.6",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^1.1.0",
|
"@actions/artifact": "^1.1.0",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "2.2.2",
|
"version": "2.2.6",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "CodeQL action",
|
"description": "CodeQL action",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@@ -4,7 +4,12 @@
|
|||||||
# basic mechanics of multi-registry auth is working.
|
# basic mechanics of multi-registry auth is working.
|
||||||
name: "Packaging: Download using registries"
|
name: "Packaging: Download using registries"
|
||||||
description: "Checks that specifying a registries block and associated auth works as expected"
|
description: "Checks that specifying a registries block and associated auth works as expected"
|
||||||
versions: ["nightly-latest"] # This feature is not compatible with old CLIs
|
versions: [
|
||||||
|
# This feature is not compatible with older CLIs
|
||||||
|
"cached",
|
||||||
|
"latest",
|
||||||
|
"nightly-latest",
|
||||||
|
]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Init with registries
|
- name: Init with registries
|
||||||
@@ -40,3 +45,33 @@ steps:
|
|||||||
echo "::error $CODEQL_PACK1 pack was not installed."
|
echo "::error $CODEQL_PACK1 pack was not installed."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
- name: Verify qlconfig.yml file was created
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
QLCONFIG_PATH=$RUNNER_TEMP/qlconfig.yml
|
||||||
|
echo "Expected qlconfig.yml file to be created at $QLCONFIG_PATH"
|
||||||
|
if [[ -f $QLCONFIG_PATH ]]
|
||||||
|
then
|
||||||
|
echo "qlconfig.yml file was created."
|
||||||
|
else
|
||||||
|
echo "::error qlconfig.yml file was not created."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Verify contents of qlconfig.yml
|
||||||
|
# yq is not available on windows
|
||||||
|
if: runner.os != 'Windows'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
QLCONFIG_PATH=$RUNNER_TEMP/qlconfig.yml
|
||||||
|
cat $QLCONFIG_PATH | yq -e '.registries[] | select(.url == "https://ghcr.io/v2/") | select(.packages == "*/*")'
|
||||||
|
if [[ $? -eq 0 ]]
|
||||||
|
then
|
||||||
|
echo "Registry was added to qlconfig.yml file."
|
||||||
|
else
|
||||||
|
echo "::error Registry was not added to qlconfig.yml file."
|
||||||
|
echo "Contents of qlconfig.yml file:"
|
||||||
|
cat $QLCONFIG_PATH
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|||||||
+174
-2
@@ -3,15 +3,18 @@ import * as path from "path";
|
|||||||
|
|
||||||
import test, { ExecutionContext } from "ava";
|
import test, { ExecutionContext } from "ava";
|
||||||
import * as yaml from "js-yaml";
|
import * as yaml from "js-yaml";
|
||||||
|
import * as sinon from "sinon";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
convertPackToQuerySuiteEntry,
|
convertPackToQuerySuiteEntry,
|
||||||
createQuerySuiteContents,
|
createQuerySuiteContents,
|
||||||
runQueries,
|
runQueries,
|
||||||
validateQueryFilters,
|
validateQueryFilters,
|
||||||
|
QueriesStatusReport,
|
||||||
} from "./analyze";
|
} from "./analyze";
|
||||||
import { setCodeQL } from "./codeql";
|
import { CodeQL, setCodeQL } from "./codeql";
|
||||||
import { Config } from "./config-utils";
|
import { Config, QueriesWithSearchPath } from "./config-utils";
|
||||||
|
import { Feature } from "./feature-flags";
|
||||||
import { Language } from "./languages";
|
import { Language } from "./languages";
|
||||||
import { getRunnerLogger } from "./logging";
|
import { getRunnerLogger } from "./logging";
|
||||||
import { setupTests, setupActionsVars, createFeatures } from "./testing-utils";
|
import { setupTests, setupActionsVars, createFeatures } from "./testing-utils";
|
||||||
@@ -229,6 +232,175 @@ test("status report fields and search path setting", async (t) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function mockCodeQL(): Partial<CodeQL> {
|
||||||
|
return {
|
||||||
|
getVersion: async () => "2.12.2",
|
||||||
|
databaseRunQueries: sinon.spy(),
|
||||||
|
databaseInterpretResults: async () => "",
|
||||||
|
databasePrintBaseline: async () => "",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createBaseConfig(tmpDir: string): Config {
|
||||||
|
return {
|
||||||
|
languages: [],
|
||||||
|
queries: {},
|
||||||
|
pathsIgnore: [],
|
||||||
|
paths: [],
|
||||||
|
originalUserInput: {},
|
||||||
|
tempDir: "tempDir",
|
||||||
|
codeQLCmd: "",
|
||||||
|
gitHubVersion: {
|
||||||
|
type: util.GitHubVariant.DOTCOM,
|
||||||
|
} as util.GitHubVersion,
|
||||||
|
dbLocation: path.resolve(tmpDir, "codeql_databases"),
|
||||||
|
packs: {},
|
||||||
|
debugMode: false,
|
||||||
|
debugArtifactName: util.DEFAULT_DEBUG_ARTIFACT_NAME,
|
||||||
|
debugDatabaseName: util.DEFAULT_DEBUG_DATABASE_NAME,
|
||||||
|
augmentationProperties: {
|
||||||
|
injectedMlQueries: false,
|
||||||
|
packsInputCombines: false,
|
||||||
|
queriesInputCombines: false,
|
||||||
|
},
|
||||||
|
trapCaches: {},
|
||||||
|
trapCacheDownloadTime: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function createQueryConfig(
|
||||||
|
builtin: string[],
|
||||||
|
custom: string[]
|
||||||
|
): { builtin: string[]; custom: QueriesWithSearchPath[] } {
|
||||||
|
return {
|
||||||
|
builtin,
|
||||||
|
custom: custom.map((c) => ({ searchPath: "/search", queries: [c] })),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runQueriesWithConfig(
|
||||||
|
config: Config,
|
||||||
|
features: Feature[]
|
||||||
|
): Promise<QueriesStatusReport> {
|
||||||
|
for (const language of config.languages) {
|
||||||
|
fs.mkdirSync(util.getCodeQLDatabasePath(config, language), {
|
||||||
|
recursive: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return runQueries(
|
||||||
|
"sarif-folder",
|
||||||
|
"--memFlag",
|
||||||
|
"--addSnippetsFlag",
|
||||||
|
"--threadsFlag",
|
||||||
|
undefined,
|
||||||
|
config,
|
||||||
|
getRunnerLogger(true),
|
||||||
|
createFeatures(features)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getDatabaseRunQueriesCalls(mock: Partial<CodeQL>) {
|
||||||
|
return (mock.databaseRunQueries as sinon.SinonSpy).getCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
test("optimizeForLastQueryRun for one language", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
setCodeQL(codeql);
|
||||||
|
const config: Config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [Language.cpp];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||||
|
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(
|
||||||
|
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||||
|
[true]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("optimizeForLastQueryRun for two languages", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
setCodeQL(codeql);
|
||||||
|
const config: Config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [Language.cpp, Language.java];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], []);
|
||||||
|
config.queries.java = createQueryConfig(["bar.ql"], []);
|
||||||
|
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(
|
||||||
|
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||||
|
[true, true]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("optimizeForLastQueryRun for two languages, with custom queries", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
setCodeQL(codeql);
|
||||||
|
const config: Config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [Language.cpp, Language.java];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||||
|
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||||
|
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(
|
||||||
|
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||||
|
[false, false, true, false, true]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("optimizeForLastQueryRun for two languages, with custom queries and packs", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
setCodeQL(codeql);
|
||||||
|
const config: Config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [Language.cpp, Language.java];
|
||||||
|
config.queries.cpp = createQueryConfig(["foo.ql"], ["c1.ql", "c2.ql"]);
|
||||||
|
config.queries.java = createQueryConfig(["bar.ql"], ["c3.ql"]);
|
||||||
|
config.packs.cpp = ["a/cpp-pack1@0.1.0"];
|
||||||
|
config.packs.java = ["b/java-pack1@0.2.0", "b/java-pack2@0.3.3"];
|
||||||
|
await runQueriesWithConfig(config, []);
|
||||||
|
t.deepEqual(
|
||||||
|
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||||
|
[false, false, false, true, false, false, true]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("optimizeForLastQueryRun for one language, CliConfigFileEnabled", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
setCodeQL(codeql);
|
||||||
|
const config: Config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [Language.cpp];
|
||||||
|
|
||||||
|
await runQueriesWithConfig(config, [Feature.CliConfigFileEnabled]);
|
||||||
|
t.deepEqual(
|
||||||
|
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||||
|
[true]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("optimizeForLastQueryRun for two languages, CliConfigFileEnabled", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const codeql = mockCodeQL();
|
||||||
|
setCodeQL(codeql);
|
||||||
|
const config: Config = createBaseConfig(tmpDir);
|
||||||
|
config.languages = [Language.cpp, Language.java];
|
||||||
|
|
||||||
|
await runQueriesWithConfig(config, [Feature.CliConfigFileEnabled]);
|
||||||
|
t.deepEqual(
|
||||||
|
getDatabaseRunQueriesCalls(codeql).map((c) => c.args[4]),
|
||||||
|
[true, true]
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
test("validateQueryFilters", (t) => {
|
test("validateQueryFilters", (t) => {
|
||||||
t.notThrows(() => validateQueryFilters([]));
|
t.notThrows(() => validateQueryFilters([]));
|
||||||
t.notThrows(() => validateQueryFilters(undefined));
|
t.notThrows(() => validateQueryFilters(undefined));
|
||||||
|
|||||||
+35
-26
@@ -212,6 +212,7 @@ export async function runQueries(
|
|||||||
const statusReport: QueriesStatusReport = {};
|
const statusReport: QueriesStatusReport = {};
|
||||||
|
|
||||||
const codeql = await getCodeQL(config.codeQLCmd);
|
const codeql = await getCodeQL(config.codeQLCmd);
|
||||||
|
const queryFlags = [memoryFlag, threadsFlag];
|
||||||
|
|
||||||
await util.logCodeScanningConfigInCli(codeql, featureEnablement, logger);
|
await util.logCodeScanningConfigInCli(codeql, featureEnablement, logger);
|
||||||
|
|
||||||
@@ -231,7 +232,7 @@ export async function runQueries(
|
|||||||
// another to interpret the results.
|
// another to interpret the results.
|
||||||
logger.startGroup(`Running queries for ${language}`);
|
logger.startGroup(`Running queries for ${language}`);
|
||||||
const startTimeBuiltIn = new Date().getTime();
|
const startTimeBuiltIn = new Date().getTime();
|
||||||
await runQueryGroup(language, "all", undefined, undefined);
|
await runQueryGroup(language, "all", undefined, undefined, true);
|
||||||
// TODO should not be using `builtin` here. We should be using `all` instead.
|
// TODO should not be using `builtin` here. We should be using `all` instead.
|
||||||
// The status report does not support `all` yet.
|
// The status report does not support `all` yet.
|
||||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||||
@@ -267,16 +268,24 @@ export async function runQueries(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const customQueryIndices: number[] = [];
|
||||||
|
for (let i = 0; i < queries.custom.length; ++i) {
|
||||||
|
if (queries.custom[i].queries.length > 0) {
|
||||||
|
customQueryIndices.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
logger.startGroup(`Running queries for ${language}`);
|
logger.startGroup(`Running queries for ${language}`);
|
||||||
const querySuitePaths: string[] = [];
|
const querySuitePaths: string[] = [];
|
||||||
if (queries["builtin"].length > 0) {
|
if (queries.builtin.length > 0) {
|
||||||
const startTimeBuiltIn = new Date().getTime();
|
const startTimeBuiltIn = new Date().getTime();
|
||||||
querySuitePaths.push(
|
querySuitePaths.push(
|
||||||
(await runQueryGroup(
|
(await runQueryGroup(
|
||||||
language,
|
language,
|
||||||
"builtin",
|
"builtin",
|
||||||
createQuerySuiteContents(queries["builtin"], queryFilters),
|
createQuerySuiteContents(queries.builtin, queryFilters),
|
||||||
undefined
|
undefined,
|
||||||
|
customQueryIndices.length === 0 && packsWithVersion.length === 0
|
||||||
)) as string
|
)) as string
|
||||||
);
|
);
|
||||||
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
statusReport[`analyze_builtin_queries_${language}_duration_ms`] =
|
||||||
@@ -284,21 +293,18 @@ export async function runQueries(
|
|||||||
}
|
}
|
||||||
const startTimeCustom = new Date().getTime();
|
const startTimeCustom = new Date().getTime();
|
||||||
let ranCustom = false;
|
let ranCustom = false;
|
||||||
for (let i = 0; i < queries["custom"].length; ++i) {
|
for (const i of customQueryIndices) {
|
||||||
if (queries["custom"][i].queries.length > 0) {
|
querySuitePaths.push(
|
||||||
querySuitePaths.push(
|
(await runQueryGroup(
|
||||||
(await runQueryGroup(
|
language,
|
||||||
language,
|
`custom-${i}`,
|
||||||
`custom-${i}`,
|
createQuerySuiteContents(queries.custom[i].queries, queryFilters),
|
||||||
createQuerySuiteContents(
|
queries.custom[i].searchPath,
|
||||||
queries["custom"][i].queries,
|
i === customQueryIndices[customQueryIndices.length - 1] &&
|
||||||
queryFilters
|
packsWithVersion.length === 0
|
||||||
),
|
)) as string
|
||||||
queries["custom"][i].searchPath
|
);
|
||||||
)) as string
|
ranCustom = true;
|
||||||
);
|
|
||||||
ranCustom = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (packsWithVersion.length > 0) {
|
if (packsWithVersion.length > 0) {
|
||||||
querySuitePaths.push(
|
querySuitePaths.push(
|
||||||
@@ -306,7 +312,8 @@ export async function runQueries(
|
|||||||
language,
|
language,
|
||||||
"packs",
|
"packs",
|
||||||
packsWithVersion,
|
packsWithVersion,
|
||||||
queryFilters
|
queryFilters,
|
||||||
|
true
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
ranCustom = true;
|
ranCustom = true;
|
||||||
@@ -373,7 +380,8 @@ export async function runQueries(
|
|||||||
language: Language,
|
language: Language,
|
||||||
type: string,
|
type: string,
|
||||||
querySuiteContents: string | undefined,
|
querySuiteContents: string | undefined,
|
||||||
searchPath: string | undefined
|
searchPath: string | undefined,
|
||||||
|
optimizeForLastQueryRun: boolean
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||||
// Pass the queries to codeql using a file instead of using the command
|
// Pass the queries to codeql using a file instead of using the command
|
||||||
@@ -391,8 +399,8 @@ export async function runQueries(
|
|||||||
databasePath,
|
databasePath,
|
||||||
searchPath,
|
searchPath,
|
||||||
querySuitePath,
|
querySuitePath,
|
||||||
memoryFlag,
|
queryFlags,
|
||||||
threadsFlag
|
optimizeForLastQueryRun
|
||||||
);
|
);
|
||||||
|
|
||||||
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
logger.debug(`BQRS results produced for ${language} (queries: ${type})"`);
|
||||||
@@ -402,7 +410,8 @@ export async function runQueries(
|
|||||||
language: Language,
|
language: Language,
|
||||||
type: string,
|
type: string,
|
||||||
packs: string[],
|
packs: string[],
|
||||||
queryFilters: configUtils.QueryFilter[]
|
queryFilters: configUtils.QueryFilter[],
|
||||||
|
optimizeForLastQueryRun: boolean
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
const databasePath = util.getCodeQLDatabasePath(config, language);
|
const databasePath = util.getCodeQLDatabasePath(config, language);
|
||||||
|
|
||||||
@@ -424,8 +433,8 @@ export async function runQueries(
|
|||||||
databasePath,
|
databasePath,
|
||||||
undefined,
|
undefined,
|
||||||
querySuitePath,
|
querySuitePath,
|
||||||
memoryFlag,
|
queryFlags,
|
||||||
threadsFlag
|
optimizeForLastQueryRun
|
||||||
);
|
);
|
||||||
|
|
||||||
return querySuitePath;
|
return querySuitePath;
|
||||||
|
|||||||
+84
-36
@@ -143,7 +143,6 @@ async function installIntoToolcache({
|
|||||||
apiDetails,
|
apiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.GHES,
|
util.GitHubVariant.GHES,
|
||||||
false,
|
|
||||||
cliVersion !== undefined
|
cliVersion !== undefined
|
||||||
? { cliVersion, tagName, variant: util.GitHubVariant.GHES }
|
? { cliVersion, tagName, variant: util.GitHubVariant.GHES }
|
||||||
: SAMPLE_DEFAULT_CLI_VERSION,
|
: SAMPLE_DEFAULT_CLI_VERSION,
|
||||||
@@ -205,7 +204,6 @@ test("downloads and caches explicitly requested bundles that aren't in the toolc
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.DOTCOM,
|
util.GitHubVariant.DOTCOM,
|
||||||
false,
|
|
||||||
SAMPLE_DEFAULT_CLI_VERSION,
|
SAMPLE_DEFAULT_CLI_VERSION,
|
||||||
getRunnerLogger(true),
|
getRunnerLogger(true),
|
||||||
false
|
false
|
||||||
@@ -239,7 +237,6 @@ test("downloads an explicitly requested bundle even if a different version is ca
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.DOTCOM,
|
util.GitHubVariant.DOTCOM,
|
||||||
false,
|
|
||||||
SAMPLE_DEFAULT_CLI_VERSION,
|
SAMPLE_DEFAULT_CLI_VERSION,
|
||||||
getRunnerLogger(true),
|
getRunnerLogger(true),
|
||||||
false
|
false
|
||||||
@@ -290,7 +287,6 @@ for (const {
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.DOTCOM,
|
util.GitHubVariant.DOTCOM,
|
||||||
false,
|
|
||||||
SAMPLE_DEFAULT_CLI_VERSION,
|
SAMPLE_DEFAULT_CLI_VERSION,
|
||||||
getRunnerLogger(true),
|
getRunnerLogger(true),
|
||||||
false
|
false
|
||||||
@@ -358,7 +354,6 @@ for (const { githubReleases, toolcacheVersion } of [
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.DOTCOM,
|
util.GitHubVariant.DOTCOM,
|
||||||
false,
|
|
||||||
SAMPLE_DEFAULT_CLI_VERSION,
|
SAMPLE_DEFAULT_CLI_VERSION,
|
||||||
getRunnerLogger(true),
|
getRunnerLogger(true),
|
||||||
false
|
false
|
||||||
@@ -387,7 +382,6 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
variant,
|
variant,
|
||||||
false,
|
|
||||||
{
|
{
|
||||||
cliVersion: defaults.cliVersion,
|
cliVersion: defaults.cliVersion,
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
@@ -423,7 +417,6 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
variant,
|
variant,
|
||||||
false,
|
|
||||||
{
|
{
|
||||||
cliVersion: defaults.cliVersion,
|
cliVersion: defaults.cliVersion,
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
@@ -460,7 +453,6 @@ test('downloads bundle if "latest" tools specified but not cached', async (t) =>
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.DOTCOM,
|
util.GitHubVariant.DOTCOM,
|
||||||
false,
|
|
||||||
SAMPLE_DEFAULT_CLI_VERSION,
|
SAMPLE_DEFAULT_CLI_VERSION,
|
||||||
getRunnerLogger(true),
|
getRunnerLogger(true),
|
||||||
false
|
false
|
||||||
@@ -533,7 +525,6 @@ for (const isBundleVersionInUrl of [true, false]) {
|
|||||||
sampleGHAEApiDetails,
|
sampleGHAEApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.GHAE,
|
util.GitHubVariant.GHAE,
|
||||||
false,
|
|
||||||
{
|
{
|
||||||
cliVersion: defaults.cliVersion,
|
cliVersion: defaults.cliVersion,
|
||||||
tagName: defaults.bundleVersion,
|
tagName: defaults.bundleVersion,
|
||||||
@@ -573,7 +564,6 @@ test("bundle URL from another repo is cached as 0.0.0-bundleVersion", async (t)
|
|||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
util.GitHubVariant.DOTCOM,
|
util.GitHubVariant.DOTCOM,
|
||||||
false,
|
|
||||||
SAMPLE_DEFAULT_CLI_VERSION,
|
SAMPLE_DEFAULT_CLI_VERSION,
|
||||||
getRunnerLogger(true),
|
getRunnerLogger(true),
|
||||||
false
|
false
|
||||||
@@ -681,6 +671,7 @@ test("databaseInitCluster() without injected codescanning config", async (t) =>
|
|||||||
"",
|
"",
|
||||||
undefined,
|
undefined,
|
||||||
createFeatures([]),
|
createFeatures([]),
|
||||||
|
"/path/to/qlconfig.yml",
|
||||||
getRunnerLogger(true)
|
getRunnerLogger(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -689,7 +680,7 @@ test("databaseInitCluster() without injected codescanning config", async (t) =>
|
|||||||
const configArg = args.find((arg: string) =>
|
const configArg = args.find((arg: string) =>
|
||||||
arg.startsWith("--codescanning-config=")
|
arg.startsWith("--codescanning-config=")
|
||||||
);
|
);
|
||||||
t.falsy(configArg, "Should have injected a codescanning config");
|
t.falsy(configArg, "Should NOT have injected a codescanning config");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -720,6 +711,7 @@ const injectedConfigMacro = test.macro({
|
|||||||
"",
|
"",
|
||||||
undefined,
|
undefined,
|
||||||
createFeatures([Feature.CliConfigFileEnabled]),
|
createFeatures([Feature.CliConfigFileEnabled]),
|
||||||
|
undefined,
|
||||||
getRunnerLogger(true)
|
getRunnerLogger(true)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -1010,34 +1002,90 @@ test(
|
|||||||
{}
|
{}
|
||||||
);
|
);
|
||||||
|
|
||||||
test("does not use injected config", async (t: ExecutionContext<unknown>) => {
|
test("does not pass a code scanning config or qlconfig file to the CLI when CLI config passing is disabled", async (t: ExecutionContext<unknown>) => {
|
||||||
const origCODEQL_PASS_CONFIG_TO_CLI = process.env.CODEQL_PASS_CONFIG_TO_CLI;
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
process.env["CODEQL_PASS_CONFIG_TO_CLI"] = "false";
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
// stubbed version doesn't matter. It just needs to be valid semver.
|
||||||
|
sinon.stub(codeqlObject, "getVersion").resolves("0.0.0");
|
||||||
|
|
||||||
try {
|
await codeqlObject.databaseInitCluster(
|
||||||
const runnerConstructorStub = stubToolRunnerConstructor();
|
stubConfig,
|
||||||
const codeqlObject = await codeql.getCodeQLForTesting();
|
"",
|
||||||
sinon
|
undefined,
|
||||||
.stub(codeqlObject, "getVersion")
|
createFeatures([]),
|
||||||
.resolves(featureConfig[Feature.CliConfigFileEnabled].minimumVersion);
|
"/path/to/qlconfig.yml",
|
||||||
|
getRunnerLogger(true)
|
||||||
|
);
|
||||||
|
|
||||||
await codeqlObject.databaseInitCluster(
|
const args = runnerConstructorStub.firstCall.args[1];
|
||||||
stubConfig,
|
// should not have used a config file
|
||||||
"",
|
const hasConfigArg = args.some((arg: string) =>
|
||||||
undefined,
|
arg.startsWith("--codescanning-config=")
|
||||||
createFeatures([]),
|
);
|
||||||
getRunnerLogger(true)
|
t.false(hasConfigArg, "Should NOT have injected a codescanning config");
|
||||||
);
|
|
||||||
|
|
||||||
const args = runnerConstructorStub.firstCall.args[1];
|
// should not have passed a qlconfig file
|
||||||
// should have used an config file
|
const hasQlconfigArg = args.some((arg: string) =>
|
||||||
const configArg = args.find((arg: string) =>
|
arg.startsWith("--qlconfig=")
|
||||||
arg.startsWith("--codescanning-config=")
|
);
|
||||||
);
|
t.false(hasQlconfigArg, "Should NOT have passed a qlconfig file");
|
||||||
t.falsy(configArg, "Should NOT have injected a codescanning config");
|
});
|
||||||
} finally {
|
|
||||||
process.env["CODEQL_PASS_CONFIG_TO_CLI"] = origCODEQL_PASS_CONFIG_TO_CLI;
|
test("passes a code scanning config AND qlconfig to the CLI when CLI config passing is enabled", async (t: ExecutionContext<unknown>) => {
|
||||||
}
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
sinon
|
||||||
|
.stub(codeqlObject, "getVersion")
|
||||||
|
.resolves(codeql.CODEQL_VERSION_INIT_WITH_QLCONFIG);
|
||||||
|
|
||||||
|
await codeqlObject.databaseInitCluster(
|
||||||
|
stubConfig,
|
||||||
|
"",
|
||||||
|
undefined,
|
||||||
|
createFeatures([Feature.CliConfigFileEnabled]),
|
||||||
|
"/path/to/qlconfig.yml",
|
||||||
|
getRunnerLogger(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
const args = runnerConstructorStub.firstCall.args[1];
|
||||||
|
// should have used a config file
|
||||||
|
const hasCodeScanningConfigArg = args.some((arg: string) =>
|
||||||
|
arg.startsWith("--codescanning-config=")
|
||||||
|
);
|
||||||
|
t.true(hasCodeScanningConfigArg, "Should have injected a qlconfig");
|
||||||
|
|
||||||
|
// should have passed a qlconfig file
|
||||||
|
const hasQlconfigArg = args.some((arg: string) =>
|
||||||
|
arg.startsWith("--qlconfig=")
|
||||||
|
);
|
||||||
|
t.truthy(hasQlconfigArg, "Should have injected a codescanning config");
|
||||||
|
});
|
||||||
|
test("passes a code scanning config BUT NOT a qlconfig to the CLI when CLI config passing is enabled", async (t: ExecutionContext<unknown>) => {
|
||||||
|
const runnerConstructorStub = stubToolRunnerConstructor();
|
||||||
|
const codeqlObject = await codeql.getCodeQLForTesting();
|
||||||
|
sinon.stub(codeqlObject, "getVersion").resolves("2.12.2");
|
||||||
|
|
||||||
|
await codeqlObject.databaseInitCluster(
|
||||||
|
stubConfig,
|
||||||
|
"",
|
||||||
|
undefined,
|
||||||
|
createFeatures([Feature.CliConfigFileEnabled]),
|
||||||
|
"/path/to/qlconfig.yml",
|
||||||
|
getRunnerLogger(true)
|
||||||
|
);
|
||||||
|
|
||||||
|
const args = runnerConstructorStub.firstCall.args[1] as any[];
|
||||||
|
// should have used a config file
|
||||||
|
const hasCodeScanningConfigArg = args.some((arg: string) =>
|
||||||
|
arg.startsWith("--codescanning-config=")
|
||||||
|
);
|
||||||
|
t.true(hasCodeScanningConfigArg, "Should NOT have injected a qlconfig");
|
||||||
|
|
||||||
|
// should have passed a qlconfig file
|
||||||
|
const hasQlconfigArg = args.some((arg: string) =>
|
||||||
|
arg.startsWith("--qlconfig=")
|
||||||
|
);
|
||||||
|
t.false(hasQlconfigArg, "Should have injected a codescanning config");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("databaseInterpretResults() sets --sarif-add-baseline-file-info for 2.11.3", async (t) => {
|
test("databaseInterpretResults() sets --sarif-add-baseline-file-info for 2.11.3", async (t) => {
|
||||||
|
|||||||
+47
-17
@@ -91,6 +91,7 @@ export interface CodeQL {
|
|||||||
sourceRoot: string,
|
sourceRoot: string,
|
||||||
processName: string | undefined,
|
processName: string | undefined,
|
||||||
featureEnablement: FeatureEnablement,
|
featureEnablement: FeatureEnablement,
|
||||||
|
qlconfigFile: string | undefined,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
/**
|
/**
|
||||||
@@ -148,13 +149,19 @@ export interface CodeQL {
|
|||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Run 'codeql database run-queries'.
|
* Run 'codeql database run-queries'.
|
||||||
|
*
|
||||||
|
* @param optimizeForLastQueryRun Whether to apply additional optimization for
|
||||||
|
* the last database query run in the action.
|
||||||
|
* It is always safe to set it to false.
|
||||||
|
* It should be set to true only for the very
|
||||||
|
* last databaseRunQueries() call.
|
||||||
*/
|
*/
|
||||||
databaseRunQueries(
|
databaseRunQueries(
|
||||||
databasePath: string,
|
databasePath: string,
|
||||||
extraSearchPath: string | undefined,
|
extraSearchPath: string | undefined,
|
||||||
querySuitePath: string | undefined,
|
querySuitePath: string | undefined,
|
||||||
memoryFlag: string,
|
flags: string[],
|
||||||
threadsFlag: string
|
optimizeForLastQueryRun: boolean
|
||||||
): Promise<void>;
|
): Promise<void>;
|
||||||
/**
|
/**
|
||||||
* Run 'codeql database interpret-results'.
|
* Run 'codeql database interpret-results'.
|
||||||
@@ -278,6 +285,16 @@ export const CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS = "2.9.0";
|
|||||||
*/
|
*/
|
||||||
export const CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
|
export const CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Versions 2.11.1+ of the CodeQL Bundle include a `security-experimental` built-in query suite for each language.
|
||||||
|
*/
|
||||||
|
export const CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE = "2.12.1";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Versions 2.12.4+ of the CodeQL CLI support the `--qlconfig` flag in calls to `database init`.
|
||||||
|
*/
|
||||||
|
export const CODEQL_VERSION_INIT_WITH_QLCONFIG = "2.12.4";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up CodeQL CLI access.
|
* Set up CodeQL CLI access.
|
||||||
*
|
*
|
||||||
@@ -285,7 +302,6 @@ export const CODEQL_VERSION_BETTER_RESOLVE_LANGUAGES = "2.10.3";
|
|||||||
* @param apiDetails
|
* @param apiDetails
|
||||||
* @param tempDir
|
* @param tempDir
|
||||||
* @param variant
|
* @param variant
|
||||||
* @param bypassToolcache
|
|
||||||
* @param defaultCliVersion
|
* @param defaultCliVersion
|
||||||
* @param logger
|
* @param logger
|
||||||
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
||||||
@@ -297,7 +313,6 @@ export async function setupCodeQL(
|
|||||||
apiDetails: api.GitHubApiDetails,
|
apiDetails: api.GitHubApiDetails,
|
||||||
tempDir: string,
|
tempDir: string,
|
||||||
variant: util.GitHubVariant,
|
variant: util.GitHubVariant,
|
||||||
bypassToolcache: boolean,
|
|
||||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
checkVersion: boolean
|
checkVersion: boolean
|
||||||
@@ -314,7 +329,6 @@ export async function setupCodeQL(
|
|||||||
apiDetails,
|
apiDetails,
|
||||||
tempDir,
|
tempDir,
|
||||||
variant,
|
variant,
|
||||||
bypassToolcache,
|
|
||||||
defaultCliVersion,
|
defaultCliVersion,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
@@ -557,6 +571,7 @@ export async function getCodeQLForCmd(
|
|||||||
sourceRoot: string,
|
sourceRoot: string,
|
||||||
processName: string | undefined,
|
processName: string | undefined,
|
||||||
featureEnablement: FeatureEnablement,
|
featureEnablement: FeatureEnablement,
|
||||||
|
qlconfigFile: string | undefined,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
) {
|
) {
|
||||||
const extraArgs = config.languages.map(
|
const extraArgs = config.languages.map(
|
||||||
@@ -586,8 +601,8 @@ export async function getCodeQLForCmd(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A config file is only generated if the CliConfigFileEnabled feature flag is enabled.
|
// A code scanning config file is only generated if the CliConfigFileEnabled feature flag is enabled.
|
||||||
const configLocation = await generateCodeScanningConfig(
|
const codeScanningConfigFile = await generateCodeScanningConfig(
|
||||||
codeql,
|
codeql,
|
||||||
config,
|
config,
|
||||||
featureEnablement,
|
featureEnablement,
|
||||||
@@ -595,14 +610,19 @@ export async function getCodeQLForCmd(
|
|||||||
);
|
);
|
||||||
// Only pass external repository token if a config file is going to be parsed by the CLI.
|
// Only pass external repository token if a config file is going to be parsed by the CLI.
|
||||||
let externalRepositoryToken: string | undefined;
|
let externalRepositoryToken: string | undefined;
|
||||||
if (configLocation) {
|
if (codeScanningConfigFile) {
|
||||||
extraArgs.push(`--codescanning-config=${configLocation}`);
|
|
||||||
externalRepositoryToken = getOptionalInput("external-repository-token");
|
externalRepositoryToken = getOptionalInput("external-repository-token");
|
||||||
|
extraArgs.push(`--codescanning-config=${codeScanningConfigFile}`);
|
||||||
if (externalRepositoryToken) {
|
if (externalRepositoryToken) {
|
||||||
extraArgs.push("--external-repository-token-stdin");
|
extraArgs.push("--external-repository-token-stdin");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
await util.codeQlVersionAbove(this, CODEQL_VERSION_INIT_WITH_QLCONFIG)
|
||||||
|
) {
|
||||||
|
extraArgs.push(`--qlconfig=${qlconfigFile}`);
|
||||||
|
}
|
||||||
await runTool(
|
await runTool(
|
||||||
cmd,
|
cmd,
|
||||||
[
|
[
|
||||||
@@ -787,19 +807,24 @@ export async function getCodeQLForCmd(
|
|||||||
databasePath: string,
|
databasePath: string,
|
||||||
extraSearchPath: string | undefined,
|
extraSearchPath: string | undefined,
|
||||||
querySuitePath: string | undefined,
|
querySuitePath: string | undefined,
|
||||||
memoryFlag: string,
|
flags: string[],
|
||||||
threadsFlag: string
|
optimizeForLastQueryRun: boolean
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const codeqlArgs = [
|
const codeqlArgs = [
|
||||||
"database",
|
"database",
|
||||||
"run-queries",
|
"run-queries",
|
||||||
memoryFlag,
|
...flags,
|
||||||
threadsFlag,
|
|
||||||
databasePath,
|
databasePath,
|
||||||
"--min-disk-free=1024", // Try to leave at least 1GB free
|
"--min-disk-free=1024", // Try to leave at least 1GB free
|
||||||
"-v",
|
"-v",
|
||||||
...getExtraOptionsFromEnv(["database", "run-queries"]),
|
...getExtraOptionsFromEnv(["database", "run-queries"]),
|
||||||
];
|
];
|
||||||
|
if (
|
||||||
|
optimizeForLastQueryRun &&
|
||||||
|
(await util.supportExpectDiscardedCache(this))
|
||||||
|
) {
|
||||||
|
codeqlArgs.push("--expect-discarded-cache");
|
||||||
|
}
|
||||||
if (extraSearchPath !== undefined) {
|
if (extraSearchPath !== undefined) {
|
||||||
codeqlArgs.push("--additional-packs", extraSearchPath);
|
codeqlArgs.push("--additional-packs", extraSearchPath);
|
||||||
}
|
}
|
||||||
@@ -1098,7 +1123,10 @@ async function generateCodeScanningConfig(
|
|||||||
if (!(await util.useCodeScanningConfigInCli(codeql, featureEnablement))) {
|
if (!(await util.useCodeScanningConfigInCli(codeql, featureEnablement))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const configLocation = path.resolve(config.tempDir, "user-config.yaml");
|
const codeScanningConfigFile = path.resolve(
|
||||||
|
config.tempDir,
|
||||||
|
"user-config.yaml"
|
||||||
|
);
|
||||||
// make a copy so we can modify it
|
// make a copy so we can modify it
|
||||||
const augmentedConfig = cloneObject(config.originalUserInput);
|
const augmentedConfig = cloneObject(config.originalUserInput);
|
||||||
|
|
||||||
@@ -1155,13 +1183,15 @@ async function generateCodeScanningConfig(
|
|||||||
augmentedConfig.packs["javascript"].push(packString);
|
augmentedConfig.packs["javascript"].push(packString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
logger.info(`Writing augmented user configuration file to ${configLocation}`);
|
logger.info(
|
||||||
|
`Writing augmented user configuration file to ${codeScanningConfigFile}`
|
||||||
|
);
|
||||||
logger.startGroup("Augmented user configuration file contents");
|
logger.startGroup("Augmented user configuration file contents");
|
||||||
logger.info(yaml.dump(augmentedConfig));
|
logger.info(yaml.dump(augmentedConfig));
|
||||||
logger.endGroup();
|
logger.endGroup();
|
||||||
|
|
||||||
fs.writeFileSync(configLocation, yaml.dump(augmentedConfig));
|
fs.writeFileSync(codeScanningConfigFile, yaml.dump(augmentedConfig));
|
||||||
return configLocation;
|
return codeScanningConfigFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
function cloneObject<T>(obj: T): T {
|
function cloneObject<T>(obj: T): T {
|
||||||
|
|||||||
+111
-16
@@ -7,9 +7,13 @@ import * as yaml from "js-yaml";
|
|||||||
import * as sinon from "sinon";
|
import * as sinon from "sinon";
|
||||||
|
|
||||||
import * as api from "./api-client";
|
import * as api from "./api-client";
|
||||||
import { getCachedCodeQL, PackDownloadOutput, setCodeQL } from "./codeql";
|
import {
|
||||||
|
CODEQL_VERSION_GHES_PACK_DOWNLOAD,
|
||||||
|
getCachedCodeQL,
|
||||||
|
PackDownloadOutput,
|
||||||
|
setCodeQL,
|
||||||
|
} from "./codeql";
|
||||||
import * as configUtils from "./config-utils";
|
import * as configUtils from "./config-utils";
|
||||||
import { RegistryConfigWithCredentials } from "./config-utils";
|
|
||||||
import { Feature } from "./feature-flags";
|
import { Feature } from "./feature-flags";
|
||||||
import { Language } from "./languages";
|
import { Language } from "./languages";
|
||||||
import { getRunnerLogger, Logger } from "./logging";
|
import { getRunnerLogger, Logger } from "./logging";
|
||||||
@@ -1993,7 +1997,7 @@ test(
|
|||||||
process.platform === "win32" ? undefined : "~0.1.0"
|
process.platform === "win32" ? undefined : "~0.1.0"
|
||||||
);
|
);
|
||||||
// Test that ML-powered queries aren't run when the user hasn't specified that we should run the
|
// Test that ML-powered queries aren't run when the user hasn't specified that we should run the
|
||||||
// `security-extended` or `security-and-quality` query suite.
|
// `security-extended`, `security-and-quality`, or `security-experimental` query suite.
|
||||||
test(mlPoweredQueriesMacro, "2.7.5", true, undefined, undefined, undefined);
|
test(mlPoweredQueriesMacro, "2.7.5", true, undefined, undefined, undefined);
|
||||||
// Test that ML-powered queries are run on non-Windows platforms running `security-extended` on
|
// Test that ML-powered queries are run on non-Windows platforms running `security-extended` on
|
||||||
// versions of the CodeQL CLI prior to 2.9.0.
|
// versions of the CodeQL CLI prior to 2.9.0.
|
||||||
@@ -2074,7 +2078,6 @@ test(
|
|||||||
"security-extended",
|
"security-extended",
|
||||||
"~0.4.0"
|
"~0.4.0"
|
||||||
);
|
);
|
||||||
|
|
||||||
// Test that ML-powered queries are run on all platforms running `security-and-quality` on CodeQL
|
// Test that ML-powered queries are run on all platforms running `security-and-quality` on CodeQL
|
||||||
// CLI 2.11.3+.
|
// CLI 2.11.3+.
|
||||||
test(
|
test(
|
||||||
@@ -2085,6 +2088,16 @@ test(
|
|||||||
"security-and-quality",
|
"security-and-quality",
|
||||||
"~0.4.0"
|
"~0.4.0"
|
||||||
);
|
);
|
||||||
|
// Test that ML-powered queries are run on all platforms running `security-experimental` on CodeQL
|
||||||
|
// CLI 2.12.1+.
|
||||||
|
test(
|
||||||
|
mlPoweredQueriesMacro,
|
||||||
|
"2.12.1",
|
||||||
|
true,
|
||||||
|
undefined,
|
||||||
|
"security-experimental",
|
||||||
|
"~0.4.0"
|
||||||
|
);
|
||||||
|
|
||||||
const calculateAugmentationMacro = test.macro({
|
const calculateAugmentationMacro = test.macro({
|
||||||
exec: async (
|
exec: async (
|
||||||
@@ -2268,8 +2281,8 @@ test("downloadPacks-no-registries", async (t) => {
|
|||||||
go: ["c", "d"],
|
go: ["c", "d"],
|
||||||
python: ["e", "f"],
|
python: ["e", "f"],
|
||||||
},
|
},
|
||||||
undefined, // registries
|
|
||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
|
undefined, // registriesAuthTokens
|
||||||
tmpDir,
|
tmpDir,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
@@ -2287,10 +2300,10 @@ test("downloadPacks-with-registries", async (t) => {
|
|||||||
// associated env vars
|
// associated env vars
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env.GITHUB_TOKEN = "not-a-token";
|
process.env.GITHUB_TOKEN = "not-a-token";
|
||||||
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
process.env.CODEQL_REGISTRIES_AUTH = undefined;
|
||||||
const logger = getRunnerLogger(true);
|
const logger = getRunnerLogger(true);
|
||||||
|
|
||||||
const registries = [
|
const registriesInput = yaml.dump([
|
||||||
{
|
{
|
||||||
// no slash
|
// no slash
|
||||||
url: "http://ghcr.io",
|
url: "http://ghcr.io",
|
||||||
@@ -2303,9 +2316,12 @@ test("downloadPacks-with-registries", async (t) => {
|
|||||||
packages: "semmle/*",
|
packages: "semmle/*",
|
||||||
token: "still-not-a-token",
|
token: "still-not-a-token",
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
|
|
||||||
// append a slash to the first url
|
// append a slash to the first url
|
||||||
|
const registries = yaml.load(
|
||||||
|
registriesInput
|
||||||
|
) as configUtils.RegistryConfigWithCredentials[];
|
||||||
const expectedRegistries = registries.map((r, i) => ({
|
const expectedRegistries = registries.map((r, i) => ({
|
||||||
packages: r.packages,
|
packages: r.packages,
|
||||||
url: i === 0 ? `${r.url}/` : r.url,
|
url: i === 0 ? `${r.url}/` : r.url,
|
||||||
@@ -2347,8 +2363,8 @@ test("downloadPacks-with-registries", async (t) => {
|
|||||||
go: ["c", "d"],
|
go: ["c", "d"],
|
||||||
python: ["e", "f"],
|
python: ["e", "f"],
|
||||||
},
|
},
|
||||||
registries,
|
|
||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
|
registriesInput,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
@@ -2366,7 +2382,7 @@ test("downloadPacks-with-registries", async (t) => {
|
|||||||
|
|
||||||
// Verify that the env vars were unset.
|
// Verify that the env vars were unset.
|
||||||
t.deepEqual(process.env.GITHUB_TOKEN, "not-a-token");
|
t.deepEqual(process.env.GITHUB_TOKEN, "not-a-token");
|
||||||
t.deepEqual(process.env.CODEQL_REGISTRIES_AUTH, "not-a-registries-auth");
|
t.deepEqual(process.env.CODEQL_REGISTRIES_AUTH, undefined);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2378,7 +2394,7 @@ test("downloadPacks-with-registries fails on 2.10.3", async (t) => {
|
|||||||
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
||||||
const logger = getRunnerLogger(true);
|
const logger = getRunnerLogger(true);
|
||||||
|
|
||||||
const registries = [
|
const registriesInput = yaml.dump([
|
||||||
{
|
{
|
||||||
url: "http://ghcr.io",
|
url: "http://ghcr.io",
|
||||||
packages: ["codeql/*", "dsp-testing/*"],
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
@@ -2389,7 +2405,7 @@ test("downloadPacks-with-registries fails on 2.10.3", async (t) => {
|
|||||||
packages: "semmle/*",
|
packages: "semmle/*",
|
||||||
token: "still-not-a-token",
|
token: "still-not-a-token",
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
|
|
||||||
const codeQL = setCodeQL({
|
const codeQL = setCodeQL({
|
||||||
getVersion: () => Promise.resolve("2.10.3"),
|
getVersion: () => Promise.resolve("2.10.3"),
|
||||||
@@ -2400,8 +2416,8 @@ test("downloadPacks-with-registries fails on 2.10.3", async (t) => {
|
|||||||
codeQL,
|
codeQL,
|
||||||
[Language.javascript, Language.java, Language.python],
|
[Language.javascript, Language.java, Language.python],
|
||||||
{},
|
{},
|
||||||
registries,
|
|
||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
|
registriesInput,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
@@ -2420,7 +2436,7 @@ test("downloadPacks-with-registries fails with invalid registries block", async
|
|||||||
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
process.env.CODEQL_REGISTRIES_AUTH = "not-a-registries-auth";
|
||||||
const logger = getRunnerLogger(true);
|
const logger = getRunnerLogger(true);
|
||||||
|
|
||||||
const registries = [
|
const registriesInput = yaml.dump([
|
||||||
{
|
{
|
||||||
// missing url property
|
// missing url property
|
||||||
packages: ["codeql/*", "dsp-testing/*"],
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
@@ -2431,7 +2447,7 @@ test("downloadPacks-with-registries fails with invalid registries block", async
|
|||||||
packages: "semmle/*",
|
packages: "semmle/*",
|
||||||
token: "still-not-a-token",
|
token: "still-not-a-token",
|
||||||
},
|
},
|
||||||
];
|
]);
|
||||||
|
|
||||||
const codeQL = setCodeQL({
|
const codeQL = setCodeQL({
|
||||||
getVersion: () => Promise.resolve("2.10.4"),
|
getVersion: () => Promise.resolve("2.10.4"),
|
||||||
@@ -2442,8 +2458,8 @@ test("downloadPacks-with-registries fails with invalid registries block", async
|
|||||||
codeQL,
|
codeQL,
|
||||||
[Language.javascript, Language.java, Language.python],
|
[Language.javascript, Language.java, Language.python],
|
||||||
{},
|
{},
|
||||||
registries as RegistryConfigWithCredentials[] | undefined,
|
|
||||||
sampleApiDetails,
|
sampleApiDetails,
|
||||||
|
registriesInput,
|
||||||
tmpDir,
|
tmpDir,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
@@ -2454,6 +2470,85 @@ test("downloadPacks-with-registries fails with invalid registries block", async
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// the happy path for generateRegistries is already tested in downloadPacks.
|
||||||
|
// these following tests are for the error cases and when nothing is generated.
|
||||||
|
test("no generateRegistries when CLI is too old", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const registriesInput = yaml.dump([
|
||||||
|
{
|
||||||
|
// no slash
|
||||||
|
url: "http://ghcr.io",
|
||||||
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
|
token: "not-a-token",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const codeQL = setCodeQL({
|
||||||
|
// Accepted CLI versions are 2.10.4 or higher
|
||||||
|
getVersion: () => Promise.resolve("2.10.3"),
|
||||||
|
});
|
||||||
|
const logger = getRunnerLogger(true);
|
||||||
|
await t.throwsAsync(
|
||||||
|
async () =>
|
||||||
|
await configUtils.generateRegistries(
|
||||||
|
registriesInput,
|
||||||
|
codeQL,
|
||||||
|
tmpDir,
|
||||||
|
logger
|
||||||
|
),
|
||||||
|
undefined,
|
||||||
|
"'registries' input is not supported on CodeQL versions less than 2.10.4."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
test("no generateRegistries when registries is undefined", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
const registriesInput = undefined;
|
||||||
|
const codeQL = setCodeQL({
|
||||||
|
// Accepted CLI versions are 2.10.4 or higher
|
||||||
|
getVersion: () => Promise.resolve(CODEQL_VERSION_GHES_PACK_DOWNLOAD),
|
||||||
|
});
|
||||||
|
const logger = getRunnerLogger(true);
|
||||||
|
const { registriesAuthTokens, qlconfigFile } =
|
||||||
|
await configUtils.generateRegistries(
|
||||||
|
registriesInput,
|
||||||
|
codeQL,
|
||||||
|
tmpDir,
|
||||||
|
logger
|
||||||
|
);
|
||||||
|
|
||||||
|
t.is(registriesAuthTokens, undefined);
|
||||||
|
t.is(qlconfigFile, undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test("generateRegistries prefers original CODEQL_REGISTRIES_AUTH", async (t) => {
|
||||||
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
|
process.env.CODEQL_REGISTRIES_AUTH = "original";
|
||||||
|
const registriesInput = yaml.dump([
|
||||||
|
{
|
||||||
|
url: "http://ghcr.io",
|
||||||
|
packages: ["codeql/*", "dsp-testing/*"],
|
||||||
|
token: "not-a-token",
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const codeQL = setCodeQL({
|
||||||
|
// Accepted CLI versions are 2.10.4 or higher
|
||||||
|
getVersion: () => Promise.resolve(CODEQL_VERSION_GHES_PACK_DOWNLOAD),
|
||||||
|
});
|
||||||
|
const logger = getRunnerLogger(true);
|
||||||
|
const { registriesAuthTokens, qlconfigFile } =
|
||||||
|
await configUtils.generateRegistries(
|
||||||
|
registriesInput,
|
||||||
|
codeQL,
|
||||||
|
tmpDir,
|
||||||
|
logger
|
||||||
|
);
|
||||||
|
|
||||||
|
t.is(registriesAuthTokens, "original");
|
||||||
|
t.is(qlconfigFile, path.join(tmpDir, "qlconfig.yml"));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
// getLanguages
|
// getLanguages
|
||||||
|
|
||||||
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
|
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
|
||||||
|
|||||||
+93
-30
@@ -10,6 +10,7 @@ import {
|
|||||||
CodeQL,
|
CodeQL,
|
||||||
CODEQL_VERSION_GHES_PACK_DOWNLOAD,
|
CODEQL_VERSION_GHES_PACK_DOWNLOAD,
|
||||||
CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS,
|
CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS,
|
||||||
|
CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE,
|
||||||
ResolveQueriesOutput,
|
ResolveQueriesOutput,
|
||||||
} from "./codeql";
|
} from "./codeql";
|
||||||
import * as externalQueries from "./external-queries";
|
import * as externalQueries from "./external-queries";
|
||||||
@@ -380,7 +381,11 @@ async function addDefaultQueries(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// The set of acceptable values for built-in suites from the codeql bundle
|
// The set of acceptable values for built-in suites from the codeql bundle
|
||||||
const builtinSuites = ["security-extended", "security-and-quality"] as const;
|
const builtinSuites = [
|
||||||
|
"security-experimental",
|
||||||
|
"security-extended",
|
||||||
|
"security-and-quality",
|
||||||
|
] as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determine the set of queries associated with suiteName's suites and add them to resultMap.
|
* Determine the set of queries associated with suiteName's suites and add them to resultMap.
|
||||||
@@ -401,6 +406,19 @@ async function addBuiltinSuiteQueries(
|
|||||||
if (!found) {
|
if (!found) {
|
||||||
throw new Error(getQueryUsesInvalid(configFile, suiteName));
|
throw new Error(getQueryUsesInvalid(configFile, suiteName));
|
||||||
}
|
}
|
||||||
|
if (
|
||||||
|
suiteName === "security-experimental" &&
|
||||||
|
!(await codeQlVersionAbove(
|
||||||
|
codeQL,
|
||||||
|
CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE
|
||||||
|
))
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`The 'security-experimental' suite is not supported on CodeQL CLI versions earlier than
|
||||||
|
${CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE}. Please upgrade to CodeQL CLI version
|
||||||
|
${CODEQL_VERSION_SECURITY_EXPERIMENTAL_SUITE} or later.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// If we're running the JavaScript security-extended analysis (or a superset of it), the repo is
|
// If we're running the JavaScript security-extended analysis (or a superset of it), the repo is
|
||||||
// opted into the ML-powered queries beta, and a user hasn't already added the ML-powered query
|
// opted into the ML-powered queries beta, and a user hasn't already added the ML-powered query
|
||||||
@@ -413,7 +431,9 @@ async function addBuiltinSuiteQueries(
|
|||||||
CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS
|
CODEQL_VERSION_ML_POWERED_QUERIES_WINDOWS
|
||||||
))) &&
|
))) &&
|
||||||
languages.includes("javascript") &&
|
languages.includes("javascript") &&
|
||||||
(found === "security-extended" || found === "security-and-quality") &&
|
(found === "security-experimental" ||
|
||||||
|
found === "security-extended" ||
|
||||||
|
found === "security-and-quality") &&
|
||||||
!packs.javascript?.some(isMlPoweredJsQueriesPack) &&
|
!packs.javascript?.some(isMlPoweredJsQueriesPack) &&
|
||||||
(await featureEnablement.getValue(Feature.MlPoweredQueriesEnabled, codeQL))
|
(await featureEnablement.getValue(Feature.MlPoweredQueriesEnabled, codeQL))
|
||||||
) {
|
) {
|
||||||
@@ -1383,7 +1403,7 @@ function parseQueriesFromInput(
|
|||||||
|
|
||||||
const trimmedInput = queriesInputCombines
|
const trimmedInput = queriesInputCombines
|
||||||
? rawQueriesInput.trim().slice(1).trim()
|
? rawQueriesInput.trim().slice(1).trim()
|
||||||
: rawQueriesInput?.trim();
|
: rawQueriesInput?.trim() ?? "";
|
||||||
if (queriesInputCombines && trimmedInput.length === 0) {
|
if (queriesInputCombines && trimmedInput.length === 0) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
getConfigFilePropertyError(
|
getConfigFilePropertyError(
|
||||||
@@ -1630,7 +1650,8 @@ export function parsePacks(
|
|||||||
* Without a '+', an input value will override the corresponding value in the config file.
|
* Without a '+', an input value will override the corresponding value in the config file.
|
||||||
*
|
*
|
||||||
* @param inputValue The input value to process.
|
* @param inputValue The input value to process.
|
||||||
* @returns true if the input value should replace the corresponding value in the config file, false if it should be appended.
|
* @returns true if the input value should replace the corresponding value in the config file,
|
||||||
|
* false if it should be appended.
|
||||||
*/
|
*/
|
||||||
function shouldCombine(inputValue?: string): boolean {
|
function shouldCombine(inputValue?: string): boolean {
|
||||||
return !!inputValue?.trim().startsWith("+");
|
return !!inputValue?.trim().startsWith("+");
|
||||||
@@ -1748,13 +1769,12 @@ export async function initConfig(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const registries = parseRegistries(registriesInput);
|
|
||||||
await downloadPacks(
|
await downloadPacks(
|
||||||
codeQL,
|
codeQL,
|
||||||
config.languages,
|
config.languages,
|
||||||
config.packs,
|
config.packs,
|
||||||
registries,
|
|
||||||
apiDetails,
|
apiDetails,
|
||||||
|
registriesInput,
|
||||||
config.tempDir,
|
config.tempDir,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
@@ -1878,32 +1898,18 @@ export async function downloadPacks(
|
|||||||
codeQL: CodeQL,
|
codeQL: CodeQL,
|
||||||
languages: Language[],
|
languages: Language[],
|
||||||
packs: Packs,
|
packs: Packs,
|
||||||
registries: RegistryConfigWithCredentials[] | undefined,
|
|
||||||
apiDetails: api.GitHubApiDetails,
|
apiDetails: api.GitHubApiDetails,
|
||||||
tmpDir: string,
|
registriesInput: string | undefined,
|
||||||
|
tempDir: string,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
) {
|
) {
|
||||||
let qlconfigFile: string | undefined;
|
// This code path is only used when config parsing occurs in the Action.
|
||||||
let registriesAuthTokens: string | undefined;
|
const { registriesAuthTokens, qlconfigFile } = await generateRegistries(
|
||||||
if (registries) {
|
registriesInput,
|
||||||
if (
|
codeQL,
|
||||||
!(await codeQlVersionAbove(codeQL, CODEQL_VERSION_GHES_PACK_DOWNLOAD))
|
tempDir,
|
||||||
) {
|
logger
|
||||||
throw new Error(
|
);
|
||||||
`'registries' input is not supported on CodeQL versions less than ${CODEQL_VERSION_GHES_PACK_DOWNLOAD}.`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// generate a qlconfig.yml file to hold the registry configs.
|
|
||||||
const qlconfig = createRegistriesBlock(registries);
|
|
||||||
qlconfigFile = path.join(tmpDir, "qlconfig.yml");
|
|
||||||
fs.writeFileSync(qlconfigFile, yaml.dump(qlconfig), "utf8");
|
|
||||||
|
|
||||||
registriesAuthTokens = registries
|
|
||||||
.map((registry) => `${registry.url}=${registry.token}`)
|
|
||||||
.join(",");
|
|
||||||
}
|
|
||||||
|
|
||||||
await wrapEnvironment(
|
await wrapEnvironment(
|
||||||
{
|
{
|
||||||
GITHUB_TOKEN: apiDetails.auth,
|
GITHUB_TOKEN: apiDetails.auth,
|
||||||
@@ -1942,6 +1948,63 @@ export async function downloadPacks(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate a `qlconfig.yml` file from the `registries` input.
|
||||||
|
* This file is used by the CodeQL CLI to list the registries to use for each
|
||||||
|
* pack.
|
||||||
|
*
|
||||||
|
* @param registriesInput The value of the `registries` input.
|
||||||
|
* @param codeQL a codeQL object, used only for checking the version of CodeQL.
|
||||||
|
* @param tempDir a temporary directory to store the generated qlconfig.yml file.
|
||||||
|
* @param logger a logger object.
|
||||||
|
* @returns The path to the generated `qlconfig.yml` file and the auth tokens to
|
||||||
|
* use for each registry.
|
||||||
|
*/
|
||||||
|
export async function generateRegistries(
|
||||||
|
registriesInput: string | undefined,
|
||||||
|
codeQL: CodeQL,
|
||||||
|
tempDir: string,
|
||||||
|
logger: Logger
|
||||||
|
) {
|
||||||
|
const registries = parseRegistries(registriesInput);
|
||||||
|
let registriesAuthTokens: string | undefined;
|
||||||
|
let qlconfigFile: string | undefined;
|
||||||
|
if (registries) {
|
||||||
|
if (
|
||||||
|
!(await codeQlVersionAbove(codeQL, CODEQL_VERSION_GHES_PACK_DOWNLOAD))
|
||||||
|
) {
|
||||||
|
throw new Error(
|
||||||
|
`The 'registries' input is not supported on CodeQL CLI versions earlier than ${CODEQL_VERSION_GHES_PACK_DOWNLOAD}. Please upgrade to CodeQL CLI version ${CODEQL_VERSION_GHES_PACK_DOWNLOAD} or later.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a qlconfig.yml file to hold the registry configs.
|
||||||
|
const qlconfig = createRegistriesBlock(registries);
|
||||||
|
qlconfigFile = path.join(tempDir, "qlconfig.yml");
|
||||||
|
const qlconfigContents = yaml.dump(qlconfig);
|
||||||
|
fs.writeFileSync(qlconfigFile, qlconfigContents, "utf8");
|
||||||
|
|
||||||
|
logger.debug("Generated qlconfig.yml:");
|
||||||
|
logger.debug(qlconfigContents);
|
||||||
|
registriesAuthTokens = registries
|
||||||
|
.map((registry) => `${registry.url}=${registry.token}`)
|
||||||
|
.join(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof process.env.CODEQL_REGISTRIES_AUTH === "string") {
|
||||||
|
logger.debug(
|
||||||
|
"Using CODEQL_REGISTRIES_AUTH environment variable to authenticate with registries."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
registriesAuthTokens:
|
||||||
|
// if the user has explicitly set the CODEQL_REGISTRIES_AUTH env var then use that
|
||||||
|
process.env.CODEQL_REGISTRIES_AUTH ?? registriesAuthTokens,
|
||||||
|
qlconfigFile,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function createRegistriesBlock(registries: RegistryConfigWithCredentials[]): {
|
function createRegistriesBlock(registries: RegistryConfigWithCredentials[]): {
|
||||||
registries: RegistryConfigNoCredentials[];
|
registries: RegistryConfigNoCredentials[];
|
||||||
} {
|
} {
|
||||||
@@ -1978,7 +2041,7 @@ function createRegistriesBlock(registries: RegistryConfigWithCredentials[]): {
|
|||||||
* @param env
|
* @param env
|
||||||
* @param operation
|
* @param operation
|
||||||
*/
|
*/
|
||||||
async function wrapEnvironment(
|
export async function wrapEnvironment(
|
||||||
env: Record<string, string | undefined>,
|
env: Record<string, string | undefined>,
|
||||||
operation: Function
|
operation: Function
|
||||||
) {
|
) {
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"bundleVersion": "codeql-bundle-20230120",
|
"bundleVersion": "codeql-bundle-20230217",
|
||||||
"cliVersion": "2.12.1",
|
"cliVersion": "2.12.3",
|
||||||
"priorBundleVersion": "codeql-bundle-20230105",
|
"priorBundleVersion": "codeql-bundle-20230207",
|
||||||
"priorCliVersion": "2.12.0"
|
"priorCliVersion": "2.12.2"
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-29
@@ -34,12 +34,9 @@ export interface FeatureEnablement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export enum Feature {
|
export enum Feature {
|
||||||
BypassToolcacheEnabled = "bypass_toolcache_enabled",
|
|
||||||
BypassToolcacheKotlinSwiftEnabled = "bypass_toolcache_kotlin_swift_enabled",
|
|
||||||
CliConfigFileEnabled = "cli_config_file_enabled",
|
CliConfigFileEnabled = "cli_config_file_enabled",
|
||||||
DisableKotlinAnalysisEnabled = "disable_kotlin_analysis_enabled",
|
DisableKotlinAnalysisEnabled = "disable_kotlin_analysis_enabled",
|
||||||
MlPoweredQueriesEnabled = "ml_powered_queries_enabled",
|
MlPoweredQueriesEnabled = "ml_powered_queries_enabled",
|
||||||
TrapCachingEnabled = "trap_caching_enabled",
|
|
||||||
UploadFailedSarifEnabled = "upload_failed_sarif_enabled",
|
UploadFailedSarifEnabled = "upload_failed_sarif_enabled",
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,18 +44,6 @@ export const featureConfig: Record<
|
|||||||
Feature,
|
Feature,
|
||||||
{ envVar: string; minimumVersion: string | undefined }
|
{ envVar: string; minimumVersion: string | undefined }
|
||||||
> = {
|
> = {
|
||||||
[Feature.BypassToolcacheEnabled]: {
|
|
||||||
envVar: "CODEQL_BYPASS_TOOLCACHE",
|
|
||||||
// Cannot specify a minimum version because this flag is checked before we have
|
|
||||||
// access to the CodeQL instance.
|
|
||||||
minimumVersion: undefined,
|
|
||||||
},
|
|
||||||
[Feature.BypassToolcacheKotlinSwiftEnabled]: {
|
|
||||||
envVar: "CODEQL_BYPASS_TOOLCACHE_KOTLIN_SWIFT",
|
|
||||||
// Cannot specify a minimum version because this flag is checked before we have
|
|
||||||
// access to the CodeQL instance.
|
|
||||||
minimumVersion: undefined,
|
|
||||||
},
|
|
||||||
[Feature.DisableKotlinAnalysisEnabled]: {
|
[Feature.DisableKotlinAnalysisEnabled]: {
|
||||||
envVar: "CODEQL_DISABLE_KOTLIN_ANALYSIS",
|
envVar: "CODEQL_DISABLE_KOTLIN_ANALYSIS",
|
||||||
minimumVersion: undefined,
|
minimumVersion: undefined,
|
||||||
@@ -71,10 +56,6 @@ export const featureConfig: Record<
|
|||||||
envVar: "CODEQL_ML_POWERED_QUERIES",
|
envVar: "CODEQL_ML_POWERED_QUERIES",
|
||||||
minimumVersion: "2.7.5",
|
minimumVersion: "2.7.5",
|
||||||
},
|
},
|
||||||
[Feature.TrapCachingEnabled]: {
|
|
||||||
envVar: "CODEQL_TRAP_CACHING",
|
|
||||||
minimumVersion: undefined,
|
|
||||||
},
|
|
||||||
[Feature.UploadFailedSarifEnabled]: {
|
[Feature.UploadFailedSarifEnabled]: {
|
||||||
envVar: "CODEQL_ACTION_UPLOAD_FAILED_SARIF",
|
envVar: "CODEQL_ACTION_UPLOAD_FAILED_SARIF",
|
||||||
minimumVersion: "2.11.3",
|
minimumVersion: "2.11.3",
|
||||||
@@ -138,11 +119,6 @@ export class Features implements FeatureEnablement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bypassing the toolcache is disabled in test mode.
|
|
||||||
if (feature === Feature.BypassToolcacheEnabled && util.isInTestMode()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
const envVar = (
|
const envVar = (
|
||||||
process.env[featureConfig[feature].envVar] || ""
|
process.env[featureConfig[feature].envVar] || ""
|
||||||
).toLocaleLowerCase();
|
).toLocaleLowerCase();
|
||||||
@@ -172,13 +148,17 @@ export class Features implements FeatureEnablement {
|
|||||||
class GitHubFeatureFlags implements FeatureEnablement {
|
class GitHubFeatureFlags implements FeatureEnablement {
|
||||||
private cachedApiResponse: GitHubFeatureFlagsApiResponse | undefined;
|
private cachedApiResponse: GitHubFeatureFlagsApiResponse | undefined;
|
||||||
|
|
||||||
|
// We cache whether the feature flags were accessed or not in order to accurately report whether flags were
|
||||||
|
// incorrectly configured vs. inaccessible in our telemetry.
|
||||||
|
private hasAccessedRemoteFeatureFlags: boolean;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly gitHubVersion: util.GitHubVersion,
|
private readonly gitHubVersion: util.GitHubVersion,
|
||||||
private readonly repositoryNwo: RepositoryNwo,
|
private readonly repositoryNwo: RepositoryNwo,
|
||||||
private readonly featureFlagsFile: string,
|
private readonly featureFlagsFile: string,
|
||||||
private readonly logger: Logger
|
private readonly logger: Logger
|
||||||
) {
|
) {
|
||||||
/**/
|
this.hasAccessedRemoteFeatureFlags = false; // Not accessed by default.
|
||||||
}
|
}
|
||||||
|
|
||||||
private getCliVersionFromFeatureFlag(f: string): string | undefined {
|
private getCliVersionFromFeatureFlag(f: string): string | undefined {
|
||||||
@@ -211,7 +191,9 @@ class GitHubFeatureFlags implements FeatureEnablement {
|
|||||||
const defaultDotComCliVersion = await this.getDefaultDotcomCliVersion();
|
const defaultDotComCliVersion = await this.getDefaultDotcomCliVersion();
|
||||||
return {
|
return {
|
||||||
cliVersion: defaultDotComCliVersion.version,
|
cliVersion: defaultDotComCliVersion.version,
|
||||||
toolsFeatureFlagsValid: defaultDotComCliVersion.toolsFeatureFlagsValid,
|
toolsFeatureFlagsValid: this.hasAccessedRemoteFeatureFlags
|
||||||
|
? defaultDotComCliVersion.toolsFeatureFlagsValid
|
||||||
|
: undefined,
|
||||||
variant,
|
variant,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -224,7 +206,7 @@ class GitHubFeatureFlags implements FeatureEnablement {
|
|||||||
|
|
||||||
async getDefaultDotcomCliVersion(): Promise<{
|
async getDefaultDotcomCliVersion(): Promise<{
|
||||||
version: string;
|
version: string;
|
||||||
toolsFeatureFlagsValid: boolean;
|
toolsFeatureFlagsValid: boolean | undefined;
|
||||||
}> {
|
}> {
|
||||||
const response = await this.getAllFeatures();
|
const response = await this.getAllFeatures();
|
||||||
|
|
||||||
@@ -252,7 +234,9 @@ class GitHubFeatureFlags implements FeatureEnablement {
|
|||||||
);
|
);
|
||||||
return {
|
return {
|
||||||
version: defaults.cliVersion,
|
version: defaults.cliVersion,
|
||||||
toolsFeatureFlagsValid: false,
|
toolsFeatureFlagsValid: this.hasAccessedRemoteFeatureFlags
|
||||||
|
? false
|
||||||
|
: undefined,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -350,6 +334,7 @@ class GitHubFeatureFlags implements FeatureEnablement {
|
|||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
"Not running against github.com. Disabling all toggleable features."
|
"Not running against github.com. Disabling all toggleable features."
|
||||||
);
|
);
|
||||||
|
this.hasAccessedRemoteFeatureFlags = false;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -365,6 +350,7 @@ class GitHubFeatureFlags implements FeatureEnablement {
|
|||||||
"Loaded the following default values for the feature flags from the Code Scanning API: " +
|
"Loaded the following default values for the feature flags from the Code Scanning API: " +
|
||||||
`${JSON.stringify(remoteFlags)}`
|
`${JSON.stringify(remoteFlags)}`
|
||||||
);
|
);
|
||||||
|
this.hasAccessedRemoteFeatureFlags = true;
|
||||||
return remoteFlags;
|
return remoteFlags;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (util.isHTTPError(e) && e.status === 403) {
|
if (util.isHTTPError(e) && e.status === 403) {
|
||||||
@@ -374,6 +360,7 @@ class GitHubFeatureFlags implements FeatureEnablement {
|
|||||||
"This could be because the Action is running on a pull request from a fork. If not, " +
|
"This could be because the Action is running on a pull request from a fork. If not, " +
|
||||||
`please ensure the Action has the 'security-events: write' permission. Details: ${e}`
|
`please ensure the Action has the 'security-events: write' permission. Details: ${e}`
|
||||||
);
|
);
|
||||||
|
this.hasAccessedRemoteFeatureFlags = false;
|
||||||
return {};
|
return {};
|
||||||
} else {
|
} else {
|
||||||
// Some features, such as `ml_powered_queries_enabled` affect the produced alerts.
|
// Some features, such as `ml_powered_queries_enabled` affect the produced alerts.
|
||||||
@@ -385,6 +372,5 @@ class GitHubFeatureFlags implements FeatureEnablement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+20
-23
@@ -16,7 +16,7 @@ import {
|
|||||||
import { getGitHubVersion } from "./api-client";
|
import { getGitHubVersion } from "./api-client";
|
||||||
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
|
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
|
||||||
import * as configUtils from "./config-utils";
|
import * as configUtils from "./config-utils";
|
||||||
import { Feature, FeatureEnablement, Features } from "./feature-flags";
|
import { Feature, Features } from "./feature-flags";
|
||||||
import {
|
import {
|
||||||
initCodeQL,
|
initCodeQL,
|
||||||
initConfig,
|
initConfig,
|
||||||
@@ -43,7 +43,6 @@ import {
|
|||||||
GitHubVariant,
|
GitHubVariant,
|
||||||
initializeEnvironment,
|
initializeEnvironment,
|
||||||
isHostedRunner,
|
isHostedRunner,
|
||||||
shouldBypassToolcache,
|
|
||||||
} from "./util";
|
} from "./util";
|
||||||
import { validateWorkflow } from "./workflow";
|
import { validateWorkflow } from "./workflow";
|
||||||
|
|
||||||
@@ -87,7 +86,9 @@ interface InitWithConfigStatusReport extends InitStatusReport {
|
|||||||
interface InitToolsDownloadFields {
|
interface InitToolsDownloadFields {
|
||||||
/** Time taken to download the bundle, in milliseconds. */
|
/** Time taken to download the bundle, in milliseconds. */
|
||||||
tools_download_duration_ms?: number;
|
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. */
|
/**
|
||||||
|
* 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;
|
tools_feature_flags_valid?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,13 +118,14 @@ async function sendInitStatusReport(
|
|||||||
workflow_languages: workflowLanguages || "",
|
workflow_languages: workflowLanguages || "",
|
||||||
};
|
};
|
||||||
|
|
||||||
let initToolsDownloadFields: InitToolsDownloadFields = {};
|
const initToolsDownloadFields: InitToolsDownloadFields = {};
|
||||||
|
|
||||||
if (toolsSource === ToolsSource.Download) {
|
if (toolsDownloadDurationMs !== undefined) {
|
||||||
initToolsDownloadFields = {
|
initToolsDownloadFields.tools_download_duration_ms =
|
||||||
tools_download_duration_ms: toolsDownloadDurationMs,
|
toolsDownloadDurationMs;
|
||||||
tools_feature_flags_valid: toolsFeatureFlagsValid,
|
}
|
||||||
};
|
if (toolsFeatureFlagsValid !== undefined) {
|
||||||
|
initToolsDownloadFields.tools_feature_flags_valid = toolsFeatureFlagsValid;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (config !== undefined) {
|
if (config !== undefined) {
|
||||||
@@ -202,6 +204,8 @@ async function run() {
|
|||||||
getRequiredEnvParam("GITHUB_REPOSITORY")
|
getRequiredEnvParam("GITHUB_REPOSITORY")
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const registriesInput = getOptionalInput("registries");
|
||||||
|
|
||||||
const features = new Features(
|
const features = new Features(
|
||||||
gitHubVersion,
|
gitHubVersion,
|
||||||
repositoryNwo,
|
repositoryNwo,
|
||||||
@@ -236,13 +240,6 @@ async function run() {
|
|||||||
apiDetails,
|
apiDetails,
|
||||||
getTemporaryDirectory(),
|
getTemporaryDirectory(),
|
||||||
gitHubVersion.type,
|
gitHubVersion.type,
|
||||||
await shouldBypassToolcache(
|
|
||||||
features,
|
|
||||||
getOptionalInput("tools"),
|
|
||||||
getOptionalInput("languages"),
|
|
||||||
repositoryNwo,
|
|
||||||
logger
|
|
||||||
),
|
|
||||||
codeQLDefaultVersionInfo,
|
codeQLDefaultVersionInfo,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
@@ -256,10 +253,10 @@ async function run() {
|
|||||||
getOptionalInput("languages"),
|
getOptionalInput("languages"),
|
||||||
getOptionalInput("queries"),
|
getOptionalInput("queries"),
|
||||||
getOptionalInput("packs"),
|
getOptionalInput("packs"),
|
||||||
getOptionalInput("registries"),
|
registriesInput,
|
||||||
getOptionalInput("config-file"),
|
getOptionalInput("config-file"),
|
||||||
getOptionalInput("db-location"),
|
getOptionalInput("db-location"),
|
||||||
await getTrapCachingEnabled(features),
|
getTrapCachingEnabled(),
|
||||||
// Debug mode is enabled if:
|
// Debug mode is enabled if:
|
||||||
// - The `init` Action is passed `debug: true`.
|
// - The `init` Action is passed `debug: true`.
|
||||||
// - Actions step debugging is enabled (e.g. by [enabling debug logging for a rerun](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow),
|
// - Actions step debugging is enabled (e.g. by [enabling debug logging for a rerun](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow),
|
||||||
@@ -340,7 +337,9 @@ async function run() {
|
|||||||
config,
|
config,
|
||||||
sourceRoot,
|
sourceRoot,
|
||||||
"Runner.Worker.exe",
|
"Runner.Worker.exe",
|
||||||
|
registriesInput,
|
||||||
features,
|
features,
|
||||||
|
apiDetails,
|
||||||
logger
|
logger
|
||||||
);
|
);
|
||||||
if (tracerConfig !== undefined) {
|
if (tracerConfig !== undefined) {
|
||||||
@@ -391,9 +390,7 @@ async function run() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getTrapCachingEnabled(
|
function getTrapCachingEnabled(): boolean {
|
||||||
featureEnablement: FeatureEnablement
|
|
||||||
): Promise<boolean> {
|
|
||||||
// If the workflow specified something always respect that
|
// If the workflow specified something always respect that
|
||||||
const trapCaching = getOptionalInput("trap-caching");
|
const trapCaching = getOptionalInput("trap-caching");
|
||||||
if (trapCaching !== undefined) return trapCaching === "true";
|
if (trapCaching !== undefined) return trapCaching === "true";
|
||||||
@@ -401,8 +398,8 @@ async function getTrapCachingEnabled(
|
|||||||
// On self-hosted runners which may have slow network access, disable TRAP caching by default
|
// On self-hosted runners which may have slow network access, disable TRAP caching by default
|
||||||
if (!isHostedRunner()) return false;
|
if (!isHostedRunner()) return false;
|
||||||
|
|
||||||
// On hosted runners, respect the feature flag
|
// On hosted runners, enable TRAP caching by default
|
||||||
return await featureEnablement.getValue(Feature.TrapCachingEnabled);
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runWrapper() {
|
async function runWrapper() {
|
||||||
|
|||||||
+33
-9
@@ -27,7 +27,6 @@ export async function initCodeQL(
|
|||||||
apiDetails: GitHubApiDetails,
|
apiDetails: GitHubApiDetails,
|
||||||
tempDir: string,
|
tempDir: string,
|
||||||
variant: util.GitHubVariant,
|
variant: util.GitHubVariant,
|
||||||
bypassToolcache: boolean,
|
|
||||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
): Promise<{
|
): Promise<{
|
||||||
@@ -43,7 +42,6 @@ export async function initCodeQL(
|
|||||||
apiDetails,
|
apiDetails,
|
||||||
tempDir,
|
tempDir,
|
||||||
variant,
|
variant,
|
||||||
bypassToolcache,
|
|
||||||
defaultCliVersion,
|
defaultCliVersion,
|
||||||
logger,
|
logger,
|
||||||
true
|
true
|
||||||
@@ -104,20 +102,46 @@ export async function runInit(
|
|||||||
config: configUtils.Config,
|
config: configUtils.Config,
|
||||||
sourceRoot: string,
|
sourceRoot: string,
|
||||||
processName: string | undefined,
|
processName: string | undefined,
|
||||||
|
registriesInput: string | undefined,
|
||||||
featureEnablement: FeatureEnablement,
|
featureEnablement: FeatureEnablement,
|
||||||
|
apiDetails: GitHubApiCombinedDetails,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
): Promise<TracerConfig | undefined> {
|
): Promise<TracerConfig | undefined> {
|
||||||
fs.mkdirSync(config.dbLocation, { recursive: true });
|
fs.mkdirSync(config.dbLocation, { recursive: true });
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (await codeQlVersionAbove(codeql, CODEQL_VERSION_NEW_TRACING)) {
|
if (await codeQlVersionAbove(codeql, CODEQL_VERSION_NEW_TRACING)) {
|
||||||
// Init a database cluster
|
// When parsing the codeql config in the CLI, we have not yet created the qlconfig file.
|
||||||
await codeql.databaseInitCluster(
|
// So, create it now.
|
||||||
config,
|
// If we are parsing the config file in the Action, then the qlconfig file was already created
|
||||||
sourceRoot,
|
// before the `pack download` command was invoked. It is not required for the init command.
|
||||||
processName,
|
let registriesAuthTokens: string | undefined;
|
||||||
featureEnablement,
|
let qlconfigFile: string | undefined;
|
||||||
logger
|
if (await util.useCodeScanningConfigInCli(codeql, featureEnablement)) {
|
||||||
|
({ registriesAuthTokens, qlconfigFile } =
|
||||||
|
await configUtils.generateRegistries(
|
||||||
|
registriesInput,
|
||||||
|
codeql,
|
||||||
|
config.tempDir,
|
||||||
|
logger
|
||||||
|
));
|
||||||
|
}
|
||||||
|
await configUtils.wrapEnvironment(
|
||||||
|
{
|
||||||
|
GITHUB_TOKEN: apiDetails.auth,
|
||||||
|
CODEQL_REGISTRIES_AUTH: registriesAuthTokens,
|
||||||
|
},
|
||||||
|
|
||||||
|
// Init a database cluster
|
||||||
|
async () =>
|
||||||
|
await codeql.databaseInitCluster(
|
||||||
|
config,
|
||||||
|
sourceRoot,
|
||||||
|
processName,
|
||||||
|
featureEnablement,
|
||||||
|
qlconfigFile,
|
||||||
|
logger
|
||||||
|
)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
for (const language of config.languages) {
|
for (const language of config.languages) {
|
||||||
|
|||||||
@@ -21,8 +21,6 @@ export const LANGUAGE_ALIASES: { [lang: string]: Language } = {
|
|||||||
|
|
||||||
export type LanguageOrAlias = Language | keyof typeof LANGUAGE_ALIASES;
|
export type LanguageOrAlias = Language | keyof typeof LANGUAGE_ALIASES;
|
||||||
|
|
||||||
export const KOTLIN_SWIFT_BYPASS = ["kotlin", "swift"];
|
|
||||||
|
|
||||||
export function resolveAlias(lang: LanguageOrAlias): Language {
|
export function resolveAlias(lang: LanguageOrAlias): Language {
|
||||||
return LANGUAGE_ALIASES[lang] || lang;
|
return LANGUAGE_ALIASES[lang] || lang;
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-20
@@ -354,7 +354,6 @@ async function findOverridingToolsInCache(
|
|||||||
|
|
||||||
export async function getCodeQLSource(
|
export async function getCodeQLSource(
|
||||||
toolsInput: string | undefined,
|
toolsInput: string | undefined,
|
||||||
bypassToolcache: boolean,
|
|
||||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||||
apiDetails: api.GitHubApiDetails,
|
apiDetails: api.GitHubApiDetails,
|
||||||
variant: util.GitHubVariant,
|
variant: util.GitHubVariant,
|
||||||
@@ -368,25 +367,18 @@ export async function getCodeQLSource(
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The reason why the tools shipped with the Action have been forced. */
|
/**
|
||||||
const forceShippedToolsReason =
|
* Whether the tools shipped with the Action, i.e. those in `defaults.json`, have been forced.
|
||||||
// We use the special value of 'latest' to prioritize the version in the
|
*
|
||||||
// defaults over any pinned cached version.
|
* We use the special value of 'latest' to prioritize the version in `defaults.json` over the
|
||||||
toolsInput === "latest"
|
* version specified by the feature flags on Dotcom and over any pinned cached version on
|
||||||
? '"tools: latest" was requested'
|
* Enterprise Server.
|
||||||
: // If the user hasn't requested a particular CodeQL version, then bypass
|
*/
|
||||||
// the toolcache when the appropriate feature is enabled. This
|
const forceShippedTools = toolsInput === "latest";
|
||||||
// allows us to quickly rollback a broken bundle that has made its way
|
|
||||||
// into the toolcache.
|
|
||||||
toolsInput === undefined && bypassToolcache
|
|
||||||
? "a specific version of the CodeQL tools was not requested and the bypass toolcache feature is enabled"
|
|
||||||
: undefined;
|
|
||||||
/** Whether the tools shipped with the Action, i.e. those in `defaults.json`, have been forced. */
|
|
||||||
const forceShippedTools = forceShippedToolsReason !== undefined;
|
|
||||||
if (forceShippedTools) {
|
if (forceShippedTools) {
|
||||||
logger.info(
|
logger.info(
|
||||||
"Overriding the version of the CodeQL tools by the version shipped with the Action since " +
|
"Overriding the version of the CodeQL tools by the version shipped with the Action since " +
|
||||||
`${forceShippedToolsReason}.`
|
`"tools: latest" was requested.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -714,7 +706,6 @@ export function getCodeQLURLVersion(url: string): string {
|
|||||||
* @param apiDetails
|
* @param apiDetails
|
||||||
* @param tempDir
|
* @param tempDir
|
||||||
* @param variant
|
* @param variant
|
||||||
* @param bypassToolcache
|
|
||||||
* @param defaultCliVersion
|
* @param defaultCliVersion
|
||||||
* @param logger
|
* @param logger
|
||||||
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
||||||
@@ -726,7 +717,6 @@ export async function setupCodeQLBundle(
|
|||||||
apiDetails: api.GitHubApiDetails,
|
apiDetails: api.GitHubApiDetails,
|
||||||
tempDir: string,
|
tempDir: string,
|
||||||
variant: util.GitHubVariant,
|
variant: util.GitHubVariant,
|
||||||
bypassToolcache: boolean,
|
|
||||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||||
logger: Logger
|
logger: Logger
|
||||||
): Promise<{
|
): Promise<{
|
||||||
@@ -737,7 +727,6 @@ export async function setupCodeQLBundle(
|
|||||||
}> {
|
}> {
|
||||||
const source = await getCodeQLSource(
|
const source = await getCodeQLSource(
|
||||||
toolsInput,
|
toolsInput,
|
||||||
bypassToolcache,
|
|
||||||
defaultCliVersion,
|
defaultCliVersion,
|
||||||
apiDetails,
|
apiDetails,
|
||||||
variant,
|
variant,
|
||||||
|
|||||||
+5
-2
@@ -416,7 +416,8 @@ export async function waitForProcessing(
|
|||||||
statusCheckingStarted + STATUS_CHECK_TIMEOUT_MILLISECONDS
|
statusCheckingStarted + STATUS_CHECK_TIMEOUT_MILLISECONDS
|
||||||
) {
|
) {
|
||||||
// If the analysis hasn't finished processing in the allotted time, we continue anyway rather than failing.
|
// If the analysis hasn't finished processing in the allotted time, we continue anyway rather than failing.
|
||||||
// It's possible the analysis will eventually finish processing, but it's not worth spending more Actions time waiting.
|
// It's possible the analysis will eventually finish processing, but it's not worth spending more
|
||||||
|
// Actions time waiting.
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Timed out waiting for analysis to finish processing. Continuing."
|
"Timed out waiting for analysis to finish processing. Continuing."
|
||||||
);
|
);
|
||||||
@@ -462,7 +463,9 @@ export async function waitForProcessing(
|
|||||||
util.assertNever(status);
|
util.assertNever(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
await util.delay(STATUS_CHECK_FREQUENCY_MILLISECONDS);
|
await util.delay(STATUS_CHECK_FREQUENCY_MILLISECONDS, {
|
||||||
|
allowProcessExit: false,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
logger.endGroup();
|
logger.endGroup();
|
||||||
|
|||||||
+1
-127
@@ -8,14 +8,8 @@ import * as sinon from "sinon";
|
|||||||
|
|
||||||
import * as api from "./api-client";
|
import * as api from "./api-client";
|
||||||
import { Config } from "./config-utils";
|
import { Config } from "./config-utils";
|
||||||
import { Feature } from "./feature-flags";
|
|
||||||
import { getRunnerLogger } from "./logging";
|
import { getRunnerLogger } from "./logging";
|
||||||
import { parseRepositoryNwo } from "./repository";
|
import { setupTests } from "./testing-utils";
|
||||||
import {
|
|
||||||
createFeatures,
|
|
||||||
mockLanguagesInRepo,
|
|
||||||
setupTests,
|
|
||||||
} from "./testing-utils";
|
|
||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
|
|
||||||
setupTests(test);
|
setupTests(test);
|
||||||
@@ -398,123 +392,3 @@ test("withTimeout doesn't call callback if promise resolves", async (t) => {
|
|||||||
t.deepEqual(shortTaskTimedOut, false);
|
t.deepEqual(shortTaskTimedOut, false);
|
||||||
t.deepEqual(result, 99);
|
t.deepEqual(result, 99);
|
||||||
});
|
});
|
||||||
|
|
||||||
const mockRepositoryNwo = parseRepositoryNwo("owner/repo");
|
|
||||||
// eslint-disable-next-line github/array-foreach
|
|
||||||
[
|
|
||||||
{
|
|
||||||
name: "disabled",
|
|
||||||
features: [],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "disabled even though swift kotlin bypassed",
|
|
||||||
features: [Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "disabled even though swift kotlin analyzed",
|
|
||||||
features: [],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: " sWiFt , KoTlIn ",
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "toolcache bypass all",
|
|
||||||
features: [Feature.BypassToolcacheEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "custom CodeQL",
|
|
||||||
features: [],
|
|
||||||
hasCustomCodeQL: true,
|
|
||||||
languagesInput: undefined,
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass swift",
|
|
||||||
features: [Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: " sWiFt ,other",
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass kotlin",
|
|
||||||
features: [Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "other, KoTlIn ",
|
|
||||||
languagesInRepository: [],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: false,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass kotlin language from repository",
|
|
||||||
features: [Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "",
|
|
||||||
languagesInRepository: ["KoTlIn", "other"],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass swift language from repository",
|
|
||||||
features: [Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "",
|
|
||||||
languagesInRepository: ["SwiFt", "other"],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "bypass java from input if there is kotlin in repository",
|
|
||||||
features: [Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "java",
|
|
||||||
languagesInRepository: ["kotlin", "other"],
|
|
||||||
expected: true,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "don't bypass java from input if there is no kotlin in repository",
|
|
||||||
features: [Feature.BypassToolcacheKotlinSwiftEnabled],
|
|
||||||
hasCustomCodeQL: false,
|
|
||||||
languagesInput: "java",
|
|
||||||
languagesInRepository: ["java", "other"],
|
|
||||||
expected: false,
|
|
||||||
expectedApiCall: true,
|
|
||||||
},
|
|
||||||
].forEach((args) => {
|
|
||||||
test(`shouldBypassToolcache: ${args.name}`, async (t) => {
|
|
||||||
const mockRequest = mockLanguagesInRepo(args.languagesInRepository);
|
|
||||||
const mockLogger = getRunnerLogger(true);
|
|
||||||
const featureEnablement = createFeatures(args.features);
|
|
||||||
const codeqlUrl = args.hasCustomCodeQL ? "custom-codeql-url" : undefined;
|
|
||||||
const actual = await util.shouldBypassToolcache(
|
|
||||||
featureEnablement,
|
|
||||||
codeqlUrl,
|
|
||||||
args.languagesInput,
|
|
||||||
mockRepositoryNwo,
|
|
||||||
mockLogger
|
|
||||||
);
|
|
||||||
t.deepEqual(actual, args.expected);
|
|
||||||
t.deepEqual(mockRequest.called, args.expectedApiCall);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
+29
-67
@@ -13,15 +13,12 @@ import * as apiCompatibility from "./api-compatibility.json";
|
|||||||
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
|
import { CodeQL, CODEQL_VERSION_NEW_TRACING } from "./codeql";
|
||||||
import {
|
import {
|
||||||
Config,
|
Config,
|
||||||
getLanguagesInRepo,
|
|
||||||
getRawLanguages,
|
|
||||||
parsePacksSpecification,
|
parsePacksSpecification,
|
||||||
prettyPrintPack,
|
prettyPrintPack,
|
||||||
} from "./config-utils";
|
} from "./config-utils";
|
||||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||||
import { KOTLIN_SWIFT_BYPASS, Language } from "./languages";
|
import { Language } from "./languages";
|
||||||
import { Logger } from "./logging";
|
import { Logger } from "./logging";
|
||||||
import { RepositoryNwo } from "./repository";
|
|
||||||
import { CODEQL_ACTION_TEST_MODE } from "./shared-environment";
|
import { CODEQL_ACTION_TEST_MODE } from "./shared-environment";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -551,16 +548,38 @@ export async function bundleDb(
|
|||||||
return databaseBundlePath;
|
return databaseBundlePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function delay(milliseconds: number) {
|
/**
|
||||||
// Immediately `unref` the timer such that it only prevents the process from exiting if the
|
* @param milliseconds time to delay
|
||||||
// surrounding promise is being awaited.
|
* @param opts options
|
||||||
return new Promise((resolve) => setTimeout(resolve, milliseconds).unref());
|
* @param opts.allowProcessExit if true, the timer will not prevent the process from exiting
|
||||||
|
*/
|
||||||
|
export async function delay(
|
||||||
|
milliseconds: number,
|
||||||
|
{ allowProcessExit }: { allowProcessExit: boolean }
|
||||||
|
) {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const timer = setTimeout(resolve, milliseconds);
|
||||||
|
if (allowProcessExit) {
|
||||||
|
// Immediately `unref` the timer such that it only prevents the process from exiting if the
|
||||||
|
// surrounding promise is being awaited.
|
||||||
|
timer.unref();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isGoodVersion(versionSpec: string) {
|
export function isGoodVersion(versionSpec: string) {
|
||||||
return !BROKEN_VERSIONS.includes(versionSpec);
|
return !BROKEN_VERSIONS.includes(versionSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the CodeQL CLI supports the `--expect-discarded-cache` command-line flag.
|
||||||
|
*/
|
||||||
|
export async function supportExpectDiscardedCache(
|
||||||
|
codeQL: CodeQL
|
||||||
|
): Promise<boolean> {
|
||||||
|
return codeQlVersionAbove(codeQL, "2.12.1");
|
||||||
|
}
|
||||||
|
|
||||||
export const ML_POWERED_JS_QUERIES_PACK_NAME =
|
export const ML_POWERED_JS_QUERIES_PACK_NAME =
|
||||||
"codeql/javascript-experimental-atm-queries";
|
"codeql/javascript-experimental-atm-queries";
|
||||||
|
|
||||||
@@ -751,7 +770,7 @@ export async function withTimeout<T>(
|
|||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
const timeoutTask = async () => {
|
const timeoutTask = async () => {
|
||||||
await delay(timeoutMs);
|
await delay(timeoutMs, { allowProcessExit: true });
|
||||||
if (!finished) {
|
if (!finished) {
|
||||||
// Workaround: While the promise racing below will allow the main code
|
// Workaround: While the promise racing below will allow the main code
|
||||||
// to continue, the process won't normally exit until the asynchronous
|
// to continue, the process won't normally exit until the asynchronous
|
||||||
@@ -776,7 +795,7 @@ export async function checkForTimeout() {
|
|||||||
core.info(
|
core.info(
|
||||||
"A timeout occurred, force exiting the process after 30 seconds to prevent hanging."
|
"A timeout occurred, force exiting the process after 30 seconds to prevent hanging."
|
||||||
);
|
);
|
||||||
await delay(30_000);
|
await delay(30_000, { allowProcessExit: true });
|
||||||
process.exit();
|
process.exit();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -802,63 +821,6 @@ export function isHostedRunner() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param featuresEnablement The features enabled for the current run
|
|
||||||
* @param languagesInput Languages input from the workflow
|
|
||||||
* @param repository The owner/name of the repository
|
|
||||||
* @param logger A logger
|
|
||||||
* @returns A boolean indicating whether or not the toolcache should be bypassed and the latest codeql should be downloaded.
|
|
||||||
*/
|
|
||||||
export async function shouldBypassToolcache(
|
|
||||||
featuresEnablement: FeatureEnablement,
|
|
||||||
codeqlUrl: string | undefined,
|
|
||||||
languagesInput: string | undefined,
|
|
||||||
repository: RepositoryNwo,
|
|
||||||
logger: Logger
|
|
||||||
): Promise<boolean> {
|
|
||||||
// An explicit codeql url is specified, that means the toolcache will not be used.
|
|
||||||
if (codeqlUrl) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the toolcache is disabled for all languages
|
|
||||||
if (await featuresEnablement.getValue(Feature.BypassToolcacheEnabled)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check if the toolcache is disabled for kotlin and swift.
|
|
||||||
if (
|
|
||||||
!(await featuresEnablement.getValue(
|
|
||||||
Feature.BypassToolcacheKotlinSwiftEnabled
|
|
||||||
))
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now check to see if kotlin or swift is one of the languages being analyzed.
|
|
||||||
const { rawLanguages, autodetected } = await getRawLanguages(
|
|
||||||
languagesInput,
|
|
||||||
repository,
|
|
||||||
logger
|
|
||||||
);
|
|
||||||
let bypass = rawLanguages.some((lang) => KOTLIN_SWIFT_BYPASS.includes(lang));
|
|
||||||
if (bypass) {
|
|
||||||
logger.info(
|
|
||||||
`Bypassing toolcache for kotlin or swift. Languages: ${rawLanguages}`
|
|
||||||
);
|
|
||||||
} else if (!autodetected && rawLanguages.includes(Language.java)) {
|
|
||||||
// special case: java was explicitly specified, but there might be
|
|
||||||
// some kotlin in the repository, so we need to make a request for that.
|
|
||||||
const langsInRepo = await getLanguagesInRepo(repository, logger);
|
|
||||||
if (langsInRepo.includes("kotlin")) {
|
|
||||||
logger.info(`Bypassing toolcache for kotlin.`);
|
|
||||||
bypass = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return bypass;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function parseMatrixInput(
|
export function parseMatrixInput(
|
||||||
matrixInput: string | undefined
|
matrixInput: string | undefined
|
||||||
): { [key: string]: string } | undefined {
|
): { [key: string]: string } | undefined {
|
||||||
|
|||||||
Reference in New Issue
Block a user