mirror of
https://github.com/github/codeql-action.git
synced 2026-05-25 12:44:37 +00:00
Compare commits
322 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 458d36d7d4 | |||
| 70a1165f9a | |||
| 4b79f1ba10 | |||
| b2dd803f6e | |||
| 0e6a98bb2f | |||
| cb4dbcd837 | |||
| cad7075882 | |||
| 9e0d7b8d25 | |||
| 6d7d59927c | |||
| 51f7e38c69 | |||
| d4b485515e | |||
| 127de8117f | |||
| 7fde13f26a | |||
| dfa61e7305 | |||
| 52aafec073 | |||
| 0d08c01f78 | |||
| 14085a675c | |||
| eb17ca4f4d | |||
| a41c444cd9 | |||
| d7e50c23fe | |||
| bb30f3132d | |||
| 336884853e | |||
| 2f137c9dc6 | |||
| 4795ef8153 | |||
| f0489abddd | |||
| 2e202367c7 | |||
| 9d7243005b | |||
| 237b03b3c3 | |||
| ea37b337cd | |||
| ba0a2f91b7 | |||
| 4041a11865 | |||
| 2a6fe1608c | |||
| 3d6ea97f26 | |||
| 7d25a3e590 | |||
| 4dc72761a6 | |||
| c559992c9e | |||
| 8d217609b0 | |||
| 257b3d3fc8 | |||
| 201a96b541 | |||
| 312a2fee96 | |||
| 2ca0fbdca8 | |||
| 12c1d88854 | |||
| 70419e3273 | |||
| b62aaa99a5 | |||
| 2f2dbd2e78 | |||
| b4ea7aa65a | |||
| 87ac48dae6 | |||
| 42d7f62579 | |||
| 540699dcca | |||
| 9a85234875 | |||
| 2a950b930c | |||
| 4f815a68d3 | |||
| 0aedbb71d8 | |||
| 868e2ea564 | |||
| 792c223bc1 | |||
| 7fd177fa68 | |||
| efc9b0a9e3 | |||
| ea18e99ca3 | |||
| 272ada693f | |||
| 610a6682b6 | |||
| 19f4654991 | |||
| 8f15c6f1ad | |||
| 349cedea3b | |||
| f0ffd5714c | |||
| 1627096569 | |||
| 68bde559de | |||
| 9739ad2d18 | |||
| b81d0d250f | |||
| a16cb53dd8 | |||
| 803d9e8c3c | |||
| 0c80cee806 | |||
| d032ee8c47 | |||
| 0fd9c7d135 | |||
| 922d6fb888 | |||
| df77e87896 | |||
| 6e3f985e4f | |||
| e7a347dfb1 | |||
| 17eabb2500 | |||
| aaef09c48d | |||
| ae1b9155d3 | |||
| 9f82f88f07 | |||
| 7525c68ea1 | |||
| 01bc9be56a | |||
| 9d6b456c59 | |||
| e259d26055 | |||
| 817b68489e | |||
| 1b5632783c | |||
| 1848b73afa | |||
| d1e9792bc8 | |||
| 2c9cd77837 | |||
| b967fdfbdc | |||
| 55d6319f96 | |||
| b0942116d7 | |||
| bc0b696b41 | |||
| a796e3e4ed | |||
| f9bb0e001c | |||
| 4b7faf0b3d | |||
| 09a1d9ec2a | |||
| f64a4491cf | |||
| 7fc86e0c37 | |||
| 5997e25ad9 | |||
| 7587714d0a | |||
| 8ab64a211d | |||
| 0daab03d71 | |||
| a723e99345 | |||
| 30f0c9d081 | |||
| 3530cdd15e | |||
| 8280251823 | |||
| e511c7b2e0 | |||
| 50052a22af | |||
| fbba1e03be | |||
| 933238e8d5 | |||
| e46ed2cbd0 | |||
| b73d1d1634 | |||
| 24e0bb00a9 | |||
| ec298daba7 | |||
| f8b93c30a6 | |||
| 8c6e48dbe0 | |||
| 80a72986d3 | |||
| e9e36aec74 | |||
| 719098349e | |||
| 2bb209555a | |||
| 4ed52dcbfa | |||
| 3cc8dd3e59 | |||
| 7851e55dc3 | |||
| 262a15f6cf | |||
| 022ff3c73f | |||
| 0a4d574ac4 | |||
| d1edf2e4de | |||
| b77983290b | |||
| 549683cee5 | |||
| 7a6ed56219 | |||
| 91fbc51606 | |||
| 35715ef8fe | |||
| 8f02cfa11d | |||
| 0ed734b61b | |||
| efdcb31f11 | |||
| 4d2c7c6e10 | |||
| 70b2658d23 | |||
| 530fcb3bbf | |||
| 2acf81942b | |||
| d2a54a4507 | |||
| bc4097bbe1 | |||
| c8e26e209a | |||
| 0752451507 | |||
| 243c274daf | |||
| 5ded561dcd | |||
| faca00d3ae | |||
| 5d1c58464f | |||
| 1279e8d41c | |||
| af1f613989 | |||
| 5026833be5 | |||
| 201ddc275d | |||
| ce64ddcb0d | |||
| c186c7b484 | |||
| 8bcc8f23a2 | |||
| 834786ac9b | |||
| 047c547345 | |||
| 7ca215887b | |||
| 4ea3a4b4af | |||
| 5c8a8a642e | |||
| 646729a1e2 | |||
| c983cb8e74 | |||
| 557b58c47c | |||
| 8bb5bdb9fd | |||
| 4d2fde9e07 | |||
| 13efb23391 | |||
| b1a5f00cf1 | |||
| 124f6eec3b | |||
| a88fb3cde0 | |||
| 57d591c67c | |||
| dba1849cf2 | |||
| ebcb5b36de | |||
| 97fd992228 | |||
| 95a562052b | |||
| ae8b37eb31 | |||
| d75030c604 | |||
| a777590c0f | |||
| dfad8f8ebc | |||
| c146cd2193 | |||
| 3fef31e9b5 | |||
| 3d7478b23a | |||
| f874badee7 | |||
| 1c3843e226 | |||
| 603b797f8b | |||
| 9ed0d758ce | |||
| 2da877a512 | |||
| 4ccf9a5deb | |||
| e50ab6dc1d | |||
| ee6db5e4f5 | |||
| 820e3160e2 | |||
| dabb34c95a | |||
| c0e7770e36 | |||
| dbc2ac9b7a | |||
| e61b8b4cf5 | |||
| b7ebceaf1a | |||
| ae9ef3a1d2 | |||
| b58ecf644d | |||
| e3632d0ee3 | |||
| cdcb071e67 | |||
| 177cb24be1 | |||
| 2427cfc4a9 | |||
| 45580472a5 | |||
| a3696cdbdf | |||
| 147ec67ee5 | |||
| acb91bd91f | |||
| 88d9aba91d | |||
| 72edeaa05b | |||
| f5c2471be7 | |||
| 70a71a57dd | |||
| 676a1ceb5c | |||
| e127ec2647 | |||
| f5e6f52190 | |||
| e2a90d3e23 | |||
| b5ebac6f4c | |||
| bb159524f9 | |||
| 6b68dd5d27 | |||
| 24e739f51f | |||
| e5a63de15c | |||
| c2d57b0fc7 | |||
| 2588666de8 | |||
| fd13ffa22c | |||
| ce04bc5815 | |||
| 27eb5f56eb | |||
| 44f67f0887 | |||
| 5d24c86a89 | |||
| 439137e1b5 | |||
| f5ab452606 | |||
| 56c8e1c8a8 | |||
| 4f5ca6f9a5 | |||
| 92f3a2822b | |||
| e9bf22fb0e | |||
| 38e701f46e | |||
| c9e0329cc4 | |||
| 9ffacc75e8 | |||
| 21961f3b6f | |||
| 8233700206 | |||
| 23e84a39f0 | |||
| 4bdb89f480 | |||
| ed629463c0 | |||
| 6252d140cd | |||
| 84cf4b44bb | |||
| 52cebb523a | |||
| fc6e643fe1 | |||
| f8ee3fcc9a | |||
| 45c373516f | |||
| 311b632b9d | |||
| d300581d5e | |||
| 7348876640 | |||
| 4f34645a82 | |||
| e7c7a2d323 | |||
| f47c8e6a9b | |||
| 74951318a2 | |||
| 5676d1f64a | |||
| c1bea80e56 | |||
| 2d9c0b97af | |||
| 827017f97b | |||
| bffd034ab1 | |||
| 817dbfb39b | |||
| 793f7006bb | |||
| d2e9832330 | |||
| c2e4b7785f | |||
| 66d7f51a10 | |||
| 497990dfed | |||
| 89cb79a131 | |||
| dbf6819ebd | |||
| 5af51f4048 | |||
| e439418aab | |||
| 249860e323 | |||
| d3ced5c96c | |||
| c12d7c1f2d | |||
| 2e2a1cf1ef | |||
| e2cca77d06 | |||
| 801a18bea6 | |||
| 1c715a714c | |||
| c3d42c5d08 | |||
| 9031cd9330 | |||
| f58938aee2 | |||
| 1f1c162805 | |||
| 7ab96a0e6f | |||
| e3cb86275a | |||
| f94c9befff | |||
| e5971bdba6 | |||
| c5a9d29dc9 | |||
| 9f1109665d | |||
| f8f60f3a2b | |||
| f4d10b9ef7 | |||
| 5d5cd550d3 | |||
| c6eb09db21 | |||
| 09db9044dc | |||
| d3cd47d8d6 | |||
| 8e9caa5100 | |||
| 23a6333b88 | |||
| c503cb4fbb | |||
| c2805e0a04 | |||
| c0d3370b54 | |||
| ddd0dc746a | |||
| 2f607936ce | |||
| 37e7dfbaa0 | |||
| d198d2fabf | |||
| 9e3918e481 | |||
| 7dd1575dac | |||
| 28fc48d83c | |||
| 12c6008004 | |||
| d3019effb0 | |||
| 42213152a8 | |||
| e677e67801 | |||
| 5f3f3164ad | |||
| ba42101490 | |||
| f11af5849b | |||
| ba5430dc86 | |||
| 13e883e119 | |||
| 755f44910c | |||
| 948223fe01 | |||
| a37add20d4 | |||
| ab163cf08b | |||
| 319796f085 | |||
| bd1ac56295 | |||
| a8d1ac45b9 | |||
| c551c50310 | |||
| 01f1a24033 | |||
| b264e15259 |
@@ -16,5 +16,5 @@ inputs:
|
||||
Comma separated list of query ids that should NOT be included in this SARIF file.
|
||||
|
||||
runs:
|
||||
using: node24
|
||||
using: node20
|
||||
main: index.js
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: Verify that the best-effort debug artifact scan completed
|
||||
description: Verifies that the best-effort debug artifact scan completed successfully during tests
|
||||
runs:
|
||||
using: node24
|
||||
using: node20
|
||||
main: index.js
|
||||
post: post.js
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: "CodeQL config"
|
||||
queries:
|
||||
queries:
|
||||
- name: Run custom queries
|
||||
uses: ./queries
|
||||
# Run all extra query suites, both because we want to
|
||||
@@ -13,3 +13,5 @@ queries:
|
||||
paths-ignore:
|
||||
- lib
|
||||
- tests
|
||||
- "**/*.test.ts"
|
||||
- "**/testing-util.ts"
|
||||
|
||||
+1
-1
@@ -59,7 +59,7 @@ jobs:
|
||||
use-all-platform-bundle: 'false'
|
||||
setup-kotlin: 'true'
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@0cb964fd540e0a24c900370abf38a33466142735 # v1.305.0
|
||||
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
- name: Install Code Scanning integration
|
||||
|
||||
@@ -6,13 +6,6 @@ env:
|
||||
# Diff informed queries add an additional query filter which is not yet
|
||||
# taken into account by these tests.
|
||||
CODEQL_ACTION_DIFF_INFORMED_QUERIES: false
|
||||
# Specify overlay enablement manually to ensure stability around the exclude-from-incremental
|
||||
# query filter. Here we only enable for the default code scanning suite.
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS: true
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_JAVASCRIPT: false
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_CODE_SCANNING_JAVASCRIPT: true
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_STATUS_CHECK: false
|
||||
CODEQL_ACTION_OVERLAY_ANALYSIS_SKIP_RESOURCE_CHECKS: true
|
||||
|
||||
on:
|
||||
push:
|
||||
@@ -79,33 +72,13 @@ jobs:
|
||||
with:
|
||||
version: ${{ matrix.version }}
|
||||
|
||||
# On PRs, overlay analysis may change the config that is passed to the CLI.
|
||||
# Therefore, we have two variants of the following test, one for PRs and one for other events.
|
||||
- name: Empty file (non-PR)
|
||||
if: github.event_name != 'pull_request'
|
||||
- name: Empty file
|
||||
uses: ./../action/.github/actions/check-codescanning-config
|
||||
with:
|
||||
expected-config-file-contents: "{}"
|
||||
languages: javascript
|
||||
tools: ${{ steps.prepare-test.outputs.tools-url }}
|
||||
|
||||
- name: Empty file (PR)
|
||||
if: github.event_name == 'pull_request'
|
||||
uses: ./../action/.github/actions/check-codescanning-config
|
||||
with:
|
||||
expected-config-file-contents: |
|
||||
{
|
||||
"query-filters": [
|
||||
{
|
||||
"exclude": {
|
||||
"tags": "exclude-from-incremental"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
languages: javascript
|
||||
tools: ${{ steps.prepare-test.outputs.tools-url }}
|
||||
|
||||
- name: Packs from input
|
||||
if: success() || failure()
|
||||
uses: ./../action/.github/actions/check-codescanning-config
|
||||
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
|
||||
- name: Generate token
|
||||
uses: actions/create-github-app-token@v3.1.1
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||
|
||||
@@ -136,7 +136,7 @@ jobs:
|
||||
|
||||
- name: Generate token
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
uses: actions/create-github-app-token@v3.1.1
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||
|
||||
@@ -93,7 +93,7 @@ jobs:
|
||||
pull-requests: write # needed to create pull request
|
||||
steps:
|
||||
- name: Generate token
|
||||
uses: actions/create-github-app-token@v3.1.1
|
||||
uses: actions/create-github-app-token@v3.2.0
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||
|
||||
Vendored
+1
-1
@@ -19,7 +19,7 @@
|
||||
"scope": "javascript, typescript",
|
||||
"prefix": "testMacro",
|
||||
"body": [
|
||||
"const ${1:nameMacro} = test.macro({",
|
||||
"const ${1:nameMacro} = makeMacro({",
|
||||
" exec: async (t: ExecutionContext<unknown>) => {},",
|
||||
"",
|
||||
" title: (providedTitle = \"\") => `${2:common title} - \\${providedTitle}`,",
|
||||
|
||||
+45
-39
@@ -2,12 +2,26 @@
|
||||
|
||||
See the [releases page](https://github.com/github/codeql-action/releases) for the relevant changes to the CodeQL CLI and language packs.
|
||||
|
||||
## [UNRELEASED]
|
||||
## 3.35.5 - 15 May 2026
|
||||
|
||||
- We have improved how the JavaScript bundles for the CodeQL Action are generated to avoid duplication across bundles and reduce the size of the repository by around 70%. This should have no effect on the runtime behaviour of the CodeQL Action. [#3899](https://github.com/github/codeql-action/pull/3899)
|
||||
- For performance and accuracy reasons, [improved incremental analysis](https://github.com/github/roadmap/issues/1158) will now only be enabled on a pull request when diff-informed analysis is also enabled for that run. If diff-informed analysis is unavailable (for example, because the PR diff ranges could not be computed), the action will fall back to a full analysis. [#3791](https://github.com/github/codeql-action/pull/3791)
|
||||
- If multiple inputs are provided for the GitHub-internal `analysis-kinds` input, only `code-scanning` will be enabled. The `analysis-kinds` input is experimental, for GitHub-internal use only, and may change without notice at any time. [#3892](https://github.com/github/codeql-action/pull/3892)
|
||||
- Added an experimental change which, when running a Code Scanning analysis for a PR with [improved incremental analysis](https://github.com/github/roadmap/issues/1158) enabled, prefers CodeQL CLI versions that have a cached overlay-base database for the configured languages. This speeds up analysis for a repository when there is not yet a cached overlay-base database for the latest CLI version. We expect to roll this change out to everyone in May. [#3880](https://github.com/github/codeql-action/pull/3880)
|
||||
|
||||
## 3.35.4 - 07 May 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.25.4](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.4). [#3881](https://github.com/github/codeql-action/pull/3881)
|
||||
|
||||
## 3.35.3 - 01 May 2026
|
||||
|
||||
- Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. [#3852](https://github.com/github/codeql-action/pull/3852)
|
||||
- _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.19.3 and earlier. These versions of CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise Server 3.15, and will be unsupported by the next minor release of the CodeQL Action. [#3837](https://github.com/github/codeql-action/pull/3837)
|
||||
- Configurations for private registries that use Cloudsmith or GCP OIDC are now accepted. [#3850](https://github.com/github/codeql-action/pull/3850)
|
||||
- Best-effort connection tests for private registries now use `GET` requests instead of `HEAD` for better compatibility with various registry implementations. For NuGet feeds, the test is now always performed against the service index. [#3853](https://github.com/github/codeql-action/pull/3853)
|
||||
- Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. [#3852](https://github.com/github/codeql-action/pull/3852)
|
||||
- Update default CodeQL bundle version to [2.25.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.3). [#3865](https://github.com/github/codeql-action/pull/3865)
|
||||
|
||||
## 4.35.2 - 15 Apr 2026
|
||||
## 3.35.2 - 15 Apr 2026
|
||||
|
||||
- The undocumented TRAP cache cleanup feature that could be enabled using the `CODEQL_ACTION_CLEANUP_TRAP_CACHES` environment variable is deprecated and will be removed in May 2026. If you are affected by this, we recommend disabling TRAP caching by passing the `trap-caching: false` input to the `init` Action. [#3795](https://github.com/github/codeql-action/pull/3795)
|
||||
- The Git version 2.36.0 requirement for improved incremental analysis now only applies to repositories that contain submodules. [#3789](https://github.com/github/codeql-action/pull/3789)
|
||||
@@ -15,29 +29,28 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
||||
- Fixed a bug in the validation of OIDC configurations for private registries that was added in CodeQL Action 4.33.0 / 3.33.0. [#3807](https://github.com/github/codeql-action/pull/3807)
|
||||
- Update default CodeQL bundle version to [2.25.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.2). [#3823](https://github.com/github/codeql-action/pull/3823)
|
||||
|
||||
## 4.35.1 - 27 Mar 2026
|
||||
## 3.35.1 - 27 Mar 2026
|
||||
|
||||
- Fix incorrect minimum required Git version for [improved incremental analysis](https://github.com/github/roadmap/issues/1158): it should have been 2.36.0, not 2.11.0. [#3781](https://github.com/github/codeql-action/pull/3781)
|
||||
|
||||
## 4.35.0 - 27 Mar 2026
|
||||
## 3.35.0 - 27 Mar 2026
|
||||
|
||||
- Reduced the minimum Git version required for [improved incremental analysis](https://github.com/github/roadmap/issues/1158) from 2.38.0 to 2.11.0. [#3767](https://github.com/github/codeql-action/pull/3767)
|
||||
- Update default CodeQL bundle version to [2.25.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.1). [#3773](https://github.com/github/codeql-action/pull/3773)
|
||||
|
||||
## 4.34.1 - 20 Mar 2026
|
||||
## 3.34.1 - 20 Mar 2026
|
||||
|
||||
- Downgrade default CodeQL bundle version to [2.24.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3) due to issues with a small percentage of Actions and JavaScript analyses. [#3762](https://github.com/github/codeql-action/pull/3762)
|
||||
|
||||
## 4.34.0 - 20 Mar 2026
|
||||
## 3.34.0 - 20 Mar 2026
|
||||
|
||||
- Added an experimental change which disables TRAP caching when [improved incremental analysis](https://github.com/github/roadmap/issues/1158) is enabled, since improved incremental analysis supersedes TRAP caching. This will improve performance and reduce Actions cache usage. We expect to roll this change out to everyone in March. [#3569](https://github.com/github/codeql-action/pull/3569)
|
||||
- We are rolling out improved incremental analysis to C/C++ analyses that use build mode `none`. We expect this rollout to be complete by the end of April 2026. [#3584](https://github.com/github/codeql-action/pull/3584)
|
||||
- Update default CodeQL bundle version to [2.25.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.25.0). [#3585](https://github.com/github/codeql-action/pull/3585)
|
||||
|
||||
## 4.33.0 - 16 Mar 2026
|
||||
## 3.33.0 - 16 Mar 2026
|
||||
|
||||
- Upcoming change: Starting April 2026, the CodeQL Action will skip collecting file coverage information on pull requests to improve analysis performance. File coverage information will still be computed on non-PR analyses. Pull request analyses will log a warning about this upcoming change. [#3562](https://github.com/github/codeql-action/pull/3562)
|
||||
|
||||
To opt out of this change:
|
||||
- **Repositories owned by an organization:** Create a custom repository property with the name `github-codeql-file-coverage-on-prs` and the type "True/false", then set this property to `true` in the repository's settings. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization). Alternatively, if you are using an advanced setup workflow, you can set the `CODEQL_ACTION_FILE_COVERAGE_ON_PRS` environment variable to `true` in your workflow.
|
||||
- **User-owned repositories using default setup:** Switch to an advanced setup workflow and set the `CODEQL_ACTION_FILE_COVERAGE_ON_PRS` environment variable to `true` in your workflow.
|
||||
@@ -48,11 +61,11 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
||||
- Fixed the retry mechanism for database uploads. Previously this would fail with the error "Response body object should not be disturbed or locked". [#3564](https://github.com/github/codeql-action/pull/3564)
|
||||
- A warning is now emitted if the CodeQL Action detects a repository property whose name suggests that it relates to the CodeQL Action, but which is not one of the properties recognised by the current version of the CodeQL Action. [#3570](https://github.com/github/codeql-action/pull/3570)
|
||||
|
||||
## 4.32.6 - 05 Mar 2026
|
||||
## 3.32.6 - 05 Mar 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.24.3](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.3). [#3548](https://github.com/github/codeql-action/pull/3548)
|
||||
|
||||
## 4.32.5 - 02 Mar 2026
|
||||
## 3.32.5 - 02 Mar 2026
|
||||
|
||||
- Repositories owned by an organization can now set up the `github-codeql-disable-overlay` custom repository property to disable [improved incremental analysis for CodeQL](https://github.com/github/roadmap/issues/1158). First, create a custom repository property with the name `github-codeql-disable-overlay` and the type "True/false" in the organization's settings. Then in the repository's settings, set this property to `true` to disable improved incremental analysis. For more information, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization). This feature is not yet available on GitHub Enterprise Server. [#3507](https://github.com/github/codeql-action/pull/3507)
|
||||
- Added an experimental change so that when [improved incremental analysis](https://github.com/github/roadmap/issues/1158) fails on a runner — potentially due to insufficient disk space — the failure is recorded in the Actions cache so that subsequent runs will automatically skip improved incremental analysis until something changes (e.g. a larger runner is provisioned or a new CodeQL version is released). We expect to roll this change out to everyone in March. [#3487](https://github.com/github/codeql-action/pull/3487)
|
||||
@@ -62,7 +75,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
||||
- Added an experimental change which allows the `start-proxy` action to resolve the CodeQL CLI version from feature flags instead of using the linked CLI bundle version. We expect to roll this change out to everyone in March. [#3512](https://github.com/github/codeql-action/pull/3512)
|
||||
- The previously experimental changes from versions 4.32.3, 4.32.4, 3.32.3 and 3.32.4 are now enabled by default. [#3503](https://github.com/github/codeql-action/pull/3503), [#3504](https://github.com/github/codeql-action/pull/3504)
|
||||
|
||||
## 4.32.4 - 20 Feb 2026
|
||||
## 3.32.4 - 20 Feb 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.24.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.2). [#3493](https://github.com/github/codeql-action/pull/3493)
|
||||
- Added an experimental change which improves how certificates are generated for the authentication proxy that is used by the CodeQL Action in Default Setup when [private package registries are configured](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries). This is expected to generate more widely compatible certificates and should have no impact on analyses which are working correctly already. We expect to roll this change out to everyone in February. [#3473](https://github.com/github/codeql-action/pull/3473)
|
||||
@@ -70,88 +83,88 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
||||
- Added a setting which allows the CodeQL Action to enable network debugging for Java programs. This will help GitHub staff support customers with troubleshooting issues in GitHub-managed CodeQL workflows, such as Default Setup. This setting can only be enabled by GitHub staff. [#3485](https://github.com/github/codeql-action/pull/3485)
|
||||
- Added a setting which enables GitHub-managed workflows, such as Default Setup, to use a [nightly CodeQL CLI release](https://github.com/dsp-testing/codeql-cli-nightlies) instead of the latest, stable release that is used by default. This will help GitHub staff support customers whose analyses for a given repository or organization require early access to a change in an upcoming CodeQL CLI release. This setting can only be enabled by GitHub staff. [#3484](https://github.com/github/codeql-action/pull/3484)
|
||||
|
||||
## 4.32.3 - 13 Feb 2026
|
||||
## 3.32.3 - 13 Feb 2026
|
||||
|
||||
- Added experimental support for testing connections to [private package registries](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries). This feature is not currently enabled for any analysis. In the future, it may be enabled by default for Default Setup. [#3466](https://github.com/github/codeql-action/pull/3466)
|
||||
|
||||
## 4.32.2 - 05 Feb 2026
|
||||
## 3.32.2 - 05 Feb 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.24.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.1). [#3460](https://github.com/github/codeql-action/pull/3460)
|
||||
|
||||
## 4.32.1 - 02 Feb 2026
|
||||
## 3.32.1 - 02 Feb 2026
|
||||
|
||||
- A warning is now shown in Default Setup workflow logs if a [private package registry is configured](https://docs.github.com/en/code-security/how-tos/secure-at-scale/configure-organization-security/manage-usage-and-access/giving-org-access-private-registries) using a GitHub Personal Access Token (PAT), but no username is configured. [#3422](https://github.com/github/codeql-action/pull/3422)
|
||||
- Fixed a bug which caused the CodeQL Action to fail when repository properties cannot successfully be retrieved. [#3421](https://github.com/github/codeql-action/pull/3421)
|
||||
|
||||
## 4.32.0 - 26 Jan 2026
|
||||
## 3.32.0 - 26 Jan 2026
|
||||
|
||||
- Update default CodeQL bundle version to [2.24.0](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.24.0). [#3425](https://github.com/github/codeql-action/pull/3425)
|
||||
|
||||
## 4.31.11 - 23 Jan 2026
|
||||
## 3.31.11 - 23 Jan 2026
|
||||
|
||||
- When running a Default Setup workflow with [Actions debugging enabled](https://docs.github.com/en/actions/how-tos/monitor-workflows/enable-debug-logging), the CodeQL Action will now use more unique names when uploading logs from the Dependabot authentication proxy as workflow artifacts. This ensures that the artifact names do not clash between multiple jobs in a build matrix. [#3409](https://github.com/github/codeql-action/pull/3409)
|
||||
- Improved error handling throughout the CodeQL Action. [#3415](https://github.com/github/codeql-action/pull/3415)
|
||||
- Added experimental support for automatically excluding [generated files](https://docs.github.com/en/repositories/working-with-files/managing-files/customizing-how-changed-files-appear-on-github) from the analysis. This feature is not currently enabled for any analysis. In the future, it may be enabled by default for some GitHub-managed analyses. [#3318](https://github.com/github/codeql-action/pull/3318)
|
||||
- The changelog extracts that are included with releases of the CodeQL Action are now shorter to avoid duplicated information from appearing in Dependabot PRs. [#3403](https://github.com/github/codeql-action/pull/3403)
|
||||
|
||||
## 4.31.10 - 12 Jan 2026
|
||||
## 3.31.10 - 12 Jan 2026
|
||||
|
||||
- Update default CodeQL bundle version to 2.23.9. [#3393](https://github.com/github/codeql-action/pull/3393)
|
||||
|
||||
## 4.31.9 - 16 Dec 2025
|
||||
## 3.31.9 - 16 Dec 2025
|
||||
|
||||
No user facing changes.
|
||||
|
||||
## 4.31.8 - 11 Dec 2025
|
||||
## 3.31.8 - 11 Dec 2025
|
||||
|
||||
- Update default CodeQL bundle version to 2.23.8. [#3354](https://github.com/github/codeql-action/pull/3354)
|
||||
|
||||
## 4.31.7 - 05 Dec 2025
|
||||
## 3.31.7 - 05 Dec 2025
|
||||
|
||||
- Update default CodeQL bundle version to 2.23.7. [#3343](https://github.com/github/codeql-action/pull/3343)
|
||||
|
||||
## 4.31.6 - 01 Dec 2025
|
||||
## 3.31.6 - 01 Dec 2025
|
||||
|
||||
No user facing changes.
|
||||
|
||||
## 4.31.5 - 24 Nov 2025
|
||||
## 3.31.5 - 24 Nov 2025
|
||||
|
||||
- Update default CodeQL bundle version to 2.23.6. [#3321](https://github.com/github/codeql-action/pull/3321)
|
||||
|
||||
## 4.31.4 - 18 Nov 2025
|
||||
## 3.31.4 - 18 Nov 2025
|
||||
|
||||
No user facing changes.
|
||||
|
||||
## 4.31.3 - 13 Nov 2025
|
||||
## 3.31.3 - 13 Nov 2025
|
||||
|
||||
- CodeQL Action v3 will be deprecated in December 2026. The Action now logs a warning for customers who are running v3 but could be running v4. For more information, see [Upcoming deprecation of CodeQL Action v3](https://github.blog/changelog/2025-10-28-upcoming-deprecation-of-codeql-action-v3/).
|
||||
- Update default CodeQL bundle version to 2.23.5. [#3288](https://github.com/github/codeql-action/pull/3288)
|
||||
|
||||
## 4.31.2 - 30 Oct 2025
|
||||
## 3.31.2 - 30 Oct 2025
|
||||
|
||||
No user facing changes.
|
||||
|
||||
## 4.31.1 - 30 Oct 2025
|
||||
## 3.31.1 - 30 Oct 2025
|
||||
|
||||
- The `add-snippets` input has been removed from the `analyze` action. This input has been deprecated since CodeQL Action 3.26.4 in August 2024 when this removal was announced.
|
||||
|
||||
## 4.31.0 - 24 Oct 2025
|
||||
## 3.31.0 - 24 Oct 2025
|
||||
|
||||
- Bump minimum CodeQL bundle version to 2.17.6. [#3223](https://github.com/github/codeql-action/pull/3223)
|
||||
- When SARIF files are uploaded by the `analyze` or `upload-sarif` actions, the CodeQL Action automatically performs post-processing steps to prepare the data for the upload. Previously, these post-processing steps were only performed before an upload took place. We are now changing this so that the post-processing steps will always be performed, even when the SARIF files are not uploaded. This does not change anything for the `upload-sarif` action. For `analyze`, this may affect Advanced Setup for CodeQL users who specify a value other than `always` for the `upload` input. [#3222](https://github.com/github/codeql-action/pull/3222)
|
||||
|
||||
## 4.30.9 - 17 Oct 2025
|
||||
## 3.30.9 - 17 Oct 2025
|
||||
|
||||
- Update default CodeQL bundle version to 2.23.3. [#3205](https://github.com/github/codeql-action/pull/3205)
|
||||
- Experimental: A new `setup-codeql` action has been added which is similar to `init`, except it only installs the CodeQL CLI and does not initialize a database. Do not use this in production as it is part of an internal experiment and subject to change at any time. [#3204](https://github.com/github/codeql-action/pull/3204)
|
||||
|
||||
## 4.30.8 - 10 Oct 2025
|
||||
## 3.30.8 - 10 Oct 2025
|
||||
|
||||
No user facing changes.
|
||||
|
||||
## 4.30.7 - 06 Oct 2025
|
||||
## 3.30.7 - 06 Oct 2025
|
||||
|
||||
- [v4+ only] The CodeQL Action now runs on Node.js v24. [#3169](https://github.com/github/codeql-action/pull/3169)
|
||||
No user facing changes.
|
||||
|
||||
## 3.30.6 - 02 Oct 2025
|
||||
|
||||
@@ -387,17 +400,13 @@ No user facing changes.
|
||||
## 3.26.12 - 07 Oct 2024
|
||||
|
||||
- _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.14.5 and earlier. These versions of CodeQL were discontinued on 24 September 2024 alongside GitHub Enterprise Server 3.10, and will be unsupported by CodeQL Action versions 3.27.0 and later and versions 2.27.0 and later. [#2520](https://github.com/github/codeql-action/pull/2520)
|
||||
|
||||
- If you are using one of these versions, please update to CodeQL CLI version 2.14.6 or later. For instance, if you have specified a custom version of the CLI using the 'tools' input to the 'init' Action, you can remove this input to use the default version.
|
||||
|
||||
- Alternatively, if you want to continue using a version of the CodeQL CLI between 2.13.5 and 2.14.5, you can replace `github/codeql-action/*@v3` by `github/codeql-action/*@v3.26.11` and `github/codeql-action/*@v2` by `github/codeql-action/*@v2.26.11` in your code scanning workflow to ensure you continue using this version of the CodeQL Action.
|
||||
|
||||
## 3.26.11 - 03 Oct 2024
|
||||
|
||||
- _Upcoming breaking change_: Add support for using `actions/download-artifact@v4` to programmatically consume CodeQL Action debug artifacts.
|
||||
|
||||
Starting November 30, 2024, GitHub.com customers will [no longer be able to use `actions/download-artifact@v3`](https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/). Therefore, to avoid breakage, customers who programmatically download the CodeQL Action debug artifacts should set the `CODEQL_ACTION_ARTIFACT_V4_UPGRADE` environment variable to `true` and bump `actions/download-artifact@v3` to `actions/download-artifact@v4` in their workflows. The CodeQL Action will enable this behavior by default in early November and workflows that have not yet bumped `actions/download-artifact@v3` to `actions/download-artifact@v4` will begin failing then.
|
||||
|
||||
This change is currently unavailable for GitHub Enterprise Server customers, as `actions/upload-artifact@v4` and `actions/download-artifact@v4` are not yet compatible with GHES.
|
||||
- Update default CodeQL bundle version to 2.19.1. [#2519](https://github.com/github/codeql-action/pull/2519)
|
||||
|
||||
@@ -520,12 +529,9 @@ No user facing changes.
|
||||
## 3.25.0 - 15 Apr 2024
|
||||
|
||||
- The deprecated feature for extracting dependencies for a Python analysis has been removed. [#2224](https://github.com/github/codeql-action/pull/2224)
|
||||
|
||||
As a result, the following inputs and environment variables are now ignored:
|
||||
|
||||
- The `setup-python-dependencies` input to the `init` Action
|
||||
- The `CODEQL_ACTION_DISABLE_PYTHON_DEPENDENCY_INSTALLATION` environment variable
|
||||
|
||||
We recommend removing any references to these from your workflows. For more information, see the release notes for CodeQL Action v3.23.0 and v2.23.0.
|
||||
- Automatically overwrite an existing database if found on the filesystem. [#2229](https://github.com/github/codeql-action/pull/2229)
|
||||
- Bump the minimum CodeQL bundle version to 2.12.6. [#2232](https://github.com/github/codeql-action/pull/2232)
|
||||
|
||||
+3
-3
@@ -94,6 +94,6 @@ outputs:
|
||||
sarif-id:
|
||||
description: The ID of the uploaded SARIF file.
|
||||
runs:
|
||||
using: node24
|
||||
main: "../lib/analyze-action.js"
|
||||
post: "../lib/analyze-action-post.js"
|
||||
using: node20
|
||||
main: "../lib/analyze-entry.js"
|
||||
post: "../lib/analyze-post-entry.js"
|
||||
|
||||
@@ -15,5 +15,5 @@ inputs:
|
||||
$GITHUB_WORKSPACE as its working directory.
|
||||
required: false
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/autobuild-action.js'
|
||||
using: node20
|
||||
main: '../lib/autobuild-entry.js'
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { copyFile, rm, writeFile } from "node:fs/promises";
|
||||
import { dirname, join } from "node:path";
|
||||
import { copyFile, readFile, rm, writeFile } from "node:fs/promises";
|
||||
import { basename, dirname, join } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
import * as esbuild from "esbuild";
|
||||
@@ -62,18 +62,123 @@ const onEndPlugin = {
|
||||
},
|
||||
};
|
||||
|
||||
/** The name of the virtual `entry-points` module. */
|
||||
const SHARED_ENTRYPOINT = "entry-points";
|
||||
|
||||
/**
|
||||
* This plugin finds all source files that contain action entry points.
|
||||
* It then generates the virtual `entry-points` module which imports all identifies files,
|
||||
* and re-exports their `runWrapper` functions with suitable aliases.
|
||||
* A tiny stub file is emitted for each Action entrypoint. Each stub imports the shared bundle
|
||||
* and calls the respective entry point.
|
||||
*
|
||||
* @type {esbuild.Plugin}
|
||||
*/
|
||||
const entryPointsPlugin = {
|
||||
name: "entry-points",
|
||||
setup(build) {
|
||||
const namespace = "actions";
|
||||
const actions = [];
|
||||
|
||||
const toPascal = (s) =>
|
||||
s.replace(/(^|-)([a-z0-9])/gi, (_, __, c) => c.toUpperCase());
|
||||
|
||||
// Find the source files containing action entry points.
|
||||
build.onStart(() => {
|
||||
const actionFiles = globSync("src/*-action{,-post}.ts");
|
||||
for (const actionFile of actionFiles) {
|
||||
const match = basename(actionFile).match(/(.*)-action(-post)?/);
|
||||
|
||||
if (match.length < 2) {
|
||||
throw new Error(`'${actionFile}' didn't match expected pattern.`);
|
||||
}
|
||||
|
||||
const actionName = match[1];
|
||||
const isPost = match[2] !== undefined;
|
||||
|
||||
actions.push({
|
||||
path: actionFile,
|
||||
name: actionName,
|
||||
isPost,
|
||||
pascalCaseName: `${toPascal(actionName)}${isPost ? "Post" : ""}Action`,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Resolve the virtual `entry-points` file and set the corresponding namespace.
|
||||
// Ideally, we'd `RegExp.escape` the entrypoint here, but that API isn't supported in Node 20.
|
||||
// Since we're dealing with a hardcoded string, this isn't too much of a problem.
|
||||
build.onResolve({ filter: new RegExp(`^${SHARED_ENTRYPOINT}$`) }, () => {
|
||||
return { path: SHARED_ENTRYPOINT, namespace };
|
||||
});
|
||||
|
||||
// Generate the virtual `entry-points` file based on the actions we discovered.
|
||||
// Restrict using the namespace. The path filter does not need to discriminate any further.
|
||||
build.onLoad({ filter: /.*/, namespace }, async () => {
|
||||
const wrapperTemplatePath = "entry-wrapper.js.tpl";
|
||||
const wrapperTemplate = await readFile(
|
||||
join(SRC_DIR, wrapperTemplatePath),
|
||||
"utf-8",
|
||||
);
|
||||
|
||||
const actionsSorted = actions.sort((a, b) =>
|
||||
a.name.localeCompare(b.name),
|
||||
);
|
||||
const imports = actionsSorted
|
||||
.map(
|
||||
(action) =>
|
||||
`import * as ${action.pascalCaseName} from "./src/${basename(action.path)}"`,
|
||||
)
|
||||
.join("\n");
|
||||
const wrappers = actionsSorted
|
||||
.map((action) =>
|
||||
wrapperTemplate.replaceAll("__ACTION__", action.pascalCaseName),
|
||||
)
|
||||
.join("\n\n");
|
||||
|
||||
return {
|
||||
contents: `"use strict";\n${imports}\n\n${wrappers}\n`,
|
||||
resolveDir: ".",
|
||||
loader: "ts",
|
||||
};
|
||||
});
|
||||
|
||||
// Emit entry point stubs for each action using the entry template.
|
||||
build.onEnd(async (result) => {
|
||||
// Read the entry point template.
|
||||
const templatePath = "action-entry.js.tpl";
|
||||
const template = await readFile(join(SRC_DIR, templatePath), "utf-8");
|
||||
|
||||
const makeHeader = (sourceFile) =>
|
||||
`// Automatically generated from '${templatePath}' for 'src/${basename(sourceFile)}'.\n\n`;
|
||||
|
||||
// Write entry point stubs for each action.
|
||||
for (const action of actions) {
|
||||
await writeFile(
|
||||
join(
|
||||
OUT_DIR,
|
||||
`${action.name}${action.isPost ? "-post" : ""}-entry.js`,
|
||||
),
|
||||
makeHeader(action.path) +
|
||||
template.replaceAll("__ACTION__", action.pascalCaseName),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
const context = await esbuild.context({
|
||||
// Include upload-lib.ts as an entry point for use in testing environments.
|
||||
entryPoints: globSync([
|
||||
`${SRC_DIR}/*-action.ts`,
|
||||
`${SRC_DIR}/*-action-post.ts`,
|
||||
"src/upload-lib.ts",
|
||||
]),
|
||||
entryPoints: [
|
||||
{ in: SHARED_ENTRYPOINT, out: SHARED_ENTRYPOINT },
|
||||
join(SRC_DIR, "upload-lib.ts"),
|
||||
],
|
||||
bundle: true,
|
||||
format: "cjs",
|
||||
outdir: OUT_DIR,
|
||||
platform: "node",
|
||||
plugins: [cleanPlugin, copyDefaultsPlugin, onEndPlugin],
|
||||
external: ["./entry-points"],
|
||||
plugins: [cleanPlugin, copyDefaultsPlugin, entryPointsPlugin, onEndPlugin],
|
||||
target: ["node20"],
|
||||
define: {
|
||||
__CODEQL_ACTION_VERSION__: JSON.stringify(pkg.version),
|
||||
|
||||
+3
-3
@@ -170,6 +170,6 @@ outputs:
|
||||
codeql-version:
|
||||
description: The version of the CodeQL binary used for analysis
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/init-action.js'
|
||||
post: '../lib/init-action-post.js'
|
||||
using: node20
|
||||
main: '../lib/init-entry.js'
|
||||
post: '../lib/init-post-entry.js'
|
||||
|
||||
Generated
-164097
File diff suppressed because one or more lines are too long
Generated
-114006
File diff suppressed because one or more lines are too long
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/analyze-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runAnalyzeAction)();
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/analyze-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runAnalyzePostAction)();
|
||||
Generated
-106399
File diff suppressed because one or more lines are too long
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/autobuild-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runAutobuildAction)();
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"bundleVersion": "codeql-bundle-v2.25.2",
|
||||
"cliVersion": "2.25.2",
|
||||
"priorBundleVersion": "codeql-bundle-v2.25.1",
|
||||
"priorCliVersion": "2.25.1"
|
||||
"bundleVersion": "codeql-bundle-v2.25.4",
|
||||
"cliVersion": "2.25.4",
|
||||
"priorBundleVersion": "codeql-bundle-v2.25.3",
|
||||
"priorCliVersion": "2.25.3"
|
||||
}
|
||||
|
||||
+70222
-80509
File diff suppressed because one or more lines are too long
Generated
-110989
File diff suppressed because one or more lines are too long
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/init-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runInitAction)();
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/init-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runInitPostAction)();
|
||||
Generated
-105958
File diff suppressed because one or more lines are too long
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/resolve-environment-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runResolveEnvironmentAction)();
|
||||
Generated
-107467
File diff suppressed because one or more lines are too long
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/setup-codeql-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runSetupCodeqlAction)();
|
||||
Generated
-162909
File diff suppressed because one or more lines are too long
Generated
-123139
File diff suppressed because one or more lines are too long
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/start-proxy-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runStartProxyAction)();
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/start-proxy-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runStartProxyPostAction)();
|
||||
Generated
+1339
-19276
File diff suppressed because one or more lines are too long
Generated
-162934
File diff suppressed because one or more lines are too long
Generated
-112357
File diff suppressed because one or more lines are too long
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/upload-sarif-action.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runUploadSarifAction)();
|
||||
Generated
+6
@@ -0,0 +1,6 @@
|
||||
// Automatically generated from 'action-entry.js.tpl' for 'src/upload-sarif-action-post.ts'.
|
||||
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.runUploadSarifPostAction)();
|
||||
Generated
+149
-158
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.35.3",
|
||||
"version": "4.35.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "codeql",
|
||||
"version": "4.35.3",
|
||||
"version": "4.35.5",
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
"pr-checks"
|
||||
@@ -43,25 +43,25 @@
|
||||
"@types/archiver": "^7.0.0",
|
||||
"@types/follow-redirects": "^1.14.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^20.19.9",
|
||||
"@types/node": "^20.19.39",
|
||||
"@types/node-forge": "^1.3.14",
|
||||
"@types/sarif": "^2.1.7",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/sinon": "^21.0.1",
|
||||
"ava": "^7.0.0",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-github": "^6.0.0",
|
||||
"eslint-plugin-import-x": "^4.16.2",
|
||||
"eslint-plugin-jsdoc": "^62.9.0",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
"glob": "^11.1.0",
|
||||
"globals": "^17.5.0",
|
||||
"globals": "^17.6.0",
|
||||
"nock": "^14.0.12",
|
||||
"sinon": "^21.1.2",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript-eslint": "^8.58.2"
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.59.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@aashutoshrathi/word-wrap": {
|
||||
@@ -410,15 +410,6 @@
|
||||
"undici": "^6.23.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/github/node_modules/undici": {
|
||||
"version": "6.23.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz",
|
||||
"integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/glob": {
|
||||
"version": "0.5.1",
|
||||
"resolved": "https://registry.npmjs.org/@actions/glob/-/glob-0.5.1.tgz",
|
||||
@@ -439,15 +430,6 @@
|
||||
"undici": "^6.23.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/http-client/node_modules/undici": {
|
||||
"version": "6.23.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.23.0.tgz",
|
||||
"integrity": "sha512-VfQPToRA5FZs/qJxLIinmU59u0r7LXqoJkCzinq3ckNJp3vKEh7jTWN589YQ5+aoAC/TGRLyJLCPKcLQbM8r9g==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/@actions/io": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@actions/io/-/io-2.0.0.tgz",
|
||||
@@ -1355,15 +1337,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/config-array": {
|
||||
"version": "0.21.1",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz",
|
||||
"integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==",
|
||||
"version": "0.21.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz",
|
||||
"integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@eslint/object-schema": "^2.1.7",
|
||||
"debug": "^4.3.1",
|
||||
"minimatch": "^3.1.2"
|
||||
"minimatch": "^3.1.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -1409,20 +1391,20 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/eslintrc": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.3.tgz",
|
||||
"integrity": "sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==",
|
||||
"version": "3.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz",
|
||||
"integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ajv": "^6.12.4",
|
||||
"ajv": "^6.14.0",
|
||||
"debug": "^4.3.2",
|
||||
"espree": "^10.0.1",
|
||||
"globals": "^14.0.0",
|
||||
"ignore": "^5.2.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
"js-yaml": "^4.1.1",
|
||||
"minimatch": "^3.1.2",
|
||||
"minimatch": "^3.1.5",
|
||||
"strip-json-comments": "^3.1.1"
|
||||
},
|
||||
"engines": {
|
||||
@@ -1445,9 +1427,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@eslint/js": {
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.2.tgz",
|
||||
"integrity": "sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==",
|
||||
"version": "9.39.4",
|
||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz",
|
||||
"integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -1494,14 +1476,6 @@
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@fastify/busboy": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
|
||||
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@github/browserslist-config": {
|
||||
"version": "1.0.0",
|
||||
"dev": true,
|
||||
@@ -2495,9 +2469,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.19.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.9.tgz",
|
||||
"integrity": "sha512-cuVNgarYWZqxRJDQHEB58GEONhOK79QVR/qYx4S7kcUObQvUwvFnYxJuuHUKm2aieN9X3yZB4LZsuYNU1Qphsw==",
|
||||
"version": "20.19.39",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.39.tgz",
|
||||
"integrity": "sha512-orrrD74MBUyK8jOAD/r0+lfa1I2MO6I+vAkmAWzMYbCcgrN4lCrmK52gRFQq/JRxfYPfonkr4b0jcY7Olqdqbw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2554,17 +2528,17 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz",
|
||||
"integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.2.tgz",
|
||||
"integrity": "sha512-j/bwmkBvHUtPNxzuWe5z6BEk3q54YRyGlBXkSsmfoih7zNrBvl5A9A98anlp/7JbyZcWIJ8KXo/3Tq/DjFLtuQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.12.2",
|
||||
"@typescript-eslint/scope-manager": "8.58.2",
|
||||
"@typescript-eslint/type-utils": "8.58.2",
|
||||
"@typescript-eslint/utils": "8.58.2",
|
||||
"@typescript-eslint/visitor-keys": "8.58.2",
|
||||
"@typescript-eslint/scope-manager": "8.59.2",
|
||||
"@typescript-eslint/type-utils": "8.59.2",
|
||||
"@typescript-eslint/utils": "8.59.2",
|
||||
"@typescript-eslint/visitor-keys": "8.59.2",
|
||||
"ignore": "^7.0.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
@@ -2577,7 +2551,7 @@
|
||||
"url": "https://opencollective.com/typescript-eslint"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@typescript-eslint/parser": "^8.58.2",
|
||||
"@typescript-eslint/parser": "^8.59.2",
|
||||
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
|
||||
"typescript": ">=4.8.4 <6.1.0"
|
||||
}
|
||||
@@ -2593,16 +2567,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz",
|
||||
"integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.59.2.tgz",
|
||||
"integrity": "sha512-plR3pp6D+SSUn1HM7xvSkx12/DhoHInI2YF35KAcVFNZvlC0gtrWqx7Qq1oH2Ssgi0vlFRCTbP+DZc7B9+TtsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "8.58.2",
|
||||
"@typescript-eslint/types": "8.58.2",
|
||||
"@typescript-eslint/typescript-estree": "8.58.2",
|
||||
"@typescript-eslint/visitor-keys": "8.58.2",
|
||||
"@typescript-eslint/scope-manager": "8.59.2",
|
||||
"@typescript-eslint/types": "8.59.2",
|
||||
"@typescript-eslint/typescript-estree": "8.59.2",
|
||||
"@typescript-eslint/visitor-keys": "8.59.2",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2636,14 +2610,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/project-service": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz",
|
||||
"integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.59.2.tgz",
|
||||
"integrity": "sha512-+2hqvEkeyf/0FBor67duF0Ll7Ot8jyKzDQOSrxazF/danillRq2DwR9dLptsXpoZQqxE1UisSmoZewrlPas9Vw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/tsconfig-utils": "^8.58.2",
|
||||
"@typescript-eslint/types": "^8.58.2",
|
||||
"@typescript-eslint/tsconfig-utils": "^8.59.2",
|
||||
"@typescript-eslint/types": "^8.59.2",
|
||||
"debug": "^4.4.3"
|
||||
},
|
||||
"engines": {
|
||||
@@ -2676,14 +2650,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz",
|
||||
"integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.59.2.tgz",
|
||||
"integrity": "sha512-JzfyEpEtOU89CcFSwyNS3mu4MLvLSXqnmX05+aKBDM+TdR5jzcGOEBwxwGNxrEQ7p/z6kK2WyioCGBf2zZBnvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.58.2",
|
||||
"@typescript-eslint/visitor-keys": "8.58.2"
|
||||
"@typescript-eslint/types": "8.59.2",
|
||||
"@typescript-eslint/visitor-keys": "8.59.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2694,9 +2668,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/tsconfig-utils": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz",
|
||||
"integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.59.2.tgz",
|
||||
"integrity": "sha512-BKK4alN7oi4C/zv4VqHQ+uRU+lTa6JGIZ7s1juw7b3RHo9OfKB+bKX3u0iVZetdsUCBBkSbdWbarJbmN0fTeSw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2711,15 +2685,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz",
|
||||
"integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.59.2.tgz",
|
||||
"integrity": "sha512-nhqaj1nmTdVVl/BP5omXNRGO38jn5iosis2vbdmupF2txCf8ylWT8lx+JlvMYYVqzGVKtjojUFoQ3JRWK+mfzQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.58.2",
|
||||
"@typescript-eslint/typescript-estree": "8.58.2",
|
||||
"@typescript-eslint/utils": "8.58.2",
|
||||
"@typescript-eslint/types": "8.59.2",
|
||||
"@typescript-eslint/typescript-estree": "8.59.2",
|
||||
"@typescript-eslint/utils": "8.59.2",
|
||||
"debug": "^4.4.3",
|
||||
"ts-api-utils": "^2.5.0"
|
||||
},
|
||||
@@ -2754,9 +2728,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz",
|
||||
"integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.59.2.tgz",
|
||||
"integrity": "sha512-e82GVOE8Ps3E++Egvb6Y3Dw0S10u8NkQ9KXmtRhCWJJ8kDhOJTvtMAWnFL16kB1583goCWXsr0NieKCZMs2/0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -2768,16 +2742,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz",
|
||||
"integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.59.2.tgz",
|
||||
"integrity": "sha512-o0XPGNwcWw+FIwStOWn+BwBuEmL6QXP0rsvAFg7ET1dey1Nr6Wb1ac8p5HEsK0ygO/6mUxlk+YWQD9xcb/nnXg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/project-service": "8.58.2",
|
||||
"@typescript-eslint/tsconfig-utils": "8.58.2",
|
||||
"@typescript-eslint/types": "8.58.2",
|
||||
"@typescript-eslint/visitor-keys": "8.58.2",
|
||||
"@typescript-eslint/project-service": "8.59.2",
|
||||
"@typescript-eslint/tsconfig-utils": "8.59.2",
|
||||
"@typescript-eslint/types": "8.59.2",
|
||||
"@typescript-eslint/visitor-keys": "8.59.2",
|
||||
"debug": "^4.4.3",
|
||||
"minimatch": "^10.2.2",
|
||||
"semver": "^7.7.3",
|
||||
@@ -2806,9 +2780,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
|
||||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
|
||||
"integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
|
||||
"version": "5.0.6",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz",
|
||||
"integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2853,16 +2827,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz",
|
||||
"integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.59.2.tgz",
|
||||
"integrity": "sha512-Juw3EinkXqjaffxz6roowvV7GZT/kET5vSKKZT6upl5TXdWkLkYmNPXwDDL2Vkt2DPn0nODIS4egC/0AGxKo/Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.9.1",
|
||||
"@typescript-eslint/scope-manager": "8.58.2",
|
||||
"@typescript-eslint/types": "8.58.2",
|
||||
"@typescript-eslint/typescript-estree": "8.58.2"
|
||||
"@typescript-eslint/scope-manager": "8.59.2",
|
||||
"@typescript-eslint/types": "8.59.2",
|
||||
"@typescript-eslint/typescript-estree": "8.59.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -2877,13 +2851,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz",
|
||||
"integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.59.2.tgz",
|
||||
"integrity": "sha512-NwjLUnGy8/Zfx23fl50tRC8rYaYnM52xNRYFAXvmiil9yh1+K6aRVQMnzW6gQB/1DLgWt977lYQn7C+wtgXZiA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "8.58.2",
|
||||
"@typescript-eslint/types": "8.59.2",
|
||||
"eslint-visitor-keys": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
@@ -3297,7 +3271,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/ajv": {
|
||||
"version": "6.12.6",
|
||||
"version": "6.15.0",
|
||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz",
|
||||
"integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -4751,25 +4727,25 @@
|
||||
}
|
||||
},
|
||||
"node_modules/eslint": {
|
||||
"version": "9.39.2",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.2.tgz",
|
||||
"integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==",
|
||||
"version": "9.39.4",
|
||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz",
|
||||
"integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.8.0",
|
||||
"@eslint-community/regexpp": "^4.12.1",
|
||||
"@eslint/config-array": "^0.21.1",
|
||||
"@eslint/config-array": "^0.21.2",
|
||||
"@eslint/config-helpers": "^0.4.2",
|
||||
"@eslint/core": "^0.17.0",
|
||||
"@eslint/eslintrc": "^3.3.1",
|
||||
"@eslint/js": "9.39.2",
|
||||
"@eslint/eslintrc": "^3.3.5",
|
||||
"@eslint/js": "9.39.4",
|
||||
"@eslint/plugin-kit": "^0.4.1",
|
||||
"@humanfs/node": "^0.16.6",
|
||||
"@humanwhocodes/module-importer": "^1.0.1",
|
||||
"@humanwhocodes/retry": "^0.4.2",
|
||||
"@types/estree": "^1.0.6",
|
||||
"ajv": "^6.12.4",
|
||||
"ajv": "^6.14.0",
|
||||
"chalk": "^4.0.0",
|
||||
"cross-spawn": "^7.0.6",
|
||||
"debug": "^4.3.2",
|
||||
@@ -4788,7 +4764,7 @@
|
||||
"is-glob": "^4.0.0",
|
||||
"json-stable-stringify-without-jsonify": "^1.0.1",
|
||||
"lodash.merge": "^4.6.2",
|
||||
"minimatch": "^3.1.2",
|
||||
"minimatch": "^3.1.5",
|
||||
"natural-compare": "^1.4.0",
|
||||
"optionator": "^0.9.3"
|
||||
},
|
||||
@@ -5694,9 +5670,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fast-xml-builder": {
|
||||
"version": "1.1.5",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz",
|
||||
"integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==",
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.2.0.tgz",
|
||||
"integrity": "sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
@@ -5705,7 +5681,8 @@
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"path-expression-matcher": "^1.1.3"
|
||||
"path-expression-matcher": "^1.5.0",
|
||||
"xml-naming": "^0.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-xml-parser": {
|
||||
@@ -5829,9 +5806,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/flatted": {
|
||||
"version": "3.3.3",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz",
|
||||
"integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz",
|
||||
"integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
@@ -6144,9 +6121,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/globals": {
|
||||
"version": "17.5.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz",
|
||||
"integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==",
|
||||
"version": "17.6.0",
|
||||
"resolved": "https://registry.npmjs.org/globals/-/globals-17.6.0.tgz",
|
||||
"integrity": "sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -7364,9 +7341,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch/node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
|
||||
"integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -7912,9 +7889,9 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
@@ -8087,9 +8064,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/readdir-glob/node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.0.tgz",
|
||||
"integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
@@ -8906,10 +8883,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/supertap/node_modules/js-yaml": {
|
||||
"version": "3.14.1",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz",
|
||||
"integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==",
|
||||
"version": "3.14.2",
|
||||
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz",
|
||||
"integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"argparse": "^1.0.7",
|
||||
"esprima": "^4.0.0"
|
||||
@@ -9797,9 +9775,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.2.tgz",
|
||||
"integrity": "sha512-bGdAIrZ0wiGDo5l8c++HWtbaNCWTS4UTv7RaTH/ThVIgjkveJt83m74bBHMJkuCbslY8ixgLBVZJIOiQlQTjfQ==",
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz",
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
@@ -9811,16 +9789,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/typescript-eslint": {
|
||||
"version": "8.58.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.2.tgz",
|
||||
"integrity": "sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==",
|
||||
"version": "8.59.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.59.2.tgz",
|
||||
"integrity": "sha512-pJw051uomb3ZeCzGTpRb8RbEqB5Y4WWet8gl/GcTlU35BSx0PVdZ86/bqkQCyKKuraVQEK7r6kBHQXF+fBhkoQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "8.58.2",
|
||||
"@typescript-eslint/parser": "8.58.2",
|
||||
"@typescript-eslint/typescript-estree": "8.58.2",
|
||||
"@typescript-eslint/utils": "8.58.2"
|
||||
"@typescript-eslint/eslint-plugin": "8.59.2",
|
||||
"@typescript-eslint/parser": "8.59.2",
|
||||
"@typescript-eslint/typescript-estree": "8.59.2",
|
||||
"@typescript-eslint/utils": "8.59.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||
@@ -9854,14 +9832,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/undici": {
|
||||
"version": "5.29.0",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
|
||||
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
|
||||
"dependencies": {
|
||||
"@fastify/busboy": "^2.0.0"
|
||||
},
|
||||
"version": "6.24.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-6.24.1.tgz",
|
||||
"integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14.0"
|
||||
"node": ">=18.17"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
@@ -10249,6 +10225,21 @@
|
||||
"node": "^20.17.0 || >=22.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/xml-naming": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/xml-naming/-/xml-naming-0.1.0.tgz",
|
||||
"integrity": "sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/NaturalIntelligence"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
@@ -10270,9 +10261,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
|
||||
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
|
||||
"version": "2.8.4",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz",
|
||||
"integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
@@ -10413,10 +10404,10 @@
|
||||
"@octokit/core": "^7.0.6",
|
||||
"@octokit/plugin-paginate-rest": ">=9.2.2",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
||||
"yaml": "^2.8.3"
|
||||
"yaml": "^2.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.19.9",
|
||||
"@types/node": "^20.19.39",
|
||||
"tsx": "^4.21.0"
|
||||
}
|
||||
}
|
||||
|
||||
+9
-9
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"name": "codeql",
|
||||
"version": "4.35.3",
|
||||
"version": "3.35.5",
|
||||
"private": true,
|
||||
"description": "CodeQL action",
|
||||
"scripts": {
|
||||
"_build_comment": "echo 'Run the full build so we typecheck the project and can reuse the transpiled files in npm test'",
|
||||
"build": "./scripts/check-node-modules.sh && npm run transpile && node build.mjs && npx tsx ./pr-checks/bundle-metadata.ts",
|
||||
"build": "./scripts/check-node-modules.sh && npm run transpile && node build.mjs",
|
||||
"lint": "eslint --report-unused-disable-directives --max-warnings=0 .",
|
||||
"lint-ci": "SARIF_ESLINT_IGNORE_SUPPRESSED=true eslint --report-unused-disable-directives --max-warnings=0 . --format @microsoft/eslint-formatter-sarif --output-file=eslint.sarif",
|
||||
"lint-fix": "eslint --report-unused-disable-directives --max-warnings=0 . --fix",
|
||||
@@ -50,25 +50,25 @@
|
||||
"@types/archiver": "^7.0.0",
|
||||
"@types/follow-redirects": "^1.14.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^20.19.9",
|
||||
"@types/node": "^20.19.39",
|
||||
"@types/node-forge": "^1.3.14",
|
||||
"@types/sarif": "^2.1.7",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@types/sinon": "^21.0.1",
|
||||
"ava": "^7.0.0",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^9.39.2",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-import-resolver-typescript": "^4.4.4",
|
||||
"eslint-plugin-github": "^6.0.0",
|
||||
"eslint-plugin-import-x": "^4.16.2",
|
||||
"eslint-plugin-jsdoc": "^62.9.0",
|
||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||
"glob": "^11.1.0",
|
||||
"globals": "^17.5.0",
|
||||
"globals": "^17.6.0",
|
||||
"nock": "^14.0.12",
|
||||
"sinon": "^21.1.2",
|
||||
"typescript": "^6.0.2",
|
||||
"typescript-eslint": "^8.58.2"
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.59.2"
|
||||
},
|
||||
"overrides": {
|
||||
"@actions/tool-cache": {
|
||||
@@ -89,7 +89,7 @@
|
||||
"eslint-plugin-jsx-a11y": {
|
||||
"semver": ">=6.3.1"
|
||||
},
|
||||
"brace-expansion@2.0.1": "2.0.2",
|
||||
"glob": "^11.1.0"
|
||||
"glob": "^11.1.0",
|
||||
"undici": "^6.24.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ versions:
|
||||
- default
|
||||
steps:
|
||||
- name: Set up Ruby
|
||||
uses: ruby/setup-ruby@0cb964fd540e0a24c900370abf38a33466142735 # v1.305.0
|
||||
uses: ruby/setup-ruby@c4e5b1316158f92e3d49443a9d58b31d25ac0f8f # v1.306.0
|
||||
with:
|
||||
ruby-version: 2.6
|
||||
- name: Install Code Scanning integration
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
"@octokit/core": "^7.0.6",
|
||||
"@octokit/plugin-paginate-rest": ">=9.2.2",
|
||||
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
|
||||
"yaml": "^2.8.3"
|
||||
"yaml": "^2.8.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.19.9",
|
||||
"@types/node": "^20.19.39",
|
||||
"tsx": "^4.21.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,5 +21,5 @@ outputs:
|
||||
environment:
|
||||
description: The inferred build environment configuration.
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/resolve-environment-action.js'
|
||||
using: node20
|
||||
main: '../lib/resolve-environment-entry.js'
|
||||
|
||||
+21
-2
@@ -19,6 +19,25 @@ inputs:
|
||||
If not specified, the Action will check in several places until it finds
|
||||
the CodeQL tools.
|
||||
required: false
|
||||
languages:
|
||||
description: >-
|
||||
A comma-separated list of CodeQL languages that will be analyzed in subsequent
|
||||
`github/codeql-action/init` and `github/codeql-action/analyze` invocations. If specified, the
|
||||
Action may use this list to select a CodeQL CLI version that is best suited to analyzing those
|
||||
languages, for example by preferring a version that has a cached overlay-base database for the
|
||||
specified languages. This input is not remembered and must also be passed to
|
||||
`github/codeql-action/init`.
|
||||
required: false
|
||||
analysis-kinds:
|
||||
description: >-
|
||||
[Internal] A comma-separated list of analysis kinds that subsequent
|
||||
`github/codeql-action/init` invocations will enable. If specified, the Action may use this
|
||||
list to select a CodeQL CLI version that is best suited to those analysis kinds. This input is
|
||||
not remembered and must also be passed to `github/codeql-action/init`.
|
||||
|
||||
Available options are the same as for the `analysis-kinds` input on the `init` Action.
|
||||
default: 'code-scanning'
|
||||
required: true
|
||||
token:
|
||||
description: GitHub token to use for authenticating with this instance of GitHub.
|
||||
default: ${{ github.token }}
|
||||
@@ -35,5 +54,5 @@ outputs:
|
||||
codeql-version:
|
||||
description: The version of the CodeQL binary that was installed.
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/setup-codeql-action.js'
|
||||
using: node20
|
||||
main: '../lib/setup-codeql-entry.js'
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
"use strict";
|
||||
|
||||
const import_entry_points = require("./entry-points");
|
||||
void (0, import_entry_points.run__ACTION__)();
|
||||
+54
-9
@@ -16,7 +16,7 @@ import {
|
||||
} from "./analyses";
|
||||
import { EnvVar } from "./environment";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { setupTests } from "./testing-utils";
|
||||
import { createFeatures, RecordingLogger, setupTests } from "./testing-utils";
|
||||
import { AssessmentPayload } from "./upload-lib/types";
|
||||
import { ConfigurationError } from "./util";
|
||||
|
||||
@@ -53,24 +53,56 @@ test("Parsing analysis kinds requires at least one analysis kind", async (t) =>
|
||||
test.serial(
|
||||
"getAnalysisKinds - returns expected analysis kinds for `analysis-kinds` input",
|
||||
async (t) => {
|
||||
process.env[EnvVar.TEST_MODE] = "true";
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns("code-scanning,code-quality");
|
||||
const result = await getAnalysisKinds(getRunnerLogger(true), true);
|
||||
const result = await getAnalysisKinds(
|
||||
getRunnerLogger(true),
|
||||
features,
|
||||
true,
|
||||
);
|
||||
t.assert(result.includes(AnalysisKind.CodeScanning));
|
||||
t.assert(result.includes(AnalysisKind.CodeQuality));
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getAnalysisKinds - only use `code-scanning` for multiple analysis kinds outside of test mode",
|
||||
async (t) => {
|
||||
process.env[EnvVar.TEST_MODE] = "false";
|
||||
const features = createFeatures([]);
|
||||
const logger = new RecordingLogger();
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns("code-scanning,code-quality");
|
||||
const result = await getAnalysisKinds(logger, features, true);
|
||||
t.deepEqual(result, [AnalysisKind.CodeScanning]);
|
||||
t.assert(
|
||||
logger.hasMessage(
|
||||
"Continuing with only `analysis-kinds: code-scanning`.",
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getAnalysisKinds - includes `code-quality` when deprecated `quality-queries` input is used",
|
||||
async (t) => {
|
||||
process.env[EnvVar.TEST_MODE] = "true";
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("analysis-kinds").returns("code-scanning");
|
||||
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
|
||||
optionalInputStub.withArgs("quality-queries").returns("code-quality");
|
||||
const result = await getAnalysisKinds(getRunnerLogger(true), true);
|
||||
const result = await getAnalysisKinds(
|
||||
getRunnerLogger(true),
|
||||
features,
|
||||
true,
|
||||
);
|
||||
t.assert(result.includes(AnalysisKind.CodeScanning));
|
||||
t.assert(result.includes(AnalysisKind.CodeQuality));
|
||||
},
|
||||
@@ -79,9 +111,12 @@ test.serial(
|
||||
test.serial(
|
||||
"getAnalysisKinds - throws if `analysis-kinds` input is invalid",
|
||||
async (t) => {
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub.withArgs("analysis-kinds").returns("no-such-thing");
|
||||
await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true));
|
||||
await t.throwsAsync(
|
||||
getAnalysisKinds(getRunnerLogger(true), features, true),
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -98,11 +133,17 @@ for (let i = 0; i < analysisKinds.length; i++) {
|
||||
test.serial(
|
||||
`getAnalysisKinds - allows ${analysisKind} with ${otherAnalysis}`,
|
||||
async (t) => {
|
||||
process.env[EnvVar.TEST_MODE] = "true";
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns([analysisKind, otherAnalysis].join(","));
|
||||
const result = await getAnalysisKinds(getRunnerLogger(true), true);
|
||||
const result = await getAnalysisKinds(
|
||||
getRunnerLogger(true),
|
||||
features,
|
||||
true,
|
||||
);
|
||||
t.is(result.length, 2);
|
||||
},
|
||||
);
|
||||
@@ -110,14 +151,18 @@ for (let i = 0; i < analysisKinds.length; i++) {
|
||||
test.serial(
|
||||
`getAnalysisKinds - throws if ${analysisKind} is enabled with ${otherAnalysis}`,
|
||||
async (t) => {
|
||||
const features = createFeatures([]);
|
||||
const requiredInputStub = sinon.stub(actionsUtil, "getRequiredInput");
|
||||
requiredInputStub
|
||||
.withArgs("analysis-kinds")
|
||||
.returns([analysisKind, otherAnalysis].join(","));
|
||||
await t.throwsAsync(getAnalysisKinds(getRunnerLogger(true), true), {
|
||||
instanceOf: ConfigurationError,
|
||||
message: `${analysisKind} and ${otherAnalysis} cannot be enabled at the same time`,
|
||||
});
|
||||
await t.throwsAsync(
|
||||
getAnalysisKinds(getRunnerLogger(true), features, true),
|
||||
{
|
||||
instanceOf: ConfigurationError,
|
||||
message: `${analysisKind} and ${otherAnalysis} cannot be enabled at the same time`,
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
+22
-1
@@ -4,13 +4,14 @@ import {
|
||||
getRequiredInput,
|
||||
} from "./actions-util";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import {
|
||||
AssessmentPayload,
|
||||
BasePayload,
|
||||
UploadPayload,
|
||||
} from "./upload-lib/types";
|
||||
import { ConfigurationError, getRequiredEnvParam } from "./util";
|
||||
import { ConfigurationError, getRequiredEnvParam, isInTestMode } from "./util";
|
||||
|
||||
export enum AnalysisKind {
|
||||
CodeScanning = "code-scanning",
|
||||
@@ -77,6 +78,7 @@ let cachedAnalysisKinds: AnalysisKind[] | undefined;
|
||||
*/
|
||||
export async function getAnalysisKinds(
|
||||
logger: Logger,
|
||||
features: FeatureEnablement,
|
||||
skipCache: boolean = false,
|
||||
): Promise<AnalysisKind[]> {
|
||||
if (!skipCache && cachedAnalysisKinds !== undefined) {
|
||||
@@ -120,6 +122,25 @@ export async function getAnalysisKinds(
|
||||
}
|
||||
}
|
||||
|
||||
// Log an error if we have multiple inputs for `analysis-kinds` outside of test mode,
|
||||
// and enable only `code-scanning`.
|
||||
if (
|
||||
!isInTestMode() &&
|
||||
analysisKinds.length > 1 &&
|
||||
!(await features.getValue(Feature.AllowMultipleAnalysisKinds))
|
||||
) {
|
||||
logger.error(
|
||||
"The `analysis-kinds` input is experimental and for GitHub-internal use only. " +
|
||||
"Its behaviour may change at any time or be removed entirely. " +
|
||||
"Specifying multiple values as input is no longer supported. " +
|
||||
"Continuing with only `analysis-kinds: code-scanning`.",
|
||||
);
|
||||
|
||||
// Only enable Code Scanning.
|
||||
cachedAnalysisKinds = [AnalysisKind.CodeScanning];
|
||||
return cachedAnalysisKinds;
|
||||
}
|
||||
|
||||
// Cache the analysis kinds and return them.
|
||||
cachedAnalysisKinds = analysisKinds;
|
||||
return cachedAnalysisKinds;
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as analyze from "./analyze";
|
||||
import { runWrapper } from "./analyze-action";
|
||||
import * as api from "./api-client";
|
||||
import * as configUtils from "./config-utils";
|
||||
import * as gitUtils from "./git-utils";
|
||||
@@ -62,14 +63,8 @@ test("analyze action with RAM & threads from environment variables", async (t) =
|
||||
|
||||
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
|
||||
const runQueriesStub = sinon.stub(analyze, "runQueries");
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const analyzeAction = require("./analyze-action");
|
||||
|
||||
// When analyze-action.ts loads, it runs an async function from the top
|
||||
// level but does not wait for it to finish. To ensure that calls to
|
||||
// runFinalize and runQueries are correctly captured by spies, we explicitly
|
||||
// wait for the action promise to complete before starting verification.
|
||||
await analyzeAction.runPromise;
|
||||
await runWrapper();
|
||||
|
||||
t.assert(
|
||||
runFinalizeStub.calledOnceWith(
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as analyze from "./analyze";
|
||||
import { runWrapper } from "./analyze-action";
|
||||
import * as api from "./api-client";
|
||||
import * as configUtils from "./config-utils";
|
||||
import * as gitUtils from "./git-utils";
|
||||
@@ -60,14 +61,8 @@ test("analyze action with RAM & threads from action inputs", async (t) => {
|
||||
|
||||
const runFinalizeStub = sinon.stub(analyze, "runFinalize");
|
||||
const runQueriesStub = sinon.stub(analyze, "runQueries");
|
||||
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
||||
const analyzeAction = require("./analyze-action");
|
||||
|
||||
// When analyze-action.ts loads, it runs an async function from the top
|
||||
// level but does not wait for it to finish. To ensure that calls to
|
||||
// runFinalize and runQueries are correctly captured by spies, we explicitly
|
||||
// wait for the action promise to complete before starting verification.
|
||||
await analyzeAction.runPromise;
|
||||
await runWrapper();
|
||||
|
||||
t.assert(
|
||||
runFinalizeStub.calledOnceWith(
|
||||
|
||||
@@ -20,7 +20,7 @@ import { EnvVar } from "./environment";
|
||||
import { getActionsLogger } from "./logging";
|
||||
import { checkGitHubVersionInRange, getErrorMessage } from "./util";
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
// To capture errors appropriately, keep as much code within the try-catch as
|
||||
// possible, and only use safe functions outside.
|
||||
|
||||
@@ -72,5 +72,3 @@ async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -523,14 +523,11 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
}
|
||||
|
||||
// Module-level startedAt so it can be accessed by runWrapper for error reporting
|
||||
const startedAt = new Date();
|
||||
export const runPromise = run(startedAt);
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
await runPromise;
|
||||
await run(startedAt);
|
||||
} catch (error) {
|
||||
core.setFailed(`analyze action failed: ${util.getErrorMessage(error)}`);
|
||||
await sendUnhandledErrorStatusReport(
|
||||
@@ -542,5 +539,3 @@ async function runWrapper() {
|
||||
}
|
||||
await util.checkForTimeout();
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+22
-5
@@ -128,6 +128,8 @@ export async function getGitHubVersionFromApi(
|
||||
|
||||
// Doesn't strictly have to be the meta endpoint as we're only
|
||||
// using the response headers which are available on every request.
|
||||
//
|
||||
// See https://docs.github.com/en/rest/meta/meta#get-github-meta-information.
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
|
||||
const response = await apiClient.rest.meta.get();
|
||||
|
||||
@@ -164,6 +166,9 @@ export async function getGitHubVersion(): Promise<GitHubVersion> {
|
||||
|
||||
/**
|
||||
* Get the path of the currently executing workflow relative to the repository root.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/actions/workflow-runs#get-a-workflow-run
|
||||
* and https://docs.github.com/en/rest/actions/workflows#get-a-workflow.
|
||||
*/
|
||||
export async function getWorkflowRelativePath(): Promise<string> {
|
||||
const repo_nwo = getRepositoryNwo();
|
||||
@@ -252,9 +257,13 @@ export interface ActionsCacheItem {
|
||||
size_in_bytes?: number;
|
||||
}
|
||||
|
||||
/** List all Actions cache entries matching the provided key and ref. */
|
||||
/**
|
||||
* List all Actions cache entries starting with the provided key prefix and matching the provided ref.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/actions/cache#list-github-actions-caches-for-a-repository.
|
||||
*/
|
||||
export async function listActionsCaches(
|
||||
key: string,
|
||||
keyPrefix: string,
|
||||
ref?: string,
|
||||
): Promise<ActionsCacheItem[]> {
|
||||
const repositoryNwo = getRepositoryNwo();
|
||||
@@ -264,13 +273,17 @@ export async function listActionsCaches(
|
||||
{
|
||||
owner: repositoryNwo.owner,
|
||||
repo: repositoryNwo.repo,
|
||||
key,
|
||||
key: keyPrefix,
|
||||
ref,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/** Delete an Actions cache item by its ID. */
|
||||
/**
|
||||
* Delete an Actions cache item by its ID.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/actions/cache#delete-a-github-actions-cache-for-a-repository-using-a-cache-id.
|
||||
*/
|
||||
export async function deleteActionsCache(id: number) {
|
||||
const repositoryNwo = getRepositoryNwo();
|
||||
|
||||
@@ -281,7 +294,11 @@ export async function deleteActionsCache(id: number) {
|
||||
});
|
||||
}
|
||||
|
||||
/** Retrieve all custom repository properties. */
|
||||
/**
|
||||
* Retrieve all custom repository properties.
|
||||
*
|
||||
* See https://docs.github.com/en/rest/repos/custom-properties#get-all-custom-property-values-for-a-repository.
|
||||
*/
|
||||
export async function getRepositoryProperties(repositoryNwo: RepositoryNwo) {
|
||||
return getApiClient().request("GET /repos/:owner/:repo/properties/values", {
|
||||
owner: repositoryNwo.owner,
|
||||
|
||||
@@ -141,9 +141,9 @@ test("scanArtifactsForTokens handles files without tokens", async (t) => {
|
||||
}
|
||||
});
|
||||
|
||||
// `scanArchiveFile` does not support Windows, so we skip this test there.
|
||||
if (os.platform() !== "win32") {
|
||||
test("scanArtifactsForTokens finds token in debug artifacts", async (t) => {
|
||||
t.timeout(15000); // 15 seconds
|
||||
const messages: LoggedMessage[] = [];
|
||||
const logger = getRecordingLogger(messages, { logToConsole: false });
|
||||
// The zip here is a regression test based on
|
||||
|
||||
@@ -156,6 +156,10 @@ async function scanArchiveFile(
|
||||
);
|
||||
}
|
||||
|
||||
if (process.platform === "win32") {
|
||||
throw new Error("Scanning archives is not supported on Windows.");
|
||||
}
|
||||
|
||||
const result: ScanResult = {
|
||||
scannedFiles: 0,
|
||||
findings: [],
|
||||
|
||||
@@ -142,7 +142,7 @@ async function run(startedAt: Date) {
|
||||
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
|
||||
}
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -157,5 +157,3 @@ async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+54
-34
@@ -33,6 +33,7 @@ import {
|
||||
mockBundleDownloadApi,
|
||||
makeVersionInfo,
|
||||
createTestConfig,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import { ToolsDownloadStatusReport } from "./tools-download";
|
||||
import * as util from "./util";
|
||||
@@ -70,8 +71,10 @@ async function installIntoToolcache({
|
||||
tmpDir,
|
||||
util.GitHubVariant.GHES,
|
||||
cliVersion !== undefined
|
||||
? { cliVersion, tagName }
|
||||
? { enabledVersions: [{ cliVersion, tagName }] }
|
||||
: SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
createFeatures([]),
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -143,6 +146,8 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -175,6 +180,8 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -214,6 +221,8 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -264,6 +273,8 @@ for (const {
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -284,11 +295,11 @@ for (const {
|
||||
for (const 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.
|
||||
SAMPLE_DEFAULT_CLI_VERSION.cliVersion,
|
||||
`${SAMPLE_DEFAULT_CLI_VERSION.cliVersion}-20230101`,
|
||||
SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion,
|
||||
`${SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion}-20230101`,
|
||||
]) {
|
||||
test.serial(
|
||||
`uses tools from toolcache when ${SAMPLE_DEFAULT_CLI_VERSION.cliVersion} is requested and ` +
|
||||
`uses tools from toolcache when ${SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion} is requested and ` +
|
||||
`${toolcacheVersion} is installed`,
|
||||
async (t) => {
|
||||
const features = createFeatures([]);
|
||||
@@ -308,11 +319,16 @@ for (const toolcacheVersion of [
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
);
|
||||
t.is(result.toolsVersion, SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
|
||||
t.is(
|
||||
result.toolsVersion,
|
||||
SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion,
|
||||
);
|
||||
t.is(result.toolsSource, ToolsSource.Toolcache);
|
||||
t.is(result.toolsDownloadStatusReport?.combinedDurationMs, undefined);
|
||||
t.is(result.toolsDownloadStatusReport?.downloadDurationMs, undefined);
|
||||
@@ -342,9 +358,15 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.GHES,
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
},
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -384,9 +406,15 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.GHES,
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
},
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -426,6 +454,8 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -467,6 +497,8 @@ test.serial(
|
||||
tmpDir,
|
||||
util.GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
getRunnerLogger(true),
|
||||
false,
|
||||
@@ -540,7 +572,7 @@ test.serial("getExtraOptions throws for bad content", (t) => {
|
||||
});
|
||||
|
||||
// Test macro for ensuring different variants of injected augmented configurations
|
||||
const injectedConfigMacro = test.macro({
|
||||
const injectedConfigMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
augmentationProperties: AugmentationProperties,
|
||||
@@ -590,9 +622,8 @@ const injectedConfigMacro = test.macro({
|
||||
`databaseInitCluster() injected config: ${providedTitle}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"basic",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
},
|
||||
@@ -600,9 +631,8 @@ test.serial(
|
||||
{},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected packs from input",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
packsInput: ["xxx", "yyy"],
|
||||
@@ -613,9 +643,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected packs from input with existing packs combines",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
packsInputCombines: true,
|
||||
@@ -635,9 +664,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected packs from input with existing packs overrides",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
packsInput: ["xxx", "yyy"],
|
||||
@@ -655,9 +683,8 @@ test.serial(
|
||||
);
|
||||
|
||||
// similar, but with queries
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected queries from input",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInput: [{ uses: "xxx" }, { uses: "yyy" }],
|
||||
@@ -675,9 +702,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected queries from input overrides",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInput: [{ uses: "xxx" }, { uses: "yyy" }],
|
||||
@@ -699,9 +725,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected queries from input combines",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -727,9 +752,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected queries from input combines 2",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -749,9 +773,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"injected queries and packs, but empty",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -768,9 +791,8 @@ test.serial(
|
||||
{},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"repo property queries have the highest precedence",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
@@ -790,9 +812,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"repo property queries combines with queries input",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: false,
|
||||
@@ -817,9 +838,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
injectedConfigMacro.serial(
|
||||
"repo property queries combines everything else",
|
||||
injectedConfigMacro,
|
||||
{
|
||||
...defaultAugmentationProperties,
|
||||
queriesInputCombines: true,
|
||||
|
||||
@@ -305,6 +305,8 @@ const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
|
||||
* @param tempDir
|
||||
* @param variant
|
||||
* @param defaultCliVersion
|
||||
* @param rawLanguages Raw set of languages.
|
||||
* @param useOverlayAwareDefaultCliVersion Whether to select an overlay-aware default CLI version.
|
||||
* @param features Information about the features that are enabled.
|
||||
* @param logger
|
||||
* @param checkVersion Whether to check that CodeQL CLI meets the minimum
|
||||
@@ -317,6 +319,8 @@ export async function setupCodeQL(
|
||||
tempDir: string,
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
useOverlayAwareDefaultCliVersion: boolean,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
checkVersion: boolean,
|
||||
@@ -340,6 +344,8 @@ export async function setupCodeQL(
|
||||
tempDir,
|
||||
variant,
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
+155
-127
@@ -21,6 +21,7 @@ import { GitVersionInfo } from "./git-utils";
|
||||
import { BuiltInLanguage, Language } from "./languages";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { CODEQL_OVERLAY_MINIMUM_VERSION } from "./overlay";
|
||||
import * as overlayDiagnostics from "./overlay/diagnostics";
|
||||
import { OverlayDisabledReason } from "./overlay/diagnostics";
|
||||
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
|
||||
import * as overlayStatus from "./overlay/status";
|
||||
@@ -34,6 +35,7 @@ import {
|
||||
LoggedMessage,
|
||||
mockCodeQLVersion,
|
||||
createTestConfig,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import {
|
||||
GitHubVariant,
|
||||
@@ -1034,10 +1036,9 @@ const defaultOverlayDatabaseModeTestSetup: OverlayDatabaseModeTestSetup = {
|
||||
repositoryProperties: {},
|
||||
};
|
||||
|
||||
const checkOverlayEnablementMacro = test.macro({
|
||||
const checkOverlayEnablementMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
setupOverrides: Partial<OverlayDatabaseModeTestSetup>,
|
||||
expected:
|
||||
| {
|
||||
@@ -1131,11 +1132,10 @@ const checkOverlayEnablementMacro = test.macro({
|
||||
}
|
||||
});
|
||||
},
|
||||
title: (_, title) => `checkOverlayEnablement: ${title}`,
|
||||
title: (title) => `checkOverlayEnablement: ${title}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Environment variable override - Overlay",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1146,8 +1146,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Environment variable override - OverlayBase",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay-base",
|
||||
@@ -1158,8 +1157,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Environment variable override - None",
|
||||
{
|
||||
overlayDatabaseEnvVar: "none",
|
||||
@@ -1169,8 +1167,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Ignore invalid environment variable",
|
||||
{
|
||||
overlayDatabaseEnvVar: "invalid-mode",
|
||||
@@ -1180,8 +1177,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Ignore feature flag when analyzing non-default branch",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1192,8 +1188,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay-base database on default branch when feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1206,15 +1201,14 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay-base database on default branch when feature enabled with custom analysis",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
} as UserConfig,
|
||||
},
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1223,8 +1217,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay-base database on default branch when code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1240,8 +1233,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch if runner disk space is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1260,8 +1252,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch if we can't determine runner disk space",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1277,8 +1268,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay-base database on default branch if runner disk space is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1299,8 +1289,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch if runner disk space is below v2 limit and v2 resource checks enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1320,8 +1309,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay-base database on default branch if runner disk space is between v2 and v1 limits and v2 resource checks enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1342,8 +1330,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch if runner disk space is between v2 and v1 limits and v2 resource checks not enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1362,8 +1349,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch if memory flag is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1379,8 +1365,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay-base database on default branch if memory flag is too low but CodeQL >= 2.24.3",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1398,8 +1383,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay-base database on default branch if memory flag is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1417,8 +1401,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when cached status indicates previous failure",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1435,8 +1418,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when cached status indicates previous failure",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1453,8 +1435,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with disable-default-queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1464,7 +1445,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"disable-default-queries": true,
|
||||
} as UserConfig,
|
||||
},
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1472,8 +1453,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with packs",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1483,7 +1463,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
} as UserConfig,
|
||||
},
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1491,8 +1471,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1502,7 +1481,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
queries: [{ uses: "some-query.ql" }],
|
||||
} as UserConfig,
|
||||
},
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1510,8 +1489,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when code-scanning feature enabled with query-filters",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1521,7 +1499,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"query-filters": [{ include: { "security-severity": "high" } }],
|
||||
} as UserConfig,
|
||||
},
|
||||
isDefaultBranch: true,
|
||||
},
|
||||
{
|
||||
@@ -1529,8 +1507,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when only language-specific feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1542,8 +1519,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when only code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1555,8 +1531,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay-base database on default branch when language-specific feature disabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1568,8 +1543,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay analysis on PR when feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1582,15 +1556,14 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay analysis on PR when feature enabled with custom analysis",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
features: [Feature.OverlayAnalysis, Feature.OverlayAnalysisJavascript],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
} as UserConfig,
|
||||
},
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1599,8 +1572,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay analysis on PR when code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1616,8 +1588,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR if runner disk space is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1636,8 +1607,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay analysis on PR if runner disk space is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1658,8 +1628,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR if we can't determine runner disk space",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1675,8 +1644,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR if memory flag is too low",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1692,8 +1660,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay analysis on PR if memory flag is too low but CodeQL >= 2.24.3",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1711,8 +1678,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay analysis on PR if memory flag is too low and skip resource checks flag is enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1730,8 +1696,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when code-scanning feature enabled with disable-default-queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1741,7 +1706,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"disable-default-queries": true,
|
||||
} as UserConfig,
|
||||
},
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1749,8 +1714,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when code-scanning feature enabled with packs",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1760,7 +1724,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
packs: ["some-custom-pack@1.0.0"],
|
||||
} as UserConfig,
|
||||
},
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1768,8 +1732,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when code-scanning feature enabled with queries",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1779,7 +1742,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
queries: [{ uses: "some-query.ql" }],
|
||||
} as UserConfig,
|
||||
},
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1787,8 +1750,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when code-scanning feature enabled with query-filters",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1798,7 +1760,7 @@ test.serial(
|
||||
],
|
||||
codeScanningConfig: {
|
||||
"query-filters": [{ include: { "security-severity": "high" } }],
|
||||
} as UserConfig,
|
||||
},
|
||||
isPullRequest: true,
|
||||
},
|
||||
{
|
||||
@@ -1806,8 +1768,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when only language-specific feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1819,8 +1780,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when only code-scanning feature enabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1832,8 +1792,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis on PR when language-specific feature disabled",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1845,8 +1804,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay PR analysis by env",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1857,8 +1815,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay PR analysis by env on a runner with low disk space",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1870,8 +1827,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay PR analysis by feature flag",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1884,8 +1840,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Fallback due to autobuild with traced language",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1897,8 +1852,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Fallback due to no build mode with traced language",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1910,8 +1864,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Fallback due to old CodeQL version",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1922,8 +1875,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Fallback due to missing git root",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1934,8 +1886,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Fallback due to old git version with submodules",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1947,8 +1898,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Fallback when git version cannot be determined and repo has submodules",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1960,8 +1910,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay enabled when git version cannot be determined and repo has no submodules",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -1974,8 +1923,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay when disabled via repository property",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -1990,8 +1938,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Overlay not disabled when repository property is false",
|
||||
{
|
||||
languages: [BuiltInLanguage.javascript],
|
||||
@@ -2007,8 +1954,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"Environment variable override takes precedence over repository property",
|
||||
{
|
||||
overlayDatabaseEnvVar: "overlay",
|
||||
@@ -2024,8 +1970,7 @@ test.serial(
|
||||
|
||||
// Exercise language-specific overlay analysis features code paths
|
||||
for (const language in BuiltInLanguage) {
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
`Check default overlay analysis feature for ${language}`,
|
||||
{
|
||||
languages: [language],
|
||||
@@ -2042,8 +1987,7 @@ for (const language in BuiltInLanguage) {
|
||||
// overlay analysis enabled, even when the base overlay feature flag is on.
|
||||
// Using swift here as it doesn't currently have overlay support — update this if
|
||||
// swift gains overlay support.
|
||||
test.serial(
|
||||
checkOverlayEnablementMacro,
|
||||
checkOverlayEnablementMacro.serial(
|
||||
"No overlay analysis for language without per-language overlay feature flag",
|
||||
{
|
||||
languages: [BuiltInLanguage.swift],
|
||||
@@ -2200,3 +2144,87 @@ test.serial(
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test("applyIncrementalAnalysisSettings: no-op when mode is not Overlay and diff ranges are unavailable", async (t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
false,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.deepEqual(config.extraQueryExclusions, []);
|
||||
});
|
||||
|
||||
test("applyIncrementalAnalysisSettings: keeps overlay mode and adds exclusions when diff ranges are available", async (t) => {
|
||||
const config = createTestConfig({
|
||||
overlayDatabaseMode: OverlayDatabaseMode.Overlay,
|
||||
});
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
true,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.Overlay);
|
||||
t.deepEqual(config.extraQueryExclusions, [
|
||||
{ exclude: { tags: "exclude-from-incremental" } },
|
||||
]);
|
||||
});
|
||||
|
||||
test("applyIncrementalAnalysisSettings: disables overlay analysis when diff ranges are unavailable", async (t) => {
|
||||
const config = createTestConfig({
|
||||
overlayDatabaseMode: OverlayDatabaseMode.Overlay,
|
||||
});
|
||||
config.useOverlayDatabaseCaching = true;
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
const addDiagnosticsStub = sinon
|
||||
.stub(overlayDiagnostics, "addOverlayDisablementDiagnostics")
|
||||
.resolves();
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
false,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.is(config.useOverlayDatabaseCaching, false);
|
||||
t.deepEqual(config.extraQueryExclusions, []);
|
||||
t.true(addDiagnosticsStub.calledOnce);
|
||||
t.is(
|
||||
addDiagnosticsStub.firstCall.args[2],
|
||||
OverlayDisabledReason.DiffInformedAnalysisNotEnabled,
|
||||
);
|
||||
});
|
||||
|
||||
test("applyIncrementalAnalysisSettings: adds exclusions for diff-informed-only runs", async (t) => {
|
||||
const config = createTestConfig({});
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
const codeql = createStubCodeQL({});
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
await configUtils.applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
true,
|
||||
codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(config.overlayDatabaseMode, OverlayDatabaseMode.None);
|
||||
t.deepEqual(config.extraQueryExclusions, [
|
||||
{ exclude: { tags: "exclude-from-incremental" } },
|
||||
]);
|
||||
});
|
||||
|
||||
+56
-13
@@ -31,7 +31,7 @@ import {
|
||||
addNoLanguageDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import { shouldPerformDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
||||
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import * as errorMessages from "./error-messages";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
@@ -407,6 +407,7 @@ export async function getLanguages(
|
||||
return languages;
|
||||
}
|
||||
|
||||
/** Splits the `languages` input into a list of raw languages without checking if they are supported by CodeQL. */
|
||||
export function getRawLanguagesNoAutodetect(
|
||||
languagesInput: string | undefined,
|
||||
): string[] {
|
||||
@@ -1076,6 +1077,48 @@ function hasQueryCustomisation(userConfig: UserConfig): boolean {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Finalize the incremental-analysis configuration for this run.
|
||||
*
|
||||
* Overlay analysis has only been validated in combination with diff-informed
|
||||
* analysis, so if `Overlay` mode was selected for a pull request but the diff
|
||||
* ranges could not be computed, fall back to a full non-overlay analysis.
|
||||
*
|
||||
* Query exclusions for incremental-only queries are then applied whenever the
|
||||
* diff ranges are available — which, after the fallback above, is exactly the
|
||||
* set of runs where any kind of incremental analysis (overlay or
|
||||
* diff-informed) is in effect.
|
||||
*/
|
||||
export async function applyIncrementalAnalysisSettings(
|
||||
config: Config,
|
||||
hasDiffRanges: boolean,
|
||||
codeql: CodeQL,
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
if (
|
||||
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay &&
|
||||
!hasDiffRanges
|
||||
) {
|
||||
logger.info(
|
||||
`Reverting overlay database mode to ${OverlayDatabaseMode.None} ` +
|
||||
"because the PR diff ranges could not be computed.",
|
||||
);
|
||||
config.overlayDatabaseMode = OverlayDatabaseMode.None;
|
||||
config.useOverlayDatabaseCaching = false;
|
||||
await addOverlayDisablementDiagnostics(
|
||||
config,
|
||||
codeql,
|
||||
OverlayDisabledReason.DiffInformedAnalysisNotEnabled,
|
||||
);
|
||||
}
|
||||
|
||||
if (hasDiffRanges) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" },
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load and return the config.
|
||||
*
|
||||
@@ -1230,18 +1273,18 @@ export async function initConfig(
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
config.overlayDatabaseMode === OverlayDatabaseMode.Overlay ||
|
||||
(await shouldPerformDiffInformedAnalysis(
|
||||
inputs.codeql,
|
||||
inputs.features,
|
||||
logger,
|
||||
))
|
||||
) {
|
||||
config.extraQueryExclusions.push({
|
||||
exclude: { tags: "exclude-from-incremental" },
|
||||
});
|
||||
}
|
||||
const hasDiffRanges = await prepareDiffInformedAnalysis(
|
||||
inputs.codeql,
|
||||
inputs.features,
|
||||
logger,
|
||||
);
|
||||
|
||||
await applyIncrementalAnalysisSettings(
|
||||
config,
|
||||
hasDiffRanges,
|
||||
inputs.codeql,
|
||||
logger,
|
||||
);
|
||||
|
||||
if (await isTrapCachingEnabled(features, config.overlayDatabaseMode)) {
|
||||
const { trapCaches, trapCacheDownloadTime } = await downloadCacheWithTime(
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
checkExpectedLogMessages,
|
||||
getRecordingLogger,
|
||||
LoggedMessage,
|
||||
makeMacro,
|
||||
} from "../testing-utils";
|
||||
import { ConfigurationError, prettyPrintPack } from "../util";
|
||||
|
||||
@@ -15,7 +16,7 @@ import * as dbConfig from "./db-config";
|
||||
/**
|
||||
* Test macro for ensuring the packs block is valid
|
||||
*/
|
||||
const parsePacksMacro = test.macro({
|
||||
const parsePacksMacro = makeMacro({
|
||||
exec: (
|
||||
t: ExecutionContext<unknown>,
|
||||
packsInput: string,
|
||||
@@ -33,7 +34,7 @@ const parsePacksMacro = test.macro({
|
||||
/**
|
||||
* Test macro for testing when the packs block is invalid
|
||||
*/
|
||||
const parsePacksErrorMacro = test.macro({
|
||||
const parsePacksErrorMacro = makeMacro({
|
||||
exec: (
|
||||
t: ExecutionContext<unknown>,
|
||||
packsInput: string,
|
||||
@@ -49,34 +50,32 @@ const parsePacksErrorMacro = test.macro({
|
||||
/**
|
||||
* Test macro for testing when the packs block is invalid
|
||||
*/
|
||||
const invalidPackNameMacro = test.macro({
|
||||
exec: (t: ExecutionContext, name: string) =>
|
||||
parsePacksErrorMacro.exec(
|
||||
const invalidPackNameMacro = makeMacro({
|
||||
exec: (t: ExecutionContext, arg: string) =>
|
||||
parsePacksErrorMacro.fn(
|
||||
t,
|
||||
name,
|
||||
arg,
|
||||
[BuiltInLanguage.cpp],
|
||||
new RegExp(`^"${name}" is not a valid pack$`),
|
||||
new RegExp(`^"${arg}" is not a valid pack$`),
|
||||
),
|
||||
title: (_providedTitle: string | undefined, arg: string | undefined) =>
|
||||
`Invalid pack string: ${arg}`,
|
||||
});
|
||||
|
||||
test("no packs", parsePacksMacro, "", [], undefined);
|
||||
test("two packs", parsePacksMacro, "a/b,c/d@1.2.3", [BuiltInLanguage.cpp], {
|
||||
parsePacksMacro("no packs", "", [], undefined);
|
||||
parsePacksMacro("two packs", "a/b,c/d@1.2.3", [BuiltInLanguage.cpp], {
|
||||
[BuiltInLanguage.cpp]: ["a/b", "c/d@1.2.3"],
|
||||
});
|
||||
test(
|
||||
parsePacksMacro(
|
||||
"two packs with spaces",
|
||||
parsePacksMacro,
|
||||
" a/b , c/d@1.2.3 ",
|
||||
[BuiltInLanguage.cpp],
|
||||
{
|
||||
[BuiltInLanguage.cpp]: ["a/b", "c/d@1.2.3"],
|
||||
},
|
||||
);
|
||||
test(
|
||||
parsePacksErrorMacro(
|
||||
"two packs with language",
|
||||
parsePacksErrorMacro,
|
||||
"a/b,c/d@1.2.3",
|
||||
[BuiltInLanguage.cpp, BuiltInLanguage.java],
|
||||
new RegExp(
|
||||
@@ -85,9 +84,8 @@ test(
|
||||
),
|
||||
);
|
||||
|
||||
test(
|
||||
parsePacksMacro(
|
||||
"packs with other valid names",
|
||||
parsePacksMacro,
|
||||
[
|
||||
// ranges are ok
|
||||
"c/d@1.0",
|
||||
@@ -123,23 +121,23 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(invalidPackNameMacro, "c"); // all packs require at least a scope and a name
|
||||
test(invalidPackNameMacro, "c-/d");
|
||||
test(invalidPackNameMacro, "-c/d");
|
||||
test(invalidPackNameMacro, "c/d_d");
|
||||
test(invalidPackNameMacro, "c/d@@");
|
||||
test(invalidPackNameMacro, "c/d@1.0.0:");
|
||||
test(invalidPackNameMacro, "c/d:");
|
||||
test(invalidPackNameMacro, "c/d:/a");
|
||||
test(invalidPackNameMacro, "@1.0.0:a");
|
||||
test(invalidPackNameMacro, "c/d@../a");
|
||||
test(invalidPackNameMacro, "c/d@b/../a");
|
||||
test(invalidPackNameMacro, "c/d:z@1");
|
||||
invalidPackNameMacro.test("c"); // all packs require at least a scope and a name
|
||||
invalidPackNameMacro.test("c-/d");
|
||||
invalidPackNameMacro.test("-c/d");
|
||||
invalidPackNameMacro.test("c/d_d");
|
||||
invalidPackNameMacro.test("c/d@@");
|
||||
invalidPackNameMacro.test("c/d@1.0.0:");
|
||||
invalidPackNameMacro.test("c/d:");
|
||||
invalidPackNameMacro.test("c/d:/a");
|
||||
invalidPackNameMacro.test("@1.0.0:a");
|
||||
invalidPackNameMacro.test("c/d@../a");
|
||||
invalidPackNameMacro.test("c/d@b/../a");
|
||||
invalidPackNameMacro.test("c/d:z@1");
|
||||
|
||||
/**
|
||||
* Test macro for pretty printing pack specs
|
||||
*/
|
||||
const packSpecPrettyPrintingMacro = test.macro({
|
||||
const packSpecPrettyPrintingMacro = makeMacro({
|
||||
exec: (t: ExecutionContext, packStr: string, packObj: dbConfig.Pack) => {
|
||||
const parsed = dbConfig.parsePacksSpecification(packStr);
|
||||
t.deepEqual(parsed, packObj, "parsed pack spec is correct");
|
||||
@@ -163,36 +161,35 @@ const packSpecPrettyPrintingMacro = test.macro({
|
||||
) => `Prettyprint pack spec: '${packStr}'`,
|
||||
});
|
||||
|
||||
test(packSpecPrettyPrintingMacro, "a/b", {
|
||||
packSpecPrettyPrintingMacro.test("a/b", {
|
||||
name: "a/b",
|
||||
version: undefined,
|
||||
path: undefined,
|
||||
});
|
||||
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3", {
|
||||
packSpecPrettyPrintingMacro.test("a/b@~1.2.3", {
|
||||
name: "a/b",
|
||||
version: "~1.2.3",
|
||||
path: undefined,
|
||||
});
|
||||
test(packSpecPrettyPrintingMacro, "a/b@~1.2.3:abc/def", {
|
||||
packSpecPrettyPrintingMacro.test("a/b@~1.2.3:abc/def", {
|
||||
name: "a/b",
|
||||
version: "~1.2.3",
|
||||
path: "abc/def",
|
||||
});
|
||||
test(packSpecPrettyPrintingMacro, "a/b:abc/def", {
|
||||
packSpecPrettyPrintingMacro.test("a/b:abc/def", {
|
||||
name: "a/b",
|
||||
version: undefined,
|
||||
path: "abc/def",
|
||||
});
|
||||
test(packSpecPrettyPrintingMacro, " a/b:abc/def ", {
|
||||
packSpecPrettyPrintingMacro.test(" a/b:abc/def ", {
|
||||
name: "a/b",
|
||||
version: undefined,
|
||||
path: "abc/def",
|
||||
});
|
||||
|
||||
const calculateAugmentationMacro = test.macro({
|
||||
const calculateAugmentationMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
rawPacksInput: string | undefined,
|
||||
rawQueriesInput: string | undefined,
|
||||
languages: Language[],
|
||||
@@ -207,11 +204,10 @@ const calculateAugmentationMacro = test.macro({
|
||||
);
|
||||
t.deepEqual(actualAugmentationProperties, expectedAugmentationProperties);
|
||||
},
|
||||
title: (_, title) => `Calculate Augmentation: ${title}`,
|
||||
title: (title) => `Calculate Augmentation: ${title}`,
|
||||
});
|
||||
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
calculateAugmentationMacro(
|
||||
"All empty",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -222,8 +218,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
calculateAugmentationMacro(
|
||||
"With queries",
|
||||
undefined,
|
||||
" a, b , c, d",
|
||||
@@ -235,8 +230,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
calculateAugmentationMacro(
|
||||
"With queries combining",
|
||||
undefined,
|
||||
" + a, b , c, d ",
|
||||
@@ -249,8 +243,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
calculateAugmentationMacro(
|
||||
"With packs",
|
||||
" codeql/a , codeql/b , codeql/c , codeql/d ",
|
||||
undefined,
|
||||
@@ -262,8 +255,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
calculateAugmentationMacro(
|
||||
"With packs combining",
|
||||
" + codeql/a, codeql/b, codeql/c, codeql/d",
|
||||
undefined,
|
||||
@@ -276,8 +268,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
calculateAugmentationMacro(
|
||||
"With repo property queries",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -294,8 +285,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationMacro,
|
||||
calculateAugmentationMacro(
|
||||
"With repo property queries combining",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -312,10 +302,9 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
const calculateAugmentationErrorMacro = test.macro({
|
||||
const calculateAugmentationErrorMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
rawPacksInput: string | undefined,
|
||||
rawQueriesInput: string | undefined,
|
||||
languages: Language[],
|
||||
@@ -333,11 +322,10 @@ const calculateAugmentationErrorMacro = test.macro({
|
||||
{ message: expectedError },
|
||||
);
|
||||
},
|
||||
title: (_, title) => `Calculate Augmentation Error: ${title}`,
|
||||
title: (title) => `Calculate Augmentation Error: ${title}`,
|
||||
});
|
||||
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
calculateAugmentationErrorMacro(
|
||||
"Plus (+) with nothing else (queries)",
|
||||
undefined,
|
||||
" + ",
|
||||
@@ -346,8 +334,7 @@ test(
|
||||
/The workflow property "queries" is invalid/,
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
calculateAugmentationErrorMacro(
|
||||
"Plus (+) with nothing else (packs)",
|
||||
" + ",
|
||||
undefined,
|
||||
@@ -356,8 +343,7 @@ test(
|
||||
/The workflow property "packs" is invalid/,
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
calculateAugmentationErrorMacro(
|
||||
"Plus (+) with nothing else (repo property queries)",
|
||||
undefined,
|
||||
undefined,
|
||||
@@ -368,8 +354,7 @@ test(
|
||||
/The repository property "github-codeql-extra-queries" is invalid/,
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
calculateAugmentationErrorMacro(
|
||||
"Packs input with multiple languages",
|
||||
" + a/b, c/d ",
|
||||
undefined,
|
||||
@@ -378,8 +363,7 @@ test(
|
||||
/Cannot specify a 'packs' input in a multi-language analysis/,
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
calculateAugmentationErrorMacro(
|
||||
"Packs input with no languages",
|
||||
" + a/b, c/d ",
|
||||
undefined,
|
||||
@@ -388,8 +372,7 @@ test(
|
||||
/No languages specified/,
|
||||
);
|
||||
|
||||
test(
|
||||
calculateAugmentationErrorMacro,
|
||||
calculateAugmentationErrorMacro(
|
||||
"Invalid packs",
|
||||
" a-pack-without-a-scope ",
|
||||
undefined,
|
||||
|
||||
@@ -263,7 +263,7 @@ export function getArtifactSuffix(matrix: string | undefined): string {
|
||||
try {
|
||||
const matrixObject = JSON.parse(matrix);
|
||||
if (json.isObject(matrixObject)) {
|
||||
for (const matrixKey of Object.keys(matrixObject as object).sort())
|
||||
for (const matrixKey of Object.keys(matrixObject).sort())
|
||||
suffix += `-${matrixObject[matrixKey]}`;
|
||||
} else {
|
||||
core.warning("User-specified `matrix` input is not an object.");
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"bundleVersion": "codeql-bundle-v2.25.2",
|
||||
"cliVersion": "2.25.2",
|
||||
"priorBundleVersion": "codeql-bundle-v2.25.1",
|
||||
"priorCliVersion": "2.25.1"
|
||||
"bundleVersion": "codeql-bundle-v2.25.4",
|
||||
"cliVersion": "2.25.4",
|
||||
"priorBundleVersion": "codeql-bundle-v2.25.3",
|
||||
"priorCliVersion": "2.25.3"
|
||||
}
|
||||
|
||||
@@ -5,17 +5,20 @@ import * as actionsUtil from "./actions-util";
|
||||
import type { PullRequestBranches } from "./actions-util";
|
||||
import * as apiClient from "./api-client";
|
||||
import {
|
||||
shouldPerformDiffInformedAnalysis,
|
||||
getDiffInformedAnalysisBranches,
|
||||
prepareDiffInformedAnalysis,
|
||||
exportedForTesting,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { Feature, initFeatures } from "./feature-flags";
|
||||
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { parseRepositoryNwo } from "./repository";
|
||||
import {
|
||||
setupTests,
|
||||
createFeatures,
|
||||
mockCodeQLVersion,
|
||||
mockFeatureFlagApiEndpoint,
|
||||
setupActionsVars,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import { GitHubVariant, withTmpDir } from "./util";
|
||||
import type { GitHubVersion } from "./util";
|
||||
@@ -42,10 +45,9 @@ const defaultTestCase: DiffInformedAnalysisTestCase = {
|
||||
codeQLVersion: "2.21.0",
|
||||
};
|
||||
|
||||
const testShouldPerformDiffInformedAnalysis = test.macro({
|
||||
const testShouldPerformDiffInformedAnalysis = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
partialTestCase: Partial<DiffInformedAnalysisTestCase>,
|
||||
expectedResult: boolean,
|
||||
) => {
|
||||
@@ -80,13 +82,13 @@ const testShouldPerformDiffInformedAnalysis = test.macro({
|
||||
.stub(actionsUtil, "getPullRequestBranches")
|
||||
.returns(testCase.pullRequestBranches);
|
||||
|
||||
const result = await shouldPerformDiffInformedAnalysis(
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.is(result, expectedResult);
|
||||
t.is(branches !== undefined, expectedResult);
|
||||
|
||||
delete process.env.CODEQL_ACTION_DIFF_INFORMED_QUERIES;
|
||||
|
||||
@@ -94,18 +96,16 @@ const testShouldPerformDiffInformedAnalysis = test.macro({
|
||||
getPullRequestBranchesStub.restore();
|
||||
});
|
||||
},
|
||||
title: (_, title) => `shouldPerformDiffInformedAnalysis: ${title}`,
|
||||
title: (title) => `getDiffInformedAnalysisBranches: ${title}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns true in the default test case",
|
||||
{},
|
||||
true,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns false when feature flag is disabled from the API",
|
||||
{
|
||||
featureEnabled: false,
|
||||
@@ -113,8 +113,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns false when CODEQL_ACTION_DIFF_INFORMED_QUERIES is set to false",
|
||||
{
|
||||
featureEnabled: true,
|
||||
@@ -123,8 +122,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns true when CODEQL_ACTION_DIFF_INFORMED_QUERIES is set to true",
|
||||
{
|
||||
featureEnabled: false,
|
||||
@@ -133,8 +131,7 @@ test.serial(
|
||||
true,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns false for CodeQL version 2.20.0",
|
||||
{
|
||||
codeQLVersion: "2.20.0",
|
||||
@@ -142,8 +139,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns false for invalid GHES version",
|
||||
{
|
||||
gitHubVersion: {
|
||||
@@ -154,8 +150,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns false for GHES version 3.18.5",
|
||||
{
|
||||
gitHubVersion: {
|
||||
@@ -166,8 +161,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns true for GHES version 3.19.0",
|
||||
{
|
||||
gitHubVersion: {
|
||||
@@ -178,8 +172,7 @@ test.serial(
|
||||
true,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testShouldPerformDiffInformedAnalysis,
|
||||
testShouldPerformDiffInformedAnalysis.serial(
|
||||
"returns false when not a pull request",
|
||||
{
|
||||
pullRequestBranches: undefined,
|
||||
@@ -187,6 +180,135 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns false when not a pull request",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
const features = createFeatures([Feature.DiffInformedQueries]);
|
||||
|
||||
sinon.stub(actionsUtil, "getPullRequestBranches").returns(undefined);
|
||||
sinon
|
||||
.stub(apiClient, "getGitHubVersion")
|
||||
.resolves({ type: GitHubVariant.DOTCOM });
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.false(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns false when applicability check throws",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
// A features implementation whose getValue rejects, simulating an
|
||||
// unexpected failure when determining whether diff-informed analysis
|
||||
// should run.
|
||||
const features: FeatureEnablement = {
|
||||
getEnabledDefaultCliVersions: async () => {
|
||||
throw new Error("not implemented");
|
||||
},
|
||||
getValue: async () => {
|
||||
throw new Error("feature flag lookup failed");
|
||||
},
|
||||
};
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.false(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns true when the diff is fetched successfully",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
const features = createFeatures([Feature.DiffInformedQueries]);
|
||||
|
||||
sinon
|
||||
.stub(actionsUtil, "getPullRequestBranches")
|
||||
.returns({ base: "main", head: "feature" });
|
||||
sinon
|
||||
.stub(apiClient, "getGitHubVersion")
|
||||
.resolves({ type: GitHubVariant.DOTCOM });
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
sinon.stub(apiClient, "getApiClient").returns({
|
||||
rest: {
|
||||
repos: {
|
||||
compareCommitsWithBasehead: sinon
|
||||
.stub()
|
||||
.resolves({ data: { files: [] } }),
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.true(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"prepareDiffInformedAnalysis: returns false when the diff API call fails",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
const logger = getRunnerLogger(true);
|
||||
const codeql = mockCodeQLVersion("2.21.0");
|
||||
const features = createFeatures([Feature.DiffInformedQueries]);
|
||||
|
||||
sinon
|
||||
.stub(actionsUtil, "getPullRequestBranches")
|
||||
.returns({ base: "main", head: "feature" });
|
||||
sinon
|
||||
.stub(apiClient, "getGitHubVersion")
|
||||
.resolves({ type: GitHubVariant.DOTCOM });
|
||||
const notFoundError: any = new Error("Not Found");
|
||||
notFoundError.status = 404;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
sinon.stub(apiClient, "getApiClient").returns({
|
||||
rest: {
|
||||
repos: {
|
||||
compareCommitsWithBasehead: sinon.stub().rejects(notFoundError),
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
|
||||
const result = await prepareDiffInformedAnalysis(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
t.false(result);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
function runGetDiffRanges(changes: number, patch: string[] | undefined): any {
|
||||
return exportedForTesting.getDiffRanges(
|
||||
{
|
||||
|
||||
@@ -5,9 +5,9 @@ import type { PullRequestBranches } from "./actions-util";
|
||||
import { getApiClient, getGitHubVersion } from "./api-client";
|
||||
import type { CodeQL } from "./codeql";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import { Logger, withGroupAsync } from "./logging";
|
||||
import { getRepositoryNwoFromEnv } from "./repository";
|
||||
import { GitHubVariant, satisfiesGHESVersion } from "./util";
|
||||
import { getErrorMessage, GitHubVariant, satisfiesGHESVersion } from "./util";
|
||||
|
||||
/**
|
||||
* This interface is an abbreviated version of the file diff object returned by
|
||||
@@ -21,20 +21,6 @@ interface FileDiff {
|
||||
patch?: string | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the action should perform diff-informed analysis.
|
||||
*/
|
||||
export async function shouldPerformDiffInformedAnalysis(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
return (
|
||||
(await getDiffInformedAnalysisBranches(codeql, features, logger)) !==
|
||||
undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the branches to use for diff-informed analysis.
|
||||
*
|
||||
@@ -69,6 +55,46 @@ export async function getDiffInformedAnalysisBranches(
|
||||
return branches;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the diff ranges needed for diff-informed analysis for the current
|
||||
* run.
|
||||
*
|
||||
* @returns `true` if the diff ranges were successfully computed and persisted
|
||||
* and are therefore available for use, `false` otherwise.
|
||||
*/
|
||||
export async function prepareDiffInformedAnalysis(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
let branches: PullRequestBranches | undefined;
|
||||
try {
|
||||
branches = await getDiffInformedAnalysisBranches(codeql, features, logger);
|
||||
} catch (e) {
|
||||
// If we cannot determine whether diff-informed analysis applies (for
|
||||
// example, because a feature-flag lookup failed), treat it as not
|
||||
// applicable rather than triggering the overlay fallback.
|
||||
logger.warning(
|
||||
`Failed to determine branch information for diff-informed analysis: ${getErrorMessage(e)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
if (!branches) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return await withGroupAsync("Computing PR diff ranges", async () => {
|
||||
try {
|
||||
return await computeAndPersistDiffRanges(branches, logger);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute diff-informed analysis ranges: ${getErrorMessage(e)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export interface DiffThunkRange {
|
||||
/** Relative path from the repository root, using forward slashes as separators. */
|
||||
path: string;
|
||||
@@ -151,6 +177,33 @@ export async function getPullRequestEditedDiffRanges(
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and persist the diff ranges for a pull request. This fetches the
|
||||
* diff from the GitHub API and writes it to the diff ranges JSON file so that
|
||||
* CodeQL can use it for diff-informed analysis.
|
||||
*
|
||||
* @param branches The base and head branches of the pull request, as returned
|
||||
* by `getDiffInformedAnalysisBranches`.
|
||||
* @param logger
|
||||
* @returns `true` if the diff ranges were successfully computed and persisted,
|
||||
* otherwise `false`.
|
||||
*/
|
||||
export async function computeAndPersistDiffRanges(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
): Promise<boolean> {
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === undefined) {
|
||||
return false;
|
||||
}
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
|
||||
logger.info(
|
||||
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
||||
async function getFileDiffsWithBasehead(
|
||||
branches: PullRequestBranches,
|
||||
logger: Logger,
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
export async function run__ACTION__() {
|
||||
return await __ACTION__.runWrapper();
|
||||
}
|
||||
+27
-12
@@ -451,12 +451,16 @@ test.serial(`selects CLI from defaults.json on GHES`, async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
const features = setUpFeatureFlagTests(tmpDir);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
||||
const defaultCliVersion = await features.getEnabledDefaultCliVersions(
|
||||
GitHubVariant.GHES,
|
||||
);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -482,10 +486,13 @@ for (const variant of [GitHubVariant.DOTCOM, GitHubVariant.GHEC_DR]) {
|
||||
false;
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||
const defaultCliVersion =
|
||||
await features.getEnabledDefaultCliVersions(variant);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: "2.20.1",
|
||||
tagName: "codeql-bundle-v2.20.1",
|
||||
enabledVersions: [
|
||||
{ cliVersion: "2.20.1", tagName: "codeql-bundle-v2.20.1" },
|
||||
{ cliVersion: "2.20.0", tagName: "codeql-bundle-v2.20.0" },
|
||||
],
|
||||
toolsFeatureFlagsValid: true,
|
||||
});
|
||||
});
|
||||
@@ -500,10 +507,15 @@ for (const variant of [GitHubVariant.DOTCOM, GitHubVariant.GHEC_DR]) {
|
||||
const expectedFeatureEnablement = initializeFeatures(true);
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||
const defaultCliVersion =
|
||||
await features.getEnabledDefaultCliVersions(variant);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
},
|
||||
],
|
||||
toolsFeatureFlagsValid: false,
|
||||
});
|
||||
});
|
||||
@@ -529,10 +541,13 @@ for (const variant of [GitHubVariant.DOTCOM, GitHubVariant.GHEC_DR]) {
|
||||
] = true;
|
||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||
|
||||
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||
const defaultCliVersion =
|
||||
await features.getEnabledDefaultCliVersions(variant);
|
||||
t.deepEqual(defaultCliVersion, {
|
||||
cliVersion: "2.20.1",
|
||||
tagName: "codeql-bundle-v2.20.1",
|
||||
enabledVersions: [
|
||||
{ cliVersion: "2.20.1", tagName: "codeql-bundle-v2.20.1" },
|
||||
{ cliVersion: "2.20.0", tagName: "codeql-bundle-v2.20.0" },
|
||||
],
|
||||
toolsFeatureFlagsValid: true,
|
||||
});
|
||||
|
||||
|
||||
+82
-24
@@ -29,9 +29,32 @@ const DEFAULT_VERSION_FEATURE_FLAG_SUFFIX = "_enabled";
|
||||
*/
|
||||
export const CODEQL_VERSION_ZSTD_BUNDLE = "2.19.0";
|
||||
|
||||
export interface CodeQLDefaultVersionInfo {
|
||||
const LINKED_CODEQL_VERSION: CodeQLVersionInfo = {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
};
|
||||
|
||||
export interface CodeQLVersionInfo {
|
||||
/** The version number of the CodeQL CLI, e.g. `2.19.0`. */
|
||||
cliVersion: string;
|
||||
/**
|
||||
* The tag name of the CodeQL Bundle associated with this version, e.g. `codeql-bundle-v2.19.0`.
|
||||
*/
|
||||
tagName: string;
|
||||
}
|
||||
|
||||
export interface CodeQLDefaultVersionInfo {
|
||||
/**
|
||||
* CodeQL CLI versions that are enabled as defaults, sorted from highest to lowest.
|
||||
*
|
||||
* Guaranteed to be non-empty. When feature flags are unavailable, this falls back to a single
|
||||
* entry containing the version pinned in `defaults.json`.
|
||||
*/
|
||||
enabledVersions: CodeQLVersionInfo[];
|
||||
/**
|
||||
* If accessed, whether the tools feature flags are valid, i.e. contain at least one enabled
|
||||
* version.
|
||||
*/
|
||||
toolsFeatureFlagsValid?: boolean;
|
||||
}
|
||||
|
||||
@@ -44,6 +67,8 @@ export interface CodeQLDefaultVersionInfo {
|
||||
* Legacy features should end with `_enabled`.
|
||||
*/
|
||||
export enum Feature {
|
||||
/** Controls whether we allow multiple values for the `analysis-kinds` input. */
|
||||
AllowMultipleAnalysisKinds = "allow_multiple_analysis_kinds",
|
||||
AllowToolcacheInput = "allow_toolcache_input",
|
||||
CleanupTrapCaches = "cleanup_trap_caches",
|
||||
CppDependencyInstallation = "cpp_dependency_installation_enabled",
|
||||
@@ -72,6 +97,19 @@ export enum Feature {
|
||||
OverlayAnalysisGo = "overlay_analysis_go",
|
||||
OverlayAnalysisJava = "overlay_analysis_java",
|
||||
OverlayAnalysisJavascript = "overlay_analysis_javascript",
|
||||
/**
|
||||
* When set, chooses the default CodeQL CLI version as the highest version that is both enabled by
|
||||
* feature flags and present as an overlay-base database in the Actions cache for the configured
|
||||
* languages. Falls back to the highest feature flagged version if no intersecting overlay-base
|
||||
* database exists in the cache.
|
||||
*/
|
||||
OverlayAnalysisMatchCodeqlVersion = "overlay_analysis_match_codeql_version",
|
||||
/**
|
||||
* Like `OverlayAnalysisMatchCodeqlVersion`, but only logs a diagnostic with the version that
|
||||
* would have been chosen instead of actually changing the default CodeQL CLI version.
|
||||
* `OverlayAnalysisMatchCodeqlVersion` overrides this flag.
|
||||
*/
|
||||
OverlayAnalysisMatchCodeqlVersionDryRun = "overlay_analysis_match_codeql_version_dry_run",
|
||||
OverlayAnalysisPython = "overlay_analysis_python",
|
||||
/**
|
||||
* Controls whether lower disk space requirements are used for overlay hardware checks.
|
||||
@@ -124,6 +162,11 @@ export type FeatureConfig = {
|
||||
};
|
||||
|
||||
export const featureConfig = {
|
||||
[Feature.AllowMultipleAnalysisKinds]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_ALLOW_MULTIPLE_ANALYSIS_KINDS",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.AllowToolcacheInput]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT",
|
||||
@@ -277,6 +320,16 @@ export const featureConfig = {
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_DISABLE_TRAP_CACHING",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.OverlayAnalysisMatchCodeqlVersion]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_MATCH_CODEQL_VERSION",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.OverlayAnalysisMatchCodeqlVersionDryRun]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_MATCH_CODEQL_VERSION_DRY_RUN",
|
||||
minimumVersion: undefined,
|
||||
},
|
||||
[Feature.OverlayAnalysisResourceChecksV2]: {
|
||||
defaultValue: false,
|
||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS_RESOURCE_CHECKS_V2",
|
||||
@@ -346,8 +399,12 @@ export type FeatureWithoutCLI = {
|
||||
}[keyof typeof featureConfig];
|
||||
|
||||
export interface FeatureEnablement {
|
||||
/** Gets the default version of the CodeQL tools. */
|
||||
getDefaultCliVersion(
|
||||
/**
|
||||
* Returns the set of default CodeQL CLI versions to consider, sorted from
|
||||
* highest to lowest. The first entry is the version that the CodeQL Action
|
||||
* will use by default. The list is always non-empty.
|
||||
*/
|
||||
getEnabledDefaultCliVersions(
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo>;
|
||||
getValue(feature: FeatureWithoutCLI): Promise<boolean>;
|
||||
@@ -371,12 +428,11 @@ export const FEATURE_FLAGS_FILE_NAME = "cached-feature-flags.json";
|
||||
class OfflineFeatures implements FeatureEnablement {
|
||||
constructor(protected readonly logger: Logger) {}
|
||||
|
||||
async getDefaultCliVersion(
|
||||
async getEnabledDefaultCliVersions(
|
||||
_variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
return {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
enabledVersions: [LINKED_CODEQL_VERSION],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -386,7 +442,7 @@ class OfflineFeatures implements FeatureEnablement {
|
||||
getFeatureConfig(feature: Feature): FeatureConfig {
|
||||
// Narrow the type to FeatureConfig to avoid type errors. To avoid unsafe use of `as`, we
|
||||
// check that the required properties exist using `satisfies`.
|
||||
return featureConfig[feature] satisfies FeatureConfig as FeatureConfig;
|
||||
return featureConfig[feature] satisfies FeatureConfig;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -518,13 +574,13 @@ class Features extends OfflineFeatures {
|
||||
);
|
||||
}
|
||||
|
||||
async getDefaultCliVersion(
|
||||
async getEnabledDefaultCliVersions(
|
||||
variant: util.GitHubVariant,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
if (supportsFeatureFlags(variant)) {
|
||||
return await this.gitHubFeatureFlags.getDefaultCliVersionFromFlags();
|
||||
return await this.gitHubFeatureFlags.getEnabledDefaultCliVersionsFromFlags();
|
||||
}
|
||||
return super.getDefaultCliVersion(variant);
|
||||
return super.getEnabledDefaultCliVersions(variant);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -600,16 +656,22 @@ class GitHubFeatureFlags {
|
||||
return version;
|
||||
}
|
||||
|
||||
async getDefaultCliVersionFromFlags(): Promise<CodeQLDefaultVersionInfo> {
|
||||
/**
|
||||
* Returns CLI versions enabled by `default_codeql_version_*_enabled` feature
|
||||
* flags, sorted from highest to lowest. Falls back to the version pinned in
|
||||
* `defaults.json` if no such flags are enabled.
|
||||
*/
|
||||
async getEnabledDefaultCliVersionsFromFlags(): Promise<CodeQLDefaultVersionInfo> {
|
||||
const response = await this.getAllFeatures();
|
||||
|
||||
const enabledFeatureFlagCliVersions = Object.entries(response)
|
||||
const sortedCliVersions = Object.entries(response)
|
||||
.map(([f, isEnabled]) =>
|
||||
isEnabled ? this.getCliVersionFromFeatureFlag(f) : undefined,
|
||||
)
|
||||
.filter((f): f is string => f !== undefined);
|
||||
.filter((f): f is string => f !== undefined)
|
||||
.sort(semver.rcompare);
|
||||
|
||||
if (enabledFeatureFlagCliVersions.length === 0) {
|
||||
if (sortedCliVersions.length === 0) {
|
||||
// We expect at least one default CLI version to be enabled on Dotcom at any time. However if
|
||||
// the feature flags are misconfigured, rather than crashing, we fall back to the CLI version
|
||||
// shipped with the Action in defaults.json. This has the effect of immediately rolling out
|
||||
@@ -625,8 +687,7 @@ class GitHubFeatureFlags {
|
||||
`shipped with the Action. This is ${defaults.cliVersion}.`,
|
||||
);
|
||||
const result: CodeQLDefaultVersionInfo = {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
enabledVersions: [LINKED_CODEQL_VERSION],
|
||||
};
|
||||
if (this.hasAccessedRemoteFeatureFlags) {
|
||||
result.toolsFeatureFlagsValid = false;
|
||||
@@ -634,17 +695,14 @@ class GitHubFeatureFlags {
|
||||
return result;
|
||||
}
|
||||
|
||||
const maxCliVersion = enabledFeatureFlagCliVersions.reduce(
|
||||
(maxVersion, currentVersion) =>
|
||||
currentVersion > maxVersion ? currentVersion : maxVersion,
|
||||
enabledFeatureFlagCliVersions[0],
|
||||
);
|
||||
this.logger.debug(
|
||||
`Derived default CLI version of ${maxCliVersion} from feature flags.`,
|
||||
`Derived default CLI version of ${sortedCliVersions[0]} from feature flags.`,
|
||||
);
|
||||
return {
|
||||
cliVersion: maxCliVersion,
|
||||
tagName: `codeql-bundle-v${maxCliVersion}`,
|
||||
enabledVersions: sortedCliVersions.map((cliVersion) => ({
|
||||
cliVersion,
|
||||
tagName: `codeql-bundle-v${cliVersion}`,
|
||||
})),
|
||||
toolsFeatureFlagsValid: true,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
createFeatures,
|
||||
createTestConfig,
|
||||
DEFAULT_ACTIONS_VARS,
|
||||
makeMacro,
|
||||
makeVersionInfo,
|
||||
RecordingLogger,
|
||||
setupActionsVars,
|
||||
@@ -601,7 +602,7 @@ async function testFailedSarifUpload(
|
||||
uploadFiles.resolves({
|
||||
sarifID: "42",
|
||||
statusReport: { raw_upload_size_bytes: 20, zipped_upload_size_bytes: 10 },
|
||||
} as uploadLib.UploadResult);
|
||||
});
|
||||
const waitForProcessing = sinon.stub(uploadLib, "waitForProcessing");
|
||||
|
||||
const features = [] as Feature[];
|
||||
@@ -796,7 +797,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
const skippedUploadTest = test.macro({
|
||||
const skippedUploadTest = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
config: Partial<configUtils.Config>,
|
||||
@@ -823,9 +824,8 @@ const skippedUploadTest = test.macro({
|
||||
`tryUploadSarifIfRunFailed - skips upload ${providedTitle}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
skippedUploadTest.serial(
|
||||
"without CodeQL command",
|
||||
skippedUploadTest,
|
||||
// No codeQLCmd
|
||||
{
|
||||
analysisKinds: [AnalysisKind.RiskAssessment],
|
||||
@@ -834,9 +834,8 @@ test.serial(
|
||||
"CodeQL command not found",
|
||||
);
|
||||
|
||||
test.serial(
|
||||
skippedUploadTest.serial(
|
||||
"if no language is configured",
|
||||
skippedUploadTest,
|
||||
// No explicit language configuration
|
||||
{
|
||||
analysisKinds: [AnalysisKind.RiskAssessment],
|
||||
@@ -845,9 +844,8 @@ test.serial(
|
||||
"Unexpectedly, the configuration is not for a single language.",
|
||||
);
|
||||
|
||||
test.serial(
|
||||
skippedUploadTest.serial(
|
||||
"if multiple languages is configured",
|
||||
skippedUploadTest,
|
||||
// Multiple explicit languages configured
|
||||
{
|
||||
analysisKinds: [AnalysisKind.RiskAssessment],
|
||||
|
||||
@@ -207,7 +207,7 @@ function getJobStatusFromEnvironment(): JobStatus | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -222,5 +222,3 @@ async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+13
-50
@@ -37,11 +37,6 @@ import {
|
||||
makeDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import {
|
||||
getDiffInformedAnalysisBranches,
|
||||
getPullRequestEditedDiffRanges,
|
||||
writeDiffRangesJsonFile,
|
||||
} from "./diff-informed-analysis-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
|
||||
import {
|
||||
@@ -281,7 +276,7 @@ async function run(startedAt: Date) {
|
||||
// successful, the results are cached so that we don't duplicate the work in normal runs.
|
||||
let analysisKinds: AnalysisKind[] | undefined;
|
||||
try {
|
||||
analysisKinds = await getAnalysisKinds(logger);
|
||||
analysisKinds = await getAnalysisKinds(logger, features);
|
||||
} catch (err) {
|
||||
logger.debug(
|
||||
`Failed to parse analysis kinds for 'starting' status report: ${getErrorMessage(err)}`,
|
||||
@@ -298,16 +293,23 @@ async function run(startedAt: Date) {
|
||||
);
|
||||
}
|
||||
|
||||
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
|
||||
gitHubVersion.type,
|
||||
);
|
||||
const codeQLDefaultVersionInfo =
|
||||
await features.getEnabledDefaultCliVersions(gitHubVersion.type);
|
||||
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
|
||||
const rawLanguages = configUtils.getRawLanguagesNoAutodetect(
|
||||
getOptionalInput("languages"),
|
||||
);
|
||||
const useOverlayAwareDefaultCliVersion =
|
||||
analysisKinds?.length === 1 &&
|
||||
analysisKinds[0] === AnalysisKind.CodeScanning;
|
||||
const initCodeQLResult = await initCodeQL(
|
||||
getOptionalInput("tools"),
|
||||
apiDetails,
|
||||
getTemporaryDirectory(),
|
||||
gitHubVersion.type,
|
||||
codeQLDefaultVersionInfo,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
@@ -346,7 +348,7 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
}
|
||||
|
||||
analysisKinds = await getAnalysisKinds(logger);
|
||||
analysisKinds = await getAnalysisKinds(logger, features);
|
||||
const debugMode = getOptionalInput("debug") === "true" || core.isDebug();
|
||||
const repositoryProperties = repositoryPropertiesResult.orElse({});
|
||||
const fileCoverageResult = await getFileCoverageInformationEnabled(
|
||||
@@ -427,7 +429,6 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
|
||||
await checkInstallPython311(config.languages, codeql);
|
||||
await computeAndPersistDiffRanges(codeql, features, logger);
|
||||
} catch (unwrappedError) {
|
||||
const error = wrapError(unwrappedError);
|
||||
core.setFailed(error.message);
|
||||
@@ -823,42 +824,6 @@ async function loadRepositoryProperties(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compute and persist diff ranges when diff-informed analysis is enabled
|
||||
* (feature flag + PR context). This writes the standard pr-diff-range.json
|
||||
* file for later reuse in the analyze step. Failures are logged but non-fatal.
|
||||
*/
|
||||
async function computeAndPersistDiffRanges(
|
||||
codeql: CodeQL,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<void> {
|
||||
await withGroupAsync("Computing PR diff ranges", async () => {
|
||||
try {
|
||||
const branches = await getDiffInformedAnalysisBranches(
|
||||
codeql,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
if (!branches) {
|
||||
return;
|
||||
}
|
||||
const ranges = await getPullRequestEditedDiffRanges(branches, logger);
|
||||
if (ranges === undefined) {
|
||||
return;
|
||||
}
|
||||
writeDiffRangesJsonFile(logger, ranges);
|
||||
const distinctFiles = new Set(ranges.map((r) => r.path)).size;
|
||||
logger.info(
|
||||
`Persisted ${ranges.length} diff range(s) across ${distinctFiles} file(s).`,
|
||||
);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
`Failed to compute and persist PR diff ranges: ${getErrorMessage(e)}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
async function recordZstdAvailability(
|
||||
config: configUtils.Config,
|
||||
zstdAvailability: ZstdAvailability,
|
||||
@@ -873,7 +838,7 @@ async function recordZstdAvailability(
|
||||
);
|
||||
}
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -889,5 +854,3 @@ async function runWrapper() {
|
||||
}
|
||||
await checkForTimeout();
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+15
-27
@@ -22,6 +22,7 @@ import {
|
||||
createTestConfig,
|
||||
getRecordingLogger,
|
||||
setupTests,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import { ConfigurationError, withTmpDir } from "./util";
|
||||
|
||||
@@ -158,10 +159,9 @@ type PackInfo = {
|
||||
qlpackFileName?: string;
|
||||
};
|
||||
|
||||
const testCheckPacksForOverlayCompatibility = test.macro({
|
||||
const testCheckPacksForOverlayCompatibility = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext,
|
||||
_title: string,
|
||||
{
|
||||
cliOverlayVersion,
|
||||
languages,
|
||||
@@ -234,11 +234,10 @@ const testCheckPacksForOverlayCompatibility = test.macro({
|
||||
);
|
||||
});
|
||||
},
|
||||
title: (_, title) => `checkPacksForOverlayCompatibility: ${title}`,
|
||||
title: (title) => `checkPacksForOverlayCompatibility: ${title}`,
|
||||
});
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns false when CLI does not support overlay",
|
||||
{
|
||||
cliOverlayVersion: undefined,
|
||||
@@ -253,8 +252,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns true when there are no query packs",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -264,8 +262,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns true when query pack has not been compiled",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -281,8 +278,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns true when query pack has expected overlay version",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -297,8 +293,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns true when query packs for all languages to analyze are compatible",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -317,8 +312,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns true when query pack for a language not analyzed is incompatible",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -337,8 +331,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns false when query pack for a language to analyze is incompatible",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -357,8 +350,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns false when query pack is missing .packinfo",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -377,8 +369,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns false when query pack has different overlay version",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -397,8 +388,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns false when query pack is missing overlayVersion in .packinfo",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -417,8 +407,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns false when .packinfo is not valid JSON",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
@@ -437,8 +426,7 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
testCheckPacksForOverlayCompatibility,
|
||||
testCheckPacksForOverlayCompatibility(
|
||||
"returns true when query pack uses codeql-pack.yml filename",
|
||||
{
|
||||
cliOverlayVersion: 2,
|
||||
|
||||
@@ -39,6 +39,8 @@ export async function initCodeQL(
|
||||
tempDir: string,
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
useOverlayAwareDefaultCliVersion: boolean,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<{
|
||||
@@ -61,6 +63,8 @@ export async function initCodeQL(
|
||||
tempDir,
|
||||
variant,
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
true,
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
import test from "ava";
|
||||
|
||||
import { setupTests } from "../testing-utils";
|
||||
|
||||
import * as json from ".";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
const testSchema = {
|
||||
requiredKey: json.string,
|
||||
};
|
||||
|
||||
const optionalSchema = {
|
||||
optionalKey: json.optional(json.string),
|
||||
};
|
||||
|
||||
test("validateSchema - required properties are required", async (t) => {
|
||||
t.false(json.validateSchema(testSchema, {}));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: undefined }));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: null }));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: 0 }));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: 123 }));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: false }));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: true }));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: [] }));
|
||||
t.false(json.validateSchema(testSchema, { requiredKey: {} }));
|
||||
t.true(json.validateSchema(testSchema, { requiredKey: "" }));
|
||||
t.true(json.validateSchema(testSchema, { requiredKey: "foo" }));
|
||||
});
|
||||
|
||||
test("validateSchema - optional properties are optional", async (t) => {
|
||||
// Optional fields may be absent
|
||||
t.true(json.validateSchema(optionalSchema, {}));
|
||||
t.true(json.validateSchema(optionalSchema, { optionalKey: undefined }));
|
||||
t.true(json.validateSchema(optionalSchema, { optionalKey: null }));
|
||||
|
||||
// But, if present, should have the expected type
|
||||
t.false(json.validateSchema(optionalSchema, { optionalKey: 0 }));
|
||||
t.false(json.validateSchema(optionalSchema, { optionalKey: 123 }));
|
||||
t.false(json.validateSchema(optionalSchema, { optionalKey: false }));
|
||||
t.false(json.validateSchema(optionalSchema, { optionalKey: true }));
|
||||
t.false(json.validateSchema(optionalSchema, { optionalKey: [] }));
|
||||
t.false(json.validateSchema(optionalSchema, { optionalKey: {} }));
|
||||
t.true(json.validateSchema(optionalSchema, { optionalKey: "" }));
|
||||
t.true(json.validateSchema(optionalSchema, { optionalKey: "foo" }));
|
||||
});
|
||||
@@ -36,3 +36,82 @@ export function isStringOrUndefined(
|
||||
): value is string | undefined {
|
||||
return value === undefined || isString(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a field of type `T` in a schema.
|
||||
* Carries a validation function and flag indicating whether the field is required or not.
|
||||
*/
|
||||
export type Validator<T> = {
|
||||
validate: (val: unknown) => val is T;
|
||||
required: boolean;
|
||||
};
|
||||
|
||||
/** Extracts `T` from `Validator<T>`. */
|
||||
export type UnwrapValidator<V> = V extends Validator<infer A> ? A : never;
|
||||
|
||||
/** A validator for string fields in schemas. */
|
||||
export const string = {
|
||||
validate: isString,
|
||||
required: true,
|
||||
} as const satisfies Validator<string>;
|
||||
|
||||
/** Transforms a validator to be optional. */
|
||||
export function optional<T>(validator: Validator<T>) {
|
||||
return {
|
||||
validate: (val: unknown) => {
|
||||
return val === undefined || val === null || validator.validate(val);
|
||||
},
|
||||
required: false,
|
||||
} as const satisfies Validator<T | undefined | null>;
|
||||
}
|
||||
|
||||
/** Represents an arbitrary object schema. */
|
||||
export type Schema = Record<string, Validator<any>>;
|
||||
|
||||
/** Extracts the required keys from `S`. */
|
||||
export type RequiredKeys<S extends Schema> = {
|
||||
[K in keyof S]: S[K]["required"] extends true ? K : never;
|
||||
}[keyof S];
|
||||
|
||||
/** Extracts optional keys from `S`. */
|
||||
export type OptionalKeys<S extends Schema> = {
|
||||
[K in keyof S]: S[K]["required"] extends true ? never : K;
|
||||
}[keyof S];
|
||||
|
||||
/** Constructs an object type corresponding to a schema. */
|
||||
export type FromSchema<S extends Schema> = {
|
||||
[K in RequiredKeys<S>]: UnwrapValidator<S[K]>;
|
||||
} & { [K in OptionalKeys<S>]?: UnwrapValidator<S[K]> };
|
||||
|
||||
/**
|
||||
* Validates that `obj` satisfies at least `schema`. Additional keys are accepted.
|
||||
*
|
||||
* @param schema The schema to validate against.
|
||||
* @param obj The object to validate.
|
||||
* @returns Asserts that `obj` is of the `schema`'s type if validation is successful.
|
||||
*/
|
||||
export function validateSchema<S extends Schema>(
|
||||
schema: S,
|
||||
obj: UnvalidatedObject<any>,
|
||||
): obj is FromSchema<S> {
|
||||
for (const [key, validator] of Object.entries(schema)) {
|
||||
const hasKey = key in obj;
|
||||
|
||||
// If the property is required, but absent, fail.
|
||||
if (validator.required && !hasKey) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the property is required, but undefined or null, fail.
|
||||
if (validator.required && (obj[key] === undefined || obj[key] === null)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// If the property is present, validate it.
|
||||
if (hasKey && !validator.validate(obj[key])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,106 @@
|
||||
import { ExecutionContext } from "ava";
|
||||
|
||||
import * as json from ".";
|
||||
|
||||
/**
|
||||
* Constructs an object based on `schema` for unit tests.
|
||||
* Assumes that all keys in `schema` have string values.
|
||||
*
|
||||
* @param includeOptional Whether to include optional properties.
|
||||
* @param schema The schema to base the object on.
|
||||
* @returns An object that satisfies `schema`.
|
||||
*/
|
||||
export function makeFromSchema<S extends json.Schema>(
|
||||
includeOptional: boolean,
|
||||
schema: S,
|
||||
): json.FromSchema<S> {
|
||||
const result = {};
|
||||
for (const [key, validator] of Object.entries(schema)) {
|
||||
if (!validator.required && !includeOptional) {
|
||||
continue;
|
||||
}
|
||||
result[key] = `value-for-${key}`;
|
||||
}
|
||||
return result as json.FromSchema<S>;
|
||||
}
|
||||
|
||||
/** Options for `withSchemaMatrix`. */
|
||||
export interface SchemaMatrixOptions {
|
||||
/** Whether cases where the properties are entirely absent should be excluded. */
|
||||
excludeAbsent?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a test matrix of possible objects for `schema`: all required properties
|
||||
* plus all permutations of possible states for the optional properties.
|
||||
*
|
||||
* @param schema The schema to construct a test matrix for.
|
||||
* @param body The test body to call with each value from the test matrix.
|
||||
*/
|
||||
export function withSchemaMatrix<S extends json.Schema>(
|
||||
t: ExecutionContext<any>,
|
||||
schema: S,
|
||||
opts: SchemaMatrixOptions,
|
||||
body: (value: json.FromSchema<S>) => void,
|
||||
): void {
|
||||
// Construct a base object that includes all required properties.
|
||||
const required = makeFromSchema(false, schema);
|
||||
|
||||
// Identify optional properties.
|
||||
const optionalKeys: Array<keyof S> = [];
|
||||
|
||||
for (const [key, validator] of Object.entries(schema)) {
|
||||
if (!validator.required) {
|
||||
optionalKeys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
const optionalValues = (key: keyof S) => [
|
||||
null,
|
||||
undefined,
|
||||
`value-for-${String(key)}`,
|
||||
];
|
||||
|
||||
// Constructs an array of test objects, starting with `required` and combining it with all
|
||||
// possible states of each optional property. For example, with default settings:
|
||||
//
|
||||
// For { requiredKey: string }, we get: `[{ requiredKey: "some-string-value" }]`
|
||||
//
|
||||
// For { requiredKey: string, optionalKey?: string }, we get:
|
||||
// [ { requiredKey: "some-string-value" },
|
||||
// { requiredKey: "some-string-value", optionalKey: undefined },
|
||||
// { requiredKey: "some-string-value", optionalKey: null },
|
||||
// { requiredKey: "some-string-value", optionalKey: "some-value" },
|
||||
// ]
|
||||
const permutations = (keys: Array<keyof S>) => {
|
||||
if (keys.length === 0) return [required];
|
||||
|
||||
const bases = permutations(keys.slice(1));
|
||||
const result: Array<json.FromSchema<S>> = [];
|
||||
|
||||
const optionalKey = keys[0];
|
||||
for (const base of bases) {
|
||||
if (!opts.excludeAbsent) {
|
||||
// Optional keys can be absent entirely.
|
||||
result.push(base);
|
||||
}
|
||||
|
||||
// Or be present and have one of the `optionalValues`.
|
||||
for (const optionalValue of optionalValues(optionalKey)) {
|
||||
result.push({ ...base, [optionalKey]: optionalValue });
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
// Call `body` for all test cases.
|
||||
const testCases = permutations(optionalKeys);
|
||||
for (const testCase of testCases) {
|
||||
try {
|
||||
body(testCase);
|
||||
} catch (err) {
|
||||
t.log(testCase);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
}
|
||||
+173
-26
@@ -7,12 +7,13 @@ import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "../actions-util";
|
||||
import * as apiClient from "../api-client";
|
||||
import { ResolveDatabaseOutput } from "../codeql";
|
||||
import type { ResolveDatabaseOutput } from "../codeql";
|
||||
import * as gitUtils from "../git-utils";
|
||||
import { BuiltInLanguage } from "../languages";
|
||||
import { getRunnerLogger } from "../logging";
|
||||
import {
|
||||
createTestConfig,
|
||||
makeMacro,
|
||||
mockCodeQLVersion,
|
||||
setupTests,
|
||||
} from "../testing-utils";
|
||||
@@ -23,6 +24,7 @@ import {
|
||||
downloadOverlayBaseDatabaseFromCache,
|
||||
getCacheRestoreKeyPrefix,
|
||||
getCacheSaveKey,
|
||||
getCodeQlVersionsForOverlayBaseDatabases,
|
||||
} from "./caching";
|
||||
import { OverlayDatabaseMode } from "./overlay-database-mode";
|
||||
|
||||
@@ -50,10 +52,9 @@ const defaultDownloadTestCase: DownloadOverlayBaseDatabaseTestCase = {
|
||||
resolveDatabaseOutput: { overlayBaseSpecifier: "20250626:XXX" },
|
||||
};
|
||||
|
||||
const testDownloadOverlayBaseDatabaseFromCache = test.macro({
|
||||
const testDownloadOverlayBaseDatabaseFromCache = makeMacro({
|
||||
exec: async (
|
||||
t,
|
||||
_title: string,
|
||||
partialTestCase: Partial<DownloadOverlayBaseDatabaseTestCase>,
|
||||
expectDownloadSuccess: boolean,
|
||||
) => {
|
||||
@@ -141,18 +142,16 @@ const testDownloadOverlayBaseDatabaseFromCache = test.macro({
|
||||
}
|
||||
});
|
||||
},
|
||||
title: (_, title) => `downloadOverlayBaseDatabaseFromCache: ${title}`,
|
||||
title: (title) => `downloadOverlayBaseDatabaseFromCache: ${title}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns stats when successful",
|
||||
{},
|
||||
true,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when mode is OverlayDatabaseMode.OverlayBase",
|
||||
{
|
||||
overlayDatabaseMode: OverlayDatabaseMode.OverlayBase,
|
||||
@@ -160,8 +159,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when mode is OverlayDatabaseMode.None",
|
||||
{
|
||||
overlayDatabaseMode: OverlayDatabaseMode.None,
|
||||
@@ -169,8 +167,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when caching is disabled",
|
||||
{
|
||||
useOverlayDatabaseCaching: false,
|
||||
@@ -178,8 +175,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined in test mode",
|
||||
{
|
||||
isInTestMode: true,
|
||||
@@ -187,8 +183,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when cache miss",
|
||||
{
|
||||
restoreCacheResult: undefined,
|
||||
@@ -196,8 +191,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when download fails",
|
||||
{
|
||||
restoreCacheResult: new Error("Download failed"),
|
||||
@@ -205,8 +199,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when downloaded database is invalid",
|
||||
{
|
||||
hasBaseDatabaseOidsFile: false,
|
||||
@@ -214,8 +207,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when downloaded database doesn't have an overlayBaseSpecifier",
|
||||
{
|
||||
resolveDatabaseOutput: {},
|
||||
@@ -223,8 +215,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when resolving database metadata fails",
|
||||
{
|
||||
resolveDatabaseOutput: new Error("Failed to resolve database metadata"),
|
||||
@@ -232,8 +223,7 @@ test.serial(
|
||||
false,
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testDownloadOverlayBaseDatabaseFromCache,
|
||||
testDownloadOverlayBaseDatabaseFromCache.serial(
|
||||
"returns undefined when filesystem error occurs",
|
||||
{
|
||||
tryGetFolderBytesSucceeds: false,
|
||||
@@ -285,3 +275,160 @@ test.serial("overlay-base database cache keys remain stable", async (t) => {
|
||||
`Expected save key "${saveKey}" to start with restore key prefix "${restoreKeyPrefix}"`,
|
||||
);
|
||||
});
|
||||
|
||||
test.serial(
|
||||
"getCodeQlVersionsForOverlayBaseDatabases returns unique versions sorted latest first",
|
||||
async (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
sinon.stub(apiClient, "listActionsCaches").resolves([
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-javascript_python-2.23.0-abc123-1-1",
|
||||
},
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-javascript_python-2.24.1-def456-2-1",
|
||||
},
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-javascript_python-2.23.0-ghi789-3-1",
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
["javascript", "python"],
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(result, ["2.24.1", "2.23.0"]);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getCodeQlVersionsForOverlayBaseDatabases returns empty list when no caches exist",
|
||||
async (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
sinon.stub(apiClient, "listActionsCaches").resolves([]);
|
||||
|
||||
const result = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
["python"],
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(result, []);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getCodeQlVersionsForOverlayBaseDatabases returns empty list when cache keys are unparseable",
|
||||
async (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
sinon.stub(apiClient, "listActionsCaches").resolves([
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-python-malformed",
|
||||
},
|
||||
{ key: undefined },
|
||||
]);
|
||||
|
||||
const result = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
["python"],
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(result, []);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getCodeQlVersionsForOverlayBaseDatabases returns the single version when only one cache exists",
|
||||
async (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
sinon.stub(apiClient, "listActionsCaches").resolves([
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-cpp-2.25.0-abc123-1-1",
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
["cpp"],
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(result, ["2.25.0"]);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getCodeQlVersionsForOverlayBaseDatabases resolves language aliases",
|
||||
async (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
// The alias `c++` should be resolved to "cpp" and match cache entries keyed with "cpp"
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
sinon.stub(apiClient, "listActionsCaches").resolves([
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-cpp-2.25.0-abc123-1-1",
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
["c++"],
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(result, ["2.25.0"]);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getCodeQlVersionsForOverlayBaseDatabases de-duplicates resolved language aliases",
|
||||
async (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
const listActionsCachesStub = sinon
|
||||
.stub(apiClient, "listActionsCaches")
|
||||
.resolves([
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-javascript_python-2.25.0-abc123-1-1",
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
["javascript", "typescript", "Python", "python"],
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(result, ["2.25.0"]);
|
||||
sinon.assert.calledOnceWithExactly(
|
||||
listActionsCachesStub,
|
||||
"codeql-overlay-base-database-1-c5666c509a2d9895-javascript_python-",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getCodeQlVersionsForOverlayBaseDatabases ignores nightly versions with build metadata",
|
||||
async (t) => {
|
||||
const logger = getRunnerLogger(true);
|
||||
|
||||
sinon.stub(apiClient, "getAutomationID").resolves("test-automation-id/");
|
||||
sinon.stub(apiClient, "listActionsCaches").resolves([
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-python-2.25.0-abc123-1-1",
|
||||
},
|
||||
{
|
||||
// Nightly release with semver build metadata; should be ignored.
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-python-2.26.0+202604211234-def456-2-1",
|
||||
},
|
||||
{
|
||||
key: "codeql-overlay-base-database-1-c5666c509a2d9895-python-2.24.0-ghi789-3-1",
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
["python"],
|
||||
logger,
|
||||
);
|
||||
t.deepEqual(result, ["2.25.0", "2.24.0"]);
|
||||
},
|
||||
);
|
||||
|
||||
+105
-12
@@ -1,18 +1,20 @@
|
||||
import * as fs from "fs";
|
||||
|
||||
import * as actionsCache from "@actions/cache";
|
||||
import * as semver from "semver";
|
||||
|
||||
import {
|
||||
getRequiredInput,
|
||||
getWorkflowRunAttempt,
|
||||
getWorkflowRunID,
|
||||
} from "../actions-util";
|
||||
import { getAutomationID } from "../api-client";
|
||||
import { getAutomationID, listActionsCaches } from "../api-client";
|
||||
import { createCacheKeyHash } from "../caching-utils";
|
||||
import { type CodeQL } from "../codeql";
|
||||
import { type Config } from "../config-utils";
|
||||
import { getCommitOid } from "../git-utils";
|
||||
import { Logger, withGroupAsync } from "../logging";
|
||||
import { type Language, parseBuiltInLanguage } from "../languages";
|
||||
import { type Logger, withGroupAsync } from "../logging";
|
||||
import {
|
||||
CleanupLevel,
|
||||
getBaseDatabaseOidsFilePath,
|
||||
@@ -404,7 +406,17 @@ export async function getCacheRestoreKeyPrefix(
|
||||
config: Config,
|
||||
codeQlVersion: string,
|
||||
): Promise<string> {
|
||||
const languages = [...config.languages].sort().join("_");
|
||||
return `${await getCacheKeyPrefixBase(config.languages)}${codeQlVersion}-`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes the cache key prefix for overlay-base databases, excluding the
|
||||
* CodeQL version.
|
||||
*/
|
||||
async function getCacheKeyPrefixBase(
|
||||
parsedLanguages: Language[],
|
||||
): Promise<string> {
|
||||
const languagesComponent = [...parsedLanguages].sort().join("_");
|
||||
|
||||
const cacheKeyComponents = {
|
||||
automationID: await getAutomationID(),
|
||||
@@ -412,17 +424,98 @@ export async function getCacheRestoreKeyPrefix(
|
||||
};
|
||||
const componentsHash = createCacheKeyHash(cacheKeyComponents);
|
||||
|
||||
// For a cached overlay-base database to be considered compatible for overlay
|
||||
// analysis, all components in the cache restore key must match:
|
||||
//
|
||||
// CACHE_PREFIX: distinguishes overlay-base databases from other cache objects
|
||||
// CACHE_VERSION: cache format version
|
||||
// componentsHash: hash of additional components (see above for details)
|
||||
// languages: the languages included in the overlay-base database
|
||||
// codeQlVersion: CodeQL bundle version
|
||||
// languagesComponent: the languages included in the overlay-base database
|
||||
//
|
||||
// Technically we can also include languages and codeQlVersion in the
|
||||
// componentsHash, but including them explicitly in the cache key makes it
|
||||
// easier to debug and understand the cache key structure.
|
||||
return `${CACHE_PREFIX}-${CACHE_VERSION}-${componentsHash}-${languages}-${codeQlVersion}-`;
|
||||
// Technically we can also include languages in the componentsHash, but
|
||||
// including them explicitly in the cache key makes it easier to debug and
|
||||
// understand the cache key structure.
|
||||
return `${CACHE_PREFIX}-${CACHE_VERSION}-${componentsHash}-${languagesComponent}-`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Searches the GitHub Actions cache for overlay-base databases matching the given languages, and
|
||||
* returns all stable CodeQL versions found across matching cache entries.
|
||||
*
|
||||
* Note that we do not guarantee that the cache entry for these versions of CodeQL will still be
|
||||
* present by the time we attempt to restore the cache. We could achieve that with a download retry
|
||||
* loop, but we expect that if there is sufficient Actions cache contention that an overlay-base
|
||||
* cache entry for a particular CodeQL version is evicted before we can use it, then it is likely
|
||||
* that the same thing will happen to other overlay-base cache entries, and therefore we will not be
|
||||
* able to use overlay.
|
||||
*
|
||||
* @returns Unique stable CodeQL versions found in cached overlay-base databases, sorted from latest to
|
||||
* earliest, or undefined if one of the languages is not a built-in language.
|
||||
*/
|
||||
export async function getCodeQlVersionsForOverlayBaseDatabases(
|
||||
rawLanguages: string[],
|
||||
logger: Logger,
|
||||
): Promise<string[] | undefined> {
|
||||
const languages = rawLanguages.map(parseBuiltInLanguage);
|
||||
if (languages.includes(undefined)) {
|
||||
logger.warning(
|
||||
"One or more provided languages are not recognized as built-in languages. " +
|
||||
"Skipping searching for overlay-base databases in cache.",
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
const dedupedLanguages = [
|
||||
...new Set(languages.filter((l) => l !== undefined)),
|
||||
];
|
||||
const cacheKeyPrefix = await getCacheKeyPrefixBase(dedupedLanguages);
|
||||
|
||||
logger.debug(
|
||||
`Searching for overlay-base databases in Actions cache with ` +
|
||||
`prefix ${cacheKeyPrefix}`,
|
||||
);
|
||||
|
||||
const caches = await listActionsCaches(cacheKeyPrefix);
|
||||
|
||||
if (caches.length === 0) {
|
||||
logger.info("No overlay-base databases found in Actions cache.");
|
||||
return [];
|
||||
}
|
||||
|
||||
logger.info(
|
||||
`Found ${caches.length} overlay-base ` +
|
||||
`${caches.length === 1 ? "database" : "databases"} in the Actions cache.`,
|
||||
);
|
||||
|
||||
// Parse CodeQL versions from cache keys, matching only stable releases.
|
||||
//
|
||||
// After the prefix, the remaining key format starts with `${codeQlVersion}-`. Nightlies will have
|
||||
// a suffix like `+202604201548` that will break the match.
|
||||
//
|
||||
// Caveat: this relies on the fact that we haven't released any CodeQL bundles with the
|
||||
// `x.y.z-<pre-release>` semver format which does not interact well with the current overlay base
|
||||
// DB cache key format.
|
||||
const versionRegex = /^([\d.]+)-/;
|
||||
const versionSet = new Set<string>();
|
||||
|
||||
for (const cache of caches) {
|
||||
if (!cache.key) continue;
|
||||
const suffix = cache.key.substring(cacheKeyPrefix.length);
|
||||
const match = suffix.match(versionRegex);
|
||||
if (match && semver.valid(match[1])) {
|
||||
versionSet.add(match[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if (versionSet.size === 0) {
|
||||
logger.info(
|
||||
"Could not parse any CodeQL versions from overlay-base database " +
|
||||
"cache keys.",
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
const versions = [...versionSet].sort(semver.rcompare);
|
||||
|
||||
logger.info(
|
||||
`Found overlay databases for the following CodeQL versions in the Actions cache: ${versions.join(", ")}`,
|
||||
);
|
||||
|
||||
return versions;
|
||||
}
|
||||
|
||||
@@ -39,6 +39,15 @@ export enum OverlayDisabledReason {
|
||||
NotPullRequestOrDefaultBranch = "not-pull-request-or-default-branch",
|
||||
/** The top-level overlay analysis feature flag is not enabled. */
|
||||
OverallFeatureNotEnabled = "overall-feature-not-enabled",
|
||||
/**
|
||||
* Overlay analysis was selected for a pull request, but diff-informed
|
||||
* analysis was not enabled for the run (for example, because the
|
||||
* `DiffInformedQueries` feature flag is off, the GHES version is too old,
|
||||
* or the PR diff ranges could not be computed). Overlay analysis has only
|
||||
* been validated in combination with diff-informed analysis, so we fall
|
||||
* back to a non-overlay analysis in this case.
|
||||
*/
|
||||
DiffInformedAnalysisNotEnabled = "diff-informed-analysis-not-enabled",
|
||||
/** Overlay analysis was skipped because it previously failed with similar hardware resources. */
|
||||
SkippedDueToCachedStatus = "skipped-due-to-cached-status",
|
||||
/** Disk usage could not be determined during the overlay status check. */
|
||||
|
||||
@@ -117,7 +117,7 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
}
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -137,5 +137,3 @@ async function runWrapper() {
|
||||
}
|
||||
await checkForTimeout();
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -7,8 +7,10 @@ import {
|
||||
getRequiredInput,
|
||||
getTemporaryDirectory,
|
||||
} from "./actions-util";
|
||||
import { AnalysisKind, getAnalysisKinds } from "./analyses";
|
||||
import { getGitHubVersion } from "./api-client";
|
||||
import { CodeQL } from "./codeql";
|
||||
import { getRawLanguagesNoAutodetect } from "./config-utils";
|
||||
import { EnvVar } from "./environment";
|
||||
import { initFeatures } from "./feature-flags";
|
||||
import { initCodeQL } from "./init";
|
||||
@@ -136,16 +138,22 @@ async function run(startedAt: Date): Promise<void> {
|
||||
if (statusReportBase !== undefined) {
|
||||
await sendStatusReport(statusReportBase);
|
||||
}
|
||||
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
|
||||
gitHubVersion.type,
|
||||
);
|
||||
const codeQLDefaultVersionInfo =
|
||||
await features.getEnabledDefaultCliVersions(gitHubVersion.type);
|
||||
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
|
||||
const rawLanguages = getRawLanguagesNoAutodetect(
|
||||
getOptionalInput("languages"),
|
||||
);
|
||||
const analysisKinds = await getAnalysisKinds(logger, features);
|
||||
const initCodeQLResult = await initCodeQL(
|
||||
getOptionalInput("tools"),
|
||||
apiDetails,
|
||||
getTemporaryDirectory(),
|
||||
gitHubVersion.type,
|
||||
codeQLDefaultVersionInfo,
|
||||
rawLanguages,
|
||||
analysisKinds.length === 1 &&
|
||||
analysisKinds[0] === AnalysisKind.CodeScanning,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
@@ -188,7 +196,7 @@ async function run(startedAt: Date): Promise<void> {
|
||||
}
|
||||
|
||||
/** Run the action and catch any unhandled errors. */
|
||||
async function runWrapper(): Promise<void> {
|
||||
export async function runWrapper(): Promise<void> {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -204,5 +212,3 @@ async function runWrapper(): Promise<void> {
|
||||
}
|
||||
await checkForTimeout();
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+315
-18
@@ -7,8 +7,9 @@ import * as sinon from "sinon";
|
||||
|
||||
import * as actionsUtil from "./actions-util";
|
||||
import * as api from "./api-client";
|
||||
import { Feature, FeatureEnablement } from "./feature-flags";
|
||||
import { Feature } from "./feature-flags";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { getCacheRestoreKeyPrefix } from "./overlay/caching";
|
||||
import * as setupCodeql from "./setup-codeql";
|
||||
import * as tar from "./tar";
|
||||
import {
|
||||
@@ -18,8 +19,9 @@ import {
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
checkExpectedLogMessages,
|
||||
createFeatures,
|
||||
createTestConfig,
|
||||
getRecordingLogger,
|
||||
initializeFeatures,
|
||||
makeMacro,
|
||||
mockBundleDownloadApi,
|
||||
setupActionsVars,
|
||||
setupTests,
|
||||
@@ -33,14 +35,6 @@ import {
|
||||
|
||||
setupTests(test);
|
||||
|
||||
// TODO: Remove when when we no longer need to pass in features (https://github.com/github/codeql-action/issues/2600)
|
||||
const expectedFeatureEnablement: FeatureEnablement = initializeFeatures(
|
||||
true,
|
||||
) as FeatureEnablement;
|
||||
expectedFeatureEnablement.getValue = function (feature: Feature) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
|
||||
return expectedFeatureEnablement[feature];
|
||||
};
|
||||
test.beforeEach(() => {
|
||||
initializeEnvironment("1.2.3");
|
||||
});
|
||||
@@ -107,6 +101,8 @@ test.serial(
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
`https://github.com/github/codeql-action/releases/download/${tagName}/codeql-bundle-linux64.tar.gz`,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
@@ -130,6 +126,8 @@ test.serial(
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
"linked",
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
@@ -155,6 +153,8 @@ test.serial(
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
"latest",
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
@@ -211,6 +211,8 @@ test.serial(
|
||||
"tmp/codeql_action_test/",
|
||||
GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
@@ -266,6 +268,8 @@ test.serial(
|
||||
"tmp/codeql_action_test/",
|
||||
GitHubVariant.DOTCOM,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
@@ -317,6 +321,8 @@ test.serial(
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
"nightly",
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
@@ -378,6 +384,8 @@ test.serial(
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
undefined,
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
@@ -432,6 +440,8 @@ test.serial(
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
"toolcache",
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
@@ -473,7 +483,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
const toolcacheInputFallbackMacro = test.macro({
|
||||
const toolcacheInputFallbackMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
featureList: Feature[],
|
||||
@@ -499,6 +509,8 @@ const toolcacheInputFallbackMacro = test.macro({
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
"toolcache",
|
||||
SAMPLE_DEFAULT_CLI_VERSION,
|
||||
undefined, // rawLanguages
|
||||
false, // useOverlayAwareDefaultCliVersion
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
@@ -514,7 +526,10 @@ const toolcacheInputFallbackMacro = test.macro({
|
||||
|
||||
// Check that `sourceType` and `toolsVersion` match expectations.
|
||||
t.is(source.sourceType, "download");
|
||||
t.is(source.toolsVersion, SAMPLE_DEFAULT_CLI_VERSION.cliVersion);
|
||||
t.is(
|
||||
source.toolsVersion,
|
||||
SAMPLE_DEFAULT_CLI_VERSION.enabledVersions[0].cliVersion,
|
||||
);
|
||||
|
||||
// Check that key messages we would expect to find in the log are present.
|
||||
for (const expectedMessage of expectedMessages) {
|
||||
@@ -533,9 +548,8 @@ const toolcacheInputFallbackMacro = test.macro({
|
||||
`getCodeQLSource falls back to downloading the CLI if ${providedTitle}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
toolcacheInputFallbackMacro.serial(
|
||||
"the toolcache doesn't have a CodeQL CLI when tools == toolcache",
|
||||
toolcacheInputFallbackMacro,
|
||||
[Feature.AllowToolcacheInput],
|
||||
{ GITHUB_EVENT_NAME: "dynamic" },
|
||||
[],
|
||||
@@ -545,9 +559,8 @@ test.serial(
|
||||
],
|
||||
);
|
||||
|
||||
test.serial(
|
||||
toolcacheInputFallbackMacro.serial(
|
||||
"the workflow trigger is not `dynamic`",
|
||||
toolcacheInputFallbackMacro,
|
||||
[Feature.AllowToolcacheInput],
|
||||
{ GITHUB_EVENT_NAME: "pull_request" },
|
||||
[],
|
||||
@@ -556,9 +569,8 @@ test.serial(
|
||||
],
|
||||
);
|
||||
|
||||
test.serial(
|
||||
toolcacheInputFallbackMacro.serial(
|
||||
"the feature flag is not enabled",
|
||||
toolcacheInputFallbackMacro,
|
||||
[],
|
||||
{ GITHUB_EVENT_NAME: "dynamic" },
|
||||
[],
|
||||
@@ -598,3 +610,288 @@ test.serial(
|
||||
t.is(setupCodeql.getLatestToolcacheVersion(getRunnerLogger(true)), "3.2.1");
|
||||
},
|
||||
);
|
||||
|
||||
const overlayMatchEnabledVersions = {
|
||||
enabledVersions: [
|
||||
{ cliVersion: "2.20.2", tagName: "codeql-bundle-v2.20.2" },
|
||||
{ cliVersion: "2.20.1", tagName: "codeql-bundle-v2.20.1" },
|
||||
{ cliVersion: "2.20.0", tagName: "codeql-bundle-v2.20.0" },
|
||||
],
|
||||
toolsFeatureFlagsValid: true,
|
||||
};
|
||||
|
||||
async function fakeOverlayBaseCacheKey(
|
||||
language: string,
|
||||
cliVersion: string,
|
||||
suffix: string,
|
||||
): Promise<string> {
|
||||
const prefix = await getCacheRestoreKeyPrefix(
|
||||
createTestConfig({ languages: [language] }),
|
||||
cliVersion,
|
||||
);
|
||||
return `${prefix}${suffix}`;
|
||||
}
|
||||
|
||||
test.serial(
|
||||
"getCodeQLSource uses overlay-aware default version when requested for a PR",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
process.env["CODE_SCANNING_REF"] = "refs/heads/feature-branch";
|
||||
process.env["CODE_SCANNING_BASE_BRANCH"] = "main";
|
||||
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
const listStub = sinon.stub(api, "listActionsCaches").resolves([
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.20.1", "abc-1-1"),
|
||||
},
|
||||
]);
|
||||
sinon
|
||||
.stub(toolcache, "find")
|
||||
.withArgs("CodeQL", "2.20.1")
|
||||
.returns("/path/to/codeql-2.20.1");
|
||||
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
undefined,
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
true,
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersion]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
t.assert(listStub.calledOnce);
|
||||
t.is(source.sourceType, "toolcache");
|
||||
t.is(source.toolsVersion, "2.20.1");
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getCodeQLSource skips overlay-aware default version when not requested",
|
||||
async (t) => {
|
||||
await withTmpDir(async (tmpDir) => {
|
||||
setupActionsVars(tmpDir, tmpDir);
|
||||
process.env["CODE_SCANNING_REF"] = "refs/heads/feature-branch";
|
||||
process.env["CODE_SCANNING_BASE_BRANCH"] = "main";
|
||||
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
const listStub = sinon.stub(api, "listActionsCaches").resolves([
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.20.1", "abc-1-1"),
|
||||
},
|
||||
]);
|
||||
sinon
|
||||
.stub(toolcache, "find")
|
||||
.withArgs("CodeQL", "2.20.2")
|
||||
.returns("/path/to/codeql-2.20.2");
|
||||
|
||||
const source = await setupCodeql.getCodeQLSource(
|
||||
undefined,
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
false,
|
||||
SAMPLE_DOTCOM_API_DETAILS,
|
||||
GitHubVariant.DOTCOM,
|
||||
false,
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersion]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
|
||||
t.assert(listStub.notCalled);
|
||||
t.is(source.sourceType, "toolcache");
|
||||
t.is(source.toolsVersion, "2.20.2");
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getEnabledVersionsWithOverlayBaseDatabases returns flag-enabled versions present in cache, sorted desc",
|
||||
async (t) => {
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
sinon.stub(api, "listActionsCaches").resolves([
|
||||
// Flag-enabled versions present in the cache, listed in non-descending
|
||||
// order so the test exercises the sort.
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.20.0", "ghi-3-1"),
|
||||
},
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.20.1", "def-2-1"),
|
||||
},
|
||||
// Newer than any flag-enabled version: should be filtered out.
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.21.0", "abc-1-1"),
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersion]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(result, [
|
||||
{ cliVersion: "2.20.1", tagName: "codeql-bundle-v2.20.1" },
|
||||
{ cliVersion: "2.20.0", tagName: "codeql-bundle-v2.20.0" },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getEnabledVersionsWithOverlayBaseDatabases returns empty when no cached version is flag-enabled",
|
||||
async (t) => {
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
sinon.stub(api, "listActionsCaches").resolves([
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.19.0", "abc-1-1"),
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersion]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(result, []);
|
||||
},
|
||||
);
|
||||
|
||||
const noLanguagesMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
rawLanguages: string[] | undefined,
|
||||
) => {
|
||||
const listStub = sinon.stub(api, "listActionsCaches").resolves([]);
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
rawLanguages,
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersion]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(result, []);
|
||||
t.assert(
|
||||
listStub.notCalled,
|
||||
"Should not list Actions caches without any rawLanguages.",
|
||||
);
|
||||
},
|
||||
title: (providedTitle = "") =>
|
||||
`getEnabledVersionsWithOverlayBaseDatabases does not list caches when rawLanguages is ${providedTitle}`,
|
||||
});
|
||||
|
||||
noLanguagesMacro.serial("undefined", undefined);
|
||||
noLanguagesMacro.serial("an empty array", []);
|
||||
|
||||
test.serial(
|
||||
"getEnabledVersionsWithOverlayBaseDatabases returns empty when listing caches throws",
|
||||
async (t) => {
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
sinon.stub(api, "listActionsCaches").rejects(new Error("listing failed"));
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersion]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(result, []);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getEnabledVersionsWithOverlayBaseDatabases returns versions present in the cache",
|
||||
async (t) => {
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
sinon.stub(api, "listActionsCaches").resolves([
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.20.2", "abc-1-1"),
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersion]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(result, [
|
||||
{ cliVersion: "2.20.2", tagName: "codeql-bundle-v2.20.2" },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getEnabledVersionsWithOverlayBaseDatabases does not list caches when both gates are off",
|
||||
async (t) => {
|
||||
const listStub = sinon.stub(api, "listActionsCaches").resolves([]);
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
createFeatures([]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(result, []);
|
||||
t.assert(
|
||||
listStub.notCalled,
|
||||
"Should not list Actions caches when both gating feature flags are off.",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getEnabledVersionsWithOverlayBaseDatabases dry-run returns empty but lists caches",
|
||||
async (t) => {
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
const listStub = sinon.stub(api, "listActionsCaches").resolves([
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.20.1", "abc-1-1"),
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
createFeatures([Feature.OverlayAnalysisMatchCodeqlVersionDryRun]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(
|
||||
result,
|
||||
[],
|
||||
"Dry-run should return an empty list so the caller falls back.",
|
||||
);
|
||||
t.assert(
|
||||
listStub.calledOnce,
|
||||
"Dry-run should still list Actions caches to populate the diagnostic.",
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
"getEnabledVersionsWithOverlayBaseDatabases match flag wins over dry-run",
|
||||
async (t) => {
|
||||
sinon.stub(api, "getAutomationID").resolves("test/");
|
||||
sinon.stub(api, "listActionsCaches").resolves([
|
||||
{
|
||||
key: await fakeOverlayBaseCacheKey("javascript", "2.20.1", "abc-1-1"),
|
||||
},
|
||||
]);
|
||||
|
||||
const result = await setupCodeql.getEnabledVersionsWithOverlayBaseDatabases(
|
||||
overlayMatchEnabledVersions,
|
||||
["javascript"],
|
||||
createFeatures([
|
||||
Feature.OverlayAnalysisMatchCodeqlVersion,
|
||||
Feature.OverlayAnalysisMatchCodeqlVersionDryRun,
|
||||
]),
|
||||
getRunnerLogger(true),
|
||||
);
|
||||
t.deepEqual(result, [
|
||||
{ cliVersion: "2.20.1", tagName: "codeql-bundle-v2.20.1" },
|
||||
]);
|
||||
},
|
||||
);
|
||||
|
||||
+155
-7
@@ -7,17 +7,27 @@ import { default as deepEqual } from "fast-deep-equal";
|
||||
import * as semver from "semver";
|
||||
import { v4 as uuidV4 } from "uuid";
|
||||
|
||||
import { isDynamicWorkflow, isRunningLocalAction } from "./actions-util";
|
||||
import {
|
||||
isAnalyzingPullRequest,
|
||||
isDynamicWorkflow,
|
||||
isRunningLocalAction,
|
||||
} from "./actions-util";
|
||||
import * as api from "./api-client";
|
||||
import * as defaults from "./defaults.json";
|
||||
import { addNoLanguageDiagnostic, makeDiagnostic } from "./diagnostics";
|
||||
import {
|
||||
addNoLanguageDiagnostic,
|
||||
makeDiagnostic,
|
||||
makeTelemetryDiagnostic,
|
||||
} from "./diagnostics";
|
||||
import {
|
||||
CODEQL_VERSION_ZSTD_BUNDLE,
|
||||
CodeQLDefaultVersionInfo,
|
||||
CodeQLVersionInfo,
|
||||
Feature,
|
||||
FeatureEnablement,
|
||||
} from "./feature-flags";
|
||||
import { Logger } from "./logging";
|
||||
import { getCodeQlVersionsForOverlayBaseDatabases } from "./overlay/caching";
|
||||
import * as tar from "./tar";
|
||||
import {
|
||||
downloadAndExtract,
|
||||
@@ -264,12 +274,131 @@ async function findOverridingToolsInCache(
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sorted set of enabled versions that have cached overlay-base databases for the
|
||||
* given languages, or an empty list if neither the `OverlayAnalysisMatchCodeqlVersion` nor the
|
||||
* `OverlayAnalysisMatchCodeqlVersionDryRun` feature flag is enabled. When only the dry-run flag
|
||||
* is enabled, this performs the lookup and emits a telemetry diagnostic with the version that
|
||||
* would have been chosen, but still returns an empty list so the caller falls back.
|
||||
*/
|
||||
export async function getEnabledVersionsWithOverlayBaseDatabases(
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<CodeQLVersionInfo[]> {
|
||||
if (rawLanguages === undefined || rawLanguages.length === 0) {
|
||||
return [];
|
||||
}
|
||||
const isEnabled = await features.getValue(
|
||||
Feature.OverlayAnalysisMatchCodeqlVersion,
|
||||
);
|
||||
const isDryRun =
|
||||
!isEnabled &&
|
||||
(await features.getValue(Feature.OverlayAnalysisMatchCodeqlVersionDryRun));
|
||||
if (!isEnabled && !isDryRun) {
|
||||
return [];
|
||||
}
|
||||
|
||||
let cachedVersions: string[] | undefined;
|
||||
try {
|
||||
cachedVersions = await getCodeQlVersionsForOverlayBaseDatabases(
|
||||
rawLanguages,
|
||||
logger,
|
||||
);
|
||||
} catch (e) {
|
||||
logger.warning(
|
||||
"Could not list overlay-base databases in the Actions cache while choosing a default " +
|
||||
`CodeQL CLI version, falling back to the highest enabled version. Details: ${util.getErrorMessage(e)}`,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
if (cachedVersions === undefined || cachedVersions.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const cachedVersionsSet = new Set(cachedVersions);
|
||||
const overlayVersions = defaultCliVersion.enabledVersions.filter((v) =>
|
||||
cachedVersionsSet.has(v.cliVersion),
|
||||
);
|
||||
|
||||
if (overlayVersions.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const isCachedVersionDifferent =
|
||||
overlayVersions[0].cliVersion !==
|
||||
defaultCliVersion.enabledVersions[0].cliVersion;
|
||||
|
||||
if (isCachedVersionDifferent) {
|
||||
addNoLanguageDiagnostic(
|
||||
undefined,
|
||||
makeTelemetryDiagnostic(
|
||||
"codeql-action/overlay-aware-default-codeql-version",
|
||||
"Overlay-aware default CodeQL version selection",
|
||||
{
|
||||
cachedVersions,
|
||||
enabledVersions: defaultCliVersion.enabledVersions.map(
|
||||
(v) => v.cliVersion,
|
||||
),
|
||||
isDryRun,
|
||||
overlayAwareVersion: overlayVersions[0].cliVersion,
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (isDryRun) {
|
||||
logger.debug(
|
||||
`Overlay-aware default CodeQL version selection is running in dry-run mode. Would have used version ${overlayVersions[0].cliVersion}.`,
|
||||
);
|
||||
return [];
|
||||
}
|
||||
|
||||
return overlayVersions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the newest enabled default CLI version that has a cached overlay-base database for the
|
||||
* relevant languages, if running a Code Scanning analysis for a pull request and one exists.
|
||||
* Otherwise, falls back to the newest enabled default CLI version.
|
||||
*/
|
||||
async function resolveDefaultCliVersion(
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
useOverlayAwareDefaultCliVersion: boolean,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<CodeQLVersionInfo> {
|
||||
if (!useOverlayAwareDefaultCliVersion || !isAnalyzingPullRequest()) {
|
||||
return defaultCliVersion.enabledVersions[0];
|
||||
}
|
||||
|
||||
const overlayVersions = await getEnabledVersionsWithOverlayBaseDatabases(
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
if (overlayVersions.length > 0) {
|
||||
logger.info(
|
||||
`Using CodeQL version ${overlayVersions[0].cliVersion} since this is the ` +
|
||||
`highest enabled version that has a cached overlay-base database.`,
|
||||
);
|
||||
return overlayVersions[0];
|
||||
}
|
||||
return defaultCliVersion.enabledVersions[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines where the CodeQL CLI we want to use comes from. This can be from a local file,
|
||||
* the Actions toolcache, or a download.
|
||||
*
|
||||
* @param toolsInput The argument provided for the `tools` input, if any.
|
||||
* @param defaultCliVersion The default CLI version that's linked to the CodeQL Action.
|
||||
* @param rawLanguages Raw set of languages.
|
||||
* @param useOverlayAwareDefaultCliVersion Whether to select an overlay-aware default CLI version.
|
||||
* @param apiDetails Information about the GitHub API.
|
||||
* @param variant The GitHub variant we are running on.
|
||||
* @param tarSupportsZstd Whether zstd is supported by `tar`.
|
||||
@@ -281,6 +410,8 @@ async function findOverridingToolsInCache(
|
||||
export async function getCodeQLSource(
|
||||
toolsInput: string | undefined,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
useOverlayAwareDefaultCliVersion: boolean,
|
||||
apiDetails: api.GitHubApiDetails,
|
||||
variant: util.GitHubVariant,
|
||||
tarSupportsZstd: boolean,
|
||||
@@ -438,8 +569,15 @@ export async function getCodeQLSource(
|
||||
}
|
||||
}
|
||||
|
||||
cliVersion = defaultCliVersion.cliVersion;
|
||||
tagName = defaultCliVersion.tagName;
|
||||
const version = await resolveDefaultCliVersion(
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
cliVersion = version.cliVersion;
|
||||
tagName = version.tagName;
|
||||
}
|
||||
} else if (toolsInput !== undefined) {
|
||||
// If a tools URL was provided, then use that.
|
||||
@@ -454,9 +592,15 @@ export async function getCodeQLSource(
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Otherwise, use the default CLI version passed in.
|
||||
cliVersion = defaultCliVersion.cliVersion;
|
||||
tagName = defaultCliVersion.tagName;
|
||||
const version = await resolveDefaultCliVersion(
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
cliVersion = version.cliVersion;
|
||||
tagName = version.tagName;
|
||||
}
|
||||
|
||||
const bundleVersion =
|
||||
@@ -791,6 +935,8 @@ export async function setupCodeQLBundle(
|
||||
tempDir: string,
|
||||
variant: util.GitHubVariant,
|
||||
defaultCliVersion: CodeQLDefaultVersionInfo,
|
||||
rawLanguages: string[] | undefined,
|
||||
useOverlayAwareDefaultCliVersion: boolean,
|
||||
features: FeatureEnablement,
|
||||
logger: Logger,
|
||||
): Promise<SetupCodeQLResult> {
|
||||
@@ -804,6 +950,8 @@ export async function setupCodeQLBundle(
|
||||
const source = await getCodeQLSource(
|
||||
toolsInput,
|
||||
defaultCliVersion,
|
||||
rawLanguages,
|
||||
useOverlayAwareDefaultCliVersion,
|
||||
apiDetails,
|
||||
variant,
|
||||
zstdAvailability.available,
|
||||
|
||||
@@ -12,7 +12,7 @@ import { uploadArtifacts } from "./debug-artifacts";
|
||||
import { getActionsLogger } from "./logging";
|
||||
import { checkGitHubVersionInRange, getErrorMessage } from "./util";
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
// To capture errors appropriately, keep as much code within the try-catch as
|
||||
// possible, and only use safe functions outside.
|
||||
|
||||
@@ -62,5 +62,3 @@ async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -128,7 +128,7 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
}
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
|
||||
@@ -198,10 +198,9 @@ async function startProxy(
|
||||
.map((credential) => ({
|
||||
type: credential.type,
|
||||
url: credential.url,
|
||||
"replaces-base": credential["replaces-base"],
|
||||
}));
|
||||
core.setOutput("proxy_urls", JSON.stringify(registry_urls));
|
||||
|
||||
return { host, port, cert: config.ca.cert, registries: registry_urls };
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
+140
-152
@@ -8,6 +8,8 @@ import sinon from "sinon";
|
||||
import * as apiClient from "./api-client";
|
||||
import * as defaults from "./defaults.json";
|
||||
import { setUpFeatureFlagTests } from "./feature-flags/testing-util";
|
||||
import { UnvalidatedObject, validateSchema } from "./json";
|
||||
import { makeFromSchema } from "./json/testing-util";
|
||||
import { BuiltInLanguage } from "./languages";
|
||||
import { getRunnerLogger, Logger } from "./logging";
|
||||
import * as startProxyExports from "./start-proxy";
|
||||
@@ -16,6 +18,7 @@ import {
|
||||
assertNotLogged,
|
||||
checkExpectedLogMessages,
|
||||
createFeatures,
|
||||
makeMacro,
|
||||
makeTestToken,
|
||||
RecordingLogger,
|
||||
setupTests,
|
||||
@@ -30,7 +33,7 @@ import {
|
||||
|
||||
setupTests(test);
|
||||
|
||||
const sendFailedStatusReportTest = test.macro({
|
||||
const sendFailedStatusReportTest = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
err: Error,
|
||||
@@ -86,16 +89,14 @@ const sendFailedStatusReportTest = test.macro({
|
||||
title: (providedTitle = "") => `sendFailedStatusReport - ${providedTitle}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
sendFailedStatusReportTest.serial(
|
||||
"reports generic error message for non-StartProxyError error",
|
||||
sendFailedStatusReportTest,
|
||||
new Error("Something went wrong today"),
|
||||
"Error from start-proxy Action omitted (Error).",
|
||||
);
|
||||
|
||||
test.serial(
|
||||
sendFailedStatusReportTest.serial(
|
||||
"reports generic error message for non-StartProxyError error with safe error message",
|
||||
sendFailedStatusReportTest,
|
||||
new Error(
|
||||
startProxyExports.getStartProxyErrorMessage(
|
||||
startProxyExports.StartProxyErrorType.DownloadFailed,
|
||||
@@ -104,9 +105,8 @@ test.serial(
|
||||
"Error from start-proxy Action omitted (Error).",
|
||||
);
|
||||
|
||||
test.serial(
|
||||
sendFailedStatusReportTest.serial(
|
||||
"reports generic error message for ConfigurationError error",
|
||||
sendFailedStatusReportTest,
|
||||
new ConfigurationError("Something went wrong today"),
|
||||
"Error from start-proxy Action omitted (ConfigurationError).",
|
||||
"user-error",
|
||||
@@ -349,131 +349,46 @@ test("getCredentials throws an error when non-printable characters are used", as
|
||||
}
|
||||
});
|
||||
|
||||
const validAzureCredential: startProxyExports.AzureConfig = {
|
||||
"tenant-id": "12345678-1234-1234-1234-123456789012",
|
||||
"client-id": "abcdef01-2345-6789-abcd-ef0123456789",
|
||||
};
|
||||
for (const oidcSchemaInfo of startProxyExports.oidcSchemas) {
|
||||
test(`getCredentials throws when non-printable characters are used (${oidcSchemaInfo.name} OIDC)`, (t) => {
|
||||
const validCredential = makeFromSchema(true, oidcSchemaInfo.schema);
|
||||
for (const key of Object.keys(validCredential)) {
|
||||
const invalidAuthConfig = {
|
||||
...validCredential,
|
||||
[key]: "123\x00",
|
||||
};
|
||||
const invalidCredential: startProxyExports.RawCredential = {
|
||||
type: "nuget_feed",
|
||||
host: `${key}.nuget.pkg.github.com`,
|
||||
...invalidAuthConfig,
|
||||
};
|
||||
const credentialsInput = toEncodedJSON([invalidCredential]);
|
||||
|
||||
const validAwsCredential: startProxyExports.AWSConfig = {
|
||||
"aws-region": "us-east-1",
|
||||
"account-id": "123456789012",
|
||||
"role-name": "MY_ROLE",
|
||||
domain: "MY_DOMAIN",
|
||||
"domain-owner": "987654321098",
|
||||
audience: "custom-audience",
|
||||
};
|
||||
|
||||
const validJFrogCredential: startProxyExports.JFrogConfig = {
|
||||
"jfrog-oidc-provider-name": "MY_PROVIDER",
|
||||
audience: "jfrog-audience",
|
||||
"identity-mapping-name": "my-mapping",
|
||||
};
|
||||
|
||||
test("getCredentials throws an error when non-printable characters are used for Azure OIDC", (t) => {
|
||||
for (const key of Object.keys(validAzureCredential)) {
|
||||
const invalidAzureCredential = {
|
||||
...validAzureCredential,
|
||||
[key]: "123\x00",
|
||||
};
|
||||
const invalidCredential: startProxyExports.RawCredential = {
|
||||
type: "nuget_feed",
|
||||
host: `${key}.nuget.pkg.github.com`,
|
||||
...invalidAzureCredential,
|
||||
};
|
||||
const credentialsInput = toEncodedJSON([invalidCredential]);
|
||||
|
||||
t.throws(
|
||||
() =>
|
||||
startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
credentialsInput,
|
||||
undefined,
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Invalid credentials - fields must contain only printable characters",
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("getCredentials throws an error when non-printable characters are used for AWS OIDC", (t) => {
|
||||
for (const key of Object.keys(validAwsCredential)) {
|
||||
const invalidAwsCredential = {
|
||||
...validAwsCredential,
|
||||
[key]: "123\x00",
|
||||
};
|
||||
const invalidCredential: startProxyExports.RawCredential = {
|
||||
type: "nuget_feed",
|
||||
host: `${key}.nuget.pkg.github.com`,
|
||||
...invalidAwsCredential,
|
||||
};
|
||||
const credentialsInput = toEncodedJSON([invalidCredential]);
|
||||
|
||||
t.throws(
|
||||
() =>
|
||||
startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
credentialsInput,
|
||||
undefined,
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Invalid credentials - fields must contain only printable characters",
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
test("getCredentials throws an error when non-printable characters are used for JFrog OIDC", (t) => {
|
||||
for (const key of Object.keys(validJFrogCredential)) {
|
||||
const invalidJFrogCredential = {
|
||||
...validJFrogCredential,
|
||||
[key]: "123\x00",
|
||||
};
|
||||
const invalidCredential: startProxyExports.RawCredential = {
|
||||
type: "nuget_feed",
|
||||
host: `${key}.nuget.pkg.github.com`,
|
||||
...invalidJFrogCredential,
|
||||
};
|
||||
const credentialsInput = toEncodedJSON([invalidCredential]);
|
||||
|
||||
t.throws(
|
||||
() =>
|
||||
startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
credentialsInput,
|
||||
undefined,
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Invalid credentials - fields must contain only printable characters",
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
t.throws(
|
||||
() =>
|
||||
startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
credentialsInput,
|
||||
undefined,
|
||||
),
|
||||
{
|
||||
message:
|
||||
"Invalid credentials - fields must contain only printable characters",
|
||||
},
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
test("getCredentials accepts OIDC configurations", (t) => {
|
||||
const oidcConfigurations = [
|
||||
{
|
||||
const oidcConfigurations = startProxyExports.oidcSchemas.map(
|
||||
(schemaInfo) => ({
|
||||
type: "nuget_feed",
|
||||
host: "azure.pkg.github.com",
|
||||
...validAzureCredential,
|
||||
},
|
||||
{
|
||||
type: "nuget_feed",
|
||||
host: "aws.pkg.github.com",
|
||||
...validAwsCredential,
|
||||
},
|
||||
{
|
||||
type: "nuget_feed",
|
||||
host: "jfrog.pkg.github.com",
|
||||
...validJFrogCredential,
|
||||
},
|
||||
];
|
||||
host: `${schemaInfo.name.toLowerCase()}.pkg.github.com`,
|
||||
...makeFromSchema(true, schemaInfo.schema),
|
||||
}),
|
||||
);
|
||||
|
||||
const credentials = startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
@@ -481,15 +396,23 @@ test("getCredentials accepts OIDC configurations", (t) => {
|
||||
toEncodedJSON(oidcConfigurations),
|
||||
BuiltInLanguage.csharp,
|
||||
);
|
||||
t.is(credentials.length, 3);
|
||||
t.is(credentials.length, startProxyExports.oidcSchemas.length);
|
||||
|
||||
t.assert(credentials.every((c) => c.type === "nuget_feed"));
|
||||
t.assert(credentials.some((c) => startProxyExports.isAzureConfig(c)));
|
||||
t.assert(credentials.some((c) => startProxyExports.isAWSConfig(c)));
|
||||
t.assert(credentials.some((c) => startProxyExports.isJFrogConfig(c)));
|
||||
|
||||
for (const oidcSchemaInfo of startProxyExports.oidcSchemas) {
|
||||
t.assert(
|
||||
credentials.some((c) =>
|
||||
validateSchema(
|
||||
oidcSchemaInfo.schema,
|
||||
c as unknown as UnvalidatedObject<any>,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const getCredentialsMacro = test.macro({
|
||||
const getCredentialsMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
credentials: startProxyExports.RawCredential[],
|
||||
@@ -515,9 +438,8 @@ const getCredentialsMacro = test.macro({
|
||||
title: (providedTitle = "") => `getCredentials - ${providedTitle}`,
|
||||
});
|
||||
|
||||
test(
|
||||
getCredentialsMacro(
|
||||
"warns for PAT-like password without a username",
|
||||
getCredentialsMacro,
|
||||
[
|
||||
{
|
||||
type: "git_server",
|
||||
@@ -532,7 +454,7 @@ test(
|
||||
t.is(results[0].type, "git_server");
|
||||
t.is(results[0].host, "https://github.com/");
|
||||
|
||||
if (startProxyExports.isUsernamePassword(results[0])) {
|
||||
if (startProxyExports.hasUsernameAndPassword(results[0])) {
|
||||
t.assert(results[0].password?.startsWith("ghp_"));
|
||||
} else {
|
||||
t.fail("Expected a `UsernamePassword`-based credential.");
|
||||
@@ -545,9 +467,8 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
getCredentialsMacro(
|
||||
"no warning for PAT-like password with a username",
|
||||
getCredentialsMacro,
|
||||
[
|
||||
{
|
||||
type: "git_server",
|
||||
@@ -563,7 +484,7 @@ test(
|
||||
t.is(results[0].type, "git_server");
|
||||
t.is(results[0].host, "https://github.com/");
|
||||
|
||||
if (startProxyExports.isUsernamePassword(results[0])) {
|
||||
if (startProxyExports.hasUsernameAndPassword(results[0])) {
|
||||
t.assert(results[0].password?.startsWith("ghp_"));
|
||||
} else {
|
||||
t.fail("Expected a `UsernamePassword`-based credential.");
|
||||
@@ -577,9 +498,8 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
getCredentialsMacro(
|
||||
"warns for PAT-like token without a username",
|
||||
getCredentialsMacro,
|
||||
[
|
||||
{
|
||||
type: "git_server",
|
||||
@@ -607,9 +527,8 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test(
|
||||
getCredentialsMacro(
|
||||
"no warning for PAT-like token with a username",
|
||||
getCredentialsMacro,
|
||||
[
|
||||
{
|
||||
type: "git_server",
|
||||
@@ -639,6 +558,76 @@ test(
|
||||
},
|
||||
);
|
||||
|
||||
test("getCredentials validates 'replaces-base' correctly", async (t) => {
|
||||
// Valid cases.
|
||||
const credentialsInput = toEncodedJSON([
|
||||
{
|
||||
type: "maven_repository",
|
||||
host: "maven1.pkg.github.com",
|
||||
token: "abc",
|
||||
"replaces-base": false,
|
||||
},
|
||||
{
|
||||
type: "maven_repository",
|
||||
host: "maven2.pkg.github.com",
|
||||
token: "def",
|
||||
"replaces-base": true,
|
||||
},
|
||||
{
|
||||
type: "maven_repository",
|
||||
host: "maven3.pkg.github.com",
|
||||
token: "ghi",
|
||||
},
|
||||
]);
|
||||
|
||||
const credentials = startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
credentialsInput,
|
||||
BuiltInLanguage.java,
|
||||
false,
|
||||
);
|
||||
|
||||
t.is(credentials.length, 3);
|
||||
t.true(credentials.some((c) => c["replaces-base"] === true));
|
||||
t.true(credentials.some((c) => c["replaces-base"] === false));
|
||||
t.true(credentials.some((c) => c["replaces-base"] === undefined));
|
||||
|
||||
// Invalid cases.
|
||||
const baseInvalid = {
|
||||
type: "maven_repository",
|
||||
host: "maven4.pkg.github.com",
|
||||
token: "jkl",
|
||||
};
|
||||
t.throws(() =>
|
||||
startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
toEncodedJSON([{ ...baseInvalid, "replaces-base": null }]),
|
||||
BuiltInLanguage.actions,
|
||||
false,
|
||||
),
|
||||
);
|
||||
t.throws(() =>
|
||||
startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
toEncodedJSON([{ ...baseInvalid, "replaces-base": 123 }]),
|
||||
BuiltInLanguage.actions,
|
||||
false,
|
||||
),
|
||||
);
|
||||
t.throws(() =>
|
||||
startProxyExports.getCredentials(
|
||||
getRunnerLogger(true),
|
||||
undefined,
|
||||
toEncodedJSON([{ ...baseInvalid, "replaces-base": "true" }]),
|
||||
BuiltInLanguage.actions,
|
||||
false,
|
||||
),
|
||||
);
|
||||
});
|
||||
|
||||
test("getCredentials returns all credentials for Actions when using LANGUAGE_TO_REGISTRY_TYPE", async (t) => {
|
||||
const credentialsInput = toEncodedJSON(mixedCredentials);
|
||||
|
||||
@@ -801,7 +790,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
const wrapFailureTest = test.macro({
|
||||
const wrapFailureTest = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
setup: () => void,
|
||||
@@ -832,9 +821,8 @@ test.serial("downloadProxy - returns file path on success", async (t) => {
|
||||
});
|
||||
});
|
||||
|
||||
test.serial(
|
||||
wrapFailureTest.serial(
|
||||
"downloadProxy",
|
||||
wrapFailureTest,
|
||||
() => {
|
||||
sinon.stub(toolcache, "downloadTool").throws();
|
||||
},
|
||||
@@ -853,9 +841,8 @@ test.serial("extractProxy - returns file path on success", async (t) => {
|
||||
});
|
||||
});
|
||||
|
||||
test.serial(
|
||||
wrapFailureTest.serial(
|
||||
"extractProxy",
|
||||
wrapFailureTest,
|
||||
() => {
|
||||
sinon.stub(toolcache, "extractTar").throws();
|
||||
},
|
||||
@@ -879,9 +866,8 @@ test.serial("cacheProxy - returns file path on success", async (t) => {
|
||||
});
|
||||
});
|
||||
|
||||
test.serial(
|
||||
wrapFailureTest.serial(
|
||||
"cacheProxy",
|
||||
wrapFailureTest,
|
||||
() => {
|
||||
sinon.stub(toolcache, "cacheDir").throws();
|
||||
},
|
||||
@@ -1024,8 +1010,10 @@ test.serial(
|
||||
return true;
|
||||
});
|
||||
const getDefaultCliVersion = sinon
|
||||
.stub(features, "getDefaultCliVersion")
|
||||
.resolves({ cliVersion: "2.20.1", tagName: expectedTag });
|
||||
.stub(features, "getEnabledDefaultCliVersions")
|
||||
.resolves({
|
||||
enabledVersions: [{ cliVersion: "2.20.1", tagName: expectedTag }],
|
||||
});
|
||||
const path = await startProxyExports.getProxyBinaryPath(logger, features);
|
||||
|
||||
t.assert(getDefaultCliVersion.calledOnce);
|
||||
|
||||
+25
-85
@@ -24,20 +24,12 @@ import {
|
||||
Address,
|
||||
Registry,
|
||||
Credential,
|
||||
AuthConfig,
|
||||
isToken,
|
||||
isAzureConfig,
|
||||
Token,
|
||||
UsernamePassword,
|
||||
AzureConfig,
|
||||
isAWSConfig,
|
||||
AWSConfig,
|
||||
isJFrogConfig,
|
||||
JFrogConfig,
|
||||
isUsernamePassword,
|
||||
hasToken,
|
||||
hasUsernameAndPassword,
|
||||
hasUsername,
|
||||
RawCredential,
|
||||
} from "./start-proxy/types";
|
||||
import { getAuthConfig } from "./start-proxy/validation";
|
||||
import {
|
||||
ActionName,
|
||||
createStatusReportBase,
|
||||
@@ -251,75 +243,6 @@ function getRegistryAddress(
|
||||
}
|
||||
}
|
||||
|
||||
/** Extracts an `AuthConfig` value from `config`. */
|
||||
export function getAuthConfig(
|
||||
config: json.UnvalidatedObject<AuthConfig>,
|
||||
): AuthConfig {
|
||||
// Start by checking for the OIDC configurations, since they have required properties
|
||||
// which we can use to identify them.
|
||||
if (isAzureConfig(config)) {
|
||||
return {
|
||||
"tenant-id": config["tenant-id"],
|
||||
"client-id": config["client-id"],
|
||||
} satisfies AzureConfig;
|
||||
} else if (isAWSConfig(config)) {
|
||||
return {
|
||||
"aws-region": config["aws-region"],
|
||||
"account-id": config["account-id"],
|
||||
"role-name": config["role-name"],
|
||||
domain: config.domain,
|
||||
"domain-owner": config["domain-owner"],
|
||||
audience: config.audience,
|
||||
} satisfies AWSConfig;
|
||||
} else if (isJFrogConfig(config)) {
|
||||
return {
|
||||
"jfrog-oidc-provider-name": config["jfrog-oidc-provider-name"],
|
||||
"identity-mapping-name": config["identity-mapping-name"],
|
||||
audience: config.audience,
|
||||
} satisfies JFrogConfig;
|
||||
} else if (isToken(config)) {
|
||||
// There are three scenarios for non-OIDC authentication based on the registry type:
|
||||
//
|
||||
// 1. `username`+`token`
|
||||
// 2. A `token` that combines the username and actual token, separated by ':'.
|
||||
// 3. `username`+`password`
|
||||
//
|
||||
// In all three cases, all fields are optional. If the `token` field is present,
|
||||
// we accept the configuration as a `Token` typed configuration, with the `token`
|
||||
// value and an optional `username`. Otherwise, we accept the configuration
|
||||
// typed as `UsernamePassword` (in the `else` clause below) with optional
|
||||
// username and password. I.e. a private registry type that uses 1. or 2.,
|
||||
// but has no `token` configured, will get accepted as `UsernamePassword` here.
|
||||
|
||||
if (isDefined(config.token)) {
|
||||
// Mask token to reduce chance of accidental leakage in logs, if we have one.
|
||||
core.setSecret(config.token);
|
||||
}
|
||||
|
||||
return { username: config.username, token: config.token } satisfies Token;
|
||||
} else {
|
||||
let username: string | undefined = undefined;
|
||||
let password: string | undefined = undefined;
|
||||
|
||||
// Both "username" and "password" are optional. If we have reached this point, we need
|
||||
// to validate which of them are present and that they have the correct type if so.
|
||||
if ("password" in config && json.isString(config.password)) {
|
||||
// Mask password to reduce chance of accidental leakage in logs, if we have one.
|
||||
core.setSecret(config.password);
|
||||
password = config.password;
|
||||
}
|
||||
if ("username" in config && json.isString(config.username)) {
|
||||
username = config.username;
|
||||
}
|
||||
|
||||
// Return the `UsernamePassword` object. Both username and password may be undefined.
|
||||
return {
|
||||
username,
|
||||
password,
|
||||
} satisfies UsernamePassword;
|
||||
}
|
||||
}
|
||||
|
||||
// getCredentials returns registry credentials from action inputs.
|
||||
// It prefers `registries_credentials` over `registry_secrets`.
|
||||
// If neither is set, it returns an empty array.
|
||||
@@ -408,11 +331,11 @@ export function getCredentials(
|
||||
const noUsername =
|
||||
!hasUsername(authConfig) || !isDefined(authConfig.username);
|
||||
const passwordIsPAT =
|
||||
isUsernamePassword(authConfig) &&
|
||||
hasUsernameAndPassword(authConfig) &&
|
||||
isDefined(authConfig.password) &&
|
||||
isPAT(authConfig.password);
|
||||
const tokenIsPAT =
|
||||
isToken(authConfig) &&
|
||||
hasToken(authConfig) &&
|
||||
isDefined(authConfig.token) &&
|
||||
isPAT(authConfig.token);
|
||||
|
||||
@@ -424,8 +347,25 @@ export function getCredentials(
|
||||
);
|
||||
}
|
||||
|
||||
// Construct the base credential object.
|
||||
const baseCredential: Omit<Registry, keyof Address> = { type: e.type };
|
||||
|
||||
// If "replaces-base" is present, it must be a boolean.
|
||||
if ("replaces-base" in e) {
|
||||
if (
|
||||
isDefined(e["replaces-base"]) &&
|
||||
typeof e["replaces-base"] === "boolean"
|
||||
) {
|
||||
baseCredential["replaces-base"] = e["replaces-base"];
|
||||
} else {
|
||||
throw new ConfigurationError(
|
||||
"Invalid credentials - 'replaces-base' must be a boolean",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
out.push({
|
||||
type: e.type,
|
||||
...baseCredential,
|
||||
...authConfig,
|
||||
...address,
|
||||
});
|
||||
@@ -475,7 +415,7 @@ async function getCliVersionFromFeatures(
|
||||
features: FeatureEnablement,
|
||||
): Promise<CodeQLDefaultVersionInfo> {
|
||||
const gitHubVersion = await getGitHubVersion();
|
||||
return await features.getDefaultCliVersion(gitHubVersion.type);
|
||||
return await features.getEnabledDefaultCliVersions(gitHubVersion.type);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -500,7 +440,7 @@ export async function getDownloadUrl(
|
||||
// Retrieve information about the CLI version we should use. This will be either the linked
|
||||
// version, or the one enabled by FFs.
|
||||
const versionInfo = useFeaturesToDetermineCLI
|
||||
? await getCliVersionFromFeatures(features)
|
||||
? (await getCliVersionFromFeatures(features)).enabledVersions[0]
|
||||
: {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import test from "ava";
|
||||
|
||||
import { makeFromSchema, withSchemaMatrix } from "../json/testing-util";
|
||||
import { setupTests } from "../testing-utils";
|
||||
|
||||
import * as types from "./types";
|
||||
@@ -26,6 +27,38 @@ const validJFrogCredential: types.JFrogConfig = {
|
||||
"identity-mapping-name": "my-mapping",
|
||||
};
|
||||
|
||||
test("hasUsername", (t) => {
|
||||
// Reject the case where `username` is missing.
|
||||
t.false(types.hasUsername({}));
|
||||
|
||||
// Test all cases where `username` is present.
|
||||
withSchemaMatrix(
|
||||
t,
|
||||
types.usernameSchema,
|
||||
{ excludeAbsent: true },
|
||||
(value) => {
|
||||
t.true(types.hasUsername(value));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("hasUsernameAndPassword", (t) => {
|
||||
// Reject cases where `username` or `password` are missing.
|
||||
t.false(types.hasUsernameAndPassword({}));
|
||||
t.false(types.hasUsernameAndPassword({ username: "foo" }));
|
||||
t.false(types.hasUsernameAndPassword({ password: "foo" }));
|
||||
|
||||
// Test all cases where both `username` and `password` are present.
|
||||
withSchemaMatrix(
|
||||
t,
|
||||
types.usernamePasswordSchema,
|
||||
{ excludeAbsent: true },
|
||||
(value) => {
|
||||
t.true(types.hasUsernameAndPassword(value));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
test("credentialToStr - pretty-prints valid username+password configurations", (t) => {
|
||||
const secret = "password123";
|
||||
const credential: types.Credential = {
|
||||
@@ -107,13 +140,46 @@ test("credentialToStr - pretty-prints valid JFrog OIDC configurations", (t) => {
|
||||
);
|
||||
});
|
||||
|
||||
test("credentialToStr - pretty-prints valid Cloudsmith OIDC configurations", (t) => {
|
||||
const credential: types.Credential = {
|
||||
type: "maven_credential",
|
||||
url: "https://localhost",
|
||||
...(makeFromSchema(
|
||||
true,
|
||||
types.cloudsmithConfigSchema,
|
||||
) as types.CloudsmithConfig),
|
||||
};
|
||||
|
||||
const str = types.credentialToStr(credential);
|
||||
|
||||
t.is(
|
||||
"Type: maven_credential; Url: https://localhost; Cloudsmith Namespace: value-for-namespace; Cloudsmith Service Slug: value-for-service-slug; Cloudsmith API Host: value-for-api-host;",
|
||||
str,
|
||||
);
|
||||
});
|
||||
|
||||
test("credentialToStr - pretty-prints valid GCP OIDC configurations", (t) => {
|
||||
const credential: types.Credential = {
|
||||
type: "maven_credential",
|
||||
url: "https://localhost",
|
||||
...(makeFromSchema(true, types.gcpConfigSchema) as types.GCPConfig),
|
||||
};
|
||||
|
||||
const str = types.credentialToStr(credential);
|
||||
|
||||
t.is(
|
||||
"Type: maven_credential; Url: https://localhost; GCP Workload Identity Provider: value-for-workload-identity-provider; GCP Service Account: value-for-service-account; GCP Audience: value-for-audience;",
|
||||
str,
|
||||
);
|
||||
});
|
||||
|
||||
test("credentialToStr - hides passwords", (t) => {
|
||||
const secret = "password123";
|
||||
const credential = {
|
||||
type: "maven_credential",
|
||||
password: secret,
|
||||
url: "https://localhost",
|
||||
};
|
||||
} satisfies types.Credential;
|
||||
|
||||
const str = types.credentialToStr(credential);
|
||||
|
||||
@@ -127,7 +193,7 @@ test("credentialToStr - hides tokens", (t) => {
|
||||
type: "maven_credential",
|
||||
token: secret,
|
||||
url: "https://localhost",
|
||||
};
|
||||
} satisfies types.Credential;
|
||||
|
||||
const str = types.credentialToStr(credential);
|
||||
|
||||
|
||||
+134
-88
@@ -9,144 +9,177 @@ import { isDefined } from "../util";
|
||||
*/
|
||||
export type RawCredential = UnvalidatedObject<Credential>;
|
||||
|
||||
/** Usernames may be present for both authentication with tokens or passwords. */
|
||||
export type Username = {
|
||||
/** A schema for credential objects with a username. */
|
||||
export const usernameSchema = {
|
||||
/** The username needed to authenticate to the package registry, if any. */
|
||||
username?: string;
|
||||
};
|
||||
username: json.optional(json.string),
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/** Decides whether `config` has a username. */
|
||||
/** Usernames may be present for both authentication with tokens or passwords. */
|
||||
export type Username = json.FromSchema<typeof usernameSchema>;
|
||||
|
||||
/**
|
||||
* Narrows `config` to `Username` if `config` has a `username` property.
|
||||
* Not used for validation. Assumes that `config` is already a validated `AuthConfig`.
|
||||
*/
|
||||
export function hasUsername(config: AuthConfig): config is Username {
|
||||
return "username" in config;
|
||||
}
|
||||
|
||||
/** A schema for credential objects with a username and password. */
|
||||
export const usernamePasswordSchema = {
|
||||
/** The password needed to authenticate to the package registry, if any. */
|
||||
password: json.optional(json.string),
|
||||
...usernameSchema,
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/**
|
||||
* Fields expected for authentication based on a username and password.
|
||||
* Both username and password are optional.
|
||||
*/
|
||||
export type UsernamePassword = {
|
||||
/** The password needed to authenticate to the package registry, if any. */
|
||||
password?: string;
|
||||
} & Username;
|
||||
export type UsernamePassword = json.FromSchema<typeof usernamePasswordSchema>;
|
||||
|
||||
/** Decides whether `config` is based on a username and password. */
|
||||
export function isUsernamePassword(
|
||||
/**
|
||||
* Narrows `config` to `UsernamePassword` if it has a `username` and `password` property.
|
||||
* Not used for validation. Assumes that `config` is already a validated `AuthConfig`.
|
||||
*/
|
||||
export function hasUsernameAndPassword(
|
||||
config: AuthConfig,
|
||||
): config is UsernamePassword {
|
||||
return hasUsername(config) && "password" in config;
|
||||
}
|
||||
|
||||
/** A schema for credential objects for token-based authentication. */
|
||||
export const tokenSchema = {
|
||||
/** The token needed to authenticate to the package registry, if any. */
|
||||
token: json.optional(json.string),
|
||||
...usernameSchema,
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/**
|
||||
* Fields expected for token-based authentication.
|
||||
* Both username and token are optional.
|
||||
*/
|
||||
export type Token = {
|
||||
/** The token needed to authenticate to the package registry, if any. */
|
||||
token?: string;
|
||||
} & Username;
|
||||
export type Token = json.FromSchema<typeof tokenSchema>;
|
||||
|
||||
/**
|
||||
* Narrows `config` to `Token` if it has a `token` property.
|
||||
* Not used for validation. Assumes that `config` is already a validated `AuthConfig`.
|
||||
*/
|
||||
export function hasToken(config: AuthConfig): config is Token {
|
||||
return "token" in config;
|
||||
}
|
||||
|
||||
/** Decides whether `config` is token-based. */
|
||||
export function isToken(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is Token {
|
||||
// The "username" field is optional, but should be a string if present.
|
||||
if ("username" in config && !json.isStringOrUndefined(config.username)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// The "token" field is required, and must be a string or undefined.
|
||||
return "token" in config && json.isStringOrUndefined(config.token);
|
||||
return "token" in config && json.validateSchema(tokenSchema, config);
|
||||
}
|
||||
|
||||
/** A schema for Azure OIDC configurations. */
|
||||
export const azureConfigSchema = {
|
||||
"tenant-id": json.string,
|
||||
"client-id": json.string,
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/** Configuration for Azure OIDC. */
|
||||
export type AzureConfig = { "tenant-id": string; "client-id": string };
|
||||
export type AzureConfig = json.FromSchema<typeof azureConfigSchema>;
|
||||
|
||||
/** Decides whether `config` is an Azure OIDC configuration. */
|
||||
export function isAzureConfig(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is AzureConfig {
|
||||
return (
|
||||
"tenant-id" in config &&
|
||||
"client-id" in config &&
|
||||
isDefined(config["tenant-id"]) &&
|
||||
isDefined(config["client-id"]) &&
|
||||
json.isString(config["tenant-id"]) &&
|
||||
json.isString(config["client-id"])
|
||||
);
|
||||
return json.validateSchema(azureConfigSchema, config);
|
||||
}
|
||||
|
||||
/** A schema for AWS OIDC configurations. */
|
||||
export const awsConfigSchema = {
|
||||
"aws-region": json.string,
|
||||
"account-id": json.string,
|
||||
"role-name": json.string,
|
||||
domain: json.string,
|
||||
"domain-owner": json.string,
|
||||
audience: json.optional(json.string),
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/** Configuration for AWS OIDC. */
|
||||
export type AWSConfig = {
|
||||
"aws-region": string;
|
||||
"account-id": string;
|
||||
"role-name": string;
|
||||
domain: string;
|
||||
"domain-owner": string;
|
||||
audience?: string;
|
||||
};
|
||||
export type AWSConfig = json.FromSchema<typeof awsConfigSchema>;
|
||||
|
||||
/** Decides whether `config` is an AWS OIDC configuration. */
|
||||
export function isAWSConfig(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is AWSConfig {
|
||||
// All of these properties are required.
|
||||
const requiredProperties = [
|
||||
"aws-region",
|
||||
"account-id",
|
||||
"role-name",
|
||||
"domain",
|
||||
"domain-owner",
|
||||
];
|
||||
|
||||
for (const property of requiredProperties) {
|
||||
if (
|
||||
!(property in config) ||
|
||||
!isDefined(config[property]) ||
|
||||
!json.isString(config[property])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The "audience" field is optional, but should be a string if present.
|
||||
if ("audience" in config && !json.isStringOrUndefined(config.audience)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return json.validateSchema(awsConfigSchema, config);
|
||||
}
|
||||
|
||||
/** A schema for JFrog OIDC configurations. */
|
||||
export const jfrogConfigSchema = {
|
||||
"jfrog-oidc-provider-name": json.string,
|
||||
audience: json.optional(json.string),
|
||||
"identity-mapping-name": json.optional(json.string),
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/** Configuration for JFrog OIDC. */
|
||||
export type JFrogConfig = {
|
||||
"jfrog-oidc-provider-name": string;
|
||||
audience?: string;
|
||||
"identity-mapping-name"?: string;
|
||||
};
|
||||
export type JFrogConfig = json.FromSchema<typeof jfrogConfigSchema>;
|
||||
|
||||
/** Decides whether `config` is a JFrog OIDC configuration. */
|
||||
export function isJFrogConfig(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is JFrogConfig {
|
||||
// The "audience" and "identity-mapping-name" fields are optional, but should be strings if present.
|
||||
if ("audience" in config && !json.isStringOrUndefined(config.audience)) {
|
||||
return false;
|
||||
}
|
||||
if (
|
||||
"identity-mapping-name" in config &&
|
||||
!json.isStringOrUndefined(config["identity-mapping-name"])
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (
|
||||
"jfrog-oidc-provider-name" in config &&
|
||||
isDefined(config["jfrog-oidc-provider-name"]) &&
|
||||
json.isString(config["jfrog-oidc-provider-name"])
|
||||
);
|
||||
return json.validateSchema(jfrogConfigSchema, config);
|
||||
}
|
||||
|
||||
/** A schema for Cloudsmith OIDC configurations. */
|
||||
export const cloudsmithConfigSchema = {
|
||||
namespace: json.string,
|
||||
"service-slug": json.string,
|
||||
"api-host": json.string,
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/** Configuration for Cloudsmith OIDC. */
|
||||
export type CloudsmithConfig = json.FromSchema<typeof cloudsmithConfigSchema>;
|
||||
|
||||
/** Decides whether `config` is a Cloudsmith OIDC configuration. */
|
||||
export function isCloudsmithConfig(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is CloudsmithConfig {
|
||||
return json.validateSchema(cloudsmithConfigSchema, config);
|
||||
}
|
||||
|
||||
/** A schema for GCP OIDC configurations. */
|
||||
export const gcpConfigSchema = {
|
||||
"workload-identity-provider": json.string,
|
||||
"service-account": json.optional(json.string),
|
||||
audience: json.optional(json.string),
|
||||
} as const satisfies json.Schema;
|
||||
|
||||
/** Configuration for GCP OIDC. */
|
||||
export type GCPConfig = json.FromSchema<typeof gcpConfigSchema>;
|
||||
|
||||
/** Decides whether `config` is a GCP OIDC configuration. */
|
||||
export function isGCPConfig(
|
||||
config: UnvalidatedObject<AuthConfig>,
|
||||
): config is GCPConfig {
|
||||
return json.validateSchema(gcpConfigSchema, config);
|
||||
}
|
||||
|
||||
/** An array of all OIDC configuration schemas along with output-friendly names. */
|
||||
export const oidcSchemas = [
|
||||
{ schema: azureConfigSchema, name: "Azure" },
|
||||
{ schema: awsConfigSchema, name: "AWS" },
|
||||
{ schema: jfrogConfigSchema, name: "JFrog" },
|
||||
{ schema: cloudsmithConfigSchema, name: "Cloudsmith" },
|
||||
{ schema: gcpConfigSchema, name: "GCP" },
|
||||
];
|
||||
|
||||
/** Represents all supported OIDC configurations. */
|
||||
export type OIDC = AzureConfig | AWSConfig | JFrogConfig;
|
||||
export type OIDC =
|
||||
| AzureConfig
|
||||
| AWSConfig
|
||||
| JFrogConfig
|
||||
| CloudsmithConfig
|
||||
| GCPConfig;
|
||||
|
||||
/** All authentication-related fields. */
|
||||
export type AuthConfig = UsernamePassword | Token | OIDC;
|
||||
@@ -165,7 +198,7 @@ export type Credential = AuthConfig & Registry;
|
||||
export function credentialToStr(credential: Credential): string {
|
||||
let result: string = `Type: ${credential.type};`;
|
||||
|
||||
const appendIfDefined = (name: string, val: string | undefined) => {
|
||||
const appendIfDefined = (name: string, val: string | undefined | null) => {
|
||||
if (isDefined(val)) {
|
||||
result += ` ${name}: ${val};`;
|
||||
}
|
||||
@@ -184,7 +217,7 @@ export function credentialToStr(credential: Credential): string {
|
||||
isDefined(credential.password) ? "***" : undefined,
|
||||
);
|
||||
}
|
||||
if (isToken(credential)) {
|
||||
if (hasToken(credential)) {
|
||||
appendIfDefined("Token", isDefined(credential.token) ? "***" : undefined);
|
||||
}
|
||||
|
||||
@@ -205,6 +238,17 @@ export function credentialToStr(credential: Credential): string {
|
||||
credential["identity-mapping-name"],
|
||||
);
|
||||
appendIfDefined("JFrog Audience", credential.audience);
|
||||
} else if (isCloudsmithConfig(credential)) {
|
||||
appendIfDefined("Cloudsmith Namespace", credential.namespace);
|
||||
appendIfDefined("Cloudsmith Service Slug", credential["service-slug"]);
|
||||
appendIfDefined("Cloudsmith API Host", credential["api-host"]);
|
||||
} else if (isGCPConfig(credential)) {
|
||||
appendIfDefined(
|
||||
"GCP Workload Identity Provider",
|
||||
credential["workload-identity-provider"],
|
||||
);
|
||||
appendIfDefined("GCP Service Account", credential["service-account"]);
|
||||
appendIfDefined("GCP Audience", credential.audience);
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -214,6 +258,8 @@ export function credentialToStr(credential: Credential): string {
|
||||
export type Registry = {
|
||||
/** The type of the package registry. */
|
||||
type: string;
|
||||
/** Whether the registry replaces the base registry for the ecosystem. */
|
||||
"replaces-base"?: boolean;
|
||||
} & Address;
|
||||
|
||||
// If a registry has an `url`, then that takes precedence over the `host` which may or may
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
import test from "ava";
|
||||
|
||||
import * as json from "../json";
|
||||
import { makeFromSchema } from "../json/testing-util";
|
||||
import { setupTests } from "../testing-utils";
|
||||
|
||||
import * as types from "./types";
|
||||
import { getAuthConfig } from "./validation";
|
||||
|
||||
setupTests(test);
|
||||
|
||||
for (const schemaTest of types.oidcSchemas) {
|
||||
for (const includeOptional of [true, false]) {
|
||||
const minimalName = includeOptional ? "full" : "minimal";
|
||||
|
||||
test(`getAuthConfig - ${schemaTest.name} - ${minimalName}`, async (t) => {
|
||||
const config = makeFromSchema(includeOptional, schemaTest.schema);
|
||||
|
||||
t.deepEqual(
|
||||
getAuthConfig({
|
||||
...config,
|
||||
unexpected: "unexpected-value",
|
||||
} as unknown as json.UnvalidatedObject<types.AuthConfig>),
|
||||
config,
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
test("getAuthConfig - token", async (t) => {
|
||||
const config = makeFromSchema(true, types.tokenSchema);
|
||||
|
||||
t.deepEqual(
|
||||
getAuthConfig({
|
||||
...config,
|
||||
unexpected: "unexpected-value",
|
||||
} as json.UnvalidatedObject<types.AuthConfig>),
|
||||
config,
|
||||
);
|
||||
});
|
||||
|
||||
test("getAuthConfig - username and password", async (t) => {
|
||||
const config = makeFromSchema(true, types.usernamePasswordSchema);
|
||||
|
||||
t.deepEqual(
|
||||
getAuthConfig({
|
||||
...config,
|
||||
unexpected: "unexpected-value",
|
||||
} as json.UnvalidatedObject<types.AuthConfig>),
|
||||
config,
|
||||
);
|
||||
});
|
||||
|
||||
test("getAuthConfig - empty", async (t) => {
|
||||
const config = makeFromSchema(false, types.usernamePasswordSchema);
|
||||
|
||||
// Since the purpose of constructing the `AuthConfig` values is for
|
||||
// serialisation to JSON so that they can be passed to the proxy as configuration,
|
||||
// we only care that the stringified JSON representations are the same.
|
||||
t.deepEqual(
|
||||
JSON.stringify(
|
||||
getAuthConfig({
|
||||
...config,
|
||||
unexpected: "unexpected-value",
|
||||
} as json.UnvalidatedObject<types.AuthConfig>),
|
||||
),
|
||||
JSON.stringify({}),
|
||||
);
|
||||
});
|
||||
@@ -0,0 +1,81 @@
|
||||
import * as core from "@actions/core";
|
||||
|
||||
import * as json from "../json";
|
||||
import { isDefined } from "../util";
|
||||
|
||||
import type { AuthConfig, UsernamePassword } from "./types";
|
||||
import * as types from "./types";
|
||||
|
||||
/** Constructs a new object from `obj` with only keys that exist in `schema`. */
|
||||
export function cloneCredential<S extends json.Schema>(
|
||||
schema: S,
|
||||
obj: json.FromSchema<S>,
|
||||
): json.FromSchema<S> {
|
||||
const result = {};
|
||||
|
||||
for (const key of Object.keys(schema)) {
|
||||
// Skip keys that don't exist or don't have a value.
|
||||
if (!isDefined(obj[key])) {
|
||||
continue;
|
||||
}
|
||||
result[key] = obj[key];
|
||||
}
|
||||
|
||||
return result as json.FromSchema<S>;
|
||||
}
|
||||
|
||||
/** Extracts an `AuthConfig` value from `config`. */
|
||||
export function getAuthConfig(
|
||||
config: json.UnvalidatedObject<AuthConfig>,
|
||||
): AuthConfig {
|
||||
// Start by checking for the OIDC configurations, since they have required properties
|
||||
// which we can use to identify them.
|
||||
for (const oidcSchema of types.oidcSchemas) {
|
||||
if (json.validateSchema(oidcSchema.schema, config)) {
|
||||
return cloneCredential(oidcSchema.schema, config);
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, try the basic configuration types.
|
||||
if (types.isToken(config)) {
|
||||
// There are three scenarios for non-OIDC authentication based on the registry type:
|
||||
//
|
||||
// 1. `username`+`token`
|
||||
// 2. A `token` that combines the username and actual token, separated by ':'.
|
||||
// 3. `username`+`password`
|
||||
//
|
||||
// In all three cases, all fields are optional. If the `token` field is present,
|
||||
// we accept the configuration as a `Token` typed configuration, with the `token`
|
||||
// value and an optional `username`. Otherwise, we accept the configuration
|
||||
// typed as `UsernamePassword` (in the `else` clause below) with optional
|
||||
// username and password. I.e. a private registry type that uses 1. or 2.,
|
||||
// but has no `token` configured, will get accepted as `UsernamePassword` here.
|
||||
|
||||
if (isDefined(config.token)) {
|
||||
// Mask token to reduce chance of accidental leakage in logs, if we have one.
|
||||
core.setSecret(config.token);
|
||||
}
|
||||
|
||||
return cloneCredential(types.tokenSchema, config);
|
||||
} else {
|
||||
let username: string | undefined = undefined;
|
||||
let password: string | undefined = undefined;
|
||||
|
||||
// Both "username" and "password" are optional. If we have reached this point, we need
|
||||
// to validate which of them are present and that they have the correct type if so.
|
||||
if ("password" in config && json.isString(config.password)) {
|
||||
// Mask password to reduce chance of accidental leakage in logs, if we have one.
|
||||
core.setSecret(config.password);
|
||||
password = config.password;
|
||||
}
|
||||
if ("username" in config && json.isString(config.username)) {
|
||||
username = config.username;
|
||||
}
|
||||
|
||||
// Return the `UsernamePassword` object. Both username and password may be undefined.
|
||||
return {
|
||||
username,
|
||||
password,
|
||||
} satisfies UsernamePassword;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import {
|
||||
setupTests,
|
||||
setupActionsVars,
|
||||
createTestConfig,
|
||||
makeMacro,
|
||||
} from "./testing-utils";
|
||||
import { BuildMode, ConfigurationError, withTmpDir, wrapError } from "./util";
|
||||
|
||||
@@ -291,10 +292,9 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
const testCreateInitWithConfigStatusReport = test.macro({
|
||||
const testCreateInitWithConfigStatusReport = makeMacro({
|
||||
exec: async (
|
||||
t,
|
||||
_title: string,
|
||||
config: Config,
|
||||
expectedReportProperties: Partial<InitWithConfigStatusReport>,
|
||||
) => {
|
||||
@@ -337,11 +337,10 @@ const testCreateInitWithConfigStatusReport = test.macro({
|
||||
}
|
||||
});
|
||||
},
|
||||
title: (_, title) => `createInitWithConfigStatusReport: ${title}`,
|
||||
title: (title) => `createInitWithConfigStatusReport: ${title}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
testCreateInitWithConfigStatusReport,
|
||||
testCreateInitWithConfigStatusReport.serial(
|
||||
"returns a value",
|
||||
createTestConfig({
|
||||
buildMode: BuildMode.None,
|
||||
@@ -355,8 +354,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testCreateInitWithConfigStatusReport,
|
||||
testCreateInitWithConfigStatusReport.serial(
|
||||
"includes packs for a single language",
|
||||
createTestConfig({
|
||||
buildMode: BuildMode.None,
|
||||
@@ -372,8 +370,7 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
testCreateInitWithConfigStatusReport,
|
||||
testCreateInitWithConfigStatusReport.serial(
|
||||
"includes packs for multiple languages",
|
||||
createTestConfig({
|
||||
buildMode: BuildMode.None,
|
||||
|
||||
Binary file not shown.
+37
-9
@@ -2,7 +2,11 @@ import { TextDecoder } from "node:util";
|
||||
import path from "path";
|
||||
|
||||
import * as github from "@actions/github";
|
||||
import { ExecutionContext, TestFn } from "ava";
|
||||
import test, {
|
||||
type ExecutionContext,
|
||||
type MacroDeclarationOptions,
|
||||
type TestFn,
|
||||
} from "ava";
|
||||
import nock from "nock";
|
||||
import * as sinon from "sinon";
|
||||
|
||||
@@ -36,16 +40,20 @@ export const SAMPLE_DOTCOM_API_DETAILS = {
|
||||
apiURL: "https://api.github.com",
|
||||
};
|
||||
|
||||
export const SAMPLE_DEFAULT_CLI_VERSION: CodeQLDefaultVersionInfo = {
|
||||
cliVersion: "2.20.0",
|
||||
tagName: "codeql-bundle-v2.20.0",
|
||||
};
|
||||
|
||||
export const LINKED_CLI_VERSION = {
|
||||
cliVersion: defaults.cliVersion,
|
||||
tagName: defaults.bundleVersion,
|
||||
};
|
||||
|
||||
export const SAMPLE_DEFAULT_CLI_VERSION: CodeQLDefaultVersionInfo = {
|
||||
enabledVersions: [
|
||||
{
|
||||
cliVersion: "2.20.0",
|
||||
tagName: "codeql-bundle-v2.20.0",
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
type TestContext = {
|
||||
stdoutWrite: any;
|
||||
stderrWrite: any;
|
||||
@@ -85,8 +93,8 @@ function wrapOutput(context: TestContext) {
|
||||
};
|
||||
}
|
||||
|
||||
export function setupTests(test: TestFn<any>) {
|
||||
const typedTest = test as TestFn<TestContext>;
|
||||
export function setupTests(testFn: TestFn<any>) {
|
||||
const typedTest = testFn as TestFn<TestContext>;
|
||||
|
||||
typedTest.beforeEach((t) => {
|
||||
// Set an empty CodeQL object so that all method calls will fail
|
||||
@@ -139,6 +147,26 @@ export function setupTests(test: TestFn<any>) {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Declare a reusable test implementation, with better type safety than `test.macro`.
|
||||
*/
|
||||
export function makeMacro<Args extends unknown[]>(
|
||||
decl: MacroDeclarationOptions<Args, unknown>,
|
||||
) {
|
||||
const m = test.macro<Args>(decl);
|
||||
|
||||
const wrapper = (name: string, ...args: Args) => test(name, m, ...args);
|
||||
wrapper.test = (...args: Args) => test(m, ...args);
|
||||
wrapper.serial = (name: string, ...args: Args) =>
|
||||
test.serial(name, m, ...args);
|
||||
// Make the implementation available as `fn`. We don't call it `exec` so
|
||||
// that results from this function are not valid arguments to `test`
|
||||
// or `test.serial`.
|
||||
wrapper.fn = decl.exec;
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* Default values for environment variables typically set in an Actions
|
||||
* environment. Tests can override individual variables by passing them in the
|
||||
@@ -442,7 +470,7 @@ export function mockCodeQLVersion(
|
||||
*/
|
||||
export function createFeatures(enabledFeatures: Feature[]): FeatureEnablement {
|
||||
return {
|
||||
getDefaultCliVersion: async () => {
|
||||
getEnabledDefaultCliVersions: async () => {
|
||||
throw new Error("not implemented");
|
||||
},
|
||||
getValue: async (feature) => {
|
||||
|
||||
+4
-3
@@ -156,9 +156,8 @@ async function combineSarifFilesUsingCLI(
|
||||
apiURL: getRequiredEnvParam("GITHUB_API_URL"),
|
||||
};
|
||||
|
||||
const codeQLDefaultVersionInfo = await features.getDefaultCliVersion(
|
||||
gitHubVersion.type,
|
||||
);
|
||||
const codeQLDefaultVersionInfo =
|
||||
await features.getEnabledDefaultCliVersions(gitHubVersion.type);
|
||||
|
||||
const initCodeQLResult = await initCodeQL(
|
||||
undefined, // There is no tools input on the upload action
|
||||
@@ -166,6 +165,8 @@ async function combineSarifFilesUsingCLI(
|
||||
tempDir,
|
||||
gitHubVersion.type,
|
||||
codeQLDefaultVersionInfo,
|
||||
undefined, // rawLanguages: upload-lib does not run analysis
|
||||
false, // useOverlayAwareDefaultCliVersion: upload-lib does not run analysis
|
||||
features,
|
||||
logger,
|
||||
);
|
||||
|
||||
@@ -12,7 +12,7 @@ import { EnvVar } from "./environment";
|
||||
import { getActionsLogger, withGroup } from "./logging";
|
||||
import { checkGitHubVersionInRange, getErrorMessage } from "./util";
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
// To capture errors appropriately, keep as much code within the try-catch as
|
||||
// possible, and only use safe functions outside.
|
||||
|
||||
@@ -48,5 +48,3 @@ async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -165,7 +165,7 @@ async function run(startedAt: Date) {
|
||||
}
|
||||
}
|
||||
|
||||
async function runWrapper() {
|
||||
export async function runWrapper() {
|
||||
const startedAt = new Date();
|
||||
const logger = getActionsLogger();
|
||||
try {
|
||||
@@ -182,5 +182,3 @@ async function runWrapper() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void runWrapper();
|
||||
|
||||
@@ -6,7 +6,7 @@ import * as sinon from "sinon";
|
||||
|
||||
import { AnalysisKind, getAnalysisConfig } from "./analyses";
|
||||
import { getRunnerLogger } from "./logging";
|
||||
import { createFeatures, setupTests } from "./testing-utils";
|
||||
import { createFeatures, makeMacro, setupTests } from "./testing-utils";
|
||||
import { UploadResult } from "./upload-lib";
|
||||
import * as uploadLib from "./upload-lib";
|
||||
import { postProcessAndUploadSarif } from "./upload-sarif";
|
||||
@@ -43,7 +43,7 @@ function mockPostProcessSarifFiles() {
|
||||
return postProcessSarifFiles;
|
||||
}
|
||||
|
||||
const postProcessAndUploadSarifMacro = test.macro({
|
||||
const postProcessAndUploadSarifMacro = makeMacro({
|
||||
exec: async (
|
||||
t: ExecutionContext<unknown>,
|
||||
sarifFiles: string[],
|
||||
@@ -67,7 +67,7 @@ const postProcessAndUploadSarifMacro = test.macro({
|
||||
const analysisConfig = getAnalysisConfig(analysisKind);
|
||||
uploadPostProcessedFiles
|
||||
.withArgs(logger, sinon.match.any, analysisConfig, sinon.match.any)
|
||||
.resolves(expectedResult[analysisKind as AnalysisKind]?.uploadResult);
|
||||
.resolves(expectedResult[analysisKind]?.uploadResult);
|
||||
}
|
||||
|
||||
const fullSarifPaths = sarifFiles.map(toFullPath);
|
||||
@@ -123,9 +123,8 @@ const postProcessAndUploadSarifMacro = test.macro({
|
||||
title: (providedTitle = "") => `processAndUploadSarif - ${providedTitle}`,
|
||||
});
|
||||
|
||||
test.serial(
|
||||
postProcessAndUploadSarifMacro.serial(
|
||||
"SARIF file",
|
||||
postProcessAndUploadSarifMacro,
|
||||
["test.sarif"],
|
||||
(tempDir) => path.join(tempDir, "test.sarif"),
|
||||
{
|
||||
@@ -138,9 +137,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
postProcessAndUploadSarifMacro.serial(
|
||||
"JSON file",
|
||||
postProcessAndUploadSarifMacro,
|
||||
["test.json"],
|
||||
(tempDir) => path.join(tempDir, "test.json"),
|
||||
{
|
||||
@@ -153,9 +151,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
postProcessAndUploadSarifMacro.serial(
|
||||
"Code Scanning files",
|
||||
postProcessAndUploadSarifMacro,
|
||||
["test.json", "test.sarif"],
|
||||
undefined,
|
||||
{
|
||||
@@ -169,9 +166,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
postProcessAndUploadSarifMacro.serial(
|
||||
"Code Quality file",
|
||||
postProcessAndUploadSarifMacro,
|
||||
["test.quality.sarif"],
|
||||
(tempDir) => path.join(tempDir, "test.quality.sarif"),
|
||||
{
|
||||
@@ -184,9 +180,8 @@ test.serial(
|
||||
},
|
||||
);
|
||||
|
||||
test.serial(
|
||||
postProcessAndUploadSarifMacro.serial(
|
||||
"Mixed files",
|
||||
postProcessAndUploadSarifMacro,
|
||||
["test.sarif", "test.quality.sarif"],
|
||||
undefined,
|
||||
{
|
||||
|
||||
@@ -422,7 +422,7 @@ async function testLanguageAliases(
|
||||
],
|
||||
},
|
||||
},
|
||||
} as Workflow,
|
||||
},
|
||||
codeql,
|
||||
);
|
||||
|
||||
|
||||
@@ -29,6 +29,6 @@ outputs:
|
||||
proxy_urls:
|
||||
description: A stringified JSON array of objects containing the types and URLs of the configured registries.
|
||||
runs:
|
||||
using: node24
|
||||
main: "../lib/start-proxy-action.js"
|
||||
post: "../lib/start-proxy-action-post.js"
|
||||
using: node20
|
||||
main: "../lib/start-proxy-entry.js"
|
||||
post: "../lib/start-proxy-post-entry.js"
|
||||
|
||||
@@ -41,6 +41,6 @@ outputs:
|
||||
|
||||
{ "code-scanning": "some-id", "code-quality": "some-other-id" }
|
||||
runs:
|
||||
using: node24
|
||||
main: '../lib/upload-sarif-action.js'
|
||||
post: '../lib/upload-sarif-action-post.js'
|
||||
using: node20
|
||||
main: '../lib/upload-sarif-entry.js'
|
||||
post: '../lib/upload-sarif-post-entry.js'
|
||||
|
||||
Reference in New Issue
Block a user