Skip to content

Commit 1fe0932

Browse files
Merge branch 'master' into autobuild_errors
2 parents 7963db1 + 5bceb2b commit 1fe0932

File tree

10 files changed

+140
-56
lines changed

10 files changed

+140
-56
lines changed

.github/pull_request_template.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
### Merge / deployment checklist
22

33
- Run test builds as necessary. Can be on this repository or elsewhere as needed in order to test the change - please include links to tests in other repos!
4-
- [ ] CodeQL using init/finish actions
4+
- [ ] CodeQL using init/analyze actions
55
- [ ] 3rd party tool using upload action
66
- [ ] Confirm this change is backwards compatible with existing workflows.
77
- [ ] Confirm the [readme](https://github.com/github/codeql-action/blob/master/README.md) has been updated if necessary.

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@
22

33
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.
44

5-
[Sign up for the Advanced Security beta](https://github.com/features/security/advanced-security/signup)
6-
75
## Usage
86

97
To get code scanning results from CodeQL analysis on your repo you can use the following workflow as a template:
@@ -82,6 +80,8 @@ The CodeQL action should be run on `push` events, and on a `schedule`. `Push` ev
8280

8381
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 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).
8482

83+
You can disable the default queries using `disable-default-queries: true`.
84+
8585
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.
8686
Identifying potential files for extraction:
8787

@@ -102,6 +102,8 @@ A config file looks like this:
102102
```yaml
103103
name: "My CodeQL config"
104104
105+
disable-default-queries: true
106+
105107
queries:
106108
- name: In-repo queries (Runs the queries located in the my-queries folder of the repo)
107109
uses: ./my-queries

lib/config-utils.js

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/finalize-db.js

Lines changed: 8 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/upload-lib.js

Lines changed: 48 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 3 additions & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"dependencies": {
1313
"@actions/core": "^1.0.0",
1414
"@actions/exec": "^1.0.1",
15-
"@actions/http-client": "^1.0.4",
15+
"@actions/http-client": "^1.0.8",
1616
"@actions/io": "^1.0.1",
1717
"@actions/tool-cache": "^1.1.2",
1818
"@octokit/rest": "^17.1.0",

src/config-utils.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ export class ExternalQuery {
1717

1818
export class Config {
1919
public name = "";
20+
public disableDefaultQueries = false;
2021
public additionalQueries: string[] = [];
2122
public externalQueries: ExternalQuery[] = [];
2223
public pathsIgnore: string[] = [];
@@ -81,6 +82,10 @@ function initConfig(): Config {
8182
config.name = parsedYAML.name;
8283
}
8384

85+
if (parsedYAML['disable-default-queries'] && typeof parsedYAML['disable-default-queries'] === "boolean") {
86+
config.disableDefaultQueries = parsedYAML['disable-default-queries'];
87+
}
88+
8489
const queries = parsedYAML.queries;
8590
if (queries && queries instanceof Array) {
8691
queries.forEach(query => {

src/finalize-db.ts

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,13 @@ async function resolveQueryLanguages(codeqlCmd: string, config: configUtils.Conf
8282
const noDeclaredLanguage = resolveQueriesOutputObject.noDeclaredLanguage;
8383
const noDeclaredLanguageQueries = Object.keys(noDeclaredLanguage);
8484
if (noDeclaredLanguageQueries.length !== 0) {
85-
core.warning('Some queries do not declare a language:\n' + noDeclaredLanguageQueries.join('\n'));
85+
throw new Error('Some queries do not declare a language, their qlpack.yml file is missing or is invalid');
8686
}
8787

8888
const multipleDeclaredLanguages = resolveQueriesOutputObject.multipleDeclaredLanguages;
8989
const multipleDeclaredLanguagesQueries = Object.keys(multipleDeclaredLanguages);
9090
if (multipleDeclaredLanguagesQueries.length !== 0) {
91-
core.warning('Some queries declare multiple languages:\n' + multipleDeclaredLanguagesQueries.join('\n'));
91+
throw new Error('Some queries declare multiple languages, their qlpack.yml file is missing or is invalid');
9292
}
9393
}
9494

@@ -102,7 +102,12 @@ async function runQueries(codeqlCmd: string, databaseFolder: string, sarifFolder
102102
for (let database of fs.readdirSync(databaseFolder)) {
103103
core.startGroup('Analyzing ' + database);
104104

105-
const additionalQueries = queriesPerLanguage[database] || [];
105+
const queries: string[] = [];
106+
if (!config.disableDefaultQueries) {
107+
queries.push(database + '-code-scanning.qls');
108+
}
109+
queries.push(...(queriesPerLanguage[database] || []));
110+
106111
const sarifFile = path.join(sarifFolder, database + '.sarif');
107112

108113
await exec.exec(codeqlCmd, [
@@ -112,8 +117,7 @@ async function runQueries(codeqlCmd: string, databaseFolder: string, sarifFolder
112117
'--format=sarif-latest',
113118
'--output=' + sarifFile,
114119
'--no-sarif-add-snippets',
115-
database + '-code-scanning.qls',
116-
...additionalQueries,
120+
...queries
117121
]);
118122

119123
core.debug('SARIF results for database ' + database + ' created at "' + sarifFile + '"');

src/upload-lib.ts

Lines changed: 57 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,61 @@ export function combineSarifFiles(sarifFiles: string[]): string {
4747
return JSON.stringify(combinedSarif);
4848
}
4949

50+
// Upload the given payload.
51+
// If the request fails then this will retry a small number of times.
52+
async function uploadPayload(payload) {
53+
core.info('Uploading results');
54+
55+
const githubToken = core.getInput('token');
56+
const ph: auth.BearerCredentialHandler = new auth.BearerCredentialHandler(githubToken);
57+
const client = new http.HttpClient('Code Scanning : Upload SARIF', [ph]);
58+
const url = 'https://api.github.com/repos/' + process.env['GITHUB_REPOSITORY'] + '/code-scanning/analysis';
59+
60+
// Make up to 4 attempts to upload, and sleep for these
61+
// number of seconds between each attempt.
62+
// We don't want to backoff too much to avoid wasting action
63+
// minutes, but just waiting a little bit could maybe help.
64+
const backoffPeriods = [1, 5, 15];
65+
66+
for (let attempt = 0; attempt <= backoffPeriods.length; attempt++) {
67+
68+
const res: http.HttpClientResponse = await client.put(url, payload);
69+
core.debug('response status: ' + res.message.statusCode);
70+
71+
const statusCode = res.message.statusCode;
72+
if (statusCode === 202) {
73+
core.info("Successfully uploaded results");
74+
return;
75+
}
76+
77+
const requestID = res.message.headers["x-github-request-id"];
78+
79+
// On any other status code that's not 5xx mark the upload as failed
80+
if (!statusCode || statusCode < 500 || statusCode >= 600) {
81+
core.setFailed('Upload failed (' + requestID + '): (' + statusCode + ') ' + await res.readBody());
82+
return;
83+
}
84+
85+
// On a 5xx status code we may retry the request
86+
if (attempt < backoffPeriods.length) {
87+
// Log the failure as a warning but don't mark the action as failed yet
88+
core.warning('Upload attempt (' + (attempt + 1) + ' of ' + (backoffPeriods.length + 1) +
89+
') failed (' + requestID + '). Retrying in ' + backoffPeriods[attempt] +
90+
' seconds: (' + statusCode + ') ' + await res.readBody());
91+
// Sleep for the backoff period
92+
await new Promise(r => setTimeout(r, backoffPeriods[attempt] * 1000));
93+
continue;
94+
95+
} else {
96+
// If the upload fails with 5xx then we assume it is a temporary problem
97+
// and not an error that the user has caused or can fix.
98+
// We avoid marking the job as failed to avoid breaking CI workflows.
99+
core.error('Upload failed (' + requestID + '): (' + statusCode + ') ' + await res.readBody());
100+
return;
101+
}
102+
}
103+
}
104+
50105
// Uploads a single sarif file or a directory of sarif files
51106
// depending on what the path happens to refer to.
52107
export async function upload(input: string) {
@@ -112,25 +167,8 @@ async function uploadFiles(sarifFiles: string[]) {
112167
"tool_names": toolNames,
113168
});
114169

115-
core.info('Uploading results');
116-
const githubToken = core.getInput('token');
117-
const ph: auth.BearerCredentialHandler = new auth.BearerCredentialHandler(githubToken);
118-
const client = new http.HttpClient('Code Scanning : Upload SARIF', [ph]);
119-
const url = 'https://api.github.com/repos/' + process.env['GITHUB_REPOSITORY'] + '/code-scanning/analysis';
120-
const res: http.HttpClientResponse = await client.put(url, payload);
121-
const requestID = res.message.headers["x-github-request-id"];
122-
123-
core.debug('response status: ' + res.message.statusCode);
124-
if (res.message.statusCode === 500) {
125-
// If the upload fails with 500 then we assume it is a temporary problem
126-
// with turbo-scan and not an error that the user has caused or can fix.
127-
// We avoid marking the job as failed to avoid breaking CI workflows.
128-
core.error('Upload failed (' + requestID + '): ' + await res.readBody());
129-
} else if (res.message.statusCode !== 202) {
130-
core.setFailed('Upload failed (' + requestID + '): ' + await res.readBody());
131-
} else {
132-
core.info("Successfully uploaded results");
133-
}
170+
// Make the upload
171+
await uploadPayload(payload);
134172

135173
// Mark that we have made an upload
136174
fs.writeFileSync(sentinelFile, '');

0 commit comments

Comments
 (0)