mirror of
https://github.com/github/codeql-action.git
synced 2025-12-07 00:08:06 +08:00
Compare commits
4 Commits
codeql-bun
...
config
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
745aace275 | ||
|
|
6ebd919fb7 | ||
|
|
2998d02818 | ||
|
|
d96885a274 |
2
.github/workflows/integration-testing.yml
vendored
2
.github/workflows/integration-testing.yml
vendored
@@ -85,7 +85,7 @@ jobs:
|
||||
- uses: ./../action/init
|
||||
with:
|
||||
languages: go
|
||||
config-file: ./.github/codeql/custom-queries.yml
|
||||
config-file: ./tests/multi-language-repo/.github/codeql/custom-queries.yml
|
||||
- name: Build code
|
||||
shell: bash
|
||||
run: ./build.sh
|
||||
|
||||
76
lib/config-utils.js
generated
76
lib/config-utils.js
generated
@@ -105,32 +105,7 @@ async function addBuiltinSuiteQueries(configFile, languages, resultMap, suiteNam
|
||||
const suites = languages.map(l => l + '-' + suiteName + '.qls');
|
||||
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.
|
||||
*/
|
||||
async function addRemoteQueries(configFile, resultMap, queryUses) {
|
||||
function parseRemoteQueryUses(configFile, queryUses) {
|
||||
let tok = queryUses.split('@');
|
||||
if (tok.length !== 2) {
|
||||
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
||||
@@ -148,12 +123,18 @@ async function addRemoteQueries(configFile, resultMap, queryUses) {
|
||||
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
||||
}
|
||||
const nwo = tok[0] + '/' + tok[1];
|
||||
const queryPath = tok.length > 2
|
||||
? tok.slice(2).join('/')
|
||||
: '';
|
||||
return [nwo, queryPath, ref];
|
||||
}
|
||||
/**
|
||||
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
||||
*/
|
||||
async function addRemoteQueries(resultMap, nwo, queryPath, ref) {
|
||||
// Checkout the external repository
|
||||
const rootOfRepo = await externalQueries.checkoutExternalRepository(nwo, ref);
|
||||
const queryPath = tok.length > 2
|
||||
? path.join(rootOfRepo, tok.slice(2).join('/'))
|
||||
: rootOfRepo;
|
||||
await runResolveQueries(resultMap, [queryPath], rootOfRepo, true);
|
||||
await runResolveQueries(resultMap, [path.join(rootOfRepo, queryPath)], rootOfRepo, true);
|
||||
}
|
||||
/**
|
||||
* Parse a query 'uses' field to a discrete set of query files and update resultMap.
|
||||
@@ -170,7 +151,8 @@ async function parseQueryUses(configFile, languages, resultMap, queryUses) {
|
||||
}
|
||||
// Check for the local path case before we start trying to parse the repository name
|
||||
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
|
||||
await addRemoteQueries(resultMap, util.getRequiredEnvParam("GITHUB_REPOSITORY"), queryUses.substr(2), util.getRef());
|
||||
return;
|
||||
}
|
||||
// Check for one of the builtin suites
|
||||
@@ -179,7 +161,8 @@ async function parseQueryUses(configFile, languages, resultMap, queryUses) {
|
||||
return;
|
||||
}
|
||||
// Otherwise, must be a reference to another repo
|
||||
await addRemoteQueries(configFile, resultMap, queryUses);
|
||||
const [nwo, queryPath, ref] = parseRemoteQueryUses(configFile, queryUses);
|
||||
await addRemoteQueries(resultMap, nwo, queryPath, ref);
|
||||
}
|
||||
// Regex validating stars in paths or paths-ignore entries.
|
||||
// The intention is to only allow ** to appear when immediately
|
||||
@@ -261,14 +244,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');
|
||||
}
|
||||
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) {
|
||||
let error = 'The configuration file "' + configFile + '" is not a supported remote file reference.';
|
||||
error += ' Expected format <owner>/<repository>/<file-path>@<ref>';
|
||||
@@ -409,10 +384,12 @@ exports.getDefaultConfig = getDefaultConfig;
|
||||
async function loadConfig(configFile) {
|
||||
let parsedYAML;
|
||||
if (isLocal(configFile)) {
|
||||
// Treat the config file as relative to the workspace
|
||||
const workspacePath = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
||||
configFile = path.resolve(workspacePath, configFile);
|
||||
parsedYAML = getLocalConfig(configFile, workspacePath);
|
||||
// Even if its local we want to retrieve the config using the api.
|
||||
// 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 {
|
||||
parsedYAML = await getRemoteConfig(configFile);
|
||||
@@ -519,17 +496,6 @@ function isLocal(configPath) {
|
||||
}
|
||||
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) {
|
||||
// retrieve the various parts of the config location, and ensure they're present
|
||||
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||
|
||||
File diff suppressed because one or more lines are too long
64
lib/config-utils.test.js
generated
64
lib/config-utils.test.js
generated
@@ -100,20 +100,6 @@ ava_1.default("loading config saves config", async (t) => {
|
||||
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) => {
|
||||
return await util.withTmpDir(async (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) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
process.env['RUNNER_TEMP'] = tmpDir;
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||
CodeQL.setCodeQL({
|
||||
resolveQueries: async function () {
|
||||
return {
|
||||
@@ -174,7 +146,12 @@ ava_1.default("load non-empty input", async (t) => {
|
||||
- b
|
||||
paths:
|
||||
- c/d`;
|
||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
// Create checkout directory for remote queries repository
|
||||
fs.mkdirSync(path.join(tmpDir, 'octo-org/codeql-config'), { recursive: true });
|
||||
// And the config we expect it to parse to
|
||||
const expectedConfig = {
|
||||
languages: ['javascript'],
|
||||
@@ -189,18 +166,20 @@ ava_1.default("load non-empty input", async (t) => {
|
||||
paths: ['c/d'],
|
||||
},
|
||||
};
|
||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
||||
setInput('config-file', 'input');
|
||||
setInput('languages', 'javascript');
|
||||
const actualConfig = await configUtils.initConfig();
|
||||
// Should exactly equal the object we constructed earlier
|
||||
t.deepEqual(actualConfig, expectedConfig);
|
||||
t.assert(spyGetContents.called);
|
||||
});
|
||||
});
|
||||
ava_1.default("default queries are used", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
process.env['RUNNER_TEMP'] = 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.
|
||||
// In this case if a config file is specified but does not include
|
||||
// the disable-default-queries field.
|
||||
@@ -227,8 +206,11 @@ ava_1.default("default queries are used", async (t) => {
|
||||
const inputFileContents = `
|
||||
paths:
|
||||
- foo`;
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
||||
setInput('config-file', 'input');
|
||||
setInput('languages', 'javascript');
|
||||
await configUtils.initConfig();
|
||||
@@ -236,12 +218,15 @@ ava_1.default("default queries are used", async (t) => {
|
||||
t.deepEqual(resolveQueriesArgs.length, 1);
|
||||
t.deepEqual(resolveQueriesArgs[0].queries, ['javascript-code-scanning.qls']);
|
||||
t.deepEqual(resolveQueriesArgs[0].extraSearchPath, undefined);
|
||||
t.assert(spyGetContents.called);
|
||||
});
|
||||
});
|
||||
ava_1.default("API client used when reading remote config", async (t) => {
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
process.env['RUNNER_TEMP'] = tmpDir;
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
process.env['GITHUB_REPOSITORY'] = 'foo/bar';
|
||||
process.env['GITHUB_REF'] = 'master';
|
||||
CodeQL.setCodeQL({
|
||||
resolveQueries: async function () {
|
||||
return {
|
||||
@@ -348,6 +333,8 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
|
||||
return await util.withTmpDir(async (tmpDir) => {
|
||||
process.env['RUNNER_TEMP'] = tmpDir;
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||
process.env["GITHUB_REF"] = "master";
|
||||
CodeQL.setCodeQL({
|
||||
resolveQueries: async function () {
|
||||
return {
|
||||
@@ -357,8 +344,12 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
|
||||
};
|
||||
},
|
||||
});
|
||||
const inputFile = path.join(tmpDir, 'input');
|
||||
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
// Create checkout directory for remote queries repository
|
||||
fs.mkdirSync(path.join(tmpDir, 'octo-org/codeql-config'), { recursive: true });
|
||||
setInput('config-file', 'input');
|
||||
setInput('languages', 'javascript');
|
||||
try {
|
||||
@@ -366,7 +357,8 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
|
||||
throw new Error('initConfig did not throw error');
|
||||
}
|
||||
catch (err) {
|
||||
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
|
||||
t.deepEqual(err, new Error(expectedErrorMessageGenerator("input")));
|
||||
t.assert(spyGetContents.called);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
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 => {
|
||||
return await util.withTmpDir(async 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 => {
|
||||
return await util.withTmpDir(async tmpDir => {
|
||||
process.env['RUNNER_TEMP'] = tmpDir;
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||
process.env["GITHUB_REF"] = "refs/heads/main";
|
||||
|
||||
CodeQL.setCodeQL({
|
||||
resolveQueries: async function() {
|
||||
@@ -192,7 +160,13 @@ test("load non-empty input", async t => {
|
||||
paths:
|
||||
- c/d`;
|
||||
|
||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
|
||||
// Create checkout directory for remote queries repository
|
||||
fs.mkdirSync(path.join(tmpDir, 'octo-org/codeql-config'), { recursive: true });
|
||||
|
||||
// And the config we expect it to parse to
|
||||
const expectedConfig: configUtils.Config = {
|
||||
@@ -209,7 +183,6 @@ test("load non-empty input", async t => {
|
||||
},
|
||||
};
|
||||
|
||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
||||
setInput('config-file', 'input');
|
||||
setInput('languages', 'javascript');
|
||||
|
||||
@@ -217,6 +190,7 @@ test("load non-empty input", async t => {
|
||||
|
||||
// Should exactly equal the object we constructed earlier
|
||||
t.deepEqual(actualConfig, expectedConfig);
|
||||
t.assert(spyGetContents.called);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -224,6 +198,8 @@ test("default queries are used", async t => {
|
||||
return await util.withTmpDir(async tmpDir => {
|
||||
process.env['RUNNER_TEMP'] = 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.
|
||||
// In this case if a config file is specified but does not include
|
||||
@@ -253,10 +229,13 @@ test("default queries are used", async t => {
|
||||
const inputFileContents = `
|
||||
paths:
|
||||
- foo`;
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
|
||||
fs.mkdirSync(path.join(tmpDir, 'foo'));
|
||||
|
||||
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
|
||||
setInput('config-file', 'input');
|
||||
setInput('languages', 'javascript');
|
||||
|
||||
@@ -266,6 +245,7 @@ test("default queries are used", async t => {
|
||||
t.deepEqual(resolveQueriesArgs.length, 1);
|
||||
t.deepEqual(resolveQueriesArgs[0].queries, ['javascript-code-scanning.qls']);
|
||||
t.deepEqual(resolveQueriesArgs[0].extraSearchPath, undefined);
|
||||
t.assert(spyGetContents.called);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -273,6 +253,8 @@ test("API client used when reading remote config", async t => {
|
||||
return await util.withTmpDir(async tmpDir => {
|
||||
process.env['RUNNER_TEMP'] = tmpDir;
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
process.env['GITHUB_REPOSITORY'] = 'foo/bar';
|
||||
process.env['GITHUB_REF'] = 'master';
|
||||
|
||||
CodeQL.setCodeQL({
|
||||
resolveQueries: async function() {
|
||||
@@ -397,6 +379,8 @@ function doInvalidInputTest(
|
||||
return await util.withTmpDir(async tmpDir => {
|
||||
process.env['RUNNER_TEMP'] = tmpDir;
|
||||
process.env['GITHUB_WORKSPACE'] = tmpDir;
|
||||
process.env['GITHUB_REPOSITORY'] = "octo-org/codeql-config";
|
||||
process.env["GITHUB_REF"] = "master";
|
||||
|
||||
CodeQL.setCodeQL({
|
||||
resolveQueries: async function() {
|
||||
@@ -408,8 +392,14 @@ function doInvalidInputTest(
|
||||
},
|
||||
});
|
||||
|
||||
const inputFile = path.join(tmpDir, 'input');
|
||||
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
|
||||
const dummyResponse = {
|
||||
content: Buffer.from(inputFileContents).toString("base64"),
|
||||
};
|
||||
const spyGetContents = mockGetContents(dummyResponse);
|
||||
|
||||
// Create checkout directory for remote queries repository
|
||||
fs.mkdirSync(path.join(tmpDir, 'octo-org/codeql-config'), { recursive: true });
|
||||
|
||||
setInput('config-file', 'input');
|
||||
setInput('languages', 'javascript');
|
||||
|
||||
@@ -417,7 +407,8 @@ function doInvalidInputTest(
|
||||
await configUtils.initConfig();
|
||||
throw new Error('initConfig did not throw error');
|
||||
} catch (err) {
|
||||
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
|
||||
t.deepEqual(err, new Error(expectedErrorMessageGenerator("input")));
|
||||
t.assert(spyGetContents.called);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -169,42 +169,8 @@ async function addBuiltinSuiteQueries(
|
||||
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) {
|
||||
function parseRemoteQueryUses(configFile: string, queryUses: 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.
|
||||
*/
|
||||
async function addRemoteQueries(configFile: string, resultMap: { [language: string]: string[] }, queryUses: string) {
|
||||
let tok = queryUses.split('@');
|
||||
if (tok.length !== 2) {
|
||||
throw new Error(getQueryUsesInvalid(configFile, queryUses));
|
||||
@@ -225,14 +191,23 @@ async function addRemoteQueries(configFile: string, resultMap: { [language: stri
|
||||
}
|
||||
const nwo = tok[0] + '/' + tok[1];
|
||||
|
||||
const queryPath = tok.length > 2
|
||||
? tok.slice(2).join('/')
|
||||
: '';
|
||||
|
||||
return [nwo, queryPath, ref];
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the set of queries at the referenced remote repo and add them to resultMap.
|
||||
*/
|
||||
async function addRemoteQueries(resultMap: { [language: string]: string[] },
|
||||
nwo: string, queryPath: string, ref: string) {
|
||||
|
||||
// Checkout the external repository
|
||||
const rootOfRepo = await externalQueries.checkoutExternalRepository(nwo, ref);
|
||||
|
||||
const queryPath = tok.length > 2
|
||||
? path.join(rootOfRepo, tok.slice(2).join('/'))
|
||||
: rootOfRepo;
|
||||
|
||||
await runResolveQueries(resultMap, [queryPath], rootOfRepo, true);
|
||||
await runResolveQueries(resultMap, [path.join(rootOfRepo, queryPath)], rootOfRepo, true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,7 +231,9 @@ async function parseQueryUses(
|
||||
|
||||
// Check for the local path case before we start trying to parse the repository name
|
||||
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
|
||||
await addRemoteQueries(resultMap, util.getRequiredEnvParam("GITHUB_REPOSITORY"),
|
||||
queryUses.substr(2), util.getRef());
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -267,7 +244,8 @@ async function parseQueryUses(
|
||||
}
|
||||
|
||||
// Otherwise, must be a reference to another repo
|
||||
await addRemoteQueries(configFile, resultMap, queryUses);
|
||||
const [nwo, queryPath, ref] = parseRemoteQueryUses(configFile, queryUses);
|
||||
await addRemoteQueries(resultMap, nwo, queryPath, ref);
|
||||
}
|
||||
|
||||
// Regex validating stars in paths or paths-ignore entries.
|
||||
@@ -384,14 +362,6 @@ export function getLocalPathDoesNotExist(configFile: string, localPath: string):
|
||||
'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 {
|
||||
let error = 'The configuration file "' + configFile + '" is not a supported remote file reference.';
|
||||
error += ' Expected format <owner>/<repository>/<file-path>@<ref>';
|
||||
@@ -543,11 +513,13 @@ async function loadConfig(configFile: string): Promise<Config> {
|
||||
let parsedYAML: UserConfig;
|
||||
|
||||
if (isLocal(configFile)) {
|
||||
// Treat the config file as relative to the workspace
|
||||
const workspacePath = util.getRequiredEnvParam('GITHUB_WORKSPACE');
|
||||
configFile = path.resolve(workspacePath, configFile);
|
||||
// Even if its local we want to retrieve the config using the api.
|
||||
|
||||
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 {
|
||||
parsedYAML = await getRemoteConfig(configFile);
|
||||
}
|
||||
@@ -666,20 +638,6 @@ function isLocal(configPath: string): boolean {
|
||||
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> {
|
||||
// retrieve the various parts of the config location, and ensure they're present
|
||||
const format = new RegExp('(?<owner>[^/]+)/(?<repo>[^/]+)/(?<path>[^@]+)@(?<ref>.*)');
|
||||
|
||||
Reference in New Issue
Block a user