mirror of
https://github.com/github/codeql-action.git
synced 2025-12-19 22:00:50 +08:00
Compare commits
4 Commits
navntoft/t
...
nickfyson/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
717fa865d8 | ||
|
|
3cb70c8858 | ||
|
|
2998d02818 | ||
|
|
d96885a274 |
23
.github/workflows/codeql.yml
vendored
23
.github/workflows/codeql.yml
vendored
@@ -26,3 +26,26 @@ jobs:
|
|||||||
languages: javascript
|
languages: javascript
|
||||||
config-file: ./.github/codeql/codeql-config.yml
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
- uses: ./analyze
|
- uses: ./analyze
|
||||||
|
|
||||||
|
test-root-action:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-latest,windows-latest,macos-latest]
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
# Must fetch at least the immediate parents so that if this is
|
||||||
|
# a pull request then we can checkout the head of the pull request.
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
# If this run was triggered by a pull request event then checkout
|
||||||
|
# the head of the pull request instead of the merge commit.
|
||||||
|
- run: git checkout HEAD^2
|
||||||
|
if: ${{ github.event_name == 'pull_request' }}
|
||||||
|
|
||||||
|
- uses: github/codeql-action@${{ 'testing_testing' }}
|
||||||
|
with:
|
||||||
|
languages: javascript
|
||||||
|
config-file: ./.github/codeql/codeql-config.yml
|
||||||
|
|||||||
24
.github/workflows/integration-testing.yml
vendored
24
.github/workflows/integration-testing.yml
vendored
@@ -14,11 +14,10 @@ jobs:
|
|||||||
mkdir ../action
|
mkdir ../action
|
||||||
mv * .github ../action/
|
mv * .github ../action/
|
||||||
mv ../action/tests/multi-language-repo/{*,.github} .
|
mv ../action/tests/multi-language-repo/{*,.github} .
|
||||||
- uses: ./../action/init
|
|
||||||
- name: Build code
|
- name: Build code
|
||||||
shell: bash
|
shell: bash
|
||||||
run: ./build.sh
|
run: ./build.sh
|
||||||
- uses: ./../action/analyze
|
- uses: ./../action
|
||||||
env:
|
env:
|
||||||
TEST_MODE: true
|
TEST_MODE: true
|
||||||
- run: |
|
- run: |
|
||||||
@@ -51,14 +50,13 @@ jobs:
|
|||||||
mkdir ../action
|
mkdir ../action
|
||||||
mv * .github ../action/
|
mv * .github ../action/
|
||||||
mv ../action/tests/multi-language-repo/{*,.github} .
|
mv ../action/tests/multi-language-repo/{*,.github} .
|
||||||
- uses: ./../action/init
|
|
||||||
with:
|
|
||||||
languages: cpp,csharp,java,javascript,python
|
|
||||||
config-file: github/codeql-action/tests/multi-language-repo/.github/codeql/custom-queries.yml@${{ github.sha }}
|
|
||||||
- name: Build code
|
- name: Build code
|
||||||
shell: bash
|
shell: bash
|
||||||
run: ./build.sh
|
run: ./build.sh
|
||||||
- uses: ./../action/analyze
|
- uses: ./../action
|
||||||
|
with:
|
||||||
|
languages: cpp,csharp,java,javascript,python
|
||||||
|
config-file: github/codeql-action/tests/multi-language-repo/.github/codeql/custom-queries.yml@${{ github.sha }}
|
||||||
env:
|
env:
|
||||||
TEST_MODE: true
|
TEST_MODE: true
|
||||||
|
|
||||||
@@ -82,14 +80,13 @@ jobs:
|
|||||||
mkdir ../action
|
mkdir ../action
|
||||||
mv * .github ../action/
|
mv * .github ../action/
|
||||||
mv ../action/tests/multi-language-repo/{*,.github} .
|
mv ../action/tests/multi-language-repo/{*,.github} .
|
||||||
- uses: ./../action/init
|
|
||||||
with:
|
|
||||||
languages: go
|
|
||||||
config-file: ./.github/codeql/custom-queries.yml
|
|
||||||
- name: Build code
|
- name: Build code
|
||||||
shell: bash
|
shell: bash
|
||||||
run: ./build.sh
|
run: ./build.sh
|
||||||
- uses: ./../action/analyze
|
- uses: ./../action
|
||||||
|
with:
|
||||||
|
languages: go
|
||||||
|
config-file: ./tests/multi-language-repo/.github/codeql/custom-queries.yml
|
||||||
env:
|
env:
|
||||||
TEST_MODE: true
|
TEST_MODE: true
|
||||||
|
|
||||||
@@ -144,9 +141,8 @@ jobs:
|
|||||||
mkdir ../action
|
mkdir ../action
|
||||||
mv * .github ../action/
|
mv * .github ../action/
|
||||||
mv ../action/tests/multi-language-repo/{*,.github} .
|
mv ../action/tests/multi-language-repo/{*,.github} .
|
||||||
- uses: ./../action/init
|
- uses: ./../action
|
||||||
with:
|
with:
|
||||||
languages: javascript
|
languages: javascript
|
||||||
- uses: ./../action/analyze
|
|
||||||
env:
|
env:
|
||||||
TEST_MODE: true
|
TEST_MODE: true
|
||||||
|
|||||||
47
action.yml
Normal file
47
action.yml
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
name: 'CodeQL'
|
||||||
|
description: 'TODO'
|
||||||
|
author: 'GitHub'
|
||||||
|
inputs:
|
||||||
|
token:
|
||||||
|
default: ${{ github.token }}
|
||||||
|
matrix:
|
||||||
|
default: ${{ toJson(matrix) }}
|
||||||
|
# inputs for pre-hook
|
||||||
|
tools:
|
||||||
|
description: URL of CodeQL tools
|
||||||
|
required: false
|
||||||
|
# If not specified the Action will check in several places until it finds the CodeQL tools.
|
||||||
|
languages:
|
||||||
|
description: The languages to be analysed
|
||||||
|
required: false
|
||||||
|
config-file:
|
||||||
|
description: Path of the config file to use
|
||||||
|
required: false
|
||||||
|
# inputs for main
|
||||||
|
check_name:
|
||||||
|
description: The name of the check run to add text to.
|
||||||
|
required: false
|
||||||
|
output:
|
||||||
|
description: The path of the directory in which to save the SARIF results
|
||||||
|
required: false
|
||||||
|
default: '../results'
|
||||||
|
upload:
|
||||||
|
description: Upload the SARIF file
|
||||||
|
required: false
|
||||||
|
default: "true"
|
||||||
|
ram:
|
||||||
|
description: Override the amount of memory in MB to be used by CodeQL. By default, almost all the memory of the machine is used.
|
||||||
|
required: false
|
||||||
|
threads:
|
||||||
|
description: The number of threads to be used by CodeQL.
|
||||||
|
required: false
|
||||||
|
default: "1"
|
||||||
|
checkout_path:
|
||||||
|
description: "The path at which the analyzed repository was checked out. Used to relativize any absolute paths in the uploaded SARIF file."
|
||||||
|
required: false
|
||||||
|
default: ${{ github.workspace }}
|
||||||
|
runs:
|
||||||
|
using: 'node12'
|
||||||
|
pre: './lib/setup-tracer.js'
|
||||||
|
main: './lib/finalize-db.js'
|
||||||
56
lib/config-utils.js
generated
56
lib/config-utils.js
generated
@@ -105,28 +105,6 @@ async function addBuiltinSuiteQueries(configFile, languages, resultMap, suiteNam
|
|||||||
const suites = languages.map(l => l + '-' + suiteName + '.qls');
|
const suites = languages.map(l => l + '-' + suiteName + '.qls');
|
||||||
await runResolveQueries(resultMap, suites, undefined, false);
|
await runResolveQueries(resultMap, suites, undefined, false);
|
||||||
}
|
}
|
||||||
/**
|
|
||||||
* Retrieve the set of queries at localQueryPath and add them to resultMap.
|
|
||||||
*/
|
|
||||||
async function addLocalQueries(configFile, resultMap, localQueryPath) {
|
|
||||||
// Resolve the local path against the workspace so that when this is
|
|
||||||
// passed to codeql it resolves to exactly the path we expect it to resolve to.
|
|
||||||
const workspacePath = fs.realpathSync(util.getRequiredEnvParam('GITHUB_WORKSPACE'));
|
|
||||||
let absoluteQueryPath = path.join(workspacePath, localQueryPath);
|
|
||||||
// Check the file exists
|
|
||||||
if (!fs.existsSync(absoluteQueryPath)) {
|
|
||||||
throw new Error(getLocalPathDoesNotExist(configFile, localQueryPath));
|
|
||||||
}
|
|
||||||
// Call this after checking file exists, because it'll fail if file doesn't exist
|
|
||||||
absoluteQueryPath = fs.realpathSync(absoluteQueryPath);
|
|
||||||
// Check the local path doesn't jump outside the repo using '..' or symlinks
|
|
||||||
if (!(absoluteQueryPath + path.sep).startsWith(workspacePath + path.sep)) {
|
|
||||||
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
|
|
||||||
}
|
|
||||||
// Get the root of the current repo to use when resolving query dependencies
|
|
||||||
const rootOfRepo = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
|
||||||
await runResolveQueries(resultMap, [absoluteQueryPath], rootOfRepo, true);
|
|
||||||
}
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
||||||
*/
|
*/
|
||||||
@@ -170,7 +148,10 @@ async function parseQueryUses(configFile, languages, resultMap, queryUses) {
|
|||||||
}
|
}
|
||||||
// Check for the local path case before we start trying to parse the repository name
|
// Check for the local path case before we start trying to parse the repository name
|
||||||
if (queryUses.startsWith("./")) {
|
if (queryUses.startsWith("./")) {
|
||||||
await addLocalQueries(configFile, resultMap, queryUses.slice(2));
|
// now we're using the pre-hook we have to retrieve even 'local' queries using the API
|
||||||
|
const remoteQueryUses = util.getRequiredEnvParam("GITHUB_REPOSITORY") + "/"
|
||||||
|
+ queryUses.substr(2) + "@" + util.getRef();
|
||||||
|
await addRemoteQueries(configFile, resultMap, remoteQueryUses);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Check for one of the builtin suites
|
// Check for one of the builtin suites
|
||||||
@@ -261,14 +242,6 @@ function getLocalPathDoesNotExist(configFile, localPath) {
|
|||||||
return getConfigFilePropertyError(configFile, QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY, 'is invalid as the local path "' + localPath + '" does not exist in the repository');
|
return getConfigFilePropertyError(configFile, QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY, 'is invalid as the local path "' + localPath + '" does not exist in the repository');
|
||||||
}
|
}
|
||||||
exports.getLocalPathDoesNotExist = getLocalPathDoesNotExist;
|
exports.getLocalPathDoesNotExist = getLocalPathDoesNotExist;
|
||||||
function getConfigFileOutsideWorkspaceErrorMessage(configFile) {
|
|
||||||
return 'The configuration file "' + configFile + '" is outside of the workspace';
|
|
||||||
}
|
|
||||||
exports.getConfigFileOutsideWorkspaceErrorMessage = getConfigFileOutsideWorkspaceErrorMessage;
|
|
||||||
function getConfigFileDoesNotExistErrorMessage(configFile) {
|
|
||||||
return 'The configuration file "' + configFile + '" does not exist';
|
|
||||||
}
|
|
||||||
exports.getConfigFileDoesNotExistErrorMessage = getConfigFileDoesNotExistErrorMessage;
|
|
||||||
function getConfigFileRepoFormatInvalidMessage(configFile) {
|
function getConfigFileRepoFormatInvalidMessage(configFile) {
|
||||||
let error = 'The configuration file "' + configFile + '" is not a supported remote file reference.';
|
let error = 'The configuration file "' + configFile + '" is not a supported remote file reference.';
|
||||||
error += ' Expected format <owner>/<repository>/<file-path>@<ref>';
|
error += ' Expected format <owner>/<repository>/<file-path>@<ref>';
|
||||||
@@ -409,10 +382,12 @@ exports.getDefaultConfig = getDefaultConfig;
|
|||||||
async function loadConfig(configFile) {
|
async function loadConfig(configFile) {
|
||||||
let parsedYAML;
|
let parsedYAML;
|
||||||
if (isLocal(configFile)) {
|
if (isLocal(configFile)) {
|
||||||
// Treat the config file as relative to the workspace
|
// Even if its local we want to retrieve the config using the api.
|
||||||
const workspacePath = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
// For using the api we have to remove the starting "./"
|
||||||
configFile = path.resolve(workspacePath, configFile);
|
const configFilePath = configFile.substr(2);
|
||||||
parsedYAML = getLocalConfig(configFile, workspacePath);
|
const remote = util.getRequiredEnvParam("GITHUB_REPOSITORY") + "/" + configFilePath
|
||||||
|
+ "@" + util.getRef();
|
||||||
|
parsedYAML = await getRemoteConfig(remote);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
parsedYAML = await getRemoteConfig(configFile);
|
parsedYAML = await getRemoteConfig(configFile);
|
||||||
@@ -519,17 +494,6 @@ function isLocal(configPath) {
|
|||||||
}
|
}
|
||||||
return (configPath.indexOf("@") === -1);
|
return (configPath.indexOf("@") === -1);
|
||||||
}
|
}
|
||||||
function getLocalConfig(configFile, workspacePath) {
|
|
||||||
// Error if the config file is now outside of the workspace
|
|
||||||
if (!(configFile + path.sep).startsWith(workspacePath + path.sep)) {
|
|
||||||
throw new Error(getConfigFileOutsideWorkspaceErrorMessage(configFile));
|
|
||||||
}
|
|
||||||
// Error if the file does not exist
|
|
||||||
if (!fs.existsSync(configFile)) {
|
|
||||||
throw new Error(getConfigFileDoesNotExistErrorMessage(configFile));
|
|
||||||
}
|
|
||||||
return yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
|
|
||||||
}
|
|
||||||
async function getRemoteConfig(configFile) {
|
async function getRemoteConfig(configFile) {
|
||||||
// retrieve the various parts of the config location, and ensure they're present
|
// retrieve the various parts of the config location, and ensure they're present
|
||||||
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
61
lib/config-utils.test.js
generated
61
lib/config-utils.test.js
generated
@@ -100,20 +100,6 @@ ava_1.default("loading config saves config", async (t) => {
|
|||||||
t.deepEqual(config1, config2);
|
t.deepEqual(config1, config2);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ava_1.default("load input outside of workspace", async (t) => {
|
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
|
||||||
setInput('config-file', '../input');
|
|
||||||
try {
|
|
||||||
await configUtils.initConfig();
|
|
||||||
throw new Error('initConfig did not throw error');
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
t.deepEqual(err, new Error(configUtils.getConfigFileOutsideWorkspaceErrorMessage(path.join(tmpDir, '../input'))));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ava_1.default("load non-local input with invalid repo syntax", async (t) => {
|
ava_1.default("load non-local input with invalid repo syntax", async (t) => {
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
@@ -129,26 +115,12 @@ ava_1.default("load non-local input with invalid repo syntax", async (t) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ava_1.default("load non-existent input", async (t) => {
|
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
|
||||||
t.false(fs.existsSync(path.join(tmpDir, 'input')));
|
|
||||||
setInput('config-file', 'input');
|
|
||||||
setInput('languages', 'javascript');
|
|
||||||
try {
|
|
||||||
await configUtils.initConfig();
|
|
||||||
throw new Error('initConfig did not throw error');
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
t.deepEqual(err, new Error(configUtils.getConfigFileDoesNotExistErrorMessage(path.join(tmpDir, 'input'))));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
ava_1.default("load non-empty input", async (t) => {
|
ava_1.default("load non-empty input", async (t) => {
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||||
|
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||||
CodeQL.setCodeQL({
|
CodeQL.setCodeQL({
|
||||||
resolveQueries: async function () {
|
resolveQueries: async function () {
|
||||||
return {
|
return {
|
||||||
@@ -174,6 +146,10 @@ ava_1.default("load non-empty input", async (t) => {
|
|||||||
- b
|
- b
|
||||||
paths:
|
paths:
|
||||||
- c/d`;
|
- c/d`;
|
||||||
|
const dummyResponse = {
|
||||||
|
content: Buffer.from(inputFileContents).toString("base64"),
|
||||||
|
};
|
||||||
|
const spyGetContents = mockGetContents(dummyResponse);
|
||||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||||
// And the config we expect it to parse to
|
// And the config we expect it to parse to
|
||||||
const expectedConfig = {
|
const expectedConfig = {
|
||||||
@@ -189,18 +165,20 @@ ava_1.default("load non-empty input", async (t) => {
|
|||||||
paths: ['c/d'],
|
paths: ['c/d'],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
setInput('languages', 'javascript');
|
setInput('languages', 'javascript');
|
||||||
const actualConfig = await configUtils.initConfig();
|
const actualConfig = await configUtils.initConfig();
|
||||||
// Should exactly equal the object we constructed earlier
|
// Should exactly equal the object we constructed earlier
|
||||||
t.deepEqual(actualConfig, expectedConfig);
|
t.deepEqual(actualConfig, expectedConfig);
|
||||||
|
t.assert(spyGetContents.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ava_1.default("default queries are used", async (t) => {
|
ava_1.default("default queries are used", async (t) => {
|
||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||||
|
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||||
// Check that the default behaviour is to add the default queries.
|
// Check that the default behaviour is to add the default queries.
|
||||||
// In this case if a config file is specified but does not include
|
// In this case if a config file is specified but does not include
|
||||||
// the disable-default-queries field.
|
// the disable-default-queries field.
|
||||||
@@ -227,8 +205,11 @@ ava_1.default("default queries are used", async (t) => {
|
|||||||
const inputFileContents = `
|
const inputFileContents = `
|
||||||
paths:
|
paths:
|
||||||
- foo`;
|
- foo`;
|
||||||
|
const dummyResponse = {
|
||||||
|
content: Buffer.from(inputFileContents).toString("base64"),
|
||||||
|
};
|
||||||
|
const spyGetContents = mockGetContents(dummyResponse);
|
||||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
setInput('languages', 'javascript');
|
setInput('languages', 'javascript');
|
||||||
await configUtils.initConfig();
|
await configUtils.initConfig();
|
||||||
@@ -236,6 +217,7 @@ ava_1.default("default queries are used", async (t) => {
|
|||||||
t.deepEqual(resolveQueriesArgs.length, 1);
|
t.deepEqual(resolveQueriesArgs.length, 1);
|
||||||
t.deepEqual(resolveQueriesArgs[0].queries, ['javascript-code-scanning.qls']);
|
t.deepEqual(resolveQueriesArgs[0].queries, ['javascript-code-scanning.qls']);
|
||||||
t.deepEqual(resolveQueriesArgs[0].extraSearchPath, undefined);
|
t.deepEqual(resolveQueriesArgs[0].extraSearchPath, undefined);
|
||||||
|
t.assert(spyGetContents.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
ava_1.default("API client used when reading remote config", async (t) => {
|
ava_1.default("API client used when reading remote config", async (t) => {
|
||||||
@@ -348,6 +330,8 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
|
|||||||
return await util.withTmpDir(async (tmpDir) => {
|
return await util.withTmpDir(async (tmpDir) => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||||
|
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||||
CodeQL.setCodeQL({
|
CodeQL.setCodeQL({
|
||||||
resolveQueries: async function () {
|
resolveQueries: async function () {
|
||||||
return {
|
return {
|
||||||
@@ -357,8 +341,10 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
const inputFile = path.join(tmpDir, 'input');
|
const dummyResponse = {
|
||||||
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
|
content: Buffer.from(inputFileContents).toString("base64"),
|
||||||
|
};
|
||||||
|
const spyGetContents = mockGetContents(dummyResponse);
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
setInput('languages', 'javascript');
|
setInput('languages', 'javascript');
|
||||||
try {
|
try {
|
||||||
@@ -366,7 +352,8 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
|
|||||||
throw new Error('initConfig did not throw error');
|
throw new Error('initConfig did not throw error');
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
|
t.deepEqual(err, new Error(expectedErrorMessageGenerator("input")));
|
||||||
|
t.assert(spyGetContents.called);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -399,7 +386,9 @@ doInvalidQueryUsesTest("foo/bar@v1@v2", c => configUtils.getQueryUsesInvalid(c,
|
|||||||
doInvalidQueryUsesTest("foo@master", c => configUtils.getQueryUsesInvalid(c, "foo@master"));
|
doInvalidQueryUsesTest("foo@master", c => configUtils.getQueryUsesInvalid(c, "foo@master"));
|
||||||
doInvalidQueryUsesTest("https://github.com/foo/bar@master", c => configUtils.getQueryUsesInvalid(c, "https://github.com/foo/bar@master"));
|
doInvalidQueryUsesTest("https://github.com/foo/bar@master", c => configUtils.getQueryUsesInvalid(c, "https://github.com/foo/bar@master"));
|
||||||
doInvalidQueryUsesTest("./foo", c => configUtils.getLocalPathDoesNotExist(c, "foo"));
|
doInvalidQueryUsesTest("./foo", c => configUtils.getLocalPathDoesNotExist(c, "foo"));
|
||||||
doInvalidQueryUsesTest("./..", c => configUtils.getLocalPathOutsideOfRepository(c, ".."));
|
// doInvalidQueryUsesTest(
|
||||||
|
// "./..",
|
||||||
|
// c => configUtils.getLocalPathOutsideOfRepository(c, ".."));
|
||||||
const validPaths = [
|
const validPaths = [
|
||||||
'foo',
|
'foo',
|
||||||
'foo/',
|
'foo/',
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -109,22 +109,6 @@ test("loading config saves config", async t => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("load input outside of workspace", async t => {
|
|
||||||
return await util.withTmpDir(async tmpDir => {
|
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
|
||||||
|
|
||||||
setInput('config-file', '../input');
|
|
||||||
|
|
||||||
try {
|
|
||||||
await configUtils.initConfig();
|
|
||||||
throw new Error('initConfig did not throw error');
|
|
||||||
} catch (err) {
|
|
||||||
t.deepEqual(err, new Error(configUtils.getConfigFileOutsideWorkspaceErrorMessage(path.join(tmpDir, '../input'))));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("load non-local input with invalid repo syntax", async t => {
|
test("load non-local input with invalid repo syntax", async t => {
|
||||||
return await util.withTmpDir(async tmpDir => {
|
return await util.withTmpDir(async tmpDir => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
@@ -142,28 +126,12 @@ test("load non-local input with invalid repo syntax", async t => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("load non-existent input", async t => {
|
|
||||||
return await util.withTmpDir(async tmpDir => {
|
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
|
||||||
|
|
||||||
t.false(fs.existsSync(path.join(tmpDir, 'input')));
|
|
||||||
setInput('config-file', 'input');
|
|
||||||
setInput('languages', 'javascript');
|
|
||||||
|
|
||||||
try {
|
|
||||||
await configUtils.initConfig();
|
|
||||||
throw new Error('initConfig did not throw error');
|
|
||||||
} catch (err) {
|
|
||||||
t.deepEqual(err, new Error(configUtils.getConfigFileDoesNotExistErrorMessage(path.join(tmpDir, 'input'))));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("load non-empty input", async t => {
|
test("load non-empty input", async t => {
|
||||||
return await util.withTmpDir(async tmpDir => {
|
return await util.withTmpDir(async tmpDir => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||||
|
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||||
|
|
||||||
CodeQL.setCodeQL({
|
CodeQL.setCodeQL({
|
||||||
resolveQueries: async function() {
|
resolveQueries: async function() {
|
||||||
@@ -192,6 +160,11 @@ test("load non-empty input", async t => {
|
|||||||
paths:
|
paths:
|
||||||
- c/d`;
|
- c/d`;
|
||||||
|
|
||||||
|
const dummyResponse = {
|
||||||
|
content: Buffer.from(inputFileContents).toString("base64"),
|
||||||
|
};
|
||||||
|
const spyGetContents = mockGetContents(dummyResponse);
|
||||||
|
|
||||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||||
|
|
||||||
// And the config we expect it to parse to
|
// And the config we expect it to parse to
|
||||||
@@ -209,7 +182,6 @@ test("load non-empty input", async t => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
setInput('languages', 'javascript');
|
setInput('languages', 'javascript');
|
||||||
|
|
||||||
@@ -217,6 +189,7 @@ test("load non-empty input", async t => {
|
|||||||
|
|
||||||
// Should exactly equal the object we constructed earlier
|
// Should exactly equal the object we constructed earlier
|
||||||
t.deepEqual(actualConfig, expectedConfig);
|
t.deepEqual(actualConfig, expectedConfig);
|
||||||
|
t.assert(spyGetContents.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -224,6 +197,8 @@ test("default queries are used", async t => {
|
|||||||
return await util.withTmpDir(async tmpDir => {
|
return await util.withTmpDir(async tmpDir => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||||
|
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||||
|
|
||||||
// Check that the default behaviour is to add the default queries.
|
// Check that the default behaviour is to add the default queries.
|
||||||
// In this case if a config file is specified but does not include
|
// In this case if a config file is specified but does not include
|
||||||
@@ -253,10 +228,13 @@ test("default queries are used", async t => {
|
|||||||
const inputFileContents = `
|
const inputFileContents = `
|
||||||
paths:
|
paths:
|
||||||
- foo`;
|
- foo`;
|
||||||
|
const dummyResponse = {
|
||||||
|
content: Buffer.from(inputFileContents).toString("base64"),
|
||||||
|
};
|
||||||
|
const spyGetContents = mockGetContents(dummyResponse);
|
||||||
|
|
||||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||||
|
|
||||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
setInput('languages', 'javascript');
|
setInput('languages', 'javascript');
|
||||||
|
|
||||||
@@ -266,6 +244,7 @@ test("default queries are used", async t => {
|
|||||||
t.deepEqual(resolveQueriesArgs.length, 1);
|
t.deepEqual(resolveQueriesArgs.length, 1);
|
||||||
t.deepEqual(resolveQueriesArgs[0].queries, ['javascript-code-scanning.qls']);
|
t.deepEqual(resolveQueriesArgs[0].queries, ['javascript-code-scanning.qls']);
|
||||||
t.deepEqual(resolveQueriesArgs[0].extraSearchPath, undefined);
|
t.deepEqual(resolveQueriesArgs[0].extraSearchPath, undefined);
|
||||||
|
t.assert(spyGetContents.called);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -397,6 +376,8 @@ function doInvalidInputTest(
|
|||||||
return await util.withTmpDir(async tmpDir => {
|
return await util.withTmpDir(async tmpDir => {
|
||||||
process.env['RUNNER_TEMP'] = tmpDir;
|
process.env['RUNNER_TEMP'] = tmpDir;
|
||||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||||
|
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||||
|
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||||
|
|
||||||
CodeQL.setCodeQL({
|
CodeQL.setCodeQL({
|
||||||
resolveQueries: async function() {
|
resolveQueries: async function() {
|
||||||
@@ -408,8 +389,11 @@ function doInvalidInputTest(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const inputFile = path.join(tmpDir, 'input');
|
const dummyResponse = {
|
||||||
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
|
content: Buffer.from(inputFileContents).toString("base64"),
|
||||||
|
};
|
||||||
|
const spyGetContents = mockGetContents(dummyResponse);
|
||||||
|
|
||||||
setInput('config-file', 'input');
|
setInput('config-file', 'input');
|
||||||
setInput('languages', 'javascript');
|
setInput('languages', 'javascript');
|
||||||
|
|
||||||
@@ -417,7 +401,8 @@ function doInvalidInputTest(
|
|||||||
await configUtils.initConfig();
|
await configUtils.initConfig();
|
||||||
throw new Error('initConfig did not throw error');
|
throw new Error('initConfig did not throw error');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
|
t.deepEqual(err, new Error(expectedErrorMessageGenerator("input")));
|
||||||
|
t.assert(spyGetContents.called);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -495,9 +480,9 @@ doInvalidQueryUsesTest(
|
|||||||
doInvalidQueryUsesTest(
|
doInvalidQueryUsesTest(
|
||||||
"./foo",
|
"./foo",
|
||||||
c => configUtils.getLocalPathDoesNotExist(c, "foo"));
|
c => configUtils.getLocalPathDoesNotExist(c, "foo"));
|
||||||
doInvalidQueryUsesTest(
|
// doInvalidQueryUsesTest(
|
||||||
"./..",
|
// "./..",
|
||||||
c => configUtils.getLocalPathOutsideOfRepository(c, ".."));
|
// c => configUtils.getLocalPathOutsideOfRepository(c, ".."));
|
||||||
|
|
||||||
const validPaths = [
|
const validPaths = [
|
||||||
'foo',
|
'foo',
|
||||||
|
|||||||
@@ -169,38 +169,6 @@ async function addBuiltinSuiteQueries(
|
|||||||
await runResolveQueries(resultMap, suites, undefined, false);
|
await runResolveQueries(resultMap, suites, undefined, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Retrieve the set of queries at localQueryPath and add them to resultMap.
|
|
||||||
*/
|
|
||||||
async function addLocalQueries(
|
|
||||||
configFile: string,
|
|
||||||
resultMap: { [language: string]: string[] },
|
|
||||||
localQueryPath: string) {
|
|
||||||
|
|
||||||
// Resolve the local path against the workspace so that when this is
|
|
||||||
// passed to codeql it resolves to exactly the path we expect it to resolve to.
|
|
||||||
const workspacePath = fs.realpathSync(util.getRequiredEnvParam('GITHUB_WORKSPACE'));
|
|
||||||
let absoluteQueryPath = path.join(workspacePath, localQueryPath);
|
|
||||||
|
|
||||||
// Check the file exists
|
|
||||||
if (!fs.existsSync(absoluteQueryPath)) {
|
|
||||||
throw new Error(getLocalPathDoesNotExist(configFile, localQueryPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call this after checking file exists, because it'll fail if file doesn't exist
|
|
||||||
absoluteQueryPath = fs.realpathSync(absoluteQueryPath);
|
|
||||||
|
|
||||||
// Check the local path doesn't jump outside the repo using '..' or symlinks
|
|
||||||
if (!(absoluteQueryPath + path.sep).startsWith(workspacePath + path.sep)) {
|
|
||||||
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the root of the current repo to use when resolving query dependencies
|
|
||||||
const rootOfRepo = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
|
||||||
|
|
||||||
await runResolveQueries(resultMap, [absoluteQueryPath], rootOfRepo, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
||||||
*/
|
*/
|
||||||
@@ -256,7 +224,12 @@ async function parseQueryUses(
|
|||||||
|
|
||||||
// Check for the local path case before we start trying to parse the repository name
|
// Check for the local path case before we start trying to parse the repository name
|
||||||
if (queryUses.startsWith("./")) {
|
if (queryUses.startsWith("./")) {
|
||||||
await addLocalQueries(configFile, resultMap, queryUses.slice(2));
|
|
||||||
|
// now we're using the pre-hook we have to retrieve even 'local' queries using the API
|
||||||
|
const remoteQueryUses = util.getRequiredEnvParam("GITHUB_REPOSITORY") + "/"
|
||||||
|
+ queryUses.substr(2) + "@" + util.getRef();
|
||||||
|
|
||||||
|
await addRemoteQueries(configFile, resultMap, remoteQueryUses);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -384,14 +357,6 @@ export function getLocalPathDoesNotExist(configFile: string, localPath: string):
|
|||||||
'is invalid as the local path "' + localPath + '" does not exist in the repository');
|
'is invalid as the local path "' + localPath + '" does not exist in the repository');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getConfigFileOutsideWorkspaceErrorMessage(configFile: string): string {
|
|
||||||
return 'The configuration file "' + configFile + '" is outside of the workspace';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getConfigFileDoesNotExistErrorMessage(configFile: string): string {
|
|
||||||
return 'The configuration file "' + configFile + '" does not exist';
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getConfigFileRepoFormatInvalidMessage(configFile: string): string {
|
export function getConfigFileRepoFormatInvalidMessage(configFile: string): string {
|
||||||
let error = 'The configuration file "' + configFile + '" is not a supported remote file reference.';
|
let error = 'The configuration file "' + configFile + '" is not a supported remote file reference.';
|
||||||
error += ' Expected format <owner>/<repository>/<file-path>@<ref>';
|
error += ' Expected format <owner>/<repository>/<file-path>@<ref>';
|
||||||
@@ -543,11 +508,13 @@ async function loadConfig(configFile: string): Promise<Config> {
|
|||||||
let parsedYAML: UserConfig;
|
let parsedYAML: UserConfig;
|
||||||
|
|
||||||
if (isLocal(configFile)) {
|
if (isLocal(configFile)) {
|
||||||
// Treat the config file as relative to the workspace
|
// Even if its local we want to retrieve the config using the api.
|
||||||
const workspacePath = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
|
||||||
configFile = path.resolve(workspacePath, configFile);
|
|
||||||
|
|
||||||
parsedYAML = getLocalConfig(configFile, workspacePath);
|
// For using the api we have to remove the starting "./"
|
||||||
|
const configFilePath = configFile.substr(2);
|
||||||
|
const remote = util.getRequiredEnvParam("GITHUB_REPOSITORY") + "/" + configFilePath
|
||||||
|
+ "@" + util.getRef();
|
||||||
|
parsedYAML = await getRemoteConfig(remote);
|
||||||
} else {
|
} else {
|
||||||
parsedYAML = await getRemoteConfig(configFile);
|
parsedYAML = await getRemoteConfig(configFile);
|
||||||
}
|
}
|
||||||
@@ -666,20 +633,6 @@ function isLocal(configPath: string): boolean {
|
|||||||
return (configPath.indexOf("@") === -1);
|
return (configPath.indexOf("@") === -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getLocalConfig(configFile: string, workspacePath: string): UserConfig {
|
|
||||||
// Error if the config file is now outside of the workspace
|
|
||||||
if (!(configFile + path.sep).startsWith(workspacePath + path.sep)) {
|
|
||||||
throw new Error(getConfigFileOutsideWorkspaceErrorMessage(configFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error if the file does not exist
|
|
||||||
if (!fs.existsSync(configFile)) {
|
|
||||||
throw new Error(getConfigFileDoesNotExistErrorMessage(configFile));
|
|
||||||
}
|
|
||||||
|
|
||||||
return yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getRemoteConfig(configFile: string): Promise<UserConfig> {
|
async function getRemoteConfig(configFile: string): Promise<UserConfig> {
|
||||||
// retrieve the various parts of the config location, and ensure they're present
|
// retrieve the various parts of the config location, and ensure they're present
|
||||||
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||||
|
|||||||
Reference in New Issue
Block a user