Merge pull request #60 from github/update-v1-6bd7f17

Merge master into v1
This commit is contained in:
Robert 2020-06-15 10:40:53 +01:00 committed by GitHub
commit c13712badb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 644 additions and 554 deletions

178
.github/update-release-branch.py vendored Normal file
View file

@ -0,0 +1,178 @@
import datetime
from github import Github
import random
import requests
import subprocess
import sys
# The branch being merged from.
# This is the one that contains day-to-day development work.
MASTER_BRANCH = 'master'
# The branch being merged into.
# This is the release branch that users reference.
LATEST_RELEASE_BRANCH = 'v1'
# Name of the remote
ORIGIN = 'origin'
# Runs git with the given args and returns the stdout.
# Raises an error if git does not exit successfully.
def run_git(*args):
cmd = ['git', *args]
p = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
if (p.returncode != 0):
raise Exception('Call to ' + ' '.join(cmd) + ' exited with code ' + str(p.returncode) + ' stderr:' + p.stderr.decode('ascii'))
return p.stdout.decode('ascii')
# Returns true if the given branch exists on the origin remote
def branch_exists_on_remote(branch_name):
return run_git('ls-remote', '--heads', ORIGIN, branch_name).strip() != ''
# Opens a PR from the given branch to the release branch
def open_pr(repo, all_commits, short_master_sha, branch_name):
# Sort the commits into the pull requests that introduced them,
# and any commits that don't have a pull request
pull_requests = []
commits_without_pull_requests = []
for commit in all_commits:
pr = get_pr_for_commit(repo, commit)
if pr is None:
commits_without_pull_requests.append(commit)
elif not any(p for p in pull_requests if p.number == pr.number):
pull_requests.append(pr)
print('Found ' + str(len(pull_requests)) + ' pull requests')
print('Found ' + str(len(commits_without_pull_requests)) + ' commits not in a pull request')
# Sort PRs and commits by age
sorted(pull_requests, key=lambda pr: pr.number)
sorted(commits_without_pull_requests, key=lambda c: c.commit.author.date)
# Start constructing the body text
body = 'Merging ' + short_master_sha + ' into ' + LATEST_RELEASE_BRANCH
conductor = get_conductor(repo, pull_requests, commits_without_pull_requests)
body += '\n\nConductor for this PR is @' + conductor
# List all PRs merged
if len(pull_requests) > 0:
body += '\n\nContains the following pull requests:'
for pr in pull_requests:
merger = get_merger_of_pr(repo, pr)
body += '\n- #' + str(pr.number)
body += ' - ' + pr.title
body += ' (@' + merger + ')'
# List all commits not part of a PR
if len(commits_without_pull_requests) > 0:
body += '\n\nContains the following commits not from a pull request:'
for commit in commits_without_pull_requests:
body += '\n- ' + commit.sha
body += ' - ' + get_truncated_commit_message(commit)
body += ' (@' + commit.author.login + ')'
title = 'Merge ' + MASTER_BRANCH + ' into ' + LATEST_RELEASE_BRANCH
# Create the pull request
pr = repo.create_pull(title=title, body=body, head=branch_name, base=LATEST_RELEASE_BRANCH)
print('Created PR #' + str(pr.number))
# Assign the conductor
pr.add_to_assignees(conductor)
print('Assigned PR to ' + conductor)
# Gets the person who should be in charge of the mergeback PR
def get_conductor(repo, pull_requests, other_commits):
# If there are any PRs then use whoever merged the last one
if len(pull_requests) > 0:
return get_merger_of_pr(repo, pull_requests[-1])
# Otherwise take the author of the latest commit
return other_commits[-1].author.login
# Gets a list of the SHAs of all commits that have happened on master
# since the release branched off.
# This will not include any commits that exist on the release branch
# that aren't on master.
def get_commit_difference(repo):
commits = run_git('log', '--pretty=format:%H', ORIGIN + '/' + LATEST_RELEASE_BRANCH + '...' + MASTER_BRANCH).strip().split('\n')
# Convert to full-fledged commit objects
commits = [repo.get_commit(c) for c in commits]
# Filter out merge commits for PRs
return list(filter(lambda c: not is_pr_merge_commit(c), commits))
# Is the given commit the automatic merge commit from when merging a PR
def is_pr_merge_commit(commit):
return commit.committer.login == 'web-flow' and len(commit.parents) > 1
# Gets a copy of the commit message that should display nicely
def get_truncated_commit_message(commit):
message = commit.commit.message.split('\n')[0]
if len(message) > 60:
return message[:57] + '...'
else:
return message
# Converts a commit into the PR that introduced it to the master branch.
# Returns the PR object, or None if no PR could be found.
def get_pr_for_commit(repo, commit):
prs = commit.get_pulls()
if prs.totalCount > 0:
# In the case that there are multiple PRs, return the earliest one
prs = list(prs)
sorted(prs, key=lambda pr: int(pr.number))
return prs[0]
else:
return None
# Get the person who merged the pull request.
# For most cases this will be the same as the author, but for PRs opened
# by external contributors getting the merger will get us the GitHub
# employee who reviewed and merged the PR.
def get_merger_of_pr(repo, pr):
return repo.get_commit(pr.merge_commit_sha).author.login
def main():
if len(sys.argv) != 3:
raise Exception('Usage: update-release.branch.py <github token> <repository nwo>')
github_token = sys.argv[1]
repository_nwo = sys.argv[2]
repo = Github(github_token).get_repo(repository_nwo)
# Print what we intend to go
print('Considering difference between ' + MASTER_BRANCH + ' and ' + LATEST_RELEASE_BRANCH)
short_master_sha = run_git('rev-parse', '--short', MASTER_BRANCH).strip()
print('Current head of ' + MASTER_BRANCH + ' is ' + short_master_sha)
# See if there are any commits to merge in
commits = get_commit_difference(repo)
if len(commits) == 0:
print('No commits to merge from ' + MASTER_BRANCH + ' to ' + LATEST_RELEASE_BRANCH)
return
# The branch name is based off of the name of branch being merged into
# and the SHA of the branch being merged from. Thus if the branch already
# exists we can assume we don't need to recreate it.
new_branch_name = 'update-' + LATEST_RELEASE_BRANCH + '-' + short_master_sha
print('Branch name is ' + new_branch_name)
# Check if the branch already exists. If so we can abort as this script
# has already run on this combination of branches.
if branch_exists_on_remote(new_branch_name):
print('Branch ' + new_branch_name + ' already exists. Nothing to do.')
return
# Create the new branch and push it to the remote
print('Creating branch ' + new_branch_name)
run_git('checkout', '-b', new_branch_name, MASTER_BRANCH)
run_git('push', ORIGIN, new_branch_name)
# Open a PR to update the branch
open_pr(repo, commits, short_master_sha, new_branch_name)
if __name__ == '__main__':
main()

View file

@ -0,0 +1,28 @@
name: Update release branch
on:
schedule:
- cron: 0 9 * * 1
repository_dispatch:
types: [update-release-branch]
jobs:
update:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
# Need full history so we calculate diffs
fetch-depth: 0
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.5
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install PyGithub==1.51 requests
- name: Update release branch
run: python .github/update-release-branch.py ${{ secrets.GITHUB_TOKEN }} ${{ github.repository }}

View file

@ -1,6 +1,6 @@
# CodeQL Action
This action runs GitHub's industry-leading static analysis engine, CodeQL, against a repository's source code to find security vulnerabilities. It then automatically uploads the results to GitHub so they can be displayed in the repository's security tab. CodeQL runs an extensible set of [queries](https://github.com/semmle/ql), which have been developed by the community and the [GitHub Security Lab](https://securitylab.github.com/) to find common vulnerabilities in your code.
This action runs GitHub's industry-leading static analysis engine, CodeQL, against a repository's source code to find security vulnerabilities. It then automatically uploads the results to GitHub so they can be displayed in the repository's security tab. CodeQL runs an extensible set of [queries](https://github.com/github/codeql), which have been developed by the community and the [GitHub Security Lab](https://securitylab.github.com/) to find common vulnerabilities in your code.
## License
@ -10,6 +10,8 @@ The underlying CodeQL CLI, used in this action, is licensed under the [GitHub Co
## Usage
This is a short walkthrough, but for more information read [configuring code scanning](https://help.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning).
To get code scanning results from CodeQL analysis on your repo you can use the following workflow as a template:
```yaml
@ -90,24 +92,9 @@ If you prefer to integrate this within an existing CI workflow, it should end up
uses: github/codeql-action/analyze@v1
```
### Actions triggers
### Configuration file
The CodeQL action should be run on `push` events, and on a `schedule`. `Push` events allow us to do a detailed analysis of the delta in a pull request, while the `schedule` event ensures that GitHub regularly scans the repository for the latest vulnerabilities, even if the repository becomes inactive. This action does not support the `pull_request` event.
### Configuration
You may optionally specify additional queries for CodeQL to execute by using a config file. The queries must belong to a [QL pack](https://help.semmle.com/codeql/codeql-cli/reference/qlpack-overview.html) and can be in your repository or any public repository. You can choose a single .ql file, a folder containing multiple .ql files, a .qls [query suite](https://help.semmle.com/codeql/codeql-cli/procedures/query-suites.html) file, or any combination of the above. To use queries stored in your repository or from other repositories use the same syntax as when [using an action](https://help.github.com/en/actions/reference/workflow-syntax-for-github-actions#jobsjob_idstepsuses). Note that when using local queries starting with `./`, the path is relative to the root of the repository and not to the location of the config file.
You can disable the default queries using `disable-default-queries: true`.
You can choose to ignore some files or folders from the analysis, or include additional files/folders for analysis. This *only* works for Javascript and Python analysis.
Identifying potential files for extraction:
- Scans each folder that's defined as `paths` in turn, traversing subfolders, and looking for relevant files.
- If it finds a subfolder that's defined as `paths-ignore`, stop traversing.
- If a file or folder is both in `paths` and `paths-ignore`, the `paths-ignore` is ignored.
Use the `config-file` parameter of the init action to enable the configuration file. For example:
Use the `config-file` parameter of the `init` action to enable the configuration file. The value of `config-file` is the path to the configuration file you want to use. This example loads the configuration file `./.github/codeql/codeql-config.yml`.
```yaml
- uses: github/codeql-action/init@v1
@ -115,72 +102,8 @@ Use the `config-file` parameter of the init action to enable the configuration f
config-file: ./.github/codeql/codeql-config.yml
```
A config file looks like this:
```yaml
name: "My CodeQL config"
disable-default-queries: true
queries:
- name: In-repo queries (Runs the queries located in the my-queries folder of the repo)
uses: ./my-queries
- name: External Javascript QL pack (Runs a QL pack located in an external repo)
uses: /Semmle/ql/javascript/ql/src/Electron@master
- name: External query (Runs a single query located in an external QL pack)
uses: Semmle/ql/javascript/ql/src/AngularJS/DeadAngularJSEventListener.ql@master
- name: Select query suite (Runs a query suites)
uses: ./codeql-querypacks/complex-python-querypack/rootAndBar.qls
paths:
- src/util.ts
paths-ignore:
- src
- lib
```
The configuration file must be located within the local repository. For information on how to write a configuration file, see "[Using a custom configuration](https://help.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#using-a-custom-configuration)."
## Troubleshooting
### Trouble with Go dependencies
#### If you use a vendor directory
Try passing
```yaml
env:
GOFLAGS: "-mod=vendor"
```
to `github/codeql-action/analyze`.
#### If you do not use a vendor directory
Dependencies on public repositories should just work. If you have dependencies on private repositories, one option is to use `git config` and a [personal access token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line) to authenticate when downloading dependencies. Add a section like
```yaml
steps:
- name: Configure git private repo access
env:
TOKEN: ${{ secrets.GITHUB_PAT }}
run: |
git config --global url."https://${TOKEN}@github.com/foo/bar".insteadOf "https://github.com/foo/bar"
git config --global url."https://${TOKEN}@github.com/foo/baz".insteadOf "https://github.com/foo/baz"
```
before any codeql actions. A similar thing can also be done with an SSH key or deploy key.
### C# using dotnet version 2 on linux
This currently requires invoking `dotnet` with the `/p:UseSharedCompilation=false` flag. For example:
```shell
dotnet build /p:UseSharedCompilation=false
```
Version 3 does not require the additional flag.
### Analysing Go together with other languages on `macos-latest`
When running on macos it is currently not possible to analyze Go in conjunction with any of Java, C/C++, or C#. Each language can still be analyzed separately.
Read about [troubleshooting code scanning](https://help.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/troubleshooting-code-scanning).

125
lib/config-utils.js generated
View file

@ -13,6 +13,12 @@ const fs = __importStar(require("fs"));
const yaml = __importStar(require("js-yaml"));
const path = __importStar(require("path"));
const util = __importStar(require("./util"));
const NAME_PROPERTY = 'name';
const DISPLAY_DEFAULT_QUERIES_PROPERTY = 'disable-default-queries';
const QUERIES_PROPERTY = 'queries';
const QUERIES_USES_PROPERTY = 'uses';
const PATHS_IGNORE_PROPERTY = 'paths-ignore';
const PATHS_PROPERTY = 'paths';
class ExternalQuery {
constructor(repository, ref) {
this.path = '';
@ -33,12 +39,12 @@ class Config {
this.pathsIgnore = [];
this.paths = [];
}
addQuery(queryUses) {
addQuery(configFile, queryUses) {
// The logic for parsing the string is based on what actions does for
// parsing the 'uses' actions in the workflow file
queryUses = queryUses.trim();
if (queryUses === "") {
throw new Error(getQueryUsesBlank());
throw new Error(getQueryUsesInvalid(configFile));
}
// Check for the local path case before we start trying to parse the repository name
if (queryUses.startsWith("./")) {
@ -49,11 +55,11 @@ class Config {
const absoluteQueryPath = path.join(workspacePath, localQueryPath);
// Check the file exists
if (!fs.existsSync(absoluteQueryPath)) {
throw new Error(getLocalPathDoesNotExist(localQueryPath));
throw new Error(getLocalPathDoesNotExist(configFile, localQueryPath));
}
// Check the local path doesn't jump outside the repo using '..' or symlinks
if (!(fs.realpathSync(absoluteQueryPath) + path.sep).startsWith(workspacePath + path.sep)) {
throw new Error(getLocalPathOutsideOfRepository(localQueryPath));
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
}
this.additionalQueries.push(absoluteQueryPath);
return;
@ -66,12 +72,12 @@ class Config {
return;
}
else {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
}
let tok = queryUses.split('@');
if (tok.length !== 2) {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
const ref = tok[1];
tok = tok[0].split('/');
@ -79,14 +85,14 @@ class Config {
// The second token is the repo
// The rest is a path, if there is more than one token combine them to form the full path
if (tok.length < 2) {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
if (tok.length > 3) {
tok = [tok[0], tok[1], tok.slice(2).join('/')];
}
// Check none of the parts of the repository name are empty
if (tok[0].trim() === '' || tok[1].trim() === '') {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
let external = new ExternalQuery(tok[0] + '/' + tok[1], ref);
if (tok.length === 3) {
@ -96,24 +102,38 @@ class Config {
}
}
exports.Config = Config;
function getQueryUsesBlank() {
return '"uses" value for queries cannot be blank';
function getNameInvalid(configFile) {
return getConfigFilePropertyError(configFile, NAME_PROPERTY, 'must be a non-empty string');
}
exports.getQueryUsesBlank = getQueryUsesBlank;
function getQueryUsesIncorrect(queryUses) {
return '"uses" value for queries must be a built-in suite (' + builtinSuites.join(' or ') +
'), a relative path, or of the form owner/repo@ref\n' +
'Found: ' + queryUses;
exports.getNameInvalid = getNameInvalid;
function getDisableDefaultQueriesInvalid(configFile) {
return getConfigFilePropertyError(configFile, DISPLAY_DEFAULT_QUERIES_PROPERTY, 'must be a boolean');
}
exports.getQueryUsesIncorrect = getQueryUsesIncorrect;
function getLocalPathOutsideOfRepository(localPath) {
return 'Unable to use queries from local path "' + localPath +
'" as it is outside of the repository';
exports.getDisableDefaultQueriesInvalid = getDisableDefaultQueriesInvalid;
function getQueriesInvalid(configFile) {
return getConfigFilePropertyError(configFile, QUERIES_PROPERTY, 'must be an array');
}
exports.getQueriesInvalid = getQueriesInvalid;
function getQueryUsesInvalid(configFile, queryUses) {
return getConfigFilePropertyError(configFile, QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY, 'must be a built-in suite (' + builtinSuites.join(' or ') +
'), a relative path, or be of the form "owner/repo[/path]@ref"' +
(queryUses !== undefined ? '\n Found: ' + queryUses : ''));
}
exports.getQueryUsesInvalid = getQueryUsesInvalid;
function getPathsIgnoreInvalid(configFile) {
return getConfigFilePropertyError(configFile, PATHS_IGNORE_PROPERTY, 'must be an array of non-empty strings');
}
exports.getPathsIgnoreInvalid = getPathsIgnoreInvalid;
function getPathsInvalid(configFile) {
return getConfigFilePropertyError(configFile, PATHS_PROPERTY, 'must be an array of non-empty strings');
}
exports.getPathsInvalid = getPathsInvalid;
function getLocalPathOutsideOfRepository(configFile, localPath) {
return getConfigFilePropertyError(configFile, QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY, 'is invalid as the local path "' + localPath + '" is outside of the repository');
}
exports.getLocalPathOutsideOfRepository = getLocalPathOutsideOfRepository;
function getLocalPathDoesNotExist(localPath) {
return 'Unable to use queries from local path "' + localPath +
'" as the path does not exist in the repository';
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) {
@ -124,6 +144,9 @@ function getConfigFileDoesNotExistErrorMessage(configFile) {
return 'The configuration file "' + configFile + '" does not exist';
}
exports.getConfigFileDoesNotExistErrorMessage = getConfigFileDoesNotExistErrorMessage;
function getConfigFilePropertyError(configFile, property, error) {
return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error;
}
function initConfig() {
let configFile = core.getInput('config-file');
const config = new Config();
@ -144,40 +167,58 @@ function initConfig() {
throw new Error(getConfigFileDoesNotExistErrorMessage(configFile));
}
const parsedYAML = yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
if (parsedYAML.name && typeof parsedYAML.name === "string") {
config.name = parsedYAML.name;
if (NAME_PROPERTY in parsedYAML) {
if (typeof parsedYAML[NAME_PROPERTY] !== "string") {
throw new Error(getNameInvalid(configFile));
}
if (parsedYAML[NAME_PROPERTY].length === 0) {
throw new Error(getNameInvalid(configFile));
}
config.name = parsedYAML[NAME_PROPERTY];
}
if (parsedYAML['disable-default-queries'] && typeof parsedYAML['disable-default-queries'] === "boolean") {
config.disableDefaultQueries = parsedYAML['disable-default-queries'];
if (DISPLAY_DEFAULT_QUERIES_PROPERTY in parsedYAML) {
if (typeof parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY] !== "boolean") {
throw new Error(getDisableDefaultQueriesInvalid(configFile));
}
config.disableDefaultQueries = parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY];
}
const queries = parsedYAML.queries;
if (queries && queries instanceof Array) {
queries.forEach(query => {
if (typeof query.uses === "string") {
config.addQuery(query.uses);
if (QUERIES_PROPERTY in parsedYAML) {
if (!(parsedYAML[QUERIES_PROPERTY] instanceof Array)) {
throw new Error(getQueriesInvalid(configFile));
}
parsedYAML[QUERIES_PROPERTY].forEach(query => {
if (!(QUERIES_USES_PROPERTY in query) || typeof query[QUERIES_USES_PROPERTY] !== "string") {
throw new Error(getQueryUsesInvalid(configFile));
}
config.addQuery(configFile, query[QUERIES_USES_PROPERTY]);
});
}
const pathsIgnore = parsedYAML['paths-ignore'];
if (pathsIgnore && pathsIgnore instanceof Array) {
pathsIgnore.forEach(path => {
if (typeof path === "string") {
config.pathsIgnore.push(path);
if (PATHS_IGNORE_PROPERTY in parsedYAML) {
if (!(parsedYAML[PATHS_IGNORE_PROPERTY] instanceof Array)) {
throw new Error(getPathsIgnoreInvalid(configFile));
}
parsedYAML[PATHS_IGNORE_PROPERTY].forEach(path => {
if (typeof path !== "string" || path === '') {
throw new Error(getPathsIgnoreInvalid(configFile));
}
config.pathsIgnore.push(path);
});
}
const paths = parsedYAML.paths;
if (paths && paths instanceof Array) {
paths.forEach(path => {
if (typeof path === "string") {
config.paths.push(path);
if (PATHS_PROPERTY in parsedYAML) {
if (!(parsedYAML[PATHS_PROPERTY] instanceof Array)) {
throw new Error(getPathsInvalid(configFile));
}
parsedYAML[PATHS_PROPERTY].forEach(path => {
if (typeof path !== "string" || path === '') {
throw new Error(getPathsInvalid(configFile));
}
config.paths.push(path);
});
}
return config;
}
function getConfigFolder() {
return util.getRequiredEnvParam('RUNNER_WORKSPACE');
return util.getRequiredEnvParam('RUNNER_TEMP');
}
function getConfigFile() {
return path.join(getConfigFolder(), 'config');

File diff suppressed because one or more lines are too long

147
lib/config-utils.test.js generated
View file

@ -28,7 +28,7 @@ function setInput(name, value) {
}
ava_1.default("load empty config", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
setInput('config-file', undefined);
const config = await configUtils.loadConfig();
@ -37,7 +37,7 @@ ava_1.default("load empty config", async (t) => {
});
ava_1.default("loading config saves config", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
const configFile = configUtils.getConfigFile();
// Sanity check the saved config file does not already exist
@ -51,7 +51,7 @@ ava_1.default("loading config saves config", async (t) => {
});
ava_1.default("load input outside of workspace", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
setInput('config-file', '../input');
try {
@ -65,7 +65,7 @@ ava_1.default("load input outside of workspace", async (t) => {
});
ava_1.default("load non-existent input", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
t.false(fs.existsSync(path.join(tmpDir, 'input')));
setInput('config-file', 'input');
@ -80,7 +80,7 @@ ava_1.default("load non-existent input", async (t) => {
});
ava_1.default("load non-empty input", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Just create a generic config object with non-default values for all fields
const inputFileContents = `
@ -112,118 +112,51 @@ ava_1.default("load non-empty input", async (t) => {
t.deepEqual(actualConfig, expectedConfig);
});
});
ava_1.default("load partially invalid input", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// The valid parts of this config should be parsed correctly.
// The invalid parts should be ignored and left as the default values.
const inputFileContents = `
name:
- foo: bar
disable-default-queries: 42
queries:
- name: foo/bar
uses: foo/bar@dev
paths-ignore:
- a
- b
paths:
- c/d`;
// And the config we expect it to parse to
const expectedConfig = new configUtils.Config();
expectedConfig.externalQueries = [new configUtils.ExternalQuery('foo/bar', 'dev')];
expectedConfig.pathsIgnore = ['a', 'b'];
expectedConfig.paths = ['c/d'];
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
setInput('config-file', 'input');
const actualConfig = await configUtils.loadConfig();
// Should exactly equal the object we constructed earlier
t.deepEqual(actualConfig, expectedConfig);
});
});
ava_1.default("load invalid input - top level entries", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Replace the arrays with strings or numbers.
// The invalid parts should be ignored and left as the default values.
const inputFileContents = `
name: my config
disable-default-queries: true
queries: foo
paths-ignore: bar
paths: 123`;
// And the config we expect it to parse to
const expectedConfig = new configUtils.Config();
expectedConfig.name = 'my config';
expectedConfig.disableDefaultQueries = true;
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
setInput('config-file', 'input');
const actualConfig = await configUtils.loadConfig();
// Should exactly equal the object we constructed earlier
t.deepEqual(actualConfig, expectedConfig);
});
});
ava_1.default("load invalid input - queries field type", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Invalid contents of the "queries" array.
// The invalid parts should be ignored and left as the default values.
const inputFileContents = `
name: my config
disable-default-queries: true
queries:
- name: foo
uses:
- hello: world
- name: bar
uses: github/bar@master`;
// And the config we expect it to parse to
const expectedConfig = new configUtils.Config();
expectedConfig.name = 'my config';
expectedConfig.disableDefaultQueries = true;
expectedConfig.externalQueries.push(new configUtils.ExternalQuery("github/bar", "master"));
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
setInput('config-file', 'input');
const actualConfig = await configUtils.loadConfig();
// Should exactly equal the object we constructed earlier
t.deepEqual(actualConfig, expectedConfig);
});
});
// Various "uses" fields, and the errors they should produce
const testInputs = {
"''": configUtils.getQueryUsesBlank(),
"foo/bar": configUtils.getQueryUsesIncorrect("foo/bar"),
"foo/bar@v1@v2": configUtils.getQueryUsesIncorrect("foo/bar@v1@v2"),
"foo@master": configUtils.getQueryUsesIncorrect("foo@master"),
"https://github.com/foo/bar@master": configUtils.getQueryUsesIncorrect("https://github.com/foo/bar@master"),
"./foo": configUtils.getLocalPathDoesNotExist("foo"),
"./..": configUtils.getLocalPathOutsideOfRepository(".."),
};
for (const [input, result] of Object.entries(testInputs)) {
ava_1.default("load invalid input - queries uses \"" + input + "\"", async (t) => {
function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGenerator) {
ava_1.default("load invalid input - " + testName, async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Invalid contents of a "queries.uses" field.
// Should fail with the expected error message
const inputFileContents = `
name: my config
queries:
- name: foo
uses: ` + input;
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
const inputFile = path.join(tmpDir, 'input');
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
setInput('config-file', 'input');
try {
await configUtils.loadConfig();
throw new Error('loadConfig did not throw error');
}
catch (err) {
t.deepEqual(err, new Error(result));
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
}
});
});
}
doInvalidInputTest('name invalid type', `
name:
- foo: bar`, configUtils.getNameInvalid);
doInvalidInputTest('disable-default-queries invalid type', `disable-default-queries: 42`, configUtils.getDisableDefaultQueriesInvalid);
doInvalidInputTest('queries invalid type', `queries: foo`, configUtils.getQueriesInvalid);
doInvalidInputTest('paths-ignore invalid type', `paths-ignore: bar`, configUtils.getPathsIgnoreInvalid);
doInvalidInputTest('paths invalid type', `paths: 17`, configUtils.getPathsInvalid);
doInvalidInputTest('queries uses invalid type', `
queries:
- uses:
- hello: world`, configUtils.getQueryUsesInvalid);
function doInvalidQueryUsesTest(input, expectedErrorMessageGenerator) {
// Invalid contents of a "queries.uses" field.
// Should fail with the expected error message
const inputFileContents = `
name: my config
queries:
- name: foo
uses: ` + input;
doInvalidInputTest("queries uses \"" + input + "\"", inputFileContents, expectedErrorMessageGenerator);
}
// Various "uses" fields, and the errors they should produce
doInvalidQueryUsesTest("''", c => configUtils.getQueryUsesInvalid(c, undefined));
doInvalidQueryUsesTest("foo/bar", c => configUtils.getQueryUsesInvalid(c, "foo/bar"));
doInvalidQueryUsesTest("foo/bar@v1@v2", c => configUtils.getQueryUsesInvalid(c, "foo/bar@v1@v2"));
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("./foo", c => configUtils.getLocalPathDoesNotExist(c, "foo"));
doInvalidQueryUsesTest("./..", c => configUtils.getLocalPathOutsideOfRepository(c, ".."));
//# sourceMappingURL=config-utils.test.js.map

File diff suppressed because one or more lines are too long

View file

@ -13,7 +13,7 @@ const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const util = __importStar(require("./util"));
async function checkoutExternalQueries(config) {
const folder = util.getRequiredEnvParam('RUNNER_WORKSPACE');
const folder = util.getRequiredEnvParam('RUNNER_TEMP');
for (const externalQuery of config.externalQueries) {
core.info('Checking out ' + externalQuery.repository);
const checkoutLocation = path.join(folder, externalQuery.repository);

View file

@ -1 +1 @@
{"version":3,"file":"external-queries.js","sourceRoot":"","sources":["../src/external-queries.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AACtC,oDAAsC;AACtC,uCAAyB;AACzB,2CAA6B;AAG7B,6CAA+B;AAExB,KAAK,UAAU,uBAAuB,CAAC,MAA0B;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,kBAAkB,CAAC,CAAC;IAE5D,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,eAAe,EAAE;QAClD,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QAEtD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;QACrE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE;YACpC,MAAM,OAAO,GAAG,qBAAqB,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC;YAC1E,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;YAC7D,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;gBACrB,cAAc,GAAG,gBAAgB;gBACjC,YAAY,GAAG,gBAAgB,GAAG,OAAO;gBACzC,UAAU,EAAE,aAAa,CAAC,GAAG;aAC9B,CAAC,CAAC;SACJ;QAED,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;KAChF;AACH,CAAC;AAnBD,0DAmBC"}
{"version":3,"file":"external-queries.js","sourceRoot":"","sources":["../src/external-queries.ts"],"names":[],"mappings":";;;;;;;;;AAAA,oDAAsC;AACtC,oDAAsC;AACtC,uCAAyB;AACzB,2CAA6B;AAG7B,6CAA+B;AAExB,KAAK,UAAU,uBAAuB,CAAC,MAA0B;IACtE,MAAM,MAAM,GAAG,IAAI,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;IAEvD,KAAK,MAAM,aAAa,IAAI,MAAM,CAAC,eAAe,EAAE;QAClD,IAAI,CAAC,IAAI,CAAC,eAAe,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QAEtD,MAAM,gBAAgB,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,CAAC,CAAC;QACrE,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,gBAAgB,CAAC,EAAE;YACpC,MAAM,OAAO,GAAG,qBAAqB,GAAG,aAAa,CAAC,UAAU,GAAG,MAAM,CAAC;YAC1E,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;YAC7D,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;gBACrB,cAAc,GAAG,gBAAgB;gBACjC,YAAY,GAAG,gBAAgB,GAAG,OAAO;gBACzC,UAAU,EAAE,aAAa,CAAC,GAAG;aAC9B,CAAC,CAAC;SACJ;QAED,MAAM,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;KAChF;AACH,CAAC;AAnBD,0DAmBC"}

View file

@ -22,7 +22,7 @@ ava_1.default("checkoutExternalQueries", async (t) => {
new configUtils.ExternalQuery("github/codeql-go", "df4c6869212341b601005567381944ed90906b6b"),
];
await util.withTmpDir(async (tmpDir) => {
process.env["RUNNER_WORKSPACE"] = tmpDir;
process.env["RUNNER_TEMP"] = tmpDir;
await externalQueries.checkoutExternalQueries(config);
// COPYRIGHT file existed in df4c6869212341b601005567381944ed90906b6b but not in master
t.true(fs.existsSync(path.join(tmpDir, "github", "codeql-go", "COPYRIGHT")));

View file

@ -1 +1 @@
{"version":3,"file":"external-queries.test.js","sourceRoot":"","sources":["../src/external-queries.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AACvB,uCAAyB;AACzB,2CAA6B;AAE7B,4DAA8C;AAC9C,oEAAsD;AACtD,6CAA+B;AAE/B,aAAI,CAAC,yBAAyB,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACtC,IAAI,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,eAAe,GAAG;QACrB,IAAI,WAAW,CAAC,aAAa,CAAC,kBAAkB,EAAE,0CAA0C,CAAC;KAChG,CAAC;IAEF,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;QACjC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,GAAG,MAAM,CAAC;QACzC,MAAM,eAAe,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAEtD,uFAAuF;QACvF,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}
{"version":3,"file":"external-queries.test.js","sourceRoot":"","sources":["../src/external-queries.test.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,8CAAuB;AACvB,uCAAyB;AACzB,2CAA6B;AAE7B,4DAA8C;AAC9C,oEAAsD;AACtD,6CAA+B;AAE/B,aAAI,CAAC,yBAAyB,EAAE,KAAK,EAAC,CAAC,EAAC,EAAE;IACtC,IAAI,MAAM,GAAG,IAAI,WAAW,CAAC,MAAM,EAAE,CAAC;IACtC,MAAM,CAAC,eAAe,GAAG;QACrB,IAAI,WAAW,CAAC,aAAa,CAAC,kBAAkB,EAAE,0CAA0C,CAAC;KAChG,CAAC;IAEF,MAAM,IAAI,CAAC,UAAU,CAAC,KAAK,EAAC,MAAM,EAAC,EAAE;QACjC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC,GAAG,MAAM,CAAC;QACpC,MAAM,eAAe,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;QAEtD,uFAAuF;QACvF,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC"}

2
lib/finalize-db.js generated
View file

@ -174,7 +174,7 @@ async function run() {
await runQueries(codeqlCmd, databaseFolder, sarifFolder, config);
if ('true' === core.getInput('upload')) {
if (!await upload_lib.upload(sarifFolder)) {
await util.reportActionFailed('failed', 'upload');
await util.reportActionFailed('finish', 'upload');
return;
}
}

13
lib/setup-tracer.js generated
View file

@ -100,12 +100,13 @@ function concatTracerConfigs(configs) {
totalCount += count;
totalLines.push(...lines.slice(2));
}
const newLogFilePath = path.resolve(util.workspaceFolder(), 'compound-build-tracer.log');
const spec = path.resolve(util.workspaceFolder(), 'compound-spec');
const tempFolder = path.resolve(util.workspaceFolder(), 'compound-temp');
const tempFolder = util.getRequiredEnvParam('RUNNER_TEMP');
const newLogFilePath = path.resolve(tempFolder, 'compound-build-tracer.log');
const spec = path.resolve(tempFolder, 'compound-spec');
const compoundTempFolder = path.resolve(tempFolder, 'compound-temp');
const newSpecContent = [newLogFilePath, totalCount.toString(10), ...totalLines];
if (copyExecutables) {
env['SEMMLE_COPY_EXECUTABLES_ROOT'] = tempFolder;
env['SEMMLE_COPY_EXECUTABLES_ROOT'] = compoundTempFolder;
envSize += 1;
}
fs.writeFileSync(spec, newSpecContent.join('\n'));
@ -156,7 +157,7 @@ async function run() {
// Setup CODEQL_RAM flag (todo improve this https://github.com/github/dsp-code-scanning/issues/935)
const codeqlRam = process.env['CODEQL_RAM'] || '6500';
core.exportVariable('CODEQL_RAM', codeqlRam);
const databaseFolder = path.resolve(util.workspaceFolder(), 'codeql_databases');
const databaseFolder = path.resolve(util.getRequiredEnvParam('RUNNER_TEMP'), 'codeql_databases');
await io.mkdirP(databaseFolder);
let tracedLanguages = {};
let scannedLanguages = [];
@ -205,8 +206,8 @@ async function run() {
await util.reportActionFailed('init', error.message, error.stack);
return;
}
core.exportVariable(sharedEnv.CODEQL_ACTION_INIT_COMPLETED, 'true');
await util.reportActionSucceeded('init');
core.exportVariable(sharedEnv.CODEQL_ACTION_INIT_COMPLETED, 'true');
}
run().catch(e => {
core.setFailed("init action failed: " + e);

File diff suppressed because one or more lines are too long

94
lib/upload-lib.js generated
View file

@ -125,58 +125,52 @@ exports.countResultsInSarif = countResultsInSarif;
// Returns true iff the upload occurred and succeeded
async function uploadFiles(sarifFiles) {
core.startGroup("Uploading results");
let succeeded = false;
try {
const sentinelEnvVar = "CODEQL_UPLOAD_SARIF";
if (process.env[sentinelEnvVar]) {
core.error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
return false;
}
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
const commitOid = await util.getCommitOid();
const workflowRunIDStr = util.getRequiredEnvParam('GITHUB_RUN_ID');
const ref = util.getRef();
const analysisKey = await util.getAnalysisKey();
const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW');
const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT];
core.info("Uploading sarif files: " + JSON.stringify(sarifFiles));
let sarifPayload = combineSarifFiles(sarifFiles);
sarifPayload = fingerprints.addFingerprints(sarifPayload);
const zipped_sarif = zlib_1.default.gzipSync(sarifPayload).toString('base64');
let checkoutPath = core.getInput('checkout_path');
let checkoutURI = file_url_1.default(checkoutPath);
const workflowRunID = parseInt(workflowRunIDStr, 10);
if (Number.isNaN(workflowRunID)) {
core.setFailed('GITHUB_RUN_ID must define a non NaN workflow run ID');
return false;
}
let matrix = core.getInput('matrix');
if (matrix === "null" || matrix === "") {
matrix = undefined;
}
const toolNames = util.getToolNames(sarifPayload);
const payload = JSON.stringify({
"commit_oid": commitOid,
"ref": ref,
"analysis_key": analysisKey,
"analysis_name": analysisName,
"sarif": zipped_sarif,
"workflow_run_id": workflowRunID,
"checkout_uri": checkoutURI,
"environment": matrix,
"started_at": startedAt,
"tool_names": toolNames,
});
// Log some useful debug info about the info
core.debug("Raw upload size: " + sarifPayload.length + " bytes");
core.debug("Base64 zipped upload size: " + zipped_sarif.length + " bytes");
core.debug("Number of results in upload: " + countResultsInSarif(sarifPayload));
// Make the upload
succeeded = await uploadPayload(payload);
const sentinelEnvVar = "CODEQL_UPLOAD_SARIF";
if (process.env[sentinelEnvVar]) {
core.error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
return false;
}
catch (error) {
core.setFailed(error.message);
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
const commitOid = await util.getCommitOid();
const workflowRunIDStr = util.getRequiredEnvParam('GITHUB_RUN_ID');
const ref = util.getRef();
const analysisKey = await util.getAnalysisKey();
const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW');
const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT];
core.info("Uploading sarif files: " + JSON.stringify(sarifFiles));
let sarifPayload = combineSarifFiles(sarifFiles);
sarifPayload = fingerprints.addFingerprints(sarifPayload);
const zipped_sarif = zlib_1.default.gzipSync(sarifPayload).toString('base64');
let checkoutPath = core.getInput('checkout_path');
let checkoutURI = file_url_1.default(checkoutPath);
const workflowRunID = parseInt(workflowRunIDStr, 10);
if (Number.isNaN(workflowRunID)) {
core.setFailed('GITHUB_RUN_ID must define a non NaN workflow run ID');
return false;
}
let matrix = core.getInput('matrix');
if (matrix === "null" || matrix === "") {
matrix = undefined;
}
const toolNames = util.getToolNames(sarifPayload);
const payload = JSON.stringify({
"commit_oid": commitOid,
"ref": ref,
"analysis_key": analysisKey,
"analysis_name": analysisName,
"sarif": zipped_sarif,
"workflow_run_id": workflowRunID,
"checkout_uri": checkoutURI,
"environment": matrix,
"started_at": startedAt,
"tool_names": toolNames,
});
// Log some useful debug info about the info
core.debug("Raw upload size: " + sarifPayload.length + " bytes");
core.debug("Base64 zipped upload size: " + zipped_sarif.length + " bytes");
core.debug("Number of results in upload: " + countResultsInSarif(sarifPayload));
// Make the upload
const succeeded = await uploadPayload(payload);
core.endGroup();
return succeeded;
}

File diff suppressed because one or more lines are too long

10
lib/util.js generated
View file

@ -42,16 +42,6 @@ function should_abort(actionName, requireInitActionHasRun) {
return false;
}
exports.should_abort = should_abort;
/**
* Resolve the path to the workspace folder.
*/
function workspaceFolder() {
let workspaceFolder = process.env['RUNNER_WORKSPACE'];
if (!workspaceFolder)
workspaceFolder = path.resolve('..');
return workspaceFolder;
}
exports.workspaceFolder = workspaceFolder;
/**
* Get an environment parameter, but throw an error if it is not set.
*/

File diff suppressed because one or more lines are too long

View file

@ -18,7 +18,7 @@ function setInput(name: string, value: string | undefined) {
test("load empty config", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
setInput('config-file', undefined);
@ -31,7 +31,7 @@ test("load empty config", async t => {
test("loading config saves config", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
const configFile = configUtils.getConfigFile();
@ -50,7 +50,7 @@ test("loading config saves config", async t => {
test("load input outside of workspace", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
setInput('config-file', '../input');
@ -66,7 +66,7 @@ test("load input outside of workspace", async t => {
test("load non-existent input", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
t.false(fs.existsSync(path.join(tmpDir, 'input')));
@ -83,7 +83,7 @@ test("load non-existent input", async t => {
test("load non-empty input", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Just create a generic config object with non-default values for all fields
@ -122,138 +122,102 @@ test("load non-empty input", async t => {
});
});
test("load partially invalid input", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
function doInvalidInputTest(
testName: string,
inputFileContents: string,
expectedErrorMessageGenerator: (configFile: string) => string) {
// The valid parts of this config should be parsed correctly.
// The invalid parts should be ignored and left as the default values.
const inputFileContents = `
name:
- foo: bar
disable-default-queries: 42
queries:
- name: foo/bar
uses: foo/bar@dev
paths-ignore:
- a
- b
paths:
- c/d`;
// And the config we expect it to parse to
const expectedConfig = new configUtils.Config();
expectedConfig.externalQueries = [new configUtils.ExternalQuery('foo/bar', 'dev')];
expectedConfig.pathsIgnore = ['a', 'b'];
expectedConfig.paths = ['c/d'];
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
setInput('config-file', 'input');
const actualConfig = await configUtils.loadConfig();
// Should exactly equal the object we constructed earlier
t.deepEqual(actualConfig, expectedConfig);
});
});
test("load invalid input - top level entries", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Replace the arrays with strings or numbers.
// The invalid parts should be ignored and left as the default values.
const inputFileContents = `
name: my config
disable-default-queries: true
queries: foo
paths-ignore: bar
paths: 123`;
// And the config we expect it to parse to
const expectedConfig = new configUtils.Config();
expectedConfig.name = 'my config';
expectedConfig.disableDefaultQueries = true;
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
setInput('config-file', 'input');
const actualConfig = await configUtils.loadConfig();
// Should exactly equal the object we constructed earlier
t.deepEqual(actualConfig, expectedConfig);
});
});
test("load invalid input - queries field type", async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Invalid contents of the "queries" array.
// The invalid parts should be ignored and left as the default values.
const inputFileContents = `
name: my config
disable-default-queries: true
queries:
- name: foo
uses:
- hello: world
- name: bar
uses: github/bar@master`;
// And the config we expect it to parse to
const expectedConfig = new configUtils.Config();
expectedConfig.name = 'my config';
expectedConfig.disableDefaultQueries = true;
expectedConfig.externalQueries.push(new configUtils.ExternalQuery("github/bar", "master"));
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
setInput('config-file', 'input');
const actualConfig = await configUtils.loadConfig();
// Should exactly equal the object we constructed earlier
t.deepEqual(actualConfig, expectedConfig);
});
});
// Various "uses" fields, and the errors they should produce
const testInputs = {
"''": configUtils.getQueryUsesBlank(),
"foo/bar": configUtils.getQueryUsesIncorrect("foo/bar"),
"foo/bar@v1@v2": configUtils.getQueryUsesIncorrect("foo/bar@v1@v2"),
"foo@master": configUtils.getQueryUsesIncorrect("foo@master"),
"https://github.com/foo/bar@master": configUtils.getQueryUsesIncorrect("https://github.com/foo/bar@master"),
"./foo": configUtils.getLocalPathDoesNotExist("foo"),
"./..": configUtils.getLocalPathOutsideOfRepository(".."),
};
for (const [input, result] of Object.entries(testInputs)) {
test("load invalid input - queries uses \"" + input + "\"", async t => {
test("load invalid input - " + testName, async t => {
return await util.withTmpDir(async tmpDir => {
process.env['RUNNER_WORKSPACE'] = tmpDir;
process.env['RUNNER_TEMP'] = tmpDir;
process.env['GITHUB_WORKSPACE'] = tmpDir;
// Invalid contents of a "queries.uses" field.
// Should fail with the expected error message
const inputFileContents = `
name: my config
queries:
- name: foo
uses: ` + input;
fs.writeFileSync(path.join(tmpDir, 'input'), inputFileContents, 'utf8');
const inputFile = path.join(tmpDir, 'input');
fs.writeFileSync(inputFile, inputFileContents, 'utf8');
setInput('config-file', 'input');
try {
await configUtils.loadConfig();
throw new Error('loadConfig did not throw error');
} catch (err) {
t.deepEqual(err, new Error(result));
t.deepEqual(err, new Error(expectedErrorMessageGenerator(inputFile)));
}
});
});
}
doInvalidInputTest(
'name invalid type',
`
name:
- foo: bar`,
configUtils.getNameInvalid);
doInvalidInputTest(
'disable-default-queries invalid type',
`disable-default-queries: 42`,
configUtils.getDisableDefaultQueriesInvalid);
doInvalidInputTest(
'queries invalid type',
`queries: foo`,
configUtils.getQueriesInvalid);
doInvalidInputTest(
'paths-ignore invalid type',
`paths-ignore: bar`,
configUtils.getPathsIgnoreInvalid);
doInvalidInputTest(
'paths invalid type',
`paths: 17`,
configUtils.getPathsInvalid);
doInvalidInputTest(
'queries uses invalid type',
`
queries:
- uses:
- hello: world`,
configUtils.getQueryUsesInvalid);
function doInvalidQueryUsesTest(
input: string,
expectedErrorMessageGenerator: (configFile: string) => string) {
// Invalid contents of a "queries.uses" field.
// Should fail with the expected error message
const inputFileContents = `
name: my config
queries:
- name: foo
uses: ` + input;
doInvalidInputTest(
"queries uses \"" + input + "\"",
inputFileContents,
expectedErrorMessageGenerator);
}
// Various "uses" fields, and the errors they should produce
doInvalidQueryUsesTest(
"''",
c => configUtils.getQueryUsesInvalid(c, undefined));
doInvalidQueryUsesTest(
"foo/bar",
c => configUtils.getQueryUsesInvalid(c, "foo/bar"));
doInvalidQueryUsesTest(
"foo/bar@v1@v2",
c => configUtils.getQueryUsesInvalid(c, "foo/bar@v1@v2"));
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(
"./foo",
c => configUtils.getLocalPathDoesNotExist(c, "foo"));
doInvalidQueryUsesTest(
"./..",
c => configUtils.getLocalPathOutsideOfRepository(c, ".."));

View file

@ -6,6 +6,13 @@ import * as path from 'path';
import * as util from './util';
const NAME_PROPERTY = 'name';
const DISPLAY_DEFAULT_QUERIES_PROPERTY = 'disable-default-queries';
const QUERIES_PROPERTY = 'queries';
const QUERIES_USES_PROPERTY = 'uses';
const PATHS_IGNORE_PROPERTY = 'paths-ignore';
const PATHS_PROPERTY = 'paths';
export class ExternalQuery {
public repository: string;
public ref: string;
@ -31,12 +38,12 @@ export class Config {
public pathsIgnore: string[] = [];
public paths: string[] = [];
public addQuery(queryUses: string) {
public addQuery(configFile: string, queryUses: string) {
// The logic for parsing the string is based on what actions does for
// parsing the 'uses' actions in the workflow file
queryUses = queryUses.trim();
if (queryUses === "") {
throw new Error(getQueryUsesBlank());
throw new Error(getQueryUsesInvalid(configFile));
}
// Check for the local path case before we start trying to parse the repository name
@ -49,12 +56,12 @@ export class Config {
// Check the file exists
if (!fs.existsSync(absoluteQueryPath)) {
throw new Error(getLocalPathDoesNotExist(localQueryPath));
throw new Error(getLocalPathDoesNotExist(configFile, localQueryPath));
}
// Check the local path doesn't jump outside the repo using '..' or symlinks
if (!(fs.realpathSync(absoluteQueryPath) + path.sep).startsWith(workspacePath + path.sep)) {
throw new Error(getLocalPathOutsideOfRepository(localQueryPath));
throw new Error(getLocalPathOutsideOfRepository(configFile, localQueryPath));
}
this.additionalQueries.push(absoluteQueryPath);
@ -68,13 +75,13 @@ export class Config {
this.additionalSuites.push(suite);
return;
} else {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
}
let tok = queryUses.split('@');
if (tok.length !== 2) {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
const ref = tok[1];
@ -83,7 +90,7 @@ export class Config {
// The second token is the repo
// The rest is a path, if there is more than one token combine them to form the full path
if (tok.length < 2) {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
if (tok.length > 3) {
tok = [tok[0], tok[1], tok.slice(2).join('/')];
@ -91,7 +98,7 @@ export class Config {
// Check none of the parts of the repository name are empty
if (tok[0].trim() === '' || tok[1].trim() === '') {
throw new Error(getQueryUsesIncorrect(queryUses));
throw new Error(getQueryUsesInvalid(configFile, queryUses));
}
let external = new ExternalQuery(tok[0] + '/' + tok[1], ref);
@ -102,24 +109,47 @@ export class Config {
}
}
export function getQueryUsesBlank(): string {
return '"uses" value for queries cannot be blank';
export function getNameInvalid(configFile: string): string {
return getConfigFilePropertyError(configFile, NAME_PROPERTY, 'must be a non-empty string');
}
export function getQueryUsesIncorrect(queryUses: string): string {
return '"uses" value for queries must be a built-in suite (' + builtinSuites.join(' or ') +
'), a relative path, or of the form owner/repo@ref\n' +
'Found: ' + queryUses;
export function getDisableDefaultQueriesInvalid(configFile: string): string {
return getConfigFilePropertyError(configFile, DISPLAY_DEFAULT_QUERIES_PROPERTY, 'must be a boolean');
}
export function getLocalPathOutsideOfRepository(localPath: string): string {
return 'Unable to use queries from local path "' + localPath +
'" as it is outside of the repository';
export function getQueriesInvalid(configFile: string): string {
return getConfigFilePropertyError(configFile, QUERIES_PROPERTY, 'must be an array');
}
export function getLocalPathDoesNotExist(localPath: string): string {
return 'Unable to use queries from local path "' + localPath +
'" as the path does not exist in the repository';
export function getQueryUsesInvalid(configFile: string, queryUses?: string): string {
return getConfigFilePropertyError(
configFile,
QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY,
'must be a built-in suite (' + builtinSuites.join(' or ') +
'), a relative path, or be of the form "owner/repo[/path]@ref"' +
(queryUses !== undefined ? '\n Found: ' + queryUses : ''));
}
export function getPathsIgnoreInvalid(configFile: string): string {
return getConfigFilePropertyError(configFile, PATHS_IGNORE_PROPERTY, 'must be an array of non-empty strings');
}
export function getPathsInvalid(configFile: string): string {
return getConfigFilePropertyError(configFile, PATHS_PROPERTY, 'must be an array of non-empty strings');
}
export function getLocalPathOutsideOfRepository(configFile: string, localPath: string): string {
return getConfigFilePropertyError(
configFile,
QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY,
'is invalid as the local path "' + localPath + '" is outside of the repository');
}
export function getLocalPathDoesNotExist(configFile: string, localPath: string): string {
return getConfigFilePropertyError(
configFile,
QUERIES_PROPERTY + '.' + QUERIES_USES_PROPERTY,
'is invalid as the local path "' + localPath + '" does not exist in the repository');
}
export function getConfigFileOutsideWorkspaceErrorMessage(configFile: string): string {
@ -130,6 +160,10 @@ export function getConfigFileDoesNotExistErrorMessage(configFile: string): strin
return 'The configuration file "' + configFile + '" does not exist';
}
function getConfigFilePropertyError(configFile: string, property: string, error: string): string {
return 'The configuration file "' + configFile + '" is invalid: property "' + property + '" ' + error;
}
function initConfig(): Config {
let configFile = core.getInput('config-file');
@ -157,38 +191,56 @@ function initConfig(): Config {
const parsedYAML = yaml.safeLoad(fs.readFileSync(configFile, 'utf8'));
if (parsedYAML.name && typeof parsedYAML.name === "string") {
config.name = parsedYAML.name;
if (NAME_PROPERTY in parsedYAML) {
if (typeof parsedYAML[NAME_PROPERTY] !== "string") {
throw new Error(getNameInvalid(configFile));
}
if (parsedYAML[NAME_PROPERTY].length === 0) {
throw new Error(getNameInvalid(configFile));
}
config.name = parsedYAML[NAME_PROPERTY];
}
if (parsedYAML['disable-default-queries'] && typeof parsedYAML['disable-default-queries'] === "boolean") {
config.disableDefaultQueries = parsedYAML['disable-default-queries'];
if (DISPLAY_DEFAULT_QUERIES_PROPERTY in parsedYAML) {
if (typeof parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY] !== "boolean") {
throw new Error(getDisableDefaultQueriesInvalid(configFile));
}
config.disableDefaultQueries = parsedYAML[DISPLAY_DEFAULT_QUERIES_PROPERTY];
}
const queries = parsedYAML.queries;
if (queries && queries instanceof Array) {
queries.forEach(query => {
if (typeof query.uses === "string") {
config.addQuery(query.uses);
if (QUERIES_PROPERTY in parsedYAML) {
if (!(parsedYAML[QUERIES_PROPERTY] instanceof Array)) {
throw new Error(getQueriesInvalid(configFile));
}
parsedYAML[QUERIES_PROPERTY].forEach(query => {
if (!(QUERIES_USES_PROPERTY in query) || typeof query[QUERIES_USES_PROPERTY] !== "string") {
throw new Error(getQueryUsesInvalid(configFile));
}
config.addQuery(configFile, query[QUERIES_USES_PROPERTY]);
});
}
const pathsIgnore = parsedYAML['paths-ignore'];
if (pathsIgnore && pathsIgnore instanceof Array) {
pathsIgnore.forEach(path => {
if (typeof path === "string") {
config.pathsIgnore.push(path);
if (PATHS_IGNORE_PROPERTY in parsedYAML) {
if (!(parsedYAML[PATHS_IGNORE_PROPERTY] instanceof Array)) {
throw new Error(getPathsIgnoreInvalid(configFile));
}
parsedYAML[PATHS_IGNORE_PROPERTY].forEach(path => {
if (typeof path !== "string" || path === '') {
throw new Error(getPathsIgnoreInvalid(configFile));
}
config.pathsIgnore.push(path);
});
}
const paths = parsedYAML.paths;
if (paths && paths instanceof Array) {
paths.forEach(path => {
if (typeof path === "string") {
config.paths.push(path);
if (PATHS_PROPERTY in parsedYAML) {
if (!(parsedYAML[PATHS_PROPERTY] instanceof Array)) {
throw new Error(getPathsInvalid(configFile));
}
parsedYAML[PATHS_PROPERTY].forEach(path => {
if (typeof path !== "string" || path === '') {
throw new Error(getPathsInvalid(configFile));
}
config.paths.push(path);
});
}
@ -196,7 +248,7 @@ function initConfig(): Config {
}
function getConfigFolder(): string {
return util.getRequiredEnvParam('RUNNER_WORKSPACE');
return util.getRequiredEnvParam('RUNNER_TEMP');
}
export function getConfigFile(): string {

View file

@ -13,7 +13,7 @@ test("checkoutExternalQueries", async t => {
];
await util.withTmpDir(async tmpDir => {
process.env["RUNNER_WORKSPACE"] = tmpDir;
process.env["RUNNER_TEMP"] = tmpDir;
await externalQueries.checkoutExternalQueries(config);
// COPYRIGHT file existed in df4c6869212341b601005567381944ed90906b6b but not in master

View file

@ -7,7 +7,7 @@ import * as configUtils from './config-utils';
import * as util from './util';
export async function checkoutExternalQueries(config: configUtils.Config) {
const folder = util.getRequiredEnvParam('RUNNER_WORKSPACE');
const folder = util.getRequiredEnvParam('RUNNER_TEMP');
for (const externalQuery of config.externalQueries) {
core.info('Checking out ' + externalQuery.repository);

View file

@ -218,7 +218,7 @@ async function run() {
if ('true' === core.getInput('upload')) {
if (!await upload_lib.upload(sarifFolder)) {
await util.reportActionFailed('failed', 'upload');
await util.reportActionFailed('finish', 'upload');
return;
}
}

View file

@ -108,13 +108,14 @@ function concatTracerConfigs(configs: { [lang: string]: TracerConfig }): TracerC
totalLines.push(...lines.slice(2));
}
const newLogFilePath = path.resolve(util.workspaceFolder(), 'compound-build-tracer.log');
const spec = path.resolve(util.workspaceFolder(), 'compound-spec');
const tempFolder = path.resolve(util.workspaceFolder(), 'compound-temp');
const tempFolder = util.getRequiredEnvParam('RUNNER_TEMP');
const newLogFilePath = path.resolve(tempFolder, 'compound-build-tracer.log');
const spec = path.resolve(tempFolder, 'compound-spec');
const compoundTempFolder = path.resolve(tempFolder, 'compound-temp');
const newSpecContent = [newLogFilePath, totalCount.toString(10), ...totalLines];
if (copyExecutables) {
env['SEMMLE_COPY_EXECUTABLES_ROOT'] = tempFolder;
env['SEMMLE_COPY_EXECUTABLES_ROOT'] = compoundTempFolder;
envSize += 1;
}
@ -181,7 +182,7 @@ async function run() {
const codeqlRam = process.env['CODEQL_RAM'] || '6500';
core.exportVariable('CODEQL_RAM', codeqlRam);
const databaseFolder = path.resolve(util.workspaceFolder(), 'codeql_databases');
const databaseFolder = path.resolve(util.getRequiredEnvParam('RUNNER_TEMP'), 'codeql_databases');
await io.mkdirP(databaseFolder);
let tracedLanguages: { [key: string]: TracerConfig } = {};
@ -238,8 +239,8 @@ async function run() {
await util.reportActionFailed('init', error.message, error.stack);
return;
}
core.exportVariable(sharedEnv.CODEQL_ACTION_INIT_COMPLETED, 'true');
await util.reportActionSucceeded('init');
core.exportVariable(sharedEnv.CODEQL_ACTION_INIT_COMPLETED, 'true');
}
run().catch(e => {

View file

@ -127,67 +127,63 @@ export function countResultsInSarif(sarif: string): number {
// Returns true iff the upload occurred and succeeded
async function uploadFiles(sarifFiles: string[]): Promise<boolean> {
core.startGroup("Uploading results");
let succeeded = false;
try {
const sentinelEnvVar = "CODEQL_UPLOAD_SARIF";
if (process.env[sentinelEnvVar]) {
core.error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
return false;
}
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
const commitOid = await util.getCommitOid();
const workflowRunIDStr = util.getRequiredEnvParam('GITHUB_RUN_ID');
const ref = util.getRef();
const analysisKey = await util.getAnalysisKey();
const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW');
const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT];
core.info("Uploading sarif files: " + JSON.stringify(sarifFiles));
let sarifPayload = combineSarifFiles(sarifFiles);
sarifPayload = fingerprints.addFingerprints(sarifPayload);
const zipped_sarif = zlib.gzipSync(sarifPayload).toString('base64');
let checkoutPath = core.getInput('checkout_path');
let checkoutURI = fileUrl(checkoutPath);
const workflowRunID = parseInt(workflowRunIDStr, 10);
if (Number.isNaN(workflowRunID)) {
core.setFailed('GITHUB_RUN_ID must define a non NaN workflow run ID');
return false;
}
let matrix: string | undefined = core.getInput('matrix');
if (matrix === "null" || matrix === "") {
matrix = undefined;
}
const toolNames = util.getToolNames(sarifPayload);
const payload = JSON.stringify({
"commit_oid": commitOid,
"ref": ref,
"analysis_key": analysisKey,
"analysis_name": analysisName,
"sarif": zipped_sarif,
"workflow_run_id": workflowRunID,
"checkout_uri": checkoutURI,
"environment": matrix,
"started_at": startedAt,
"tool_names": toolNames,
});
// Log some useful debug info about the info
core.debug("Raw upload size: " + sarifPayload.length + " bytes");
core.debug("Base64 zipped upload size: " + zipped_sarif.length + " bytes");
core.debug("Number of results in upload: " + countResultsInSarif(sarifPayload));
// Make the upload
succeeded = await uploadPayload(payload);
} catch (error) {
core.setFailed(error.message);
const sentinelEnvVar = "CODEQL_UPLOAD_SARIF";
if (process.env[sentinelEnvVar]) {
core.error("Aborting upload: only one run of the codeql/analyze or codeql/upload-sarif actions is allowed per job");
return false;
}
core.exportVariable(sentinelEnvVar, sentinelEnvVar);
const commitOid = await util.getCommitOid();
const workflowRunIDStr = util.getRequiredEnvParam('GITHUB_RUN_ID');
const ref = util.getRef();
const analysisKey = await util.getAnalysisKey();
const analysisName = util.getRequiredEnvParam('GITHUB_WORKFLOW');
const startedAt = process.env[sharedEnv.CODEQL_ACTION_STARTED_AT];
core.info("Uploading sarif files: " + JSON.stringify(sarifFiles));
let sarifPayload = combineSarifFiles(sarifFiles);
sarifPayload = fingerprints.addFingerprints(sarifPayload);
const zipped_sarif = zlib.gzipSync(sarifPayload).toString('base64');
let checkoutPath = core.getInput('checkout_path');
let checkoutURI = fileUrl(checkoutPath);
const workflowRunID = parseInt(workflowRunIDStr, 10);
if (Number.isNaN(workflowRunID)) {
core.setFailed('GITHUB_RUN_ID must define a non NaN workflow run ID');
return false;
}
let matrix: string | undefined = core.getInput('matrix');
if (matrix === "null" || matrix === "") {
matrix = undefined;
}
const toolNames = util.getToolNames(sarifPayload);
const payload = JSON.stringify({
"commit_oid": commitOid,
"ref": ref,
"analysis_key": analysisKey,
"analysis_name": analysisName,
"sarif": zipped_sarif,
"workflow_run_id": workflowRunID,
"checkout_uri": checkoutURI,
"environment": matrix,
"started_at": startedAt,
"tool_names": toolNames,
});
// Log some useful debug info about the info
core.debug("Raw upload size: " + sarifPayload.length + " bytes");
core.debug("Base64 zipped upload size: " + zipped_sarif.length + " bytes");
core.debug("Number of results in upload: " + countResultsInSarif(sarifPayload));
// Make the upload
const succeeded = await uploadPayload(payload);
core.endGroup();
return succeeded;

View file

@ -35,17 +35,6 @@ export function should_abort(actionName: string, requireInitActionHasRun: boolea
return false;
}
/**
* Resolve the path to the workspace folder.
*/
export function workspaceFolder(): string {
let workspaceFolder = process.env['RUNNER_WORKSPACE'];
if (!workspaceFolder)
workspaceFolder = path.resolve('..');
return workspaceFolder;
}
/**
* Get an environment parameter, but throw an error if it is not set.
*/