Compare commits

..

1 Commits

Author SHA1 Message Date
Óscar San José 652e91defb Add repo property to override codeql-cli version 2026-04-16 17:09:34 +02:00
42 changed files with 12295 additions and 14857 deletions
+1 -1
View File
@@ -59,7 +59,7 @@ jobs:
use-all-platform-bundle: 'false'
setup-kotlin: 'true'
- name: Set up Ruby
uses: ruby/setup-ruby@0cb964fd540e0a24c900370abf38a33466142735 # v1.305.0
uses: ruby/setup-ruby@4c56a21280b36d862b5fc31348f463d60bdc55d5 # v1.301.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration
-106
View File
@@ -1,106 +0,0 @@
# Workflow runs on main, on a release branch, and that were triggered as part of a merge group have
# already passed CI before being merged. Therefore if they fail, we should make sure that there
# wasn't a transient failure by rerunning the failed jobs once before investigating further.
name: Deflake
on:
workflow_run:
types: [completed]
# Exclude workflows that have significant side effects, like publishing releases. It's OK to
# retry CodeQL analysis.
workflows:
- Check Expected Release Files
- Code-Scanning config CLI tests
- CodeQL action
- Manual Check - go
- "PR Check - All-platform bundle"
- "PR Check - Analysis kinds"
- "PR Check - Analyze: 'ref' and 'sha' from inputs"
- "PR Check - autobuild-action"
- "PR Check - Autobuild direct tracing (custom working directory)"
- "PR Check - Autobuild working directory"
- "PR Check - Build mode autobuild"
- "PR Check - Build mode manual"
- "PR Check - Build mode none"
- "PR Check - Build mode rollback"
- "PR Check - Bundle: Caching checks"
- "PR Check - Bundle: From nightly"
- "PR Check - Bundle: From toolcache"
- "PR Check - Bundle: Zstandard checks"
- "PR Check - C/C\\+\\+: autoinstalling dependencies (Linux)"
- "PR Check - C/C\\+\\+: autoinstalling dependencies is skipped (macOS)"
- "PR Check - C/C\\+\\+: disabling autoinstalling dependencies (Linux)"
- "PR Check - Clean up database cluster directory"
- "PR Check - CodeQL Bundle All"
- "PR Check - Config export"
- "PR Check - Config input"
- "PR Check - Custom source root"
- "PR Check - Debug artifact upload"
- "PR Check - Debug artifacts after failure"
- "PR Check - Diagnostic export"
- "PR Check - Export file baseline information"
- "PR Check - Extractor ram and threads options test"
- "PR Check - Go: Custom queries"
- "PR Check - Go: diagnostic when Go is changed after init step"
- "PR Check - Go: diagnostic when `file` is not installed"
- "PR Check - Go: tracing with autobuilder step"
- "PR Check - Go: tracing with custom build steps"
- "PR Check - Go: tracing with legacy workflow"
- "PR Check - Go: workaround for indirect tracing"
- "PR Check - Job run UUID added to SARIF"
- "PR Check - Language aliases"
- "PR Check - Local CodeQL bundle"
- "PR Check - Multi-language repository"
- "PR Check - Overlay database init fallback"
- "PR Check - Packaging: Action input"
- "PR Check - Packaging: Config and input"
- "PR Check - Packaging: Config and input passed to the CLI"
- "PR Check - Packaging: Config file"
- "PR Check - Packaging: Download using registries"
- "PR Check - Proxy test"
- "PR Check - Remote config file"
- "PR Check - Resolve environment"
- "PR Check - RuboCop multi-language"
- "PR Check - Ruby analysis"
- "PR Check - Rust analysis"
- "PR Check - Split workflow"
- "PR Check - Start proxy"
- "PR Check - Submit SARIF after failure"
- "PR Check - Swift analysis using a custom build command"
- "PR Check - Swift analysis using autobuild"
- "PR Check - Test different uses of `upload-sarif`"
- "PR Check - Test unsetting environment variables"
- "PR Check - Upload-sarif: ref and sha from inputs"
- "PR Check - Use a custom `checkout_path`"
- PR Checks
- Query filters tests
- Test that the workaround for python 3.12 on windows works
jobs:
rerun-on-failure:
name: Rerun failed jobs
if: >-
github.event.workflow_run.conclusion == 'failure' &&
github.event.workflow_run.run_attempt == 1 &&
(
github.event.workflow_run.head_branch == 'main' ||
startsWith(github.event.workflow_run.head_branch, 'releases/') ||
github.event.workflow_run.event == 'merge_group'
)
runs-on: ubuntu-slim
permissions:
actions: write
steps:
- name: Rerun failed jobs in ${{ github.event.workflow_run.name }}
env:
GH_TOKEN: ${{ github.token }}
GH_REPO: ${{ github.repository }}
RUN_ID: ${{ github.event.workflow_run.id }}
RUN_NAME: ${{ github.event.workflow_run.name }}
RUN_URL: ${{ github.event.workflow_run.html_url }}
run: |
echo "Rerunning failed jobs for workflow run ${RUN_ID}"
gh run rerun "${RUN_ID}" --failed
echo "### Reran failed jobs :recycle:" >> "$GITHUB_STEP_SUMMARY"
echo "" >> "$GITHUB_STEP_SUMMARY"
echo "Workflow: [${RUN_NAME}](${RUN_URL})" >> "$GITHUB_STEP_SUMMARY"
-8
View File
@@ -52,14 +52,6 @@ jobs:
- name: Verify compiled JS up to date
run: .github/workflows/script/check-js.sh
- name: Upload esbuild metadata
uses: actions/upload-artifact@v7
with:
name: bundle-metadata-${{ matrix.os }}-${{ matrix.node-version }}
path: build-metadata.json
retention-days: ${{ (github.ref_name == github.event.repository.default_branch && 90) || 7 }}
if-no-files-found: error
- name: Run unit tests
if: always()
run: npm test
+1 -1
View File
@@ -12,4 +12,4 @@ eslint.sarif
# for local incremental compilation
tsconfig.tsbuildinfo
# esbuild metadata file
build-metadata.json
meta.json
+1 -2
View File
@@ -4,8 +4,7 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
## [UNRELEASED]
- Fixed a bug where two diagnostics produced within the same millisecond could overwrite each other on disk, causing one of them to be lost. [#3852](https://github.com/github/codeql-action/pull/3852)
- _Upcoming breaking change_: Add a deprecation warning for customers using CodeQL version 2.19.3 and earlier. These versions of CodeQL were discontinued on 9 April 2026 alongside GitHub Enterprise Server 3.15, and will be unsupported by the next minor release of the CodeQL Action. [#3837](https://github.com/github/codeql-action/pull/3837)
- Organizations can now create a custom repository property with the name `github-codeql-tools` to control the CodeQL CLI tools input at the repository level. When this property is set to a valid tools input value (such as `"toolcache"`, `"latest"`, or a specific version), it will override the default tools configuration for that repository. This allows organization administrators to standardize CodeQL CLI versions across repositories or enable toolcache usage on repositories where it would otherwise be restricted. For more information on creating custom repository properties, see [Managing custom properties for repositories in your organization](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization).
## 4.35.2 - 15 Apr 2026
-1
View File
@@ -72,7 +72,6 @@ We typically release new minor versions of the CodeQL Action and Bundle when a n
| Minimum CodeQL Action | Minimum CodeQL Bundle Version | GitHub Environment | Notes |
|-----------------------|-------------------------------|--------------------|-------|
| `v4.33.0` | `2.24.3` | Enterprise Server 3.21 | |
| `v4.31.10` | `2.23.9` | Enterprise Server 3.20 | |
| `v3.29.11` | `2.22.4` | Enterprise Server 3.19 | |
| `v3.28.21` | `2.21.3` | Enterprise Server 3.18 | |
+1 -1
View File
@@ -82,6 +82,6 @@ const context = await esbuild.context({
});
const result = await context.rebuild();
await writeFile(join(__dirname, "build-metadata.json"), JSON.stringify(result.metafile));
await writeFile(join(__dirname, "meta.json"), JSON.stringify(result.metafile));
await context.dispose();
+808 -1045
View File
File diff suppressed because it is too large Load Diff
+797 -1020
View File
File diff suppressed because it is too large Load Diff
+759 -996
View File
File diff suppressed because it is too large Load Diff
+837 -1069
View File
File diff suppressed because it is too large Load Diff
+2737 -2933
View File
File diff suppressed because it is too large Load Diff
+759 -996
View File
File diff suppressed because it is too large Load Diff
+984 -1026
View File
File diff suppressed because it is too large Load Diff
+805 -1042
View File
File diff suppressed because it is too large Load Diff
+757 -1013
View File
File diff suppressed because it is too large Load Diff
+785 -1017
View File
File diff suppressed because it is too large Load Diff
+805 -1042
View File
File diff suppressed because it is too large Load Diff
+785 -1017
View File
File diff suppressed because it is too large Load Diff
+170 -158
View File
@@ -33,10 +33,10 @@
"long": "^5.3.2",
"node-forge": "^1.4.0",
"semver": "^7.7.4",
"uuid": "^14.0.0"
"uuid": "^13.0.0"
},
"devDependencies": {
"@ava/typescript": "7.0.0",
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.5",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"@octokit/types": "^16.0.0",
@@ -51,17 +51,17 @@
"ava": "^7.0.0",
"esbuild": "^0.28.0",
"eslint": "^9.39.2",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-import-resolver-typescript": "^3.8.7",
"eslint-plugin-github": "^6.0.0",
"eslint-plugin-import-x": "^4.16.2",
"eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^11.1.0",
"globals": "^17.5.0",
"globals": "^17.4.0",
"nock": "^14.0.12",
"sinon": "^21.1.2",
"sinon": "^21.0.3",
"typescript": "^6.0.2",
"typescript-eslint": "^8.58.2"
"typescript-eslint": "^8.58.1"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -468,17 +468,16 @@
}
},
"node_modules/@ava/typescript": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@ava/typescript/-/typescript-7.0.0.tgz",
"integrity": "sha512-0ktzq4/9ya2QoAuVWzl3McpLV9W//Tj+oMonQ4ucgm5l6tQ46aaju/rJL9kzeY5MkG6wzXvFt/MmaLqf9uNC9w==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@ava/typescript/-/typescript-6.0.0.tgz",
"integrity": "sha512-+8oDYc4J5cCaWZh1VUbyc+cegGplJO9FqHpqR4LVAVx8fRLVRaYlC4yyA6cqHJ1vWP23Ff/ECS5U68Zz6OLZlg==",
"dev": true,
"license": "MIT",
"dependencies": {
"escape-string-regexp": "^5.0.0",
"execa": "^9.6.1"
"execa": "^9.6.0"
},
"engines": {
"node": "^22.20 || ^24.12 || >=25"
"node": "^20.8 || ^22 || >=24"
}
},
"node_modules/@ava/typescript/node_modules/escape-string-regexp": {
@@ -1989,18 +1988,6 @@
"@tybys/wasm-util": "^0.10.0"
}
},
"node_modules/@nodable/entities": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@nodable/entities/-/entities-2.1.0.tgz",
"integrity": "sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/nodable"
}
],
"license": "MIT"
},
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"dev": true,
@@ -2033,6 +2020,15 @@
"node": ">= 8"
}
},
"node_modules/@nolyfill/is-core-module": {
"version": "1.0.39",
"resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
"integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
"dev": true,
"engines": {
"node": ">=12.4.0"
}
},
"node_modules/@octokit/auth-token": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz",
@@ -2366,8 +2362,7 @@
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
"integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
"dev": true,
"license": "MIT"
"dev": true
},
"node_modules/@sindresorhus/base62": {
"version": "1.0.0",
@@ -2405,9 +2400,9 @@
}
},
"node_modules/@sinonjs/fake-timers": {
"version": "15.3.2",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.3.2.tgz",
"integrity": "sha512-mrn35Jl2pCpns+mE3HaZa1yPN5EYCRgiMI+135COjr2hr8Cls9DXqIZ57vZe2cz7y2XVSq92tcs6kGQcT1J8Rw==",
"version": "15.1.1",
"resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-15.1.1.tgz",
"integrity": "sha512-cO5W33JgAPbOh07tvZjUOJ7oWhtaqGHiZw+11DPbyqh2kHTBc3eF/CjJDeQ4205RLQsX6rxCuYOroFQwl7JDRw==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -2415,9 +2410,9 @@
}
},
"node_modules/@sinonjs/samsam": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-10.0.2.tgz",
"integrity": "sha512-8lVwD1Df1BmzoaOLhMcGGcz/Jyr5QY2KSB75/YK1QgKzoabTeLdIVyhXNZK9ojfSKSdirbXqdbsXXqP9/Ve8+A==",
"version": "9.0.3",
"resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-9.0.3.tgz",
"integrity": "sha512-ZgYY7Dc2RW+OUdnZ1DEHg00lhRt+9BjymPKHog4PRFzr1U3MbK57+djmscWyKxzO1qfunHqs4N45WWyKIFKpiQ==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
@@ -2554,17 +2549,17 @@
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.2.tgz",
"integrity": "sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.58.1.tgz",
"integrity": "sha512-eSkwoemjo76bdXl2MYqtxg51HNwUSkWfODUOQ3PaTLZGh9uIWWFZIjyjaJnex7wXDu+TRx+ATsnSxdN9YWfRTQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.58.2",
"@typescript-eslint/type-utils": "8.58.2",
"@typescript-eslint/utils": "8.58.2",
"@typescript-eslint/visitor-keys": "8.58.2",
"@typescript-eslint/scope-manager": "8.58.1",
"@typescript-eslint/type-utils": "8.58.1",
"@typescript-eslint/utils": "8.58.1",
"@typescript-eslint/visitor-keys": "8.58.1",
"ignore": "^7.0.5",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0"
@@ -2577,7 +2572,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.58.2",
"@typescript-eslint/parser": "^8.58.1",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
@@ -2593,16 +2588,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.2.tgz",
"integrity": "sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.58.1.tgz",
"integrity": "sha512-gGkiNMPqerb2cJSVcruigx9eHBlLG14fSdPdqMoOcBfh+vvn4iCq2C8MzUB89PrxOXk0y3GZ1yIWb9aOzL93bw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.58.2",
"@typescript-eslint/types": "8.58.2",
"@typescript-eslint/typescript-estree": "8.58.2",
"@typescript-eslint/visitor-keys": "8.58.2",
"@typescript-eslint/scope-manager": "8.58.1",
"@typescript-eslint/types": "8.58.1",
"@typescript-eslint/typescript-estree": "8.58.1",
"@typescript-eslint/visitor-keys": "8.58.1",
"debug": "^4.4.3"
},
"engines": {
@@ -2636,14 +2631,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.2.tgz",
"integrity": "sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.58.1.tgz",
"integrity": "sha512-gfQ8fk6cxhtptek+/8ZIqw8YrRW5048Gug8Ts5IYcMLCw18iUgrZAEY/D7s4hkI0FxEfGakKuPK/XUMPzPxi5g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.58.2",
"@typescript-eslint/types": "^8.58.2",
"@typescript-eslint/tsconfig-utils": "^8.58.1",
"@typescript-eslint/types": "^8.58.1",
"debug": "^4.4.3"
},
"engines": {
@@ -2676,14 +2671,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.2.tgz",
"integrity": "sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.58.1.tgz",
"integrity": "sha512-TPYUEqJK6avLcEjumWsIuTpuYODTTDAtoMdt8ZZa93uWMTX13Nb8L5leSje1NluammvU+oI3QRr5lLXPgihX3w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.58.2",
"@typescript-eslint/visitor-keys": "8.58.2"
"@typescript-eslint/types": "8.58.1",
"@typescript-eslint/visitor-keys": "8.58.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2694,9 +2689,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.2.tgz",
"integrity": "sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.58.1.tgz",
"integrity": "sha512-JAr2hOIct2Q+qk3G+8YFfqkqi7sC86uNryT+2i5HzMa2MPjw4qNFvtjnw1IiA1rP7QhNKVe21mSSLaSjwA1Olw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2711,15 +2706,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.2.tgz",
"integrity": "sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.58.1.tgz",
"integrity": "sha512-HUFxvTJVroT+0rXVJC7eD5zol6ID+Sn5npVPWoFuHGg9Ncq5Q4EYstqR+UOqaNRFXi5TYkpXXkLhoCHe3G0+7w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.58.2",
"@typescript-eslint/typescript-estree": "8.58.2",
"@typescript-eslint/utils": "8.58.2",
"@typescript-eslint/types": "8.58.1",
"@typescript-eslint/typescript-estree": "8.58.1",
"@typescript-eslint/utils": "8.58.1",
"debug": "^4.4.3",
"ts-api-utils": "^2.5.0"
},
@@ -2754,9 +2749,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.2.tgz",
"integrity": "sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.58.1.tgz",
"integrity": "sha512-io/dV5Aw5ezwzfPBBWLoT+5QfVtP8O7q4Kftjn5azJ88bYyp/ZMCsyW1lpKK46EXJcaYMZ1JtYj+s/7TdzmQMw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2768,16 +2763,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.2.tgz",
"integrity": "sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.58.1.tgz",
"integrity": "sha512-w4w7WR7GHOjqqPnvAYbazq+Y5oS68b9CzasGtnd6jIeOIeKUzYzupGTB2T4LTPSv4d+WPeccbxuneTFHYgAAWg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.58.2",
"@typescript-eslint/tsconfig-utils": "8.58.2",
"@typescript-eslint/types": "8.58.2",
"@typescript-eslint/visitor-keys": "8.58.2",
"@typescript-eslint/project-service": "8.58.1",
"@typescript-eslint/tsconfig-utils": "8.58.1",
"@typescript-eslint/types": "8.58.1",
"@typescript-eslint/visitor-keys": "8.58.1",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
@@ -2853,16 +2848,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.2.tgz",
"integrity": "sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.58.1.tgz",
"integrity": "sha512-Ln8R0tmWC7pTtLOzgJzYTXSCjJ9rDNHAqTaVONF4FEi2qwce8mD9iSOxOpLFFvWp/wBFlew0mjM1L1ihYWfBdQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.58.2",
"@typescript-eslint/types": "8.58.2",
"@typescript-eslint/typescript-estree": "8.58.2"
"@typescript-eslint/scope-manager": "8.58.1",
"@typescript-eslint/types": "8.58.1",
"@typescript-eslint/typescript-estree": "8.58.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2877,13 +2872,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.2.tgz",
"integrity": "sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.58.1.tgz",
"integrity": "sha512-y+vH7QE8ycjoa0bWciFg7OpFcipUuem1ujhrdLtq1gByKwfbC7bPeKsiny9e0urg93DqwGcHey+bGRKCnF1nZQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.58.2",
"@typescript-eslint/types": "8.58.1",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
@@ -4482,9 +4477,9 @@
}
},
"node_modules/diff": {
"version": "8.0.4",
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
"integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
"version": "8.0.3",
"resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz",
"integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
@@ -4545,6 +4540,19 @@
"version": "8.0.0",
"license": "MIT"
},
"node_modules/enhanced-resolve": {
"version": "5.17.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz",
"integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==",
"dev": true,
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
},
"engines": {
"node": ">=10.13.0"
}
},
"node_modules/es-abstract": {
"version": "1.24.1",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.1.tgz",
@@ -4865,25 +4873,24 @@
}
},
"node_modules/eslint-import-resolver-typescript": {
"version": "4.4.4",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-4.4.4.tgz",
"integrity": "sha512-1iM2zeBvrYmUNTj2vSC/90JTHDth+dfOfiNKkxApWRsTJYNrc8rOdxxIf5vazX+BiAXTeOT0UvWpGI/7qIWQOw==",
"version": "3.8.7",
"resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.8.7.tgz",
"integrity": "sha512-U7k84gOzrfl09c33qrIbD3TkWTWu3nt3dK5sDajHSekfoLlYGusIwSdPlPzVeA6TFpi0Wpj+ZdBD8hX4hxPoww==",
"dev": true,
"license": "ISC",
"dependencies": {
"debug": "^4.4.1",
"eslint-import-context": "^0.1.8",
"get-tsconfig": "^4.10.1",
"is-bun-module": "^2.0.0",
"stable-hash-x": "^0.2.0",
"tinyglobby": "^0.2.14",
"unrs-resolver": "^1.7.11"
"@nolyfill/is-core-module": "1.0.39",
"debug": "^4.3.7",
"enhanced-resolve": "^5.15.0",
"get-tsconfig": "^4.10.0",
"is-bun-module": "^1.0.2",
"stable-hash": "^0.0.4",
"tinyglobby": "^0.2.12"
},
"engines": {
"node": "^16.17.0 || >=18.6.0"
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
"url": "https://opencollective.com/eslint-import-resolver-typescript"
"url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts"
},
"peerDependencies": {
"eslint": "*",
@@ -5609,11 +5616,10 @@
}
},
"node_modules/execa": {
"version": "9.6.1",
"resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz",
"integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==",
"version": "9.6.0",
"resolved": "https://registry.npmjs.org/execa/-/execa-9.6.0.tgz",
"integrity": "sha512-jpWzZ1ZhwUmeWRhS7Qv3mhpOhLfwI+uAX4e5fOcXqwMR7EcJ0pj2kV1CVzHVMX/LphnKWD3LObjZCoJ71lKpHw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sindresorhus/merge-streams": "^4.0.0",
"cross-spawn": "^7.0.6",
@@ -5694,9 +5700,9 @@
"license": "MIT"
},
"node_modules/fast-xml-builder": {
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.5.tgz",
"integrity": "sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==",
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/fast-xml-builder/-/fast-xml-builder-1.1.4.tgz",
"integrity": "sha512-f2jhpN4Eccy0/Uz9csxh3Nu6q4ErKxf0XIsasomfOihuSUa3/xw6w8dnOtCDgEItQFJG8KyXPzQXzcODDrrbOg==",
"funding": [
{
"type": "github",
@@ -5709,9 +5715,9 @@
}
},
"node_modules/fast-xml-parser": {
"version": "5.7.1",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.7.1.tgz",
"integrity": "sha512-8Cc3f8GUGUULg34pBch/KGyPLglS+OFs05deyOlY7fL2MTagYPKrVQNmR1fLF/yJ9PH5ZSTd3YDF6pnmeZU+zA==",
"version": "5.5.7",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-5.5.7.tgz",
"integrity": "sha512-LteOsISQ2GEiDHZch6L9hB0+MLoYVLToR7xotrzU0opCICBkxOPgHAy1HxAvtxfJNXDJpgAsQN30mkrfpO2Prg==",
"funding": [
{
"type": "github",
@@ -5720,10 +5726,9 @@
],
"license": "MIT",
"dependencies": {
"@nodable/entities": "^2.1.0",
"fast-xml-builder": "^1.1.5",
"path-expression-matcher": "^1.5.0",
"strnum": "^2.2.3"
"fast-xml-builder": "^1.1.4",
"path-expression-matcher": "^1.1.3",
"strnum": "^2.2.0"
},
"bin": {
"fxparser": "src/cli/cli.js"
@@ -6028,7 +6033,6 @@
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
"integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@sec-ant/readable-stream": "^0.4.1",
"is-stream": "^4.0.1"
@@ -6144,9 +6148,9 @@
}
},
"node_modules/globals": {
"version": "17.5.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.5.0.tgz",
"integrity": "sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==",
"version": "17.4.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.4.0.tgz",
"integrity": "sha512-hjrNztw/VajQwOLsMNT1cbJiH2muO3OROCHnbehc8eY5JyD2gqz4AcMHPqgaOR59DjgUjYAYLeH699g/eWi2jw==",
"dev": true,
"license": "MIT",
"engines": {
@@ -6389,7 +6393,6 @@
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz",
"integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==",
"dev": true,
"license": "Apache-2.0",
"engines": {
"node": ">=18.18.0"
}
@@ -6578,13 +6581,12 @@
}
},
"node_modules/is-bun-module": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
"integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-1.1.0.tgz",
"integrity": "sha512-4mTAVPlrXpaN3jtF0lsnPCMGnq4+qZjVIKq0HCpfcqf8OC1SM5oATCIAPM5V5FN05qp2NNnFndphmdZS9CV3hA==",
"dev": true,
"license": "MIT",
"dependencies": {
"semver": "^7.7.1"
"semver": "^7.6.3"
}
},
"node_modules/is-callable": {
@@ -6787,7 +6789,6 @@
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
"integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
@@ -6862,7 +6863,6 @@
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
"integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
@@ -7571,7 +7571,6 @@
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz",
"integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==",
"dev": true,
"license": "MIT",
"dependencies": {
"path-key": "^4.0.0",
"unicorn-magic": "^0.3.0"
@@ -7588,7 +7587,6 @@
"resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz",
"integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=12"
},
@@ -7862,9 +7860,9 @@
}
},
"node_modules/path-expression-matcher": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.5.0.tgz",
"integrity": "sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==",
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/path-expression-matcher/-/path-expression-matcher-1.1.3.tgz",
"integrity": "sha512-qdVgY8KXmVdJZRSS1JdEPOKPdTiEK/pi0RkcT2sw1RhXxohdujUlJFPuS1TSkevZ9vzd3ZlL7ULl1MHGTApKzQ==",
"funding": [
{
"type": "github",
@@ -8534,16 +8532,17 @@
}
},
"node_modules/sinon": {
"version": "21.1.2",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-21.1.2.tgz",
"integrity": "sha512-FS6mN+/bx7e2ajpXkEmOcWB6xBzWiuNoAQT18/+a20SS4U7FSYl8Ms7N6VTUxN/1JAjkx7aXp+THMC8xdpp0gA==",
"version": "21.0.3",
"resolved": "https://registry.npmjs.org/sinon/-/sinon-21.0.3.tgz",
"integrity": "sha512-0x8TQFr8EjADhSME01u1ZK31yv2+bd6Z5NrBCHVM+n4qL1wFqbxftmeyi3bwlr49FbbzRfrqSFOpyHCOh/YmYA==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@sinonjs/commons": "^3.0.1",
"@sinonjs/fake-timers": "^15.3.2",
"@sinonjs/samsam": "^10.0.2",
"diff": "^8.0.4"
"@sinonjs/fake-timers": "^15.1.1",
"@sinonjs/samsam": "^9.0.3",
"diff": "^8.0.3",
"supports-color": "^7.2.0"
},
"funding": {
"type": "opencollective",
@@ -8627,6 +8626,13 @@
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"dev": true
},
"node_modules/stable-hash": {
"version": "0.0.4",
"resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.4.tgz",
"integrity": "sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g==",
"dev": true,
"license": "MIT"
},
"node_modules/stable-hash-x": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz",
@@ -8838,7 +8844,6 @@
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz",
"integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
@@ -8858,9 +8863,9 @@
}
},
"node_modules/strnum": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.3.tgz",
"integrity": "sha512-oKx6RUCuHfT3oyVjtnrmn19H1SiCqgJSg+54XqURKp5aCMbrXrhLjRN9TjuwMjiYstZ0MzDrHqkGZ5dFTKd+zg==",
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/strnum/-/strnum-2.2.1.tgz",
"integrity": "sha512-BwRvNd5/QoAtyW1na1y1LsJGQNvRlkde6Q/ipqqEaivoMdV+B1OMOTVdwR+N/cwVUcIt9PYyHmV8HyexCZSupg==",
"funding": [
{
"type": "github",
@@ -8983,6 +8988,15 @@
"url": "https://opencollective.com/unts"
}
},
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
"integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
"dev": true,
"engines": {
"node": ">=6"
}
},
"node_modules/tar": {
"version": "7.5.11",
"resolved": "https://registry.npmjs.org/tar/-/tar-7.5.11.tgz",
@@ -9811,16 +9825,16 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.58.2",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.2.tgz",
"integrity": "sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==",
"version": "8.58.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.58.1.tgz",
"integrity": "sha512-gf6/oHChByg9HJvhMO1iBexJh12AqqTfnuxscMDOVqfJW3htsdRJI/GfPpHTTcyeB8cSTUY2JcZmVgoyPqcrDg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.58.2",
"@typescript-eslint/parser": "8.58.2",
"@typescript-eslint/typescript-estree": "8.58.2",
"@typescript-eslint/utils": "8.58.2"
"@typescript-eslint/eslint-plugin": "8.58.1",
"@typescript-eslint/parser": "8.58.1",
"@typescript-eslint/typescript-estree": "8.58.1",
"@typescript-eslint/utils": "8.58.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -9876,7 +9890,6 @@
"resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz",
"integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
@@ -9986,9 +9999,9 @@
"license": "MIT"
},
"node_modules/uuid": {
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz",
"integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==",
"version": "13.0.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-13.0.0.tgz",
"integrity": "sha512-XQegIaBTVUjSHliKqcnFqYypAd4S+WCYt5NIeRs6w/UAry7z8Y9j5ZwRRL4kzq9U3sD6v+85er9FvkEaBpji2w==",
"funding": [
"https://github.com/sponsors/broofa",
"https://github.com/sponsors/ctavan"
@@ -10380,11 +10393,10 @@
}
},
"node_modules/yoctocolors": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.2.tgz",
"integrity": "sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==",
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.1.1.tgz",
"integrity": "sha512-GQHQqAopRhwU8Kt1DDM8NjibDXHC8eoh1erhGAJPEyveY9qqVeXvVikNKrDz69sHowPMorbPUrH/mx8c50eiBQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=18"
},
+7 -7
View File
@@ -5,7 +5,7 @@
"description": "CodeQL action",
"scripts": {
"_build_comment": "echo 'Run the full build so we typecheck the project and can reuse the transpiled files in npm test'",
"build": "./scripts/check-node-modules.sh && npm run transpile && node build.mjs",
"build": "./scripts/check-node-modules.sh && npm run transpile && node build.mjs && npx tsx ./pr-checks/bundle-metadata.ts",
"lint": "eslint --report-unused-disable-directives --max-warnings=0 .",
"lint-ci": "SARIF_ESLINT_IGNORE_SUPPRESSED=true eslint --report-unused-disable-directives --max-warnings=0 . --format @microsoft/eslint-formatter-sarif --output-file=eslint.sarif",
"lint-fix": "eslint --report-unused-disable-directives --max-warnings=0 . --fix",
@@ -40,10 +40,10 @@
"long": "^5.3.2",
"node-forge": "^1.4.0",
"semver": "^7.7.4",
"uuid": "^14.0.0"
"uuid": "^13.0.0"
},
"devDependencies": {
"@ava/typescript": "7.0.0",
"@ava/typescript": "6.0.0",
"@eslint/compat": "^2.0.5",
"@microsoft/eslint-formatter-sarif": "^3.1.0",
"@octokit/types": "^16.0.0",
@@ -58,17 +58,17 @@
"ava": "^7.0.0",
"esbuild": "^0.28.0",
"eslint": "^9.39.2",
"eslint-import-resolver-typescript": "^4.4.4",
"eslint-import-resolver-typescript": "^3.8.7",
"eslint-plugin-github": "^6.0.0",
"eslint-plugin-import-x": "^4.16.2",
"eslint-plugin-jsdoc": "^62.9.0",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^11.1.0",
"globals": "^17.5.0",
"globals": "^17.4.0",
"nock": "^14.0.12",
"sinon": "^21.1.2",
"sinon": "^21.0.3",
"typescript": "^6.0.2",
"typescript-eslint": "^8.58.2"
"typescript-eslint": "^8.58.1"
},
"overrides": {
"@actions/tool-cache": {
-21
View File
@@ -1,16 +1,8 @@
import { ParseArgsConfig } from "node:util";
import * as githubUtils from "@actions/github/lib/utils";
import { type Octokit } from "@octokit/core";
import { type PaginateInterface } from "@octokit/plugin-paginate-rest";
import { type Api } from "@octokit/plugin-rest-endpoint-methods";
/** Identifies the CodeQL Action repository. */
export const CODEQL_ACTION_REPO = {
owner: "github",
repo: "codeql-action",
};
/** The type of the Octokit client. */
export type ApiClient = Octokit & Api & { paginate: PaginateInterface };
@@ -19,16 +11,3 @@ export function getApiClient(token: string): ApiClient {
const opts = githubUtils.getOctokitOptions(token);
return new githubUtils.GitHub(opts);
}
export interface TokenOption {
/** The token to use to authenticate to the GitHub API. */
token?: string;
}
/** Command-line argument parser settings for the token parameter. */
export const TOKEN_OPTION_CONFIG = {
// The token to use to authenticate to the API.
token: {
type: "string",
},
} satisfies ParseArgsConfig["options"];
+7 -146
View File
@@ -1,43 +1,8 @@
#!/usr/bin/env npx tsx
import * as fs from "node:fs/promises";
import { parseArgs, ParseArgsConfig } from "node:util";
import * as exec from "@actions/exec";
import {
ApiClient,
CODEQL_ACTION_REPO,
getApiClient,
TOKEN_OPTION_CONFIG,
} from "./api-client";
import { BASELINE_BUNDLE_METADATA_FILE, BUNDLE_METADATA_FILE } from "./config";
const optionsConfig = {
...TOKEN_OPTION_CONFIG,
branch: {
type: "string",
default: "main",
},
runner: {
type: "string",
default: "macos-latest",
},
"node-version": {
type: "string",
default: "24",
},
} satisfies ParseArgsConfig["options"];
function parseOptions() {
const { values: options } = parseArgs({
options: optionsConfig,
});
return options;
}
type Options = ReturnType<typeof parseOptions>;
import { BUNDLE_METADATA_FILE } from "./config";
interface InputInfo {
bytesInOutput: number;
@@ -58,125 +23,21 @@ function toMB(bytes: number): string {
return `${(bytes / (1024 * 1024)).toFixed(2)}MB`;
}
async function getBaselineFrom(client: ApiClient, options: Options) {
const workflowRun = await client.rest.actions.listWorkflowRuns({
...CODEQL_ACTION_REPO,
branch: options.branch,
workflow_id: "pr-checks.yml",
status: "success",
per_page: 1,
event: "push",
});
if (workflowRun.data.total_count === 0) {
throw new Error(
`Expected to find a 'pr-checks.yml' run for '${options.branch}', but found none.`,
);
}
const expectedArtifactName = `bundle-metadata-${options.runner}-${options["node-version"]}`;
const artifacts = await client.rest.actions.listWorkflowRunArtifacts({
...CODEQL_ACTION_REPO,
run_id: workflowRun.data.workflow_runs[0].id,
name: expectedArtifactName,
});
if (artifacts.data.total_count === 0) {
throw new Error(
`Expected to find an artifact named '${expectedArtifactName}', but found none.`,
);
}
const downloadInfo = await client.rest.actions.downloadArtifact({
...CODEQL_ACTION_REPO,
artifact_id: artifacts.data.artifacts[0].id,
archive_format: "zip",
});
// This works fine for us with our version of Octokit, so we don't need to
// worry about over-complicating this script and handle other possibilities.
if (downloadInfo.data instanceof ArrayBuffer) {
const archivePath = `${expectedArtifactName}.zip`;
await fs.writeFile(archivePath, Buffer.from(downloadInfo.data));
console.info(`Extracting zip file: ${archivePath}`);
await exec.exec("unzip", ["-o", archivePath, "-d", "."]);
// We no longer need the archive after unzipping it.
await fs.rm(archivePath);
// Check that we have the expected file.
try {
await fs.stat(BASELINE_BUNDLE_METADATA_FILE);
} catch (err) {
throw new Error(
`Expected '${BASELINE_BUNDLE_METADATA_FILE}' to have been extracted, but it does not exist: ${err}`,
);
}
const baselineData = await fs.readFile(BASELINE_BUNDLE_METADATA_FILE);
return JSON.parse(String(baselineData)) as Metadata;
} else {
throw new Error("Expected to receive artifact data, but didn't.");
}
}
async function main() {
const options = parseOptions();
if (options.token === undefined) {
throw new Error("Missing --token");
}
// Initialise the API client.
const client = getApiClient(options.token);
const baselineMetadata = await getBaselineFrom(client, options);
const fileContents = await fs.readFile(BUNDLE_METADATA_FILE);
const metadata = JSON.parse(String(fileContents)) as Metadata;
console.info("Comparing bundle metadata to baseline...");
const filesInBaseline = new Set(Object.keys(baselineMetadata.outputs));
const filesInCurrent = new Set(Object.keys(metadata.outputs));
const filesNotPresent = filesInBaseline.difference(filesInCurrent);
if (filesNotPresent.size > 0) {
console.info(`Found ${filesNotPresent.size} file(s) which were removed:`);
for (const removedFile of filesNotPresent) {
console.info(` - ${removedFile}`);
}
}
for (const [outputFile, outputData] of Object.entries(
metadata.outputs,
).reverse()) {
const baselineOutputData = baselineMetadata.outputs[outputFile];
console.info(`${outputFile}: ${toMB(outputData.bytes)}`);
if (baselineOutputData === undefined) {
console.info(`${outputFile}: New file (${toMB(outputData.bytes)})`);
} else {
const percentageDifference =
((outputData.bytes - baselineOutputData.bytes) /
baselineOutputData.bytes) *
100.0;
for (const [inputName, inputData] of Object.entries(outputData.inputs)) {
// Ignore any inputs that make up less than 5% of the output.
const percentage = (inputData.bytesInOutput / outputData.bytes) * 100.0;
if (percentage < 5.0) continue;
if (Math.abs(percentageDifference) >= 5) {
console.info(
`${outputFile}: ${toMB(outputData.bytes)} (${percentageDifference.toFixed(2)}%)`,
);
for (const [inputName, inputData] of Object.entries(
outputData.inputs,
)) {
// Ignore any inputs that make up less than 5% of the output.
const percentage =
(inputData.bytesInOutput / outputData.bytes) * 100.0;
if (percentage < 5.0) continue;
console.info(` ${inputName}: ${toMB(inputData.bytesInOutput)}`);
}
}
console.info(` ${inputName}: ${toMB(inputData.bytesInOutput)}`);
}
}
}
+1 -1
View File
@@ -5,7 +5,7 @@ versions:
- default
steps:
- name: Set up Ruby
uses: ruby/setup-ruby@0cb964fd540e0a24c900370abf38a33466142735 # v1.305.0
uses: ruby/setup-ruby@4c56a21280b36d862b5fc31348f463d60bdc55d5 # v1.301.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration
+1 -11
View File
@@ -10,17 +10,7 @@ export const PR_CHECKS_DIR = __dirname;
export const PR_CHECK_EXCLUDED_FILE = path.join(PR_CHECKS_DIR, "excluded.yml");
/** The path to the esbuild metadata file. */
export const BUNDLE_METADATA_FILE = path.join(
PR_CHECKS_DIR,
"..",
"build-metadata.json",
);
/** The path of the baseline esbuild metadata file, once extracted from a workflow artifact. */
export const BASELINE_BUNDLE_METADATA_FILE = path.join(
PR_CHECKS_DIR,
"build-metadata.json",
);
export const BUNDLE_METADATA_FILE = path.join(PR_CHECKS_DIR, "..", "meta.json");
/** The `src` directory. */
const SOURCE_ROOT = path.join(PR_CHECKS_DIR, "..", "src");
+18 -13
View File
@@ -7,20 +7,16 @@ import { parseArgs } from "node:util";
import * as yaml from "yaml";
import {
type ApiClient,
CODEQL_ACTION_REPO,
getApiClient,
TOKEN_OPTION_CONFIG,
TokenOption,
} from "./api-client";
import { type ApiClient, getApiClient } from "./api-client";
import {
OLDEST_SUPPORTED_MAJOR_VERSION,
PR_CHECK_EXCLUDED_FILE,
} from "./config";
/** Represents the command-line options. */
export interface Options extends TokenOption {
export interface Options {
/** The token to use to authenticate to the GitHub API. */
token?: string;
/** The git ref to use the checks for. */
ref?: string;
/** Whether to actually apply the changes or not. */
@@ -29,6 +25,12 @@ export interface Options extends TokenOption {
verbose: boolean;
}
/** Identifies the CodeQL Action repository. */
const codeqlActionRepo = {
owner: "github",
repo: "codeql-action",
};
/** Represents a configuration of which checks should not be set up as required checks. */
export interface Exclusions {
/** A list of strings that, if contained in a check name, are excluded. */
@@ -98,7 +100,7 @@ async function getChecksFor(
const response = await client.paginate(
"GET /repos/{owner}/{repo}/commits/{ref}/check-runs",
{
...CODEQL_ACTION_REPO,
...codeqlActionRepo,
ref,
},
);
@@ -131,7 +133,7 @@ async function getChecksFor(
/** Gets the current list of release branches. */
async function getReleaseBranches(client: ApiClient): Promise<string[]> {
const refs = await client.rest.git.listMatchingRefs({
...CODEQL_ACTION_REPO,
...codeqlActionRepo,
ref: "heads/releases/v",
});
return refs.data.map((ref) => ref.ref).sort();
@@ -144,7 +146,7 @@ async function patchBranchProtectionRule(
checks: Set<string>,
) {
await client.rest.repos.setStatusCheckContexts({
...CODEQL_ACTION_REPO,
...codeqlActionRepo,
branch,
contexts: Array.from(checks),
});
@@ -161,7 +163,7 @@ async function updateBranch(
// Query the current set of required checks for this branch.
const currentContexts = await client.rest.repos.getAllStatusCheckContexts({
...CODEQL_ACTION_REPO,
...codeqlActionRepo,
branch,
});
@@ -203,7 +205,10 @@ async function updateBranch(
async function main(): Promise<void> {
const { values: options } = parseArgs({
options: {
...TOKEN_OPTION_CONFIG,
// The token to use to authenticate to the API.
token: {
type: "string",
},
// The git ref for which to retrieve the check runs.
ref: {
type: "string",
+18 -6
View File
@@ -251,9 +251,16 @@ export async function setupDiffInformedQueryRun(
diffRanges,
checkoutPath,
);
logger.info(
`Successfully created diff range extension pack at ${packDir}.`,
);
if (packDir === undefined) {
logger.warning(
"Cannot create diff range extension pack for diff-informed queries; " +
"reverting to performing full analysis.",
);
} else {
logger.info(
`Successfully created diff range extension pack at ${packDir}.`,
);
}
return packDir;
},
);
@@ -307,13 +314,18 @@ extensions:
* @param ranges The file line ranges, as returned by
* `getPullRequestEditedDiffRanges`.
* @param checkoutPath The path at which the repository was checked out.
* @returns The absolute path of the directory containing the extension pack.
* @returns The absolute path of the directory containing the extension pack, or
* `undefined` if no extension pack was created.
*/
function writeDiffRangeDataExtensionPack(
logger: Logger,
ranges: DiffThunkRange[],
ranges: DiffThunkRange[] | undefined,
checkoutPath: string,
): string {
): string | undefined {
if (ranges === undefined) {
return undefined;
}
if (ranges.length === 0) {
// An empty diff range means that there are no added or modified lines in
// the pull request. But the `restrictAlertsTo` extensible predicate
+1 -1
View File
@@ -1 +1 @@
{"maximumVersion": "3.21", "minimumVersion": "3.16"}
{"maximumVersion": "3.21", "minimumVersion": "3.14"}
+3 -3
View File
@@ -282,17 +282,17 @@ const CODEQL_MINIMUM_VERSION = "2.17.6";
/**
* This version will shortly become the oldest version of CodeQL that the Action will run with.
*/
const CODEQL_NEXT_MINIMUM_VERSION = "2.19.4";
const CODEQL_NEXT_MINIMUM_VERSION = "2.17.6";
/**
* This is the version of GHES that was most recently deprecated.
*/
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.15";
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.13";
/**
* This is the deprecation date for the version of GHES that was most recently deprecated.
*/
const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-04-09";
const GHES_MOST_RECENT_DEPRECATION_DATE = "2025-06-19";
/** The CLI verbosity level to use for extraction in debug mode. */
const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
+2 -17
View File
@@ -72,13 +72,6 @@ let unwrittenDiagnostics: UnwrittenDiagnostic[] = [];
*/
let unwrittenDefaultLanguageDiagnostics: DiagnosticMessage[] = [];
/**
* Counter used to generate a unique suffix for each diagnostic filename, so that
* two diagnostics produced within the same millisecond do not overwrite each
* other on disk.
*/
let diagnosticCounter = 0;
/**
* Constructs a new diagnostic message with the specified id and name, as well as optional additional data.
*
@@ -174,18 +167,10 @@ function writeDiagnostic(
// Create the directory if it doesn't exist yet.
mkdirSync(diagnosticsPath, { recursive: true });
// Include a monotonically increasing suffix to avoid filename collisions
// between diagnostics produced within the same millisecond.
const uniqueSuffix = (diagnosticCounter++).toString();
// We should only need to remove colons, but to be defensive, only allow a restricted set of
// characters.
const sanitizedTimestamp = diagnostic.timestamp.replace(
/[^a-zA-Z0-9.-]/g,
"",
);
const jsonPath = path.resolve(
diagnosticsPath,
`codeql-action-${sanitizedTimestamp}-${uniqueSuffix}.json`,
// Remove colons from the timestamp as these are not allowed in Windows filenames.
`codeql-action-${diagnostic.timestamp.replaceAll(":", "")}.json`,
);
writeFileSync(jsonPath, JSON.stringify(diagnostic));
-1
View File
@@ -8,7 +8,6 @@ export enum DocUrl {
CODEQL_BUILD_MODES = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#codeql-build-modes",
DEFINE_ENV_VARIABLES = "https://docs.github.com/en/actions/learn-github-actions/variables#defining-environment-variables-for-a-single-workflow",
DELETE_ACTIONS_CACHE_ENTRIES = "https://docs.github.com/en/actions/how-tos/manage-workflow-runs/manage-caches#deleting-cache-entries",
PRIVATE_REGISTRY_LOGS = "https://docs.github.com/en/code-security/reference/code-scanning/code-scanning-logs#diagnostic-information-for-private-package-registries",
SCANNING_ON_PUSH = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning#scanning-on-push",
SPECIFY_BUILD_STEPS_MANUALLY = "https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages#about-specifying-build-steps-manually",
SYSTEM_REQUIREMENTS = "https://codeql.github.com/docs/codeql-overview/system-requirements/",
+5 -1
View File
@@ -78,6 +78,7 @@ test.serial("loadPropertiesFromApi loads known properties", async (t) => {
url: "",
data: [
{ property_name: "github-codeql-extra-queries", value: "+queries" },
{ property_name: "github-codeql-tools", value: "toolcache" },
{ property_name: "unknown-property", value: "something" },
] satisfies properties.GitHubPropertiesResponse,
});
@@ -87,7 +88,10 @@ test.serial("loadPropertiesFromApi loads known properties", async (t) => {
logger,
mockRepositoryNwo,
);
t.deepEqual(response, { "github-codeql-extra-queries": "+queries" });
t.deepEqual(response, {
"github-codeql-extra-queries": "+queries",
"github-codeql-tools": "toolcache",
});
});
test.serial("loadPropertiesFromApi parses true boolean property", async (t) => {
+39
View File
@@ -1,7 +1,10 @@
import * as github from "@actions/github";
import { isDynamicWorkflow } from "../actions-util";
import { getRepositoryProperties } from "../api-client";
import { Logger } from "../logging";
import { RepositoryNwo } from "../repository";
import { getErrorMessage, Result, Success, Failure } from "../util";
/** The common prefix that we expect all of our repository properties to have. */
export const GITHUB_CODEQL_PROPERTY_PREFIX = "github-codeql-";
@@ -13,6 +16,7 @@ export enum RepositoryPropertyName {
DISABLE_OVERLAY = "github-codeql-disable-overlay",
EXTRA_QUERIES = "github-codeql-extra-queries",
FILE_COVERAGE_ON_PRS = "github-codeql-file-coverage-on-prs",
TOOLS = "github-codeql-tools",
}
/** Parsed types of the known repository properties. */
@@ -20,6 +24,7 @@ export type AllRepositoryProperties = {
[RepositoryPropertyName.DISABLE_OVERLAY]: boolean;
[RepositoryPropertyName.EXTRA_QUERIES]: string;
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: boolean;
[RepositoryPropertyName.TOOLS]: string;
};
/** Parsed repository properties. */
@@ -30,6 +35,7 @@ export type RepositoryPropertyApiType = {
[RepositoryPropertyName.DISABLE_OVERLAY]: string;
[RepositoryPropertyName.EXTRA_QUERIES]: string;
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: string;
[RepositoryPropertyName.TOOLS]: string;
};
/** The type of functions which take the `value` from the API and try to convert it to the type we want. */
@@ -77,6 +83,7 @@ const repositoryPropertyParsers: {
[RepositoryPropertyName.DISABLE_OVERLAY]: booleanProperty,
[RepositoryPropertyName.EXTRA_QUERIES]: stringProperty,
[RepositoryPropertyName.FILE_COVERAGE_ON_PRS]: booleanProperty,
[RepositoryPropertyName.TOOLS]: stringProperty,
};
/**
@@ -172,6 +179,38 @@ export async function loadPropertiesFromApi(
}
}
/**
* Loads [repository properties](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) if applicable.
*/
export async function loadRepositoryProperties(
repositoryNwo: RepositoryNwo,
logger: Logger,
): Promise<Result<RepositoryProperties, unknown>> {
// See if we can skip loading repository properties early. In particular,
// repositories owned by users cannot have repository properties, so we can
// skip the API call entirely in that case.
const repositoryOwnerType = github.context.payload.repository?.owner.type;
logger.debug(
`Repository owner type is '${repositoryOwnerType ?? "unknown"}'.`,
);
if (repositoryOwnerType === "User") {
logger.debug(
"Skipping loading repository properties because the repository is owned by a user and " +
"therefore cannot have repository properties.",
);
return new Success({});
}
try {
return new Success(await loadPropertiesFromApi(logger, repositoryNwo));
} catch (error) {
logger.warning(
`Failed to load repository properties: ${getErrorMessage(error)}`,
);
return new Failure(error);
}
}
/**
* Validate that `value` has the correct type for `K` and, if so, update the partial set of repository
* properties with the parsed value of the specified property.
+26 -58
View File
@@ -2,7 +2,6 @@ import * as fs from "fs";
import * as path from "path";
import * as core from "@actions/core";
import * as github from "@actions/github";
import * as io from "@actions/io";
import * as semver from "semver";
import { v4 as uuidV4 } from "uuid";
@@ -44,10 +43,7 @@ import {
} from "./diff-informed-analysis-utils";
import { EnvVar } from "./environment";
import { Feature, FeatureEnablement, initFeatures } from "./feature-flags";
import {
loadPropertiesFromApi,
RepositoryProperties,
} from "./feature-flags/properties";
import { loadRepositoryProperties } from "./feature-flags/properties";
import {
checkInstallPython311,
checkPacksForOverlayCompatibility,
@@ -65,7 +61,8 @@ import {
OverlayBaseDatabaseDownloadStats,
} from "./overlay/caching";
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
import { getRepositoryNwo, RepositoryNwo } from "./repository";
import { getRepositoryNwo } from "./repository";
import { resolveToolsInput } from "./resolve-tools-input";
import { ToolsSource } from "./setup-codeql";
import {
ActionName,
@@ -98,10 +95,7 @@ import {
checkActionVersion,
getErrorMessage,
BuildMode,
Result,
getOptionalEnvVar,
Success,
Failure,
} from "./util";
import { checkWorkflow } from "./workflow";
@@ -145,6 +139,7 @@ async function sendCompletedStatusReport(
toolsFeatureFlagsValid: boolean | undefined,
toolsSource: ToolsSource,
toolsVersion: string,
effectiveToolsInput: string | undefined,
overlayBaseDatabaseStats: OverlayBaseDatabaseDownloadStats | undefined,
dependencyCachingResults: DependencyCacheRestoreStatusReport | undefined,
logger: Logger,
@@ -170,6 +165,7 @@ async function sendCompletedStatusReport(
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
computed_tools_input: effectiveToolsInput || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || ToolsSource.Unknown,
workflow_languages: workflowLanguages || "",
@@ -224,6 +220,7 @@ async function run(startedAt: Date) {
let toolsSource: ToolsSource;
let toolsVersion: string;
let zstdAvailability: ZstdAvailability | undefined;
let effectiveToolsInput: string | undefined;
try {
initializeEnvironment(getActionVersion());
@@ -302,8 +299,14 @@ async function run(startedAt: Date) {
gitHubVersion.type,
);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
// Determine the effective tools input.
// The explicit `tools` workflow input takes precedence. If none is provided,
// fall back to the 'github-codeql-tools' repository property (if set).
effectiveToolsInput = await resolveToolsInput(repositoryNwo, logger);
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
effectiveToolsInput,
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
@@ -465,23 +468,18 @@ async function run(startedAt: Date) {
// necessary preparations. So, in that mode, we would assume that
// everything is in order and let the analysis fail if that turns out not
// to be the case.
await withGroupAsync(
"Checking cache for overlay-base database",
async () => {
overlayBaseDatabaseStats = await downloadOverlayBaseDatabaseFromCache(
codeql,
config,
logger,
);
if (!overlayBaseDatabaseStats) {
config.overlayDatabaseMode = OverlayDatabaseMode.None;
logger.info(
"No overlay-base database found in cache, " +
`reverting overlay database mode to ${OverlayDatabaseMode.None}.`,
);
}
},
overlayBaseDatabaseStats = await downloadOverlayBaseDatabaseFromCache(
codeql,
config,
logger,
);
if (!overlayBaseDatabaseStats) {
config.overlayDatabaseMode = OverlayDatabaseMode.None;
logger.info(
"No overlay-base database found in cache, " +
`reverting overlay database mode to ${OverlayDatabaseMode.None}.`,
);
}
}
if (config.overlayDatabaseMode !== OverlayDatabaseMode.Overlay) {
@@ -768,6 +766,7 @@ async function run(startedAt: Date) {
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
overlayBaseDatabaseStats,
dependencyCachingStatus,
logger,
@@ -785,44 +784,13 @@ async function run(startedAt: Date) {
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
overlayBaseDatabaseStats,
dependencyCachingStatus,
logger,
);
}
/**
* Loads [repository properties](https://docs.github.com/en/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization) if applicable.
*/
async function loadRepositoryProperties(
repositoryNwo: RepositoryNwo,
logger: Logger,
): Promise<Result<RepositoryProperties, unknown>> {
// See if we can skip loading repository properties early. In particular,
// repositories owned by users cannot have repository properties, so we can
// skip the API call entirely in that case.
const repositoryOwnerType = github.context.payload.repository?.owner.type;
logger.debug(
`Repository owner type is '${repositoryOwnerType ?? "unknown"}'.`,
);
if (repositoryOwnerType === "User") {
logger.debug(
"Skipping loading repository properties because the repository is owned by a user and " +
"therefore cannot have repository properties.",
);
return new Success({});
}
try {
return new Success(await loadPropertiesFromApi(logger, repositoryNwo));
} catch (error) {
logger.warning(
`Failed to load repository properties: ${getErrorMessage(error)}`,
);
return new Failure(error);
}
}
/**
* Compute and persist diff ranges when diff-informed analysis is enabled
* (feature flag + PR context). This writes the standard pr-diff-range.json
+295
View File
@@ -0,0 +1,295 @@
import test from "ava";
import * as sinon from "sinon";
import * as actionsUtil from "./actions-util";
import * as properties from "./feature-flags/properties";
import { RepositoryPropertyName } from "./feature-flags/properties";
import { RepositoryNwo } from "./repository";
import { resolveToolsInput } from "./resolve-tools-input";
import { getRecordingLogger, LoggedMessage, setupTests } from "./testing-utils";
import { Success } from "./util";
setupTests(test);
const repositoryNwo = { owner: "owner", repo: "repo" } as RepositoryNwo;
test.serial(
"resolveToolsInput returns undefined when no tools input or repository property is set",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns(undefined);
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(undefined);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, undefined);
t.is(loggedMessages.length, 0); // No logging when no tools input is resolved
},
);
test.serial(
"resolveToolsInput returns workflow input when only workflow input is provided",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns("latest");
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(undefined);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, "latest");
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Setting tools: latest based on workflow input.",
);
},
);
test.serial(
"resolveToolsInput returns repository property when only repository property is provided",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns(undefined);
const repositoryPropertiesResult = new Success({
[RepositoryPropertyName.TOOLS]: "toolcache",
});
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, "toolcache");
t.is(loggedMessages.length, 2);
t.is(
loggedMessages[1].message,
"Setting tools: toolcache based on the 'github-codeql-tools' repository property.",
);
},
);
test.serial(
"resolveToolsInput prioritizes workflow input over repository property",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns("nightly");
const repositoryPropertiesResult = new Success({
[RepositoryPropertyName.TOOLS]: "toolcache",
});
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, "nightly");
t.is(loggedMessages.length, 2);
t.is(
loggedMessages[1].message,
"Setting tools: nightly based on workflow input.",
);
},
);
test.serial(
"resolveToolsInput handles empty string values correctly",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon.stub(actionsUtil, "getOptionalInput").withArgs("tools").returns("");
const repositoryPropertiesResult = new Success({
[RepositoryPropertyName.TOOLS]: "toolcache",
});
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
// Empty string is falsy, so should fall back to repository property
t.is(result, "toolcache");
t.is(loggedMessages.length, 2);
t.is(
loggedMessages[1].message,
"Setting tools: toolcache based on the 'github-codeql-tools' repository property.",
);
},
);
test.serial(
"resolveToolsInput handles various tools input values correctly",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
// Test with specific version
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns("2.15.0");
const repositoryPropertiesResult = new Success({
[RepositoryPropertyName.TOOLS]: "2.20.0",
});
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, "2.15.0");
t.is(
loggedMessages[loggedMessages.length - 1].message,
"Setting tools: 2.15.0 based on workflow input.",
);
},
);
test.serial(
"resolveToolsInput handles URL input values correctly",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
// Test with URL
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns("https://example.com/codeql-bundle.tar.gz");
const repositoryPropertiesResult = new Success({
[RepositoryPropertyName.TOOLS]:
"https://example.com/old-codeql-bundle.tar.gz",
});
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, "https://example.com/codeql-bundle.tar.gz");
t.is(
loggedMessages[loggedMessages.length - 1].message,
"Setting tools: https://example.com/codeql-bundle.tar.gz based on workflow input.",
);
},
);
test.serial(
"resolveToolsInput handles repository property with different values",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns(undefined);
// Test with "latest"
const repositoryProperties = {
[RepositoryPropertyName.TOOLS]: "latest",
};
const repositoryPropertiesResult = new Success(repositoryProperties);
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, "latest");
t.is(
loggedMessages[loggedMessages.length - 1].message,
"Setting tools: latest based on the 'github-codeql-tools' repository property.",
);
},
);
test.serial(
"resolveToolsInput handles repository property with specific version",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns(undefined);
const repositoryProperties = {
[RepositoryPropertyName.TOOLS]: "2.16.1",
};
const repositoryPropertiesResult = new Success(repositoryProperties);
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, "2.16.1");
t.is(
loggedMessages[loggedMessages.length - 1].message,
"Setting tools: 2.16.1 based on the 'github-codeql-tools' repository property.",
);
},
);
test.serial(
"resolveToolsInput handles undefined repository property correctly",
async (t) => {
const loggedMessages: LoggedMessage[] = [];
const logger = getRecordingLogger(loggedMessages);
sinon
.stub(actionsUtil, "getOptionalInput")
.withArgs("tools")
.returns(undefined);
const repositoryProperties = {
[RepositoryPropertyName.TOOLS]: undefined,
};
const repositoryPropertiesResult = new Success(repositoryProperties);
sinon
.stub(properties, "loadRepositoryProperties")
.withArgs(repositoryNwo, logger)
.resolves(repositoryPropertiesResult);
const result = await resolveToolsInput(repositoryNwo, logger);
t.is(result, undefined);
t.is(loggedMessages.length, 1);
t.is(
loggedMessages[0].message,
"Loaded repository properties: github-codeql-tools",
);
},
);
+62
View File
@@ -0,0 +1,62 @@
import { getOptionalInput } from "./actions-util";
import {
loadRepositoryProperties,
RepositoryPropertyName,
} from "./feature-flags/properties";
import { Logger } from "./logging";
import { RepositoryNwo } from "./repository";
/**
* Resolves the effective tools input by combining workflow input and repository properties.
* The explicit `tools` workflow input takes precedence. If none is provided,
* fall back to the repository property (if set).
*
* @param repositoryNwo - The Name-With-Owner of the repository, used for fetching repository properties
* @param logger - Logger for outputting resolution messages
* @returns The effective tools input value
*/
export async function resolveToolsInput(
repositoryNwo: RepositoryNwo,
logger: Logger,
): Promise<string | undefined> {
const repositoryPropertiesResult = await loadRepositoryProperties(
repositoryNwo,
logger,
);
const toolsWorkflowInput = getOptionalInput("tools");
let toolsPropertyValue: string | undefined;
if (repositoryPropertiesResult) {
if (repositoryPropertiesResult.isSuccess()) {
logger.debug(
`Loaded repository properties: ${Object.keys(repositoryPropertiesResult.value).join(", ")}`,
);
toolsPropertyValue =
RepositoryPropertyName.TOOLS in repositoryPropertiesResult.value
? (repositoryPropertiesResult.value[
RepositoryPropertyName.TOOLS
] as string)
: undefined;
} else {
logger.warning(
`Failed to load repository properties: ${repositoryPropertiesResult.value}`,
);
toolsPropertyValue = undefined;
}
}
const effectiveToolsInput = toolsWorkflowInput || toolsPropertyValue;
// Log the source of the tools input for transparency
if (effectiveToolsInput) {
if (toolsWorkflowInput) {
logger.info(
`Setting tools: ${effectiveToolsInput} based on workflow input.`,
);
} else {
logger.info(
`Setting tools: ${effectiveToolsInput} based on the '${RepositoryPropertyName.TOOLS}' repository property.`,
);
}
}
return effectiveToolsInput;
}
+12 -1
View File
@@ -14,6 +14,7 @@ import { initFeatures } from "./feature-flags";
import { initCodeQL } from "./init";
import { getActionsLogger, Logger } from "./logging";
import { getRepositoryNwo } from "./repository";
import { resolveToolsInput } from "./resolve-tools-input";
import { ToolsSource } from "./setup-codeql";
import {
ActionName,
@@ -46,6 +47,7 @@ async function sendCompletedStatusReport(
toolsFeatureFlagsValid: boolean | undefined,
toolsSource: ToolsSource,
toolsVersion: string,
effectiveToolsInput: string | undefined,
logger: Logger,
error?: Error,
): Promise<void> {
@@ -67,6 +69,7 @@ async function sendCompletedStatusReport(
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: getOptionalInput("tools") || "",
computed_tools_input: effectiveToolsInput || "",
tools_resolved_version: toolsVersion,
tools_source: toolsSource || ToolsSource.Unknown,
workflow_languages: "",
@@ -97,6 +100,7 @@ async function run(startedAt: Date): Promise<void> {
let toolsFeatureFlagsValid: boolean | undefined;
let toolsSource: ToolsSource;
let toolsVersion: string;
let effectiveToolsInput: string | undefined;
try {
initializeEnvironment(getActionVersion());
@@ -140,8 +144,14 @@ async function run(startedAt: Date): Promise<void> {
gitHubVersion.type,
);
toolsFeatureFlagsValid = codeQLDefaultVersionInfo.toolsFeatureFlagsValid;
// Determine the effective tools input.
// The explicit `tools` workflow input takes precedence. If none is provided,
// fall back to the 'github-codeql-tools' repository property (if set).
effectiveToolsInput = await resolveToolsInput(repositoryNwo, logger);
const initCodeQLResult = await initCodeQL(
getOptionalInput("tools"),
effectiveToolsInput,
apiDetails,
getTemporaryDirectory(),
gitHubVersion.type,
@@ -183,6 +193,7 @@ async function run(startedAt: Date): Promise<void> {
toolsFeatureFlagsValid,
toolsSource,
toolsVersion,
effectiveToolsInput,
logger,
);
}
+1 -1
View File
@@ -111,7 +111,7 @@ async function run(startedAt: Date) {
logger,
);
// Perform best-effort checks that the private registries are reachable.
// Check that the private registries are reachable.
await checkConnections(logger, proxyInfo);
// Report success if we have reached this point.
-32
View File
@@ -8,7 +8,6 @@ import {
} from "./../testing-utils";
import {
checkConnections,
connectionTestConfig,
ReachabilityBackend,
ReachabilityError,
} from "./reachability";
@@ -119,34 +118,3 @@ test("checkConnections - handles invalid URLs", async (t) => {
`Finished testing connections`,
]);
});
test("checkConnections - appends extra paths", async (t) => {
const backend = new MockReachabilityBackend();
const checkConnection = sinon.stub(backend, "checkConnection").resolves(200);
const messages = await withRecordingLoggerAsync(async (logger) => {
await checkConnections(
logger,
{
...proxyInfo,
registries: [{ ...nugetFeed, url: "https://api.nuget.org/" }],
},
backend,
);
});
checkExpectedLogMessages(t, messages, [
`Testing connection to https://api.nuget.org/`,
`Successfully tested connection to https://api.nuget.org/`,
`Finished testing connections`,
]);
t.true(
checkConnection.calledWith(
sinon.match(
new URL(
`https://api.nuget.org/${connectionTestConfig["nuget_feed"]?.path}`,
),
),
),
);
});
+2 -43
View File
@@ -2,41 +2,11 @@ import * as https from "https";
import { HttpsProxyAgent } from "https-proxy-agent";
import { DocUrl } from "../doc-url";
import { Logger } from "../logging";
import { getErrorMessage } from "../util";
import { getAddressString, ProxyInfo, Registry } from "./types";
/** Represents registry-specific connection test configurations. */
export interface ConnectionTestConfig {
/** An optional path to append to the end of the base url. */
path?: string;
}
/** A partial mapping of registry types to extra connection test configurations. */
export const connectionTestConfig: Partial<
Record<string, ConnectionTestConfig>
> = {
nuget_feed: { path: "v3/index.json" },
};
/**
* Applies the registry-specific check configuration to the base URL, if any and applicable.
*/
export function makeTestUrl(
config: ConnectionTestConfig | undefined,
base: URL,
): URL {
if (config?.path === undefined) {
return base;
}
if (base.pathname.endsWith(config.path)) {
return base;
}
return new URL(config.path, base);
}
export class ReachabilityError extends Error {
constructor(public readonly statusCode?: number | undefined) {
super();
@@ -71,7 +41,7 @@ class NetworkReachabilityBackend implements ReachabilityBackend {
url,
{
agent: this.agent,
method: "GET",
method: "HEAD",
ca: this.proxy.cert,
timeout: 5 * 1000, // 5 seconds
},
@@ -115,13 +85,6 @@ export async function checkConnections(
// Don't do anything if there are no registries.
if (proxy.registries.length === 0) return result;
// Start a log group and print a message with a disclaimer with a link to the
// relevant documentation that these checks are a best-effort process.
logger.startGroup("Testing connections via the proxy");
logger.info(
`The connection tests performed here are best-effort only and failures here may not affect the subsequent analysis. See ${DocUrl.PRIVATE_REGISTRY_LOGS} for more information.`,
);
try {
// Initialise a networking backend if no backend was provided.
if (backend === undefined) {
@@ -129,7 +92,6 @@ export async function checkConnections(
}
for (const registry of proxy.registries) {
const config = connectionTestConfig[registry.type];
const address = getAddressString(registry);
const url = URL.parse(address);
@@ -140,11 +102,9 @@ export async function checkConnections(
continue;
}
const testUrl = makeTestUrl(config, url);
try {
logger.debug(`Testing connection to ${url}...`);
const statusCode = await backend.checkConnection(testUrl);
const statusCode = await backend.checkConnection(url);
logger.info(`Successfully tested connection to ${url} (${statusCode})`);
result.add(registry);
@@ -166,6 +126,5 @@ export async function checkConnections(
);
}
logger.endGroup();
return result;
}
+1
View File
@@ -316,6 +316,7 @@ const testCreateInitWithConfigStatusReport = test.macro({
const initStatusReport: InitStatusReport = {
...statusReportBase,
tools_input: "",
computed_tools_input: "",
tools_resolved_version: "foo",
tools_source: ToolsSource.Unknown,
workflow_languages: "actions",
+2
View File
@@ -482,6 +482,8 @@ export async function sendStatusReport<S extends StatusReportBase>(
export interface InitStatusReport extends StatusReportBase {
/** Value given by the user as the "tools" input. */
tools_input: string;
/** The effective tools input that was used, after applying defaults and repository properties. */
computed_tools_input: string;
/** Version of the bundle used. */
tools_resolved_version: string;
/** Where the bundle originated from. */