Compare commits

...

95 Commits

Author SHA1 Message Date
Angela P Wen
f0e3dfb303 Merge pull request #1700 from github/update-v2.3.4-570734c55
Merge main into releases/v2
2023-05-24 15:14:53 -07:00
Angela P Wen
0d65621757 Update CHANGELOG.md 2023-05-24 14:49:16 -07:00
github-actions[bot]
c3ae9dcd15 Update changelog for v2.3.4 2023-05-24 21:41:27 +00:00
Angela P Wen
570734c55c Remove unnecessary conditional for Ruby autodetect (#1699)
We should check language autodetect for Ruby unconditionally. We can now move it into the step that checks all other languages.
2023-05-24 18:33:06 +00:00
Angela P Wen
8c923c00a3 Fix Swift PR Checks on nightly-latest CLI (#1696) 2023-05-24 17:59:40 +01:00
Henry Mercer
1245696032 Merge pull request #1687 from github/henrymercer/update-changelog-note
Push back semver CodeQL bundles
2023-05-22 17:11:03 +01:00
Henry Mercer
317cd34a7a Push back semver CodeQL bundles
Push back the first bundle released using a semantic version number to 2.13.4 now that we're skipping 2.13.2.
2023-05-22 11:00:25 +01:00
Henry Mercer
6cfb483131 Merge pull request #1682 from github/henrymercer/semver-bundles
Extract semantic CLI version from URL when requesting specific tools
2023-05-18 11:32:45 +01:00
Henry Mercer
a5f4123fb0 Improve changelog note 2023-05-17 18:23:54 +01:00
Henry Mercer
50931b43dd Add changelog note 2023-05-17 14:57:27 +01:00
Henry Mercer
f54f0731d1 Merge branch 'main' into henrymercer/semver-bundles 2023-05-17 14:45:33 +01:00
Henry Mercer
ca6b925548 Merge pull request #1681 from github/henrymercer/remove-redundant-flag
Remove redundant query help version flag
2023-05-16 19:50:47 +01:00
Henry Mercer
d439786b65 Merge branch 'main' into henrymercer/remove-redundant-flag 2023-05-16 19:21:22 +01:00
Henry Mercer
f5159143cd Merge pull request #1680 from github/henrymercer/handle-swift-promotion
Use `resolve extractor` when finding autobuild scripts
2023-05-16 19:19:11 +01:00
Henry Mercer
a1be09ed8a Remove redundant query help version flag 2023-05-16 18:20:13 +01:00
Henry Mercer
2bf10dc4b9 Extract semantic CLI version from URL when requesting specific tools 2023-05-16 14:47:32 +01:00
Henry Mercer
e422b64793 Use resolve extractor when finding autobuild scripts 2023-05-16 11:18:16 +01:00
Rasmus Wriedt Larsen
5489416722 Merge pull request #1676 from github/rasmuswl/python-disable-dependency-installation
Feature flag to disable python dependency installation
2023-05-16 10:40:47 +02:00
Rasmus Wriedt Larsen
dc0f6da426 Update CHANGELOG.md
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-05-15 12:38:10 +02:00
Rasmus Wriedt Larsen
e1cca2565c Generate JS 2023-05-15 12:05:50 +02:00
Rasmus Wriedt Larsen
cf58ef4480 Update wording for CODEQL_PYTHON warning
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-05-15 12:05:03 +02:00
Rasmus Wriedt Larsen
fce87bbc67 Generate JS 2023-05-12 10:00:31 +02:00
Rasmus Wriedt Larsen
cc641561b7 Improve python warning message
The last dot in `=3.11.` is just slightly confusing, so added single
quotes around the environment variable assignments to make it 100% clear
2023-05-12 09:59:20 +02:00
Rasmus Wriedt Larsen
c237da1a2f Fix linting errors 2023-05-12 09:58:30 +02:00
Rasmus Wriedt Larsen
cbc79bf64b Merge branch 'main' into rasmuswl/python-disable-dependency-installation 2023-05-12 09:55:57 +02:00
Rasmus Wriedt Larsen
b8f39fe0f5 Use features properly in setupPythonExtractor 2023-05-12 09:55:22 +02:00
Henry Mercer
130884e4e1 Merge pull request #1675 from shaikhul/remove-consts
Remove MismatchedBranches check from code scanning workflow validation
2023-05-11 15:45:33 +01:00
Shaikhul Islam
a0755a79b6 Update CHANGELOG.md
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-05-11 10:22:57 -04:00
Shaikhul Islam
903cb278c5 recompile src 2023-05-11 14:16:34 +00:00
Shaikhul Islam
e5fdcd4a8f Apply suggestions from code review
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-05-11 09:29:25 -04:00
Rasmus Wriedt Larsen
eb8a70647a Update CHANGELOG.md 2023-05-11 12:18:29 +02:00
Rasmus Wriedt Larsen
0ccdbf8cd5 Feature flag to disable python dependency installation 2023-05-11 12:14:04 +02:00
Shaikhul Islam
c26fc558ba revert MissingPushHook checks changes 2023-05-10 20:37:56 +00:00
Shaikhul Islam
f8707c9939 update changelog 2023-05-10 15:01:33 +00:00
Shaikhul Islam
699855c048 fix linter issue 2023-05-09 15:05:36 +00:00
Shaikhul Islam
edb138ff88 remove consts MismatchedBranches and MissingPushHook 2023-05-09 14:39:49 +00:00
Andrew Eisenberg
95cfca769b Merge pull request #1673 from github/dependabot/github_actions/peter-evans/create-pull-request-5.0.1
Bump peter-evans/create-pull-request from 5.0.0 to 5.0.1
2023-05-08 12:25:32 -07:00
dependabot[bot]
9c51a58355 Bump peter-evans/create-pull-request from 5.0.0 to 5.0.1
Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 5.0.0 to 5.0.1.
- [Release notes](https://github.com/peter-evans/create-pull-request/releases)
- [Commits](5b4a9f6a9e...284f54f989)

---
updated-dependencies:
- dependency-name: peter-evans/create-pull-request
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-08 18:00:47 +00:00
Aditya Sharad
deb312c60b Merge pull request #1672 from github/aeisenberg/sarif-again
Fix broken regex
2023-05-05 12:53:12 -07:00
Andrew Eisenberg
9824588133 Fix broken regex
`($i)` is not valid for javascript regexes.
2023-05-05 12:02:19 -07:00
Andrew Eisenberg
11fba50273 Merge pull request #1668 from github/aeisenberg/update-sarif-schema 2023-05-05 09:14:24 -07:00
Andrew Eisenberg
684c4b5c77 Update CHANGELOG.md
Co-authored-by: Aditya Sharad <6874315+adityasharad@users.noreply.github.com>
2023-05-05 08:41:11 -07:00
Dave Bartolomeo
1e1aca8165 Merge pull request #1670 from github/mergeback/v2.3.3-to-main-29b1f65c
Mergeback v2.3.3 refs/heads/releases/v2 into main
2023-05-04 15:27:32 -04:00
github-actions[bot]
898fba281b Update checked-in dependencies 2023-05-04 19:02:16 +00:00
github-actions[bot]
913b8b11ad Update changelog and version after v2.3.3 2023-05-04 18:53:44 +00:00
Dave Bartolomeo
29b1f65c5e Merge pull request #1669 from github/update-v2.3.3-318bcc7f8
Merge main into releases/v2
2023-05-04 14:52:14 -04:00
github-actions[bot]
140500d80a Update changelog for v2.3.3 2023-05-04 18:24:50 +00:00
Dave Bartolomeo
318bcc7f84 Merge pull request #1664 from github/update-bundle/codeql-bundle-20230428
Update default bundle to 2.13.1
2023-05-04 00:32:01 -04:00
Dave Bartolomeo
f72bf5dfb3 Fix workflow formatting 2023-05-03 21:43:47 -04:00
Dave Bartolomeo
33461954a5 Merge branch 'main' into update-bundle/codeql-bundle-20230428 2023-05-03 19:02:27 -04:00
Andrew Eisenberg
3df80238a3 Re-run sync.py with new ruamel.yaml 2023-05-02 15:19:05 -07:00
Andrew Eisenberg
ef88842204 Update jsonschema version
Fixes bug in `uniqueItems` property.
2023-05-02 14:26:17 -07:00
Andrew Eisenberg
ece3cbc8ec Update changelog 2023-05-02 13:52:28 -07:00
Andrew Eisenberg
febbadf751 Update the sarif schema file
The version we were using is quite old. Copied the latest from
123e95847b/Schemata/sarif-schema-2.1.0.json

I do not think the sarif spec will be changing any more without
an explicit version update, so this is fine for now.
2023-05-02 13:46:24 -07:00
Andrew Eisenberg
8ca5570701 Merge pull request #1666 from github/aeisenberg/readme-update
Add link to changenote for custom config
2023-05-01 15:07:45 -07:00
Andrew Eisenberg
b1b3d00b62 Add link to changenote for custom config
Also, use a better link in the readme.
2023-05-01 11:06:31 -07:00
Andrew Eisenberg
d2f6dfd52d Merge pull request #1665 from github/aeisenberg/config-param
Add new configuration Parameter
2023-05-01 10:26:31 -07:00
Andrew Eisenberg
cba5616040 Update CHANGELOG.md 2023-05-01 09:21:50 -07:00
github-actions[bot]
40c95932fe Add changelog note 2023-05-01 03:46:54 +00:00
github-actions[bot]
234badad23 Update default bundle to codeql-bundle-20230428 2023-05-01 03:46:50 +00:00
Andrew Eisenberg
824d18c689 Merge remote-tracking branch 'upstream/main' into issue-1589-config-param 2023-04-28 11:34:52 -07:00
Angela P Wen
f31a31c052 Merge pull request #1663 from github/mergeback/v2.3.2-to-main-f3feb00a
Mergeback v2.3.2 refs/heads/releases/v2 into main
2023-04-27 14:00:39 -07:00
github-actions[bot]
e3395de200 Update checked-in dependencies 2023-04-27 18:52:55 +00:00
github-actions[bot]
1cccbfcedc Update changelog and version after v2.3.2 2023-04-27 18:51:28 +00:00
Angela P Wen
f3feb00acb Merge pull request #1662 from github/update-v2.3.2-8b12d99ee
Merge main into releases/v2
2023-04-27 11:49:50 -07:00
github-actions[bot]
1c9e206df3 Update changelog for v2.3.2 2023-04-27 18:18:58 +00:00
Angela P Wen
8b12d99ee5 Fix bug where run attempt was reported as run ID (#1661) 2023-04-27 18:05:34 +00:00
Angela P Wen
dcf71cf79b Merge pull request #1660 from github/mergeback/v2.3.1-to-main-8662eabe
Mergeback v2.3.1 refs/heads/releases/v2 into main
2023-04-26 14:15:40 -07:00
github-actions[bot]
194450bdd6 Update checked-in dependencies 2023-04-26 20:48:31 +00:00
github-actions[bot]
e78ef455a8 Update changelog and version after v2.3.1 2023-04-26 20:44:18 +00:00
Angela P Wen
8662eabe0e Merge pull request #1659 from github/update-v2.3.1-da583b07a
* Update changelog and version after v2.3.0

* Update checked-in dependencies

* Throw full error for CLI bundle download (#1657)

* Add `workload_run_attempt` to analysis upload (#1658)

* Refactor status report upload logic

Previously we had duplicated the logic to check `GITHUB_RUN_ID`. We now call the `getWorkflowRunID()` method for the status report upload method, and move the logic for the run attempt to `getWorkflowRunAttempt()`

* Add `workflow_run_attempt` to analysis payload

* Stop allowing `undefined` run IDs and attempts

Because we already throw an error if the ID or attempt aren't numbers, we don't have to allow `undefined` values into the payload.

* Update changelog for v2.3.1

---------

Co-authored-by: github-actions[bot] <github-actions@github.com>
Co-authored-by: Chuan-kai Lin <cklin@github.com>
Co-authored-by: Angela P Wen <angelapwen@github.com>
2023-04-26 13:42:37 -07:00
github-actions[bot]
1f2f707d99 Update changelog for v2.3.1 2023-04-26 20:16:15 +00:00
Angela P Wen
da583b07a7 Add workload_run_attempt to analysis upload (#1658)
* Refactor status report upload logic

Previously we had duplicated the logic to check `GITHUB_RUN_ID`. We now call the `getWorkflowRunID()` method for the status report upload method, and move the logic for the run attempt to `getWorkflowRunAttempt()`

* Add `workflow_run_attempt` to analysis payload

* Stop allowing `undefined` run IDs and attempts

Because we already throw an error if the ID or attempt aren't numbers, we don't have to allow `undefined` values into the payload.
2023-04-26 02:13:27 +00:00
Angela P Wen
a9648ea7c6 Throw full error for CLI bundle download (#1657) 2023-04-24 07:46:45 -07:00
Chuan-kai Lin
c5f3f016ae Merge pull request #1656 from github/mergeback/v2.3.0-to-main-b2c19fb9
Mergeback v2.3.0 refs/heads/releases/v2 into main
2023-04-21 12:43:38 -07:00
github-actions[bot]
90f053271e Update checked-in dependencies 2023-04-21 19:12:19 +00:00
github-actions[bot]
0f085f964c Update changelog and version after v2.3.0 2023-04-21 19:09:10 +00:00
tgrall
47cec7ab01 add test with config file and input together 2023-04-18 06:01:33 +02:00
tgrall
7b876ae4f4 remove space from json string 2023-04-18 05:46:51 +02:00
tgrall
f398a65921 fix after review from @henrymercer 2023-04-18 05:43:21 +02:00
tgrall
fc374f5e9a remove the documentation about workflow parameters 2023-04-10 07:59:26 +02:00
tgrall
b4e6f81a72 resolve comments from @henrymercer 2023-04-10 07:56:09 +02:00
Tugdual Grall
0b75f471b1 Update CHANGELOG.md : during PR Review
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-04-10 07:38:51 +02:00
Tugdual Grall
c9f360d9af Update README.md : during PR Review
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-04-10 07:38:31 +02:00
Tugdual Grall
d2950c11f0 Update README.md : during PR Review
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-04-10 07:37:52 +02:00
Tugdual Grall
a9fb7d923c Update init/action.yml : PR review
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-04-10 07:37:20 +02:00
Tugdual Grall
696504dcab Accept change in PR
Co-authored-by: Henry Mercer <henry.mercer@me.com>
2023-04-10 07:35:57 +02:00
Tugdual Grall
18f13455eb Merge branch 'main' into issue-1589-config-param 2023-04-10 07:33:09 +02:00
tgrall
fe4a785361 rename new parameter from configuration to config 2023-04-01 07:13:01 +02:00
Tugdual Grall
34231cfd52 fix CI failure - check js 2023-03-18 16:51:49 +00:00
Tugdual Grall
f1fb80a041 Update README.md 2023-03-18 16:17:44 +01:00
Tugdual Grall
f81f52702f Update README.md - typo 2023-03-18 16:17:16 +01:00
Tugdual Grall
2f141340f0 fix linter issues 2023-03-18 15:14:34 +00:00
Tugdual Grall
94786b354b update changelog 2023-03-18 13:48:45 +00:00
Tugdual Grall
ee44252240 - Add new configuration Parameter
- Write test to check it is read from configuration
- Update documentation
2023-03-18 13:40:54 +00:00
103 changed files with 1669 additions and 918 deletions

View File

@@ -1,5 +1,5 @@
name: "Set up Swift"
description: Sets up an appropriate Swift version if Swift is enabled via CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT.
description: Sets up an appropriate Swift version if supported on this platform.
inputs:
codeql-path:
description: Path to the CodeQL CLI executable.
@@ -9,24 +9,29 @@ runs:
steps:
- name: Get Swift version
id: get_swift_version
if: env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true'
if: runner.os != 'Windows'
shell: bash
env:
CODEQL_PATH: ${{ inputs.codeql-path }}
run: |
if [ $RUNNER_OS = "macOS" ]; then
if [[ $RUNNER_OS = "macOS" ]]; then
PLATFORM="osx64"
else # We do not run this step on Windows.
PLATFORM="linux64"
fi
SWIFT_EXTRACTOR_DIR="$("$CODEQL_PATH" resolve languages --format json | jq -r '.swift[0]')"
VERSION="$("$SWIFT_EXTRACTOR_DIR/tools/$PLATFORM/extractor" --version | awk '/version/ { print $3 }')"
# Specify 5.7.0, otherwise setup Action will default to latest minor version.
if [ $VERSION = "5.7" ]; then
VERSION="5.7.0"
if [ $SWIFT_EXTRACTOR_DIR = "null" ]; then
VERSION="null"
else
VERSION="$("$SWIFT_EXTRACTOR_DIR/tools/$PLATFORM/extractor" --version | awk '/version/ { print $3 }')"
# Specify 5.7.0, otherwise setup Action will default to latest minor version.
if [ $VERSION = "5.7" ]; then
VERSION="5.7.0"
fi
fi
echo "version=$VERSION" | tee -a $GITHUB_OUTPUT
- uses: swift-actions/setup-swift@65540b95f51493d65f5e59e97dcef9629ddf11bf # Please update the corresponding SHA in the CLI's CodeQL Action Integration Test.
if: env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true'
if: runner.os != 'Windows' && steps.get_swift_version.outputs.version != 'null'
with:
swift-version: "${{ steps.get_swift_version.outputs.version }}"

View File

@@ -84,8 +84,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -48,8 +48,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -54,8 +54,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -60,8 +60,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -48,8 +48,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -44,8 +44,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -84,8 +84,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -70,8 +70,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -70,8 +70,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -70,8 +70,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -60,8 +60,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -48,8 +48,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -84,8 +84,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV
@@ -114,7 +113,8 @@ jobs:
if: "!(matrix.version == 'stable-20220401' && runner.os == 'Windows')"
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: js/ml-powered/nosql-injection,js/ml-powered/path-injection,js/ml-powered/sql-injection,js/ml-powered/xss
queries-run:
js/ml-powered/nosql-injection,js/ml-powered/path-injection,js/ml-powered/sql-injection,js/ml-powered/xss
queries-not-run: foo,bar
- name: Check results

View File

@@ -70,8 +70,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV
@@ -94,7 +93,7 @@ jobs:
with:
upload-database: false
- name: Check language autodetect for all languages excluding Ruby, Swift
- name: Check language autodetect for all languages excluding Swift
shell: bash
run: |
CPP_DB=${{ fromJson(steps.analysis.outputs.db-locations).cpp }}
@@ -127,11 +126,6 @@ jobs:
echo "Did not create a database for Python, or created it in the wrong location."
exit 1
fi
- name: Check language autodetect for Ruby
if: env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true'
shell: bash
run: |
RUBY_DB=${{ fromJson(steps.analysis.outputs.db-locations).ruby }}
if [[ ! -d $RUBY_DB ]] || [[ ! $RUBY_DB == ${{ runner.temp }}/customDbLocation/* ]]; then
echo "Did not create a database for Ruby, or created it in the wrong location."
@@ -139,7 +133,9 @@ jobs:
fi
- name: Check language autodetect for Swift
if: env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true'
if: >-
env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true' ||
(runner.os != 'Windows' && matrix.version == 'nightly-latest')
shell: bash
run: |
SWIFT_DB=${{ fromJson(steps.analysis.outputs.db-locations).swift }}

View File

@@ -60,8 +60,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV
@@ -83,7 +82,8 @@ jobs:
uses: ./../action/.github/actions/check-sarif
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-run:
javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-not-run: foo,bar
- name: Assert Results

View File

@@ -60,8 +60,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV
@@ -83,7 +82,8 @@ jobs:
uses: ./../action/.github/actions/check-sarif
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-run:
javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-not-run: foo,bar
- name: Assert Results

View File

@@ -60,8 +60,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV
@@ -82,7 +81,8 @@ jobs:
uses: ./../action/.github/actions/check-sarif
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-run:
javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-not-run: foo,bar
- name: Assert Results

View File

@@ -60,8 +60,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV
@@ -82,7 +81,8 @@ jobs:
uses: ./../action/.github/actions/check-sarif
with:
sarif-file: ${{ runner.temp }}/results/javascript.sarif
queries-run: javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-run:
javascript/example/empty-or-one-block,javascript/example/empty-or-one-block,javascript/example/other-query-block,javascript/example/two-block
queries-not-run: foo,bar
- name: Assert Results

View File

@@ -84,8 +84,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -44,8 +44,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

3
.github/workflows/__ruby.yml generated vendored
View File

@@ -54,8 +54,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -54,8 +54,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -48,8 +48,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -54,8 +54,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -44,8 +44,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -44,8 +44,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

3
.github/workflows/__test-proxy.yml generated vendored
View File

@@ -44,8 +44,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -56,8 +56,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -84,8 +84,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -84,8 +84,7 @@ jobs:
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
shell: bash
run: echo "CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT=true" >> $GITHUB_ENV

View File

@@ -49,11 +49,16 @@ jobs:
with:
go-version: ^1.13.1
- uses: ./../action/init
id: init
with:
tools: ${{ steps.prepare-test.outputs.tools-url }}
debug: true
debug-artifact-name: my-debug-artifacts
debug-database-name: my-db
- uses: ./../action/.github/actions/setup-swift
if: matrix.version == 'nightly-latest'
with:
codeql-path: ${{ steps.init.outputs.codeql-path }}
- name: Build code
shell: bash
run: ./build.sh

View File

@@ -36,7 +36,7 @@ jobs:
env:
ENTERPRISE_RELEASES_PATH: ${{ github.workspace }}/enterprise-releases/
- name: Commit Changes
uses: peter-evans/create-pull-request@5b4a9f6a9e2af26e5f02351490b90d01eb8ec1e5 # v5.0.0
uses: peter-evans/create-pull-request@284f54f989303d2699d373481a0cfa13ad5a6666 # v5.0.1
with:
commit-message: Update supported GitHub Enterprise Server versions.
title: Update supported GitHub Enterprise Server versions.

View File

@@ -1,5 +1,28 @@
# CodeQL Action Changelog
## 2.3.4 - 24 May 2023
- Updated the SARIF 2.1.0 JSON schema file to the latest from [oasis-tcs/sarif-spec](https://github.com/oasis-tcs/sarif-spec/blob/123e95847b13fbdd4cbe2120fa5e33355d4a042b/Schemata/sarif-schema-2.1.0.json). [#1668](https://github.com/github/codeql-action/pull/1668)
- We are rolling out a feature in May 2023 that will disable Python dependency installation for new users of the CodeQL Action. This improves the speed of analysis while having only a very minor impact on results. [#1676](https://github.com/github/codeql-action/pull/1676)
- We are improving the way that [CodeQL bundles](https://github.com/github/codeql-action/releases) are tagged to make it possible to easily identify bundles by their CodeQL semantic version. [#1682](https://github.com/github/codeql-action/pull/1682)
- As of CodeQL CLI 2.13.4, CodeQL bundles will be tagged using semantic versions, for example `codeql-bundle-v2.13.4`, instead of timestamps, like `codeql-bundle-20230615`.
- This change does not affect the majority of workflows, and we will not be changing tags for existing bundle releases.
- Some workflows with custom logic that depends on the specific format of the CodeQL bundle tag may need to be updated. For example, if your workflow matches CodeQL bundle tag names against a `codeql-bundle-yyyymmdd` pattern, you should update it to also recognize `codeql-bundle-vx.y.z` tags.
- Remove the requirement for `on.push` and `on.pull_request` to trigger on the same branches. [#1675](https://github.com/github/codeql-action/pull/1675)
## 2.3.3 - 04 May 2023
- Update default CodeQL bundle version to 2.13.1. [#1664](https://github.com/github/codeql-action/pull/1664)
- You can now configure CodeQL within your code scanning workflow by passing a `config` input to the `init` Action. See [Using a custom configuration file](https://aka.ms/code-scanning-docs/config-file) for more information about configuring code scanning. [#1590](https://github.com/github/codeql-action/pull/1590)
## 2.3.2 - 27 Apr 2023
No user facing changes.
## 2.3.1 - 26 Apr 2023
No user facing changes.
## 2.3.0 - 21 Apr 2023
- Update default CodeQL bundle version to 2.13.0. [#1649](https://github.com/github/codeql-action/pull/1649)

View File

@@ -135,7 +135,38 @@ By default, this will override any queries specified in a config file. If you wi
queries: +<local-or-remote-query>,<another-query>
```
### Configuration via `config` input
You can alternatively configure CodeQL using the `config` input to the `init` Action. The value of this input must be a YAML string that follows the configuration file format documented at "[Using a custom configuration file](https://aka.ms/code-scanning-docs/config-file)."
#### Example configuration
```yaml
- uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
config: |
disable-default-queries: true
queries:
- uses: security-extended
- uses: security-and-quality
query-filters:
- include:
tags: /cwe-020/
```
#### Sharing configuration across multiple repositories
You can use Actions or environment variables to share configuration across multiple repositories and to modify configuration without needing to edit the workflow file. In the following example, `vars.CODEQL_CONF` is an [Actions configuration variable](https://docs.github.com/en/actions/learn-github-actions/variables#defining-configuration-variables-for-multiple-workflows):
```yaml
- uses: github/codeql-action/init@v2
with:
languages: ${{ matrix.language }}
config: ${{ vars.CODEQL_CONF }}
```
## Troubleshooting
Read about [troubleshooting code scanning](https://help.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/troubleshooting-code-scanning).

View File

@@ -44,6 +44,9 @@ inputs:
db-location:
description: Path where CodeQL databases should be created. If not specified, a temporary directory will be used.
required: false
config:
description: Configuration passed as a YAML string in the same format as the config-file input. This takes precedence over the config-file input.
required: false
queries:
description: Comma-separated list of additional queries to run. By default, this overrides the same setting in a configuration file; prefix with "+" to use both sets of queries.
required: false

12
lib/actions-util.js generated
View File

@@ -290,16 +290,8 @@ exports.getActionVersion = getActionVersion;
async function createStatusReportBase(actionName, status, actionStartedAt, cause, exception) {
const commitOid = (0, exports.getOptionalInput)("sha") || process.env["GITHUB_SHA"] || "";
const ref = await getRef();
const workflowRunIDStr = process.env["GITHUB_RUN_ID"];
let workflowRunID = -1;
if (workflowRunIDStr) {
workflowRunID = parseInt(workflowRunIDStr, 10);
}
const workflowRunAttemptStr = process.env["GITHUB_RUN_ATTEMPT"];
let workflowRunAttempt = -1;
if (workflowRunAttemptStr) {
workflowRunAttempt = parseInt(workflowRunAttemptStr, 10);
}
const workflowRunID = (0, workflow_1.getWorkflowRunID)();
const workflowRunAttempt = (0, workflow_1.getWorkflowRunAttempt)();
const workflowName = process.env["GITHUB_WORKFLOW"] || "";
const jobName = process.env["GITHUB_JOB"] || "";
const analysis_key = await getAnalysisKey();

File diff suppressed because one or more lines are too long

2
lib/analyze-action.js generated
View File

@@ -163,7 +163,7 @@ async function run() {
const gitHubVersion = await (0, api_client_1.getGitHubVersion)();
const features = new feature_flags_1.Features(gitHubVersion, repositoryNwo, actionsUtil.getTemporaryDirectory(), logger);
await runAutobuildIfLegacyGoWorkflow(config, logger);
dbCreationTimings = await (0, analyze_1.runFinalize)(outputDir, threads, memory, config, logger);
dbCreationTimings = await (0, analyze_1.runFinalize)(outputDir, threads, memory, config, logger, features);
if (actionsUtil.getRequiredInput("skip-queries") !== "true") {
runStats = await (0, analyze_1.runQueries)(outputDir, memory, util.getAddSnippetsFlag(actionsUtil.getRequiredInput("add-snippets")), threads, actionsUtil.getOptionalInput("category"), config, logger, features);
}

File diff suppressed because one or more lines are too long

20
lib/analyze.js generated
View File

@@ -36,6 +36,7 @@ const yaml = __importStar(require("js-yaml"));
const analysisPaths = __importStar(require("./analysis-paths"));
const codeql_1 = require("./codeql");
const configUtils = __importStar(require("./config-utils"));
const feature_flags_1 = require("./feature-flags");
const languages_1 = require("./languages");
const tracer_config_1 = require("./tracer-config");
const util = __importStar(require("./util"));
@@ -47,12 +48,17 @@ class CodeQLAnalysisError extends Error {
}
}
exports.CodeQLAnalysisError = CodeQLAnalysisError;
async function setupPythonExtractor(logger) {
async function setupPythonExtractor(logger, features, codeql) {
const codeqlPython = process.env["CODEQL_PYTHON"];
if (codeqlPython === undefined || codeqlPython.length === 0) {
// If CODEQL_PYTHON is not set, no dependencies were installed, so we don't need to do anything
return;
}
if (await features.getValue(feature_flags_1.Feature.DisablePythonDependencyInstallation, codeql)) {
logger.warning("We recommend that you remove the CODEQL_PYTHON environment variable from your workflow. This environment variable was originally used to specify a Python executable that included the dependencies of your Python code, however Python analysis no longer uses these dependencies." +
"\nIf you used CODEQL_PYTHON to force the version of Python to analyze as, please use CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION instead, such as 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=2.7' or 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=3.11'.");
return;
}
const scriptsFolder = path.resolve(__dirname, "../python-setup");
let output = "";
const options = {
@@ -70,7 +76,7 @@ async function setupPythonExtractor(logger) {
logger.info(`Setting LGTM_PYTHON_SETUP_VERSION=${output}`);
process.env["LGTM_PYTHON_SETUP_VERSION"] = output;
}
async function createdDBForScannedLanguages(codeql, config, logger) {
async function createdDBForScannedLanguages(codeql, config, logger, features) {
// Insert the LGTM_INDEX_X env vars at this point so they are set when
// we extract any scanned languages.
analysisPaths.includeAndExcludeAnalysisPaths(config);
@@ -79,7 +85,7 @@ async function createdDBForScannedLanguages(codeql, config, logger) {
!dbIsFinalized(config, language, logger)) {
logger.startGroup(`Extracting ${language}`);
if (language === languages_1.Language.python) {
await setupPythonExtractor(logger);
await setupPythonExtractor(logger, features, codeql);
}
await codeql.extractScannedLanguage(config, language);
logger.endGroup();
@@ -99,10 +105,10 @@ function dbIsFinalized(config, language, logger) {
}
}
exports.dbIsFinalized = dbIsFinalized;
async function finalizeDatabaseCreation(config, threadsFlag, memoryFlag, logger) {
async function finalizeDatabaseCreation(config, threadsFlag, memoryFlag, logger, features) {
const codeql = await (0, codeql_1.getCodeQL)(config.codeQLCmd);
const extractionStart = perf_hooks_1.performance.now();
await createdDBForScannedLanguages(codeql, config, logger);
await createdDBForScannedLanguages(codeql, config, logger, features);
const extractionTime = perf_hooks_1.performance.now() - extractionStart;
const trapImportStart = perf_hooks_1.performance.now();
for (const language of config.languages) {
@@ -271,7 +277,7 @@ function createQuerySuiteContents(queries, queryFilters) {
return yaml.dump(queries.map((q) => ({ query: q })).concat(queryFilters));
}
exports.createQuerySuiteContents = createQuerySuiteContents;
async function runFinalize(outputDir, threadsFlag, memoryFlag, config, logger) {
async function runFinalize(outputDir, threadsFlag, memoryFlag, config, logger, features) {
try {
await (0, del_1.default)(outputDir, { force: true });
}
@@ -281,7 +287,7 @@ async function runFinalize(outputDir, threadsFlag, memoryFlag, config, logger) {
}
}
await fs.promises.mkdir(outputDir, { recursive: true });
const timings = await finalizeDatabaseCreation(config, threadsFlag, memoryFlag, logger);
const timings = await finalizeDatabaseCreation(config, threadsFlag, memoryFlag, logger, features);
// WARNING: This does not _really_ end tracing, as the tracer will restore its
// critical environment variables and it'll still be active for all processes
// launched from this build step.

File diff suppressed because one or more lines are too long

60
lib/codeql.js generated
View File

@@ -66,7 +66,6 @@ const CODEQL_MINIMUM_VERSION = "2.8.5";
* For convenience, please keep these in descending order. Once a version
* flag is older than the oldest supported version above, it may be removed.
*/
const CODEQL_VERSION_CUSTOM_QUERY_HELP = "2.7.1";
const CODEQL_VERSION_LUA_TRACER_CONFIG = "2.10.0";
const CODEQL_VERSION_LUA_TRACING_GO_WINDOWS_FIXED = "2.10.4";
exports.CODEQL_VERSION_GHES_PACK_DOWNLOAD = "2.10.4";
@@ -122,8 +121,7 @@ async function setupCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliV
};
}
catch (e) {
logger.error((0, util_1.wrapError)(e).message);
throw new Error("Unable to download and extract CodeQL CLI");
throw new Error(`Unable to download and extract CodeQL CLI: ${(0, util_1.wrapError)(e).message}`);
}
}
exports.setupCodeQL = setupCodeQL;
@@ -175,6 +173,7 @@ function setCodeQL(partialCodeql) {
databasePrintBaseline: resolveFunction(partialCodeql, "databasePrintBaseline"),
databaseExportDiagnostics: resolveFunction(partialCodeql, "databaseExportDiagnostics"),
diagnosticsExport: resolveFunction(partialCodeql, "diagnosticsExport"),
resolveExtractor: resolveFunction(partialCodeql, "resolveExtractor"),
};
return cachedCodeQL;
}
@@ -270,10 +269,7 @@ async function getCodeQLForCmd(cmd, checkVersion) {
], { stdin: externalRepositoryToken });
},
async runAutobuild(language) {
const cmdName = process.platform === "win32" ? "autobuild.cmd" : "autobuild.sh";
// The autobuilder for Swift is located in the experimental/ directory.
const possibleExperimentalDir = language === languages_1.Language.swift ? "experimental" : "";
const autobuildCmd = path.join(path.dirname(cmd), possibleExperimentalDir, language, "tools", cmdName);
const autobuildCmd = path.join(await this.resolveExtractor(language), "tools", process.platform === "win32" ? "autobuild.cmd" : "autobuild.sh");
// Update JAVA_TOOL_OPTIONS to contain '-Dhttp.keepAlive=false'
// This is because of an issue with Azure pipelines timing out connections after 4 minutes
// and Maven not properly handling closed connections
@@ -302,31 +298,9 @@ async function getCodeQLForCmd(cmd, checkVersion) {
},
async extractScannedLanguage(config, language) {
const databasePath = util.getCodeQLDatabasePath(config, language);
// Get extractor location
//
// Request it using `format=json` so we don't need to strip the trailing new line generated by
// the CLI.
let extractorPath = "";
await new toolrunner.ToolRunner(cmd, [
"resolve",
"extractor",
"--format=json",
`--language=${language}`,
...getExtraOptionsFromEnv(["resolve", "extractor"]),
], {
silent: true,
listeners: {
stdout: (data) => {
extractorPath += data.toString();
},
stderr: (data) => {
process.stderr.write(data);
},
},
}).exec();
// Set trace command
const ext = process.platform === "win32" ? ".cmd" : ".sh";
const traceCommand = path.resolve(JSON.parse(extractorPath), "tools", `autobuild${ext}`);
const traceCommand = path.resolve(await this.resolveExtractor(language), "tools", `autobuild${ext}`);
// Run trace command
await (0, toolrunner_error_catcher_1.toolrunnerErrorCatcher)(cmd, [
"database",
@@ -439,12 +413,11 @@ async function getCodeQLForCmd(cmd, checkVersion) {
addSnippetsFlag,
"--print-diagnostics-summary",
"--print-metrics-summary",
"--sarif-add-query-help",
"--sarif-group-rules-by-pack",
...(await getCodeScanningConfigExportArguments(config, this, features)),
...getExtraOptionsFromEnv(["database", "interpret-results"]),
];
if (await util.codeQlVersionAbove(this, CODEQL_VERSION_CUSTOM_QUERY_HELP))
codeqlArgs.push("--sarif-add-query-help");
if (automationDetailsId !== undefined) {
codeqlArgs.push("--sarif-category", automationDetailsId);
}
@@ -582,6 +555,29 @@ async function getCodeQLForCmd(cmd, checkVersion) {
}
await new toolrunner.ToolRunner(cmd, args).exec();
},
async resolveExtractor(language) {
// Request it using `format=json` so we don't need to strip the trailing new line generated by
// the CLI.
let extractorPath = "";
await new toolrunner.ToolRunner(cmd, [
"resolve",
"extractor",
"--format=json",
`--language=${language}`,
...getExtraOptionsFromEnv(["resolve", "extractor"]),
], {
silent: true,
listeners: {
stdout: (data) => {
extractorPath += data.toString();
},
stderr: (data) => {
process.stderr.write(data);
},
},
}).exec();
return JSON.parse(extractorPath);
},
};
// To ensure that status reports include the CodeQL CLI version wherever
// possible, we want to call getVersion(), which populates the version value

File diff suppressed because one or more lines are too long

98
lib/codeql.test.js generated
View File

@@ -49,20 +49,11 @@ const testing_utils_1 = require("./testing-utils");
const util = __importStar(require("./util"));
const util_1 = require("./util");
(0, testing_utils_1.setupTests)(ava_1.default);
const sampleApiDetails = {
auth: "token",
url: "https://github.com",
apiURL: "https://api.github.com",
};
const sampleGHAEApiDetails = {
auth: "token",
url: "https://example.githubenterprise.com",
apiURL: "https://example.githubenterprise.com/api/v3",
};
const SAMPLE_DEFAULT_CLI_VERSION = {
cliVersion: "2.0.0",
variant: util.GitHubVariant.DOTCOM,
};
let stubConfig;
ava_1.default.beforeEach(() => {
(0, util_1.initializeEnvironment)("1.2.3");
@@ -91,34 +82,13 @@ ava_1.default.beforeEach(() => {
trapCacheDownloadTime: 0,
};
});
/**
* Mocks the API for downloading the bundle tagged `tagName`.
*
* @returns the download URL for the bundle. This can be passed to the tools parameter of
* `codeql.setupCodeQL`.
*/
function mockDownloadApi({ apiDetails = sampleApiDetails, isPinned, repo = "github/codeql-action", platformSpecific = true, tagName, }) {
const platform = process.platform === "win32"
? "win64"
: process.platform === "linux"
? "linux64"
: "osx64";
const baseUrl = apiDetails?.url ?? "https://example.com";
const relativeUrl = apiDetails
? `/${repo}/releases/download/${tagName}/codeql-bundle${platformSpecific ? `-${platform}` : ""}.tar.gz`
: `/download/${tagName}/codeql-bundle.tar.gz`;
(0, nock_1.default)(baseUrl)
.get(relativeUrl)
.replyWithFile(200, path_1.default.join(__dirname, `/../src/testdata/codeql-bundle${isPinned ? "-pinned" : ""}.tar.gz`));
return `${baseUrl}${relativeUrl}`;
}
async function installIntoToolcache({ apiDetails = sampleApiDetails, cliVersion, isPinned, tagName, tmpDir, }) {
const url = mockDownloadApi({ apiDetails, isPinned, tagName });
async function installIntoToolcache({ apiDetails = testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, cliVersion, isPinned, tagName, tmpDir, }) {
const url = (0, testing_utils_1.mockBundleDownloadApi)({ apiDetails, isPinned, tagName });
await codeql.setupCodeQL(cliVersion !== undefined ? undefined : url, apiDetails, tmpDir, util.GitHubVariant.GHES, cliVersion !== undefined
? { cliVersion, tagName, variant: util.GitHubVariant.GHES }
: SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
: testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
}
function mockReleaseApi({ apiDetails = sampleApiDetails, assetNames, tagName, }) {
function mockReleaseApi({ apiDetails = testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, assetNames, tagName, }) {
return (0, nock_1.default)(apiDetails.apiURL)
.get(`/repos/github/codeql-action/releases/tags/${tagName}`)
.reply(200, {
@@ -149,11 +119,11 @@ function mockApiDetails(apiDetails) {
const versions = ["20200601", "20200610"];
for (let i = 0; i < versions.length; i++) {
const version = versions[i];
const url = mockDownloadApi({
const url = (0, testing_utils_1.mockBundleDownloadApi)({
tagName: `codeql-bundle-${version}`,
isPinned: false,
});
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
const result = await codeql.setupCodeQL(url, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, util.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.assert(toolcache.find("CodeQL", `0.0.0-${version}`));
t.is(result.toolsVersion, `0.0.0-${version}`);
t.is(result.toolsSource, init_1.ToolsSource.Download);
@@ -170,10 +140,10 @@ function mockApiDetails(apiDetails) {
isPinned: true,
tmpDir,
});
const url = mockDownloadApi({
const url = (0, testing_utils_1.mockBundleDownloadApi)({
tagName: "codeql-bundle-20200610",
});
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
const result = await codeql.setupCodeQL(url, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, util.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.assert(toolcache.find("CodeQL", "0.0.0-20200610"));
t.deepEqual(result.toolsVersion, "0.0.0-20200610");
t.is(result.toolsSource, init_1.ToolsSource.Download);
@@ -198,16 +168,16 @@ for (const { cliVersion, expectedToolcacheVersion, } of EXPLICITLY_REQUESTED_BUN
(0, ava_1.default)(`caches an explicitly requested bundle containing CLI ${cliVersion} as ${expectedToolcacheVersion}`, async (t) => {
await util.withTmpDir(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
mockApiDetails(sampleApiDetails);
mockApiDetails(testing_utils_1.SAMPLE_DOTCOM_API_DETAILS);
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
const releaseApiMock = mockReleaseApi({
assetNames: [`cli-version-${cliVersion}.txt`],
tagName: "codeql-bundle-20200610",
});
const url = mockDownloadApi({
const url = (0, testing_utils_1.mockBundleDownloadApi)({
tagName: "codeql-bundle-20200610",
});
const result = await codeql.setupCodeQL(url, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
const result = await codeql.setupCodeQL(url, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, util.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.assert(releaseApiMock.isDone(), "Releases API should have been called");
t.assert(toolcache.find("CodeQL", expectedToolcacheVersion));
t.deepEqual(result.toolsVersion, cliVersion);
@@ -220,19 +190,19 @@ for (const { githubReleases, toolcacheVersion } of [
// Test that we use the tools from the toolcache when `SAMPLE_DEFAULT_CLI_VERSION` is requested
// and `SAMPLE_DEFAULT_CLI_VERSION-` is in the toolcache.
{
toolcacheVersion: SAMPLE_DEFAULT_CLI_VERSION.cliVersion,
toolcacheVersion: testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION.cliVersion,
},
{
githubReleases: {
"codeql-bundle-20230101": `cli-version-${SAMPLE_DEFAULT_CLI_VERSION.cliVersion}.txt`,
"codeql-bundle-20230101": `cli-version-${testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION.cliVersion}.txt`,
},
toolcacheVersion: "0.0.0-20230101",
},
{
toolcacheVersion: `${SAMPLE_DEFAULT_CLI_VERSION.cliVersion}-20230101`,
toolcacheVersion: `${testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION.cliVersion}-20230101`,
},
]) {
(0, ava_1.default)(`uses tools from toolcache when ${SAMPLE_DEFAULT_CLI_VERSION.cliVersion} is requested and ` +
(0, ava_1.default)(`uses tools from toolcache when ${testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION.cliVersion} is requested and ` +
`${toolcacheVersion} is installed`, async (t) => {
await util.withTmpDir(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
@@ -256,8 +226,8 @@ for (const { githubReleases, toolcacheVersion } of [
}))),
}));
}
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.is(result.toolsVersion, SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
const result = await codeql.setupCodeQL(undefined, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, util.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.is(result.toolsVersion, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
t.is(result.toolsSource, init_1.ToolsSource.Toolcache);
t.is(result.toolsDownloadDurationMs, undefined);
});
@@ -272,7 +242,7 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
isPinned: true,
tmpDir,
});
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, {
const result = await codeql.setupCodeQL(undefined, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, variant, {
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
@@ -292,10 +262,10 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
isPinned: false,
tmpDir,
});
mockDownloadApi({
(0, testing_utils_1.mockBundleDownloadApi)({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL(undefined, sampleApiDetails, tmpDir, variant, {
const result = await codeql.setupCodeQL(undefined, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, variant, {
cliVersion: defaults.cliVersion,
tagName: defaults.bundleVersion,
variant,
@@ -316,10 +286,10 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
isPinned: true,
tmpDir,
});
mockDownloadApi({
(0, testing_utils_1.mockBundleDownloadApi)({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL("latest", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
const result = await codeql.setupCodeQL("latest", testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, util.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.deepEqual(result.toolsVersion, defaults.cliVersion);
t.is(result.toolsSource, init_1.ToolsSource.Download);
t.assert(Number.isInteger(result.toolsDownloadDurationMs));
@@ -375,18 +345,18 @@ for (const isBundleVersionInUrl of [true, false]) {
(0, ava_1.default)("bundle URL from another repo is cached as 0.0.0-bundleVersion", async (t) => {
await util.withTmpDir(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
mockApiDetails(sampleApiDetails);
mockApiDetails(testing_utils_1.SAMPLE_DOTCOM_API_DETAILS);
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
const releasesApiMock = mockReleaseApi({
assetNames: ["cli-version-2.12.2.txt"],
tagName: "codeql-bundle-20230203",
});
mockDownloadApi({
(0, testing_utils_1.mockBundleDownloadApi)({
repo: "codeql-testing/codeql-cli-nightlies",
platformSpecific: false,
tagName: "codeql-bundle-20230203",
});
const result = await codeql.setupCodeQL("https://github.com/codeql-testing/codeql-cli-nightlies/releases/download/codeql-bundle-20230203/codeql-bundle.tar.gz", sampleApiDetails, tmpDir, util.GitHubVariant.DOTCOM, SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
const result = await codeql.setupCodeQL("https://github.com/codeql-testing/codeql-cli-nightlies/releases/download/codeql-bundle-20230203/codeql-bundle.tar.gz", testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, tmpDir, util.GitHubVariant.DOTCOM, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, (0, logging_1.getRunnerLogger)(true), false);
t.is(result.toolsVersion, "0.0.0-20230203");
t.is(result.toolsSource, init_1.ToolsSource.Download);
t.true(Number.isInteger(result.toolsDownloadDurationMs));
@@ -418,24 +388,6 @@ for (const isBundleVersionInUrl of [true, false]) {
t.throws(() => codeql.getExtraOptions({ foo: 87 }, ["foo"], []));
t.throws(() => codeql.getExtraOptions({ "*": [42], foo: { "*": 87, bar: [99] } }, ["foo", "bar"], []));
});
(0, ava_1.default)("databaseInterpretResults() does not set --sarif-add-query-help for 2.7.0", async (t) => {
const runnerConstructorStub = stubToolRunnerConstructor();
const codeqlObject = await codeql.getCodeQLForTesting();
sinon.stub(codeqlObject, "getVersion").resolves("2.7.0");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.false(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be absent, but it is present");
});
(0, ava_1.default)("databaseInterpretResults() sets --sarif-add-query-help for 2.7.1", async (t) => {
const runnerConstructorStub = stubToolRunnerConstructor();
const codeqlObject = await codeql.getCodeQLForTesting();
sinon.stub(codeqlObject, "getVersion").resolves("2.7.1");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults("", [], "", "", "", "-v", "", stubConfig, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.true(runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"), "--sarif-add-query-help should be present, but it is absent");
});
(0, ava_1.default)("databaseInitCluster() without injected codescanning config", async (t) => {
await util.withTmpDir(async (tempDir) => {
const runnerConstructorStub = stubToolRunnerConstructor();

File diff suppressed because one or more lines are too long

11
lib/config-utils.js generated
View File

@@ -932,8 +932,17 @@ function dbLocationOrDefault(dbLocation, tempDir) {
* This will parse the config from the user input if present, or generate
* a default config. The parsed config is then stored to a known location.
*/
async function initConfig(languagesInput, queriesInput, packsInput, registriesInput, configFile, dbLocation, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeQL, workspacePath, gitHubVersion, apiDetails, features, logger) {
async function initConfig(languagesInput, queriesInput, packsInput, registriesInput, configFile, dbLocation, configInput, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeQL, workspacePath, gitHubVersion, apiDetails, features, logger) {
let config;
// if configInput is set, it takes precedence over configFile
if (configInput) {
if (configFile) {
logger.warning(`Both a config file and config input were provided. Ignoring config file.`);
}
configFile = path.resolve(workspacePath, "user-config-from-action.yml");
fs.writeFileSync(configFile, configInput);
logger.debug(`Using config from action input: ${configFile}`);
}
// If no config file was provided create an empty one
if (!configFile) {
logger.debug("No configuration file was provided");

File diff suppressed because one or more lines are too long

137
lib/config-utils.test.js generated
View File

@@ -102,8 +102,8 @@ function mockListLanguages(languages) {
return { packs: [] };
},
});
const config = await configUtils.initConfig(languages, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), logger);
t.deepEqual(config, await configUtils.getDefaultConfig(languages, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), logger));
const config = await configUtils.initConfig(languages, undefined, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), logger);
t.deepEqual(config, await configUtils.getDefaultConfig(languages, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), logger));
});
});
(0, ava_1.default)("loading config saves config", async (t) => {
@@ -128,7 +128,7 @@ function mockListLanguages(languages) {
t.false(fs.existsSync(configUtils.getPathToParsedConfigFile(tmpDir)));
// Sanity check that getConfig returns undefined before we have called initConfig
t.deepEqual(await configUtils.getConfig(tmpDir, logger), undefined);
const config1 = await configUtils.initConfig("javascript,python", undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), logger);
const config1 = await configUtils.initConfig("javascript,python", undefined, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), logger);
// The saved config file should now exist
t.true(fs.existsSync(configUtils.getPathToParsedConfigFile(tmpDir)));
// And that same newly-initialised config should now be returned by getConfig
@@ -144,7 +144,7 @@ function mockListLanguages(languages) {
(0, ava_1.default)("load input outside of workspace", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
try {
await configUtils.initConfig(undefined, undefined, undefined, undefined, "../input", undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(undefined, undefined, undefined, undefined, "../input", undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -157,7 +157,7 @@ function mockListLanguages(languages) {
// no filename given, just a repo
const configFile = "octo-org/codeql-config@main";
try {
await configUtils.initConfig(undefined, undefined, undefined, undefined, configFile, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(undefined, undefined, undefined, undefined, configFile, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -171,7 +171,7 @@ function mockListLanguages(languages) {
const configFile = "input";
t.false(fs.existsSync(path.join(tmpDir, configFile)));
try {
await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -247,7 +247,7 @@ function mockListLanguages(languages) {
};
const languages = "javascript";
const configFilePath = createConfigFile(inputFileContents, tmpDir);
const actualConfig = await configUtils.initConfig(languages, undefined, undefined, undefined, configFilePath, undefined, false, false, "my-artifact", "my-db", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const actualConfig = await configUtils.initConfig(languages, undefined, undefined, undefined, configFilePath, undefined, undefined, false, false, "my-artifact", "my-db", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Should exactly equal the object we constructed earlier
t.deepEqual(actualConfig, expectedConfig);
});
@@ -286,7 +286,7 @@ function mockListLanguages(languages) {
fs.mkdirSync(path.join(tmpDir, "foo"));
const languages = "javascript";
const configFilePath = createConfigFile(inputFileContents, tmpDir);
await configUtils.initConfig(languages, undefined, undefined, undefined, configFilePath, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(languages, undefined, undefined, undefined, configFilePath, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolve queries was called correctly
t.deepEqual(resolveQueriesArgs.length, 1);
t.deepEqual(resolveQueriesArgs[0].queries, [
@@ -332,7 +332,7 @@ function queriesToResolvedQueryForm(queries) {
},
});
const languages = "javascript";
const config = await configUtils.initConfig(languages, undefined, undefined, undefined, configFilePath, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const config = await configUtils.initConfig(languages, undefined, undefined, undefined, configFilePath, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolveQueries was called correctly
// It'll be called once for the default queries
// and once for `./foo` from the config file.
@@ -368,7 +368,7 @@ function queriesToResolvedQueryForm(queries) {
},
});
const languages = "javascript";
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, configFilePath, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, configFilePath, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolveQueries was called correctly
// It'll be called once for the default queries and once for `./override`,
// but won't be called for './foo' from the config file.
@@ -403,7 +403,7 @@ function queriesToResolvedQueryForm(queries) {
},
});
const languages = "javascript";
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, configFilePath, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, configFilePath, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolveQueries was called correctly
// It'll be called once for `./workflow-query`,
// but won't be called for the default one since that was disabled
@@ -432,7 +432,7 @@ function queriesToResolvedQueryForm(queries) {
},
});
const languages = "javascript";
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolveQueries was called correctly:
// It'll be called once for the default queries,
// and then once for each of the two queries from the workflow
@@ -474,7 +474,7 @@ function queriesToResolvedQueryForm(queries) {
},
});
const languages = "javascript";
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, configFilePath, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const config = await configUtils.initConfig(languages, testQueries, undefined, undefined, configFilePath, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolveQueries was called correctly
// It'll be called once for the default queries,
// once for each of additional1 and additional2,
@@ -495,6 +495,97 @@ function queriesToResolvedQueryForm(queries) {
t.true(config.queries["javascript"].custom[2].queries[0].endsWith(`${path.sep}foo`));
});
});
(0, ava_1.default)("Queries can be specified using config input", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
const configInput = `
name: my config
queries:
- uses: ./foo
packs:
javascript:
- a/b@1.2.3
python:
- c/d@1.2.3
`;
fs.mkdirSync(path.join(tmpDir, "foo"));
const resolveQueriesArgs = [];
const codeQL = (0, codeql_1.setCodeQL)({
async resolveQueries(queries, extraSearchPath) {
resolveQueriesArgs.push({ queries, extraSearchPath });
return queriesToResolvedQueryForm(queries);
},
async packDownload() {
return { packs: [] };
},
});
// Only JS, python packs will be ignored
const languages = "javascript";
const config = await configUtils.initConfig(languages, undefined, undefined, undefined, undefined, undefined, configInput, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolveQueries was called correctly
// It'll be called once for the default queries
// and once for `./foo` from the config file.
t.deepEqual(resolveQueriesArgs.length, 2);
t.deepEqual(resolveQueriesArgs[1].queries.length, 1);
t.true(resolveQueriesArgs[1].queries[0].endsWith(`${path.sep}foo`));
t.deepEqual(config.packs, {
[languages_1.Language.javascript]: ["a/b@1.2.3"],
});
// Now check that the end result contains the default queries and the query from config
t.deepEqual(config.queries["javascript"].builtin.length, 1);
t.deepEqual(config.queries["javascript"].custom.length, 1);
t.true(config.queries["javascript"].builtin[0].endsWith("javascript-code-scanning.qls"));
t.true(config.queries["javascript"].custom[0].queries[0].endsWith(`${path.sep}foo`));
});
});
(0, ava_1.default)("Using config input and file together, config input should be used.", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env["RUNNER_TEMP"] = tmpDir;
process.env["GITHUB_WORKSPACE"] = tmpDir;
const inputFileContents = `
name: my config
queries:
- uses: ./foo_file`;
const configFilePath = createConfigFile(inputFileContents, tmpDir);
const configInput = `
name: my config
queries:
- uses: ./foo
packs:
javascript:
- a/b@1.2.3
python:
- c/d@1.2.3
`;
fs.mkdirSync(path.join(tmpDir, "foo"));
const resolveQueriesArgs = [];
const codeQL = (0, codeql_1.setCodeQL)({
async resolveQueries(queries, extraSearchPath) {
resolveQueriesArgs.push({ queries, extraSearchPath });
return queriesToResolvedQueryForm(queries);
},
async packDownload() {
return { packs: [] };
},
});
// Only JS, python packs will be ignored
const languages = "javascript";
const config = await configUtils.initConfig(languages, undefined, undefined, undefined, undefined, configFilePath, configInput, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
// Check resolveQueries was called correctly
// It'll be called once for the default queries
// and once for `./foo` from the config file.
t.deepEqual(resolveQueriesArgs.length, 2);
t.deepEqual(resolveQueriesArgs[1].queries.length, 1);
t.true(resolveQueriesArgs[1].queries[0].endsWith(`${path.sep}foo`));
t.deepEqual(config.packs, {
[languages_1.Language.javascript]: ["a/b@1.2.3"],
});
// Now check that the end result contains the default queries and the query from config
t.deepEqual(config.queries["javascript"].builtin.length, 1);
t.deepEqual(config.queries["javascript"].custom.length, 1);
t.true(config.queries["javascript"].builtin[0].endsWith("javascript-code-scanning.qls"));
t.true(config.queries["javascript"].custom[0].queries[0].endsWith(`${path.sep}foo`));
});
});
(0, ava_1.default)("Invalid queries in workflow file handled correctly", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
const queries = "foo/bar@v1@v3";
@@ -516,7 +607,7 @@ function queriesToResolvedQueryForm(queries) {
},
});
try {
await configUtils.initConfig(languages, queries, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(languages, queries, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.fail("initConfig did not throw error");
}
catch (err) {
@@ -562,7 +653,7 @@ function queriesToResolvedQueryForm(queries) {
fs.mkdirSync(path.join(tmpDir, "foo/bar/dev"), { recursive: true });
const configFile = "octo-org/codeql-config/config.yaml@main";
const languages = "javascript";
await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.assert(spyGetContents.called);
});
});
@@ -572,7 +663,7 @@ function queriesToResolvedQueryForm(queries) {
mockGetContents(dummyResponse);
const repoReference = "octo-org/codeql-config/config.yaml@main";
try {
await configUtils.initConfig(undefined, undefined, undefined, undefined, repoReference, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(undefined, undefined, undefined, undefined, repoReference, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -588,7 +679,7 @@ function queriesToResolvedQueryForm(queries) {
mockGetContents(dummyResponse);
const repoReference = "octo-org/codeql-config/config.yaml@main";
try {
await configUtils.initConfig(undefined, undefined, undefined, undefined, repoReference, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(undefined, undefined, undefined, undefined, repoReference, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -608,7 +699,7 @@ function queriesToResolvedQueryForm(queries) {
},
});
try {
await configUtils.initConfig(undefined, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(undefined, undefined, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -620,7 +711,7 @@ function queriesToResolvedQueryForm(queries) {
return await util.withTmpDir(async (tmpDir) => {
const languages = "rubbish,english";
try {
await configUtils.initConfig(languages, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(languages, undefined, undefined, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, (0, codeql_1.getCachedCodeQL)(), tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -651,7 +742,7 @@ function queriesToResolvedQueryForm(queries) {
const configFile = path.join(tmpDir, "codeql-config.yaml");
fs.writeFileSync(configFile, inputFileContents);
const languages = "javascript";
const { packs } = await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const { packs } = await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.deepEqual(packs, {
[languages_1.Language.javascript]: ["a/b@1.2.3"],
});
@@ -688,7 +779,7 @@ function queriesToResolvedQueryForm(queries) {
fs.writeFileSync(configFile, inputFileContents);
fs.mkdirSync(path.join(tmpDir, "foo"));
const languages = "javascript,python,cpp";
const { packs, queries } = await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
const { packs, queries } = await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
t.deepEqual(packs, {
[languages_1.Language.javascript]: ["a/b@1.2.3"],
[languages_1.Language.python]: ["c/d@1.2.3"],
@@ -734,7 +825,7 @@ function doInvalidInputTest(testName, inputFileContents, expectedErrorMessageGen
const inputFile = path.join(tmpDir, configFile);
fs.writeFileSync(inputFile, inputFileContents, "utf8");
try {
await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
await configUtils.initConfig(languages, undefined, undefined, undefined, configFile, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)([]), (0, logging_1.getRunnerLogger)(true));
throw new Error("initConfig did not throw error");
}
catch (err) {
@@ -991,7 +1082,7 @@ const mlPoweredQueriesMacro = ava_1.default.macro({
return { packs: [] };
},
});
const { packs } = await configUtils.initConfig("javascript", queriesInput, packsInput, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example " }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)(isMlPoweredQueriesEnabled ? [feature_flags_1.Feature.MlPoweredQueriesEnabled] : []), (0, logging_1.getRunnerLogger)(true));
const { packs } = await configUtils.initConfig("javascript", queriesInput, packsInput, undefined, undefined, undefined, undefined, false, false, "", "", { owner: "github", repo: "example" }, tmpDir, codeQL, tmpDir, gitHubVersion, sampleApiDetails, (0, testing_utils_1.createFeatures)(isMlPoweredQueriesEnabled ? [feature_flags_1.Feature.MlPoweredQueriesEnabled] : []), (0, logging_1.getRunnerLogger)(true));
if (expectedVersionString !== undefined) {
t.deepEqual(packs, {
[languages_1.Language.javascript]: [

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-20230414",
"cliVersion": "2.13.0",
"priorBundleVersion": "codeql-bundle-20230403",
"priorCliVersion": "2.12.6"
"bundleVersion": "codeql-bundle-20230428",
"cliVersion": "2.13.1",
"priorBundleVersion": "codeql-bundle-20230414",
"priorCliVersion": "2.13.0"
}

11
lib/feature-flags.js generated
View File

@@ -40,6 +40,7 @@ var Feature;
Feature["ExportDiagnosticsEnabled"] = "export_diagnostics_enabled";
Feature["MlPoweredQueriesEnabled"] = "ml_powered_queries_enabled";
Feature["UploadFailedSarifEnabled"] = "upload_failed_sarif_enabled";
Feature["DisablePythonDependencyInstallation"] = "disable_python_dependency_installation";
})(Feature = exports.Feature || (exports.Feature = {}));
exports.featureConfig = {
[Feature.DisableKotlinAnalysisEnabled]: {
@@ -72,6 +73,16 @@ exports.featureConfig = {
minimumVersion: "2.11.3",
defaultValue: true,
},
[Feature.DisablePythonDependencyInstallation]: {
envVar: "CODEQL_ACTION_DISABLE_PYTHON_DEPENDENCY_INSTALLATION",
// Although the python extractor only started supporting not extracting installed
// dependencies in 2.13.1, the init-action can still benefit from not installing
// dependencies no matter what codeql version we are using, so therefore the
// minimumVersion is set to 'undefined'. This means that with an old CodeQL version,
// packages available with current python3 installation might get extracted.
minimumVersion: undefined,
defaultValue: false,
},
};
exports.FEATURE_FLAGS_FILE_NAME = "cached-feature-flags.json";
/**

File diff suppressed because one or more lines are too long

21
lib/init-action.js generated
View File

@@ -128,7 +128,7 @@ async function run() {
toolsDownloadDurationMs = initCodeQLResult.toolsDownloadDurationMs;
toolsVersion = initCodeQLResult.toolsVersion;
toolsSource = initCodeQLResult.toolsSource;
config = await (0, init_1.initConfig)((0, actions_util_1.getOptionalInput)("languages"), (0, actions_util_1.getOptionalInput)("queries"), (0, actions_util_1.getOptionalInput)("packs"), registriesInput, (0, actions_util_1.getOptionalInput)("config-file"), (0, actions_util_1.getOptionalInput)("db-location"), getTrapCachingEnabled(),
config = await (0, init_1.initConfig)((0, actions_util_1.getOptionalInput)("languages"), (0, actions_util_1.getOptionalInput)("queries"), (0, actions_util_1.getOptionalInput)("packs"), registriesInput, (0, actions_util_1.getOptionalInput)("config-file"), (0, actions_util_1.getOptionalInput)("db-location"), (0, actions_util_1.getOptionalInput)("config"), getTrapCachingEnabled(),
// Debug mode is enabled if:
// - The `init` Action is passed `debug: true`.
// - Actions step debugging is enabled (e.g. by [enabling debug logging for a rerun](https://docs.github.com/en/actions/managing-workflow-runs/re-running-workflows-and-jobs#re-running-all-the-jobs-in-a-workflow),
@@ -136,12 +136,17 @@ async function run() {
(0, actions_util_1.getOptionalInput)("debug") === "true" || core.isDebug(), (0, actions_util_1.getOptionalInput)("debug-artifact-name") || util_1.DEFAULT_DEBUG_ARTIFACT_NAME, (0, actions_util_1.getOptionalInput)("debug-database-name") || util_1.DEFAULT_DEBUG_DATABASE_NAME, repositoryNwo, (0, actions_util_1.getTemporaryDirectory)(), codeql, (0, util_1.getRequiredEnvParam)("GITHUB_WORKSPACE"), gitHubVersion, apiDetails, features, logger);
if (config.languages.includes(languages_1.Language.python) &&
(0, actions_util_1.getRequiredInput)("setup-python-dependencies") === "true") {
try {
await (0, init_1.installPythonDeps)(codeql, logger);
if (await features.getValue(feature_flags_1.Feature.DisablePythonDependencyInstallation, codeql)) {
logger.info("Skipping python dependency installation");
}
catch (unwrappedError) {
const error = (0, util_1.wrapError)(unwrappedError);
logger.warning(`${error.message} You can call this action with 'setup-python-dependencies: false' to disable this process`);
else {
try {
await (0, init_1.installPythonDeps)(codeql, logger);
}
catch (unwrappedError) {
const error = (0, util_1.wrapError)(unwrappedError);
logger.warning(`${error.message} You can call this action with 'setup-python-dependencies: false' to disable this process`);
}
}
}
}
@@ -170,6 +175,10 @@ async function run() {
if (await features.getValue(feature_flags_1.Feature.DisableKotlinAnalysisEnabled)) {
core.exportVariable("CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN", "true");
}
// Disable Python dependency extraction if feature flag set
if (await features.getValue(feature_flags_1.Feature.DisablePythonDependencyInstallation, codeql)) {
core.exportVariable("CODEQL_EXTRACTOR_PYTHON_DISABLE_LIBRARY_EXTRACTION", "true");
}
const sourceRoot = path.resolve((0, util_1.getRequiredEnvParam)("GITHUB_WORKSPACE"), (0, actions_util_1.getOptionalInput)("source-root") || "");
const tracerConfig = await (0, init_1.runInit)(codeql, config, sourceRoot, "Runner.Worker.exe", registriesInput, features, apiDetails, logger);
if (tracerConfig !== undefined) {

File diff suppressed because one or more lines are too long

4
lib/init.js generated
View File

@@ -48,9 +48,9 @@ async function initCodeQL(toolsInput, apiDetails, tempDir, variant, defaultCliVe
return { codeql, toolsDownloadDurationMs, toolsSource, toolsVersion };
}
exports.initCodeQL = initCodeQL;
async function initConfig(languagesInput, queriesInput, packsInput, registriesInput, configFile, dbLocation, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeQL, workspacePath, gitHubVersion, apiDetails, features, logger) {
async function initConfig(languagesInput, queriesInput, packsInput, registriesInput, configFile, dbLocation, configInput, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeQL, workspacePath, gitHubVersion, apiDetails, features, logger) {
logger.startGroup("Load language configuration");
const config = await configUtils.initConfig(languagesInput, queriesInput, packsInput, registriesInput, configFile, dbLocation, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeQL, workspacePath, gitHubVersion, apiDetails, features, logger);
const config = await configUtils.initConfig(languagesInput, queriesInput, packsInput, registriesInput, configFile, dbLocation, configInput, trapCachingEnabled, debugMode, debugArtifactName, debugDatabaseName, repository, tempDir, codeQL, workspacePath, gitHubVersion, apiDetails, features, logger);
analysisPaths.printPathFiltersWarning(config, logger);
logger.endGroup();
return config;

View File

@@ -1 +1 @@
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"init.js","sourceRoot":"","sources":["../src/init.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,uCAAyB;AACzB,2CAA6B;AAE7B,yEAA2D;AAC3D,kEAAoD;AAEpD,gEAAkD;AAElD,qCAA+C;AAC/C,4DAA8C;AAI9C,mDAAwE;AACxE,6CAA+B;AAE/B,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,kCAAmB,CAAA;IACnB,8BAAe,CAAA;IACf,sCAAuB,CAAA;IACvB,oCAAqB,CAAA;AACvB,CAAC,EALW,WAAW,GAAX,mBAAW,KAAX,mBAAW,QAKtB;AAEM,KAAK,UAAU,UAAU,CAC9B,UAA8B,EAC9B,UAA4B,EAC5B,OAAe,EACf,OAA2B,EAC3B,iBAA2C,EAC3C,MAAc;IAOd,MAAM,CAAC,UAAU,CAAC,oBAAoB,CAAC,CAAC;IACxC,MAAM,EAAE,MAAM,EAAE,uBAAuB,EAAE,WAAW,EAAE,YAAY,EAAE,GAClE,MAAM,IAAA,oBAAW,EACf,UAAU,EACV,UAAU,EACV,OAAO,EACP,OAAO,EACP,iBAAiB,EACjB,MAAM,EACN,IAAI,CACL,CAAC;IACJ,MAAM,MAAM,CAAC,YAAY,EAAE,CAAC;IAC5B,MAAM,CAAC,QAAQ,EAAE,CAAC;IAClB,OAAO,EAAE,MAAM,EAAE,uBAAuB,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;AACxE,CAAC;AA3BD,gCA2BC;AAEM,KAAK,UAAU,UAAU,CAC9B,cAAkC,EAClC,YAAgC,EAChC,UAA8B,EAC9B,eAAmC,EACnC,UAA8B,EAC9B,UAA8B,EAC9B,WAA+B,EAC/B,kBAA2B,EAC3B,SAAkB,EAClB,iBAAyB,EACzB,iBAAyB,EACzB,UAAyB,EACzB,OAAe,EACf,MAAc,EACd,aAAqB,EACrB,aAAiC,EACjC,UAAoC,EACpC,QAA2B,EAC3B,MAAc;IAEd,MAAM,CAAC,UAAU,CAAC,6BAA6B,CAAC,CAAC;IACjD,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,UAAU,CACzC,cAAc,EACd,YAAY,EACZ,UAAU,EACV,eAAe,EACf,UAAU,EACV,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,UAAU,EACV,OAAO,EACP,MAAM,EACN,aAAa,EACb,aAAa,EACb,UAAU,EACV,QAAQ,EACR,MAAM,CACP,CAAC;IACF,aAAa,CAAC,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtD,MAAM,CAAC,QAAQ,EAAE,CAAC;IAClB,OAAO,MAAM,CAAC;AAChB,CAAC;AA9CD,gCA8CC;AAEM,KAAK,UAAU,OAAO,CAC3B,MAAc,EACd,MAA0B,EAC1B,UAAkB,EAClB,WAA+B,EAC/B,eAAmC,EACnC,QAA2B,EAC3B,UAAoC,EACpC,MAAc;IAEd,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACrD,IAAI;QACF,wFAAwF;QACxF,qBAAqB;QACrB,8FAA8F;QAC9F,2FAA2F;QAC3F,IAAI,oBAAwC,CAAC;QAC7C,IAAI,YAAgC,CAAC;QACrC,IAAI,MAAM,IAAI,CAAC,0BAA0B,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE;YAC3D,CAAC,EAAE,oBAAoB,EAAE,YAAY,EAAE;gBACrC,MAAM,WAAW,CAAC,kBAAkB,CAClC,eAAe,EACf,MAAM,EACN,MAAM,CAAC,OAAO,EACd,MAAM,CACP,CAAC,CAAC;SACN;QACD,MAAM,WAAW,CAAC,eAAe,CAC/B;YACE,YAAY,EAAE,UAAU,CAAC,IAAI;YAC7B,sBAAsB,EAAE,oBAAoB;SAC7C;QAED,0BAA0B;QAC1B,KAAK,IAAI,EAAE,CACT,MAAM,MAAM,CAAC,mBAAmB,CAC9B,MAAM,EACN,UAAU,EACV,WAAW,EACX,QAAQ,EACR,YAAY,EACZ,MAAM,CACP,CACJ,CAAC;KACH;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,YAAY,CAAC,CAAC,CAAC,CAAC;KACvB;IACD,OAAO,MAAM,IAAA,uCAAuB,EAAC,MAAM,CAAC,CAAC;AAC/C,CAAC;AAhDD,0BAgDC;AAED;;;;;;;;GAQG;AACH,SAAS,YAAY,CAAC,CAAM;IAC1B,IAAI,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,EAAE;QACzB,OAAO,CAAC,CAAC;KACV;IAED;IACE,2BAA2B;IAC3B,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,8BAA8B,CAAC;QACnD,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,uCAAuC,CAAC,EAC5D;QACA,OAAO,IAAI,IAAI,CAAC,SAAS,CACvB,sDAAsD,CAAC,CAAC,OAAO,EAAE,CAClE,CAAC;KACH;IAED;IACE,+EAA+E;IAC/E,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,wCAAwC,CAAC;QAC7D,gEAAgE;QAChE,CAAC,CAAC,OAAO,EAAE,QAAQ,CAAC,qBAAqB,CAAC,EAC1C;QACA,OAAO,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;KACtC;IAED,OAAO,CAAC,CAAC;AACX,CAAC;AAEM,KAAK,UAAU,iBAAiB,CAAC,MAAc,EAAE,MAAc;IACpE,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;IAE/C,MAAM,aAAa,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,CAAC;IAEjE,IAAI;QACF,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;YAChC,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,YAAY,CAAC,EAAE;gBACvE,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,mBAAmB,CAAC;aAC9C,CAAC,CAAC,IAAI,EAAE,CAAC;SACX;aAAM;YACL,MAAM,IAAI,UAAU,CAAC,UAAU,CAC7B,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,kBAAkB,CAAC,CAC7C,CAAC,IAAI,EAAE,CAAC;SACV;QACD,MAAM,MAAM,GAAG,0BAA0B,CAAC;QAC1C,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO,EAAE;YAChC,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE;gBAC/D,IAAI;gBACJ,IAAI;gBACJ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;aAC/B,CAAC,CAAC,IAAI,EAAE,CAAC;SACX;aAAM;YACL,MAAM,IAAI,UAAU,CAAC,UAAU,CAAC,MAAM,SAAS,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE;gBACpE,IAAI;gBACJ,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;gBAChC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;aAC/B,CAAC,CAAC,IAAI,EAAE,CAAC;SACX;KACF;IAAC,OAAO,CAAC,EAAE;QACV,MAAM,CAAC,QAAQ,EAAE,CAAC;QAClB,MAAM,CAAC,OAAO,CACZ,gFAAgF,CAAC,IAAI;YACnF,qGAAqG;YACrG,oGAAoG;YACpG,iDAAiD,CACpD,CAAC;QACF,OAAO;KACR;IACD,MAAM,CAAC,QAAQ,EAAE,CAAC;AACpB,CAAC;AAzCD,8CAyCC"}

7
lib/setup-codeql.js generated
View File

@@ -315,6 +315,13 @@ async function getCodeQLSource(toolsInput, defaultCliVersion, apiDetails, varian
// If a tools URL was provided, then use that.
tagName = tryGetTagNameFromUrl(toolsInput, logger);
url = toolsInput;
if (tagName) {
const bundleVersion = tryGetBundleVersionFromTagName(tagName, logger);
// If the bundle version is a semantic version, it is a CLI version number.
if (bundleVersion && semver.valid(bundleVersion)) {
cliVersion = convertToSemVer(bundleVersion, logger);
}
}
}
else {
// Otherwise, use the default CLI version passed in.

File diff suppressed because one or more lines are too long

View File

@@ -117,4 +117,14 @@ ava_1.default.beforeEach(() => {
message: "Failed to find a release of the CodeQL tools that contains CodeQL CLI 2.12.1.",
});
});
(0, ava_1.default)("getCodeQLSource sets CLI version for a semver tagged bundle", async (t) => {
await (0, util_1.withTmpDir)(async (tmpDir) => {
(0, testing_utils_1.setupActionsVars)(tmpDir, tmpDir);
const tagName = "codeql-bundle-v1.2.3";
(0, testing_utils_1.mockBundleDownloadApi)({ tagName });
const source = await setupCodeql.getCodeQLSource(`https://github.com/github/codeql-action/releases/download/${tagName}/codeql-bundle-linux64.tar.gz`, testing_utils_1.SAMPLE_DEFAULT_CLI_VERSION, testing_utils_1.SAMPLE_DOTCOM_API_DETAILS, util_1.GitHubVariant.DOTCOM, (0, logging_1.getRunnerLogger)(true));
t.is(source.sourceType, "download");
t.is(source["cliVersion"], "1.2.3");
});
});
//# sourceMappingURL=setup-codeql.test.js.map

View File

@@ -1 +1 @@
{"version":3,"file":"setup-codeql.test.js","sourceRoot":"","sources":["../src/setup-codeql.test.ts"],"names":[],"mappings":"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"}
{"version":3,"file":"setup-codeql.test.js","sourceRoot":"","sources":["../src/setup-codeql.test.ts"],"names":[],"mappings":"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"}

41
lib/testing-utils.js generated
View File

@@ -22,15 +22,28 @@ var __importStar = (this && this.__importStar) || function (mod) {
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createFeatures = exports.mockCodeQLVersion = exports.mockLanguagesInRepo = exports.mockFeatureFlagApiEndpoint = exports.getRecordingLogger = exports.setupActionsVars = exports.setupTests = void 0;
exports.mockBundleDownloadApi = exports.createFeatures = exports.mockCodeQLVersion = exports.mockLanguagesInRepo = exports.mockFeatureFlagApiEndpoint = exports.getRecordingLogger = exports.setupActionsVars = exports.setupTests = exports.SAMPLE_DEFAULT_CLI_VERSION = exports.SAMPLE_DOTCOM_API_DETAILS = void 0;
const node_util_1 = require("node:util");
const path_1 = __importDefault(require("path"));
const github = __importStar(require("@actions/github"));
const nock = __importStar(require("nock"));
const nock_1 = __importDefault(require("nock"));
const sinon = __importStar(require("sinon"));
const apiClient = __importStar(require("./api-client"));
const CodeQL = __importStar(require("./codeql"));
const util_1 = require("./util");
exports.SAMPLE_DOTCOM_API_DETAILS = {
auth: "token",
url: "https://github.com",
apiURL: "https://api.github.com",
};
exports.SAMPLE_DEFAULT_CLI_VERSION = {
cliVersion: "2.0.0",
variant: util_1.GitHubVariant.DOTCOM,
};
function wrapOutput(context) {
// Function signature taken from Socket.write.
// Note there are two overloads:
@@ -92,7 +105,7 @@ function setupTests(test) {
process.stdout.write(t.context.testOutput);
}
// Undo any modifications made by nock
nock.cleanAll();
nock_1.default.cleanAll();
// Undo any modifications made by sinon
sinon.restore();
// Undo any modifications to the env
@@ -196,4 +209,26 @@ function createFeatures(enabledFeatures) {
};
}
exports.createFeatures = createFeatures;
/**
* Mocks the API for downloading the bundle tagged `tagName`.
*
* @returns the download URL for the bundle. This can be passed to the tools parameter of
* `codeql.setupCodeQL`.
*/
function mockBundleDownloadApi({ apiDetails = exports.SAMPLE_DOTCOM_API_DETAILS, isPinned, repo = "github/codeql-action", platformSpecific = true, tagName, }) {
const platform = process.platform === "win32"
? "win64"
: process.platform === "linux"
? "linux64"
: "osx64";
const baseUrl = apiDetails?.url ?? "https://example.com";
const relativeUrl = apiDetails
? `/${repo}/releases/download/${tagName}/codeql-bundle${platformSpecific ? `-${platform}` : ""}.tar.gz`
: `/download/${tagName}/codeql-bundle.tar.gz`;
(0, nock_1.default)(baseUrl)
.get(relativeUrl)
.replyWithFile(200, path_1.default.join(__dirname, `/../src/testdata/codeql-bundle${isPinned ? "-pinned" : ""}.tar.gz`));
return `${baseUrl}${relativeUrl}`;
}
exports.mockBundleDownloadApi = mockBundleDownloadApi;
//# sourceMappingURL=testing-utils.js.map

File diff suppressed because one or more lines are too long

11
lib/upload-lib.js generated
View File

@@ -134,7 +134,7 @@ exports.findSarifFilesInDir = findSarifFilesInDir;
// Uploads a single sarif file or a directory of sarif files
// depending on what the path happens to refer to.
async function uploadFromActions(sarifPath, checkoutPath, category, logger) {
return await uploadFiles(getSarifFilePaths(sarifPath), (0, repository_1.parseRepositoryNwo)(util.getRequiredEnvParam("GITHUB_REPOSITORY")), await actionsUtil.getCommitOid(checkoutPath), await actionsUtil.getRef(), await actionsUtil.getAnalysisKey(), category, util.getRequiredEnvParam("GITHUB_WORKFLOW"), workflow.getWorkflowRunID(), checkoutPath, actionsUtil.getRequiredInput("matrix"), logger);
return await uploadFiles(getSarifFilePaths(sarifPath), (0, repository_1.parseRepositoryNwo)(util.getRequiredEnvParam("GITHUB_REPOSITORY")), await actionsUtil.getCommitOid(checkoutPath), await actionsUtil.getRef(), await actionsUtil.getAnalysisKey(), category, util.getRequiredEnvParam("GITHUB_WORKFLOW"), workflow.getWorkflowRunID(), workflow.getWorkflowRunAttempt(), checkoutPath, actionsUtil.getRequiredInput("matrix"), logger);
}
exports.uploadFromActions = uploadFromActions;
function getSarifFilePaths(sarifPath) {
@@ -179,7 +179,7 @@ exports.countResultsInSarif = countResultsInSarif;
// Throws an error if the file is invalid.
function validateSarifFileSchema(sarifFilePath, logger) {
const sarif = JSON.parse(fs.readFileSync(sarifFilePath, "utf8"));
const schema = require("../src/sarif_v2.1.0_schema.json");
const schema = require("../src/sarif-schema-2.1.0.json");
const result = new jsonschema.Validator().validate(sarif, schema);
if (!result.valid) {
// Output the more verbose error messages in groups as these may be very large.
@@ -197,7 +197,7 @@ function validateSarifFileSchema(sarifFilePath, logger) {
exports.validateSarifFileSchema = validateSarifFileSchema;
// buildPayload constructs a map ready to be uploaded to the API from the given
// parameters, respecting the current mode and target GitHub instance version.
function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, workflowRunID, checkoutURI, environment, toolNames, mergeBaseCommitOid) {
function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, workflowRunID, workflowRunAttempt, checkoutURI, environment, toolNames, mergeBaseCommitOid) {
const payloadObj = {
commit_oid: commitOid,
ref,
@@ -205,6 +205,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo
analysis_name: analysisName,
sarif: zippedSarif,
workflow_run_id: workflowRunID,
workflow_run_attempt: workflowRunAttempt,
checkout_uri: checkoutURI,
environment,
started_at: process.env[shared_environment_1.CODEQL_WORKFLOW_STARTED_AT],
@@ -235,7 +236,7 @@ function buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, wo
exports.buildPayload = buildPayload;
// Uploads the given set of sarif files.
// Returns true iff the upload occurred and succeeded
async function uploadFiles(sarifFiles, repositoryNwo, commitOid, ref, analysisKey, category, analysisName, workflowRunID, sourceRoot, environment, logger) {
async function uploadFiles(sarifFiles, repositoryNwo, commitOid, ref, analysisKey, category, analysisName, workflowRunID, workflowRunAttempt, sourceRoot, environment, logger) {
logger.startGroup("Uploading results");
logger.info(`Processing sarif files: ${JSON.stringify(sarifFiles)}`);
// Validate that the files we were asked to upload are all valid SARIF files
@@ -252,7 +253,7 @@ async function uploadFiles(sarifFiles, repositoryNwo, commitOid, ref, analysisKe
const sarifPayload = JSON.stringify(sarif);
const zippedSarif = zlib_1.default.gzipSync(sarifPayload).toString("base64");
const checkoutURI = (0, file_url_1.default)(sourceRoot);
const payload = buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, workflowRunID, checkoutURI, environment, toolNames, await actionsUtil.determineMergeBaseCommitOid());
const payload = buildPayload(commitOid, ref, analysisKey, analysisName, zippedSarif, workflowRunID, workflowRunAttempt, checkoutURI, environment, toolNames, await actionsUtil.determineMergeBaseCommitOid());
// Log some useful debug info about the info
const rawUploadSizeBytes = sarifPayload.length;
logger.debug(`Raw upload size: ${rawUploadSizeBytes} bytes`);

File diff suppressed because one or more lines are too long

View File

@@ -48,7 +48,7 @@ ava_1.default.beforeEach(() => {
});
(0, ava_1.default)("validate correct payload used for push, PR merge commit, and PR head", async (t) => {
process.env["GITHUB_EVENT_NAME"] = "push";
const pushPayload = uploadLib.buildPayload("commit", "refs/heads/master", "key", undefined, "", undefined, "/opt/src", undefined, ["CodeQL", "eslint"], "mergeBaseCommit");
const pushPayload = uploadLib.buildPayload("commit", "refs/heads/master", "key", undefined, "", 1234, 1, "/opt/src", undefined, ["CodeQL", "eslint"], "mergeBaseCommit");
// Not triggered by a pull request
t.falsy(pushPayload.base_ref);
t.falsy(pushPayload.base_sha);
@@ -56,11 +56,11 @@ ava_1.default.beforeEach(() => {
process.env["GITHUB_SHA"] = "commit";
process.env["GITHUB_BASE_REF"] = "master";
process.env["GITHUB_EVENT_PATH"] = `${__dirname}/../src/testdata/pull_request.json`;
const prMergePayload = uploadLib.buildPayload("commit", "refs/pull/123/merge", "key", undefined, "", undefined, "/opt/src", undefined, ["CodeQL", "eslint"], "mergeBaseCommit");
const prMergePayload = uploadLib.buildPayload("commit", "refs/pull/123/merge", "key", undefined, "", 1234, 1, "/opt/src", undefined, ["CodeQL", "eslint"], "mergeBaseCommit");
// Uploads for a merge commit use the merge base
t.deepEqual(prMergePayload.base_ref, "refs/heads/master");
t.deepEqual(prMergePayload.base_sha, "mergeBaseCommit");
const prHeadPayload = uploadLib.buildPayload("headCommit", "refs/pull/123/head", "key", undefined, "", undefined, "/opt/src", undefined, ["CodeQL", "eslint"], "mergeBaseCommit");
const prHeadPayload = uploadLib.buildPayload("headCommit", "refs/pull/123/head", "key", undefined, "", 1234, 1, "/opt/src", undefined, ["CodeQL", "eslint"], "mergeBaseCommit");
// Uploads for the head use the PR base
t.deepEqual(prHeadPayload.base_ref, "refs/heads/master");
t.deepEqual(prHeadPayload.base_sha, "f95f852bd8fca8fcc58a9a2d6c842781e32a215e");

File diff suppressed because one or more lines are too long

62
lib/workflow.js generated
View File

@@ -26,7 +26,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCheckoutPathInputOrThrow = exports.getUploadInputOrThrow = exports.getCategoryInputOrThrow = exports.getWorkflowRunID = exports.getWorkflowRelativePath = exports.getWorkflow = exports.formatWorkflowCause = exports.formatWorkflowErrors = exports.validateWorkflow = exports.getWorkflowErrors = exports.WorkflowErrors = exports.patternIsSuperset = void 0;
exports.getCheckoutPathInputOrThrow = exports.getUploadInputOrThrow = exports.getCategoryInputOrThrow = exports.getWorkflowRunAttempt = exports.getWorkflowRunID = exports.getWorkflowRelativePath = exports.getWorkflow = exports.formatWorkflowCause = exports.formatWorkflowErrors = exports.validateWorkflow = exports.getWorkflowErrors = exports.WorkflowErrors = exports.patternIsSuperset = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const zlib_1 = __importDefault(require("zlib"));
@@ -65,18 +65,6 @@ function patternIsSuperset(patternA, patternB) {
return patternToRegExp(patternA).test(patternB);
}
exports.patternIsSuperset = patternIsSuperset;
function branchesToArray(branches) {
if (typeof branches === "string") {
return [branches];
}
if (Array.isArray(branches)) {
if (branches.length === 0) {
return "**";
}
return branches;
}
return "**";
}
function toCodedErrors(errors) {
return Object.entries(errors).reduce((acc, [code, message]) => {
acc[code] = { message, code };
@@ -86,8 +74,7 @@ function toCodedErrors(errors) {
// code to send back via status report
// message to add as a warning annotation to the run
exports.WorkflowErrors = toCodedErrors({
MismatchedBranches: `Please make sure that every branch in on.pull_request is also in on.push so that Code Scanning can compare pull requests against the state of the base branch.`,
MissingPushHook: `Please specify an on.push hook so that Code Scanning can compare pull requests against the state of the base branch.`,
MissingPushHook: `Please specify an on.push hook to analyze and see code scanning alerts from the default branch on the Security tab.`,
CheckoutWrongHead: `git checkout HEAD^2 is no longer necessary. Please remove this step as Code Scanning recommends analyzing the merge commit for best results.`,
});
function getWorkflowErrors(doc) {
@@ -132,28 +119,6 @@ function getWorkflowErrors(doc) {
if (!hasPush && hasPullRequest) {
missingPush = true;
}
// if doc.on.pull_request is null that means 'all branches'
// if doc.on.pull_request is undefined that means 'off'
// we only want to check for mismatched branches if pull_request is on.
if (doc.on.pull_request !== undefined) {
const push = branchesToArray(doc.on.push?.branches);
if (push !== "**") {
const pull_request = branchesToArray(doc.on.pull_request?.branches);
if (pull_request !== "**") {
const difference = pull_request.filter((value) => !push.some((o) => patternIsSuperset(o, value)));
if (difference.length > 0) {
// there are branches in pull_request that may not have a baseline
// because we are not building them on push
errors.push(exports.WorkflowErrors.MismatchedBranches);
}
}
else if (push.length > 0) {
// push is set up to run on a subset of branches
// and you could open a PR against a branch with no baseline
errors.push(exports.WorkflowErrors.MismatchedBranches);
}
}
}
}
if (missingPush) {
errors.push(exports.WorkflowErrors.MissingPushHook);
@@ -252,13 +217,32 @@ exports.getWorkflowRelativePath = getWorkflowRelativePath;
* Get the workflow run ID.
*/
function getWorkflowRunID() {
const workflowRunID = parseInt((0, util_1.getRequiredEnvParam)("GITHUB_RUN_ID"), 10);
const workflowRunIdString = (0, util_1.getRequiredEnvParam)("GITHUB_RUN_ID");
const workflowRunID = parseInt(workflowRunIdString, 10);
if (Number.isNaN(workflowRunID)) {
throw new Error("GITHUB_RUN_ID must define a non NaN workflow run ID");
throw new Error(`GITHUB_RUN_ID must define a non NaN workflow run ID. Current value is ${workflowRunIdString}`);
}
if (workflowRunID < 0) {
throw new Error(`GITHUB_RUN_ID must be a non-negative integer. Current value is ${workflowRunIdString}`);
}
return workflowRunID;
}
exports.getWorkflowRunID = getWorkflowRunID;
/**
* Get the workflow run attempt number.
*/
function getWorkflowRunAttempt() {
const workflowRunAttemptString = (0, util_1.getRequiredEnvParam)("GITHUB_RUN_ATTEMPT");
const workflowRunAttempt = parseInt(workflowRunAttemptString, 10);
if (Number.isNaN(workflowRunAttempt)) {
throw new Error(`GITHUB_RUN_ATTEMPT must define a non NaN workflow run attempt. Current value is ${workflowRunAttemptString}`);
}
if (workflowRunAttempt <= 0) {
throw new Error(`GITHUB_RUN_ATTEMPT must be a positive integer. Current value is ${workflowRunAttemptString}`);
}
return workflowRunAttempt;
}
exports.getWorkflowRunAttempt = getWorkflowRunAttempt;
function getStepsCallingAction(job, actionName) {
if (job.uses) {
throw new Error(`Could not get steps calling ${actionName} since the job calls a reusable workflow.`);

File diff suppressed because one or more lines are too long

49
lib/workflow.test.js generated
View File

@@ -64,12 +64,6 @@ function errorCodes(actual, expected) {
});
t.deepEqual(...errorCodes(errors, []));
});
(0, ava_1.default)("getWorkflowErrors() when on.pull_requests is a string", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)({
on: { push: { branches: ["main"] }, pull_request: { branches: "*" } },
});
t.deepEqual(...errorCodes(errors, [workflow_1.WorkflowErrors.MismatchedBranches]));
});
(0, ava_1.default)("getWorkflowErrors() when on.pull_requests is a string and correct", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)({
on: { push: { branches: "*" }, pull_request: { branches: "*" } },
@@ -84,15 +78,6 @@ function errorCodes(actual, expected) {
`));
t.deepEqual(...errorCodes(errors, []));
});
(0, ava_1.default)("getWorkflowErrors() when on.push is mismatched", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)({
on: {
push: { branches: ["main"] },
pull_request: { branches: ["feature"] },
},
});
t.deepEqual(...errorCodes(errors, [workflow_1.WorkflowErrors.MismatchedBranches]));
});
(0, ava_1.default)("getWorkflowErrors() when on.push is not mismatched", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)({
on: {
@@ -102,15 +87,6 @@ function errorCodes(actual, expected) {
});
t.deepEqual(...errorCodes(errors, []));
});
(0, ava_1.default)("getWorkflowErrors() when on.push is mismatched for pull_request", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)({
on: {
push: { branches: ["main"] },
pull_request: { branches: ["main", "feature"] },
},
});
t.deepEqual(...errorCodes(errors, [workflow_1.WorkflowErrors.MismatchedBranches]));
});
(0, ava_1.default)("getWorkflowErrors() for a range of malformed workflows", (t) => {
t.deepEqual(...errorCodes((0, workflow_1.getWorkflowErrors)({
on: {
@@ -175,16 +151,6 @@ function errorCodes(actual, expected) {
},
}), []));
});
(0, ava_1.default)("getWorkflowErrors() when on.pull_request for every branch but push specifies branches", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)(yaml.load(`
name: "CodeQL"
on:
push:
branches: ["main"]
pull_request:
`));
t.deepEqual(...errorCodes(errors, [workflow_1.WorkflowErrors.MismatchedBranches]));
});
(0, ava_1.default)("getWorkflowErrors() when on.pull_request for wildcard branches", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)({
on: {
@@ -194,15 +160,6 @@ function errorCodes(actual, expected) {
});
t.deepEqual(...errorCodes(errors, []));
});
(0, ava_1.default)("getWorkflowErrors() when on.pull_request for mismatched wildcard branches", (t) => {
const errors = (0, workflow_1.getWorkflowErrors)({
on: {
push: { branches: ["feature/moose"] },
pull_request: { branches: "feature/*" },
},
});
t.deepEqual(...errorCodes(errors, [workflow_1.WorkflowErrors.MismatchedBranches]));
});
(0, ava_1.default)("getWorkflowErrors() when HEAD^2 is checked out", (t) => {
process.env.GITHUB_JOB = "test";
const errors = (0, workflow_1.getWorkflowErrors)({
@@ -218,7 +175,7 @@ function errorCodes(actual, expected) {
(0, ava_1.default)("formatWorkflowErrors() when there are multiple errors", (t) => {
const message = (0, workflow_1.formatWorkflowErrors)([
workflow_1.WorkflowErrors.CheckoutWrongHead,
workflow_1.WorkflowErrors.MismatchedBranches,
workflow_1.WorkflowErrors.MissingPushHook,
]);
t.true(message.startsWith("2 issues were detected with this workflow:"));
});
@@ -229,9 +186,9 @@ function errorCodes(actual, expected) {
(0, ava_1.default)("formatWorkflowCause()", (t) => {
const message = (0, workflow_1.formatWorkflowCause)([
workflow_1.WorkflowErrors.CheckoutWrongHead,
workflow_1.WorkflowErrors.MismatchedBranches,
workflow_1.WorkflowErrors.MissingPushHook,
]);
t.deepEqual(message, "CheckoutWrongHead,MismatchedBranches");
t.deepEqual(message, "CheckoutWrongHead,MissingPushHook");
t.deepEqual((0, workflow_1.formatWorkflowCause)([]), undefined);
});
(0, ava_1.default)("patternIsSuperset()", (t) => {

File diff suppressed because one or more lines are too long

7
node_modules/.package-lock.json generated vendored
View File

@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "2.3.0",
"version": "2.3.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
@@ -4146,8 +4146,9 @@
}
},
"node_modules/jsonschema": {
"version": "1.2.6",
"integrity": "sha512-SqhURKZG07JyKKeo/ir24QnS4/BV7a6gQy93bUSe4lUdNp0QNpIz2c9elWJQ9dpc5cQYY6cvCzgRwy0MQCLyqA==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz",
"integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==",
"engines": {
"node": "*"
}

230
node_modules/jsonschema/README.md generated vendored
View File

@@ -1,18 +1,21 @@
[![Build Status](https://secure.travis-ci.org/tdegrunt/jsonschema.svg)](http://travis-ci.org/tdegrunt/jsonschema)
# jsonschema
[JSON schema](http://json-schema.org/) validator, which is designed to be fast and simple to use.
The latest IETF published draft is v6, this library is mostly v4 compatible.
[JSON schema](http://json-schema.org/) validator, which is designed to be fast and simple to use. JSON Schema versions through draft-07 are fully supported.
## Contributing & bugs
Please fork the repository, make the changes in your fork and include tests. Once you're done making changes, send in a pull request.
### Bug reports
Please include a test which shows why the code fails.
## Usage
### Simple
Simple object validation using JSON schemas.
```javascript
@@ -78,6 +81,7 @@ v.addSchema(addressSchema, '/SimpleAddress');
console.log(v.validate(p, schema));
```
### Example for Array schema
```json
var arraySchema = {
"type": "array",
@@ -95,21 +99,42 @@ For a comprehensive, annotated example illustrating all possible validation opti
## Features
### Definitions
All schema definitions are supported, $schema is ignored.
### Types
All types are supported
### Handling `undefined`
`undefined` is not a value known to JSON, and by default, the validator treats it as if it is not invalid. i.e., it will return valid.
```javascript
var res = validate(undefined, {type: 'string'});
res.valid // true
```
This behavior may be changed with the "required" option:
```javascript
var res = validate(undefined, {type: 'string'}, {required: true});
res.valid // false
```
### Formats
#### Disabling the format keyword.
You may disable format validation by providing `disableFormat: true` to the validator
options.
#### String Formats
All formats are supported, phone numbers are expected to follow the [E.123](http://en.wikipedia.org/wiki/E.123) standard.
#### Custom Formats
You may add your own custom format functions. Format functions accept the input
being validated and return a boolean value. If the returned value is `true`, then
validation succeeds. If the returned value is `false`, then validation fails.
@@ -133,27 +158,86 @@ validator.validate('foo', {type: 'string', format: 'myFormat'}).valid; // false
```
### Results
The first error found will be thrown as an `Error` object if `options.throwError` is `true`. Otherwise all results will be appended to the `result.errors` array which also contains the success flag `result.valid`.
When `oneOf` or `anyOf` validations fail, errors that caused any of the sub-schemas referenced therein to fail are not reported, unless `options.nestedErrors` is truthy. This option may be useful when troubleshooting validation errors in complex schemas.
By default, results will be returned in a `ValidatorResult` object with the following properties:
### Custom properties
Specify your own JSON Schema properties with the validator.attributes property:
* `instance`: any.
* `schema`: Schema.
* `errors`: ValidationError[].
* `valid`: boolean.
Each item in `errors` is a `ValidationError` with the following properties:
* path: array. An array of property keys or array offsets, indicating where inside objects or arrays the instance was found.
* property: string. Describes the property path. Starts with `instance`, and is delimited with a dot (`.`).
* message: string. A human-readable message for debugging use. Provided in English and subject to change.
* schema: object. The schema containing the keyword that failed
* instance: any. The instance that failed
* name: string. The keyword within the schema that failed.
* argument: any. Provides information about the keyword that failed.
The validator can be configured to throw in the event of a validation error:
* If the `throwFirst` option is set, the validator will terminate validation at the first encountered error and throw a `ValidatorResultError` object.
* If the `throwAll` option is set, the validator will throw a `ValidatorResultError` object after the entire instance has been validated.
* If the `throwError` option is set, it will throw at the first encountered validation error (like `throwFirst`), but the `ValidationError` object itself will be thrown. Note that, despite the name, this does not inherit from Error like `ValidatorResultError` does.
The `ValidatorResultError` object has the same properties as `ValidatorResult` and additionally inherits from Error.
#### "nestedErrors" option
When `oneOf` or `anyOf` validations fail, errors that caused any of the sub-schemas referenced therein to fail are normally suppressed, because it is not necessary to fix all of them. And in the case of `oneOf`, it would itself be an error to fix all of the listed errors.
This behavior may be configured with `options.nestedErrors`. If truthy, it will emit all the errors from the subschemas. This option may be useful when troubleshooting validation errors in complex schemas:
```javascript
var schema = {
oneOf: [
{ type: 'string', minLength: 32, maxLength: 32 },
{ type: 'string', maxLength: 16 },
{ type: 'number' },
]
};
var validator = new Validator();
var result = validator.validate('This string is 28 chars long', schema, {nestedErrors: true});
// result.toString() reads out:
// 0: instance does not meet minimum length of 32
// 1: instance does not meet maximum length of 16
// 2: instance is not of a type(s) number
// 3: instance is not exactly one from [subschema 0],[subschema 1],[subschema 2]
```
#### Localizing Error Messages
To provide localized, human-readable errors, use the `name` string as a translation key. Feel free to open an issue for support relating to localizing error messages. For example:
```
var localized = result.errors.map(function(err){
return localeService.translate(err.name);
});
```
### Custom keywords
Specify your own JSON Schema keywords with the validator.attributes property:
```javascript
validator.attributes.contains = function validateContains(instance, schema, options, ctx) {
if(typeof instance!='string') return;
if(typeof schema.contains!='string') throw new jsonschema.SchemaError('"contains" expects a string', schema);
if(typeof instance !== 'string') return;
if(typeof schema.contains !== 'string') throw new jsonschema.SchemaError('"contains" expects a string', schema);
if(instance.indexOf(schema.contains)<0){
return 'does not contain the string ' + JSON.stringify(schema.contains);
}
}
var result = validator.validate("i am an instance", { type:"string", contains: "i am" });
var result = validator.validate("I am an instance", { type:"string", contains: "I am" });
// result.valid === true;
```
The instance passes validation if the function returns nothing. A single validation error is produced
if the fuction returns a string. Any number of errors (maybe none at all) may be returned by passing a
if the function returns a string. Any number of errors (maybe none at all) may be returned by passing a
`ValidatorResult` object, which may be used like so:
```javascript
@@ -165,6 +249,7 @@ if the fuction returns a string. Any number of errors (maybe none at all) may be
```
### Dereferencing schemas
Sometimes you may want to download schemas from remote sources, like a database, or over HTTP. When importing a schema,
unknown references are inserted into the `validator.unresolvedRefs` Array. Asynchronously shift elements off this array and import
them:
@@ -184,44 +269,119 @@ function importNextSchema(){
importNextSchema();
```
### Default base URI
Schemas should typically have an `id` with an absolute, full URI. However if the schema you are using contains only relative URI references, the `base` option will be used to resolve these.
This following example would throw a `SchemaError` if the `base` option were unset:
```javascript
var result = validate(["Name"], {
id: "/schema.json",
type: "array",
items: { $ref: "http://example.com/schema.json#/definitions/item" },
definitions: {
item: { type: "string" },
},
}, { base: 'http://example.com/' });
```
### Rewrite Hook
The `rewrite` option lets you change the value of an instance after it has successfully been validated. This will mutate the `instance` passed to the validate function. This can be useful for unmarshalling data and parsing it into native instances, such as changing a string to a `Date` instance.
The `rewrite` option accepts a function with the following arguments:
* instance: any
* schema: object
* options: object
* ctx: object
* return value: any new value for the instance
The value may be removed by returning `undefined`.
If you don't want to change the value, call `return instance`.
Here is an example that can convert a property expecting a date into a Date instance:
```javascript
const schema = {
properties: {
date: {id: 'http://example.com/date', type: 'string'},
},
};
const value = {
date: '2020-09-30T23:39:27.060Z',
};
function unmarshall(instance, schema){
if(schema.id === 'http://example.com/date'){
return new Date(instance);
}
return instance;
}
const v = new Validator();
const res = v.validate(value, schema, {rewrite: unmarshall});
assert(res.instance.date instanceof Date);
```
### Pre-Property Validation Hook
If some processing of properties is required prior to validation a function may be passed via the options parameter of the validate function. For example, say you needed to perform type coercion for some properties:
```javascript
const coercionHook = function (instance, property, schema, options, ctx) {
var value = instance[property];
// See examples/coercion.js
function preValidateProperty(object, key, schema, options, ctx) {
var value = object[key];
if (typeof value === 'undefined') return;
// Skip nulls and undefineds
if (value === null || typeof value == 'undefined') {
return;
}
// If the schema declares a type and the property fails type validation.
if (schema.type && this.attributes.type.call(this, instance, schema, options, ctx.makeChild(schema, property))) {
var types = Array.isArray(schema.type) ? schema.type : [schema.type];
var coerced = undefined;
// Go through the declared types until we find something that we can
// coerce the value into.
for (var i = 0; typeof coerced == 'undefined' && i < types.length; i++) {
// If we support coercion to this type
if (lib.coercions[types[i]]) {
// ...attempt it.
coerced = lib.coercions[types[i]](value);
}
// Test if the schema declares a type, but the type keyword fails validation
if (schema.type && validator.attributes.type.call(validator, value, schema, options, ctx.makeChild(schema, key))) {
// If the type is "number" but the instance is not a number, cast it
if(schema.type==='number' && typeof value!=='number'){
object[key] = parseFloat(value);
return;
}
// If we got a successful coercion we modify the property of the instance.
if (typeof coerced != 'undefined') {
instance[property] = coerced;
// If the type is "string" but the instance is not a string, cast it
if(schema.type==='string' && typeof value!=='string'){
object[key] = String(value).toString();
return;
}
}
}.bind(validator)
};
// And now, to actually perform validation with the coercion hook!
v.validate(instance, schema, { preValidateProperty: coercionHook });
v.validate(instance, schema, { preValidateProperty });
```
### Skip validation of certain keywords
Use the "skipAttributes" option to skip validation of certain keywords. Provide an array of keywords to ignore.
For skipping the "format" keyword, see the disableFormat option.
### Fail on unknown keywords
By default, JSON Schema is supposed to ignore unknown schema keywords.
You can change this behavior to require that all keywords used in a schema have a defined behavior, by using setting the "allowUnknownAttributes" option to false.
This example will throw a `SchemaError`:
```javascript
var schema = {
type: "string",
format: "email",
example: "foo",
};
var result = validate("Name", schema, { allowUnknownAttributes: false });
```
## Tests
Uses [JSON Schema Test Suite](https://github.com/json-schema/JSON-Schema-Test-Suite) as well as our own tests.
You'll need to update and init the git submodules:

View File

@@ -16,13 +16,13 @@ attribute.ignoreProperties = {
'description': true,
'title': true,
// arguments to other properties
'exclusiveMinimum': true,
'exclusiveMaximum': true,
'additionalItems': true,
'then': true,
'else': true,
// special-handled properties
'$schema': true,
'$ref': true,
'extends': true
'extends': true,
};
/**
@@ -47,7 +47,9 @@ validators.type = function validateType (instance, schema, options, ctx) {
var types = Array.isArray(schema.type) ? schema.type : [schema.type];
if (!types.some(this.testType.bind(this, instance, schema, options, ctx))) {
var list = types.map(function (v) {
return v.id && ('<' + v.id + '>') || (v+'');
if(!v) return;
var id = v.$id || v.id;
return id ? ('<' + id + '>') : (v+'');
});
result.addError({
name: 'type',
@@ -60,9 +62,12 @@ validators.type = function validateType (instance, schema, options, ctx) {
function testSchemaNoThrow(instance, options, ctx, callback, schema){
var throwError = options.throwError;
var throwAll = options.throwAll;
options.throwError = false;
options.throwAll = false;
var res = this.validateSchema(instance, schema, options, ctx);
options.throwError = throwError;
options.throwAll = throwAll;
if (!res.valid && callback instanceof Function) {
callback(res);
@@ -91,9 +96,11 @@ validators.anyOf = function validateAnyOf (instance, schema, options, ctx) {
if (!schema.anyOf.some(
testSchemaNoThrow.bind(
this, instance, options, ctx, function(res){inner.importErrors(res);}
))) {
))) {
var list = schema.anyOf.map(function (v, i) {
return (v.id && ('<' + v.id + '>')) || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
var id = v.$id || v.id;
if(id) return '<' + id + '>';
return(v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
});
if (options.nestedErrors) {
result.importErrors(inner);
@@ -128,7 +135,8 @@ validators.allOf = function validateAllOf (instance, schema, options, ctx) {
schema.allOf.forEach(function(v, i){
var valid = self.validateSchema(instance, v, options, ctx);
if(!valid.valid){
var msg = (v.id && ('<' + v.id + '>')) || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
var id = v.$id || v.id;
var msg = id || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
result.addError({
name: 'allOf',
argument: { id: msg, length: valid.errors.length, valid: valid },
@@ -161,9 +169,10 @@ validators.oneOf = function validateOneOf (instance, schema, options, ctx) {
var count = schema.oneOf.filter(
testSchemaNoThrow.bind(
this, instance, options, ctx, function(res) {inner.importErrors(res);}
) ).length;
) ).length;
var list = schema.oneOf.map(function (v, i) {
return (v.id && ('<' + v.id + '>')) || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
var id = v.$id || v.id;
return id || (v.title && JSON.stringify(v.title)) || (v['$ref'] && ('<' + v['$ref'] + '>')) || '[subschema '+i+']';
});
if (count!==1) {
if (options.nestedErrors) {
@@ -178,6 +187,70 @@ validators.oneOf = function validateOneOf (instance, schema, options, ctx) {
return result;
};
/**
* Validates "then" or "else" depending on the result of validating "if"
* @param instance
* @param schema
* @param options
* @param ctx
* @return {String|null}
*/
validators.if = function validateIf (instance, schema, options, ctx) {
// Ignore undefined instances
if (instance === undefined) return null;
if (!helpers.isSchema(schema.if)) throw new Error('Expected "if" keyword to be a schema');
var ifValid = testSchemaNoThrow.call(this, instance, options, ctx, null, schema.if);
var result = new ValidatorResult(instance, schema, options, ctx);
var res;
if(ifValid){
if (schema.then === undefined) return;
if (!helpers.isSchema(schema.then)) throw new Error('Expected "then" keyword to be a schema');
res = this.validateSchema(instance, schema.then, options, ctx.makeChild(schema.then));
result.importErrors(res);
}else{
if (schema.else === undefined) return;
if (!helpers.isSchema(schema.else)) throw new Error('Expected "else" keyword to be a schema');
res = this.validateSchema(instance, schema.else, options, ctx.makeChild(schema.else));
result.importErrors(res);
}
return result;
};
function getEnumerableProperty(object, key){
// Determine if `key` shows up in `for(var key in object)`
// First test Object.hasOwnProperty.call as an optimization: that guarantees it does
if(Object.hasOwnProperty.call(object, key)) return object[key];
// Test `key in object` as an optimization; false means it won't
if(!(key in object)) return;
while( (object = Object.getPrototypeOf(object)) ){
if(Object.propertyIsEnumerable.call(object, key)) return object[key];
}
}
/**
* Validates propertyNames
* @param instance
* @param schema
* @param options
* @param ctx
* @return {String|null|ValidatorResult}
*/
validators.propertyNames = function validatePropertyNames (instance, schema, options, ctx) {
if(!this.types.object(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
var subschema = schema.propertyNames!==undefined ? schema.propertyNames : {};
if(!helpers.isSchema(subschema)) throw new SchemaError('Expected "propertyNames" to be a schema (object or boolean)');
for (var property in instance) {
if(getEnumerableProperty(instance, property) !== undefined){
var res = this.validateSchema(property, subschema, options, ctx.makeChild(subschema));
result.importErrors(res);
}
}
return result;
};
/**
* Validates properties
* @param instance
@@ -191,12 +264,17 @@ validators.properties = function validateProperties (instance, schema, options,
var result = new ValidatorResult(instance, schema, options, ctx);
var properties = schema.properties || {};
for (var property in properties) {
if (typeof options.preValidateProperty == 'function') {
options.preValidateProperty(instance, property, properties[property], options, ctx);
var subschema = properties[property];
if(subschema===undefined){
continue;
}else if(subschema===null){
throw new SchemaError('Unexpected null, expected schema in "properties"');
}
var prop = Object.hasOwnProperty.call(instance, property) ? instance[property] : undefined;
var res = this.validateSchema(prop, properties[property], options, ctx.makeChild(properties[property], property));
if (typeof options.preValidateProperty == 'function') {
options.preValidateProperty(instance, property, subschema, options, ctx);
}
var prop = getEnumerableProperty(instance, property);
var res = this.validateSchema(prop, subschema, options, ctx.makeChild(subschema, property));
if(res.instance !== result.instance[property]) result.instance[property] = res.instance;
result.importErrors(res);
}
@@ -206,7 +284,7 @@ validators.properties = function validateProperties (instance, schema, options,
/**
* Test a specific property within in instance against the additionalProperties schema attribute
* This ignores properties with definitions in the properties schema attribute, but no other attributes.
* If too many more types of property-existance tests pop up they may need their own class of tests (like `type` has)
* If too many more types of property-existence tests pop up they may need their own class of tests (like `type` has)
* @private
* @return {boolean}
*/
@@ -219,7 +297,7 @@ function testAdditionalProperty (instance, schema, options, ctx, property, resul
result.addError({
name: 'additionalProperties',
argument: property,
message: "additionalProperty " + JSON.stringify(property) + " exists in instance when not allowed",
message: "is not allowed to have the additional property " + JSON.stringify(property),
});
} else {
var additionalProperties = schema.additionalProperties || {};
@@ -250,17 +328,29 @@ validators.patternProperties = function validatePatternProperties (instance, sch
for (var property in instance) {
var test = true;
for (var pattern in patternProperties) {
var expr = new RegExp(pattern);
if (!expr.test(property)) {
var subschema = patternProperties[pattern];
if(subschema===undefined){
continue;
}else if(subschema===null){
throw new SchemaError('Unexpected null, expected schema in "patternProperties"');
}
try {
var regexp = new RegExp(pattern, 'u');
} catch(_e) {
// In the event the stricter handling causes an error, fall back on the forgiving handling
// DEPRECATED
regexp = new RegExp(pattern);
}
if (!regexp.test(property)) {
continue;
}
test = false;
if (typeof options.preValidateProperty == 'function') {
options.preValidateProperty(instance, property, patternProperties[pattern], options, ctx);
options.preValidateProperty(instance, property, subschema, options, ctx);
}
var res = this.validateSchema(instance[property], patternProperties[pattern], options, ctx.makeChild(patternProperties[pattern], property));
var res = this.validateSchema(instance[property], subschema, options, ctx.makeChild(subschema, property));
if(res.instance !== result.instance[property]) result.instance[property] = res.instance;
result.importErrors(res);
}
@@ -308,7 +398,7 @@ validators.minProperties = function validateMinProperties (instance, schema, opt
name: 'minProperties',
argument: schema.minProperties,
message: "does not meet minimum property length of " + schema.minProperties,
})
});
}
return result;
};
@@ -344,10 +434,14 @@ validators.maxProperties = function validateMaxProperties (instance, schema, opt
validators.items = function validateItems (instance, schema, options, ctx) {
var self = this;
if (!this.types.array(instance)) return;
if (!schema.items) return;
if (schema.items===undefined) return;
var result = new ValidatorResult(instance, schema, options, ctx);
instance.every(function (value, i) {
var items = Array.isArray(schema.items) ? (schema.items[i] || schema.additionalItems) : schema.items;
if(Array.isArray(schema.items)){
var items = schema.items[i]===undefined ? schema.additionalItems : schema.items[i];
}else{
var items = schema.items;
}
if (items === undefined) {
return true;
}
@@ -366,6 +460,34 @@ validators.items = function validateItems (instance, schema, options, ctx) {
return result;
};
/**
* Validates the "contains" keyword
* @param instance
* @param schema
* @param options
* @param ctx
* @return {String|null|ValidatorResult}
*/
validators.contains = function validateContains (instance, schema, options, ctx) {
var self = this;
if (!this.types.array(instance)) return;
if (schema.contains===undefined) return;
if (!helpers.isSchema(schema.contains)) throw new Error('Expected "contains" keyword to be a schema');
var result = new ValidatorResult(instance, schema, options, ctx);
var count = instance.some(function (value, i) {
var res = self.validateSchema(value, schema.contains, options, ctx.makeChild(schema.contains, i));
return res.errors.length===0;
});
if(count===false){
result.addError({
name: 'contains',
argument: schema.contains,
message: "must contain an item matching given schema",
});
}
return result;
};
/**
* Validates minimum and exclusiveMinimum when the type of the instance value is a number.
* @param instance
@@ -375,18 +497,22 @@ validators.items = function validateItems (instance, schema, options, ctx) {
validators.minimum = function validateMinimum (instance, schema, options, ctx) {
if (!this.types.number(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
var valid = true;
if (schema.exclusiveMinimum && schema.exclusiveMinimum === true) {
valid = instance > schema.minimum;
if(!(instance > schema.minimum)){
result.addError({
name: 'minimum',
argument: schema.minimum,
message: "must be greater than " + schema.minimum,
});
}
} else {
valid = instance >= schema.minimum;
}
if (!valid) {
result.addError({
name: 'minimum',
argument: schema.minimum,
message: "must have a minimum value of " + schema.minimum,
});
if(!(instance >= schema.minimum)){
result.addError({
name: 'minimum',
argument: schema.minimum,
message: "must be greater than or equal to " + schema.minimum,
});
}
}
return result;
};
@@ -400,17 +526,65 @@ validators.minimum = function validateMinimum (instance, schema, options, ctx) {
validators.maximum = function validateMaximum (instance, schema, options, ctx) {
if (!this.types.number(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
var valid;
if (schema.exclusiveMaximum && schema.exclusiveMaximum === true) {
valid = instance < schema.maximum;
if(!(instance < schema.maximum)){
result.addError({
name: 'maximum',
argument: schema.maximum,
message: "must be less than " + schema.maximum,
});
}
} else {
valid = instance <= schema.maximum;
if(!(instance <= schema.maximum)){
result.addError({
name: 'maximum',
argument: schema.maximum,
message: "must be less than or equal to " + schema.maximum,
});
}
}
return result;
};
/**
* Validates the number form of exclusiveMinimum when the type of the instance value is a number.
* @param instance
* @param schema
* @return {String|null}
*/
validators.exclusiveMinimum = function validateExclusiveMinimum (instance, schema, options, ctx) {
// Support the boolean form of exclusiveMinimum, which is handled by the "minimum" keyword.
if(typeof schema.exclusiveMinimum === 'boolean') return;
if (!this.types.number(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
var valid = instance > schema.exclusiveMinimum;
if (!valid) {
result.addError({
name: 'maximum',
argument: schema.maximum,
message: "must have a maximum value of " + schema.maximum,
name: 'exclusiveMinimum',
argument: schema.exclusiveMinimum,
message: "must be strictly greater than " + schema.exclusiveMinimum,
});
}
return result;
};
/**
* Validates the number form of exclusiveMaximum when the type of the instance value is a number.
* @param instance
* @param schema
* @return {String|null}
*/
validators.exclusiveMaximum = function validateExclusiveMaximum (instance, schema, options, ctx) {
// Support the boolean form of exclusiveMaximum, which is handled by the "maximum" keyword.
if(typeof schema.exclusiveMaximum === 'boolean') return;
if (!this.types.number(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
var valid = instance < schema.exclusiveMaximum;
if (!valid) {
result.addError({
name: 'exclusiveMaximum',
argument: schema.exclusiveMaximum,
message: "must be strictly less than " + schema.exclusiveMaximum,
});
}
return result;
@@ -444,7 +618,7 @@ var validateMultipleOfOrDivisbleBy = function validateMultipleOfOrDivisbleBy (in
result.addError({
name: validationType,
argument: validationArgument,
message: errorMessage + JSON.stringify(validationArgument)
message: errorMessage + JSON.stringify(validationArgument),
});
}
@@ -458,7 +632,7 @@ var validateMultipleOfOrDivisbleBy = function validateMultipleOfOrDivisbleBy (in
* @return {String|null}
*/
validators.multipleOf = function validateMultipleOf (instance, schema, options, ctx) {
return validateMultipleOfOrDivisbleBy.call(this, instance, schema, options, ctx, "multipleOf", "is not a multiple of (divisible by) ");
return validateMultipleOfOrDivisbleBy.call(this, instance, schema, options, ctx, "multipleOf", "is not a multiple of (divisible by) ");
};
/**
@@ -480,14 +654,14 @@ validators.divisibleBy = function validateDivisibleBy (instance, schema, options
validators.required = function validateRequired (instance, schema, options, ctx) {
var result = new ValidatorResult(instance, schema, options, ctx);
if (instance === undefined && schema.required === true) {
// A boolean form is implemented for reverse-compatability with schemas written against older drafts
// A boolean form is implemented for reverse-compatibility with schemas written against older drafts
result.addError({
name: 'required',
message: "is required"
message: "is required",
});
} else if (this.types.object(instance) && Array.isArray(schema.required)) {
schema.required.forEach(function(n){
if(instance[n]===undefined){
if(getEnumerableProperty(instance, n)===undefined){
result.addError({
name: 'required',
argument: n,
@@ -508,7 +682,15 @@ validators.required = function validateRequired (instance, schema, options, ctx)
validators.pattern = function validatePattern (instance, schema, options, ctx) {
if (!this.types.string(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
if (!instance.match(schema.pattern)) {
var pattern = schema.pattern;
try {
var regexp = new RegExp(pattern, 'u');
} catch(_e) {
// In the event the stricter handling causes an error, fall back on the forgiving handling
// DEPRECATED
regexp = new RegExp(pattern);
}
if (!instance.match(regexp)) {
result.addError({
name: 'pattern',
argument: schema.pattern,
@@ -633,32 +815,6 @@ validators.maxItems = function validateMaxItems (instance, schema, options, ctx)
return result;
};
/**
* Validates that every item in an instance array is unique, when instance is an array
* @param instance
* @param schema
* @param options
* @param ctx
* @return {String|null|ValidatorResult}
*/
validators.uniqueItems = function validateUniqueItems (instance, schema, options, ctx) {
if (!this.types.array(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
function testArrays (v, i, a) {
for (var j = i + 1; j < a.length; j++) if (helpers.deepCompareStrict(v, a[j])) {
return false;
}
return true;
}
if (!instance.every(testArrays)) {
result.addError({
name: 'uniqueItems',
message: "contains duplicate item",
});
}
return result;
};
/**
* Deep compares arrays for duplicates
* @param v
@@ -683,6 +839,7 @@ function testArrays (v, i, a) {
* @return {String|null}
*/
validators.uniqueItems = function validateUniqueItems (instance, schema, options, ctx) {
if (schema.uniqueItems!==true) return;
if (!this.types.array(instance)) return;
var result = new ValidatorResult(instance, schema, options, ctx);
if (!instance.every(testArrays)) {
@@ -806,7 +963,8 @@ validators.not = validators.disallow = function validateNot (instance, schema, o
if(!Array.isArray(notTypes)) notTypes=[notTypes];
notTypes.forEach(function (type) {
if (self.testType(instance, schema, options, ctx, type)) {
var schemaId = type && type.id && ('<' + type.id + '>') || type;
var id = type && (type.$id || type.id);
var schemaId = id || type;
result.addError({
name: 'not',
argument: schemaId,

View File

@@ -2,21 +2,23 @@
var uri = require('url');
var ValidationError = exports.ValidationError = function ValidationError (message, instance, schema, propertyPath, name, argument) {
if (propertyPath) {
this.property = propertyPath;
var ValidationError = exports.ValidationError = function ValidationError (message, instance, schema, path, name, argument) {
if(Array.isArray(path)){
this.path = path;
this.property = path.reduce(function(sum, item){
return sum + makeSuffix(item);
}, 'instance');
}else if(path !== undefined){
this.property = path;
}
if (message) {
this.message = message;
}
if (schema) {
if (schema.id) {
this.schema = schema.id;
} else {
this.schema = schema;
}
var id = schema.$id || schema.id;
this.schema = id || schema;
}
if (instance) {
if (instance !== undefined) {
this.instance = instance;
}
this.name = name;
@@ -31,27 +33,33 @@ ValidationError.prototype.toString = function toString() {
var ValidatorResult = exports.ValidatorResult = function ValidatorResult(instance, schema, options, ctx) {
this.instance = instance;
this.schema = schema;
this.options = options;
this.path = ctx.path;
this.propertyPath = ctx.propertyPath;
this.errors = [];
this.throwError = options && options.throwError;
this.throwFirst = options && options.throwFirst;
this.throwAll = options && options.throwAll;
this.disableFormat = options && options.disableFormat === true;
};
ValidatorResult.prototype.addError = function addError(detail) {
var err;
if (typeof detail == 'string') {
err = new ValidationError(detail, this.instance, this.schema, this.propertyPath);
err = new ValidationError(detail, this.instance, this.schema, this.path);
} else {
if (!detail) throw new Error('Missing error detail');
if (!detail.message) throw new Error('Missing error message');
if (!detail.name) throw new Error('Missing validator type');
err = new ValidationError(detail.message, this.instance, this.schema, this.propertyPath, detail.name, detail.argument);
err = new ValidationError(detail.message, this.instance, this.schema, this.path, detail.name, detail.argument);
}
if (this.throwError) {
this.errors.push(err);
if (this.throwFirst) {
throw new ValidatorResultError(this);
}else if(this.throwError){
throw err;
}
this.errors.push(err);
return err;
};
@@ -59,7 +67,7 @@ ValidatorResult.prototype.importErrors = function importErrors(res) {
if (typeof res == 'string' || (res && res.validatorType)) {
this.addError(res);
} else if (res && res.errors) {
Array.prototype.push.apply(this.errors, res.errors);
this.errors = this.errors.concat(res.errors);
}
};
@@ -74,6 +82,20 @@ Object.defineProperty(ValidatorResult.prototype, "valid", { get: function() {
return !this.errors.length;
} });
module.exports.ValidatorResultError = ValidatorResultError;
function ValidatorResultError(result) {
if(Error.captureStackTrace){
Error.captureStackTrace(this, ValidatorResultError);
}
this.instance = result.instance;
this.schema = result.schema;
this.options = result.options;
this.errors = result.errors;
}
ValidatorResultError.prototype = new Error();
ValidatorResultError.prototype.constructor = ValidatorResultError;
ValidatorResultError.prototype.name = "Validation Error";
/**
* Describes a problem with a Schema which prevents validation of an instance
* @name SchemaError
@@ -86,14 +108,22 @@ var SchemaError = exports.SchemaError = function SchemaError (msg, schema) {
Error.captureStackTrace(this, SchemaError);
};
SchemaError.prototype = Object.create(Error.prototype,
{ constructor: {value: SchemaError, enumerable: false}
, name: {value: 'SchemaError', enumerable: false}
{
constructor: {value: SchemaError, enumerable: false},
name: {value: 'SchemaError', enumerable: false},
});
var SchemaContext = exports.SchemaContext = function SchemaContext (schema, options, propertyPath, base, schemas) {
var SchemaContext = exports.SchemaContext = function SchemaContext (schema, options, path, base, schemas) {
this.schema = schema;
this.options = options;
this.propertyPath = propertyPath;
if(Array.isArray(path)){
this.path = path;
this.propertyPath = path.reduce(function(sum, item){
return sum + makeSuffix(item);
}, 'instance');
}else{
this.propertyPath = path;
}
this.base = base;
this.schemas = schemas;
};
@@ -103,36 +133,60 @@ SchemaContext.prototype.resolve = function resolve (target) {
};
SchemaContext.prototype.makeChild = function makeChild(schema, propertyName){
var propertyPath = (propertyName===undefined) ? this.propertyPath : this.propertyPath+makeSuffix(propertyName);
var base = uri.resolve(this.base, schema.id||'');
var ctx = new SchemaContext(schema, this.options, propertyPath, base, Object.create(this.schemas));
if(schema.id && !ctx.schemas[base]){
var path = (propertyName===undefined) ? this.path : this.path.concat([propertyName]);
var id = schema.$id || schema.id;
var base = uri.resolve(this.base, id||'');
var ctx = new SchemaContext(schema, this.options, path, base, Object.create(this.schemas));
if(id && !ctx.schemas[base]){
ctx.schemas[base] = schema;
}
return ctx;
}
};
var FORMAT_REGEXPS = exports.FORMAT_REGEXPS = {
// 7.3.1. Dates, Times, and Duration
'date-time': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-(3[01]|0[1-9]|[12][0-9])[tT ](2[0-4]|[01][0-9]):([0-5][0-9]):(60|[0-5][0-9])(\.\d+)?([zZ]|[+-]([0-5][0-9]):(60|[0-5][0-9]))$/,
'date': /^\d{4}-(?:0[0-9]{1}|1[0-2]{1})-(3[01]|0[1-9]|[12][0-9])$/,
'time': /^(2[0-4]|[01][0-9]):([0-5][0-9]):(60|[0-5][0-9])$/,
'duration': /P(T\d+(H(\d+M(\d+S)?)?|M(\d+S)?|S)|\d+(D|M(\d+D)?|Y(\d+M(\d+D)?)?)(T\d+(H(\d+M(\d+S)?)?|M(\d+S)?|S))?|\d+W)/i,
// 7.3.2. Email Addresses
// TODO: fix the email production
'email': /^(?:[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+\.)*[\w\!\#\$\%\&\'\*\+\-\/\=\?\^\`\{\|\}\~]+@(?:(?:(?:[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!\.)){0,61}[a-zA-Z0-9]?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9\-](?!$)){0,61}[a-zA-Z0-9]?)|(?:\[(?:(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\.){3}(?:[01]?\d{1,2}|2[0-4]\d|25[0-5])\]))$/,
'ip-address': /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
'ipv6': /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/,
'uri': /^[a-zA-Z][a-zA-Z0-9+-.]*:[^\s]*$/,
'idn-email': /^("(?:[!#-\[\]-\u{10FFFF}]|\\[\t -\u{10FFFF}])*"|[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*)@([!#-'*+\-/-9=?A-Z\^-\u{10FFFF}](?:\.?[!#-'*+\-/-9=?A-Z\^-\u{10FFFF}])*|\[[!-Z\^-\u{10FFFF}]*\])$/u,
'color': /^(#?([0-9A-Fa-f]{3}){1,2}\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\)))$/,
// 7.3.3. Hostnames
// 7.3.4. IP Addresses
'ip-address': /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/,
// FIXME whitespace is invalid
'ipv6': /^\s*((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?\s*$/,
// 7.3.5. Resource Identifiers
// TODO: A more accurate regular expression for "uri" goes:
// [A-Za-z][+\-.0-9A-Za-z]*:((/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?)?#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])|/?%[0-9A-Fa-f]{2}|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*(#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?|/(/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)?)?
'uri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/,
'uri-reference': /^(((([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|([A-Za-z][+\-.0-9A-Za-z]*:?)?)|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?))#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|(([A-Za-z][+\-.0-9A-Za-z]*)?%[0-9A-Fa-f]{2}|[!$&-.0-9;=@_~]|[A-Za-z][+\-.0-9A-Za-z]*[!$&-*,;=@_~])(%[0-9A-Fa-f]{2}|[!$&-.0-9;=@-Z_a-z~])*((([/?](%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?#|[/?])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*)?|([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~])*|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~]+)?|[.0-:A-Fa-f]+)\])?)?|[A-Za-z][+\-.0-9A-Za-z]*:?)?$/,
'iri': /^[a-zA-Z][a-zA-Z0-9+.-]*:[^\s]*$/,
'iri-reference': /^(((([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~-\u{10FFFF}]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|([A-Za-z][+\-.0-9A-Za-z]*:?)?)|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|(\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?)?))#(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|(([A-Za-z][+\-.0-9A-Za-z]*)?%[0-9A-Fa-f]{2}|[!$&-.0-9;=@_~-\u{10FFFF}]|[A-Za-z][+\-.0-9A-Za-z]*[!$&-*,;=@_~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-.0-9;=@-Z_a-z~-\u{10FFFF}])*((([/?](%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*)?#|[/?])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*)?|([A-Za-z][+\-.0-9A-Za-z]*(:%[0-9A-Fa-f]{2}|:[!$&-.0-;=?-Z_a-z~-\u{10FFFF}]|[/?])|\?)(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|([A-Za-z][+\-.0-9A-Za-z]*:)?\/((%[0-9A-Fa-f]{2}|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)(:\d*)?[/?]|[!$&-.0-;=?-Z_a-z~-\u{10FFFF}])(%[0-9A-Fa-f]{2}|[!$&-;=?-Z_a-z~-\u{10FFFF}])*|\/((%[0-9A-Fa-f]{2}|[!$&-.0-9;=A-Z_a-z~-\u{10FFFF}])+(:\d*)?|(\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?:\d*|\[(([Vv][0-9A-Fa-f]+\.[!$&-.0-;=A-Z_a-z~-\u{10FFFF}]+)?|[.0-:A-Fa-f]+)\])?)?|[A-Za-z][+\-.0-9A-Za-z]*:?)?$/u,
'uuid': /^[0-9A-F]{8}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{4}-[0-9A-F]{12}$/i,
// 7.3.6. uri-template
'uri-template': /(%[0-9a-f]{2}|[!#$&(-;=?@\[\]_a-z~]|\{[!#&+,./;=?@|]?(%[0-9a-f]{2}|[0-9_a-z])(\.?(%[0-9a-f]{2}|[0-9_a-z]))*(:[1-9]\d{0,3}|\*)?(,(%[0-9a-f]{2}|[0-9_a-z])(\.?(%[0-9a-f]{2}|[0-9_a-z]))*(:[1-9]\d{0,3}|\*)?)*\})*/iu,
// 7.3.7. JSON Pointers
'json-pointer': /^(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*$/iu,
'relative-json-pointer': /^\d+(#|(\/([\x00-\x2e0-@\[-}\x7f]|~[01])*)*)$/iu,
// hostname regex from: http://stackoverflow.com/a/1420225/5628
'hostname': /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/,
'host-name': /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/,
'alpha': /^[a-zA-Z]+$/,
'alphanumeric': /^[a-zA-Z0-9]+$/,
'utc-millisec': function (input) {
return (typeof input === 'string') && parseFloat(input) === parseInt(input, 10) && !isNaN(input);
},
// 7.3.8. regex
'regex': function (input) {
var result = true;
try {
@@ -142,8 +196,15 @@ var FORMAT_REGEXPS = exports.FORMAT_REGEXPS = {
}
return result;
},
'style': /\s*(.+?):\s*([^;]+);?/,
'phone': /^\+(?:[0-9] ?){6,14}[0-9]$/
// Other definitions
// "style" was removed from JSON Schema in draft-4 and is deprecated
'style': /[\r\n\t ]*[^\r\n\t ][^:]*:[\r\n\t ]*[^\r\n\t ;]*[\r\n\t ]*;?/,
// "color" was removed from JSON Schema in draft-4 and is deprecated
'color': /^(#?([0-9A-Fa-f]{3}){1,2}\b|aqua|black|blue|fuchsia|gray|green|lime|maroon|navy|olive|orange|purple|red|silver|teal|white|yellow|(rgb\(\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*,\s*\b([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\b\s*\))|(rgb\(\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*,\s*(\d?\d%|100%)+\s*\)))$/,
'phone': /^\+(?:[0-9] ?){6,14}[0-9]$/,
'alpha': /^[a-zA-Z]+$/,
'alphanumeric': /^[a-zA-Z0-9]+$/,
};
FORMAT_REGEXPS.regexp = FORMAT_REGEXPS.regex;
@@ -212,10 +273,10 @@ exports.deepCompareStrict = function deepCompareStrict (a, b) {
function deepMerger (target, dst, e, i) {
if (typeof e === 'object') {
dst[i] = deepMerge(target[i], e)
dst[i] = deepMerge(target[i], e);
} else {
if (target.indexOf(e) === -1) {
dst.push(e)
dst.push(e);
}
}
}
@@ -232,7 +293,7 @@ function copyistWithDeepMerge (target, src, dst, key) {
if (!target[key]) {
dst[key] = src[key];
} else {
dst[key] = deepMerge(target[key], src[key])
dst[key] = deepMerge(target[key], src[key]);
}
}
}
@@ -253,7 +314,7 @@ function deepMerge (target, src) {
}
return dst;
};
}
module.exports.deepMerge = deepMerge;
@@ -284,9 +345,9 @@ function pathEncoder (v) {
* @return {String}
*/
exports.encodePath = function encodePointer(a){
// ~ must be encoded explicitly because hacks
// the slash is encoded by encodeURIComponent
return a.map(pathEncoder).join('');
// ~ must be encoded explicitly because hacks
// the slash is encoded by encodeURIComponent
return a.map(pathEncoder).join('');
};
@@ -323,3 +384,7 @@ exports.getDecimalPlaces = function getDecimalPlaces(number) {
return decimalPlaces;
};
exports.isSchema = function isSchema(val){
return (typeof val === 'object' && val) || (typeof val === 'boolean');
};

View File

@@ -29,6 +29,7 @@ export declare class ValidatorResult {
export declare class ValidationError {
constructor(message?: string, instance?: any, schema?: Schema, propertyPath?: any, name?: string, argument?: any);
path: (string|number)[];
property: string;
message: string;
schema: string|Schema;
@@ -48,6 +49,7 @@ export declare class SchemaError extends Error{
export declare function validate(instance: any, schema: any, options?: Options): ValidatorResult
export interface Schema {
$id?: string
id?: string
$schema?: string
$ref?: string
@@ -55,9 +57,9 @@ export interface Schema {
description?: string
multipleOf?: number
maximum?: number
exclusiveMaximum?: boolean
exclusiveMaximum?: number | boolean
minimum?: number
exclusiveMinimum?: boolean
exclusiveMinimum?: number | boolean
maxLength?: number
minLength?: number
pattern?: string | RegExp
@@ -82,6 +84,7 @@ export interface Schema {
dependencies?: {
[name: string]: Schema | string[]
}
const?: any
'enum'?: any[]
type?: string | string[]
format?: string
@@ -89,27 +92,39 @@ export interface Schema {
anyOf?: Schema[]
oneOf?: Schema[]
not?: Schema
if?: Schema
then?: Schema
else?: Schema
}
export interface Options {
skipAttributes?: string[];
allowUnknownAttributes?: boolean;
preValidateProperty?: PreValidatePropertyFunction;
rewrite?: RewriteFunction;
propertyName?: string;
base?: string;
throwError?: boolean;
required?: boolean;
throwFirst?: boolean;
throwAll?: boolean;
nestedErrors?: boolean;
}
export interface RewriteFunction {
(instance: any, schema: Schema, options: Options, ctx: SchemaContext): any;
}
export interface PreValidatePropertyFunction {
(instance: any, key: string, schema: Schema, options: Options, ctx: SchemaContext): any;
}
export interface SchemaContext {
schema: Schema;
options: Options;
propertyPath: string;
base: string;
schemas: {[base: string]: Schema};
makeChild: (schema: Schema, key: string) => SchemaContext;
}
export interface CustomFormat {

View File

@@ -3,6 +3,7 @@
var Validator = module.exports.Validator = require('./validator');
module.exports.ValidatorResult = require('./helpers').ValidatorResult;
module.exports.ValidatorResultError = require('./helpers').ValidatorResultError;
module.exports.ValidationError = require('./helpers').ValidationError;
module.exports.SchemaError = require('./helpers').SchemaError;
module.exports.SchemaScanResult = require('./scan').SchemaScanResult;

View File

@@ -1,3 +1,4 @@
"use strict";
var urilib = require('url');
var helpers = require('./helpers');
@@ -23,13 +24,14 @@ module.exports.scan = function scan(base, schema){
ref[resolvedUri] = ref[resolvedUri] ? ref[resolvedUri]+1 : 0;
return;
}
var ourBase = schema.id ? urilib.resolve(baseuri, schema.id) : baseuri;
var id = schema.$id || schema.id;
var ourBase = id ? urilib.resolve(baseuri, id) : baseuri;
if (ourBase) {
// If there's no fragment, append an empty one
if(ourBase.indexOf('#')<0) ourBase += '#';
if(found[ourBase]){
if(!helpers.deepCompareStrict(found[ourBase], schema)){
throw new Error('Schema <'+schema+'> already exists with different definition');
throw new Error('Schema <'+ourBase+'> already exists with different definition');
}
return found[ourBase];
}
@@ -68,7 +70,6 @@ module.exports.scan = function scan(base, schema){
var found = {};
var ref = {};
var schemaUri = base;
scanSchema(base, schema);
return new SchemaScanResult(found, ref);
}
};

View File

@@ -6,6 +6,7 @@ var attribute = require('./attribute');
var helpers = require('./helpers');
var scanSchema = require('./scan').scan;
var ValidatorResult = helpers.ValidatorResult;
var ValidatorResultError = helpers.ValidatorResultError;
var SchemaError = helpers.SchemaError;
var SchemaContext = helpers.SchemaContext;
//var anonymousBase = 'vnd.jsonschema:///';
@@ -49,13 +50,15 @@ Validator.prototype.addSchema = function addSchema (schema, base) {
return null;
}
var scan = scanSchema(base||anonymousBase, schema);
var ourUri = base || schema.id;
var ourUri = base || schema.$id || schema.id;
for(var uri in scan.id){
this.schemas[uri] = scan.id[uri];
}
for(var uri in scan.ref){
// If this schema is already defined, it will be filtered out by the next step
this.unresolvedRefs.push(uri);
}
// Remove newly defined schemas from unresolvedRefs
this.unresolvedRefs = this.unresolvedRefs.filter(function(uri){
return typeof self.schemas[uri]==='undefined';
});
@@ -103,14 +106,18 @@ Validator.prototype.getSchema = function getSchema (urn) {
* @return {Array}
*/
Validator.prototype.validate = function validate (instance, schema, options, ctx) {
if((typeof schema !== 'boolean' && typeof schema !== 'object') || schema === null){
throw new SchemaError('Expected `schema` to be an object or boolean');
}
if (!options) {
options = {};
}
var propertyName = options.propertyName || 'instance';
// This section indexes subschemas in the provided schema, so they don't need to be added with Validator#addSchema
// This will work so long as the function at uri.resolve() will resolve a relative URI to a relative URI
var base = urilib.resolve(options.base||anonymousBase, schema.id||'');
var id = schema.$id || schema.id;
var base = urilib.resolve(options.base||anonymousBase, id||'');
if(!ctx){
ctx = new SchemaContext(schema, options, propertyName, base, Object.create(this.schemas));
ctx = new SchemaContext(schema, options, [], base, Object.create(this.schemas));
if (!ctx.schemas[base]) {
ctx.schemas[base] = schema;
}
@@ -120,14 +127,18 @@ Validator.prototype.validate = function validate (instance, schema, options, ctx
ctx.schemas[n] = sch;
}
}
if (schema) {
var result = this.validateSchema(instance, schema, options, ctx);
if (!result) {
throw new Error('Result undefined');
}
if(options.required && instance===undefined){
var result = new ValidatorResult(instance, schema, options, ctx);
result.addError('is required, but is undefined');
return result;
}
throw new SchemaError('no schema specified', schema);
var result = this.validateSchema(instance, schema, options, ctx);
if (!result) {
throw new Error('Result undefined');
}else if(options.throwAll && result.errors.length){
throw new ValidatorResultError(result);
}
return result;
};
/**
@@ -152,7 +163,7 @@ function shouldResolve(schema) {
Validator.prototype.validateSchema = function validateSchema (instance, schema, options, ctx) {
var result = new ValidatorResult(instance, schema, options, ctx);
// Support for the true/false schemas
// Support for the true/false schemas
if(typeof schema==='boolean') {
if(schema===true){
// `true` is always valid
@@ -180,10 +191,10 @@ Validator.prototype.validateSchema = function validateSchema (instance, schema,
}
// If passed a string argument, load that schema URI
var switchSchema;
if (switchSchema = shouldResolve(schema)) {
var switchSchema = shouldResolve(schema);
if (switchSchema) {
var resolved = this.resolve(schema, switchSchema, ctx);
var subctx = new SchemaContext(resolved.subschema, options, ctx.propertyPath, resolved.switchSchema, ctx.schemas);
var subctx = new SchemaContext(resolved.subschema, options, ctx.path, resolved.switchSchema, ctx.schemas);
return this.validateSchema(instance, resolved.subschema, options, subctx);
}
@@ -220,7 +231,7 @@ Validator.prototype.validateSchema = function validateSchema (instance, schema,
*/
Validator.prototype.schemaTraverser = function schemaTraverser (schemaobj, s) {
schemaobj.schema = helpers.deepMerge(schemaobj.schema, this.superResolve(s, schemaobj.ctx));
}
};
/**
* @private
@@ -229,12 +240,12 @@ Validator.prototype.schemaTraverser = function schemaTraverser (schemaobj, s) {
* @returns Object schema or resolved schema
*/
Validator.prototype.superResolve = function superResolve (schema, ctx) {
var ref;
if(ref = shouldResolve(schema)) {
var ref = shouldResolve(schema);
if(ref) {
return this.resolve(schema, ref, ctx).subschema;
}
return schema;
}
};
/**
* @private
@@ -275,6 +286,11 @@ Validator.prototype.resolve = function resolve (schema, switchSchema, ctx) {
* @return {boolean}
*/
Validator.prototype.testType = function validateType (instance, schema, options, ctx, type) {
if(type===undefined){
return;
}else if(type===null){
throw new SchemaError('Unexpected null in "type" keyword');
}
if (typeof this.types[type] == 'function') {
return this.types[type].call(this, instance);
}

12
node_modules/jsonschema/package.json generated vendored
View File

@@ -1,7 +1,7 @@
{
"author": "Tom de Grunt <tom@degrunt.nl>",
"name": "jsonschema",
"version": "1.2.6",
"version": "1.4.1",
"license": "MIT",
"dependencies": {},
"contributors": [
@@ -9,12 +9,15 @@
"name": "Austin Wright"
}
],
"main": "./lib",
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"devDependencies": {
"@stryker-mutator/core": "^4.0.0",
"@stryker-mutator/mocha-runner": "^4.0.0",
"chai": "~4.2.0",
"eslint": "^7.7.0",
"json-metaschema": "^1.2.0",
"mocha": "~3",
"chai": "~1.5.0"
"mocha": "~8.1.1"
},
"optionalDependencies": {},
"engines": {
@@ -33,6 +36,7 @@
},
"description": "A fast and easy to use JSON Schema validator",
"scripts": {
"stryker": "stryker run",
"test": "./node_modules/.bin/mocha -R spec"
}
}

11
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "codeql",
"version": "2.3.0",
"version": "2.3.4",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codeql",
"version": "2.3.0",
"version": "2.3.4",
"license": "MIT",
"dependencies": {
"@actions/artifact": "^1.1.0",
@@ -29,7 +29,7 @@
"fs": "0.0.1-security",
"get-folder-size": "^2.0.1",
"js-yaml": "^4.1.0",
"jsonschema": "1.2.6",
"jsonschema": "1.4.1",
"long": "^5.2.0",
"path": "^0.12.7",
"semver": "^7.3.2",
@@ -4202,8 +4202,9 @@
}
},
"node_modules/jsonschema": {
"version": "1.2.6",
"integrity": "sha512-SqhURKZG07JyKKeo/ir24QnS4/BV7a6gQy93bUSe4lUdNp0QNpIz2c9elWJQ9dpc5cQYY6cvCzgRwy0MQCLyqA==",
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz",
"integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==",
"engines": {
"node": "*"
}

View File

@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "2.3.0",
"version": "2.3.4",
"private": true,
"description": "CodeQL action",
"scripts": {
@@ -41,7 +41,7 @@
"fs": "0.0.1-security",
"get-folder-size": "^2.0.1",
"js-yaml": "^4.1.0",
"jsonschema": "1.2.6",
"jsonschema": "1.4.1",
"long": "^5.2.0",
"path": "^0.12.7",
"semver": "^7.3.2",

View File

@@ -21,7 +21,7 @@ steps:
with:
upload-database: false
- name: Check language autodetect for all languages excluding Ruby, Swift
- name: Check language autodetect for all languages excluding Swift
shell: bash
run: |
CPP_DB=${{ fromJson(steps.analysis.outputs.db-locations).cpp }}
@@ -54,11 +54,6 @@ steps:
echo "Did not create a database for Python, or created it in the wrong location."
exit 1
fi
- name: Check language autodetect for Ruby
if: env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true'
shell: bash
run: |
RUBY_DB=${{ fromJson(steps.analysis.outputs.db-locations).ruby }}
if [[ ! -d $RUBY_DB ]] || [[ ! $RUBY_DB == ${{ runner.temp }}/customDbLocation/* ]]; then
echo "Did not create a database for Ruby, or created it in the wrong location."
@@ -66,7 +61,9 @@ steps:
fi
- name: Check language autodetect for Swift
if: env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true'
if: >-
env.CODEQL_ENABLE_EXPERIMENTAL_FEATURES_SWIFT == 'true' ||
(runner.os != 'Windows' && matrix.version == 'nightly-latest')
shell: bash
run: |
SWIFT_DB=${{ fromJson(steps.analysis.outputs.db-locations).swift }}

View File

@@ -83,8 +83,7 @@ for file in os.listdir('checks'):
matrix.version == '20220908' ||
matrix.version == '20221211' ||
matrix.version == 'cached' ||
matrix.version == 'latest' ||
matrix.version == 'nightly-latest'
matrix.version == 'latest'
)
''').strip()),
'shell': 'bash',

View File

@@ -21,7 +21,11 @@ import {
parseMatrixInput,
UserError,
} from "./util";
import { getWorkflowRelativePath } from "./workflow";
import {
getWorkflowRunID,
getWorkflowRunAttempt,
getWorkflowRelativePath,
} from "./workflow";
// eslint-disable-next-line import/no-commonjs
const pkg = require("../package.json") as JSONSchemaForNPMPackageJsonFiles;
@@ -407,16 +411,8 @@ export async function createStatusReportBase(
): Promise<StatusReportBase> {
const commitOid = getOptionalInput("sha") || process.env["GITHUB_SHA"] || "";
const ref = await getRef();
const workflowRunIDStr = process.env["GITHUB_RUN_ID"];
let workflowRunID = -1;
if (workflowRunIDStr) {
workflowRunID = parseInt(workflowRunIDStr, 10);
}
const workflowRunAttemptStr = process.env["GITHUB_RUN_ATTEMPT"];
let workflowRunAttempt = -1;
if (workflowRunAttemptStr) {
workflowRunAttempt = parseInt(workflowRunAttemptStr, 10);
}
const workflowRunID = getWorkflowRunID();
const workflowRunAttempt = getWorkflowRunAttempt();
const workflowName = process.env["GITHUB_WORKFLOW"] || "";
const jobName = process.env["GITHUB_JOB"] || "";
const analysis_key = await getAnalysisKey();

View File

@@ -237,7 +237,8 @@ async function run() {
threads,
memory,
config,
logger
logger,
features
);
if (actionsUtil.getRequiredInput("skip-queries") !== "true") {

View File

@@ -10,7 +10,7 @@ import { DatabaseCreationTimings } from "./actions-util";
import * as analysisPaths from "./analysis-paths";
import { CodeQL, getCodeQL } from "./codeql";
import * as configUtils from "./config-utils";
import { FeatureEnablement } from "./feature-flags";
import { FeatureEnablement, Feature } from "./feature-flags";
import { isScannedLanguage, Language } from "./languages";
import { Logger } from "./logging";
import { endTracingForCluster } from "./tracer-config";
@@ -80,13 +80,27 @@ export interface QueriesStatusReport {
analyze_failure_language?: string;
}
async function setupPythonExtractor(logger: Logger) {
async function setupPythonExtractor(
logger: Logger,
features: FeatureEnablement,
codeql: CodeQL
) {
const codeqlPython = process.env["CODEQL_PYTHON"];
if (codeqlPython === undefined || codeqlPython.length === 0) {
// If CODEQL_PYTHON is not set, no dependencies were installed, so we don't need to do anything
return;
}
if (
await features.getValue(Feature.DisablePythonDependencyInstallation, codeql)
) {
logger.warning(
"We recommend that you remove the CODEQL_PYTHON environment variable from your workflow. This environment variable was originally used to specify a Python executable that included the dependencies of your Python code, however Python analysis no longer uses these dependencies." +
"\nIf you used CODEQL_PYTHON to force the version of Python to analyze as, please use CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION instead, such as 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=2.7' or 'CODEQL_EXTRACTOR_PYTHON_ANALYSIS_VERSION=3.11'."
);
return;
}
const scriptsFolder = path.resolve(__dirname, "../python-setup");
let output = "";
@@ -119,7 +133,8 @@ async function setupPythonExtractor(logger: Logger) {
export async function createdDBForScannedLanguages(
codeql: CodeQL,
config: configUtils.Config,
logger: Logger
logger: Logger,
features: FeatureEnablement
) {
// Insert the LGTM_INDEX_X env vars at this point so they are set when
// we extract any scanned languages.
@@ -133,7 +148,7 @@ export async function createdDBForScannedLanguages(
logger.startGroup(`Extracting ${language}`);
if (language === Language.python) {
await setupPythonExtractor(logger);
await setupPythonExtractor(logger, features, codeql);
}
await codeql.extractScannedLanguage(config, language);
@@ -165,12 +180,13 @@ async function finalizeDatabaseCreation(
config: configUtils.Config,
threadsFlag: string,
memoryFlag: string,
logger: Logger
logger: Logger,
features: FeatureEnablement
): Promise<DatabaseCreationTimings> {
const codeql = await getCodeQL(config.codeQLCmd);
const extractionStart = performance.now();
await createdDBForScannedLanguages(codeql, config, logger);
await createdDBForScannedLanguages(codeql, config, logger, features);
const extractionTime = performance.now() - extractionStart;
const trapImportStart = performance.now();
@@ -474,7 +490,8 @@ export async function runFinalize(
threadsFlag: string,
memoryFlag: string,
config: configUtils.Config,
logger: Logger
logger: Logger,
features: FeatureEnablement
): Promise<DatabaseCreationTimings> {
try {
await del(outputDir, { force: true });
@@ -489,7 +506,8 @@ export async function runFinalize(
config,
threadsFlag,
memoryFlag,
logger
logger,
features
);
// WARNING: This does not _really_ end tracing, as the tracer will restore its

View File

@@ -16,37 +16,29 @@ import { GitHubApiDetails } from "./api-client";
import * as codeql from "./codeql";
import { AugmentationProperties, Config } from "./config-utils";
import * as defaults from "./defaults.json";
import {
CodeQLDefaultVersionInfo,
Feature,
featureConfig,
} from "./feature-flags";
import { Feature, featureConfig } from "./feature-flags";
import { ToolsSource } from "./init";
import { Language } from "./languages";
import { getRunnerLogger } from "./logging";
import { setupTests, createFeatures, setupActionsVars } from "./testing-utils";
import {
setupTests,
createFeatures,
setupActionsVars,
SAMPLE_DOTCOM_API_DETAILS,
SAMPLE_DEFAULT_CLI_VERSION,
mockBundleDownloadApi,
} from "./testing-utils";
import * as util from "./util";
import { initializeEnvironment } from "./util";
setupTests(test);
const sampleApiDetails = {
auth: "token",
url: "https://github.com",
apiURL: "https://api.github.com",
};
const sampleGHAEApiDetails = {
auth: "token",
url: "https://example.githubenterprise.com",
apiURL: "https://example.githubenterprise.com/api/v3",
};
const SAMPLE_DEFAULT_CLI_VERSION: CodeQLDefaultVersionInfo = {
cliVersion: "2.0.0",
variant: util.GitHubVariant.DOTCOM,
};
let stubConfig: Config;
test.beforeEach(() => {
@@ -78,54 +70,8 @@ test.beforeEach(() => {
};
});
/**
* Mocks the API for downloading the bundle tagged `tagName`.
*
* @returns the download URL for the bundle. This can be passed to the tools parameter of
* `codeql.setupCodeQL`.
*/
function mockDownloadApi({
apiDetails = sampleApiDetails,
isPinned,
repo = "github/codeql-action",
platformSpecific = true,
tagName,
}: {
apiDetails?: GitHubApiDetails;
isPinned?: boolean;
repo?: string;
platformSpecific?: boolean;
tagName: string;
}): string {
const platform =
process.platform === "win32"
? "win64"
: process.platform === "linux"
? "linux64"
: "osx64";
const baseUrl = apiDetails?.url ?? "https://example.com";
const relativeUrl = apiDetails
? `/${repo}/releases/download/${tagName}/codeql-bundle${
platformSpecific ? `-${platform}` : ""
}.tar.gz`
: `/download/${tagName}/codeql-bundle.tar.gz`;
nock(baseUrl)
.get(relativeUrl)
.replyWithFile(
200,
path.join(
__dirname,
`/../src/testdata/codeql-bundle${isPinned ? "-pinned" : ""}.tar.gz`
)
);
return `${baseUrl}${relativeUrl}`;
}
async function installIntoToolcache({
apiDetails = sampleApiDetails,
apiDetails = SAMPLE_DOTCOM_API_DETAILS,
cliVersion,
isPinned,
tagName,
@@ -137,7 +83,7 @@ async function installIntoToolcache({
tagName: string;
tmpDir: string;
}) {
const url = mockDownloadApi({ apiDetails, isPinned, tagName });
const url = mockBundleDownloadApi({ apiDetails, isPinned, tagName });
await codeql.setupCodeQL(
cliVersion !== undefined ? undefined : url,
apiDetails,
@@ -152,7 +98,7 @@ async function installIntoToolcache({
}
function mockReleaseApi({
apiDetails = sampleApiDetails,
apiDetails = SAMPLE_DOTCOM_API_DETAILS,
assetNames,
tagName,
}: {
@@ -195,13 +141,13 @@ test("downloads and caches explicitly requested bundles that aren't in the toolc
for (let i = 0; i < versions.length; i++) {
const version = versions[i];
const url = mockDownloadApi({
const url = mockBundleDownloadApi({
tagName: `codeql-bundle-${version}`,
isPinned: false,
});
const result = await codeql.setupCodeQL(
url,
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
@@ -229,12 +175,12 @@ test("downloads an explicitly requested bundle even if a different version is ca
tmpDir,
});
const url = mockDownloadApi({
const url = mockBundleDownloadApi({
tagName: "codeql-bundle-20200610",
});
const result = await codeql.setupCodeQL(
url,
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
@@ -271,20 +217,20 @@ for (const {
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
mockApiDetails(sampleApiDetails);
mockApiDetails(SAMPLE_DOTCOM_API_DETAILS);
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
const releaseApiMock = mockReleaseApi({
assetNames: [`cli-version-${cliVersion}.txt`],
tagName: "codeql-bundle-20200610",
});
const url = mockDownloadApi({
const url = mockBundleDownloadApi({
tagName: "codeql-bundle-20200610",
});
const result = await codeql.setupCodeQL(
url,
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
@@ -351,7 +297,7 @@ for (const { githubReleases, toolcacheVersion } of [
const result = await codeql.setupCodeQL(
undefined,
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
@@ -379,7 +325,7 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
const result = await codeql.setupCodeQL(
undefined,
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
variant,
{
@@ -409,12 +355,12 @@ for (const variant of [util.GitHubVariant.GHAE, util.GitHubVariant.GHES]) {
tmpDir,
});
mockDownloadApi({
mockBundleDownloadApi({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL(
undefined,
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
variant,
{
@@ -445,12 +391,12 @@ test('downloads bundle if "latest" tools specified but not cached', async (t) =>
tmpDir,
});
mockDownloadApi({
mockBundleDownloadApi({
tagName: defaults.bundleVersion,
});
const result = await codeql.setupCodeQL(
"latest",
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
@@ -547,13 +493,13 @@ test("bundle URL from another repo is cached as 0.0.0-bundleVersion", async (t)
await util.withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
mockApiDetails(sampleApiDetails);
mockApiDetails(SAMPLE_DOTCOM_API_DETAILS);
sinon.stub(actionsUtil, "isRunningLocalAction").returns(true);
const releasesApiMock = mockReleaseApi({
assetNames: ["cli-version-2.12.2.txt"],
tagName: "codeql-bundle-20230203",
});
mockDownloadApi({
mockBundleDownloadApi({
repo: "codeql-testing/codeql-cli-nightlies",
platformSpecific: false,
tagName: "codeql-bundle-20230203",
@@ -561,7 +507,7 @@ test("bundle URL from another repo is cached as 0.0.0-bundleVersion", async (t)
const result = await codeql.setupCodeQL(
"https://github.com/codeql-testing/codeql-cli-nightlies/releases/download/codeql-bundle-20230203/codeql-bundle.tar.gz",
sampleApiDetails,
SAMPLE_DOTCOM_API_DETAILS,
tmpDir,
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
@@ -622,54 +568,6 @@ test("getExtraOptions throws for bad content", (t) => {
);
});
test("databaseInterpretResults() does not set --sarif-add-query-help for 2.7.0", async (t) => {
const runnerConstructorStub = stubToolRunnerConstructor();
const codeqlObject = await codeql.getCodeQLForTesting();
sinon.stub(codeqlObject, "getVersion").resolves("2.7.0");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults(
"",
[],
"",
"",
"",
"-v",
"",
stubConfig,
createFeatures([]),
getRunnerLogger(true)
);
t.false(
runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"),
"--sarif-add-query-help should be absent, but it is present"
);
});
test("databaseInterpretResults() sets --sarif-add-query-help for 2.7.1", async (t) => {
const runnerConstructorStub = stubToolRunnerConstructor();
const codeqlObject = await codeql.getCodeQLForTesting();
sinon.stub(codeqlObject, "getVersion").resolves("2.7.1");
// safeWhich throws because of the test CodeQL object.
sinon.stub(safeWhich, "safeWhich").resolves("");
await codeqlObject.databaseInterpretResults(
"",
[],
"",
"",
"",
"-v",
"",
stubConfig,
createFeatures([]),
getRunnerLogger(true)
);
t.true(
runnerConstructorStub.firstCall.args[1].includes("--sarif-add-query-help"),
"--sarif-add-query-help should be present, but it is absent"
);
});
test("databaseInitCluster() without injected codescanning config", async (t) => {
await util.withTmpDir(async (tempDir) => {
const runnerConstructorStub = stubToolRunnerConstructor();

View File

@@ -196,6 +196,8 @@ export interface CodeQL {
config: Config,
features: FeatureEnablement
): Promise<void>;
/** Get the location of an extractor for the specified language. */
resolveExtractor(language: Language): Promise<string>;
}
export interface ResolveLanguagesOutput {
@@ -259,7 +261,6 @@ const CODEQL_MINIMUM_VERSION = "2.8.5";
* For convenience, please keep these in descending order. Once a version
* flag is older than the oldest supported version above, it may be removed.
*/
const CODEQL_VERSION_CUSTOM_QUERY_HELP = "2.7.1";
const CODEQL_VERSION_LUA_TRACER_CONFIG = "2.10.0";
const CODEQL_VERSION_LUA_TRACING_GO_WINDOWS_FIXED = "2.10.4";
export const CODEQL_VERSION_GHES_PACK_DOWNLOAD = "2.10.4";
@@ -340,8 +341,9 @@ export async function setupCodeQL(
toolsVersion,
};
} catch (e) {
logger.error(wrapError(e).message);
throw new Error("Unable to download and extract CodeQL CLI");
throw new Error(
`Unable to download and extract CodeQL CLI: ${wrapError(e).message}`
);
}
}
@@ -417,6 +419,7 @@ export function setCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
"databaseExportDiagnostics"
),
diagnosticsExport: resolveFunction(partialCodeql, "diagnosticsExport"),
resolveExtractor: resolveFunction(partialCodeql, "resolveExtractor"),
};
return cachedCodeQL;
}
@@ -546,17 +549,10 @@ export async function getCodeQLForCmd(
);
},
async runAutobuild(language: Language) {
const cmdName =
process.platform === "win32" ? "autobuild.cmd" : "autobuild.sh";
// The autobuilder for Swift is located in the experimental/ directory.
const possibleExperimentalDir =
language === Language.swift ? "experimental" : "";
const autobuildCmd = path.join(
path.dirname(cmd),
possibleExperimentalDir,
language,
await this.resolveExtractor(language),
"tools",
cmdName
process.platform === "win32" ? "autobuild.cmd" : "autobuild.sh"
);
// Update JAVA_TOOL_OPTIONS to contain '-Dhttp.keepAlive=false'
@@ -589,37 +585,11 @@ export async function getCodeQLForCmd(
},
async extractScannedLanguage(config: Config, language: Language) {
const databasePath = util.getCodeQLDatabasePath(config, language);
// Get extractor location
//
// Request it using `format=json` so we don't need to strip the trailing new line generated by
// the CLI.
let extractorPath = "";
await new toolrunner.ToolRunner(
cmd,
[
"resolve",
"extractor",
"--format=json",
`--language=${language}`,
...getExtraOptionsFromEnv(["resolve", "extractor"]),
],
{
silent: true,
listeners: {
stdout: (data) => {
extractorPath += data.toString();
},
stderr: (data) => {
process.stderr.write(data);
},
},
}
).exec();
// Set trace command
const ext = process.platform === "win32" ? ".cmd" : ".sh";
const traceCommand = path.resolve(
JSON.parse(extractorPath) as string,
await this.resolveExtractor(language),
"tools",
`autobuild${ext}`
);
@@ -772,12 +742,11 @@ export async function getCodeQLForCmd(
addSnippetsFlag,
"--print-diagnostics-summary",
"--print-metrics-summary",
"--sarif-add-query-help",
"--sarif-group-rules-by-pack",
...(await getCodeScanningConfigExportArguments(config, this, features)),
...getExtraOptionsFromEnv(["database", "interpret-results"]),
];
if (await util.codeQlVersionAbove(this, CODEQL_VERSION_CUSTOM_QUERY_HELP))
codeqlArgs.push("--sarif-add-query-help");
if (automationDetailsId !== undefined) {
codeqlArgs.push("--sarif-category", automationDetailsId);
}
@@ -953,6 +922,33 @@ export async function getCodeQLForCmd(
}
await new toolrunner.ToolRunner(cmd, args).exec();
},
async resolveExtractor(language: Language): Promise<string> {
// Request it using `format=json` so we don't need to strip the trailing new line generated by
// the CLI.
let extractorPath = "";
await new toolrunner.ToolRunner(
cmd,
[
"resolve",
"extractor",
"--format=json",
`--language=${language}`,
...getExtraOptionsFromEnv(["resolve", "extractor"]),
],
{
silent: true,
listeners: {
stdout: (data) => {
extractorPath += data.toString();
},
stderr: (data) => {
process.stderr.write(data);
},
},
}
).exec();
return JSON.parse(extractorPath);
},
};
// To ensure that status reports include the CodeQL CLI version wherever
// possible, we want to call getVersion(), which populates the version value

View File

@@ -105,11 +105,12 @@ test("load empty config", async (t) => {
undefined,
undefined,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -130,7 +131,7 @@ test("load empty config", async (t) => {
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -176,11 +177,12 @@ test("loading config saves config", async (t) => {
undefined,
undefined,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -214,11 +216,12 @@ test("load input outside of workspace", async (t) => {
undefined,
"../input",
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
getCachedCodeQL(),
tmpDir,
@@ -254,11 +257,12 @@ test("load non-local input with invalid repo syntax", async (t) => {
undefined,
configFile,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
getCachedCodeQL(),
tmpDir,
@@ -295,11 +299,12 @@ test("load non-existent input", async (t) => {
undefined,
configFile,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
getCachedCodeQL(),
tmpDir,
@@ -402,11 +407,12 @@ test("load non-empty input", async (t) => {
undefined,
configFilePath,
undefined,
undefined,
false,
false,
"my-artifact",
"my-db",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -473,11 +479,12 @@ test("Default queries are used", async (t) => {
undefined,
configFilePath,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -552,11 +559,12 @@ test("Queries can be specified in config file", async (t) => {
undefined,
configFilePath,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -630,11 +638,12 @@ test("Queries from config file can be overridden in workflow file", async (t) =>
undefined,
configFilePath,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -706,11 +715,12 @@ test("Queries in workflow file can be used in tandem with the 'disable default q
undefined,
configFilePath,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -773,11 +783,12 @@ test("Multiple queries can be specified in workflow file, no config file require
undefined,
undefined,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -861,11 +872,12 @@ test("Queries in workflow file can be added to the set of queries without overri
undefined,
configFilePath,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -913,6 +925,181 @@ test("Queries in workflow file can be added to the set of queries without overri
});
});
test("Queries can be specified using config input", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
const configInput = `
name: my config
queries:
- uses: ./foo
packs:
javascript:
- a/b@1.2.3
python:
- c/d@1.2.3
`;
fs.mkdirSync(path.join(tmpDir, "foo"));
const resolveQueriesArgs: Array<{
queries: string[];
extraSearchPath: string | undefined;
}> = [];
const codeQL = setCodeQL({
async resolveQueries(
queries: string[],
extraSearchPath: string | undefined
) {
resolveQueriesArgs.push({ queries, extraSearchPath });
return queriesToResolvedQueryForm(queries);
},
async packDownload(): Promise<PackDownloadOutput> {
return { packs: [] };
},
});
// Only JS, python packs will be ignored
const languages = "javascript";
const config = await configUtils.initConfig(
languages,
undefined,
undefined,
undefined,
undefined,
undefined,
configInput,
false,
false,
"",
"",
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
gitHubVersion,
sampleApiDetails,
createFeatures([]),
getRunnerLogger(true)
);
// Check resolveQueries was called correctly
// It'll be called once for the default queries
// and once for `./foo` from the config file.
t.deepEqual(resolveQueriesArgs.length, 2);
t.deepEqual(resolveQueriesArgs[1].queries.length, 1);
t.true(resolveQueriesArgs[1].queries[0].endsWith(`${path.sep}foo`));
t.deepEqual(config.packs as unknown, {
[Language.javascript]: ["a/b@1.2.3"],
});
// Now check that the end result contains the default queries and the query from config
t.deepEqual(config.queries["javascript"].builtin.length, 1);
t.deepEqual(config.queries["javascript"].custom.length, 1);
t.true(
config.queries["javascript"].builtin[0].endsWith(
"javascript-code-scanning.qls"
)
);
t.true(
config.queries["javascript"].custom[0].queries[0].endsWith(
`${path.sep}foo`
)
);
});
});
test("Using config input and file together, config input should be used.", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
process.env["RUNNER_TEMP"] = tmpDir;
process.env["GITHUB_WORKSPACE"] = tmpDir;
const inputFileContents = `
name: my config
queries:
- uses: ./foo_file`;
const configFilePath = createConfigFile(inputFileContents, tmpDir);
const configInput = `
name: my config
queries:
- uses: ./foo
packs:
javascript:
- a/b@1.2.3
python:
- c/d@1.2.3
`;
fs.mkdirSync(path.join(tmpDir, "foo"));
const resolveQueriesArgs: Array<{
queries: string[];
extraSearchPath: string | undefined;
}> = [];
const codeQL = setCodeQL({
async resolveQueries(
queries: string[],
extraSearchPath: string | undefined
) {
resolveQueriesArgs.push({ queries, extraSearchPath });
return queriesToResolvedQueryForm(queries);
},
async packDownload(): Promise<PackDownloadOutput> {
return { packs: [] };
},
});
// Only JS, python packs will be ignored
const languages = "javascript";
const config = await configUtils.initConfig(
languages,
undefined,
undefined,
undefined,
undefined,
configFilePath,
configInput,
false,
false,
"",
"",
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
gitHubVersion,
sampleApiDetails,
createFeatures([]),
getRunnerLogger(true)
);
// Check resolveQueries was called correctly
// It'll be called once for the default queries
// and once for `./foo` from the config file.
t.deepEqual(resolveQueriesArgs.length, 2);
t.deepEqual(resolveQueriesArgs[1].queries.length, 1);
t.true(resolveQueriesArgs[1].queries[0].endsWith(`${path.sep}foo`));
t.deepEqual(config.packs as unknown, {
[Language.javascript]: ["a/b@1.2.3"],
});
// Now check that the end result contains the default queries and the query from config
t.deepEqual(config.queries["javascript"].builtin.length, 1);
t.deepEqual(config.queries["javascript"].custom.length, 1);
t.true(
config.queries["javascript"].builtin[0].endsWith(
"javascript-code-scanning.qls"
)
);
t.true(
config.queries["javascript"].custom[0].queries[0].endsWith(
`${path.sep}foo`
)
);
});
});
test("Invalid queries in workflow file handled correctly", async (t) => {
return await util.withTmpDir(async (tmpDir) => {
const queries = "foo/bar@v1@v3";
@@ -943,11 +1130,12 @@ test("Invalid queries in workflow file handled correctly", async (t) => {
undefined,
undefined,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -1015,11 +1203,12 @@ test("API client used when reading remote config", async (t) => {
undefined,
configFile,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -1046,11 +1235,12 @@ test("Remote config handles the case where a directory is provided", async (t) =
undefined,
repoReference,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
getCachedCodeQL(),
tmpDir,
@@ -1085,11 +1275,12 @@ test("Invalid format of remote config handled correctly", async (t) => {
undefined,
repoReference,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
getCachedCodeQL(),
tmpDir,
@@ -1128,11 +1319,12 @@ test("No detected languages", async (t) => {
undefined,
undefined,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -1160,11 +1352,12 @@ test("Unknown languages", async (t) => {
undefined,
undefined,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
getCachedCodeQL(),
tmpDir,
@@ -1217,11 +1410,12 @@ test("Config specifies packages", async (t) => {
undefined,
configFile,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -1278,6 +1472,7 @@ test("Config specifies packages for multiple languages", async (t) => {
undefined,
configFile,
undefined,
undefined,
false,
false,
"",
@@ -1350,11 +1545,12 @@ function doInvalidInputTest(
undefined,
configFile,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,
@@ -1934,11 +2130,12 @@ const mlPoweredQueriesMacro = test.macro({
undefined,
undefined,
undefined,
undefined,
false,
false,
"",
"",
{ owner: "github", repo: "example " },
{ owner: "github", repo: "example" },
tmpDir,
codeQL,
tmpDir,

View File

@@ -1690,6 +1690,7 @@ export async function initConfig(
registriesInput: string | undefined,
configFile: string | undefined,
dbLocation: string | undefined,
configInput: string | undefined,
trapCachingEnabled: boolean,
debugMode: boolean,
debugArtifactName: string,
@@ -1705,6 +1706,18 @@ export async function initConfig(
): Promise<Config> {
let config: Config;
// if configInput is set, it takes precedence over configFile
if (configInput) {
if (configFile) {
logger.warning(
`Both a config file and config input were provided. Ignoring config file.`
);
}
configFile = path.resolve(workspacePath, "user-config-from-action.yml");
fs.writeFileSync(configFile, configInput);
logger.debug(`Using config from action input: ${configFile}`);
}
// If no config file was provided create an empty one
if (!configFile) {
logger.debug("No configuration file was provided");

View File

@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-20230414",
"cliVersion": "2.13.0",
"priorBundleVersion": "codeql-bundle-20230403",
"priorCliVersion": "2.12.6"
"bundleVersion": "codeql-bundle-20230428",
"cliVersion": "2.13.1",
"priorBundleVersion": "codeql-bundle-20230414",
"priorCliVersion": "2.13.0"
}

View File

@@ -43,6 +43,7 @@ export enum Feature {
ExportDiagnosticsEnabled = "export_diagnostics_enabled",
MlPoweredQueriesEnabled = "ml_powered_queries_enabled",
UploadFailedSarifEnabled = "upload_failed_sarif_enabled",
DisablePythonDependencyInstallation = "disable_python_dependency_installation",
}
export const featureConfig: Record<
@@ -80,6 +81,16 @@ export const featureConfig: Record<
minimumVersion: "2.11.3",
defaultValue: true,
},
[Feature.DisablePythonDependencyInstallation]: {
envVar: "CODEQL_ACTION_DISABLE_PYTHON_DEPENDENCY_INSTALLATION",
// Although the python extractor only started supporting not extracting installed
// dependencies in 2.13.1, the init-action can still benefit from not installing
// dependencies no matter what codeql version we are using, so therefore the
// minimumVersion is set to 'undefined'. This means that with an old CodeQL version,
// packages available with current python3 installation might get extracted.
minimumVersion: undefined,
defaultValue: false,
},
};
/**

View File

@@ -254,6 +254,7 @@ async function run() {
registriesInput,
getOptionalInput("config-file"),
getOptionalInput("db-location"),
getOptionalInput("config"),
getTrapCachingEnabled(),
// Debug mode is enabled if:
// - The `init` Action is passed `debug: true`.
@@ -276,13 +277,22 @@ async function run() {
config.languages.includes(Language.python) &&
getRequiredInput("setup-python-dependencies") === "true"
) {
try {
await installPythonDeps(codeql, logger);
} catch (unwrappedError) {
const error = wrapError(unwrappedError);
logger.warning(
`${error.message} You can call this action with 'setup-python-dependencies: false' to disable this process`
);
if (
await features.getValue(
Feature.DisablePythonDependencyInstallation,
codeql
)
) {
logger.info("Skipping python dependency installation");
} else {
try {
await installPythonDeps(codeql, logger);
} catch (unwrappedError) {
const error = wrapError(unwrappedError);
logger.warning(
`${error.message} You can call this action with 'setup-python-dependencies: false' to disable this process`
);
}
}
}
} catch (unwrappedError) {
@@ -330,6 +340,19 @@ async function run() {
core.exportVariable("CODEQL_EXTRACTOR_JAVA_AGENT_DISABLE_KOTLIN", "true");
}
// Disable Python dependency extraction if feature flag set
if (
await features.getValue(
Feature.DisablePythonDependencyInstallation,
codeql
)
) {
core.exportVariable(
"CODEQL_EXTRACTOR_PYTHON_DISABLE_LIBRARY_EXTRACTION",
"true"
);
}
const sourceRoot = path.resolve(
getRequiredEnvParam("GITHUB_WORKSPACE"),
getOptionalInput("source-root") || ""

View File

@@ -57,6 +57,7 @@ export async function initConfig(
registriesInput: string | undefined,
configFile: string | undefined,
dbLocation: string | undefined,
configInput: string | undefined,
trapCachingEnabled: boolean,
debugMode: boolean,
debugArtifactName: string,
@@ -78,6 +79,7 @@ export async function initConfig(
registriesInput,
configFile,
dbLocation,
configInput,
trapCachingEnabled,
debugMode,
debugArtifactName,
@@ -107,7 +109,6 @@ export async function runInit(
logger: Logger
): Promise<TracerConfig | undefined> {
fs.mkdirSync(config.dbLocation, { recursive: true });
try {
// When parsing the codeql config in the CLI, we have not yet created the qlconfig file.
// So, create it now.

View File

@@ -1,5 +1,5 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$schema": "https://json-schema.org/draft/2020-12/schema",
"title": "Static Analysis Results Format (SARIF) Version 2.1.0 JSON Schema",
"$id": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
"description": "Static Analysis Results Format (SARIF) Version 2.1.0 JSON Schema: a standard format for the output of static analysis tools.",
@@ -15,13 +15,15 @@
"version": {
"description": "The SARIF format version of this log file.",
"enum": [ "2.1.0" ]
"enum": [ "2.1.0" ],
"type": "string"
},
"runs": {
"description": "The set of runs contained in this log file.",
"type": "array",
"type": [ "array", "null" ],
"minItems": 0,
"uniqueItems": false,
"items": {
"$ref": "#/definitions/run"
}
@@ -180,7 +182,8 @@
"userSpecifiedConfiguration",
"toolSpecifiedConfiguration",
"debugOutputFile"
]
],
"type": "string"
}
},
@@ -241,6 +244,7 @@
"description": "An array of replacement objects, each of which represents the replacement of a single region in a single artifact specified by 'artifactLocation'.",
"type": "array",
"minItems": 1,
"uniqueItems": false,
"items": {
"$ref": "#/definitions/replacement"
}
@@ -382,6 +386,7 @@
"description": "An array of one or more unique threadFlow objects, each of which describes the progress of a program through a thread of execution.",
"type": "array",
"minItems": 1,
"uniqueItems": false,
"items": {
"$ref": "#/definitions/threadFlow"
}
@@ -556,6 +561,7 @@
"description": "An array of exception objects each of which is considered a cause of this exception.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/exception"
@@ -583,17 +589,18 @@
"version": {
"description": "The SARIF format version of this external properties object.",
"enum": [ "2.1.0" ]
"enum": [ "2.1.0" ],
"type": "string"
},
"guid": {
"description": "A stable, unique identifer for this external properties object, in the form of a GUID.",
"description": "A stable, unique identifier for this external properties object, in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
"runGuid": {
"description": "A stable, unique identifer for the run associated with this external properties object, in the form of a GUID.",
"description": "A stable, unique identifier for the run associated with this external properties object, in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
@@ -633,6 +640,7 @@
"description": "Describes the invocation of the analysis tool that will be merged with a separate run.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/invocation"
@@ -665,6 +673,7 @@
"description": "An array of result objects that will be merged with a separate run.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/result"
@@ -724,6 +733,7 @@
"description": "Addresses that will be merged with a separate run.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/address"
@@ -771,7 +781,7 @@
},
"guid": {
"description": "A stable, unique identifer for the external property file in the form of a GUID.",
"description": "A stable, unique identifier for the external property file in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
@@ -1079,6 +1089,7 @@
"description": "The sequences of edges traversed by this graph traversal.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/edgeTraversal"
@@ -1111,6 +1122,7 @@
"description": "An array of strings, containing in order the command line arguments passed to the tool from the operating system.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"items": {
"type": "string"
}
@@ -1127,13 +1139,13 @@
},
"startTimeUtc": {
"description": "The Coordinated Universal Time (UTC) date and time at which the run started. See \"Date/time properties\" in the SARIF spec for the required format.",
"description": "The Coordinated Universal Time (UTC) date and time at which the invocation started. See \"Date/time properties\" in the SARIF spec for the required format.",
"type": "string",
"format": "date-time"
},
"endTimeUtc": {
"description": "The Coordinated Universal Time (UTC) date and time at which the run ended. See \"Date/time properties\" in the SARIF spec for the required format.",
"description": "The Coordinated Universal Time (UTC) date and time at which the invocation ended. See \"Date/time properties\" in the SARIF spec for the required format.",
"type": "string",
"format": "date-time"
},
@@ -1169,6 +1181,7 @@
"description": "A list of runtime conditions detected by the tool during the analysis.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/notification"
@@ -1179,6 +1192,7 @@
"description": "A list of conditions detected by the tool that are relevant to the tool's configuration.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/notification"
@@ -1211,27 +1225,27 @@
},
"machine": {
"description": "The machine that hosted the analysis tool run.",
"description": "The machine on which the invocation occurred.",
"type": "string"
},
"account": {
"description": "The account that ran the analysis tool.",
"description": "The account under which the invocation occurred.",
"type": "string"
},
"processId": {
"description": "The process id for the analysis tool run.",
"description": "The id of the process in which the invocation occurred.",
"type": "integer"
},
"executableLocation": {
"description": "An absolute URI specifying the location of the analysis tool's executable.",
"description": "An absolute URI specifying the location of the executable that was invoked.",
"$ref": "#/definitions/artifactLocation"
},
"workingDirectory": {
"description": "The working directory for the analysis tool run.",
"description": "The working directory for the invocation.",
"$ref": "#/definitions/artifactLocation"
},
@@ -1442,6 +1456,7 @@
"description": "An array of strings to substitute into the message string.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"type": "string"
@@ -1551,7 +1566,8 @@
"level": {
"description": "A value specifying the severity level of the notification.",
"default": "warning",
"enum": [ "none", "note", "warning", "error" ]
"enum": [ "none", "note", "warning", "error" ],
"type": "string"
},
"threadId": {
@@ -1762,7 +1778,13 @@
"properties": {
"description": "Key/value pairs that provide additional information about the region.",
"$ref": "#/definitions/propertyBag"
}
},
"anyOf": [
{ "required": [ "startLine" ] },
{ "required": [ "charOffset" ] },
{ "required": [ "byteOffset" ] }
]
}
},
@@ -1813,7 +1835,7 @@
},
"guid": {
"description": "A unique identifer for the reporting descriptor in the form of a GUID.",
"description": "A unique identifier for the reporting descriptor in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
@@ -1912,7 +1934,8 @@
"level": {
"description": "Specifies the failure level for the report.",
"default": "warning",
"enum": [ "none", "note", "warning", "error" ]
"enum": [ "none", "note", "warning", "error" ],
"type": "string"
},
"rank": {
@@ -2017,7 +2040,7 @@
"properties": {
"ruleId": {
"description": "The stable, unique identifier of the rule, if any, to which this notification is relevant. This member can be used to retrieve rule metadata from the rules dictionary, if it exists.",
"description": "The stable, unique identifier of the rule, if any, to which this result is relevant.",
"type": "string"
},
@@ -2036,13 +2059,15 @@
"kind": {
"description": "A value that categorizes results by evaluation state.",
"default": "fail",
"enum": [ "notApplicable", "pass", "fail", "review", "open", "informational" ]
"enum": [ "notApplicable", "pass", "fail", "review", "open", "informational" ],
"type": "string"
},
"level": {
"description": "A value specifying the severity level of the result.",
"default": "warning",
"enum": [ "none", "note", "warning", "error" ]
"enum": [ "none", "note", "warning", "error" ],
"type": "string"
},
"message": {
@@ -2059,6 +2084,7 @@
"description": "The set of locations where the result was detected. Specify only one location unless the problem indicated by the result can only be corrected by making a change at every specified location.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/location"
@@ -2066,7 +2092,7 @@
},
"guid": {
"description": "A stable, unique identifer for the result in the form of a GUID.",
"description": "A stable, unique identifier for the result in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
@@ -2114,6 +2140,7 @@
"description": "An array of 'codeFlow' objects relevant to the result.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/codeFlow"
@@ -2170,7 +2197,8 @@
"unchanged",
"updated",
"absent"
]
],
"type": "string"
},
"rank": {
@@ -2324,6 +2352,7 @@
"description": "Describes the invocation of the analysis tool.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/invocation"
@@ -2341,6 +2370,7 @@
"default": "en-US",
"pattern": "^[a-zA-Z]{2}(-[a-zA-Z]{2})?$"
},
"versionControlProvenance": {
"description": "Specifies the revision in version control of the artifacts that were scanned.",
"type": "array",
@@ -2396,6 +2426,7 @@
"description": "The set of results contained in an SARIF log. The results array can be omitted when a run is solely exporting rules metadata. It must be present (but may be empty) if a log file represents an actual scan.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"items": {
"$ref": "#/definitions/result"
}
@@ -2457,7 +2488,8 @@
"columnKind": {
"description": "Specifies the unit in which the tool measures columns.",
"enum": [ "utf16CodeUnits", "unicodeCodePoints" ]
"enum": [ "utf16CodeUnits", "unicodeCodePoints" ],
"type": "string"
},
"externalPropertyFileReferences": {
@@ -2491,6 +2523,7 @@
"description": "Addresses associated with this run instance, if any.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"$ref": "#/definitions/address"
@@ -2572,7 +2605,7 @@
},
"guid": {
"description": "A stable, unique identifer for this object's containing run object in the form of a GUID.",
"description": "A stable, unique identifier for this object's containing run object in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
@@ -2623,6 +2656,7 @@
"description": "An array of stack frames that represents a sequence of calls, rendered in reverse chronological order, that comprise the call stack.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"items": {
"$ref": "#/definitions/stackFrame"
}
@@ -2661,6 +2695,7 @@
"description": "The parameters of the call that is executing.",
"type": "array",
"minItems": 0,
"uniqueItems": false,
"default": [],
"items": {
"type": "string",
@@ -2682,7 +2717,7 @@
"properties": {
"guid": {
"description": "A stable, unique identifer for the suprression in the form of a GUID.",
"description": "A stable, unique identifier for the suprression in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
@@ -2692,16 +2727,18 @@
"enum": [
"inSource",
"external"
]
],
"type": "string"
},
"state": {
"description": "A string that indicates the state of the suppression.",
"status": {
"description": "A string that indicates the review status of the suppression.",
"enum": [
"accepted",
"underReview",
"rejected"
]
],
"type": "string"
},
"justification": {
@@ -2759,6 +2796,7 @@
"description": "A temporally ordered array of 'threadFlowLocation' objects, each of which describes a location visited by the tool while producing the result.",
"type": "array",
"minItems": 1,
"uniqueItems": false,
"items": {
"$ref": "#/definitions/threadFlowLocation"
}
@@ -2853,7 +2891,8 @@
"importance": {
"description": "Specifies the importance of this location in understanding the code flow in which it occurs. The order from most to least important is \"essential\", \"important\", \"unimportant\". Default: \"important\".",
"enum": [ "important", "essential", "unimportant" ],
"default": "important"
"default": "important",
"type": "string"
},
"webRequest": {
@@ -2911,7 +2950,7 @@
"properties": {
"guid": {
"description": "A unique identifer for the tool component in the form of a GUID.",
"description": "A unique identifier for the tool component in the form of a GUID.",
"type": "string",
"pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[1-5][0-9a-fA-F]{3}-[89abAB][0-9a-fA-F]{3}-[0-9a-fA-F]{12}$"
},
@@ -3051,7 +3090,8 @@
"enum": [
"localizedData",
"nonLocalizedData"
]
],
"type": "string"
}
},

View File

@@ -7,8 +7,19 @@ import * as actionsUtil from "./actions-util";
import * as api from "./api-client";
import { getRunnerLogger } from "./logging";
import * as setupCodeql from "./setup-codeql";
import { setupTests } from "./testing-utils";
import { initializeEnvironment, wrapError } from "./util";
import {
SAMPLE_DEFAULT_CLI_VERSION,
SAMPLE_DOTCOM_API_DETAILS,
mockBundleDownloadApi,
setupActionsVars,
setupTests,
} from "./testing-utils";
import {
GitHubVariant,
initializeEnvironment,
withTmpDir,
wrapError,
} from "./util";
setupTests(test);
@@ -123,3 +134,21 @@ test("findCodeQLBundleTagDotcomOnly() errors if no GitHub Release matches marker
}
);
});
test("getCodeQLSource sets CLI version for a semver tagged bundle", async (t) => {
await withTmpDir(async (tmpDir) => {
setupActionsVars(tmpDir, tmpDir);
const tagName = "codeql-bundle-v1.2.3";
mockBundleDownloadApi({ tagName });
const source = await setupCodeql.getCodeQLSource(
`https://github.com/github/codeql-action/releases/download/${tagName}/codeql-bundle-linux64.tar.gz`,
SAMPLE_DEFAULT_CLI_VERSION,
SAMPLE_DOTCOM_API_DETAILS,
GitHubVariant.DOTCOM,
getRunnerLogger(true)
);
t.is(source.sourceType, "download");
t.is(source["cliVersion"], "1.2.3");
});
});

View File

@@ -400,6 +400,14 @@ export async function getCodeQLSource(
// If a tools URL was provided, then use that.
tagName = tryGetTagNameFromUrl(toolsInput, logger);
url = toolsInput;
if (tagName) {
const bundleVersion = tryGetBundleVersionFromTagName(tagName, logger);
// If the bundle version is a semantic version, it is a CLI version number.
if (bundleVersion && semver.valid(bundleVersion)) {
cliVersion = convertToSemVer(bundleVersion, logger);
}
}
} else {
// Otherwise, use the default CLI version passed in.
cliVersion = defaultCliVersion.cliVersion;

View File

@@ -1,15 +1,32 @@
import { TextDecoder } from "node:util";
import path from "path";
import * as github from "@actions/github";
import { TestFn } from "ava";
import * as nock from "nock";
import nock from "nock";
import * as sinon from "sinon";
import * as apiClient from "./api-client";
import { GitHubApiDetails } from "./api-client";
import * as CodeQL from "./codeql";
import { Feature, FeatureEnablement } from "./feature-flags";
import {
CodeQLDefaultVersionInfo,
Feature,
FeatureEnablement,
} from "./feature-flags";
import { Logger } from "./logging";
import { HTTPError } from "./util";
import { GitHubVariant, HTTPError } from "./util";
export const SAMPLE_DOTCOM_API_DETAILS = {
auth: "token",
url: "https://github.com",
apiURL: "https://api.github.com",
};
export const SAMPLE_DEFAULT_CLI_VERSION: CodeQLDefaultVersionInfo = {
cliVersion: "2.0.0",
variant: GitHubVariant.DOTCOM,
};
type TestContext = {
stdoutWrite: any;
@@ -212,3 +229,49 @@ export function createFeatures(enabledFeatures: Feature[]): FeatureEnablement {
},
};
}
/**
* Mocks the API for downloading the bundle tagged `tagName`.
*
* @returns the download URL for the bundle. This can be passed to the tools parameter of
* `codeql.setupCodeQL`.
*/
export function mockBundleDownloadApi({
apiDetails = SAMPLE_DOTCOM_API_DETAILS,
isPinned,
repo = "github/codeql-action",
platformSpecific = true,
tagName,
}: {
apiDetails?: GitHubApiDetails;
isPinned?: boolean;
repo?: string;
platformSpecific?: boolean;
tagName: string;
}): string {
const platform =
process.platform === "win32"
? "win64"
: process.platform === "linux"
? "linux64"
: "osx64";
const baseUrl = apiDetails?.url ?? "https://example.com";
const relativeUrl = apiDetails
? `/${repo}/releases/download/${tagName}/codeql-bundle${
platformSpecific ? `-${platform}` : ""
}.tar.gz`
: `/download/${tagName}/codeql-bundle.tar.gz`;
nock(baseUrl)
.get(relativeUrl)
.replyWithFile(
200,
path.join(
__dirname,
`/../src/testdata/codeql-bundle${isPinned ? "-pinned" : ""}.tar.gz`
)
);
return `${baseUrl}${relativeUrl}`;
}

View File

@@ -37,7 +37,8 @@ test("validate correct payload used for push, PR merge commit, and PR head", asy
"key",
undefined,
"",
undefined,
1234,
1,
"/opt/src",
undefined,
["CodeQL", "eslint"],
@@ -59,7 +60,8 @@ test("validate correct payload used for push, PR merge commit, and PR head", asy
"key",
undefined,
"",
undefined,
1234,
1,
"/opt/src",
undefined,
["CodeQL", "eslint"],
@@ -75,7 +77,8 @@ test("validate correct payload used for push, PR merge commit, and PR head", asy
"key",
undefined,
"",
undefined,
1234,
1,
"/opt/src",
undefined,
["CodeQL", "eslint"],

Some files were not shown because too many files have changed in this diff Show More