mirror of
https://github.com/github/codeql-action.git
synced 2025-12-18 13:29:25 +08:00
Compare commits
83 Commits
codeql-bun
...
henrymerce
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ac6c41b910 | ||
|
|
7673a2de65 | ||
|
|
6b5763e5ee | ||
|
|
3322491022 | ||
|
|
6bc6217487 | ||
|
|
faf6d35e7b | ||
|
|
3b94cfeb15 | ||
|
|
b88acb2f6c | ||
|
|
241948c698 | ||
|
|
da77f9f638 | ||
|
|
de172624a1 | ||
|
|
488c1f1959 | ||
|
|
f2ccf3b4f1 | ||
|
|
f28848a66a | ||
|
|
5459b98ca0 | ||
|
|
0c8bfeaf84 | ||
|
|
1fe89fe9cb | ||
|
|
6dba00881c | ||
|
|
d4d47c0d3d | ||
|
|
6c6e810910 | ||
|
|
5d4e8d1aca | ||
|
|
1dc115f17a | ||
|
|
998798e34d | ||
|
|
5eb751966f | ||
|
|
d29eddb39b | ||
|
|
e9626872ef | ||
|
|
19c7f96922 | ||
|
|
ae5de9a20d | ||
|
|
0cb86337c5 | ||
|
|
c07cc0d3a9 | ||
|
|
7a5748cf0d | ||
|
|
db75d46248 | ||
|
|
a0fc644617 | ||
|
|
a2ee53c0d3 | ||
|
|
b5e1a28b8a | ||
|
|
c2d4383e64 | ||
|
|
d0ad1da72a | ||
|
|
07cd437640 | ||
|
|
a682bbe410 | ||
|
|
7fd7db3f26 | ||
|
|
d6c1a791b7 | ||
|
|
034374eb3f | ||
|
|
6dbc22c93f | ||
|
|
a539068a61 | ||
|
|
e1058e4d74 | ||
|
|
d4f39b0766 | ||
|
|
b30cb9ae2a | ||
|
|
009fe6b0c1 | ||
|
|
b1dea65f65 | ||
|
|
7e0b77e3a8 | ||
|
|
0264b51610 | ||
|
|
2ac846d41e | ||
|
|
5d063dd3af | ||
|
|
8e921c3145 | ||
|
|
4b675e451b | ||
|
|
65bad627f3 | ||
|
|
4564f5e482 | ||
|
|
1b168cd394 | ||
|
|
120f277b16 | ||
|
|
1b0b941e1f | ||
|
|
db812c1ae6 | ||
|
|
2930dba17a | ||
|
|
805b7e1790 | ||
|
|
da501245d4 | ||
|
|
1fc7d3785d | ||
|
|
7a55ffeaf1 | ||
|
|
c43362b91a | ||
|
|
002a7f25fd | ||
|
|
5b7e7fcc9c | ||
|
|
cd48547da5 | ||
|
|
44570be32d | ||
|
|
b73d396b48 | ||
|
|
0ffebf72b2 | ||
|
|
149d184a51 | ||
|
|
97c2630b10 | ||
|
|
b93926dc35 | ||
|
|
cf1bb45a27 | ||
|
|
f4ebe95061 | ||
|
|
f5c63fadd5 | ||
|
|
a2c01e776e | ||
|
|
ac34c13834 | ||
|
|
c4efbda299 | ||
|
|
dd8914320f |
6
.github/actions/verify-debug-artifact-scan-completed/action.yml
vendored
Normal file
6
.github/actions/verify-debug-artifact-scan-completed/action.yml
vendored
Normal file
@@ -0,0 +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
|
||||||
|
main: index.js
|
||||||
|
post: post.js
|
||||||
2
.github/actions/verify-debug-artifact-scan-completed/index.js
vendored
Normal file
2
.github/actions/verify-debug-artifact-scan-completed/index.js
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
// The main step is a no-op, since we can only verify artifact scan completion in the post step.
|
||||||
|
console.log("Will verify artifact scan completion in the post step.");
|
||||||
11
.github/actions/verify-debug-artifact-scan-completed/post.js
vendored
Normal file
11
.github/actions/verify-debug-artifact-scan-completed/post.js
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
// Post step - runs after the workflow completes, when artifact scan has finished
|
||||||
|
const process = require("process");
|
||||||
|
|
||||||
|
const scanFinished = process.env.CODEQL_ACTION_ARTIFACT_SCAN_FINISHED;
|
||||||
|
|
||||||
|
if (scanFinished !== "true") {
|
||||||
|
console.error("Error: Best-effort artifact scan did not complete. Expected CODEQL_ACTION_ARTIFACT_SCAN_FINISHED=true");
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("✓ Best-effort artifact scan completed successfully");
|
||||||
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -34,7 +34,7 @@ Products:
|
|||||||
|
|
||||||
Environments:
|
Environments:
|
||||||
|
|
||||||
- **Dotcom** - Impacts CodeQL workflows on `github.com`.
|
- **Dotcom** - Impacts CodeQL workflows on `github.com` and/or GitHub Enterprise Cloud with Data Residency.
|
||||||
- **GHES** - Impacts CodeQL workflows on GitHub Enterprise Server.
|
- **GHES** - Impacts CodeQL workflows on GitHub Enterprise Server.
|
||||||
- **Testing/None** - This change does not impact any CodeQL workflows in production.
|
- **Testing/None** - This change does not impact any CodeQL workflows in production.
|
||||||
|
|
||||||
|
|||||||
2
.github/workflows/__bundle-zstd.yml
generated
vendored
2
.github/workflows/__bundle-zstd.yml
generated
vendored
@@ -79,7 +79,7 @@ jobs:
|
|||||||
output: ${{ runner.temp }}/results
|
output: ${{ runner.temp }}/results
|
||||||
upload-database: false
|
upload-database: false
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.os }}-zstd-bundle.sarif
|
name: ${{ matrix.os }}-zstd-bundle.sarif
|
||||||
path: ${{ runner.temp }}/results/javascript.sarif
|
path: ${{ runner.temp }}/results/javascript.sarif
|
||||||
|
|||||||
2
.github/workflows/__config-export.yml
generated
vendored
2
.github/workflows/__config-export.yml
generated
vendored
@@ -67,7 +67,7 @@ jobs:
|
|||||||
output: ${{ runner.temp }}/results
|
output: ${{ runner.temp }}/results
|
||||||
upload-database: false
|
upload-database: false
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: config-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: config-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: ${{ runner.temp }}/results/javascript.sarif
|
path: ${{ runner.temp }}/results/javascript.sarif
|
||||||
|
|||||||
2
.github/workflows/__diagnostics-export.yml
generated
vendored
2
.github/workflows/__diagnostics-export.yml
generated
vendored
@@ -78,7 +78,7 @@ jobs:
|
|||||||
output: ${{ runner.temp }}/results
|
output: ${{ runner.temp }}/results
|
||||||
upload-database: false
|
upload-database: false
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: diagnostics-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: diagnostics-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: ${{ runner.temp }}/results/javascript.sarif
|
path: ${{ runner.temp }}/results/javascript.sarif
|
||||||
|
|||||||
2
.github/workflows/__export-file-baseline-information.yml
generated
vendored
2
.github/workflows/__export-file-baseline-information.yml
generated
vendored
@@ -99,7 +99,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
output: ${{ runner.temp }}/results
|
output: ${{ runner.temp }}/results
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: with-baseline-information-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: with-baseline-information-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: ${{ runner.temp }}/results/javascript.sarif
|
path: ${{ runner.temp }}/results/javascript.sarif
|
||||||
|
|||||||
2
.github/workflows/__job-run-uuid-sarif.yml
generated
vendored
2
.github/workflows/__job-run-uuid-sarif.yml
generated
vendored
@@ -64,7 +64,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
output: ${{ runner.temp }}/results
|
output: ${{ runner.temp }}/results
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: ${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: ${{ runner.temp }}/results/javascript.sarif
|
path: ${{ runner.temp }}/results/javascript.sarif
|
||||||
|
|||||||
6
.github/workflows/__quality-queries.yml
generated
vendored
6
.github/workflows/__quality-queries.yml
generated
vendored
@@ -83,7 +83,7 @@ jobs:
|
|||||||
post-processed-sarif-path: ${{ runner.temp }}/post-processed
|
post-processed-sarif-path: ${{ runner.temp }}/post-processed
|
||||||
- name: Upload security SARIF
|
- name: Upload security SARIF
|
||||||
if: contains(matrix.analysis-kinds, 'code-scanning')
|
if: contains(matrix.analysis-kinds, 'code-scanning')
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: |
|
name: |
|
||||||
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
||||||
@@ -91,14 +91,14 @@ jobs:
|
|||||||
retention-days: 7
|
retention-days: 7
|
||||||
- name: Upload quality SARIF
|
- name: Upload quality SARIF
|
||||||
if: contains(matrix.analysis-kinds, 'code-quality')
|
if: contains(matrix.analysis-kinds, 'code-quality')
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: |
|
name: |
|
||||||
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json
|
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json
|
||||||
path: ${{ runner.temp }}/results/javascript.quality.sarif
|
path: ${{ runner.temp }}/results/javascript.quality.sarif
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
- name: Upload post-processed SARIF
|
- name: Upload post-processed SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: |
|
name: |
|
||||||
post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
||||||
|
|||||||
2
.github/workflows/__rubocop-multi-language.yml
generated
vendored
2
.github/workflows/__rubocop-multi-language.yml
generated
vendored
@@ -56,7 +56,7 @@ jobs:
|
|||||||
use-all-platform-bundle: 'false'
|
use-all-platform-bundle: 'false'
|
||||||
setup-kotlin: 'true'
|
setup-kotlin: 'true'
|
||||||
- name: Set up Ruby
|
- name: Set up Ruby
|
||||||
uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0
|
uses: ruby/setup-ruby@ac793fdd38cc468a4dd57246fa9d0e868aba9085 # v1.270.0
|
||||||
with:
|
with:
|
||||||
ruby-version: 2.6
|
ruby-version: 2.6
|
||||||
- name: Install Code Scanning integration
|
- name: Install Code Scanning integration
|
||||||
|
|||||||
@@ -58,6 +58,8 @@ jobs:
|
|||||||
uses: actions/setup-dotnet@v5
|
uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
dotnet-version: '9.x'
|
dotnet-version: '9.x'
|
||||||
|
- name: Assert best-effort artifact scan completed
|
||||||
|
uses: ./../action/.github/actions/verify-debug-artifact-scan-completed
|
||||||
- uses: ./../action/init
|
- uses: ./../action/init
|
||||||
with:
|
with:
|
||||||
tools: ${{ steps.prepare-test.outputs.tools-url }}
|
tools: ${{ steps.prepare-test.outputs.tools-url }}
|
||||||
@@ -83,7 +85,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v7
|
||||||
- name: Check expected artifacts exist
|
- name: Check expected artifacts exist
|
||||||
run: |
|
run: |
|
||||||
LANGUAGES="cpp csharp go java javascript python"
|
LANGUAGES="cpp csharp go java javascript python"
|
||||||
|
|||||||
4
.github/workflows/debug-artifacts-safe.yml
vendored
4
.github/workflows/debug-artifacts-safe.yml
vendored
@@ -54,6 +54,8 @@ jobs:
|
|||||||
uses: actions/setup-dotnet@v5
|
uses: actions/setup-dotnet@v5
|
||||||
with:
|
with:
|
||||||
dotnet-version: '9.x'
|
dotnet-version: '9.x'
|
||||||
|
- name: Assert best-effort artifact scan completed
|
||||||
|
uses: ./../action/.github/actions/verify-debug-artifact-scan-completed
|
||||||
- uses: ./../action/init
|
- uses: ./../action/init
|
||||||
id: init
|
id: init
|
||||||
with:
|
with:
|
||||||
@@ -77,7 +79,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Download all artifacts
|
- name: Download all artifacts
|
||||||
uses: actions/download-artifact@v6
|
uses: actions/download-artifact@v7
|
||||||
- name: Check expected artifacts exist
|
- name: Check expected artifacts exist
|
||||||
run: |
|
run: |
|
||||||
VERSIONS="stable-v2.20.3 default linked nightly-latest"
|
VERSIONS="stable-v2.20.3 default linked nightly-latest"
|
||||||
|
|||||||
2
.github/workflows/post-release-mergeback.yml
vendored
2
.github/workflows/post-release-mergeback.yml
vendored
@@ -142,7 +142,7 @@ jobs:
|
|||||||
token: "${{ secrets.GITHUB_TOKEN }}"
|
token: "${{ secrets.GITHUB_TOKEN }}"
|
||||||
|
|
||||||
- name: Generate token
|
- name: Generate token
|
||||||
uses: actions/create-github-app-token@v2.2.0
|
uses: actions/create-github-app-token@v2.2.1
|
||||||
id: app-token
|
id: app-token
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||||
|
|||||||
2
.github/workflows/rollback-release.yml
vendored
2
.github/workflows/rollback-release.yml
vendored
@@ -137,7 +137,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Generate token
|
- name: Generate token
|
||||||
if: github.event_name == 'workflow_dispatch'
|
if: github.event_name == 'workflow_dispatch'
|
||||||
uses: actions/create-github-app-token@v2.2.0
|
uses: actions/create-github-app-token@v2.2.1
|
||||||
id: app-token
|
id: app-token
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||||
|
|||||||
2
.github/workflows/update-release-branch.yml
vendored
2
.github/workflows/update-release-branch.yml
vendored
@@ -93,7 +93,7 @@ jobs:
|
|||||||
pull-requests: write # needed to create pull request
|
pull-requests: write # needed to create pull request
|
||||||
steps:
|
steps:
|
||||||
- name: Generate token
|
- name: Generate token
|
||||||
uses: actions/create-github-app-token@v2.2.0
|
uses: actions/create-github-app-token@v2.2.1
|
||||||
id: app-token
|
id: app-token
|
||||||
with:
|
with:
|
||||||
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
app-id: ${{ vars.AUTOMATION_APP_ID }}
|
||||||
|
|||||||
12
CHANGELOG.md
12
CHANGELOG.md
@@ -6,6 +6,18 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
|
|||||||
|
|
||||||
No user facing changes.
|
No user facing changes.
|
||||||
|
|
||||||
|
## 4.31.9 - 16 Dec 2025
|
||||||
|
|
||||||
|
No user facing changes.
|
||||||
|
|
||||||
|
## 4.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
|
||||||
|
|
||||||
|
- Update default CodeQL bundle version to 2.23.7. [#3343](https://github.com/github/codeql-action/pull/3343)
|
||||||
|
|
||||||
## 4.31.6 - 01 Dec 2025
|
## 4.31.6 - 01 Dec 2025
|
||||||
|
|
||||||
No user facing changes.
|
No user facing changes.
|
||||||
|
|||||||
43681
lib/analyze-action-post.js
generated
43681
lib/analyze-action-post.js
generated
File diff suppressed because it is too large
Load Diff
37766
lib/analyze-action.js
generated
37766
lib/analyze-action.js
generated
File diff suppressed because it is too large
Load Diff
36456
lib/autobuild-action.js
generated
36456
lib/autobuild-action.js
generated
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"bundleVersion": "codeql-bundle-v2.23.6",
|
"bundleVersion": "codeql-bundle-v2.23.8",
|
||||||
"cliVersion": "2.23.6",
|
"cliVersion": "2.23.8",
|
||||||
"priorBundleVersion": "codeql-bundle-v2.23.5",
|
"priorBundleVersion": "codeql-bundle-v2.23.7",
|
||||||
"priorCliVersion": "2.23.5"
|
"priorCliVersion": "2.23.7"
|
||||||
}
|
}
|
||||||
|
|||||||
43789
lib/init-action-post.js
generated
43789
lib/init-action-post.js
generated
File diff suppressed because it is too large
Load Diff
37611
lib/init-action.js
generated
37611
lib/init-action.js
generated
File diff suppressed because it is too large
Load Diff
36441
lib/resolve-environment-action.js
generated
36441
lib/resolve-environment-action.js
generated
File diff suppressed because it is too large
Load Diff
36464
lib/setup-codeql-action.js
generated
36464
lib/setup-codeql-action.js
generated
File diff suppressed because it is too large
Load Diff
43015
lib/start-proxy-action-post.js
generated
43015
lib/start-proxy-action-post.js
generated
File diff suppressed because it is too large
Load Diff
36784
lib/start-proxy-action.js
generated
36784
lib/start-proxy-action.js
generated
File diff suppressed because it is too large
Load Diff
36467
lib/upload-lib.js
generated
36467
lib/upload-lib.js
generated
File diff suppressed because it is too large
Load Diff
43568
lib/upload-sarif-action-post.js
generated
43568
lib/upload-sarif-action-post.js
generated
File diff suppressed because it is too large
Load Diff
36486
lib/upload-sarif-action.js
generated
36486
lib/upload-sarif-action.js
generated
File diff suppressed because it is too large
Load Diff
1216
package-lock.json
generated
1216
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
22
package.json
22
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "codeql",
|
"name": "codeql",
|
||||||
"version": "4.31.7",
|
"version": "4.31.10",
|
||||||
"private": true,
|
"private": true,
|
||||||
"description": "CodeQL action",
|
"description": "CodeQL action",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@@ -24,12 +24,12 @@
|
|||||||
},
|
},
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@actions/artifact": "^4.0.0",
|
"@actions/artifact": "^5.0.1",
|
||||||
"@actions/artifact-legacy": "npm:@actions/artifact@^1.1.2",
|
"@actions/artifact-legacy": "npm:@actions/artifact@^1.1.2",
|
||||||
"@actions/cache": "^4.1.0",
|
"@actions/cache": "^5.0.1",
|
||||||
"@actions/core": "^1.11.1",
|
"@actions/core": "^2.0.1",
|
||||||
"@actions/exec": "^1.1.1",
|
"@actions/exec": "^2.0.0",
|
||||||
"@actions/github": "^6.0.0",
|
"@actions/github": "^6.0.1",
|
||||||
"@actions/glob": "^0.5.0",
|
"@actions/glob": "^0.5.0",
|
||||||
"@actions/http-client": "^3.0.0",
|
"@actions/http-client": "^3.0.0",
|
||||||
"@actions/io": "^2.0.0",
|
"@actions/io": "^2.0.0",
|
||||||
@@ -43,7 +43,7 @@
|
|||||||
"js-yaml": "^4.1.1",
|
"js-yaml": "^4.1.1",
|
||||||
"jsonschema": "1.4.1",
|
"jsonschema": "1.4.1",
|
||||||
"long": "^5.3.2",
|
"long": "^5.3.2",
|
||||||
"node-forge": "^1.3.2",
|
"node-forge": "^1.3.3",
|
||||||
"semver": "^7.7.3",
|
"semver": "^7.7.3",
|
||||||
"uuid": "^13.0.0"
|
"uuid": "^13.0.0"
|
||||||
},
|
},
|
||||||
@@ -51,7 +51,7 @@
|
|||||||
"@ava/typescript": "6.0.0",
|
"@ava/typescript": "6.0.0",
|
||||||
"@eslint/compat": "^2.0.0",
|
"@eslint/compat": "^2.0.0",
|
||||||
"@eslint/eslintrc": "^3.3.3",
|
"@eslint/eslintrc": "^3.3.3",
|
||||||
"@eslint/js": "^9.39.1",
|
"@eslint/js": "^9.39.2",
|
||||||
"@microsoft/eslint-formatter-sarif": "^3.1.0",
|
"@microsoft/eslint-formatter-sarif": "^3.1.0",
|
||||||
"@octokit/types": "^16.0.0",
|
"@octokit/types": "^16.0.0",
|
||||||
"@types/archiver": "^7.0.0",
|
"@types/archiver": "^7.0.0",
|
||||||
@@ -61,16 +61,16 @@
|
|||||||
"@types/node-forge": "^1.3.14",
|
"@types/node-forge": "^1.3.14",
|
||||||
"@types/semver": "^7.7.1",
|
"@types/semver": "^7.7.1",
|
||||||
"@types/sinon": "^21.0.0",
|
"@types/sinon": "^21.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.48.0",
|
"@typescript-eslint/eslint-plugin": "^8.49.0",
|
||||||
"@typescript-eslint/parser": "^8.48.0",
|
"@typescript-eslint/parser": "^8.48.0",
|
||||||
"ava": "^6.4.1",
|
"ava": "^6.4.1",
|
||||||
"esbuild": "^0.27.0",
|
"esbuild": "^0.27.1",
|
||||||
"eslint": "^8.57.1",
|
"eslint": "^8.57.1",
|
||||||
"eslint-import-resolver-typescript": "^3.8.7",
|
"eslint-import-resolver-typescript": "^3.8.7",
|
||||||
"eslint-plugin-filenames": "^1.3.2",
|
"eslint-plugin-filenames": "^1.3.2",
|
||||||
"eslint-plugin-github": "^5.1.8",
|
"eslint-plugin-github": "^5.1.8",
|
||||||
"eslint-plugin-import": "2.29.1",
|
"eslint-plugin-import": "2.29.1",
|
||||||
"eslint-plugin-jsdoc": "^61.4.1",
|
"eslint-plugin-jsdoc": "^61.5.0",
|
||||||
"eslint-plugin-no-async-foreach": "^0.1.1",
|
"eslint-plugin-no-async-foreach": "^0.1.1",
|
||||||
"glob": "^11.1.0",
|
"glob": "^11.1.0",
|
||||||
"nock": "^14.0.10",
|
"nock": "^14.0.10",
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ steps:
|
|||||||
output: ${{ runner.temp }}/results
|
output: ${{ runner.temp }}/results
|
||||||
upload-database: false
|
upload-database: false
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.os }}-zstd-bundle.sarif
|
name: ${{ matrix.os }}-zstd-bundle.sarif
|
||||||
path: ${{ runner.temp }}/results/javascript.sarif
|
path: ${{ runner.temp }}/results/javascript.sarif
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ steps:
|
|||||||
output: "${{ runner.temp }}/results"
|
output: "${{ runner.temp }}/results"
|
||||||
upload-database: false
|
upload-database: false
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: config-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: config-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: "${{ runner.temp }}/results/javascript.sarif"
|
path: "${{ runner.temp }}/results/javascript.sarif"
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ steps:
|
|||||||
output: "${{ runner.temp }}/results"
|
output: "${{ runner.temp }}/results"
|
||||||
upload-database: false
|
upload-database: false
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: diagnostics-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: diagnostics-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: "${{ runner.temp }}/results/javascript.sarif"
|
path: "${{ runner.temp }}/results/javascript.sarif"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ steps:
|
|||||||
with:
|
with:
|
||||||
output: "${{ runner.temp }}/results"
|
output: "${{ runner.temp }}/results"
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: with-baseline-information-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: with-baseline-information-${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: "${{ runner.temp }}/results/javascript.sarif"
|
path: "${{ runner.temp }}/results/javascript.sarif"
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ steps:
|
|||||||
with:
|
with:
|
||||||
output: "${{ runner.temp }}/results"
|
output: "${{ runner.temp }}/results"
|
||||||
- name: Upload SARIF
|
- name: Upload SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
name: ${{ matrix.os }}-${{ matrix.version }}.sarif.json
|
||||||
path: "${{ runner.temp }}/results/javascript.sarif"
|
path: "${{ runner.temp }}/results/javascript.sarif"
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ steps:
|
|||||||
post-processed-sarif-path: "${{ runner.temp }}/post-processed"
|
post-processed-sarif-path: "${{ runner.temp }}/post-processed"
|
||||||
- name: Upload security SARIF
|
- name: Upload security SARIF
|
||||||
if: contains(matrix.analysis-kinds, 'code-scanning')
|
if: contains(matrix.analysis-kinds, 'code-scanning')
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: |
|
name: |
|
||||||
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
||||||
@@ -47,14 +47,14 @@ steps:
|
|||||||
retention-days: 7
|
retention-days: 7
|
||||||
- name: Upload quality SARIF
|
- name: Upload quality SARIF
|
||||||
if: contains(matrix.analysis-kinds, 'code-quality')
|
if: contains(matrix.analysis-kinds, 'code-quality')
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: |
|
name: |
|
||||||
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json
|
quality-queries-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.quality.sarif.json
|
||||||
path: "${{ runner.temp }}/results/javascript.quality.sarif"
|
path: "${{ runner.temp }}/results/javascript.quality.sarif"
|
||||||
retention-days: 7
|
retention-days: 7
|
||||||
- name: Upload post-processed SARIF
|
- name: Upload post-processed SARIF
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: |
|
name: |
|
||||||
post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}.sarif.json
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ description: "Tests using RuboCop to analyze a multi-language repository and the
|
|||||||
versions: ["default"]
|
versions: ["default"]
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Ruby
|
- name: Set up Ruby
|
||||||
uses: ruby/setup-ruby@8aeb6ff8030dd539317f8e1769a044873b56ea71 # v1.268.0
|
uses: ruby/setup-ruby@ac793fdd38cc468a4dd57246fa9d0e868aba9085 # v1.270.0
|
||||||
with:
|
with:
|
||||||
ruby-version: 2.6
|
ruby-version: 2.6
|
||||||
- name: Install Code Scanning integration
|
- name: Install Code Scanning integration
|
||||||
|
|||||||
@@ -19,20 +19,18 @@ import { getApiDetails, getGitHubVersion } from "./api-client";
|
|||||||
import { runAutobuild } from "./autobuild";
|
import { runAutobuild } from "./autobuild";
|
||||||
import { getTotalCacheSize, shouldStoreCache } from "./caching-utils";
|
import { getTotalCacheSize, shouldStoreCache } from "./caching-utils";
|
||||||
import { getCodeQL } from "./codeql";
|
import { getCodeQL } from "./codeql";
|
||||||
|
import { Config, getConfig } from "./config-utils";
|
||||||
import {
|
import {
|
||||||
Config,
|
cleanupAndUploadDatabases,
|
||||||
getConfig,
|
DatabaseUploadResult,
|
||||||
isCodeQualityEnabled,
|
} from "./database-upload";
|
||||||
isCodeScanningEnabled,
|
|
||||||
} from "./config-utils";
|
|
||||||
import { cleanupAndUploadDatabases } from "./database-upload";
|
|
||||||
import {
|
import {
|
||||||
DependencyCacheUploadStatusReport,
|
DependencyCacheUploadStatusReport,
|
||||||
uploadDependencyCaches,
|
uploadDependencyCaches,
|
||||||
} from "./dependency-caching";
|
} from "./dependency-caching";
|
||||||
import { getDiffInformedAnalysisBranches } from "./diff-informed-analysis-utils";
|
import { getDiffInformedAnalysisBranches } from "./diff-informed-analysis-utils";
|
||||||
import { EnvVar } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
import { Feature, Features } from "./feature-flags";
|
import { Features } from "./feature-flags";
|
||||||
import { KnownLanguage } from "./languages";
|
import { KnownLanguage } from "./languages";
|
||||||
import { getActionsLogger, Logger } from "./logging";
|
import { getActionsLogger, Logger } from "./logging";
|
||||||
import { cleanupAndUploadOverlayBaseDatabaseToCache } from "./overlay-database-utils";
|
import { cleanupAndUploadOverlayBaseDatabaseToCache } from "./overlay-database-utils";
|
||||||
@@ -59,15 +57,13 @@ interface AnalysisStatusReport
|
|||||||
extends uploadLib.UploadStatusReport,
|
extends uploadLib.UploadStatusReport,
|
||||||
QueriesStatusReport {}
|
QueriesStatusReport {}
|
||||||
|
|
||||||
interface DependencyCachingUploadStatusReport {
|
|
||||||
dependency_caching_upload_results?: DependencyCacheUploadStatusReport;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface FinishStatusReport
|
interface FinishStatusReport
|
||||||
extends StatusReportBase,
|
extends StatusReportBase,
|
||||||
DatabaseCreationTimings,
|
DatabaseCreationTimings,
|
||||||
AnalysisStatusReport,
|
AnalysisStatusReport {
|
||||||
DependencyCachingUploadStatusReport {}
|
dependency_caching_upload_results?: DependencyCacheUploadStatusReport;
|
||||||
|
database_upload_results: DatabaseUploadResult[];
|
||||||
|
}
|
||||||
|
|
||||||
interface FinishWithTrapUploadStatusReport extends FinishStatusReport {
|
interface FinishWithTrapUploadStatusReport extends FinishStatusReport {
|
||||||
/** Size of TRAP caches that we uploaded, in bytes. */
|
/** Size of TRAP caches that we uploaded, in bytes. */
|
||||||
@@ -86,6 +82,7 @@ async function sendStatusReport(
|
|||||||
didUploadTrapCaches: boolean,
|
didUploadTrapCaches: boolean,
|
||||||
trapCacheCleanup: TrapCacheCleanupStatusReport | undefined,
|
trapCacheCleanup: TrapCacheCleanupStatusReport | undefined,
|
||||||
dependencyCacheResults: DependencyCacheUploadStatusReport | undefined,
|
dependencyCacheResults: DependencyCacheUploadStatusReport | undefined,
|
||||||
|
databaseUploadResults: DatabaseUploadResult[],
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
) {
|
) {
|
||||||
const status = getActionsStatus(error, stats?.analyze_failure_language);
|
const status = getActionsStatus(error, stats?.analyze_failure_language);
|
||||||
@@ -106,6 +103,7 @@ async function sendStatusReport(
|
|||||||
...(dbCreationTimings || {}),
|
...(dbCreationTimings || {}),
|
||||||
...(trapCacheCleanup || {}),
|
...(trapCacheCleanup || {}),
|
||||||
dependency_caching_upload_results: dependencyCacheResults,
|
dependency_caching_upload_results: dependencyCacheResults,
|
||||||
|
database_upload_results: databaseUploadResults,
|
||||||
};
|
};
|
||||||
if (config && didUploadTrapCaches) {
|
if (config && didUploadTrapCaches) {
|
||||||
const trapCacheUploadStatusReport: FinishWithTrapUploadStatusReport = {
|
const trapCacheUploadStatusReport: FinishWithTrapUploadStatusReport = {
|
||||||
@@ -223,6 +221,7 @@ async function run() {
|
|||||||
let dbCreationTimings: DatabaseCreationTimings | undefined = undefined;
|
let dbCreationTimings: DatabaseCreationTimings | undefined = undefined;
|
||||||
let didUploadTrapCaches = false;
|
let didUploadTrapCaches = false;
|
||||||
let dependencyCacheResults: DependencyCacheUploadStatusReport | undefined;
|
let dependencyCacheResults: DependencyCacheUploadStatusReport | undefined;
|
||||||
|
let databaseUploadResults: DatabaseUploadResult[] = [];
|
||||||
util.initializeEnvironment(actionsUtil.getActionVersion());
|
util.initializeEnvironment(actionsUtil.getActionVersion());
|
||||||
|
|
||||||
// Make inputs accessible in the `post` step, details at
|
// Make inputs accessible in the `post` step, details at
|
||||||
@@ -358,46 +357,15 @@ async function run() {
|
|||||||
const checkoutPath = actionsUtil.getRequiredInput("checkout_path");
|
const checkoutPath = actionsUtil.getRequiredInput("checkout_path");
|
||||||
const category = actionsUtil.getOptionalInput("category");
|
const category = actionsUtil.getOptionalInput("category");
|
||||||
|
|
||||||
if (await features.getValue(Feature.AnalyzeUseNewUpload)) {
|
uploadResults = await postProcessAndUploadSarif(
|
||||||
uploadResults = await postProcessAndUploadSarif(
|
logger,
|
||||||
logger,
|
features,
|
||||||
features,
|
uploadKind,
|
||||||
uploadKind,
|
checkoutPath,
|
||||||
checkoutPath,
|
outputDir,
|
||||||
outputDir,
|
category,
|
||||||
category,
|
actionsUtil.getOptionalInput("post-processed-sarif-path"),
|
||||||
actionsUtil.getOptionalInput("post-processed-sarif-path"),
|
);
|
||||||
);
|
|
||||||
} else if (uploadKind === "always") {
|
|
||||||
uploadResults = {};
|
|
||||||
|
|
||||||
if (isCodeScanningEnabled(config)) {
|
|
||||||
uploadResults[analyses.AnalysisKind.CodeScanning] =
|
|
||||||
await uploadLib.uploadFiles(
|
|
||||||
outputDir,
|
|
||||||
checkoutPath,
|
|
||||||
category,
|
|
||||||
features,
|
|
||||||
logger,
|
|
||||||
analyses.CodeScanning,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isCodeQualityEnabled(config)) {
|
|
||||||
uploadResults[analyses.AnalysisKind.CodeQuality] =
|
|
||||||
await uploadLib.uploadFiles(
|
|
||||||
outputDir,
|
|
||||||
checkoutPath,
|
|
||||||
category,
|
|
||||||
features,
|
|
||||||
logger,
|
|
||||||
analyses.CodeQuality,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
uploadResults = {};
|
|
||||||
logger.info("Not uploading results");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set the SARIF id outputs only if we have results for them, to avoid
|
// Set the SARIF id outputs only if we have results for them, to avoid
|
||||||
// having keys with empty values in the action output.
|
// having keys with empty values in the action output.
|
||||||
@@ -425,7 +393,7 @@ async function run() {
|
|||||||
// Possibly upload the database bundles for remote queries.
|
// Possibly upload the database bundles for remote queries.
|
||||||
// Note: Take care with the ordering of this call since databases may be cleaned up
|
// Note: Take care with the ordering of this call since databases may be cleaned up
|
||||||
// at the `overlay` or `clear` level.
|
// at the `overlay` or `clear` level.
|
||||||
await cleanupAndUploadDatabases(
|
databaseUploadResults = await cleanupAndUploadDatabases(
|
||||||
repositoryNwo,
|
repositoryNwo,
|
||||||
codeql,
|
codeql,
|
||||||
config,
|
config,
|
||||||
@@ -497,6 +465,7 @@ async function run() {
|
|||||||
didUploadTrapCaches,
|
didUploadTrapCaches,
|
||||||
trapCacheCleanupTelemetry,
|
trapCacheCleanupTelemetry,
|
||||||
dependencyCacheResults,
|
dependencyCacheResults,
|
||||||
|
databaseUploadResults,
|
||||||
logger,
|
logger,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
@@ -519,6 +488,7 @@ async function run() {
|
|||||||
didUploadTrapCaches,
|
didUploadTrapCaches,
|
||||||
trapCacheCleanupTelemetry,
|
trapCacheCleanupTelemetry,
|
||||||
dependencyCacheResults,
|
dependencyCacheResults,
|
||||||
|
databaseUploadResults,
|
||||||
logger,
|
logger,
|
||||||
);
|
);
|
||||||
} else if (runStats !== undefined) {
|
} else if (runStats !== undefined) {
|
||||||
@@ -532,6 +502,7 @@ async function run() {
|
|||||||
didUploadTrapCaches,
|
didUploadTrapCaches,
|
||||||
trapCacheCleanupTelemetry,
|
trapCacheCleanupTelemetry,
|
||||||
dependencyCacheResults,
|
dependencyCacheResults,
|
||||||
|
databaseUploadResults,
|
||||||
logger,
|
logger,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -545,6 +516,7 @@ async function run() {
|
|||||||
didUploadTrapCaches,
|
didUploadTrapCaches,
|
||||||
trapCacheCleanupTelemetry,
|
trapCacheCleanupTelemetry,
|
||||||
dependencyCacheResults,
|
dependencyCacheResults,
|
||||||
|
databaseUploadResults,
|
||||||
logger,
|
logger,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,14 +95,14 @@ test("getGitHubVersion for different domain", async (t) => {
|
|||||||
t.deepEqual({ type: util.GitHubVariant.DOTCOM }, v3);
|
t.deepEqual({ type: util.GitHubVariant.DOTCOM }, v3);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("getGitHubVersion for GHE_DOTCOM", async (t) => {
|
test("getGitHubVersion for GHEC-DR", async (t) => {
|
||||||
mockGetMetaVersionHeader("ghe.com");
|
mockGetMetaVersionHeader("ghe.com");
|
||||||
const gheDotcom = await api.getGitHubVersionFromApi(api.getApiClient(), {
|
const gheDotcom = await api.getGitHubVersionFromApi(api.getApiClient(), {
|
||||||
auth: "",
|
auth: "",
|
||||||
url: "https://foo.ghe.com",
|
url: "https://foo.ghe.com",
|
||||||
apiURL: undefined,
|
apiURL: undefined,
|
||||||
});
|
});
|
||||||
t.deepEqual({ type: util.GitHubVariant.GHE_DOTCOM }, gheDotcom);
|
t.deepEqual({ type: util.GitHubVariant.GHEC_DR }, gheDotcom);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("wrapApiConfigurationError correctly wraps specific configuration errors", (t) => {
|
test("wrapApiConfigurationError correctly wraps specific configuration errors", (t) => {
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ export async function getGitHubVersionFromApi(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] === "ghe.com") {
|
if (response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] === "ghe.com") {
|
||||||
return { type: GitHubVariant.GHE_DOTCOM };
|
return { type: GitHubVariant.GHEC_DR };
|
||||||
}
|
}
|
||||||
|
|
||||||
const version = response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] as string;
|
const version = response.headers[GITHUB_ENTERPRISE_VERSION_HEADER] as string;
|
||||||
|
|||||||
98
src/artifact-scanner.test.ts
Normal file
98
src/artifact-scanner.test.ts
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
import * as fs from "fs";
|
||||||
|
import * as os from "os";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
import test from "ava";
|
||||||
|
|
||||||
|
import { scanArtifactsForTokens } from "./artifact-scanner";
|
||||||
|
import { getRunnerLogger } from "./logging";
|
||||||
|
import { getRecordingLogger, LoggedMessage } from "./testing-utils";
|
||||||
|
|
||||||
|
test("scanArtifactsForTokens detects GitHub tokens in files", async (t) => {
|
||||||
|
const logger = getRunnerLogger(true);
|
||||||
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "scanner-test-"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a test file with a fake GitHub token
|
||||||
|
const testFile = path.join(tempDir, "test.txt");
|
||||||
|
fs.writeFileSync(
|
||||||
|
testFile,
|
||||||
|
"This is a test file with token ghp_1234567890123456789012345678901234AB",
|
||||||
|
);
|
||||||
|
|
||||||
|
const error = await t.throwsAsync(
|
||||||
|
async () => await scanArtifactsForTokens([testFile], logger),
|
||||||
|
);
|
||||||
|
|
||||||
|
t.regex(
|
||||||
|
error?.message || "",
|
||||||
|
/Found 1 potential GitHub token.*Personal Access Token/,
|
||||||
|
);
|
||||||
|
t.regex(error?.message || "", /test\.txt/);
|
||||||
|
} finally {
|
||||||
|
// Clean up
|
||||||
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("scanArtifactsForTokens handles files without tokens", async (t) => {
|
||||||
|
const logger = getRunnerLogger(true);
|
||||||
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "scanner-test-"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Create a test file without tokens
|
||||||
|
const testFile = path.join(tempDir, "test.txt");
|
||||||
|
fs.writeFileSync(
|
||||||
|
testFile,
|
||||||
|
"This is a test file without any sensitive data",
|
||||||
|
);
|
||||||
|
|
||||||
|
await t.notThrowsAsync(
|
||||||
|
async () => await scanArtifactsForTokens([testFile], logger),
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
// Clean up
|
||||||
|
fs.rmSync(tempDir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
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
|
||||||
|
// https://github.com/github/codeql-action/security/advisories/GHSA-vqf5-2xx6-9wfm
|
||||||
|
const testZip = path.join(
|
||||||
|
__dirname,
|
||||||
|
"..",
|
||||||
|
"src",
|
||||||
|
"testdata",
|
||||||
|
"debug-artifacts-with-fake-token.zip",
|
||||||
|
);
|
||||||
|
|
||||||
|
// This zip file contains a nested structure with a fake token in:
|
||||||
|
// my-db-java-partial.zip/trap/java/invocations/kotlin.9017231652989744319.trap
|
||||||
|
const error = await t.throwsAsync(
|
||||||
|
async () => await scanArtifactsForTokens([testZip], logger),
|
||||||
|
);
|
||||||
|
|
||||||
|
t.regex(
|
||||||
|
error?.message || "",
|
||||||
|
/Found.*potential GitHub token/,
|
||||||
|
"Should detect token in nested zip",
|
||||||
|
);
|
||||||
|
t.regex(
|
||||||
|
error?.message || "",
|
||||||
|
/kotlin\.9017231652989744319\.trap/,
|
||||||
|
"Should report the .trap file containing the token",
|
||||||
|
);
|
||||||
|
|
||||||
|
const logOutput = messages.map((msg) => msg.message).join("\n");
|
||||||
|
t.regex(
|
||||||
|
logOutput,
|
||||||
|
/^Extracting gz file: .*\.gz$/m,
|
||||||
|
"Logs should show that .gz files were extracted",
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
379
src/artifact-scanner.ts
Normal file
379
src/artifact-scanner.ts
Normal file
@@ -0,0 +1,379 @@
|
|||||||
|
import * as fs from "fs";
|
||||||
|
import * as os from "os";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
import * as exec from "@actions/exec";
|
||||||
|
|
||||||
|
import { Logger } from "./logging";
|
||||||
|
import { getErrorMessage } from "./util";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GitHub token patterns to scan for.
|
||||||
|
* These patterns match various GitHub token formats.
|
||||||
|
*/
|
||||||
|
const GITHUB_TOKEN_PATTERNS = [
|
||||||
|
{
|
||||||
|
name: "Personal Access Token",
|
||||||
|
pattern: /\bghp_[a-zA-Z0-9]{36}\b/g,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OAuth Access Token",
|
||||||
|
pattern: /\bgho_[a-zA-Z0-9]{36}\b/g,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "User-to-Server Token",
|
||||||
|
pattern: /\bghu_[a-zA-Z0-9]{36}\b/g,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Server-to-Server Token",
|
||||||
|
pattern: /\bghs_[a-zA-Z0-9]{36}\b/g,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Refresh Token",
|
||||||
|
pattern: /\bghr_[a-zA-Z0-9]{36}\b/g,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "App Installation Access Token",
|
||||||
|
pattern: /\bghs_[a-zA-Z0-9]{255}\b/g,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
interface TokenFinding {
|
||||||
|
tokenType: string;
|
||||||
|
filePath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScanResult {
|
||||||
|
scannedFiles: number;
|
||||||
|
findings: TokenFinding[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a file for GitHub tokens.
|
||||||
|
*
|
||||||
|
* @param filePath Path to the file to scan
|
||||||
|
* @param relativePath Relative path for display purposes
|
||||||
|
* @param logger Logger instance
|
||||||
|
* @returns Array of token findings in the file
|
||||||
|
*/
|
||||||
|
function scanFileForTokens(
|
||||||
|
filePath: string,
|
||||||
|
relativePath: string,
|
||||||
|
logger: Logger,
|
||||||
|
): TokenFinding[] {
|
||||||
|
const findings: TokenFinding[] = [];
|
||||||
|
try {
|
||||||
|
const content = fs.readFileSync(filePath, "utf8");
|
||||||
|
|
||||||
|
for (const { name, pattern } of GITHUB_TOKEN_PATTERNS) {
|
||||||
|
const matches = content.match(pattern);
|
||||||
|
if (matches) {
|
||||||
|
for (let i = 0; i < matches.length; i++) {
|
||||||
|
findings.push({ tokenType: name, filePath: relativePath });
|
||||||
|
}
|
||||||
|
logger.debug(`Found ${matches.length} ${name}(s) in ${relativePath}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return findings;
|
||||||
|
} catch (e) {
|
||||||
|
// If we can't read the file as text, it's likely binary or inaccessible
|
||||||
|
logger.debug(
|
||||||
|
`Could not scan file ${filePath} for tokens: ${getErrorMessage(e)}`,
|
||||||
|
);
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively extracts and scans archive files (.zip, .gz, .tar.gz).
|
||||||
|
*
|
||||||
|
* @param archivePath Path to the archive file
|
||||||
|
* @param relativeArchivePath Relative path of the archive for display
|
||||||
|
* @param extractDir Directory to extract to
|
||||||
|
* @param logger Logger instance
|
||||||
|
* @param depth Current recursion depth (to prevent infinite loops)
|
||||||
|
* @returns Scan results
|
||||||
|
*/
|
||||||
|
async function scanArchiveFile(
|
||||||
|
archivePath: string,
|
||||||
|
relativeArchivePath: string,
|
||||||
|
extractDir: string,
|
||||||
|
logger: Logger,
|
||||||
|
depth: number = 0,
|
||||||
|
): Promise<ScanResult> {
|
||||||
|
const MAX_DEPTH = 10; // Prevent infinite recursion
|
||||||
|
if (depth > MAX_DEPTH) {
|
||||||
|
throw new Error(
|
||||||
|
`Maximum archive extraction depth (${MAX_DEPTH}) reached for ${archivePath}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const result: ScanResult = {
|
||||||
|
scannedFiles: 0,
|
||||||
|
findings: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
const tempExtractDir = fs.mkdtempSync(
|
||||||
|
path.join(extractDir, `extract-${depth}-`),
|
||||||
|
);
|
||||||
|
|
||||||
|
// Determine archive type and extract accordingly
|
||||||
|
const fileName = path.basename(archivePath).toLowerCase();
|
||||||
|
if (fileName.endsWith(".tar.gz") || fileName.endsWith(".tgz")) {
|
||||||
|
// Extract tar.gz files
|
||||||
|
logger.debug(`Extracting tar.gz file: ${archivePath}`);
|
||||||
|
await exec.exec("tar", ["-xzf", archivePath, "-C", tempExtractDir], {
|
||||||
|
silent: true,
|
||||||
|
});
|
||||||
|
} else if (fileName.endsWith(".tar.zst")) {
|
||||||
|
// Extract tar.zst files
|
||||||
|
logger.debug(`Extracting tar.zst file: ${archivePath}`);
|
||||||
|
await exec.exec(
|
||||||
|
"tar",
|
||||||
|
["--zstd", "-xf", archivePath, "-C", tempExtractDir],
|
||||||
|
{
|
||||||
|
silent: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else if (fileName.endsWith(".zst")) {
|
||||||
|
// Extract .zst files (single file compression)
|
||||||
|
logger.debug(`Extracting zst file: ${archivePath}`);
|
||||||
|
const outputFile = path.join(
|
||||||
|
tempExtractDir,
|
||||||
|
path.basename(archivePath, ".zst"),
|
||||||
|
);
|
||||||
|
await exec.exec("zstd", ["-d", archivePath, "-o", outputFile], {
|
||||||
|
silent: true,
|
||||||
|
});
|
||||||
|
} else if (fileName.endsWith(".gz")) {
|
||||||
|
// Extract .gz files (single file compression)
|
||||||
|
logger.debug(`Extracting gz file: ${archivePath}`);
|
||||||
|
const outputFile = path.join(
|
||||||
|
tempExtractDir,
|
||||||
|
path.basename(archivePath, ".gz"),
|
||||||
|
);
|
||||||
|
await exec.exec("gunzip", ["-c", archivePath], {
|
||||||
|
outStream: fs.createWriteStream(outputFile),
|
||||||
|
silent: true,
|
||||||
|
});
|
||||||
|
} else if (fileName.endsWith(".zip")) {
|
||||||
|
// Extract zip files
|
||||||
|
logger.debug(`Extracting zip file: ${archivePath}`);
|
||||||
|
await exec.exec(
|
||||||
|
"unzip",
|
||||||
|
["-q", "-o", archivePath, "-d", tempExtractDir],
|
||||||
|
{
|
||||||
|
silent: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan the extracted contents
|
||||||
|
const scanResult = await scanDirectory(
|
||||||
|
tempExtractDir,
|
||||||
|
relativeArchivePath,
|
||||||
|
logger,
|
||||||
|
depth + 1,
|
||||||
|
);
|
||||||
|
result.scannedFiles += scanResult.scannedFiles;
|
||||||
|
result.findings.push(...scanResult.findings);
|
||||||
|
|
||||||
|
// Clean up extracted files
|
||||||
|
fs.rmSync(tempExtractDir, { recursive: true, force: true });
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug(
|
||||||
|
`Could not extract or scan archive file ${archivePath}: ${getErrorMessage(e)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a single file, including recursive archive extraction if applicable.
|
||||||
|
*
|
||||||
|
* @param fullPath Full path to the file
|
||||||
|
* @param relativePath Relative path for display
|
||||||
|
* @param extractDir Directory to use for extraction (for archive files)
|
||||||
|
* @param logger Logger instance
|
||||||
|
* @param depth Current recursion depth
|
||||||
|
* @returns Scan results
|
||||||
|
*/
|
||||||
|
async function scanFile(
|
||||||
|
fullPath: string,
|
||||||
|
relativePath: string,
|
||||||
|
extractDir: string,
|
||||||
|
logger: Logger,
|
||||||
|
depth: number = 0,
|
||||||
|
): Promise<ScanResult> {
|
||||||
|
const result: ScanResult = {
|
||||||
|
scannedFiles: 1,
|
||||||
|
findings: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check if it's an archive file and recursively scan it
|
||||||
|
const fileName = path.basename(fullPath).toLowerCase();
|
||||||
|
const isArchive =
|
||||||
|
fileName.endsWith(".zip") ||
|
||||||
|
fileName.endsWith(".tar.gz") ||
|
||||||
|
fileName.endsWith(".tgz") ||
|
||||||
|
fileName.endsWith(".tar.zst") ||
|
||||||
|
fileName.endsWith(".zst") ||
|
||||||
|
fileName.endsWith(".gz");
|
||||||
|
|
||||||
|
if (isArchive) {
|
||||||
|
const archiveResult = await scanArchiveFile(
|
||||||
|
fullPath,
|
||||||
|
relativePath,
|
||||||
|
extractDir,
|
||||||
|
logger,
|
||||||
|
depth,
|
||||||
|
);
|
||||||
|
result.scannedFiles += archiveResult.scannedFiles;
|
||||||
|
result.findings.push(...archiveResult.findings);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scan the file itself for tokens (unless it's a pure binary archive format)
|
||||||
|
const fileFindings = scanFileForTokens(fullPath, relativePath, logger);
|
||||||
|
result.findings.push(...fileFindings);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursively scans a directory for GitHub tokens.
|
||||||
|
*
|
||||||
|
* @param dirPath Directory path to scan
|
||||||
|
* @param baseRelativePath Base relative path for computing display paths
|
||||||
|
* @param logger Logger instance
|
||||||
|
* @param depth Current recursion depth
|
||||||
|
* @returns Scan results
|
||||||
|
*/
|
||||||
|
async function scanDirectory(
|
||||||
|
dirPath: string,
|
||||||
|
baseRelativePath: string,
|
||||||
|
logger: Logger,
|
||||||
|
depth: number = 0,
|
||||||
|
): Promise<ScanResult> {
|
||||||
|
const result: ScanResult = {
|
||||||
|
scannedFiles: 0,
|
||||||
|
findings: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
||||||
|
|
||||||
|
for (const entry of entries) {
|
||||||
|
const fullPath = path.join(dirPath, entry.name);
|
||||||
|
const relativePath = path.join(baseRelativePath, entry.name);
|
||||||
|
|
||||||
|
if (entry.isDirectory()) {
|
||||||
|
const subResult = await scanDirectory(
|
||||||
|
fullPath,
|
||||||
|
relativePath,
|
||||||
|
logger,
|
||||||
|
depth,
|
||||||
|
);
|
||||||
|
result.scannedFiles += subResult.scannedFiles;
|
||||||
|
result.findings.push(...subResult.findings);
|
||||||
|
} else if (entry.isFile()) {
|
||||||
|
const fileResult = await scanFile(
|
||||||
|
fullPath,
|
||||||
|
relativePath,
|
||||||
|
path.dirname(fullPath),
|
||||||
|
logger,
|
||||||
|
depth,
|
||||||
|
);
|
||||||
|
result.scannedFiles += fileResult.scannedFiles;
|
||||||
|
result.findings.push(...fileResult.findings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scans a list of files and directories for GitHub tokens.
|
||||||
|
* Recursively extracts and scans archive files (.zip, .gz, .tar.gz).
|
||||||
|
*
|
||||||
|
* @param filesToScan List of file paths to scan
|
||||||
|
* @param logger Logger instance
|
||||||
|
* @returns Scan results
|
||||||
|
*/
|
||||||
|
export async function scanArtifactsForTokens(
|
||||||
|
filesToScan: string[],
|
||||||
|
logger: Logger,
|
||||||
|
): Promise<void> {
|
||||||
|
logger.info(
|
||||||
|
"Starting best-effort check for potential GitHub tokens in debug artifacts (for testing purposes only)...",
|
||||||
|
);
|
||||||
|
|
||||||
|
const result: ScanResult = {
|
||||||
|
scannedFiles: 0,
|
||||||
|
findings: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a temporary directory for extraction
|
||||||
|
const tempScanDir = fs.mkdtempSync(path.join(os.tmpdir(), "artifact-scan-"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
for (const filePath of filesToScan) {
|
||||||
|
const stats = fs.statSync(filePath);
|
||||||
|
const fileName = path.basename(filePath);
|
||||||
|
|
||||||
|
if (stats.isDirectory()) {
|
||||||
|
const dirResult = await scanDirectory(filePath, fileName, logger);
|
||||||
|
result.scannedFiles += dirResult.scannedFiles;
|
||||||
|
result.findings.push(...dirResult.findings);
|
||||||
|
} else if (stats.isFile()) {
|
||||||
|
const fileResult = await scanFile(
|
||||||
|
filePath,
|
||||||
|
fileName,
|
||||||
|
tempScanDir,
|
||||||
|
logger,
|
||||||
|
);
|
||||||
|
result.scannedFiles += fileResult.scannedFiles;
|
||||||
|
result.findings.push(...fileResult.findings);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute statistics from findings
|
||||||
|
const tokenTypesCounts = new Map<string, number>();
|
||||||
|
const filesWithTokens = new Set<string>();
|
||||||
|
for (const finding of result.findings) {
|
||||||
|
tokenTypesCounts.set(
|
||||||
|
finding.tokenType,
|
||||||
|
(tokenTypesCounts.get(finding.tokenType) || 0) + 1,
|
||||||
|
);
|
||||||
|
filesWithTokens.add(finding.filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenTypesSummary = Array.from(tokenTypesCounts.entries())
|
||||||
|
.map(([type, count]) => `${count} ${type}${count > 1 ? "s" : ""}`)
|
||||||
|
.join(", ");
|
||||||
|
|
||||||
|
const baseSummary = `scanned ${result.scannedFiles} files, found ${result.findings.length} potential token(s) in ${filesWithTokens.size} file(s)`;
|
||||||
|
const summaryWithTypes = tokenTypesSummary
|
||||||
|
? `${baseSummary} (${tokenTypesSummary})`
|
||||||
|
: baseSummary;
|
||||||
|
|
||||||
|
logger.info(`Artifact check complete: ${summaryWithTypes}`);
|
||||||
|
|
||||||
|
if (result.findings.length > 0) {
|
||||||
|
const fileList = Array.from(filesWithTokens).join(", ");
|
||||||
|
throw new Error(
|
||||||
|
`Found ${result.findings.length} potential GitHub token(s) (${tokenTypesSummary}) in debug artifacts at: ${fileList}. This is a best-effort check for testing purposes only.`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
// Clean up temporary directory
|
||||||
|
try {
|
||||||
|
fs.rmSync(tempScanDir, { recursive: true, force: true });
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug(
|
||||||
|
`Could not clean up temporary scan directory: ${getErrorMessage(e)}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -206,6 +206,7 @@ export interface CodeQL {
|
|||||||
* Run 'codeql resolve queries --format=startingpacks'.
|
* Run 'codeql resolve queries --format=startingpacks'.
|
||||||
*/
|
*/
|
||||||
resolveQueriesStartingPacks(queries: string[]): Promise<string[]>;
|
resolveQueriesStartingPacks(queries: string[]): Promise<string[]>;
|
||||||
|
resolveDatabase(databasePath: string): Promise<ResolveDatabaseOutput>;
|
||||||
/**
|
/**
|
||||||
* Run 'codeql github merge-results'.
|
* Run 'codeql github merge-results'.
|
||||||
*/
|
*/
|
||||||
@@ -230,6 +231,10 @@ export interface VersionInfo {
|
|||||||
overlayVersion?: number;
|
overlayVersion?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ResolveDatabaseOutput {
|
||||||
|
overlayBaseSpecifier?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ResolveLanguagesOutput {
|
export interface ResolveLanguagesOutput {
|
||||||
[language: string]: [string];
|
[language: string]: [string];
|
||||||
}
|
}
|
||||||
@@ -493,6 +498,7 @@ export function createStubCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
|
|||||||
partialCodeql,
|
partialCodeql,
|
||||||
"resolveQueriesStartingPacks",
|
"resolveQueriesStartingPacks",
|
||||||
),
|
),
|
||||||
|
resolveDatabase: resolveFunction(partialCodeql, "resolveDatabase"),
|
||||||
mergeResults: resolveFunction(partialCodeql, "mergeResults"),
|
mergeResults: resolveFunction(partialCodeql, "mergeResults"),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -1003,6 +1009,26 @@ async function getCodeQLForCmd(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
async resolveDatabase(
|
||||||
|
databasePath: string,
|
||||||
|
): Promise<ResolveDatabaseOutput> {
|
||||||
|
const codeqlArgs = [
|
||||||
|
"resolve",
|
||||||
|
"database",
|
||||||
|
databasePath,
|
||||||
|
"--format=json",
|
||||||
|
...getExtraOptionsFromEnv(["resolve", "database"]),
|
||||||
|
];
|
||||||
|
const output = await runCli(cmd, codeqlArgs, { noStreamStdout: true });
|
||||||
|
|
||||||
|
try {
|
||||||
|
return JSON.parse(output) as ResolveDatabaseOutput;
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error(
|
||||||
|
`Unexpected output from codeql resolve database --format=json: ${e}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
async mergeResults(
|
async mergeResults(
|
||||||
sarifFiles: string[],
|
sarifFiles: string[],
|
||||||
outputFile: string,
|
outputFile: string,
|
||||||
|
|||||||
@@ -231,7 +231,7 @@ test("Don't crash if uploading a database fails", async (t) => {
|
|||||||
(v) =>
|
(v) =>
|
||||||
v.type === "warning" &&
|
v.type === "warning" &&
|
||||||
v.message ===
|
v.message ===
|
||||||
"Failed to upload database for javascript: Error: some error message",
|
"Failed to upload database for javascript: some error message",
|
||||||
) !== undefined,
|
) !== undefined,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,20 @@ import { RepositoryNwo } from "./repository";
|
|||||||
import * as util from "./util";
|
import * as util from "./util";
|
||||||
import { bundleDb, CleanupLevel, parseGitHubUrl } from "./util";
|
import { bundleDb, CleanupLevel, parseGitHubUrl } from "./util";
|
||||||
|
|
||||||
|
/** Information about a database upload. */
|
||||||
|
export interface DatabaseUploadResult {
|
||||||
|
/** Language of the database. */
|
||||||
|
language: string;
|
||||||
|
/** Size of the zipped database in bytes. */
|
||||||
|
zipped_upload_size_bytes?: number;
|
||||||
|
/** Whether the uploaded database is an overlay base. */
|
||||||
|
is_overlay_base?: boolean;
|
||||||
|
/** Time taken to upload database in milliseconds. */
|
||||||
|
upload_duration_ms?: number;
|
||||||
|
/** If there was an error during database upload, this is its message. */
|
||||||
|
error?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export async function cleanupAndUploadDatabases(
|
export async function cleanupAndUploadDatabases(
|
||||||
repositoryNwo: RepositoryNwo,
|
repositoryNwo: RepositoryNwo,
|
||||||
codeql: CodeQL,
|
codeql: CodeQL,
|
||||||
@@ -20,44 +34,46 @@ export async function cleanupAndUploadDatabases(
|
|||||||
apiDetails: GitHubApiDetails,
|
apiDetails: GitHubApiDetails,
|
||||||
features: FeatureEnablement,
|
features: FeatureEnablement,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
): Promise<void> {
|
): Promise<DatabaseUploadResult[]> {
|
||||||
if (actionsUtil.getRequiredInput("upload-database") !== "true") {
|
if (actionsUtil.getRequiredInput("upload-database") !== "true") {
|
||||||
logger.debug("Database upload disabled in workflow. Skipping upload.");
|
logger.debug("Database upload disabled in workflow. Skipping upload.");
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config.analysisKinds.includes(AnalysisKind.CodeScanning)) {
|
if (!config.analysisKinds.includes(AnalysisKind.CodeScanning)) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`Not uploading database because 'analysis-kinds: ${AnalysisKind.CodeScanning}' is not enabled.`,
|
`Not uploading database because 'analysis-kinds: ${AnalysisKind.CodeScanning}' is not enabled.`,
|
||||||
);
|
);
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util.isInTestMode()) {
|
if (util.isInTestMode()) {
|
||||||
logger.debug("In test mode. Skipping database upload.");
|
logger.debug("In test mode. Skipping database upload.");
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do nothing when not running against github.com
|
// Do nothing when not running against github.com
|
||||||
if (
|
if (
|
||||||
config.gitHubVersion.type !== util.GitHubVariant.DOTCOM &&
|
config.gitHubVersion.type !== util.GitHubVariant.DOTCOM &&
|
||||||
config.gitHubVersion.type !== util.GitHubVariant.GHE_DOTCOM
|
config.gitHubVersion.type !== util.GitHubVariant.GHEC_DR
|
||||||
) {
|
) {
|
||||||
logger.debug("Not running against github.com or GHEC-DR. Skipping upload.");
|
logger.debug("Not running against github.com or GHEC-DR. Skipping upload.");
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(await gitUtils.isAnalyzingDefaultBranch())) {
|
if (!(await gitUtils.isAnalyzingDefaultBranch())) {
|
||||||
// We only want to upload a database if we are analyzing the default branch.
|
// We only want to upload a database if we are analyzing the default branch.
|
||||||
logger.debug("Not analyzing default branch. Skipping upload.");
|
logger.debug("Not analyzing default branch. Skipping upload.");
|
||||||
return;
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const cleanupLevel =
|
// If config.overlayDatabaseMode is OverlayBase, then we have overlay base databases for all languages.
|
||||||
|
const shouldUploadOverlayBase =
|
||||||
config.overlayDatabaseMode === OverlayDatabaseMode.OverlayBase &&
|
config.overlayDatabaseMode === OverlayDatabaseMode.OverlayBase &&
|
||||||
(await features.getValue(Feature.UploadOverlayDbToApi))
|
(await features.getValue(Feature.UploadOverlayDbToApi));
|
||||||
? CleanupLevel.Overlay
|
const cleanupLevel = shouldUploadOverlayBase
|
||||||
: CleanupLevel.Clear;
|
? CleanupLevel.Overlay
|
||||||
|
: CleanupLevel.Clear;
|
||||||
|
|
||||||
// Clean up the database, since intermediate results may still be written to the
|
// Clean up the database, since intermediate results may still be written to the
|
||||||
// database if there is high RAM pressure.
|
// database if there is high RAM pressure.
|
||||||
@@ -77,6 +93,7 @@ export async function cleanupAndUploadDatabases(
|
|||||||
uploadsBaseUrl = uploadsBaseUrl.slice(0, -1);
|
uploadsBaseUrl = uploadsBaseUrl.slice(0, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const reports: DatabaseUploadResult[] = [];
|
||||||
for (const language of config.languages) {
|
for (const language of config.languages) {
|
||||||
try {
|
try {
|
||||||
// Upload the database bundle.
|
// Upload the database bundle.
|
||||||
@@ -90,6 +107,7 @@ export async function cleanupAndUploadDatabases(
|
|||||||
actionsUtil.getRequiredInput("checkout_path"),
|
actionsUtil.getRequiredInput("checkout_path"),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
|
const startTime = performance.now();
|
||||||
await client.request(
|
await client.request(
|
||||||
`POST /repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name&commit_oid=:commit_oid`,
|
`POST /repos/:owner/:repo/code-scanning/codeql/databases/:language?name=:name&commit_oid=:commit_oid`,
|
||||||
{
|
{
|
||||||
@@ -107,13 +125,27 @@ export async function cleanupAndUploadDatabases(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
const endTime = performance.now();
|
||||||
|
reports.push({
|
||||||
|
language,
|
||||||
|
zipped_upload_size_bytes: bundledDbSize,
|
||||||
|
is_overlay_base: shouldUploadOverlayBase,
|
||||||
|
upload_duration_ms: endTime - startTime,
|
||||||
|
});
|
||||||
logger.debug(`Successfully uploaded database for ${language}`);
|
logger.debug(`Successfully uploaded database for ${language}`);
|
||||||
} finally {
|
} finally {
|
||||||
bundledDbReadStream.close();
|
bundledDbReadStream.close();
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Log a warning but don't fail the workflow
|
// Log a warning but don't fail the workflow
|
||||||
logger.warning(`Failed to upload database for ${language}: ${e}`);
|
logger.warning(
|
||||||
|
`Failed to upload database for ${language}: ${util.getErrorMessage(e)}`,
|
||||||
|
);
|
||||||
|
reports.push({
|
||||||
|
language,
|
||||||
|
error: util.getErrorMessage(e),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return reports;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import archiver from "archiver";
|
|||||||
|
|
||||||
import { getOptionalInput, getTemporaryDirectory } from "./actions-util";
|
import { getOptionalInput, getTemporaryDirectory } from "./actions-util";
|
||||||
import { dbIsFinalized } from "./analyze";
|
import { dbIsFinalized } from "./analyze";
|
||||||
|
import { scanArtifactsForTokens } from "./artifact-scanner";
|
||||||
import { type CodeQL } from "./codeql";
|
import { type CodeQL } from "./codeql";
|
||||||
import { Config } from "./config-utils";
|
import { Config } from "./config-utils";
|
||||||
import { EnvVar } from "./environment";
|
import { EnvVar } from "./environment";
|
||||||
@@ -23,6 +24,7 @@ import {
|
|||||||
getCodeQLDatabasePath,
|
getCodeQLDatabasePath,
|
||||||
getErrorMessage,
|
getErrorMessage,
|
||||||
GitHubVariant,
|
GitHubVariant,
|
||||||
|
isInTestMode,
|
||||||
listFolder,
|
listFolder,
|
||||||
} from "./util";
|
} from "./util";
|
||||||
|
|
||||||
@@ -269,6 +271,14 @@ export async function uploadDebugArtifacts(
|
|||||||
return "upload-not-supported";
|
return "upload-not-supported";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// When running in test mode, perform a best effort scan of the debug artifacts. The artifact
|
||||||
|
// scanner is basic and not reliable or fast enough for production use, but it can help catch
|
||||||
|
// some issues early.
|
||||||
|
if (isInTestMode()) {
|
||||||
|
await scanArtifactsForTokens(toUpload, logger);
|
||||||
|
core.exportVariable("CODEQL_ACTION_ARTIFACT_SCAN_FINISHED", "true");
|
||||||
|
}
|
||||||
|
|
||||||
let suffix = "";
|
let suffix = "";
|
||||||
const matrix = getOptionalInput("matrix");
|
const matrix = getOptionalInput("matrix");
|
||||||
if (matrix) {
|
if (matrix) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"bundleVersion": "codeql-bundle-v2.23.6",
|
"bundleVersion": "codeql-bundle-v2.23.8",
|
||||||
"cliVersion": "2.23.6",
|
"cliVersion": "2.23.8",
|
||||||
"priorBundleVersion": "codeql-bundle-v2.23.5",
|
"priorBundleVersion": "codeql-bundle-v2.23.7",
|
||||||
"priorCliVersion": "2.23.5"
|
"priorCliVersion": "2.23.7"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -603,28 +603,6 @@ test("getFeaturePrefix - returns empty string if no features are enabled", async
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
test("getFeaturePrefix - Java - returns 'minify-' if JavaMinimizeDependencyJars is enabled", async (t) => {
|
|
||||||
const codeql = createStubCodeQL({});
|
|
||||||
const features = createFeatures([Feature.JavaMinimizeDependencyJars]);
|
|
||||||
|
|
||||||
const result = await getFeaturePrefix(codeql, features, KnownLanguage.java);
|
|
||||||
t.deepEqual(result, "minify-");
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getFeaturePrefix - non-Java - returns '' if JavaMinimizeDependencyJars is enabled", async (t) => {
|
|
||||||
const codeql = createStubCodeQL({});
|
|
||||||
const features = createFeatures([Feature.JavaMinimizeDependencyJars]);
|
|
||||||
|
|
||||||
for (const knownLanguage of Object.values(KnownLanguage)) {
|
|
||||||
// Skip Java since we expect a result for it, which is tested in the previous test.
|
|
||||||
if (knownLanguage === KnownLanguage.java) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const result = await getFeaturePrefix(codeql, features, knownLanguage);
|
|
||||||
t.deepEqual(result, "", `Expected no feature prefix for ${knownLanguage}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
test("getFeaturePrefix - C# - returns prefix if CsharpNewCacheKey is enabled", async (t) => {
|
test("getFeaturePrefix - C# - returns prefix if CsharpNewCacheKey is enabled", async (t) => {
|
||||||
const codeql = createStubCodeQL({});
|
const codeql = createStubCodeQL({});
|
||||||
const features = createFeatures([Feature.CsharpNewCacheKey]);
|
const features = createFeatures([Feature.CsharpNewCacheKey]);
|
||||||
|
|||||||
@@ -541,18 +541,7 @@ export async function getFeaturePrefix(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (language === KnownLanguage.java) {
|
if (language === KnownLanguage.csharp) {
|
||||||
// To ensure a safe rollout of JAR minimization, we change the key when the feature is enabled.
|
|
||||||
const minimizeJavaJars = await features.getValue(
|
|
||||||
Feature.JavaMinimizeDependencyJars,
|
|
||||||
codeql,
|
|
||||||
);
|
|
||||||
|
|
||||||
// To maintain backwards compatibility with this, we return "minify-" instead of a hash.
|
|
||||||
if (minimizeJavaJars) {
|
|
||||||
return "minify-";
|
|
||||||
}
|
|
||||||
} else if (language === KnownLanguage.csharp) {
|
|
||||||
await addFeatureIfEnabled(Feature.CsharpNewCacheKey);
|
await addFeatureIfEnabled(Feature.CsharpNewCacheKey);
|
||||||
await addFeatureIfEnabled(Feature.CsharpCacheBuildModeNone);
|
await addFeatureIfEnabled(Feature.CsharpCacheBuildModeNone);
|
||||||
}
|
}
|
||||||
@@ -593,14 +582,8 @@ async function cachePrefix(
|
|||||||
// experimental features that affect the cache contents.
|
// experimental features that affect the cache contents.
|
||||||
const featurePrefix = await getFeaturePrefix(codeql, features, language);
|
const featurePrefix = await getFeaturePrefix(codeql, features, language);
|
||||||
|
|
||||||
// Assemble the cache key. For backwards compatibility with the JAR minification experiment's existing
|
// Assemble the cache key.
|
||||||
// feature prefix usage, we add that feature prefix at the start. Other feature prefixes are inserted
|
return `${prefix}-${featurePrefix}${CODEQL_DEPENDENCY_CACHE_VERSION}-${runnerOs}-${language}-`;
|
||||||
// after the general CodeQL dependency cache prefix.
|
|
||||||
if (featurePrefix === "minify-") {
|
|
||||||
return `${featurePrefix}${prefix}-${CODEQL_DEPENDENCY_CACHE_VERSION}-${runnerOs}-${language}-`;
|
|
||||||
} else {
|
|
||||||
return `${prefix}-${featurePrefix}${CODEQL_DEPENDENCY_CACHE_VERSION}-${runnerOs}-${language}-`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Represents information about our overall cache usage for CodeQL dependency caches. */
|
/** Represents information about our overall cache usage for CodeQL dependency caches. */
|
||||||
|
|||||||
@@ -62,13 +62,13 @@ test(`All features are disabled if running against GHES`, async (t) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test(`Feature flags are requested in Proxima`, async (t) => {
|
test(`Feature flags are requested in GHEC-DR`, async (t) => {
|
||||||
await withTmpDir(async (tmpDir) => {
|
await withTmpDir(async (tmpDir) => {
|
||||||
const loggedMessages = [];
|
const loggedMessages = [];
|
||||||
const features = setUpFeatureFlagTests(
|
const features = setUpFeatureFlagTests(
|
||||||
tmpDir,
|
tmpDir,
|
||||||
getRecordingLogger(loggedMessages),
|
getRecordingLogger(loggedMessages),
|
||||||
{ type: GitHubVariant.GHE_DOTCOM },
|
{ type: GitHubVariant.GHEC_DR },
|
||||||
);
|
);
|
||||||
|
|
||||||
mockFeatureFlagApiEndpoint(200, initializeFeatures(true));
|
mockFeatureFlagApiEndpoint(200, initializeFeatures(true));
|
||||||
@@ -436,97 +436,79 @@ test(`selects CLI from defaults.json on GHES`, async (t) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test("selects CLI v2.20.1 on Dotcom when feature flags enable v2.20.0 and v2.20.1", async (t) => {
|
for (const variant of [GitHubVariant.DOTCOM, GitHubVariant.GHEC_DR]) {
|
||||||
await withTmpDir(async (tmpDir) => {
|
test(`selects CLI v2.20.1 on ${variant} when feature flags enable v2.20.0 and v2.20.1`, async (t) => {
|
||||||
const features = setUpFeatureFlagTests(tmpDir);
|
await withTmpDir(async (tmpDir) => {
|
||||||
const expectedFeatureEnablement = initializeFeatures(true);
|
const features = setUpFeatureFlagTests(tmpDir);
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
|
const expectedFeatureEnablement = initializeFeatures(true);
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true;
|
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_2_enabled"] = false;
|
expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true;
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_3_enabled"] = false;
|
expectedFeatureEnablement["default_codeql_version_2_20_2_enabled"] =
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_4_enabled"] = false;
|
false;
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_5_enabled"] = false;
|
expectedFeatureEnablement["default_codeql_version_2_20_3_enabled"] =
|
||||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
false;
|
||||||
|
expectedFeatureEnablement["default_codeql_version_2_20_4_enabled"] =
|
||||||
|
false;
|
||||||
|
expectedFeatureEnablement["default_codeql_version_2_20_5_enabled"] =
|
||||||
|
false;
|
||||||
|
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||||
|
|
||||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||||
GitHubVariant.DOTCOM,
|
t.deepEqual(defaultCliVersion, {
|
||||||
);
|
cliVersion: "2.20.1",
|
||||||
t.deepEqual(defaultCliVersion, {
|
tagName: "codeql-bundle-v2.20.1",
|
||||||
cliVersion: "2.20.1",
|
toolsFeatureFlagsValid: true,
|
||||||
tagName: "codeql-bundle-v2.20.1",
|
});
|
||||||
toolsFeatureFlagsValid: true,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test("includes tag name", async (t) => {
|
test(`selects CLI from defaults.json on ${variant} when no default version feature flags are enabled`, async (t) => {
|
||||||
await withTmpDir(async (tmpDir) => {
|
await withTmpDir(async (tmpDir) => {
|
||||||
const features = setUpFeatureFlagTests(tmpDir);
|
const features = setUpFeatureFlagTests(tmpDir);
|
||||||
const expectedFeatureEnablement = initializeFeatures(true);
|
const expectedFeatureEnablement = initializeFeatures(true);
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
|
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
|
||||||
|
|
||||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||||
GitHubVariant.DOTCOM,
|
t.deepEqual(defaultCliVersion, {
|
||||||
);
|
cliVersion: defaults.cliVersion,
|
||||||
t.deepEqual(defaultCliVersion, {
|
tagName: defaults.bundleVersion,
|
||||||
cliVersion: "2.20.0",
|
toolsFeatureFlagsValid: false,
|
||||||
tagName: "codeql-bundle-v2.20.0",
|
});
|
||||||
toolsFeatureFlagsValid: true,
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
test(`selects CLI from defaults.json on Dotcom when no default version feature flags are enabled`, async (t) => {
|
test(`ignores invalid version numbers in default version feature flags on ${variant}`, async (t) => {
|
||||||
await withTmpDir(async (tmpDir) => {
|
await withTmpDir(async (tmpDir) => {
|
||||||
const features = setUpFeatureFlagTests(tmpDir);
|
const loggedMessages = [];
|
||||||
const expectedFeatureEnablement = initializeFeatures(true);
|
const features = setUpFeatureFlagTests(
|
||||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
tmpDir,
|
||||||
|
getRecordingLogger(loggedMessages),
|
||||||
|
);
|
||||||
|
const expectedFeatureEnablement = initializeFeatures(true);
|
||||||
|
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
|
||||||
|
expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true;
|
||||||
|
expectedFeatureEnablement["default_codeql_version_2_20_invalid_enabled"] =
|
||||||
|
true;
|
||||||
|
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
||||||
|
|
||||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
const defaultCliVersion = await features.getDefaultCliVersion(variant);
|
||||||
GitHubVariant.DOTCOM,
|
t.deepEqual(defaultCliVersion, {
|
||||||
);
|
cliVersion: "2.20.1",
|
||||||
t.deepEqual(defaultCliVersion, {
|
tagName: "codeql-bundle-v2.20.1",
|
||||||
cliVersion: defaults.cliVersion,
|
toolsFeatureFlagsValid: true,
|
||||||
tagName: defaults.bundleVersion,
|
});
|
||||||
toolsFeatureFlagsValid: false,
|
|
||||||
|
t.assert(
|
||||||
|
loggedMessages.find(
|
||||||
|
(v: LoggedMessage) =>
|
||||||
|
v.type === "warning" &&
|
||||||
|
v.message ===
|
||||||
|
"Ignoring feature flag default_codeql_version_2_20_invalid_enabled as it does not specify a valid CodeQL version.",
|
||||||
|
) !== undefined,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
}
|
||||||
|
|
||||||
test("ignores invalid version numbers in default version feature flags", async (t) => {
|
|
||||||
await withTmpDir(async (tmpDir) => {
|
|
||||||
const loggedMessages = [];
|
|
||||||
const features = setUpFeatureFlagTests(
|
|
||||||
tmpDir,
|
|
||||||
getRecordingLogger(loggedMessages),
|
|
||||||
);
|
|
||||||
const expectedFeatureEnablement = initializeFeatures(true);
|
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_0_enabled"] = true;
|
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_1_enabled"] = true;
|
|
||||||
expectedFeatureEnablement["default_codeql_version_2_20_invalid_enabled"] =
|
|
||||||
true;
|
|
||||||
mockFeatureFlagApiEndpoint(200, expectedFeatureEnablement);
|
|
||||||
|
|
||||||
const defaultCliVersion = await features.getDefaultCliVersion(
|
|
||||||
GitHubVariant.DOTCOM,
|
|
||||||
);
|
|
||||||
t.deepEqual(defaultCliVersion, {
|
|
||||||
cliVersion: "2.20.1",
|
|
||||||
tagName: "codeql-bundle-v2.20.1",
|
|
||||||
toolsFeatureFlagsValid: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
t.assert(
|
|
||||||
loggedMessages.find(
|
|
||||||
(v: LoggedMessage) =>
|
|
||||||
v.type === "warning" &&
|
|
||||||
v.message ===
|
|
||||||
"Ignoring feature flag default_codeql_version_2_20_invalid_enabled as it does not specify a valid CodeQL version.",
|
|
||||||
) !== undefined,
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
test("legacy feature flags should end with _enabled", async (t) => {
|
test("legacy feature flags should end with _enabled", async (t) => {
|
||||||
for (const [feature, config] of Object.entries(featureConfig)) {
|
for (const [feature, config] of Object.entries(featureConfig)) {
|
||||||
|
|||||||
@@ -44,7 +44,6 @@ export interface FeatureEnablement {
|
|||||||
*/
|
*/
|
||||||
export enum Feature {
|
export enum Feature {
|
||||||
AllowToolcacheInput = "allow_toolcache_input",
|
AllowToolcacheInput = "allow_toolcache_input",
|
||||||
AnalyzeUseNewUpload = "analyze_use_new_upload",
|
|
||||||
CleanupTrapCaches = "cleanup_trap_caches",
|
CleanupTrapCaches = "cleanup_trap_caches",
|
||||||
CppDependencyInstallation = "cpp_dependency_installation_enabled",
|
CppDependencyInstallation = "cpp_dependency_installation_enabled",
|
||||||
CsharpCacheBuildModeNone = "csharp_cache_bmn",
|
CsharpCacheBuildModeNone = "csharp_cache_bmn",
|
||||||
@@ -54,7 +53,6 @@ export enum Feature {
|
|||||||
DisableJavaBuildlessEnabled = "disable_java_buildless_enabled",
|
DisableJavaBuildlessEnabled = "disable_java_buildless_enabled",
|
||||||
DisableKotlinAnalysisEnabled = "disable_kotlin_analysis_enabled",
|
DisableKotlinAnalysisEnabled = "disable_kotlin_analysis_enabled",
|
||||||
ExportDiagnosticsEnabled = "export_diagnostics_enabled",
|
ExportDiagnosticsEnabled = "export_diagnostics_enabled",
|
||||||
JavaMinimizeDependencyJars = "java_minimize_dependency_jars",
|
|
||||||
OverlayAnalysis = "overlay_analysis",
|
OverlayAnalysis = "overlay_analysis",
|
||||||
OverlayAnalysisActions = "overlay_analysis_actions",
|
OverlayAnalysisActions = "overlay_analysis_actions",
|
||||||
OverlayAnalysisCodeScanningActions = "overlay_analysis_code_scanning_actions",
|
OverlayAnalysisCodeScanningActions = "overlay_analysis_code_scanning_actions",
|
||||||
@@ -120,11 +118,6 @@ export const featureConfig: Record<
|
|||||||
envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT",
|
envVar: "CODEQL_ACTION_ALLOW_TOOLCACHE_INPUT",
|
||||||
minimumVersion: undefined,
|
minimumVersion: undefined,
|
||||||
},
|
},
|
||||||
[Feature.AnalyzeUseNewUpload]: {
|
|
||||||
defaultValue: false,
|
|
||||||
envVar: "CODEQL_ACTION_ANALYZE_USE_NEW_UPLOAD",
|
|
||||||
minimumVersion: undefined,
|
|
||||||
},
|
|
||||||
[Feature.CleanupTrapCaches]: {
|
[Feature.CleanupTrapCaches]: {
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
envVar: "CODEQL_ACTION_CLEANUP_TRAP_CACHES",
|
envVar: "CODEQL_ACTION_CLEANUP_TRAP_CACHES",
|
||||||
@@ -174,11 +167,6 @@ export const featureConfig: Record<
|
|||||||
legacyApi: true,
|
legacyApi: true,
|
||||||
minimumVersion: undefined,
|
minimumVersion: undefined,
|
||||||
},
|
},
|
||||||
[Feature.JavaMinimizeDependencyJars]: {
|
|
||||||
defaultValue: false,
|
|
||||||
envVar: "CODEQL_ACTION_JAVA_MINIMIZE_DEPENDENCY_JARS",
|
|
||||||
minimumVersion: "2.23.0",
|
|
||||||
},
|
|
||||||
[Feature.OverlayAnalysis]: {
|
[Feature.OverlayAnalysis]: {
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS",
|
envVar: "CODEQL_ACTION_OVERLAY_ANALYSIS",
|
||||||
@@ -498,8 +486,8 @@ class GitHubFeatureFlags {
|
|||||||
async getDefaultCliVersion(
|
async getDefaultCliVersion(
|
||||||
variant: util.GitHubVariant,
|
variant: util.GitHubVariant,
|
||||||
): Promise<CodeQLDefaultVersionInfo> {
|
): Promise<CodeQLDefaultVersionInfo> {
|
||||||
if (variant === util.GitHubVariant.DOTCOM) {
|
if (supportsFeatureFlags(variant)) {
|
||||||
return await this.getDefaultDotcomCliVersion();
|
return await this.getDefaultCliVersionFromFlags();
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
cliVersion: defaults.cliVersion,
|
cliVersion: defaults.cliVersion,
|
||||||
@@ -507,7 +495,7 @@ class GitHubFeatureFlags {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async getDefaultDotcomCliVersion(): Promise<CodeQLDefaultVersionInfo> {
|
async getDefaultCliVersionFromFlags(): Promise<CodeQLDefaultVersionInfo> {
|
||||||
const response = await this.getAllFeatures();
|
const response = await this.getAllFeatures();
|
||||||
|
|
||||||
const enabledFeatureFlagCliVersions = Object.entries(response)
|
const enabledFeatureFlagCliVersions = Object.entries(response)
|
||||||
@@ -633,10 +621,7 @@ class GitHubFeatureFlags {
|
|||||||
|
|
||||||
private async loadApiResponse(): Promise<GitHubFeatureFlagsApiResponse> {
|
private async loadApiResponse(): Promise<GitHubFeatureFlagsApiResponse> {
|
||||||
// Do nothing when not running against github.com
|
// Do nothing when not running against github.com
|
||||||
if (
|
if (!supportsFeatureFlags(this.gitHubVersion.type)) {
|
||||||
this.gitHubVersion.type !== util.GitHubVariant.DOTCOM &&
|
|
||||||
this.gitHubVersion.type !== util.GitHubVariant.GHE_DOTCOM
|
|
||||||
) {
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
"Not running against github.com. Disabling all toggleable features.",
|
"Not running against github.com. Disabling all toggleable features.",
|
||||||
);
|
);
|
||||||
@@ -702,3 +687,10 @@ class GitHubFeatureFlags {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function supportsFeatureFlags(githubVariant: util.GitHubVariant): boolean {
|
||||||
|
return (
|
||||||
|
githubVariant === util.GitHubVariant.DOTCOM ||
|
||||||
|
githubVariant === util.GitHubVariant.GHEC_DR
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,6 +88,13 @@ import {
|
|||||||
} from "./util";
|
} from "./util";
|
||||||
import { checkWorkflow } from "./workflow";
|
import { checkWorkflow } from "./workflow";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First version of CodeQL where the Java extractor safely supports the option to minimize
|
||||||
|
* dependency jars. Note: some earlier versions of the extractor will respond to the corresponding
|
||||||
|
* option, but may rewrite jars in ways that lead to extraction errors.
|
||||||
|
*/
|
||||||
|
export const CODEQL_VERSION_JAR_MINIMIZATION = "2.23.0";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sends a status report indicating that the `init` Action is starting.
|
* Sends a status report indicating that the `init` Action is starting.
|
||||||
*
|
*
|
||||||
@@ -638,18 +645,20 @@ async function run() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the feature flag to minimize Java dependency jars is enabled, and we are doing a Java
|
// If we are doing a Java `build-mode: none` analysis, then set the environment variable that
|
||||||
// `build-mode: none` analysis (i.e. the flag is relevant), then set the environment variable
|
// enables the option in the Java extractor to minimize dependency jars. We also only do this if
|
||||||
// that enables the corresponding option in the Java extractor. We also only do this if
|
// dependency caching is enabled, since the option is intended to reduce the size of dependency
|
||||||
// dependency caching is enabled, since the option is intended to reduce the size of
|
// caches, but the jar-rewriting does have a performance cost that we'd like to avoid when
|
||||||
// dependency caches, but the jar-rewriting does have a performance cost that we'd like to avoid
|
// caching is not being used.
|
||||||
// when caching is not being used.
|
// TODO: Remove this language-specific mechanism and replace it with a more general one that
|
||||||
|
// tells extractors when dependency caching is enabled, and then the Java extractor can make its
|
||||||
|
// own decision about whether to rewrite jars.
|
||||||
if (process.env[EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS]) {
|
if (process.env[EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS]) {
|
||||||
logger.debug(
|
logger.debug(
|
||||||
`${EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS} is already set to '${process.env[EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS]}', so the Action will not override it.`,
|
`${EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS} is already set to '${process.env[EnvVar.JAVA_EXTRACTOR_MINIMIZE_DEPENDENCY_JARS]}', so the Action will not override it.`,
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
(await features.getValue(Feature.JavaMinimizeDependencyJars, codeql)) &&
|
(await codeQlVersionAtLeast(codeql, CODEQL_VERSION_JAR_MINIMIZATION)) &&
|
||||||
config.dependencyCachingEnabled &&
|
config.dependencyCachingEnabled &&
|
||||||
config.buildMode === BuildMode.None &&
|
config.buildMode === BuildMode.None &&
|
||||||
config.languages.includes(KnownLanguage.java)
|
config.languages.includes(KnownLanguage.java)
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import * as sinon from "sinon";
|
|||||||
|
|
||||||
import * as actionsUtil from "./actions-util";
|
import * as actionsUtil from "./actions-util";
|
||||||
import * as apiClient from "./api-client";
|
import * as apiClient from "./api-client";
|
||||||
|
import { ResolveDatabaseOutput } from "./codeql";
|
||||||
import * as gitUtils from "./git-utils";
|
import * as gitUtils from "./git-utils";
|
||||||
|
import { KnownLanguage } from "./languages";
|
||||||
import { getRunnerLogger } from "./logging";
|
import { getRunnerLogger } from "./logging";
|
||||||
import {
|
import {
|
||||||
downloadOverlayBaseDatabaseFromCache,
|
downloadOverlayBaseDatabaseFromCache,
|
||||||
@@ -95,6 +97,7 @@ interface DownloadOverlayBaseDatabaseTestCase {
|
|||||||
hasBaseDatabaseOidsFile: boolean;
|
hasBaseDatabaseOidsFile: boolean;
|
||||||
tryGetFolderBytesSucceeds: boolean;
|
tryGetFolderBytesSucceeds: boolean;
|
||||||
codeQLVersion: string;
|
codeQLVersion: string;
|
||||||
|
resolveDatabaseOutput: ResolveDatabaseOutput | Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultDownloadTestCase: DownloadOverlayBaseDatabaseTestCase = {
|
const defaultDownloadTestCase: DownloadOverlayBaseDatabaseTestCase = {
|
||||||
@@ -105,6 +108,7 @@ const defaultDownloadTestCase: DownloadOverlayBaseDatabaseTestCase = {
|
|||||||
hasBaseDatabaseOidsFile: true,
|
hasBaseDatabaseOidsFile: true,
|
||||||
tryGetFolderBytesSucceeds: true,
|
tryGetFolderBytesSucceeds: true,
|
||||||
codeQLVersion: "2.20.5",
|
codeQLVersion: "2.20.5",
|
||||||
|
resolveDatabaseOutput: { overlayBaseSpecifier: "20250626:XXX" },
|
||||||
};
|
};
|
||||||
|
|
||||||
const testDownloadOverlayBaseDatabaseFromCache = test.macro({
|
const testDownloadOverlayBaseDatabaseFromCache = test.macro({
|
||||||
@@ -119,9 +123,11 @@ const testDownloadOverlayBaseDatabaseFromCache = test.macro({
|
|||||||
await fs.promises.mkdir(dbLocation, { recursive: true });
|
await fs.promises.mkdir(dbLocation, { recursive: true });
|
||||||
|
|
||||||
const logger = getRunnerLogger(true);
|
const logger = getRunnerLogger(true);
|
||||||
const config = createTestConfig({ dbLocation });
|
|
||||||
|
|
||||||
const testCase = { ...defaultDownloadTestCase, ...partialTestCase };
|
const testCase = { ...defaultDownloadTestCase, ...partialTestCase };
|
||||||
|
const config = createTestConfig({
|
||||||
|
dbLocation,
|
||||||
|
languages: [KnownLanguage.java],
|
||||||
|
});
|
||||||
|
|
||||||
config.overlayDatabaseMode = testCase.overlayDatabaseMode;
|
config.overlayDatabaseMode = testCase.overlayDatabaseMode;
|
||||||
config.useOverlayDatabaseCaching = testCase.useOverlayDatabaseCaching;
|
config.useOverlayDatabaseCaching = testCase.useOverlayDatabaseCaching;
|
||||||
@@ -163,9 +169,23 @@ const testDownloadOverlayBaseDatabaseFromCache = test.macro({
|
|||||||
.resolves(testCase.tryGetFolderBytesSucceeds ? 1024 * 1024 : undefined);
|
.resolves(testCase.tryGetFolderBytesSucceeds ? 1024 * 1024 : undefined);
|
||||||
stubs.push(tryGetFolderBytesStub);
|
stubs.push(tryGetFolderBytesStub);
|
||||||
|
|
||||||
|
const codeql = mockCodeQLVersion(testCase.codeQLVersion);
|
||||||
|
|
||||||
|
if (testCase.resolveDatabaseOutput instanceof Error) {
|
||||||
|
const resolveDatabaseStub = sinon
|
||||||
|
.stub(codeql, "resolveDatabase")
|
||||||
|
.rejects(testCase.resolveDatabaseOutput);
|
||||||
|
stubs.push(resolveDatabaseStub);
|
||||||
|
} else {
|
||||||
|
const resolveDatabaseStub = sinon
|
||||||
|
.stub(codeql, "resolveDatabase")
|
||||||
|
.resolves(testCase.resolveDatabaseOutput);
|
||||||
|
stubs.push(resolveDatabaseStub);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const result = await downloadOverlayBaseDatabaseFromCache(
|
const result = await downloadOverlayBaseDatabaseFromCache(
|
||||||
mockCodeQLVersion(testCase.codeQLVersion),
|
codeql,
|
||||||
config,
|
config,
|
||||||
logger,
|
logger,
|
||||||
);
|
);
|
||||||
@@ -255,6 +275,24 @@ test(
|
|||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
testDownloadOverlayBaseDatabaseFromCache,
|
||||||
|
"returns undefined when downloaded database doesn't have an overlayBaseSpecifier",
|
||||||
|
{
|
||||||
|
resolveDatabaseOutput: {},
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
testDownloadOverlayBaseDatabaseFromCache,
|
||||||
|
"returns undefined when resolving database metadata fails",
|
||||||
|
{
|
||||||
|
resolveDatabaseOutput: new Error("Failed to resolve database metadata"),
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
|
||||||
test(
|
test(
|
||||||
testDownloadOverlayBaseDatabaseFromCache,
|
testDownloadOverlayBaseDatabaseFromCache,
|
||||||
"returns undefined when filesystem error occurs",
|
"returns undefined when filesystem error occurs",
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { getCommitOid, getFileOidsUnderPath } from "./git-utils";
|
|||||||
import { Logger, withGroupAsync } from "./logging";
|
import { Logger, withGroupAsync } from "./logging";
|
||||||
import {
|
import {
|
||||||
CleanupLevel,
|
CleanupLevel,
|
||||||
|
getCodeQLDatabasePath,
|
||||||
getErrorMessage,
|
getErrorMessage,
|
||||||
isInTestMode,
|
isInTestMode,
|
||||||
tryGetFolderBytes,
|
tryGetFolderBytes,
|
||||||
@@ -176,11 +177,12 @@ const MAX_CACHE_OPERATION_MS = 600_000;
|
|||||||
* @param warningPrefix Prefix for the check failure warning message
|
* @param warningPrefix Prefix for the check failure warning message
|
||||||
* @returns True if the verification succeeded, false otherwise
|
* @returns True if the verification succeeded, false otherwise
|
||||||
*/
|
*/
|
||||||
function checkOverlayBaseDatabase(
|
async function checkOverlayBaseDatabase(
|
||||||
|
codeql: CodeQL,
|
||||||
config: Config,
|
config: Config,
|
||||||
logger: Logger,
|
logger: Logger,
|
||||||
warningPrefix: string,
|
warningPrefix: string,
|
||||||
): boolean {
|
): Promise<boolean> {
|
||||||
// An overlay-base database should contain the base database OIDs file.
|
// An overlay-base database should contain the base database OIDs file.
|
||||||
const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config);
|
const baseDatabaseOidsFilePath = getBaseDatabaseOidsFilePath(config);
|
||||||
if (!fs.existsSync(baseDatabaseOidsFilePath)) {
|
if (!fs.existsSync(baseDatabaseOidsFilePath)) {
|
||||||
@@ -189,6 +191,29 @@ function checkOverlayBaseDatabase(
|
|||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const language of config.languages) {
|
||||||
|
const dbPath = getCodeQLDatabasePath(config, language);
|
||||||
|
try {
|
||||||
|
const resolveDatabaseOutput = await codeql.resolveDatabase(dbPath);
|
||||||
|
if (
|
||||||
|
resolveDatabaseOutput === undefined ||
|
||||||
|
!("overlayBaseSpecifier" in resolveDatabaseOutput)
|
||||||
|
) {
|
||||||
|
logger.info(`${warningPrefix}: no overlayBaseSpecifier defined`);
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
logger.debug(
|
||||||
|
`Overlay base specifier for ${language} overlay-base database found: ` +
|
||||||
|
`${resolveDatabaseOutput.overlayBaseSpecifier}`,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
logger.warning(`${warningPrefix}: failed to resolve database: ${e}`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,7 +257,8 @@ export async function cleanupAndUploadOverlayBaseDatabaseToCache(
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const databaseIsValid = checkOverlayBaseDatabase(
|
const databaseIsValid = await checkOverlayBaseDatabase(
|
||||||
|
codeql,
|
||||||
config,
|
config,
|
||||||
logger,
|
logger,
|
||||||
"Abort uploading overlay-base database to cache",
|
"Abort uploading overlay-base database to cache",
|
||||||
@@ -415,7 +441,8 @@ export async function downloadOverlayBaseDatabaseFromCache(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
const databaseIsValid = checkOverlayBaseDatabase(
|
const databaseIsValid = await checkOverlayBaseDatabase(
|
||||||
|
codeql,
|
||||||
config,
|
config,
|
||||||
logger,
|
logger,
|
||||||
"Downloaded overlay-base database is invalid",
|
"Downloaded overlay-base database is invalid",
|
||||||
|
|||||||
@@ -511,7 +511,7 @@ export async function getCodeQLSource(
|
|||||||
// different version to save download time if the version hasn't been
|
// different version to save download time if the version hasn't been
|
||||||
// specified explicitly (in which case we always honor it).
|
// specified explicitly (in which case we always honor it).
|
||||||
if (
|
if (
|
||||||
variant !== util.GitHubVariant.DOTCOM &&
|
variant === util.GitHubVariant.GHES &&
|
||||||
!forceShippedTools &&
|
!forceShippedTools &&
|
||||||
!toolsInput
|
!toolsInput
|
||||||
) {
|
) {
|
||||||
|
|||||||
BIN
src/testdata/debug-artifacts-with-fake-token.zip
vendored
Normal file
BIN
src/testdata/debug-artifacts-with-fake-token.zip
vendored
Normal file
Binary file not shown.
@@ -152,27 +152,38 @@ export interface LoggedMessage {
|
|||||||
message: string | Error;
|
message: string | Error;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getRecordingLogger(messages: LoggedMessage[]): Logger {
|
export function getRecordingLogger(
|
||||||
|
messages: LoggedMessage[],
|
||||||
|
{ logToConsole }: { logToConsole?: boolean } = { logToConsole: true },
|
||||||
|
): Logger {
|
||||||
return {
|
return {
|
||||||
debug: (message: string) => {
|
debug: (message: string) => {
|
||||||
messages.push({ type: "debug", message });
|
messages.push({ type: "debug", message });
|
||||||
// eslint-disable-next-line no-console
|
if (logToConsole) {
|
||||||
console.debug(message);
|
// eslint-disable-next-line no-console
|
||||||
|
console.debug(message);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
info: (message: string) => {
|
info: (message: string) => {
|
||||||
messages.push({ type: "info", message });
|
messages.push({ type: "info", message });
|
||||||
// eslint-disable-next-line no-console
|
if (logToConsole) {
|
||||||
console.info(message);
|
// eslint-disable-next-line no-console
|
||||||
|
console.info(message);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
warning: (message: string | Error) => {
|
warning: (message: string | Error) => {
|
||||||
messages.push({ type: "warning", message });
|
messages.push({ type: "warning", message });
|
||||||
// eslint-disable-next-line no-console
|
if (logToConsole) {
|
||||||
console.warn(message);
|
// eslint-disable-next-line no-console
|
||||||
|
console.warn(message);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
error: (message: string | Error) => {
|
error: (message: string | Error) => {
|
||||||
messages.push({ type: "error", message });
|
messages.push({ type: "error", message });
|
||||||
// eslint-disable-next-line no-console
|
if (logToConsole) {
|
||||||
console.error(message);
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(message);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
isDebug: () => true,
|
isDebug: () => true,
|
||||||
startGroup: () => undefined,
|
startGroup: () => undefined,
|
||||||
|
|||||||
@@ -433,8 +433,8 @@ function formatGitHubVersion(version: util.GitHubVersion): string {
|
|||||||
switch (version.type) {
|
switch (version.type) {
|
||||||
case util.GitHubVariant.DOTCOM:
|
case util.GitHubVariant.DOTCOM:
|
||||||
return "dotcom";
|
return "dotcom";
|
||||||
case util.GitHubVariant.GHE_DOTCOM:
|
case util.GitHubVariant.GHEC_DR:
|
||||||
return "GHE dotcom";
|
return "GHEC-DR";
|
||||||
case util.GitHubVariant.GHES:
|
case util.GitHubVariant.GHES:
|
||||||
return `GHES ${version.version}`;
|
return `GHES ${version.version}`;
|
||||||
default:
|
default:
|
||||||
@@ -445,12 +445,12 @@ function formatGitHubVersion(version: util.GitHubVersion): string {
|
|||||||
const CHECK_ACTION_VERSION_TESTS: Array<[string, util.GitHubVersion, boolean]> =
|
const CHECK_ACTION_VERSION_TESTS: Array<[string, util.GitHubVersion, boolean]> =
|
||||||
[
|
[
|
||||||
["2.2.1", { type: util.GitHubVariant.DOTCOM }, true],
|
["2.2.1", { type: util.GitHubVariant.DOTCOM }, true],
|
||||||
["2.2.1", { type: util.GitHubVariant.GHE_DOTCOM }, true],
|
["2.2.1", { type: util.GitHubVariant.GHEC_DR }, true],
|
||||||
["2.2.1", { type: util.GitHubVariant.GHES, version: "3.10" }, false],
|
["2.2.1", { type: util.GitHubVariant.GHES, version: "3.10" }, false],
|
||||||
["2.2.1", { type: util.GitHubVariant.GHES, version: "3.11" }, false],
|
["2.2.1", { type: util.GitHubVariant.GHES, version: "3.11" }, false],
|
||||||
["2.2.1", { type: util.GitHubVariant.GHES, version: "3.12" }, false],
|
["2.2.1", { type: util.GitHubVariant.GHES, version: "3.12" }, false],
|
||||||
["3.2.1", { type: util.GitHubVariant.DOTCOM }, true],
|
["3.2.1", { type: util.GitHubVariant.DOTCOM }, true],
|
||||||
["3.2.1", { type: util.GitHubVariant.GHE_DOTCOM }, true],
|
["3.2.1", { type: util.GitHubVariant.GHEC_DR }, true],
|
||||||
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.10" }, false],
|
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.10" }, false],
|
||||||
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.11" }, false],
|
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.11" }, false],
|
||||||
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.12" }, false],
|
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.12" }, false],
|
||||||
@@ -458,7 +458,7 @@ const CHECK_ACTION_VERSION_TESTS: Array<[string, util.GitHubVersion, boolean]> =
|
|||||||
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.20" }, true],
|
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.20" }, true],
|
||||||
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.21" }, true],
|
["3.2.1", { type: util.GitHubVariant.GHES, version: "3.21" }, true],
|
||||||
["4.2.1", { type: util.GitHubVariant.DOTCOM }, false],
|
["4.2.1", { type: util.GitHubVariant.DOTCOM }, false],
|
||||||
["4.2.1", { type: util.GitHubVariant.GHE_DOTCOM }, false],
|
["4.2.1", { type: util.GitHubVariant.GHEC_DR }, false],
|
||||||
["4.2.1", { type: util.GitHubVariant.GHES, version: "3.19" }, false],
|
["4.2.1", { type: util.GitHubVariant.GHES, version: "3.19" }, false],
|
||||||
["4.2.1", { type: util.GitHubVariant.GHES, version: "3.20" }, false],
|
["4.2.1", { type: util.GitHubVariant.GHES, version: "3.20" }, false],
|
||||||
["4.2.1", { type: util.GitHubVariant.GHES, version: "3.21" }, false],
|
["4.2.1", { type: util.GitHubVariant.GHES, version: "3.21" }, false],
|
||||||
|
|||||||
14
src/util.ts
14
src/util.ts
@@ -556,13 +556,17 @@ const CODEQL_ACTION_WARNED_ABOUT_VERSION_ENV_VAR =
|
|||||||
let hasBeenWarnedAboutVersion = false;
|
let hasBeenWarnedAboutVersion = false;
|
||||||
|
|
||||||
export enum GitHubVariant {
|
export enum GitHubVariant {
|
||||||
DOTCOM,
|
/** [GitHub.com](https://github.com) */
|
||||||
GHES,
|
DOTCOM = "GitHub.com",
|
||||||
GHE_DOTCOM,
|
/** [GitHub Enterprise Server](https://docs.github.com/en/enterprise-server@latest/admin/overview/about-github-enterprise-server) */
|
||||||
|
GHES = "GitHub Enterprise Server",
|
||||||
|
/** [GitHub Enterprise Cloud with data residency](https://docs.github.com/en/enterprise-cloud@latest/admin/data-residency/about-github-enterprise-cloud-with-data-residency) */
|
||||||
|
GHEC_DR = "GitHub Enterprise Cloud with data residency",
|
||||||
}
|
}
|
||||||
|
|
||||||
export type GitHubVersion =
|
export type GitHubVersion =
|
||||||
| { type: GitHubVariant.DOTCOM }
|
| { type: GitHubVariant.DOTCOM }
|
||||||
| { type: GitHubVariant.GHE_DOTCOM }
|
| { type: GitHubVariant.GHEC_DR }
|
||||||
| { type: GitHubVariant.GHES; version: string };
|
| { type: GitHubVariant.GHES; version: string };
|
||||||
|
|
||||||
export function checkGitHubVersionInRange(
|
export function checkGitHubVersionInRange(
|
||||||
@@ -1105,7 +1109,7 @@ export function checkActionVersion(
|
|||||||
// and should update to CodeQL Action v4.
|
// and should update to CodeQL Action v4.
|
||||||
if (
|
if (
|
||||||
githubVersion.type === GitHubVariant.DOTCOM ||
|
githubVersion.type === GitHubVariant.DOTCOM ||
|
||||||
githubVersion.type === GitHubVariant.GHE_DOTCOM ||
|
githubVersion.type === GitHubVariant.GHEC_DR ||
|
||||||
(githubVersion.type === GitHubVariant.GHES &&
|
(githubVersion.type === GitHubVariant.GHES &&
|
||||||
semver.satisfies(
|
semver.satisfies(
|
||||||
semver.coerce(githubVersion.version) ?? "0.0.0",
|
semver.coerce(githubVersion.version) ?? "0.0.0",
|
||||||
|
|||||||
Reference in New Issue
Block a user