Compare commits

..

1 Commits

Author SHA1 Message Date
Michael B. Gale
bac9cb908d Update undici 2026-10-02 15:58:31 +01:00
145 changed files with 3785 additions and 5600 deletions

View File

@@ -92,7 +92,8 @@ runs:
Please do the following:
- [ ] Approve running the full set of PR checks.
- [ ] Approve and merge the PR. When merging the PR, make sure "Create a merge commit" is selected rather than "Squash and merge" or "Rebase and merge".
- [ ] Approve and merge the PR. When merging the PR, make sure "Create a merge commit" is
selected rather than "Squash and merge" or "Rebase and merge".
EOF
)

View File

@@ -11,12 +11,9 @@ The CodeQL Action is used in GitHub Actions workflows to run CodeQL scans using
## Review instructions
- Prioritise identifying critical issues, such as logic bugs, over comments on documentation or typos.
- When wording review comments, be helpful and friendly. Assume that the PR author has written the code with the best of intentions. Never word suggestions as commands or using the imperative. Examples of what you should never write: "Preserve that non-fatal behaviour here" or "Please preserve that non-fatal behaviour here".
- When writing feedback, assume that the PR author is competent and is able to understand whether the point you are making is valid or not, why you are raising it, and how to best address it. While you can suggest how to address a point you are making, don't phrase it as a requirement or assume that it is the only solution.
- Always word your comments constructively as suggestions for improvements, for example: "It would make sense to ..." or "Could you add ...?" or "Would it make sense to ...?"
- When wording review comments, be helpful and friendly. Assume that the PR author has written the code with the best of intentions. Word your comments constructively as suggestions for improvements. Do not word suggestions as commands.
- If you want to comment on a change that you believe will fail a CI check, do not present the CI failure you expect as a fact. Instead, write that you think a change "may" lead to a failure in CI. Suggest that, if such a failure manifests, the changes you are commenting on may be the place responsible for the failure and are worth looking at.
- If a suggestion you make is suitable for a follow-up, such as a refactoring that doesn't change the behaviour or fixing a typo in a comment, mention that it can be addressed in a later PR rather than blocking this one or prefix your comment with "Minor: ".
- If a suggestion you make is suitable for a follow-up, such as a refactoring that doesn't change the behaviour or fixing a typo in a comment, mention that it can be addressed in a later PR rather than blocking this one.
- If a change is a net improvement, for example because it improves on an existing limitation of existing code, do not complain about pre-existing problems that remain. You may comment on them, but you should make it clear that the thing you are commenting on is not new by writing e.g. "Not new in this PR, but [..]" followed by your description of the issue and a suggestion that it could be improved at the same time with e.g. "Consider whether this is worth addressing as part of this PR as well."
## Generated code
@@ -25,16 +22,6 @@ The main codebase of the CodeQL Action is written in TypeScript and compiled to
GitHub Actions workflows in the `.github/workflows` directory whose filenames start with two underscores (e.g. `__all-platform-bundle.yml`) are automatically generated using the `pr-checks/sync.sh` script from template files in the `pr-checks/checks` directory. Therefore, you do not need to review files in the `.github/workflows` directory that start with two underscores. However, you should review changes to the `pr-checks` directory as well as workflows in the `.github/workflows` directory that do not start with underscores.
## Feature flags
Some functionality in the code may be gated behind feature flags, which are controlled server-side. If the functionality that is gated behind them is user-facing, then this should be documented in a change note at the time that the gated functionality is added. See `CHANGELOG.md` for existing notes that mention "experimental" for examples. These typically include information about when users may expect to see the feature rolled out.
When a feature flag that gates some functionality is removed, this does not need to be documented in a change note since the feature is already rolled out and the notes for the release which introduced the feature already describe it. The only exception is functionality which will start having an effect on GHES as a result of the feature flag removal:
- Most functionality gated behind feature flags does not affect GHES.
- We can make functionality available on GHES by setting `defaultValue` to `true` first and waiting for this to have had an effect on GHES. No change note is needed if a feature flag is removed where `defaultValue` was `true`.
- When removing a feature flag where `defaultValue` was `false` and the functionality starts to affect GHES, a change note may be appropriate.
## Release process
Changes that are merged to the `main` branch are not used in production straight away. Instead, changes from `main` must first be released using the release process, which has to be manually triggered by a staff member. Therefore, it is possible for further changes to be made to the code after some changes have been merged to `main` but before they are released. Once the release process automation is started, a series of PRs are automatically generated:

View File

@@ -8,6 +8,8 @@ updates:
interval: weekly
cooldown:
default-days: 7
exclude:
- "@actions/*"
labels:
- Rebuild
# Ignore incompatible dependency updates
@@ -31,6 +33,8 @@ updates:
interval: weekly
cooldown:
default-days: 7
exclude:
- "actions/*"
labels:
- Rebuild
groups:

View File

@@ -87,7 +87,7 @@ jobs:
post-processed-sarif-path: '${{ runner.temp }}/post-processed'
- name: Upload SARIF files
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: |
analysis-kinds-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}
@@ -95,7 +95,7 @@ jobs:
retention-days: 7
- name: Upload post-processed SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: |
post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}

View File

@@ -65,7 +65,7 @@ jobs:
output: '${{ runner.temp }}/results'
upload-database: false
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: config-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: '${{ runner.temp }}/results/javascript.sarif'

View File

@@ -47,12 +47,10 @@ jobs:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20.x
cache: npm
- name: Install newer npm
run: npm install -g npm@11.19.1
- name: Install dependencies
run: npm ci
- name: Prepare test

View File

@@ -76,7 +76,7 @@ jobs:
output: '${{ runner.temp }}/results'
upload-database: false
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: diagnostics-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: '${{ runner.temp }}/results/javascript.sarif'

View File

@@ -97,7 +97,7 @@ jobs:
with:
output: '${{ runner.temp }}/results'
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: with-baseline-information-${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: '${{ runner.temp }}/results/javascript.sarif'
@@ -124,5 +124,4 @@ jobs:
env:
CODEQL_ACTION_SKIP_FILE_COVERAGE_ON_PRS: false
CODEQL_ACTION_SUBLANGUAGE_FILE_COVERAGE: true
CODEQL_ACTION_PER_LANGUAGE_BUNDLES: false
CODEQL_ACTION_TEST_MODE: true

View File

@@ -44,6 +44,8 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
version: stable-v2.19.4
- os: ubuntu-latest
version: stable-v2.20.7
- os: ubuntu-latest
@@ -54,8 +56,6 @@ jobs:
version: stable-v2.23.9
- os: ubuntu-latest
version: stable-v2.24.3
- os: ubuntu-latest
version: stable-v2.25.6
- os: ubuntu-latest
version: default
- os: ubuntu-latest

View File

@@ -44,6 +44,8 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
version: stable-v2.19.4
- os: ubuntu-latest
version: stable-v2.20.7
- os: ubuntu-latest
@@ -54,8 +56,6 @@ jobs:
version: stable-v2.23.9
- os: ubuntu-latest
version: stable-v2.24.3
- os: ubuntu-latest
version: stable-v2.25.6
- os: ubuntu-latest
version: default
- os: ubuntu-latest

View File

@@ -44,6 +44,8 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
version: stable-v2.19.4
- os: ubuntu-latest
version: stable-v2.20.7
- os: ubuntu-latest
@@ -54,8 +56,6 @@ jobs:
version: stable-v2.23.9
- os: ubuntu-latest
version: stable-v2.24.3
- os: ubuntu-latest
version: stable-v2.25.6
- os: ubuntu-latest
version: default
- os: ubuntu-latest

View File

@@ -62,7 +62,7 @@ jobs:
with:
output: '${{ runner.temp }}/results'
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: '${{ runner.temp }}/results/javascript.sarif'

View File

@@ -54,6 +54,10 @@ jobs:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
version: stable-v2.19.4
- os: macos-15-xlarge
version: stable-v2.19.4
- os: ubuntu-latest
version: stable-v2.20.7
- os: macos-15-xlarge
@@ -74,10 +78,6 @@ jobs:
version: stable-v2.24.3
- os: macos-latest-xlarge
version: stable-v2.24.3
- os: ubuntu-latest
version: stable-v2.25.6
- os: macos-latest-xlarge
version: stable-v2.25.6
- os: ubuntu-latest
version: default
- os: macos-latest-xlarge
@@ -116,14 +116,13 @@ jobs:
version: ${{ matrix.version }}
use-all-platform-bundle: 'false'
setup-kotlin: 'true'
- name: Install Python 3.13.15 for older CLI versions
# Older CLI versions don't work with Python 3.13.16 or newer because their Python extractor
# imports `importlib._bootstrap._ERR_MSG`, which those Python versions no longer define.
- name: Install Python 3.13 for older CLI versions
# We need Python 3.13 for older CLI versions because they are not compatible with Python 3.14 or newer.
# See https://github.com/github/codeql-action/pull/3212
if: matrix.version != 'nightly-latest' && matrix.version != 'linked'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: '3.13.15'
python-version: '3.13'
- name: Use Xcode 16
# Only the older CodeQL CLI versions need Xcode 16, and these run on macOS 15.
@@ -192,5 +191,6 @@ jobs:
exit 1
fi
env:
CODEQL_ACTION_CLEANUP_TOOLCACHE_BUNDLES: true
CODEQL_ACTION_RESOLVE_SUPPORTED_LANGUAGES_USING_CLI: true
CODEQL_ACTION_TEST_MODE: true

View File

@@ -80,12 +80,10 @@ jobs:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20.x
cache: npm
- name: Install newer npm
run: npm install -g npm@11.19.1
- name: Install dependencies
run: npm ci
- name: Prepare test

View File

@@ -80,12 +80,10 @@ jobs:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20.x
cache: npm
- name: Install newer npm
run: npm install -g npm@11.19.1
- name: Install dependencies
run: npm ci
- name: Prepare test

View File

@@ -80,12 +80,10 @@ jobs:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20.x
cache: npm
- name: Install newer npm
run: npm install -g npm@11.19.1
- name: Install dependencies
run: npm ci
- name: Prepare test

View File

@@ -80,12 +80,10 @@ jobs:
go-version: ${{ inputs.go-version || '>=1.21.0' }}
cache: false
- name: Install Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 20.x
cache: npm
- name: Install newer npm
run: npm install -g npm@11.19.1
- name: Install dependencies
run: npm ci
- name: Prepare test

View File

@@ -54,7 +54,7 @@ jobs:
use-all-platform-bundle: 'false'
setup-kotlin: 'true'
- name: Set up Ruby
uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
uses: ruby/setup-ruby@762794c140bbeda0f1224786aa33b4b46783a6c1 # v1.326.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration

2
.github/workflows/__rust.yml generated vendored
View File

@@ -35,7 +35,7 @@ jobs:
matrix:
include:
- os: ubuntu-latest
version: stable-v2.20.7
version: stable-v2.19.4
- os: ubuntu-latest
version: stable-v2.22.1
- os: ubuntu-latest

View File

@@ -57,7 +57,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: 'npm'

View File

@@ -30,7 +30,7 @@ jobs:
fail-fast: false
matrix:
version:
- stable-v2.20.7
- stable-v2.20.3
- default
- linked
- nightly-latest
@@ -89,7 +89,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- name: Check expected artifacts exist
run: |
LANGUAGES="cpp csharp go java javascript python"

View File

@@ -29,7 +29,7 @@ jobs:
fail-fast: false
matrix:
version:
- stable-v2.20.7
- stable-v2.20.3
- default
- linked
- nightly-latest
@@ -82,10 +82,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Download all artifacts
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
- name: Check expected artifacts exist
run: |
VERSIONS="stable-v2.20.7 default linked nightly-latest"
VERSIONS="stable-v2.20.3 default linked nightly-latest"
LANGUAGES="cpp csharp go java javascript python"
for version in $VERSIONS; do
pushd "./my-debug-artifacts-${version//./}"

View File

@@ -47,7 +47,7 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
fetch-depth: 0 # ensure we have all tags and can push commits
- uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: 'npm'

View File

@@ -42,17 +42,11 @@ jobs:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
# Install a new enough version of `npm` to understand `min-release-age`
# that is still compatible with Node 20.
- name: Install newer npm
if: matrix.node-version == 20
run: npm install -g npm@11.19.1
- name: Install dependencies
run: |
# Use the system Bash shell to ensure we can run commands like `npm ci`
@@ -101,16 +95,8 @@ jobs:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Check for incorrect addresses in package-lock.json
run: |
if git grep -nE '(pkgs\.visualstudio\.com|pkgs\.dev\.azure\.com|packagefeedproxy\.microsoft\.io)' -- \
'package-lock.json'; then
echo "::error::package-lock.json contains internal package feed URLs. Replace them with public registry URLs."
exit 1
fi
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: "npm"
@@ -128,9 +114,9 @@ jobs:
working-directory: pr-checks
run: npx tsx --test
- name: Run `pr-checks/changenotes.ts` to ensure that all unreleased change notes are valid
- name: Run `pr-checks/changenotes.mts` to ensure that all unreleased change notes are valid
if: ${{ !cancelled() && steps.install-deps.outcome == 'success' }}
run: npx tsx pr-checks/changenotes.ts validate
run: npx tsx pr-checks/changenotes.mts validate
- name: Verify all Actions use the same Node version
id: head-version
@@ -175,7 +161,7 @@ jobs:
- name: Upload repo size comment
if: steps.fetch-base.outcome == 'success'
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: repo-size-comment
path: ${{ runner.temp }}/repo-size/
@@ -223,7 +209,7 @@ jobs:
steps:
- name: Download repo size comment
uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: repo-size-comment
path: repo-size-comment

View File

@@ -28,7 +28,7 @@ defaults:
jobs:
prepare:
name: "Release info"
name: "Prepare release"
runs-on: ubuntu-latest
if: github.repository == 'github/codeql-action'

View File

@@ -33,7 +33,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Install Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: npm

View File

@@ -30,7 +30,7 @@ jobs:
ref: ${{ env.HEAD_REF }}
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: 'npm'
@@ -54,27 +54,32 @@ jobs:
run: |
git fetch origin "$BASE_BRANCH"
# Allow merge conflicts in `lib`, since rebuilding should resolve them. Conflicts leave the
# merge in progress, so check for `MERGE_HEAD` to tell them apart from failures that don't.
if git merge "origin/$BASE_BRANCH"; then
# Allow merge conflicts in `lib`, since rebuilding should resolve them.
git merge "origin/$BASE_BRANCH"
MERGE_RESULT=$?
if [ "$MERGE_RESULT" -eq 0 ]; then
echo "Merge succeeded cleanly."
elif git rev-parse --verify MERGE_HEAD >/dev/null 2>&1; then
echo "Merge conflicts detected, continuing."
elif [ "$MERGE_RESULT" -eq 1 ]; then
echo "Merge conflicts detected (exit code $MERGE_RESULT), continuing."
else
echo "git merge failed with unexpected exit code $MERGE_RESULT."
exit 1
fi
if [ "$MERGE_RESULT" -ne 0 ]; then
echo "merge-in-progress=true" >> $GITHUB_OUTPUT
# Check for merge conflicts outside of `lib`.
CONFLICTS_OUTSIDE_LIB=$(git diff --name-only --diff-filter=U | grep --invert-match '^lib/' || true)
if [ -n "$CONFLICTS_OUTSIDE_LIB" ]; then
# Check for merge conflicts outside of `lib`. Disable git diff's trailing whitespace check
# since `node_modules/@types/semver/README.md` fails it.
if git -c core.whitespace=-trailing-space diff --check | grep --invert-match '^lib/'; then
echo "Merge conflicts were detected outside of the lib directory. Please resolve them manually."
echo "$CONFLICTS_OUTSIDE_LIB"
git -c core.whitespace=-trailing-space diff --check | grep --invert-match '^lib/' || true
exit 1
fi
echo "No merge conflicts found outside the lib directory. We should be able to resolve all of" \
"these by rebuilding the Action."
else
echo "git merge failed for a reason other than merge conflicts."
exit 1
fi
- name: Compile TypeScript

View File

@@ -10,7 +10,8 @@ on:
required: true
# Only for dry-runs of changes to the workflow.
push:
# Don't run dry-run on release branches, since that's unnecessary.
# Don't run dry-run on release branches, to avoid an issue where the
# "new" tag determined by the "Prepare release" job already exists.
branches-ignore:
- releases/v*
paths:
@@ -23,7 +24,7 @@ defaults:
jobs:
prepare:
name: "Prepare"
name: "Prepare release"
if: github.repository == 'github/codeql-action'
permissions:
@@ -106,10 +107,8 @@ jobs:
# We usually expect to checkout `inputs.rollback-tag` (required for `workflow_dispatch`),
# but use `v0.0.0` for testing.
ROLLBACK_TAG: ${{ inputs.rollback-tag || 'v0.0.0' }}
# Use `needs.prepare.outputs.version` for actual runs and `v0.0.1` for testing.
RELEASE_TAG: ${{ case(github.event_name == 'workflow_dispatch', needs.prepare.outputs.version, 'v0.0.1') }}
# Use `needs.prepare.outputs.major_version` for actual runs and `v0` for testing.
MAJOR_VERSION_TAG: ${{ case(github.event_name == 'workflow_dispatch', needs.prepare.outputs.major_version, 'v0') }}
RELEASE_TAG: ${{ needs.prepare.outputs.version }}
MAJOR_VERSION_TAG: ${{ needs.prepare.outputs.major_version }}
run: |
git checkout "refs/tags/${ROLLBACK_TAG}"
git tag --annotate "${RELEASE_TAG}" --message "${RELEASE_TAG}"
@@ -185,3 +184,4 @@ jobs:
# Setting this to `true` for non-workflow_dispatch events will
# still push the `branch`, but won't create a corresponding PR
dry-run: "${{ github.event_name != 'workflow_dispatch' }}"

View File

@@ -41,7 +41,7 @@ jobs:
git config --global user.name "github-actions[bot]"
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: 'npm'

View File

@@ -16,15 +16,15 @@ defaults:
shell: bash
jobs:
prepare:
name: "Prepare"
name: "Prepare release"
permissions:
contents: read
uses: ./.github/workflows/prepare-release.yml
update:
name: "Update release branch"
timeout-minutes: 45
runs-on: ubuntu-latest
if: github.event_name == 'workflow_dispatch'
@@ -77,7 +77,6 @@ jobs:
--conductor ${GITHUB_ACTOR}
backport:
name: "Create backport"
timeout-minutes: 45
runs-on: ubuntu-latest
environment: Automation

View File

@@ -26,7 +26,7 @@ jobs:
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Set up Node.js
uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
with:
node-version: 24
cache: 'npm'

1
.npmrc
View File

@@ -1,2 +1 @@
lockfile-version=3
min-release-age=7

View File

@@ -7,10 +7,6 @@
// transpiled JavaScript
"build": true,
"lib": true,
// exclude "tests" by default because it causes VSCode to start language-specific extensions
// that are not typically needed during development (or indeed may not work correctly)
"tests": true
},
"search.exclude": {
"**/node_modules": true,
@@ -22,7 +18,7 @@
"git.ignoreLimitWarning": true,
// Use the vendored TypeScript version to have a consistent development experience across
// machines.
"js/ts.tsdk.path": "node_modules/typescript/lib",
"typescript.tsdk": "node_modules/typescript/lib",
"[typescript]": {
"editor.defaultFormatter": "esbenp.prettier-vscode"
},

View File

@@ -6,19 +6,6 @@ See the [releases page](https://github.com/github/codeql-action/releases) for th
No user facing changes.
## 4.39.0 - 15 Oct 2026
- _Breaking change_: Bump the minimum required CodeQL bundle version to 2.20.7. [#4205](https://github.com/github/codeql-action/pull/4205)
- The `codeql-action/analyze` step now validates that a correct argument for the `checkout_path` input has been provided. The `checkout_path` input must be set to the path where the repository that is being analyzed is checked out at on the runner, if that path is something other than the workspace root. If the path does not point to a repository checkout or is different from the path that was used by `codeql-action/init`, then the CodeQL Action now produces a warning. [#4148](https://github.com/github/codeql-action/pull/4148)
- Resolved an issue with third-party caching implementations that prevented caches from being restored correctly. [#4206](https://github.com/github/codeql-action/pull/4206)
- The `codeql-action/start-proxy` step that is used in Code Scanning Default Setup now finds CodeQL releases using the same logic as `codeql-action/init`. This primarily benefits customers who are using GitHub instances other than `github.com` where the `codeql-action/start-proxy` step may previously have been unable to locate recent releases and ended up using outdated versions of the private registry authentication proxy as a result. [#4198](https://github.com/github/codeql-action/pull/4198)
## 4.38.3 - 08 Oct 2026
- _Upcoming breaking change_: CodeQL version 2.21.2 and earlier were discontinued on 24 September 2026 alongside GitHub Enterprise Server 3.17, and will be unsupported by the next minor release of the CodeQL Action. Added a deprecation warning for customers using these versions of CodeQL. [#4188](https://github.com/github/codeql-action/pull/4188)
- Update default CodeQL bundle version to [2.27.2](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.2). [#4203](https://github.com/github/codeql-action/pull/4203)
- Fixed a bug where the decision of whether to use a per-language bundle did not account for custom configurations that reference queries outside of compiled CodeQL packs. This issue was caught during internal testing and did not affect any customer repositories. We will resume the roll out of per-language bundles in the coming weeks. [#4184](https://github.com/github/codeql-action/pull/4184)
## 4.38.2 - 24 Sept 2026
- Update default CodeQL bundle version to [2.27.1](https://github.com/github/codeql-action/releases/tag/codeql-bundle-v2.27.1). [#4160](https://github.com/github/codeql-action/pull/4160)

View File

@@ -53,7 +53,6 @@ Here are a few things you can do that will increase the likelihood of your pull
- Write tests.
- Keep your change as focused as possible. If there are multiple changes you would like to make that are not dependent upon each other, consider submitting them as separate pull requests.
- Write a [good commit message](http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html).
- For user-facing changes, add a change-note file. See [unreleased-change-notes/README.md](unreleased-change-notes/README.md).
## Releasing (write access required)

View File

@@ -72,11 +72,12 @@ 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.36.2` | `2.25.6` | Enterprise Server 3.22 | |
| `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 | |
| `v3.28.12` | `2.20.7` | Enterprise Server 3.17 | |
| `v3.28.6` | `2.20.3` | Enterprise Server 3.16 | |
See the full list of GHES release and deprecation dates at [GitHub Enterprise Server releases](https://docs.github.com/en/enterprise-server/admin/all-releases#releases-of-github-enterprise-server).

View File

@@ -1,4 +1,3 @@
import pkg from "./package.json" with { type: "json" };
globalThis.__CODEQL_ACTION_VERSION__ = pkg.version;
globalThis.__CODEQL_ACTION_TEST_ENV__ = "unit-test";

View File

@@ -78,7 +78,7 @@ const UPLOAD_LIB_SRC = "./src/upload-lib";
*
* The virtual module additionally re-exports `upload-lib` under the `uploadLib` namespace so that
* external consumers can access it via the small `lib/upload-lib.js` stub emitted below.
*
*
* A tiny stub file is emitted for each Action entrypoint, and one for `upload-lib`. Each stub
* imports the shared bundle and calls/re-exports from the respective entry point.
*
@@ -212,7 +212,6 @@ const context = await esbuild.context({
target: ["node20"],
define: {
__CODEQL_ACTION_VERSION__: JSON.stringify(pkg.version),
__CODEQL_ACTION_TEST_ENV__: JSON.stringify(""),
},
metafile: true,
});

View File

@@ -140,17 +140,6 @@ export default [
"no-async-foreach/no-async-foreach": "error",
"no-sequences": "error",
"no-shadow": "off",
// A basic check that we don't use `exportVariable` from `@actions/core`.
"no-restricted-syntax": [
"error",
{
selector: "MemberExpression[property.name='exportVariable']",
message:
"Use the `export` method of an `Env` instance or `exportEnvVar` from `environment.ts` instead.",
},
],
// This is overly restrictive with unsetting `EnvVar`s
"@typescript-eslint/no-dynamic-delete": "off",
"@typescript-eslint/no-shadow": "error",
@@ -169,16 +158,7 @@ export default [
},
},
{
files: ["src/environment.ts"],
// We allow `exportVariable` from `@actions/core` to be used in this file
// since it defines the wrapper around it that other modules use.
rules: {
"no-restricted-syntax": "off",
},
},
{
files: ["**/*.ts", "**/*.js"],
files: ["**/*.ts", "**/*.js", "**/*.mts"],
rules: {
"@typescript-eslint/no-explicit-any": "off",
@@ -200,7 +180,7 @@ export default [
},
},
{
files: ["pr-checks/**/*.ts"],
files: ["pr-checks/**/*.ts", "pr-checks/**/*.mts"],
languageOptions: {
parserOptions: {

View File

@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.27.2",
"cliVersion": "2.27.2",
"priorBundleVersion": "codeql-bundle-v2.27.1",
"priorCliVersion": "2.27.1"
"bundleVersion": "codeql-bundle-v2.27.1",
"cliVersion": "2.27.1",
"priorBundleVersion": "codeql-bundle-v2.27.0",
"priorCliVersion": "2.27.0"
}

3856
lib/entry-points.js generated

File diff suppressed because it is too large Load Diff

288
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "codeql",
"version": "4.39.1",
"version": "4.38.3",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "codeql",
"version": "4.39.1",
"version": "4.38.3",
"license": "MIT",
"workspaces": [
"pr-checks"
@@ -23,19 +23,20 @@
"@actions/io": "^2.0.0",
"@actions/tool-cache": "^3.0.1",
"@octokit/core": "^7.0.8",
"@octokit/plugin-paginate-rest": "^16.0.0",
"@octokit/plugin-paginate-rest": "^15.0.0",
"@octokit/plugin-rest-endpoint-methods": "^18.0.0",
"@octokit/plugin-retry": "^8.1.1",
"archiver": "^8.0.0",
"follow-redirects": "^1.16.1",
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.16.0",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^5.4.3",
"js-yaml": "^5.4.2",
"jsonschema": "1.5.0",
"long": "^5.3.2",
"node-forge": "^1.4.0",
"semver": "^7.8.5",
"undici": "^6.28.0",
"undici": "^6.29.0",
"uuid": "^14.0.2"
},
"devDependencies": {
@@ -57,14 +58,14 @@
"eslint-import-resolver-typescript": "^4.4.5",
"eslint-plugin-github": "^6.1.2",
"eslint-plugin-import-x": "^4.17.1",
"eslint-plugin-jsdoc": "^65.2.0",
"eslint-plugin-jsdoc": "^64.5.4",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^13.0.6",
"globals": "^17.13.0",
"globals": "^17.12.0",
"nock": "^14.0.17",
"sinon": "^22.1.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.71.1"
"typescript-eslint": "^8.70.1"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@@ -2204,12 +2205,12 @@
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-16.0.0.tgz",
"integrity": "sha512-7RtUeGZypAK4EA4LrjTCnsLALNOoUcYh5vOnCNXpdIQVTQCPh4OFu7324iPqAls3KGgVnZktKUnNKZCOKyHrlA==",
"version": "15.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-15.0.0.tgz",
"integrity": "sha512-lw9A9YL5s4VPj+VEx8uMxaxQm2YTgrPDkrLEuZuu18R8TK3oPcXF4K6t52nx6xn1RcogZC9i188sAr/4XYJaQQ==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^18.0.0"
"@octokit/types": "^17.0.0"
},
"engines": {
"node": ">= 20"
@@ -2218,6 +2219,21 @@
"@octokit/core": ">=6"
}
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
"version": "28.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-28.0.0.tgz",
"integrity": "sha512-0rFyLuyHvIj6uuZWuDslxkowFYdPXoNIkeAv4b27dzm2Tf4vGWXnPsMcxs7d65kLdMERgP3wc1AEPlqMz8e1cQ==",
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
"version": "17.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-17.0.0.tgz",
"integrity": "sha512-ByP1v7YL5SMveFPP7+sj0/ZuWCOOg/Chs4NafOMpq6WNIM/hdGY0S7C0TCGDBWu1aGmOxmUIhMx3cO+IdwYZ1Q==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^28.0.0"
}
},
"node_modules/@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
@@ -2580,7 +2596,7 @@
},
"node_modules/@types/debug": {
"version": "4.1.13",
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/debug/-/debug-4.1.13.tgz",
"integrity": "sha1-ItHMnVQtNZPK6nZPl0MGqzYobuc=",
"license": "MIT",
"dependencies": {
@@ -2623,7 +2639,7 @@
},
"node_modules/@types/mdast": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/mdast/-/mdast-4.0.4.tgz",
"integrity": "sha1-fM9y7dLxqn3TQ34YDGQ3NYWATdY=",
"license": "MIT",
"dependencies": {
@@ -2632,7 +2648,7 @@
},
"node_modules/@types/ms": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/ms/-/ms-2.1.0.tgz",
"integrity": "sha1-BSqmekjszEMJ1/AZG35BQ0uQu3g=",
"license": "MIT"
},
@@ -2697,22 +2713,22 @@
},
"node_modules/@types/unist": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/@types/unist/-/unist-3.0.3.tgz",
"integrity": "sha1-rKqw+RnOaczmKcLU7S60rcG2wgw=",
"license": "MIT"
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.71.1.tgz",
"integrity": "sha512-nNlBf6HuotqMgZvSkWD5hNdemiBIxQ2NmrlgfcUIeZRs+BbakjscCQRq/Hb74EFVnFiSWWdL12JruqwBy3ERDw==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.70.1.tgz",
"integrity": "sha512-nDNrUQ/4ruSNYbu749TRY7cfrzPtoLHEXSNBI8aaNY32LlZCajixqRf3FqcKC4p5Cam4VOHYx/t+i5+nKXvrqA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/regexpp": "^4.12.2",
"@typescript-eslint/scope-manager": "8.71.1",
"@typescript-eslint/type-utils": "8.71.1",
"@typescript-eslint/utils": "8.71.1",
"@typescript-eslint/visitor-keys": "8.71.1",
"@typescript-eslint/scope-manager": "8.70.1",
"@typescript-eslint/type-utils": "8.70.1",
"@typescript-eslint/utils": "8.70.1",
"@typescript-eslint/visitor-keys": "8.70.1",
"ignore": "^7.0.5",
"natural-compare": "^1.4.0",
"ts-api-utils": "^2.5.0"
@@ -2725,7 +2741,7 @@
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^8.71.1",
"@typescript-eslint/parser": "^8.70.1",
"eslint": "^8.57.0 || ^9.0.0 || ^10.0.0",
"typescript": ">=4.8.4 <6.1.0"
}
@@ -2741,16 +2757,16 @@
}
},
"node_modules/@typescript-eslint/parser": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.71.1.tgz",
"integrity": "sha512-oM/5sAqz/l1v/zYK1qTOPrn2+JIrBGC1V6uNYucRO5gh6eT9vWJ/RhPbGE59byvZEUQ4VP6XkLBaS5Jti5jpvw==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.70.1.tgz",
"integrity": "sha512-nO974WLllwhSFWQXnMLj6nDGa8f0khKEz1JzpPJ1u7Vm/4X1X6ZHajpoknU4bb41vJyMB0HHVyS2GqdhWfIXZw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/scope-manager": "8.71.1",
"@typescript-eslint/types": "8.71.1",
"@typescript-eslint/typescript-estree": "8.71.1",
"@typescript-eslint/visitor-keys": "8.71.1",
"@typescript-eslint/scope-manager": "8.70.1",
"@typescript-eslint/types": "8.70.1",
"@typescript-eslint/typescript-estree": "8.70.1",
"@typescript-eslint/visitor-keys": "8.70.1",
"debug": "^4.4.3"
},
"engines": {
@@ -2784,14 +2800,14 @@
}
},
"node_modules/@typescript-eslint/project-service": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.71.1.tgz",
"integrity": "sha512-Oijc9RUsohHjncg6iGi7gCtjnEjYt9FWv9u6ygK8uKcHK5eLjLAkqERQ9BaytbpceOFdk6kifPCS/zAZE+A99g==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.70.1.tgz",
"integrity": "sha512-62xOgboPfwc3/IgPSX/W6oQR3ZbF04194FPGUGH8HL8iLFHbt/456/8Ph1wLNUgVF+s94FlHoipBsz+v7+LMnA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/tsconfig-utils": "^8.71.1",
"@typescript-eslint/types": "^8.71.1",
"@typescript-eslint/tsconfig-utils": "^8.70.1",
"@typescript-eslint/types": "^8.70.1",
"debug": "^4.4.3"
},
"engines": {
@@ -2824,14 +2840,14 @@
}
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.71.1.tgz",
"integrity": "sha512-1YUDZXdTnXLlob03SFHBipdyMBsDVm7zoSz0ytTJ39dk5J1TgsTK03VlR/dLXG/RLLUrPcYbD4rp23BmHxHP0w==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.70.1.tgz",
"integrity": "sha512-Pa0EeSeAusQc1WbjQMac+YfenewYTBu0KjgYvkUKwhXaHUKbFog23Dm/rp0DX/6tyYOQ3Xl1a+3EcFNZynGHCw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.71.1",
"@typescript-eslint/visitor-keys": "8.71.1"
"@typescript-eslint/types": "8.70.1",
"@typescript-eslint/visitor-keys": "8.70.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -2842,9 +2858,9 @@
}
},
"node_modules/@typescript-eslint/tsconfig-utils": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.71.1.tgz",
"integrity": "sha512-oTvkml5SxXhgg+WWKhod5qWQICDXtOB+/Hi9VdPKFAANJ2b7YOgMffgvzXuqog7R6A/JtrzRf128dsxummyWhg==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.70.1.tgz",
"integrity": "sha512-jumze1fPI+sDOaM2TWGQdn39PDxTr7TZGeuyLkAbNyx2vtMT3uRnVKChN0hfht5V2TugphJzF6bYXvBcE09qqg==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2859,15 +2875,15 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.71.1.tgz",
"integrity": "sha512-kH3t3jZCYv2PZSBEWPKTariLrCaoF1CLoPitYFBJOhAGEwWnSRAtGEifrfrpBa4K9JlwWNZotgA5w3/wLSk/FQ==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.70.1.tgz",
"integrity": "sha512-7zKTnyvaVWqzLZHPFQtX1hVHqgkMC+WebPWakNCSyrQVbIP1AM0L0TlBZtACldIRb6PptI8Odk+jyZ5kP3B1VA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.71.1",
"@typescript-eslint/typescript-estree": "8.71.1",
"@typescript-eslint/utils": "8.71.1",
"@typescript-eslint/types": "8.70.1",
"@typescript-eslint/typescript-estree": "8.70.1",
"@typescript-eslint/utils": "8.70.1",
"debug": "^4.4.3",
"ts-api-utils": "^2.5.0"
},
@@ -2902,9 +2918,9 @@
}
},
"node_modules/@typescript-eslint/types": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.71.1.tgz",
"integrity": "sha512-ybYnPTUwg3VQQOFEiBPLs8Jxl1ry2vXdn1kVKguomBbvxpetdu3MKTNDqFNUrlG8ylP9MpZosmXMFYlGQHk1oQ==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.70.1.tgz",
"integrity": "sha512-Dm1ypdhhrGCTyyehxElhgJ6kgk8MVCv5qXdoOVqPr1uqk42jX8KjrZqhROvdShczA8qrDoYiOWn1ykWlx2k81Q==",
"dev": true,
"license": "MIT",
"engines": {
@@ -2916,16 +2932,16 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.71.1.tgz",
"integrity": "sha512-pSKSEK1JJpHs6KiKVtABCE4iJK5d7FLFzDXQNBQ2oRY7LEd3UwOt3TZemTgu9syTIf56dJWlTn/pdmrO9oKUXQ==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.70.1.tgz",
"integrity": "sha512-TU8PwyGN0PQJUcE96mw8eCQ44SmxGdQlJmlWakHaHQ15eIuuvye5yNtmh/i6oS88jzXVQB71xdNkbkB/fMwL0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/project-service": "8.71.1",
"@typescript-eslint/tsconfig-utils": "8.71.1",
"@typescript-eslint/types": "8.71.1",
"@typescript-eslint/visitor-keys": "8.71.1",
"@typescript-eslint/project-service": "8.70.1",
"@typescript-eslint/tsconfig-utils": "8.70.1",
"@typescript-eslint/types": "8.70.1",
"@typescript-eslint/visitor-keys": "8.70.1",
"debug": "^4.4.3",
"minimatch": "^10.2.2",
"semver": "^7.7.3",
@@ -3001,16 +3017,16 @@
}
},
"node_modules/@typescript-eslint/utils": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.1.tgz",
"integrity": "sha512-CBjT6gfAz3DW2j9Q4moFnqt208Aq+506sVGXfpRcyAeqn0EpayL0mjdWoCO2t3RC7GewNrFxdeehuEaPg6DMzQ==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.70.1.tgz",
"integrity": "sha512-Esgul8MsnKnRLdYU2Eb2cRV9bS5HJYtKj1ByJnOzzG2M58DGdSUQ1jUuILxipqcpB2h9WLrbD5GijIWUjX/Tqw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@eslint-community/eslint-utils": "^4.9.1",
"@typescript-eslint/scope-manager": "8.71.1",
"@typescript-eslint/types": "8.71.1",
"@typescript-eslint/typescript-estree": "8.71.1"
"@typescript-eslint/scope-manager": "8.70.1",
"@typescript-eslint/types": "8.70.1",
"@typescript-eslint/typescript-estree": "8.70.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -3025,13 +3041,13 @@
}
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.71.1.tgz",
"integrity": "sha512-0GxiUGqMU0qXJt58cBsiG3DP8lUmBaFo2vChtUX+CT7PnR3v/VGLLrzVP4K9r1lNiZXjHYefMBbPunplr09v6w==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.70.1.tgz",
"integrity": "sha512-Vwj9lUIW5Xq3wQ9w6gv3R86g1hMK8f2zNOdGTAgeXUMMXFK78G9ruCjjqutHMNJc0+CH7LYRnHeUB9IT8wFmcw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/types": "8.71.1",
"@typescript-eslint/types": "8.70.1",
"eslint-visitor-keys": "^5.0.0"
},
"engines": {
@@ -4233,7 +4249,7 @@
},
"node_modules/character-entities": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/character-entities/-/character-entities-2.0.2.tgz",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/character-entities/-/character-entities-2.0.2.tgz",
"integrity": "sha1-LQnC5yzZUjB2zLIRV9/2atQ/zCI=",
"license": "MIT",
"funding": {
@@ -4628,7 +4644,7 @@
},
"node_modules/decode-named-character-reference": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
"resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/decode-named-character-reference/-/decode-named-character-reference-1.3.0.tgz",
"integrity": "sha1-PkBgN2CHTC5YZ2kbWZ1zp9oltT8=",
"license": "MIT",
"dependencies": {
@@ -4684,7 +4700,7 @@
},
"node_modules/dequal": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/dequal/-/dequal-2.0.3.tgz",
"integrity": "sha1-JkQhTxmX057Q7g7OcjNUkKesZ74=",
"license": "MIT",
"engines": {
@@ -4703,7 +4719,7 @@
},
"node_modules/devlop": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/devlop/-/devlop-1.1.0.tgz",
"integrity": "sha1-TbfCyk3G4Og0wwvnDJS7yXbccBg=",
"license": "MIT",
"dependencies": {
@@ -5365,15 +5381,15 @@
}
},
"node_modules/eslint-plugin-jsdoc": {
"version": "65.2.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-65.2.0.tgz",
"integrity": "sha512-IMZaNwdDa5otUQYGWN1pzywZLsGKswitvFFNhcO8IOsBfaWpWIDXYuZh2sYhe9MNyKN9hz0YryOFaKdpbTP5Bw==",
"version": "64.5.4",
"resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-64.5.4.tgz",
"integrity": "sha512-xfRhXPSSWT612muJ6XTvxuVJ8zYHv99qNgBqPVqF28aSqoy4s4XbSkrWXnYA2hl5ejC02yEpk6fqkj3BmJ6Xbg==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"@es-joy/jsdoccomment": "~0.98.0",
"@es-joy/resolve.exports": "1.2.0",
"@typescript-eslint/utils": "^8.70.1",
"@typescript-eslint/utils": "^8.70.0",
"are-docs-informative": "^0.1.1",
"comment-parser": "1.4.9",
"debug": "^4.4.3",
@@ -5801,7 +5817,6 @@
},
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"dev": true,
"license": "MIT"
},
"node_modules/fast-diff": {
@@ -5992,9 +6007,9 @@
"license": "ISC"
},
"node_modules/follow-redirects": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.1.tgz",
"integrity": "sha512-FNvFGzoMLWmE6Yj9spb/zjd7yiNCHiAW9/Tg9CXrQ8wuu32HtlJOwWO11OJafl5FfY3DxTdQ0vj42zU1kvv5jg==",
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz",
"integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==",
"funding": [
{
"type": "individual",
@@ -6278,9 +6293,9 @@
}
},
"node_modules/globals": {
"version": "17.13.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz",
"integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==",
"version": "17.12.0",
"resolved": "https://registry.npmjs.org/globals/-/globals-17.12.0.tgz",
"integrity": "sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==",
"dev": true,
"license": "MIT",
"engines": {
@@ -7121,9 +7136,9 @@
}
},
"node_modules/js-yaml": {
"version": "5.4.3",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.3.tgz",
"integrity": "sha512-yzzNtgczwgoVHNigCyKTXcQJU4Y8t/ikU4UxXW0BvrLfHTGWZhsNcOT2s/a7vn81/4KqVnNmHjaUEPlvWnNwVw==",
"version": "5.4.2",
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.2.tgz",
"integrity": "sha512-m+aqu+LwO1O6sIopafj8HUVl5aawITwZQe/yHpMCKjaWBaA/d07B/QdMb3529REftiU+RMMHL3Vlsw3hON7vWg==",
"funding": [
{
"type": "github",
@@ -7479,9 +7494,9 @@
}
},
"node_modules/mdast-util-from-markdown": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.1.0.tgz",
"integrity": "sha512-KRLgmPaP2H1ul2bpoJkOS+9pAcDAAj9Nu1mqLnh8NLeJG5tlvj42TH80PIGBpROWlRXLk0lDrWNuZCFy/tsB4A==",
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/mdast-util-from-markdown/-/mdast-util-from-markdown-2.0.3.tgz",
"integrity": "sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==",
"license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
@@ -7504,7 +7519,7 @@
},
"node_modules/mdast-util-to-string": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/mdast-util-to-string/-/mdast-util-to-string-4.0.0.tgz",
"integrity": "sha1-elEhR1VWoE5+3etnsmSq550xKBQ=",
"license": "MIT",
"dependencies": {
@@ -7543,7 +7558,7 @@
},
"node_modules/micromark": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/micromark/-/micromark-4.0.2.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark/-/micromark-4.0.2.tgz",
"integrity": "sha1-kTlaPhiEoZjmIRbjPJxWjjmTb9s=",
"funding": [
{
@@ -7578,7 +7593,7 @@
},
"node_modules/micromark-core-commonmark": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-core-commonmark/-/micromark-core-commonmark-2.0.3.tgz",
"integrity": "sha1-xpFjDkhQIaaM8o28Kyyifr9njNQ=",
"funding": [
{
@@ -7612,7 +7627,7 @@
},
"node_modules/micromark-factory-destination": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-destination/-/micromark-factory-destination-2.0.1.tgz",
"integrity": "sha1-j++OD3CB8EdPvdkt61DJkKAmRjk=",
"funding": [
{
@@ -7633,7 +7648,7 @@
},
"node_modules/micromark-factory-label": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-label/-/micromark-factory-label-2.0.1.tgz",
"integrity": "sha1-UmfvqX8eUlTvx/ILRZo4yyEFi6E=",
"funding": [
{
@@ -7655,7 +7670,7 @@
},
"node_modules/micromark-factory-space": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-space/-/micromark-factory-space-2.0.1.tgz",
"integrity": "sha1-NtAhLpYrKzEh+FJfx6PHwCnzNPw=",
"funding": [
{
@@ -7675,7 +7690,7 @@
},
"node_modules/micromark-factory-title": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
"resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-title/-/micromark-factory-title-2.0.1.tgz",
"integrity": "sha1-I35KpdWKlYY/AQMtnumwkPHebpQ=",
"funding": [
{
@@ -7697,7 +7712,7 @@
},
"node_modules/micromark-factory-whitespace": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
"resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-factory-whitespace/-/micromark-factory-whitespace-2.0.1.tgz",
"integrity": "sha1-BrJrKYPE0nv8xlezPiUTTUhosLE=",
"funding": [
{
@@ -7719,7 +7734,7 @@
},
"node_modules/micromark-util-character": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-character/-/micromark-util-character-2.1.1.tgz",
"integrity": "sha1-L5h4MaQNTFEKwmHomFLE6XA8zaY=",
"funding": [
{
@@ -7739,7 +7754,7 @@
},
"node_modules/micromark-util-chunked": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
"resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-chunked/-/micromark-util-chunked-2.0.1.tgz",
"integrity": "sha1-R/vNk0caP8yrhs/wOEf8NVLbEFE=",
"funding": [
{
@@ -7758,7 +7773,7 @@
},
"node_modules/micromark-util-classify-character": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
"resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-classify-character/-/micromark-util-classify-character-2.0.1.tgz",
"integrity": "sha1-05n6+cRcoUyLS+mLHqSBvO2Htik=",
"funding": [
{
@@ -7779,7 +7794,7 @@
},
"node_modules/micromark-util-combine-extensions": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-combine-extensions/-/micromark-util-combine-extensions-2.0.1.tgz",
"integrity": "sha1-Kg9JCrCL/1zC/V7sbdDKBPibMKk=",
"funding": [
{
@@ -7799,7 +7814,7 @@
},
"node_modules/micromark-util-decode-numeric-character-reference": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-decode-numeric-character-reference/-/micromark-util-decode-numeric-character-reference-2.0.2.tgz",
"integrity": "sha1-/PFbZgl5OI5vEYzba/fXnXPSb+U=",
"funding": [
{
@@ -7818,7 +7833,7 @@
},
"node_modules/micromark-util-decode-string": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
"resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-decode-string/-/micromark-util-decode-string-2.0.1.tgz",
"integrity": "sha1-bLmVguXScehO/KjmGoB5lNcWHrI=",
"funding": [
{
@@ -7840,7 +7855,7 @@
},
"node_modules/micromark-util-encode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz",
"integrity": "sha1-DVHRwJVVHPqsNoMmljz1XxX1QLg=",
"funding": [
{
@@ -7856,7 +7871,7 @@
},
"node_modules/micromark-util-html-tag-name": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.1.tgz",
"integrity": "sha1-5AQDCWSBmGtBwQZif5j3LU0QuCU=",
"funding": [
{
@@ -7872,7 +7887,7 @@
},
"node_modules/micromark-util-normalize-identifier": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-normalize-identifier/-/micromark-util-normalize-identifier-2.0.1.tgz",
"integrity": "sha1-ww13sugyrPZSb4vxqke8nJQ4wW0=",
"funding": [
{
@@ -7891,7 +7906,7 @@
},
"node_modules/micromark-util-resolve-all": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-resolve-all/-/micromark-util-resolve-all-2.0.1.tgz",
"integrity": "sha1-4aLWLN0jcjCirhGDkCexk4HjHos=",
"funding": [
{
@@ -7910,7 +7925,7 @@
},
"node_modules/micromark-util-sanitize-uri": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
"resolved": "https://ms-feed-17.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz",
"integrity": "sha1-q4l4m4GKWHUrc9a1UjhiG3+qj9c=",
"funding": [
{
@@ -7931,7 +7946,7 @@
},
"node_modules/micromark-util-subtokenize": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-subtokenize/-/micromark-util-subtokenize-2.1.0.tgz",
"integrity": "sha1-2K3lug8xl6HPaimZ+7/mNXoaGe4=",
"funding": [
{
@@ -7953,7 +7968,7 @@
},
"node_modules/micromark-util-symbol": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
"resolved": "https://ms-feed-2.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz",
"integrity": "sha1-5dpJTo6ysHGg0I+zT2zv7GwKGbg=",
"funding": [
{
@@ -7969,7 +7984,7 @@
},
"node_modules/micromark-util-types": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
"resolved": "https://ms-feed-12.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/micromark-util-types/-/micromark-util-types-2.0.2.tgz",
"integrity": "sha1-8AIl9fWg68MlT5bDa2YFxLOTkI4=",
"funding": [
{
@@ -9981,16 +9996,16 @@
}
},
"node_modules/typescript-eslint": {
"version": "8.71.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.71.1.tgz",
"integrity": "sha512-oiNVPC3/NbV1FpaHU07l8O6ynqG9v4PAiW2WvTrAmZdR0f2HI/gE668ElMLCK7Xbsu5k2fK5C4fXNiq05j7/nQ==",
"version": "8.70.1",
"resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.70.1.tgz",
"integrity": "sha512-AcWG7KDjZ2THNXsgwttMaGmzVi0VFRlFYfqFHYQRbDpF3owuYbuiL8c7UUrd2k8s3PoSfIQrWfrGXfcElrWLYA==",
"dev": true,
"license": "MIT",
"dependencies": {
"@typescript-eslint/eslint-plugin": "8.71.1",
"@typescript-eslint/parser": "8.71.1",
"@typescript-eslint/typescript-estree": "8.71.1",
"@typescript-eslint/utils": "8.71.1"
"@typescript-eslint/eslint-plugin": "8.70.1",
"@typescript-eslint/parser": "8.70.1",
"@typescript-eslint/typescript-estree": "8.70.1",
"@typescript-eslint/utils": "8.70.1"
},
"engines": {
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
@@ -10024,9 +10039,9 @@
}
},
"node_modules/undici": {
"version": "6.28.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.28.0.tgz",
"integrity": "sha512-LIY910g9TI13YS95lrMFrs8Rm/u/irgHeTWoKCoteeJ04CUJ92eEfj0rVn+7VKMPBpUPiUoBKfhNyLI23EE/KA==",
"version": "6.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.29.0.tgz",
"integrity": "sha512-R+RODBqp6i2pPflGdq+xIOUkl+RNfGgHwoinecKu/JCuf2uO06cOKoDbI2P7Dn6KcswdKwrczbU6IYJ6K8X+wg==",
"license": "MIT",
"engines": {
"node": ">=18.17"
@@ -10054,7 +10069,7 @@
},
"node_modules/unist-util-stringify-position": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
"resolved": "https://ms-feed-25.pkgs.visualstudio.com/1es-public/_packaging/npm-public/npm/registry/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
"integrity": "sha1-RJxuIaiA4IVb9aq63rOnQDFKusI=",
"license": "MIT",
"dependencies": {
@@ -10485,34 +10500,17 @@
"@actions/core": "^2.0.3",
"@actions/github": "^8.0.1",
"@octokit/core": "^7.0.8",
"@octokit/plugin-paginate-rest": ">=16.0.0",
"@octokit/plugin-paginate-rest": ">=15.0.0",
"@octokit/plugin-rest-endpoint-methods": "^18.0.0",
"lite-matter": "^0.1.2",
"mdast-util-from-markdown": "^2.1.0",
"mdast-util-from-markdown": "^2.0.3",
"semver": "^7.8.5",
"yaml": "^2.9.1"
},
"devDependencies": {
"@types/node": "^24.19.0",
"@types/node": "^20.19.43",
"tsx": "^4.23.15"
}
},
"pr-checks/node_modules/@types/node": {
"version": "24.19.0",
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.0.tgz",
"integrity": "sha512-zY+5tKxXdhGh1PYI0ac+7juvEu4OI6vWtVVoj5i2m42jxAY1U+zHGt6QCyOFwykdP62sM3MJ9stoYYUw5aCWew==",
"dev": true,
"license": "MIT",
"dependencies": {
"undici-types": ">=7.24.0 <7.24.7"
}
},
"pr-checks/node_modules/undici-types": {
"version": "7.24.6",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz",
"integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==",
"dev": true,
"license": "MIT"
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "codeql",
"version": "4.39.1",
"version": "4.38.3",
"private": true,
"description": "CodeQL action",
"scripts": {
@@ -31,20 +31,21 @@
"@actions/io": "^2.0.0",
"@actions/tool-cache": "^3.0.1",
"@octokit/core": "^7.0.8",
"@octokit/plugin-paginate-rest": "^16.0.0",
"@octokit/plugin-paginate-rest": "^15.0.0",
"@octokit/plugin-rest-endpoint-methods": "^18.0.0",
"@octokit/plugin-retry": "^8.1.1",
"archiver": "^8.0.0",
"follow-redirects": "^1.16.1",
"fast-deep-equal": "^3.1.3",
"follow-redirects": "^1.16.0",
"get-folder-size": "^5.0.0",
"https-proxy-agent": "^7.0.6",
"js-yaml": "^5.4.3",
"js-yaml": "^5.4.2",
"jsonschema": "1.5.0",
"long": "^5.3.2",
"node-forge": "^1.4.0",
"semver": "^7.8.5",
"undici": "^6.28.0",
"uuid": "^14.0.2"
"uuid": "^14.0.2",
"undici": "^6.29.0"
},
"devDependencies": {
"@ava/typescript": "6.0.0",
@@ -65,14 +66,14 @@
"eslint-import-resolver-typescript": "^4.4.5",
"eslint-plugin-github": "^6.1.2",
"eslint-plugin-import-x": "^4.17.1",
"eslint-plugin-jsdoc": "^65.2.0",
"eslint-plugin-jsdoc": "^64.5.4",
"eslint-plugin-no-async-foreach": "^0.1.1",
"glob": "^13.0.6",
"globals": "^17.13.0",
"globals": "^17.12.0",
"nock": "^14.0.17",
"sinon": "^22.1.0",
"typescript": "^6.0.3",
"typescript-eslint": "^8.71.1"
"typescript-eslint": "^8.70.1"
},
"overrides": {
"@actions/tool-cache": {
@@ -94,6 +95,6 @@
"semver": ">=6.3.1"
},
"glob": "^13.0.6",
"undici": "^6.28.0"
"undici": "^6.29.0"
}
}

View File

@@ -1 +0,0 @@
24

View File

@@ -122,6 +122,6 @@ function main() {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
process.exit(main());
}

View File

@@ -43,6 +43,6 @@ async function main() {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
void main();
}

View File

@@ -1,4 +1,5 @@
import * as fs from "node:fs";
import * as path from "node:path";
import { matter } from "lite-matter";
import type { List, ListItem } from "mdast";
@@ -94,7 +95,21 @@ export function isValidChangenoteFile(filename: string): boolean {
return false;
}
const { content } = matter(fileData);
const { data: frontmatter, content } = matter(fileData);
if (!isValidChangenoteFilename(path.basename(filename))) {
isValid = false;
console.error(
`${filename}: invalid filename; must match pattern YYYY-MM-DD-id.md`,
);
}
if (!hasValidChangenoteCategory(frontmatter)) {
isValid = false;
const categories = Object.keys(VALID_CHANGE_NOTE_CATEGORIES).join(", ");
console.error(
`${filename}: invalid category; must be one of: ${categories}`,
);
}
if (!isValidChangenoteContent(content)) {
isValid = false;
console.error(

View File

@@ -9,7 +9,7 @@ import {
isValidChangenoteFile,
isValidChangenoteFilename,
VALID_CHANGE_NOTE_CATEGORIES,
} from "./validate";
} from "./validate.mjs";
await describe("isValidChangenoteContent", async () => {
await it("recognizes an unordered Markdown list", () => {
@@ -154,6 +154,26 @@ await describe("isValidChangenoteFile", async () => {
assert.equal(isValidChangenoteFile("non-existent-file.md"), false);
});
await it("rejects invalid filename", async () => {
await withTmpFile(
"fix-bug.md",
"---\ncategory: fix\n---\n- Fixed a bug\n",
(filePath) => {
assert.equal(isValidChangenoteFile(filePath), false);
},
);
});
await it("rejects missing frontmatter", async () => {
await withTmpFile(
"2026-01-01-fix-bug.md",
"- Fixed a bug\n",
(filePath) => {
assert.equal(isValidChangenoteFile(filePath), false);
},
);
});
await it("rejects invalid Markdown", async () => {
await withTmpFile(
"2026-01-01-fix-bug.md",

View File

@@ -14,7 +14,7 @@ import {
renderChangelog,
withChangelog,
} from "./changelog";
import { isValidChangenoteFile } from "./changelog/validate";
import { isValidChangenoteFile } from "./changelog/validate.mjs";
import { CHANGENOTES_DIR } from "./config";
/**
@@ -28,12 +28,12 @@ interface ChangenoteFile {
/**
* Returns the absolute file paths of all files in
* {@link CHANGENOTES_DIR} (except ".gitkeep" and "README.md").
* {@link CHANGENOTES_DIR} (except ".gitkeep").
* */
function listUnreleasedChangenoteDir(): string[] {
return fs
.readdirSync(CHANGENOTES_DIR)
.filter((name) => ![".gitkeep", "README.md"].includes(name))
.filter((name) => name !== ".gitkeep")
.map((name) => path.join(CHANGENOTES_DIR, name));
}
@@ -50,28 +50,6 @@ function getChangenotes(): ChangenoteFile[] {
});
}
/**
* Populates the '[UNRELEASED]' section of CHANGELOG.md with the contents
* of the changenotes in {@link CHANGENOTES_DIR} and then deletes those changenotes.
* @param contents The contents of CHANGELOG.md
* @returns The updated contents of CHANGELOG.md
*/
export function transferChangenotesToChangelog(contents: string): string {
const changenotes = getChangenotes();
const changenoteBodies = changenotes.map((c) => c.content.trim());
const changenotePaths = changenotes.map((c) => c.absolutePath);
const changelog = parseChangelog(contents);
addBodyLinesToUnreleasedSection(changelog, changenoteBodies);
const updatedChangelog = renderChangelog(changelog);
for (const p of changenotePaths) {
fs.unlinkSync(p);
}
return updatedChangelog;
}
const entryPoint = process.argv[1];
if (entryPoint && import.meta.url === pathToFileURL(entryPoint).href) {
try {
@@ -104,22 +82,35 @@ function main(): ExitCode {
function usage(): ExitCode {
const message =
"Usage: changenotes.ts assemble\n" +
" changenotes.ts validate\n" +
" changenotes.ts help";
"Usage: changenotes.mts assemble\n" +
" changenotes.mts validate\n" +
" changenotes.mts help";
console.log(message);
return ExitCode.Success;
}
function assemble(): ExitCode {
try {
const changenotes = getChangenotes();
const changenoteBodies = changenotes.map((c) => c.content);
const changenotePaths = changenotes.map((c) => c.absolutePath);
withChangelog((contents) => {
return transferChangenotesToChangelog(contents);
const changelog = parseChangelog(contents);
addBodyLinesToUnreleasedSection(changelog, changenoteBodies);
return renderChangelog(changelog);
}, {});
// Delete changenotes only after successful processing.
for (const p of changenotePaths) {
fs.unlinkSync(p);
}
return ExitCode.Success;
} catch (e) {
console.error("Failed to assemble changenotes to 'CHANGELOG.md'", e);
}
return ExitCode.Failure;
}

View File

@@ -218,6 +218,6 @@ async function run(): Promise<void> {
}
}
if (import.meta.main) {
if (require.main === module) {
void run();
}

View File

@@ -46,7 +46,7 @@ steps:
post-processed-sarif-path: "${{ runner.temp }}/post-processed"
- name: Upload SARIF files
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: |
analysis-kinds-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}
@@ -54,7 +54,7 @@ steps:
retention-days: 7
- name: Upload post-processed SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: |
post-processed-${{ matrix.os }}-${{ matrix.version }}-${{ matrix.analysis-kinds }}

View File

@@ -14,7 +14,7 @@ steps:
output: "${{ runner.temp }}/results"
upload-database: false
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: config-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: "${{ runner.temp }}/results/javascript.sarif"

View File

@@ -27,7 +27,7 @@ steps:
output: "${{ runner.temp }}/results"
upload-database: false
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: diagnostics-export-${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: "${{ runner.temp }}/results/javascript.sarif"

View File

@@ -11,10 +11,6 @@ installDotNet: true
env:
CODEQL_ACTION_SKIP_FILE_COVERAGE_ON_PRS: false
CODEQL_ACTION_SUBLANGUAGE_FILE_COVERAGE: true
# To balance speed and coverage, we analyze only a single language (JavaScript), but use the
# combined bundle so we can test that baseline information is reported for each language in the
# multi-language source directory.
CODEQL_ACTION_PER_LANGUAGE_BUNDLES: false
steps:
- uses: ./../action/init
id: init
@@ -27,7 +23,7 @@ steps:
with:
output: "${{ runner.temp }}/results"
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: with-baseline-information-${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: "${{ runner.temp }}/results/javascript.sarif"

View File

@@ -12,7 +12,7 @@ steps:
with:
output: "${{ runner.temp }}/results"
- name: Upload SARIF
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: ${{ matrix.os }}-${{ matrix.version }}.sarif.json
path: "${{ runner.temp }}/results/javascript.sarif"

View File

@@ -10,22 +10,23 @@ operatingSystems:
- os: macos
runner-image: macos-15-xlarge
codeql-versions:
- stable-v2.19.4
- stable-v2.20.7
- stable-v2.21.4
- stable-v2.22.4
env:
CODEQL_ACTION_CLEANUP_TOOLCACHE_BUNDLES: true
CODEQL_ACTION_RESOLVE_SUPPORTED_LANGUAGES_USING_CLI: true
installGo: true
installDotNet: true
steps:
- name: Install Python 3.13.15 for older CLI versions
# Older CLI versions don't work with Python 3.13.16 or newer because their Python extractor
# imports `importlib._bootstrap._ERR_MSG`, which those Python versions no longer define.
- name: Install Python 3.13 for older CLI versions
# We need Python 3.13 for older CLI versions because they are not compatible with Python 3.14 or newer.
# See https://github.com/github/codeql-action/pull/3212
if: matrix.version != 'nightly-latest' && matrix.version != 'linked'
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
with:
python-version: "3.13.15"
python-version: "3.13"
- name: Use Xcode 16
# Only the older CodeQL CLI versions need Xcode 16, and these run on macOS 15.

View File

@@ -5,7 +5,7 @@ versions:
- default
steps:
- name: Set up Ruby
uses: ruby/setup-ruby@14594264cd68ce8a2345dd349bc3d138a4ef85c8 # v1.327.0
uses: ruby/setup-ruby@762794c140bbeda0f1224786aa33b4b46783a6c1 # v1.326.0
with:
ruby-version: 2.6
- name: Install Code Scanning integration

View File

@@ -1,8 +1,8 @@
name: "Rust analysis"
description: "Tests creation of a Rust database"
versions:
# oldest CodeQL version supported by the Action, where Rust support is experimental and requires the Action to set `CODEQL_ENABLE_EXPERIMENTAL_FEATURES`
- stable-v2.20.7
# experimental rust support introduced, requires action to set `CODEQL_ENABLE_EXPERIMENTAL_FEATURES`
- stable-v2.19.4
# first public preview version
- stable-v2.22.1
- linked

View File

@@ -1,9 +1,4 @@
import path from "path";
import { fileURLToPath } from "url";
// For backwards-compatibility.
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
/** The oldest supported major version of the CodeQL Action. */
export const OLDEST_SUPPORTED_MAJOR_VERSION = 3;

View File

@@ -5,8 +5,6 @@ contains:
- "test-setup-python-scripts"
- "update"
- "Update"
# Matrix-ed job; the name starts with this
- "Create backport"
is:
- "Agent"
- "check-expected-release-files"
@@ -17,6 +15,4 @@ is:
- "Label PR with size"
- "Post repo size comment"
- "Prepare"
- "Release info"
- "Upload results"
- "Update release branch"

View File

@@ -1,20 +1,19 @@
{
"private": true,
"description": "Dependencies for codeql-action scripts",
"type": "module",
"dependencies": {
"@actions/core": "^2.0.3",
"@actions/github": "^8.0.1",
"@octokit/core": "^7.0.8",
"@octokit/plugin-paginate-rest": ">=16.0.0",
"@octokit/plugin-paginate-rest": ">=15.0.0",
"@octokit/plugin-rest-endpoint-methods": "^18.0.0",
"lite-matter": "^0.1.2",
"mdast-util-from-markdown": "^2.1.0",
"mdast-util-from-markdown": "^2.0.3",
"semver": "^7.8.5",
"yaml": "^2.9.1"
},
"devDependencies": {
"@types/node": "^24.19.0",
"@types/node": "^20.19.43",
"tsx": "^4.23.15"
}
}

View File

@@ -77,6 +77,6 @@ function main() {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
process.exit(main());
}

View File

@@ -116,6 +116,6 @@ async function main() {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
void main();
}

View File

@@ -79,6 +79,6 @@ function main() {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
process.exit(main());
}

View File

@@ -21,11 +21,10 @@ import * as fs from "fs";
import { parseArgs } from "node:util";
import * as path from "path";
import { PR_CHECKS_DIR, REPO_ROOT } from "./config";
const CHECKS_DIR = path.join(PR_CHECKS_DIR, "checks");
const WORKFLOW_DIR = path.join(REPO_ROOT, ".github", "workflows");
const SYNC_TS_PATH = path.join(PR_CHECKS_DIR, "sync.ts");
const THIS_DIR = __dirname;
const CHECKS_DIR = path.join(THIS_DIR, "checks");
const WORKFLOW_DIR = path.join(THIS_DIR, "..", ".github", "workflows");
const SYNC_TS_PATH = path.join(THIS_DIR, "sync.ts");
/**
* Scan generated workflow files to extract the latest action versions.
@@ -233,6 +232,6 @@ function main(): number {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
process.exit(main());
}

View File

@@ -342,6 +342,6 @@ async function main(): Promise<void> {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
void main();
}

View File

@@ -7,8 +7,6 @@ import * as yaml from "yaml";
import { BuiltInLanguage } from "../src/languages";
import { PR_CHECKS_DIR, REPO_ROOT } from "./config";
/**
* Returns a `uses` value for `action` pinned to a commit SHA, with the
* human-readable version recorded in a trailing comment.
@@ -136,6 +134,8 @@ type LanguageSetups = Partial<Record<BuiltInLanguage, LanguageSetup>>;
// The default set of CodeQL Bundle versions to use for the PR checks.
const defaultTestVersions = [
// The oldest supported CodeQL version. If bumping, update `CODEQL_MINIMUM_VERSION` in `codeql.ts`
"stable-v2.19.4",
// The last CodeQL release in the 2.20 series.
"stable-v2.20.7",
// The last CodeQL release in the 2.21 series.
"stable-v2.21.4",
@@ -145,8 +145,6 @@ const defaultTestVersions = [
"stable-v2.23.9",
// The last CodeQL release in the 2.24 series.
"stable-v2.24.3",
// The last CodeQL release in the 2.25 series.
"stable-v2.25.6",
// The default version of CodeQL for Dotcom, as determined by feature flags.
"default",
// The version of CodeQL shipped with the Action in `defaults.json`. During the release process
@@ -215,20 +213,14 @@ const languageSetups: LanguageSetups = {
name: "Install Node.js",
uses: pinnedUses(
"actions/setup-node",
"949feb2413d6458794dcd2491c4babbbce0c15c1",
"v7.1.0",
"820762786026740c76f36085b0efc47a31fe5020",
"v7.0.0",
),
with: {
"node-version": defaultLanguageVersions.javascript,
cache: "npm",
},
},
// Install a new enough version of `npm` to understand `min-release-age`
// that is still compatible with Node 20.
{
name: "Install newer npm",
run: "npm install -g npm@11.19.1",
},
{
name: "Install dependencies",
run: "npm ci",
@@ -314,8 +306,9 @@ const languageSetups: LanguageSetups = {
// See https://github.com/github/codeql-action/pull/3423
const YQ_VERSION = "v4.50.1";
const CHECKS_DIR = path.join(PR_CHECKS_DIR, "checks");
const OUTPUT_DIR = path.join(REPO_ROOT, ".github", "workflows");
const THIS_DIR = __dirname;
const CHECKS_DIR = path.join(THIS_DIR, "checks");
const OUTPUT_DIR = path.join(THIS_DIR, "..", ".github", "workflows");
/**
* Loads and parses a YAML file.

View File

@@ -8,6 +8,6 @@
"sourceMap": false,
"noEmit": true
},
"include": ["./**/*.ts", "../src/**/*.ts"],
"include": ["./**/*.ts", "./**/*.mts", "../src/**/*.ts"],
"exclude": ["node_modules"]
}

View File

@@ -238,6 +238,6 @@ function main() {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
main();
}

View File

@@ -23,13 +23,7 @@ import { parseArgs } from "node:util";
import { type ApiClient, getApiClient } from "./api-client";
import * as changelog from "./changelog";
import { transferChangenotesToChangelog } from "./changenotes";
import {
CHANGELOG_FILE,
CHANGENOTES_DIR,
DryRunOption,
REPO_ROOT,
} from "./config";
import { DryRunOption, REPO_ROOT } from "./config";
import {
getCurrentVersion,
replaceVersionInPackageJson,
@@ -699,14 +693,11 @@ export async function prepareNewBranch(
console.log("Updating changelog");
changelog.withChangelog(
(contents) => {
const populatedContents = transferChangenotesToChangelog(contents);
return changelog.setVersionAndDate(version, populatedContents);
},
(contents) => changelog.setVersionAndDate(version, contents),
{ ...options, initChangelog: true },
);
runGit(["add", CHANGELOG_FILE, CHANGENOTES_DIR], {
runGit(["add", "CHANGELOG.md"], {
dryRun: options.dryRun,
});
runGit(["commit", "-m", `Update changelog for v${version}`], {
@@ -844,6 +835,6 @@ async function main(): Promise<void> {
}
// Only call `main` if this script was run directly.
if (import.meta.main) {
if (require.main === module) {
void main();
}

View File

@@ -23,8 +23,7 @@ predicate isSafeForDefaultSetup(string envVar) {
"GITHUB_BASE_REF", "GITHUB_EVENT_NAME", "GITHUB_JOB", "GITHUB_RUN_ATTEMPT", "GITHUB_RUN_ID",
"GITHUB_SHA", "GITHUB_REPOSITORY", "GITHUB_SERVER_URL", "GITHUB_TOKEN", "GITHUB_WORKFLOW",
"GITHUB_WORKSPACE", "GOFLAGS", "ImageVersion", "JAVA_TOOL_OPTIONS", "RUNNER_ARCH",
"RUNNER_ENVIRONMENT", "RUNNER_NAME", "RUNNER_OS", "RUNNER_TEMP", "RUNNER_TOOL_CACHE",
"NODE_ENV"
"RUNNER_ENVIRONMENT", "RUNNER_NAME", "RUNNER_OS", "RUNNER_TEMP", "RUNNER_TOOL_CACHE"
]
}

View File

@@ -21,16 +21,19 @@ inputs:
required: false
languages:
description: >-
A comma-separated list of CodeQL languages that the installed CodeQL CLI will be used to
analyze. If specified, the Action may use this list to select a CodeQL CLI version that is
best suited to analyzing those languages, for example by preferring a version that has a
cached overlay-base database for the specified languages.
A comma-separated list of CodeQL languages that will be analyzed in subsequent
`github/codeql-action/init` and `github/codeql-action/analyze` invocations. If specified, the
Action may use this list to select a CodeQL CLI version that is best suited to analyzing those
languages, for example by preferring a version that has a cached overlay-base database for the
specified languages. This input is not remembered and must also be passed to
`github/codeql-action/init`.
required: false
analysis-kinds:
description: >-
[Internal] A comma-separated list of analysis kinds that the installed CodeQL CLI will be used
for. If specified, the Action may use this list to select a CodeQL CLI version that is best
suited to those analysis kinds.
[Internal] A comma-separated list of analysis kinds that subsequent
`github/codeql-action/init` invocations will enable. If specified, the Action may use this
list to select a CodeQL CLI version that is best suited to those analysis kinds. This input is
not remembered and must also be passed to `github/codeql-action/init`.
Available options are the same as for the `analysis-kinds` input on the `init` Action.
default: 'code-scanning'

View File

@@ -19,24 +19,6 @@ import { getErrorMessage } from "./util";
setupTests(test);
for (const [key, displayName] of Object.entries(
statusReport.ACTION_DISPLAY_NAMES,
)) {
test(`getDisplayActionName - '${displayName}' instead of '${key}'`, (t) => {
t.is(statusReport.getDisplayActionName(key as ActionName), displayName);
});
}
test("getDisplayActionName - returns action name", (t) => {
for (const actionName of Object.values(ActionName)) {
if (statusReport.ACTION_DISPLAY_NAMES[actionName]) {
continue;
}
t.is(statusReport.getDisplayActionName(actionName), actionName);
}
});
interface RunInActionsTestOpts {
runFn?: () => Promise<any>;
expectedErrorMessage?: string;

View File

@@ -56,29 +56,6 @@ export interface FeatureState {
/** Identifies a type of state an Action may have. */
export type StateFeature = keyof FeatureState;
/**
* The `Env` feature implies the availability of the `ReadOnlyEnv` feature.
*
* If `T` is `Env`, this returns `Env | ReadOnlyEnv`.
* Otherwise, it is the identity and returns T.
*/
type ImpliedFeatures<T extends StateFeature> = T extends "Env"
? "Env" | "ReadOnlyEnv"
: T;
/**
* Given an object type `Obj`, this tries to lookup a corresponding `StateFeature`
* to which the object type belongs in `FeatureState`. Resolves to `never` if there
* is no match.
*/
type FeatureNameFor<Obj extends object> = {
[K in StateFeature]: [Obj] extends [FeatureState[K]]
? [FeatureState[K]] extends [Obj]
? K
: never
: never;
}[StateFeature];
/** Constructs the intersection of all state types identifies by `Fs`. */
export type FieldsOf<Fs extends readonly StateFeature[]> = Fs extends []
? Record<never, never>
@@ -89,54 +66,8 @@ export type FieldsOf<Fs extends readonly StateFeature[]> = Fs extends []
? FeatureState[Head] & FieldsOf<Tail>
: never;
/**
* Symbol used for a field in `ActionState` that carries the type array of state features.
* This is a Symbol so that it doesn't clash with any property names we might want to have.
*/
const stateFeatures = Symbol();
/** Describes the state of an Action that has access to the state corresponding to `Fs`. */
export type ActionState<Fs extends readonly StateFeature[]> = FieldsOf<Fs> & {
/**
* When given a chance, TypeScript will simplify an `ActionState<Fs>` type as much as possible,
* which results in a concrete object type that doesn't mention `Fs`.
*
* That causes problems for functions which accept `ActionState<Fs>` values, but need to know the
* feature keys `Fs`. This property here explicitly captures `Fs` in the concrete object type
* that results from simplifying `ActionState<Fs>`.
*
* This is a function rather than a field, because we want to be able to provide values of type
* `ActionState<Fs>` to functions expecting `ActionState<As>` where `As` is a subset of `Fs`.
*
* Since function types are contravariant in the types of their parameters, using a function
* type here allows that to happen.
*
* Because the field is optional, we don't have to explicitly provide a value
* for it anywhere while the type is still inferred.
*
* `Fs[number]` returns the union of all features in `Fs`. We wrap it in `ImpliedFeatures`
* so that `Env` is expanded into `Env | ReadOnlyEnv`, allowing functions that expect the
* `ReadOnlyEnv` feature to be provided with an `ActionState` that has the `Env` feature
* without requiring this to be made explicit.
*/
readonly [stateFeatures]?: (ts: ImpliedFeatures<Fs[number]>) => void;
};
/** Extends `state` with an `extra` feature. */
export function extendActionState<
// In first position, so that it can be explicitly provided if `FeatureNameFor`
// should not work on `extra`.
F extends StateFeature,
Fs extends readonly StateFeature[],
E extends FeatureState[F],
>(
state: ActionState<Fs>,
extra: E,
): ActionState<[...Fs, FeatureNameFor<E> & F]> {
return { ...state, ...extra } as unknown as ActionState<
[...Fs, FeatureNameFor<E> & F]
>;
}
export type ActionState<Fs extends readonly StateFeature[]> = FieldsOf<Fs>;
/** The type of an Action's main entry point. This is a function that is provided
* with a basic `ActionState` object with features that are always available.

View File

@@ -7,13 +7,12 @@ import {
isAnalyzingPullRequest,
isDefaultSetup,
isDynamicWorkflow,
printDebugLogs,
} from "./actions-util";
import { computeAutomationID } from "./api-client";
import { EnvVar } from "./environment";
import { getRunnerLogger } from "./logging";
import { getTestEnv, RecordingLogger, setupTests } from "./testing-utils";
import { withTmpDir } from "./util";
import { setupTests } from "./testing-utils";
import { initializeEnvironment } from "./util";
setupTests(test);
@@ -101,21 +100,6 @@ test("computeAutomationID()", async (t) => {
);
});
test("printDebugLogs - doesn't throw when config doesn't have needed properties", async (t) => {
const logger = new RecordingLogger();
await t.notThrowsAsync(printDebugLogs(logger, {}));
await t.notThrowsAsync(printDebugLogs(logger, { languages: [] }));
await t.notThrowsAsync(printDebugLogs(logger, { dbLocation: "nowhere" }));
});
test("printDebugLogs - doesn't throw when language db doesn't exist", async (t) =>
withTmpDir(async (tmpDir) => {
const logger = new RecordingLogger();
await t.notThrowsAsync(
printDebugLogs(logger, { dbLocation: tmpDir, languages: ["javascript"] }),
);
}));
test.serial("getPullRequestBranches() with pull request context", (t) => {
withMockedContext(
{
@@ -228,9 +212,8 @@ test.serial(
);
test.serial("initializeEnvironment", (t) => {
const env = getTestEnv();
env.initialise("1.2.3");
t.deepEqual(env.getOptional(EnvVar.VERSION), "1.2.3");
initializeEnvironment("1.2.3");
t.deepEqual(process.env[EnvVar.VERSION], "1.2.3");
});
test.serial("fixCodeQualityCategory", (t) => {

View File

@@ -6,7 +6,7 @@ import * as toolrunner from "@actions/exec/lib/toolrunner";
import * as github from "@actions/github";
import * as io from "@actions/io";
import { hasConfigKey, type Config } from "./config/action-config";
import type { Config } from "./config-utils";
import { Env, EnvVar, ActionsEnvVars, ReadOnlyEnv } from "./environment";
import { Logger } from "./logging";
import {
@@ -30,6 +30,7 @@ declare const __CODEQL_ACTION_VERSION__: string;
export interface ActionsEnv {
getRequiredInput: (name: string) => string;
getOptionalInput: (name: string) => string | undefined;
exportVariable: (name: string, value: string) => void;
}
/**
@@ -39,6 +40,7 @@ export function getActionsEnv(): ActionsEnv {
return {
getRequiredInput,
getOptionalInput,
exportVariable: core.exportVariable,
};
}
@@ -93,7 +95,7 @@ export function getActionVersion(): string {
*
* This will be "dynamic" for default setup workflow runs.
*/
export function getWorkflowEventName(env: ReadOnlyEnv = getEnv()) {
export function getWorkflowEventName(env: Env = getEnv()) {
return env.getRequired(ActionsEnvVars.GITHUB_EVENT_NAME);
}
@@ -101,7 +103,7 @@ export function getWorkflowEventName(env: ReadOnlyEnv = getEnv()) {
* Returns whether the current workflow is executing a local copy of the Action, e.g. we're running
* a workflow on the codeql-action repo itself.
*/
export function isRunningLocalAction(env: ReadOnlyEnv = getEnv()): boolean {
export function isRunningLocalAction(env: Env = getEnv()): boolean {
const relativeScriptPath = getRelativeScriptPath(env);
return (
relativeScriptPath.startsWith("..") || path.isAbsolute(relativeScriptPath)
@@ -113,14 +115,14 @@ export function isRunningLocalAction(env: ReadOnlyEnv = getEnv()): boolean {
*
* This can be used to get the Action's name or tell if we're running a local Action.
*/
function getRelativeScriptPath(env: ReadOnlyEnv): string {
function getRelativeScriptPath(env: Env): string {
const runnerTemp = env.getRequired(ActionsEnvVars.RUNNER_TEMP);
const actionsDirectory = path.join(path.dirname(runnerTemp), "_actions");
return path.relative(actionsDirectory, __filename);
}
/** Returns the contents of `GITHUB_EVENT_PATH` as a JSON object. */
export function getWorkflowEvent(env: ReadOnlyEnv = getEnv()): any {
export function getWorkflowEvent(env: Env = getEnv()): any {
const eventJsonFile = env.getRequired(ActionsEnvVars.GITHUB_EVENT_PATH);
try {
return JSON.parse(fs.readFileSync(eventJsonFile, "utf-8"));
@@ -131,38 +133,28 @@ export function getWorkflowEvent(env: ReadOnlyEnv = getEnv()): any {
}
}
export async function printDebugLogs(logger: Logger, config: Partial<Config>) {
if (
!hasConfigKey(config, "languages") ||
!hasConfigKey(config, "dbLocation")
) {
logger.debug(
`Not printing debug logs, because the configuration does not include the 'languages' or 'dbLocation' fields.`,
);
return;
}
export async function printDebugLogs(config: Config) {
for (const language of config.languages) {
const databaseDirectory = getCodeQLDatabasePath(config, language);
const logsDirectory = path.join(databaseDirectory, "log");
if (!doesDirectoryExist(logsDirectory)) {
logger.info(`Directory ${logsDirectory} does not exist.`);
core.info(`Directory ${logsDirectory} does not exist.`);
continue; // Skip this language database.
}
const walkLogFiles = (dir: string) => {
const entries = fs.readdirSync(dir, { withFileTypes: true });
if (entries.length === 0) {
logger.info(`No debug logs found at directory ${logsDirectory}.`);
core.info(`No debug logs found at directory ${logsDirectory}.`);
}
for (const entry of entries) {
if (entry.isFile()) {
const absolutePath = path.resolve(dir, entry.name);
logger.startGroup(
core.startGroup(
`CodeQL Debug Logs - ${language} - ${entry.name} from file at path ${absolutePath}`,
);
logger.info(fs.readFileSync(absolutePath, "utf-8"));
logger.endGroup();
process.stdout.write(fs.readFileSync(absolutePath));
core.endGroup();
} else if (entry.isDirectory()) {
walkLogFiles(path.resolve(dir, entry.name));
}

View File

@@ -9,6 +9,7 @@ import * as core from "@actions/core";
import * as actionsUtil from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { getCodeQL } from "./codeql";
import { getConfig } from "./config-utils";
import * as debugArtifacts from "./debug-artifacts";
import {
@@ -37,9 +38,12 @@ export async function runWrapper() {
logger,
);
if (config !== undefined) {
const codeql = await getCodeQL(logger, config.codeQLCmd);
const version = await codeql.getVersion();
await debugArtifacts.uploadCombinedSarifArtifacts(
logger,
config.gitHubVersion.type,
version.version,
);
}
}

View File

@@ -45,7 +45,6 @@ test.serial(
requiredInputStub.withArgs("token").returns("fake-token");
requiredInputStub.withArgs("upload-database").returns("false");
requiredInputStub.withArgs("output").returns("out");
requiredInputStub.withArgs("checkout_path").returns("");
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
optionalInputStub.withArgs("expect-error").returns("false");
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);
@@ -105,7 +104,6 @@ test.serial(
requiredInputStub.withArgs("token").returns("fake-token");
requiredInputStub.withArgs("upload-database").returns("false");
requiredInputStub.withArgs("output").returns("out");
requiredInputStub.withArgs("checkout_path").returns("");
const optionalInputStub = sinon.stub(actionsUtil, "getOptionalInput");
optionalInputStub.withArgs("expect-error").returns("false");
sinon.stub(api, "getGitHubVersion").resolves(gitHubVersion);

View File

@@ -4,18 +4,12 @@ import { performance } from "perf_hooks";
import * as core from "@actions/core";
import {
Action,
ActionState,
extendActionState,
runInActions,
} from "./action-common";
import { Action, ActionState, runInActions } from "./action-common";
import * as actionsUtil from "./actions-util";
import * as analyses from "./analyses";
import {
CodeQLAnalysisError,
dbIsFinalized,
determineCheckoutPath,
QueriesStatusReport,
runFinalize,
runQueries,
@@ -218,11 +212,13 @@ async function runAutobuildIfLegacyGoWorkflow(config: Config, logger: Logger) {
await runAutobuild(config, BuiltInLanguage.go, logger);
}
async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
async function run({
startedAt,
logger,
actions,
}: ActionState<["Base", "Logger", "Actions"]>) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
const startedAt = action.startedAt;
const logger = action.logger;
let uploadResults:
| Partial<Record<analyses.AnalysisKind, UploadResult>>
@@ -238,7 +234,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
let databaseUploadResults: DatabaseUploadResult[] = [];
try {
action.env.initialise(actionsUtil.getActionVersion());
util.initializeEnvironment(actionsUtil.getActionVersion());
// Make inputs accessible in the `post` step, details at
// https://github.com/github/codeql-action/issues/2553
@@ -271,6 +267,17 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
);
}
// Unset the CODEQL_PROXY_* environment variables when using older CodeQL
// CLIs, as they are not needed and can cause issues.
if (
process.env.CODEQL_PROXY_HOST === "" &&
!(await util.codeQlVersionAtLeast(codeql, "2.20.7"))
) {
delete process.env.CODEQL_PROXY_HOST;
delete process.env.CODEQL_PROXY_PORT;
delete process.env.CODEQL_PROXY_CA_CERTIFICATE;
}
if (actionsUtil.getOptionalInput("cleanup-level")) {
logger.info(
"The 'cleanup-level' input is ignored since the CodeQL Action now automatically " +
@@ -280,7 +287,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
const apiDetails = getApiDetails();
const outputDir = actionsUtil.getRequiredInput("output");
action.env.export(EnvVar.SARIF_RESULTS_OUTPUT_DIR, outputDir);
core.exportVariable(EnvVar.SARIF_RESULTS_OUTPUT_DIR, outputDir);
const threads = util.getThreadsFlag(
actionsUtil.getOptionalInput("threads") || process.env["CODEQL_THREADS"],
logger,
@@ -304,7 +311,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
logger,
);
const checkoutPath = await determineCheckoutPath(action, config);
const checkoutPath = actions.getRequiredInput("checkout_path");
// Setup diff informed analysis if needed (based on whether init created the file)
const diffRangePackDir = await setupDiffInformedQueryRun(
@@ -396,13 +403,11 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
checkoutPath,
);
const actionWithFeatures = extendActionState(action, { features });
// Possibly upload the database bundles for remote queries.
// Note: Take care with the ordering of this call since databases may be cleaned up
// at the `overlay` or `clear` level.
databaseUploadResults = await cleanupAndUploadDatabases(
actionWithFeatures,
{ logger, features },
repositoryNwo,
codeql,
config,
@@ -451,7 +456,7 @@ async function run(action: ActionState<["Base", "Logger", "Env", "Actions"]>) {
`expect-error input was set to true but no error was thrown.`,
);
}
action.env.export(EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY, "true");
core.exportVariable(EnvVar.ANALYZE_DID_COMPLETE_SUCCESSFULLY, "true");
} catch (unwrappedError) {
const error = util.wrapError(unwrappedError);
if (

View File

@@ -7,15 +7,13 @@ import * as sinon from "sinon";
import { CodeQuality, CodeScanning, RiskAssessment } from "./analyses";
import {
runQueries,
defaultSuites,
resolveQuerySuiteAlias,
addSarifExtension,
diffRangeExtensionPackContents,
determineCheckoutPath,
} from "./analyze";
import { createStubCodeQL } from "./codeql";
import { defaultSuites } from "./config/db-config";
import { Feature } from "./feature-flags";
import * as gitUtils from "./git-utils";
import { BuiltInLanguage } from "./languages";
import { getRunnerLogger } from "./logging";
import {
@@ -23,98 +21,12 @@ import {
setupActionsVars,
createFeatures,
createTestConfig,
callee,
} from "./testing-utils";
import * as uploadLib from "./upload-lib";
import * as util from "./util";
setupTests(test);
test.serial(
"determineCheckoutPath - logs when checkout_path is not in a work tree",
async (t) => {
const expectedPath = path.resolve("/checkout/path");
const target = callee(determineCheckoutPath)
.withActions((actions) => {
sinon
.stub(actions, "getRequiredInput")
.withArgs("checkout_path")
.returns(expectedPath);
})
.withArgs(createTestConfig({}));
sinon.stub(gitUtils, "getGitRoot").resolves(undefined);
await target
.logs(t, "is not in the work tree of a git repository")
.passes(t.is, expectedPath);
},
);
test.serial(
"determineCheckoutPath - logs when checkout_path is not a repo root",
async (t) => {
const expectedPath = path.resolve("/checkout/path");
const target = callee(determineCheckoutPath)
.withActions((actions) => {
sinon
.stub(actions, "getRequiredInput")
.withArgs("checkout_path")
.returns(expectedPath);
})
.withArgs(createTestConfig({}));
sinon.stub(gitUtils, "getGitRoot").resolves("/checkout");
await target
.logs(t, "is not the root of the repository")
.passes(t.is, expectedPath);
},
);
test.serial(
"determineCheckoutPath - logs when checkout_path is not the same as repo root in config",
async (t) => {
const expectedPath = path.resolve("/checkout/path");
const target = callee(determineCheckoutPath)
.withActions((actions) => {
sinon
.stub(actions, "getRequiredInput")
.withArgs("checkout_path")
.returns(expectedPath);
})
.withArgs(createTestConfig({ repositoryRoot: "/some/other/path" }));
sinon.stub(gitUtils, "getGitRoot").resolves(expectedPath);
await target
.logs(t, "does not match that found by the 'codeql-action/init' step")
.passes(t.is, expectedPath);
},
);
test.serial(
"determineCheckoutPath - doesn't log any of the messages when all is as expected",
async (t) => {
const expectedPath = path.resolve("/checkout/path");
const target = callee(determineCheckoutPath)
.withActions((actions) => {
sinon
.stub(actions, "getRequiredInput")
.withArgs("checkout_path")
.returns(expectedPath);
})
.withArgs(createTestConfig({ repositoryRoot: expectedPath }));
sinon.stub(gitUtils, "getGitRoot").resolves(expectedPath);
await target
.notLogs(
t,
"is not in the work tree of a git repository",
"is not the root of the repository",
"does not match that found by the 'codeql-action/init' step",
)
.passes(t.is, expectedPath);
},
);
/**
* Checks the status report produced by the analyze Action.
*

View File

@@ -5,13 +5,10 @@ import { performance } from "perf_hooks";
import * as io from "@actions/io";
import * as yaml from "js-yaml";
import type { ActionState } from "./action-common";
import { getTemporaryDirectory } from "./actions-util";
import * as analyses from "./analyses";
import { setupCppAutobuild } from "./autobuild";
import { type CodeQL } from "./codeql";
import type { ActionConfig } from "./config/action-config";
import { defaultSuites } from "./config/db-config";
import * as configUtils from "./config-utils";
import {
getCsharpTempDependencyDir,
@@ -24,7 +21,6 @@ import {
} from "./diff-informed-analysis-utils";
import { EnvVar } from "./environment";
import { FeatureEnablement, Feature } from "./feature-flags";
import { getGitRoot } from "./git-utils";
import { BuiltInLanguage, Language } from "./languages";
import { Logger, withGroupAsync } from "./logging";
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
@@ -89,58 +85,6 @@ export interface QueriesStatusReport
event_reports?: EventReport[];
}
/**
* Determines the path at which the repository being analysed is checked out at.
* Returns the value of the required `checkout_path` input and validates that it
* refers to the root of a repository.
*
* @param action The action state.
* @param config The CodeQL Action configuration state.
*/
export async function determineCheckoutPath(
action: ActionState<["Logger", "Actions"]>,
config: configUtils.Config,
) {
const checkoutPathInput = action.actions.getRequiredInput("checkout_path");
// Try to obtain the root path of the repository and validate that it matches the input.
const absCheckoutPathInput = path.resolve(checkoutPathInput);
const repositoryRoot = await getGitRoot(absCheckoutPathInput);
if (repositoryRoot === undefined) {
action.logger.warning(
[
`The directory at '${absCheckoutPathInput}' is not in the work tree of a git repository.`,
"If the repository being analyzed is checked out elsewhere,",
"you must explicitly set the 'checkout_path' input for the 'codeql-action/analyze' step to",
"the checkout path.",
].join(" "),
);
} else if (repositoryRoot !== absCheckoutPathInput) {
action.logger.warning(
[
`The directory at '${absCheckoutPathInput}' is not the root of the repository ('${repositoryRoot}').`,
"Set the 'checkout_path' input for the 'codeql-action/analyze' step to the root path of the checkout.",
].join(" "),
);
} else if (
config.repositoryRoot !== undefined &&
repositoryRoot !== config.repositoryRoot
) {
// The repository root that was persisted by the `init` step doesn't match the one we have found here.
action.logger.warning(
[
`The repository path at '${repositoryRoot}' does not match that found by the 'codeql-action/init' step: '${config.repositoryRoot}'.`,
"Ensure that the 'checkout_path' input for the 'codeql-action/analyze' step is set to the path of the same repository that",
"the 'codeql-action/init' step determined. This is either the GitHub Actions workspace or the repository root corresponding to",
"the 'source-root' input if that was provided.",
].join(" "),
);
}
return absCheckoutPathInput;
}
async function setupPythonExtractor(logger: Logger) {
const codeqlPython = process.env["CODEQL_PYTHON"];
if (codeqlPython === undefined || codeqlPython.length === 0) {
@@ -179,7 +123,7 @@ export async function runExtraction(
language === BuiltInLanguage.cpp &&
config.buildMode === BuildMode.Autobuild
) {
await setupCppAutobuild(logger);
await setupCppAutobuild(codeql, logger);
}
// The Java and C# `build-mode: none` extractors place dependencies in the
@@ -226,7 +170,7 @@ async function shouldExtractLanguage(
}
export function dbIsFinalized(
config: ActionConfig<"dbLocation">,
config: configUtils.Config,
language: Language,
logger: Logger,
) {
@@ -413,6 +357,15 @@ dataExtensions:
return diffRangeDir;
}
// A set of default query suite names that are understood by the CLI.
export const defaultSuites: Set<string> = new Set([
"security-experimental",
"security-extended",
"security-and-quality",
"code-quality",
"code-scanning",
]);
/**
* If `maybeSuite` is the name of a default query suite, it is resolved into the corresponding
* query suite name for the given `language`. Otherwise, `maybeSuite` is returned as is.

View File

@@ -7,21 +7,14 @@ import { ProxyAgent } from "undici";
import * as actionsUtil from "./actions-util";
import * as api from "./api-client";
import { DO_NOT_RETRY_STATUSES } from "./api-client";
import { ActionsEnvVars, RegistryProxyVars, getEnv } from "./environment";
import { GITHUB_DOTCOM_API_URL, GITHUB_DOTCOM_URL } from "./github";
import {
callee,
getTestEnv,
RecordingLogger,
SAMPLE_DOTCOM_API_DETAILS,
setupTests,
} from "./testing-utils";
import { ActionsEnvVars, RegistryProxyVars } from "./environment";
import { callee, getTestEnv, setupTests } from "./testing-utils";
import * as util from "./util";
setupTests(test);
test.beforeEach(() => {
getEnv().initialise(actionsUtil.getActionVersion());
util.initializeEnvironment(actionsUtil.getActionVersion());
});
test.serial("getApiClient", async (t) => {
@@ -291,87 +284,3 @@ test("makeProxyRequestOptions - returns fetch with custom proxy", async (t) => {
githubUtils.defaults.request,
);
});
test.serial(
"getApiClientWithExternalAuth constructs clients with or without tokens",
(t) => {
t.notThrows(() => {
api.getApiClientWithExternalAuth(SAMPLE_DOTCOM_API_DETAILS);
api.getApiClientWithExternalAuth({
...SAMPLE_DOTCOM_API_DETAILS,
auth: undefined,
});
});
},
);
test("getAuthorizationHeaderFor - returns undefined if there's no token", (t) => {
const logger = new RecordingLogger();
t.is(
api.getAuthorizationHeaderFor(
logger,
{ ...SAMPLE_DOTCOM_API_DETAILS, auth: undefined },
`${GITHUB_DOTCOM_URL}/github`,
),
undefined,
);
t.is(
api.getAuthorizationHeaderFor(
logger,
{ ...SAMPLE_DOTCOM_API_DETAILS, auth: "" },
`${GITHUB_DOTCOM_URL}/github`,
),
undefined,
);
t.is(
api.getAuthorizationHeaderFor(
logger,
{ ...SAMPLE_DOTCOM_API_DETAILS, auth: " " },
`${GITHUB_DOTCOM_URL}/github`,
),
undefined,
);
});
test("getAuthorizationHeaderFor - returns header value with token if url is allowed", (t) => {
const logger = new RecordingLogger();
t.is(
api.getAuthorizationHeaderFor(
logger,
SAMPLE_DOTCOM_API_DETAILS,
`${GITHUB_DOTCOM_URL}/github`,
),
`token ${SAMPLE_DOTCOM_API_DETAILS.auth}`,
);
t.is(
api.getAuthorizationHeaderFor(
logger,
SAMPLE_DOTCOM_API_DETAILS,
`${GITHUB_DOTCOM_API_URL}/github`,
),
`token ${SAMPLE_DOTCOM_API_DETAILS.auth}`,
);
});
test("getAuthorizationHeaderFor - returns undefined if url is not allowed", (t) => {
const logger = new RecordingLogger();
t.is(
api.getAuthorizationHeaderFor(
logger,
SAMPLE_DOTCOM_API_DETAILS,
`https://localhost/github`,
),
undefined,
);
t.is(
api.getAuthorizationHeaderFor(
logger,
SAMPLE_DOTCOM_API_DETAILS,
`https://api.localhost/github`,
),
undefined,
);
});

View File

@@ -1,6 +1,5 @@
import * as core from "@actions/core";
import * as githubUtils from "@actions/github/lib/utils";
import type { OctokitOptions } from "@octokit/core";
import * as retry from "@octokit/plugin-retry";
import { RequestRequestOptions } from "@octokit/types";
import {
@@ -13,32 +12,25 @@ import {
import type { ActionState } from "./action-common";
import { getActionVersion, getRequiredInput } from "./actions-util";
import {
ActionsEnvVars,
EnvVar,
ReadOnlyEnv,
RegistryProxyVars,
getEnv,
exportEnvVar,
} from "./environment";
import {
getCurrentInstance,
GITHUB_DOTCOM_URL,
parseGitHubUrl,
type GitHubApiCombinedDetails,
type GitHubApiDetails,
} from "./github";
import { Logger } from "./logging";
import { getRepositoryNwo, RepositoryNwo } from "./repository";
import {
asHTTPError,
ConfigurationError,
getRequiredEnvParam,
GITHUB_DOTCOM_URL,
GitHubVariant,
GitHubVersion,
parseGitHubUrl,
parseMatrixInput,
} from "./util";
export type { GitHubApiDetails, GitHubApiCombinedDetails } from "./github";
const GITHUB_ENTERPRISE_VERSION_HEADER = "x-github-enterprise-version";
/**
@@ -50,6 +42,21 @@ const GITHUB_ENTERPRISE_VERSION_HEADER = "x-github-enterprise-version";
*/
export const DO_NOT_RETRY_STATUSES = [400, 410, 422, 451];
export type GitHubApiCombinedDetails = GitHubApiDetails &
GitHubApiExternalRepoDetails;
export interface GitHubApiDetails {
auth: string;
url: string;
apiURL: string | undefined;
}
export interface GitHubApiExternalRepoDetails {
externalRepoAuth?: string;
url: string;
apiURL: string | undefined;
}
/**
* Gets the configuration for the private registry authentication proxy,
* if it is available in the environment.
@@ -131,60 +138,37 @@ function createApiClientWithDetails(
{ allowExternal = false, proxy = undefined }: CreateApiClientOptions = {},
): ApiClient {
const auth =
allowExternal && apiDetails.externalRepoAuth !== undefined
? apiDetails.externalRepoAuth
: apiDetails.auth;
(allowExternal && apiDetails.externalRepoAuth) || apiDetails.auth;
const retryingOctokit = githubUtils.GitHub.plugin(retry.retry);
const requestOptions = makeProxyRequestOptions(proxy);
const opts: OctokitOptions = {
auth:
auth !== undefined && auth.trim() !== "" ? `token ${auth}` : undefined,
baseUrl: apiDetails.apiURL,
userAgent: `CodeQL-Action/${getActionVersion()}`,
log: {
debug: core.debug,
info: core.info,
warn: core.warning,
error: core.error,
},
request: requestOptions,
retry: {
doNotRetry: DO_NOT_RETRY_STATUSES,
},
};
return new retryingOctokit(opts);
return new retryingOctokit(
githubUtils.getOctokitOptions(auth, {
baseUrl: apiDetails.apiURL,
userAgent: `CodeQL-Action/${getActionVersion()}`,
log: {
debug: core.debug,
info: core.info,
warn: core.warning,
error: core.error,
},
request: requestOptions,
retry: {
doNotRetry: DO_NOT_RETRY_STATUSES,
},
}),
);
}
/**
* Gets a `GitHubApiDetails` object describing the GitHub instance we are currently running on.
*
* @param env The environment variables to read.
*/
export function getApiDetails(env: ReadOnlyEnv = getEnv()): GitHubApiDetails {
return {
auth: getRequiredInput("token"),
...getCurrentInstance(env),
url: env.getRequired(ActionsEnvVars.GITHUB_SERVER_URL),
apiURL: env.getRequired(ActionsEnvVars.GITHUB_API_URL),
};
}
/**
* Constructs an {@link ApiClient} using {@link apiDetails}.
*
* If {@link apiDetails} is not specified, then the GitHub instance URLs and auth token
* are taken from {@link env}.
*
* If {@link env} is not specified, then the process environment is used.
*
* @param env The environment to obtain the GitHub instance URLs from.
* @param apiDetails The {@link GitHubApiDetails} to construct the {@link ApiClient} for.
*/
export function getApiClient(
env: ReadOnlyEnv = getEnv(),
apiDetails?: GitHubApiDetails,
) {
return createApiClientWithDetails(apiDetails ?? getApiDetails(env));
export function getApiClient(env: ReadOnlyEnv = getEnv()) {
return createApiClientWithDetails(getApiDetails(env));
}
export function getApiClientWithExternalAuth(
@@ -209,12 +193,6 @@ export function getAuthorizationHeaderFor(
apiDetails: GitHubApiDetails,
url: string,
): string | undefined {
// We don't have to check the `url` if we don't have a token to begin with.
const token = apiDetails.auth?.trim();
if (token === undefined || token === "") {
return undefined;
}
// We only want to provide an authorization header if we are downloading
// from the same GitHub instance the Action is running on.
// This avoids leaking Enterprise tokens to dotcom.
@@ -223,7 +201,7 @@ export function getAuthorizationHeaderFor(
(apiDetails.apiURL && url.startsWith(`${apiDetails.apiURL}/`))
) {
logger.debug(`Providing an authorization token.`);
return `token ${token}`;
return `token ${apiDetails.auth}`;
}
logger.debug(`Not using an authorization token.`);
@@ -338,7 +316,7 @@ export async function getAnalysisKey(): Promise<string> {
const jobName = getRequiredEnvParam("GITHUB_JOB");
analysisKey = `${workflowPath}:${jobName}`;
exportEnvVar(EnvVar.ANALYSIS_KEY, analysisKey);
core.exportVariable(EnvVar.ANALYSIS_KEY, analysisKey);
return analysisKey;
}

View File

@@ -1 +1 @@
{"maximumVersion":"3.23","minimumVersion":"3.18"}
{"maximumVersion":"3.23","minimumVersion":"3.17"}

View File

@@ -10,7 +10,7 @@ import { getGitHubVersion } from "./api-client";
import { determineAutobuildLanguages, runAutobuild } from "./autobuild";
import { getCodeQL } from "./codeql";
import { Config, getConfig } from "./config-utils";
import { EnvVar, type Env } from "./environment";
import { EnvVar } from "./environment";
import { Language } from "./languages";
import { Logger } from "./logging";
import {
@@ -26,6 +26,7 @@ import {
checkDiskUsage,
checkGitHubVersionInRange,
ConfigurationError,
initializeEnvironment,
wrapError,
} from "./util";
@@ -37,7 +38,6 @@ interface AutobuildStatusReport extends StatusReportBase {
}
async function sendCompletedStatusReport(
env: Env,
config: Config | undefined,
logger: Logger,
startedAt: Date,
@@ -45,7 +45,7 @@ async function sendCompletedStatusReport(
failingLanguage?: string,
cause?: Error,
) {
env.initialise(getActionVersion());
initializeEnvironment(getActionVersion());
const status = getActionsStatus(cause, failingLanguage);
const statusReportBase = await createStatusReportBase(
@@ -68,11 +68,7 @@ async function sendCompletedStatusReport(
}
}
async function run({
startedAt,
env,
logger,
}: ActionState<["Base", "Env", "Logger"]>) {
async function run({ startedAt, logger }: ActionState<["Base", "Logger"]>) {
// To capture errors appropriately, keep as much code within the try-catch as
// possible, and only use safe functions outside.
@@ -129,7 +125,6 @@ async function run({
`We were unable to automatically build your code. Please replace the call to the autobuild action with your custom build steps. ${error.message}`,
);
await sendCompletedStatusReport(
env,
config,
logger,
startedAt,
@@ -140,15 +135,9 @@ async function run({
return;
}
env.export(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
core.exportVariable(EnvVar.AUTOBUILD_DID_COMPLETE_SUCCESSFULLY, "true");
await sendCompletedStatusReport(
env,
config,
logger,
startedAt,
languages ?? [],
);
await sendCompletedStatusReport(config, logger, startedAt, languages ?? []);
}
/** Defines the `autobuild` Action. */

View File

@@ -1,9 +1,11 @@
import * as core from "@actions/core";
import { getTemporaryDirectory, getWorkflowEventName } from "./actions-util";
import { getGitHubVersion } from "./api-client";
import { CodeQL, getCodeQL } from "./codeql";
import * as configUtils from "./config-utils";
import { DocUrl } from "./doc-url";
import { ActionsEnvVars, EnvVar, exportEnvVar } from "./environment";
import { ActionsEnvVars, EnvVar } from "./environment";
import { Feature, featureConfig, initFeatures } from "./feature-flags";
import { BuiltInLanguage, Language } from "./languages";
import { Logger } from "./logging";
@@ -110,7 +112,7 @@ export async function determineAutobuildLanguages(
return languages;
}
export async function setupCppAutobuild(logger: Logger) {
export async function setupCppAutobuild(codeql: CodeQL, logger: Logger) {
const envVar = featureConfig[Feature.CppDependencyInstallation].envVar;
const featureName = "C++ automatic installation of dependencies";
const gitHubVersion = await getGitHubVersion();
@@ -121,7 +123,7 @@ export async function setupCppAutobuild(logger: Logger) {
getTemporaryDirectory(),
logger,
);
if (await features.getValue(Feature.CppDependencyInstallation)) {
if (await features.getValue(Feature.CppDependencyInstallation, codeql)) {
// disable autoinstall on self-hosted runners unless explicitly requested
if (
process.env[ActionsEnvVars.RUNNER_ENVIRONMENT] === "self-hosted" &&
@@ -134,16 +136,16 @@ export async function setupCppAutobuild(logger: Logger) {
: ""
}`,
);
exportEnvVar(envVar, "false");
core.exportVariable(envVar, "false");
} else {
logger.info(
`Enabling ${featureName}. This can be disabled by setting the ${envVar} environment variable to 'false'. See ${DocUrl.DEFINE_ENV_VARIABLES} for more information.`,
);
exportEnvVar(envVar, "true");
core.exportVariable(envVar, "true");
}
} else {
logger.info(`Disabling ${featureName}.`);
exportEnvVar(envVar, "false");
core.exportVariable(envVar, "false");
}
}
@@ -155,7 +157,7 @@ export async function runAutobuild(
logger.startGroup(`Attempting to automatically build ${language} code`);
const codeQL = await getCodeQL(logger, config.codeQLCmd);
if (language === BuiltInLanguage.cpp) {
await setupCppAutobuild(logger);
await setupCppAutobuild(codeQL, logger);
}
if (config.buildMode) {
await codeQL.extractUsingBuildMode(config, language);
@@ -163,7 +165,7 @@ export async function runAutobuild(
await codeQL.runAutobuild(config, language);
}
if (language === BuiltInLanguage.go) {
exportEnvVar(EnvVar.DID_AUTOBUILD_GOLANG, "true");
core.exportVariable(EnvVar.DID_AUTOBUILD_GOLANG, "true");
}
logger.endGroup();
}

View File

@@ -21,7 +21,6 @@ import {
import type { Config } from "./config-utils";
import * as defaults from "./defaults.json";
import { DocUrl } from "./doc-url";
import { getEnv } from "./environment";
import { BuiltInLanguage } from "./languages";
import { getRunnerLogger } from "./logging";
import { ToolsSource } from "./setup-codeql";
@@ -38,13 +37,14 @@ import {
} from "./testing-utils";
import { ToolsDownloadStatusReport } from "./tools-download";
import * as util from "./util";
import { initializeEnvironment } from "./util";
setupTests(test);
let stubConfig: Config;
test.beforeEach(() => {
getEnv().initialise("1.2.3");
initializeEnvironment("1.2.3");
stubConfig = createTestConfig({
languages: [BuiltInLanguage.cpp],
@@ -99,7 +99,6 @@ async function installIntoToolcache({
? { enabledVersions: [{ cliVersion, tagName }] }
: SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
createFeatures([]),
getRunnerLogger(true),
@@ -126,7 +125,7 @@ function mockReleaseApi({
});
}
function mockApiDetails(apiDetails: Required<GitHubApiDetails>) {
function mockApiDetails(apiDetails: GitHubApiDetails) {
// This is a workaround to mock `api.getApiDetails()` since it doesn't seem to be possible to
// mock this directly. The difficulty is that `getApiDetails()` is called locally in
// `api-client.ts`, but `sinon.stub(api, "getApiDetails")` only affects calls to
@@ -173,7 +172,6 @@ test.serial(
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -209,7 +207,6 @@ test.serial(
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -249,7 +246,6 @@ test.serial(
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -359,7 +355,6 @@ for (const {
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -402,7 +397,6 @@ for (const toolcacheVersion of [
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -447,7 +441,6 @@ test.serial(
],
},
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -494,7 +487,6 @@ test.serial(
],
},
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -534,7 +526,6 @@ test.serial(
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),
@@ -576,7 +567,6 @@ test.serial(
util.GitHubVariant.DOTCOM,
SAMPLE_DEFAULT_CLI_VERSION,
undefined, // rawLanguages
undefined, // otherLanguagePacksReason
false, // useOverlayAwareDefaultCliVersion
features,
getRunnerLogger(true),

View File

@@ -4,7 +4,6 @@ import * as path from "path";
import * as core from "@actions/core";
import * as toolrunner from "@actions/exec/lib/toolrunner";
import * as yaml from "js-yaml";
import * as semver from "semver";
import {
CommandInvocationError,
@@ -16,11 +15,9 @@ import * as api from "./api-client";
import * as outputCache from "./cli/output-cache";
import type { VersionInfo } from "./cli/types";
import { CliError, wrapCliConfigurationError } from "./cli-errors";
import type { ActionConfig } from "./config/action-config";
import { appendExtraQueryExclusions, type Config } from "./config-utils";
import { DocUrl } from "./doc-url";
import { EnvVar, getEnv, exportEnvVar } from "./environment";
import { getErrorMessage, isDiskConfigurationError } from "./errors";
import { EnvVar, getEnv } from "./environment";
import {
CodeQLDefaultVersionInfo,
Feature,
@@ -36,9 +33,7 @@ import { ToolsDownloadStatusReport } from "./tools-download";
import { ToolsFeature, isSupportedToolsFeature } from "./tools-features";
import { shouldEnableIndirectTracing } from "./tracer-config";
import * as util from "./util";
import { BuildMode, CleanupLevel } from "./util";
export { isDiskConfigurationError } from "./errors";
import { BuildMode, CleanupLevel, getErrorMessage } from "./util";
type Options = Array<string | number | boolean>;
@@ -74,11 +69,6 @@ export interface CodeQL {
* Get a string containing the semver version of the CodeQL executable.
*/
getVersion(): Promise<VersionInfo>;
/**
* Determines whether the CLI installation represented by this {@link CodeQL} instance
* has at least the {@link requiredVersion}.
*/
isVersionAtLeast(requiredVersion: string): Promise<boolean>;
/**
* Print version information about CodeQL.
*/
@@ -207,7 +197,7 @@ export interface CodeQL {
diagnosticsExport(
sarifFile: string,
automationDetailsId: string | undefined,
config: ActionConfig<"tempDir">,
config: Config,
): Promise<void>;
/** Get the location of an extractor for the specified language. */
resolveExtractor(language: Language): Promise<string>;
@@ -263,26 +253,46 @@ let cachedCodeQL: CodeQL | undefined = undefined;
* The version flags below can be used to conditionally enable certain features
* on versions newer than this.
*/
const CODEQL_MINIMUM_VERSION = "2.20.7";
const CODEQL_MINIMUM_VERSION = "2.19.4";
/**
* This version will shortly become the oldest version of CodeQL that the Action will run with.
*/
const CODEQL_NEXT_MINIMUM_VERSION = "2.21.3";
const CODEQL_NEXT_MINIMUM_VERSION = "2.20.7";
/**
* This is the version of GHES that was most recently deprecated.
*/
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.17";
const GHES_VERSION_MOST_RECENTLY_DEPRECATED = "3.16";
/**
* This is the deprecation date for the version of GHES that was most recently deprecated.
*/
const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-09-24";
const GHES_MOST_RECENT_DEPRECATION_DATE = "2026-07-01";
/** The CLI verbosity level to use for extraction in debug mode. */
const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
/**
* Decides whether `e` is a disk-related error outside of our control
* that should be classified as a `ConfigurationError`.
*
* @param e The error to check.
* @returns True if the error should be treated as a `ConfigurationError` or false if not.
*/
export function isDiskConfigurationError(e: unknown): boolean {
if (!(e instanceof Error)) {
return false;
}
return (
// out of disk space
e.message.includes("ENOSPC") ||
// access denied
e.message.includes("EACCES")
);
}
/**
* Set up CodeQL CLI access.
*
@@ -292,9 +302,6 @@ const EXTRACTION_DEBUG_MODE_VERBOSITY = "progress++";
* @param variant
* @param defaultCliVersion
* @param rawLanguages Raw set of languages.
* @param otherLanguagePacksReason Why the CodeQL CLI may need packs for languages other than
* `rawLanguages`, or `undefined` if it won't. If defined, the combined bundle is used. See
* `PerLanguageBundleOptions.otherLanguagePacksReason`.
* @param useOverlayAwareDefaultCliVersion Whether to select an overlay-aware default CLI version.
* @param features Information about the features that are enabled.
* @param logger
@@ -309,7 +316,6 @@ export async function setupCodeQL(
variant: util.GitHubVariant,
defaultCliVersion: CodeQLDefaultVersionInfo,
rawLanguages: string[] | undefined,
otherLanguagePacksReason: string | undefined,
useOverlayAwareDefaultCliVersion: boolean,
features: FeatureEnablement,
logger: Logger,
@@ -333,7 +339,6 @@ export async function setupCodeQL(
variant,
defaultCliVersion,
rawLanguages,
otherLanguagePacksReason,
useOverlayAwareDefaultCliVersion,
features,
logger,
@@ -420,19 +425,6 @@ export function createStubCodeQL(partialCodeql: Partial<CodeQL>): CodeQL {
getVersion: resolveFunction(partialCodeql, "getVersion", async () => ({
version: "1.0.0",
})),
isVersionAtLeast: resolveFunction(
partialCodeql,
"codeQlVersionAtLeast",
async (requiredVersion) => {
return (
!!partialCodeql.getVersion &&
semver.gte(
(await partialCodeql.getVersion()).version,
requiredVersion,
)
);
},
),
printVersion: resolveFunction(partialCodeql, "printVersion"),
supportsFeature: resolveFunction(
partialCodeql,
@@ -536,9 +528,6 @@ async function getCodeQLForCmd(
}
return result;
},
async isVersionAtLeast(requiredVersion: string) {
return semver.gte((await this.getVersion()).version, requiredVersion);
},
async printVersion() {
// Reuse the cached version information rather than invoking the CLI again.
core.info(JSON.stringify(await this.getVersion(), null, 2));
@@ -919,7 +908,7 @@ async function getCodeQLForCmd(
async diagnosticsExport(
sarifFile: string,
automationDetailsId: string | undefined,
config: ActionConfig<"tempDir">,
config: Config,
): Promise<void> {
const args = [
"diagnostics",
@@ -1033,7 +1022,7 @@ async function getCodeQLForCmd(
// CodeQL object is created.
if (
checkVersion &&
!(await codeql.isVersionAtLeast(CODEQL_MINIMUM_VERSION))
!(await util.codeQlVersionAtLeast(codeql, CODEQL_MINIMUM_VERSION))
) {
throw new util.ConfigurationError(
`Expected a CodeQL CLI with version at least ${CODEQL_MINIMUM_VERSION} but got version ${
@@ -1043,7 +1032,7 @@ async function getCodeQLForCmd(
} else if (
checkVersion &&
process.env[EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING] !== "true" &&
!(await codeql.isVersionAtLeast(CODEQL_NEXT_MINIMUM_VERSION))
!(await util.codeQlVersionAtLeast(codeql, CODEQL_NEXT_MINIMUM_VERSION))
) {
const result = await codeql.getVersion();
core.warning(
@@ -1060,7 +1049,7 @@ async function getCodeQLForCmd(
}' by 'github/codeql-action/*@v${getActionVersion()}' in your code scanning workflow to ` +
"continue using this version of the CodeQL Action.",
);
exportEnvVar(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING, "true");
core.exportVariable(EnvVar.SUPPRESS_DEPRECATED_SOON_WARNING, "true");
}
return codeql;
}
@@ -1230,7 +1219,7 @@ export async function getTrapCachingExtractorConfigArgsForLang(
): Promise<string[]> {
const cacheDir = config.trapCaches[language];
if (cacheDir === undefined) return [];
const write = await isAnalyzingDefaultBranch(getEnv(), config.repositoryRoot);
const write = await isAnalyzingDefaultBranch();
return [
`-O=${language}.trap.cache.dir=${cacheDir}`,
`-O=${language}.trap.cache.bound=${TRAP_CACHE_SIZE_MB}`,
@@ -1243,9 +1232,7 @@ export async function getTrapCachingExtractorConfigArgsForLang(
*
* This will not exist if the configuration is being parsed in the Action.
*/
function getGeneratedCodeScanningConfigPath(
config: ActionConfig<"tempDir">,
): string {
function getGeneratedCodeScanningConfigPath(config: Config): string {
return path.resolve(config.tempDir, "user-config.yaml");
}

View File

@@ -172,7 +172,6 @@ test.serial("load empty config", async (t) => {
createTestInitConfigInputs({
languagesInput: languages,
repository: { owner: "github", repo: "example" },
sourceRoot: tempDir,
tempDir,
codeql,
logger,
@@ -187,7 +186,6 @@ test.serial("load empty config", async (t) => {
logger,
}),
{},
undefined,
);
t.deepEqual(config, expectedConfig);
@@ -218,7 +216,6 @@ test.serial("load code quality config", async (t) => {
analysisKinds: [AnalysisKind.CodeQuality],
languagesInput: languages,
repository: { owner: "github", repo: "example" },
sourceRoot: tempDir,
tempDir,
codeql,
logger,
@@ -299,7 +296,6 @@ test.serial(
analysisKinds: [AnalysisKind.CodeQuality],
languagesInput: languages,
repository: { owner: "github", repo: "example" },
sourceRoot: tempDir,
tempDir,
codeql,
repositoryProperties,
@@ -477,12 +473,6 @@ const simpleConfigFileContents = `
queries:
- uses: ./foo_file`;
/** The configuration in `simpleConfigFileContents`. */
const simpleConfigInput: UserConfig = {
name: "my config",
queries: [{ uses: "./foo_file" }],
};
/** A less minimal configuration file. */
const otherConfigFileContents = `
name: my config
@@ -522,7 +512,6 @@ test.serial("load non-empty input", async (t) => {
// And the config we expect it to parse to
const expectedConfig = createTestConfig({
languages: [BuiltInLanguage.javascript],
repositoryRoot: undefined,
buildMode: BuildMode.None,
originalUserInput: userConfig,
computedConfig: userConfig,
@@ -543,7 +532,6 @@ test.serial("load non-empty input", async (t) => {
state,
createTestInitConfigInputs({
languagesInput,
sourceRoot: tempDir,
buildModeInput: "none",
configFile: configFilePath,
debugArtifactName: "my-artifact",
@@ -570,14 +558,16 @@ test.serial(
tempDir,
);
const configInput: UserConfig = {
name: "my config",
queries: [{ uses: "./foo" }],
packs: {
javascript: ["a/b@1.2.3"],
python: ["c/d@1.2.3"],
},
};
const configInput = `
name: my config
queries:
- uses: ./foo
packs:
javascript:
- a/b@1.2.3
python:
- c/d@1.2.3
`;
fs.mkdirSync(path.join(tempDir, "foo"));
@@ -608,16 +598,7 @@ test.serial(
}),
);
// Compare with a separate object rather than `configInput` itself, so that the test catches
// changes made to the input in place.
t.deepEqual(config.originalUserInput, {
name: "my config",
queries: [{ uses: "./foo" }],
packs: {
javascript: ["a/b@1.2.3"],
python: ["c/d@1.2.3"],
},
});
t.deepEqual(config.originalUserInput, yaml.load(configInput));
});
},
);
@@ -1111,6 +1092,11 @@ const checkOverlayEnablementMacro = makeMacro({
return lang === BuiltInLanguage.java;
});
// Mock git root detection
if (setup.gitRoot !== undefined) {
sinon.stub(gitUtils, "getGitRoot").resolves(setup.gitRoot);
}
// Mock submodule detection
sinon.stub(gitUtils, "hasSubmodules").returns(setup.hasSubmodules);
@@ -1123,7 +1109,6 @@ const checkOverlayEnablementMacro = makeMacro({
codeql,
features,
setup.languages,
setup.gitRoot, // repositoryRoot
tempDir, // sourceRoot
setup.buildMode,
undefined,
@@ -2428,7 +2413,7 @@ test("determineUserConfig - loads config input", async (t) => {
const expectedConfigPath = configUtils.userConfigFromActionPath(tmpDir);
const inputs = createTestInitConfigInputs({
configInput: simpleConfigInput,
configInput: simpleConfigFileContents,
configFile: undefined,
workspacePath: tmpDir,
});
@@ -2438,15 +2423,17 @@ test("determineUserConfig - loads config input", async (t) => {
await target
// The input source and path of the generated config file should have been logged.
.logs(t, `Using config from action input: ${expectedConfigPath}`)
// The message about no configuration input and the warning about both inputs should not have
// been logged. The generated config file isn't loaded, since the `config` input has already
// been parsed.
.logs(
t,
"Using config from action input:",
`Using configuration file: ${expectedConfigPath}`,
)
// The message about no configuration input and
// the warning about both inputs should not have been logged.
.notLogs(
t,
"No configuration file was provided",
"Both a config file and config input were provided. Ignoring config file.",
`Using configuration file: ${expectedConfigPath}`,
)
// The loaded configuration should match `simpleConfigFileContents`.
.passes(t.deepEqual, {
@@ -2465,7 +2452,7 @@ test("determineUserConfig - ignores config file input when both specified", asyn
const expectedConfigPath = configUtils.userConfigFromActionPath(tmpDir);
const inputs = createTestInitConfigInputs({
configInput: simpleConfigInput,
configInput: simpleConfigFileContents,
configFile: configFilePath,
workspacePath: tmpDir,
});
@@ -2479,14 +2466,10 @@ test("determineUserConfig - ignores config file input when both specified", asyn
.logs(
t,
`Using config from action input: ${expectedConfigPath}`,
`Using configuration file: ${expectedConfigPath}`,
"Both a config file and config input were provided. Ignoring config file.",
)
// The generated config file isn't loaded, since the `config` input has already been parsed.
.notLogs(
t,
"No configuration file was provided",
`Using configuration file: ${expectedConfigPath}`,
)
.notLogs(t, "No configuration file was provided")
// The loaded configuration should match `simpleConfigFileContents`.
.passes(t.deepEqual, {
name: "my config",
@@ -2499,14 +2482,11 @@ test("determineUserConfig - ignores config file input when both specified", asyn
});
/** A `config` input that we might get from Default Setup. */
const defaultSetupConfigInput: UserConfig = {
"threat-models": ["local", "remote"],
"default-setup": {
org: {
"model-packs": ["foo", "bar"],
},
},
};
const defaultSetupConfigInput = `
threat-models: [local, remote]
default-setup:
org:
model-packs: [foo, bar]`;
test("determineUserConfig - merges configs if FF is enabled in Default Setup", async (t) => {
await withTmpDir(async (tmpDir) => {
@@ -2575,7 +2555,7 @@ test("determineUserConfig - ignores config file input in Default Setup if FF is
.withArgs(
tmpDir,
createTestInitConfigInputs({
configInput: simpleConfigInput,
configInput: simpleConfigFileContents,
configFile: configFilePath,
workspacePath: tmpDir,
}),
@@ -2585,14 +2565,10 @@ test("determineUserConfig - ignores config file input in Default Setup if FF is
.logs(
t,
`Using config from action input: ${expectedConfigPath}`,
`Using configuration file: ${expectedConfigPath}`,
"Both a config file and config input were provided. Ignoring config file.",
)
// The generated config file isn't loaded, since the `config` input has already been parsed.
.notLogs(
t,
"No configuration file was provided",
`Using configuration file: ${expectedConfigPath}`,
)
.notLogs(t, "No configuration file was provided")
.passes(t.deepEqual, {
name: "my config",
queries: [{ uses: "./foo_file" }],
@@ -2611,7 +2587,7 @@ test("determineUserConfig - ignores config file input outside Default Setup if F
.withArgs(
tmpDir,
createTestInitConfigInputs({
configInput: simpleConfigInput,
configInput: simpleConfigFileContents,
configFile: configFilePath,
workspacePath: tmpDir,
}),
@@ -2621,14 +2597,10 @@ test("determineUserConfig - ignores config file input outside Default Setup if F
.logs(
t,
`Using config from action input: ${expectedConfigPath}`,
`Using configuration file: ${expectedConfigPath}`,
"Both a config file and config input were provided. Ignoring config file.",
)
// The generated config file isn't loaded, since the `config` input has already been parsed.
.notLogs(
t,
"No configuration file was provided",
`Using configuration file: ${expectedConfigPath}`,
)
.notLogs(t, "No configuration file was provided")
.passes(t.deepEqual, {
name: "my config",
queries: [{ uses: "./foo_file" }],

View File

@@ -2,6 +2,7 @@ import * as fs from "fs";
import * as path from "path";
import { performance } from "perf_hooks";
import * as core from "@actions/core";
import * as yaml from "js-yaml";
import { ActionState } from "./action-common";
@@ -21,11 +22,7 @@ import {
import * as api from "./api-client";
import { getCachingKind } from "./caching-utils";
import { type CodeQL } from "./codeql";
import {
type AbortedInitConfig,
type ActionConfig,
type Config,
} from "./config/action-config";
import { type Config } from "./config/action-config";
import {
calculateAugmentation,
ExcludeQueryFilter,
@@ -49,7 +46,7 @@ import {
makeTelemetryDiagnostic,
} from "./diagnostics";
import { prepareDiffInformedAnalysis } from "./diff-informed-analysis-utils";
import { EnvVar, exportEnvVar, getEnv } from "./environment";
import { EnvVar } from "./environment";
import * as errorMessages from "./error-messages";
import { Feature, FeatureEnablement, FeatureWithoutCLI } from "./feature-flags";
import {
@@ -75,13 +72,13 @@ import {
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
import { shouldSkipOverlayAnalysis } from "./overlay/status";
import { RepositoryNwo } from "./repository";
import { ActionName } from "./status-report";
import { ToolsFeature } from "./tools-features";
import { downloadTrapCaches } from "./trap-caching";
import {
GitHubVersion,
ConfigurationError,
BuildMode,
codeQlVersionAtLeast,
cloneObject,
isDefined,
checkDiskUsage,
@@ -340,8 +337,7 @@ export interface InitConfigInputs {
packsInput: string | undefined;
configFile: string | undefined;
dbLocation: string | undefined;
/** The configuration from the `config` input. */
configInput: UserConfig | undefined;
configInput: string | undefined;
buildModeInput: string | undefined;
ramInput: string | undefined;
dependencyCachingEnabled: string | undefined;
@@ -389,7 +385,6 @@ export async function initActionState(
enableFileCoverageInformation,
}: InitConfigInputs,
userConfig: UserConfig,
repositoryRoot: string | undefined,
): Promise<Config> {
const languages = await getLanguages(
codeql,
@@ -441,7 +436,6 @@ export async function initActionState(
return {
version: getActionVersion(),
repositoryRoot,
analysisKinds,
languages,
buildMode,
@@ -471,18 +465,12 @@ async function downloadCacheWithTime(
codeQL: CodeQL,
languages: Language[],
logger: Logger,
repositoryRoot: string | undefined,
): Promise<{
trapCaches: { [language: string]: string };
trapCacheDownloadTime: number;
}> {
const start = performance.now();
const trapCaches = await downloadTrapCaches(
codeQL,
languages,
logger,
repositoryRoot,
);
const trapCaches = await downloadTrapCaches(codeQL, languages, logger);
const trapCacheDownloadTime = performance.now() - start;
return { trapCaches, trapCacheDownloadTime };
}
@@ -651,7 +639,10 @@ async function runnerHasSufficientMemory(
logger: Logger,
): Promise<boolean> {
if (
await codeql.isVersionAtLeast(CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE)
await codeQlVersionAtLeast(
codeql,
CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE,
)
) {
logger.debug(
`Skipping memory check for overlay analysis because CodeQL version is at least ${CODEQL_VERSION_REDUCED_OVERLAY_MEMORY_USAGE}.`,
@@ -727,7 +718,6 @@ export async function checkOverlayEnablement(
codeql: CodeQL,
features: FeatureEnablement,
languages: Language[],
repositoryRoot: string | undefined,
sourceRoot: string,
buildMode: BuildMode | undefined,
ramInput: string | undefined,
@@ -757,7 +747,6 @@ export async function checkOverlayEnablement(
true,
codeql,
languages,
repositoryRoot,
sourceRoot,
buildMode,
gitVersion,
@@ -831,7 +820,7 @@ export async function checkOverlayEnablement(
`Setting overlay database mode to ${overlayDatabaseMode} ` +
"with caching because we are analyzing a pull request.",
);
} else if (await isAnalyzingDefaultBranch(getEnv(), repositoryRoot)) {
} else if (await isAnalyzingDefaultBranch()) {
overlayDatabaseMode = OverlayDatabaseMode.OverlayBase;
logger.info(
`Setting overlay database mode to ${overlayDatabaseMode} ` +
@@ -847,7 +836,6 @@ export async function checkOverlayEnablement(
false,
codeql,
languages,
repositoryRoot,
sourceRoot,
buildMode,
gitVersion,
@@ -867,7 +855,6 @@ async function validateOverlayDatabaseMode(
overlayModeSetExplicitly: boolean,
codeql: CodeQL,
languages: Language[],
repositoryRoot: string | undefined,
sourceRoot: string,
buildMode: BuildMode | undefined,
gitVersion: GitVersionInfo | undefined,
@@ -895,7 +882,7 @@ async function validateOverlayDatabaseMode(
);
return new Failure(OverlayDisabledReason.IncompatibleBuildMode);
}
if (!(await codeql.isVersionAtLeast(CODEQL_OVERLAY_MINIMUM_VERSION))) {
if (!(await codeQlVersionAtLeast(codeql, CODEQL_OVERLAY_MINIMUM_VERSION))) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because ` +
`the CodeQL CLI is older than ${CODEQL_OVERLAY_MINIMUM_VERSION}. ` +
@@ -903,7 +890,8 @@ async function validateOverlayDatabaseMode(
);
return new Failure(OverlayDisabledReason.IncompatibleCodeQl);
}
if (repositoryRoot === undefined) {
const gitRoot = await getGitRoot(sourceRoot);
if (gitRoot === undefined) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because ` +
`the source root "${sourceRoot}" is not inside a git repository. ` +
@@ -911,7 +899,7 @@ async function validateOverlayDatabaseMode(
);
return new Failure(OverlayDisabledReason.NoGitRoot);
}
if (hasSubmodules(repositoryRoot)) {
if (hasSubmodules(gitRoot)) {
if (gitVersion === undefined) {
logger.warning(
`Cannot build an ${overlayDatabaseMode} database because ` +
@@ -976,10 +964,10 @@ async function setCppTrapCachingEnvironmentVariables(
);
} else if (config.trapCaches[BuiltInLanguage.cpp]) {
logger.info("Enabling TRAP caching for C/C++.");
exportEnvVar(envVar, "true");
core.exportVariable(envVar, "true");
} else {
logger.debug(`Disabling TRAP caching for C/C++.`);
exportEnvVar(envVar, "false");
core.exportVariable(envVar, "false");
}
}
}
@@ -1069,13 +1057,17 @@ export async function determineUserConfig(
tempDir: string,
inputs: InitConfigInputs,
): Promise<UserConfig> {
const validateConfig = await action.features.getValue(
Feature.ValidateDbConfig,
);
// We have the following cases:
// 1. A `config` or `config-file` input is provided, but not both: use the provided one.
// 2. Both are provided and we are in an advanced workflow: ignore the `config-file` input.
// 3. Both are provided and we are in Default Setup: the `config` input uses a limited
// set of options, which are supported by `mergeDefaultSetupAndUserConfigs`,
// and we merge the two configs.
if (inputs.configInput !== undefined) {
if (inputs.configInput) {
const computedConfigPath = userConfigFromActionPath(tempDir);
// Get a function which enables us to determine whether the FF that allows us to
@@ -1092,6 +1084,12 @@ export async function determineUserConfig(
) {
// If the FF is enabled and we are in Default Setup, combine the supported
// configuration file properties and write the result to disk.
const fromConfigInput = parseUserConfig(
action.logger,
"`config` input",
inputs.configInput,
validateConfig,
);
const fromConfigFile = await loadUserConfig(
action,
inputs.configFile,
@@ -1104,7 +1102,7 @@ export async function determineUserConfig(
// the CLI or other CodeQL Action steps.
const mergedConfig = mergeDefaultSetupAndUserConfigs(
action.logger,
inputs.configInput,
fromConfigInput,
fromConfigFile,
);
fs.writeFileSync(computedConfigPath, yaml.dump(mergedConfig));
@@ -1124,13 +1122,12 @@ export async function determineUserConfig(
);
}
// Write the `config` input to disk without merging it with a configuration file.
fs.writeFileSync(computedConfigPath, yaml.dump(inputs.configInput));
// Write the `config` input straight to disk.
fs.writeFileSync(computedConfigPath, inputs.configInput);
inputs.configFile = computedConfigPath;
action.logger.debug(
`Using config from action input: ${inputs.configFile}`,
);
return inputs.configInput;
}
}
@@ -1163,11 +1160,9 @@ export async function initConfig(
const { logger, features } = actionState;
const { tempDir } = inputs;
const repositoryRoot = await getGitRoot(inputs.sourceRoot);
const userConfig = await determineUserConfig(actionState, tempDir, inputs);
const config = await initActionState(inputs, userConfig, repositoryRoot);
const config = await initActionState(inputs, userConfig);
// If Code Quality analysis is the only enabled analysis kind, then we will initialise
// the database for Code Quality. That entails disabling the default queries and only
@@ -1249,7 +1244,6 @@ export async function initConfig(
inputs.codeql,
inputs.features,
config.languages,
repositoryRoot,
inputs.sourceRoot,
config.buildMode,
inputs.ramInput,
@@ -1303,7 +1297,6 @@ export async function initConfig(
inputs.codeql,
config.languages,
logger,
repositoryRoot,
);
config.trapCaches = trapCaches;
config.trapCacheDownloadTime = trapCacheDownloadTime;
@@ -1395,86 +1388,31 @@ export function getPathToParsedConfigFile(tempDir: string): string {
return path.join(tempDir, "config");
}
function getPathToFailedConfigFile(tempDir: string): string {
return path.join(tempDir, "failed-config");
}
/**
* Writes {@link config} to {@link configFilePath}.
*
* This function is not intended to be called, other than by
* {@link saveConfig} and {@link saveAbortedInitConfig} below.
* Store the given config to the path returned from getPathToParsedConfigFile.
*/
function saveConfigFile(
logger: Logger,
configFilePath: string,
config: Partial<Config>,
) {
export async function saveConfig(config: Config, logger: Logger) {
const configString = JSON.stringify(config);
fs.mkdirSync(path.dirname(configFilePath), { recursive: true });
fs.writeFileSync(configFilePath, configString, "utf8");
const configFile = getPathToParsedConfigFile(config.tempDir);
fs.mkdirSync(path.dirname(configFile), { recursive: true });
fs.writeFileSync(configFile, configString, "utf8");
logger.debug("Saved config:");
logger.debug(configString);
}
/**
* Store the given config to the path returned from getPathToParsedConfigFile.
* Get the config that has been saved to the given temp dir.
* If the config could not be found then returns undefined.
*/
export async function saveConfig(config: Config, logger: Logger) {
const configFile = getPathToParsedConfigFile(config.tempDir);
saveConfigFile(logger, configFile, config);
}
/**
* Store parts of {@link config} as a failed configuration file.
*
* The file will only contain parts of {@link config} that are relevant to
* the `init-post` step in the workflow.
*/
export function saveAbortedInitConfig(
action: ActionState<["Base", "Logger"]>,
config: Config,
) {
// Should only be called by init.
if (action.name !== ActionName.Init) {
throw new Error(
`Internal error: 'saveAbortedInitConfig' should only be called by '${ActionName.Init}', but was called by '${action.name}'.`,
);
}
// Create a copy of the input `Config` that only contains the keys we want.
const failedConfig: AbortedInitConfig = {
version: config.version,
tempDir: config.tempDir,
codeQLCmd: config.codeQLCmd,
debugMode: config.debugMode,
gitHubVersion: config.gitHubVersion,
languages: config.languages,
analysisKinds: config.analysisKinds,
};
action.logger.debug(`Saving config for failed init step.`);
saveConfigFile(
action.logger,
getPathToFailedConfigFile(config.tempDir),
failedConfig,
);
}
/**
* Attempts to read a {@link Config} from {@link configFilePath}.
*
* This function is not intended to be called, other than by
* {@link getConfig} and {@link getAbortedInitConfig} below.
*/
function readConfigFile(
export async function getConfig(
tempDir: string,
logger: Logger,
configFilePath: string,
): Config | undefined {
if (!fs.existsSync(configFilePath)) {
): Promise<Config | undefined> {
const configFile = getPathToParsedConfigFile(tempDir);
if (!fs.existsSync(configFile)) {
return undefined;
}
const configString = fs.readFileSync(configFilePath, "utf8");
const configString = fs.readFileSync(configFile, "utf8");
logger.debug("Loaded config:");
logger.debug(configString);
@@ -1499,38 +1437,6 @@ function readConfigFile(
return config as Config;
}
/**
* Get the config that has been saved to the given temp dir.
* If the config could not be found then returns undefined.
*/
export async function getConfig(
tempDir: string,
logger: Logger,
): Promise<Config | undefined> {
const configFile = getPathToParsedConfigFile(tempDir);
return readConfigFile(logger, configFile);
}
/**
* Loads a {@link AbortedInitConfig} from a failed `init` step if it exists.
*
* The result will only contain parts of a {@link Config} that are relevant to
* the `init-post` step in the workflow.
*/
export function getAbortedInitConfig(
action: ActionState<["Base", "Logger"]>,
tempDir: string,
): AbortedInitConfig | undefined {
// Only intended to be called by the `init-post` action.
if (action.name !== ActionName.InitPost) {
throw new Error(
`Internal error: 'getAbortedInitConfig' should only be called by '${ActionName.InitPost}', but was called by '${action.name}'.`,
);
}
return readConfigFile(action.logger, getPathToFailedConfigFile(tempDir));
}
/**
* Generate a `qlconfig.yml` file from the `registries` input.
* This file is used by the CodeQL CLI to list the registries to use for each
@@ -1721,27 +1627,21 @@ export function appendExtraQueryExclusions(
/**
* Returns `true` if Code Scanning analysis is enabled, or `false` if not.
*/
export function isCodeScanningEnabled(
config: ActionConfig<"analysisKinds">,
): boolean {
export function isCodeScanningEnabled(config: Config): boolean {
return config.analysisKinds.includes(AnalysisKind.CodeScanning);
}
/**
* Returns `true` if Code Quality analysis is enabled, or `false` if not.
*/
export function isCodeQualityEnabled(
config: ActionConfig<"analysisKinds">,
): boolean {
export function isCodeQualityEnabled(config: Config): boolean {
return config.analysisKinds.includes(AnalysisKind.CodeQuality);
}
/**
* Returns `true` if Code Scanning Risk Assessment analysis is enabled, or `false` if not.
*/
export function isRiskAssessmentEnabled(
config: ActionConfig<"analysisKinds">,
): boolean {
export function isRiskAssessmentEnabled(config: Config): boolean {
return config.analysisKinds.includes(AnalysisKind.RiskAssessment);
}

View File

@@ -16,11 +16,6 @@ export interface Config {
* The version of the CodeQL Action that the configuration is for.
*/
version: string;
/**
* The path at which the repository being analysed is checked out at, if available.
* Persisted in the CodeQL Action configuration state, so that we can consult it in later workflow steps.
*/
repositoryRoot: string | undefined;
/**
* Set of analysis kinds that are enabled.
*/
@@ -131,38 +126,3 @@ export interface Config {
*/
enableFileCoverageInformation: boolean;
}
/** Properties available in `Config`. */
export type ActionConfigProperties = keyof Config;
/**
* The CodeQL Action configuration state that is persisted
* between steps of the CodeQL Action in a CodeQL workflow.
*
* By default, this is equivalent to `Config`. By explicitly
* providing required property names for `T` this can be restricted
* to requiring only those. For example, in `ActionConfig<"codeQLCmd">`
* all properties except `codeqlCmd` are optional.
*/
export type ActionConfig<
T extends ActionConfigProperties = ActionConfigProperties,
> = Partial<Config> & Pick<Config, T>;
/** Helper function to check whether `config` has `key` to narrow the type of `config`. */
export function hasConfigKey<Key extends ActionConfigProperties>(
config: Partial<Config>,
key: Key,
): config is ActionConfig<Key> {
return config[key] !== undefined;
}
/** A minimal configuration that we can make available even when `init` aborts. */
export type AbortedInitConfig = ActionConfig<
| "version"
| "tempDir"
| "gitHubVersion"
| "debugMode"
| "languages"
| "analysisKinds"
| "codeQLCmd"
>;

View File

@@ -625,73 +625,3 @@ test("mergeDefaultSetupAndUserConfigs - warns about invalid keys from Default Se
`Invalid keys in Default Setup configuration: ${expectedInvalidKeys}`,
]);
});
/** Parses `contents` as a configuration without validating it. */
function parseUnvalidatedConfig(contents: string): dbConfig.UserConfig {
return dbConfig.parseUserConfig(
getRunnerLogger(true),
"test",
contents,
false,
);
}
test("matchesDefaultSetupConfigSchema - returns true for configurations that only use Default Setup properties", (t) => {
for (const contents of [
[
"default-setup:",
" org:",
" model-packs: [ github/immutable-actions-list@0.0.1 ]",
"threat-models: [ ]",
].join("\n"),
"threat-models: [ local ]",
"{}",
]) {
t.true(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});
test("matchesDefaultSetupConfigSchema - returns false for configurations that use other properties", (t) => {
for (const contents of [
"queries: [ { uses: ./queries/show_ifs.ql } ]",
"paths-ignore: [ tests ]",
"default-setup: { org: { model-packs: [], queries: [] } }",
]) {
t.false(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});
test("matchesDefaultSetupConfigSchema - returns false for invalid Default Setup properties", (t) => {
for (const contents of [
"threat-models: local",
"default-setup: { org: { model-packs: [ 1 ] } }",
]) {
t.false(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});
test("matchesDefaultSetupConfigSchema - returns false for configurations that aren't mappings", (t) => {
for (const contents of ["- threat-models", "local", "null"]) {
t.false(
dbConfig.matchesDefaultSetupConfigSchema(
parseUnvalidatedConfig(contents),
),
contents,
);
}
});

View File

@@ -33,15 +33,6 @@ export interface QuerySpec {
uses: string;
}
// A set of default query suite names that are understood by the CLI.
export const defaultSuites: Set<string> = new Set([
"security-experimental",
"security-extended",
"security-and-quality",
"code-quality",
"code-scanning",
]);
const ORG_SCHEMA = {
/** An array of model pack names. */
"model-packs": json.optional(json.array(json.string)),
@@ -86,11 +77,7 @@ export interface UserConfig {
"default-setup"?: DefaultSetupConfig;
}
/**
* A subset of the `UserConfig` schema that is known to be used by Default Setup. None of these
* properties may add queries, since a per-language CodeQL bundle can be used with a `config` input
* that only sets them.
*/
/** A subset of the `UserConfig` schema that is used by Default Setup. */
const DEFAULT_SETUP_CONFIG_SCHEMA = {
"threat-models": json.optional(json.array(json.string)),
"default-setup": json.optional<DefaultSetupConfig>(
@@ -98,24 +85,6 @@ const DEFAULT_SETUP_CONFIG_SCHEMA = {
),
} as const satisfies json.Schema;
/**
* Returns whether `config` matches what we expect Default Setup to send in the `config` input: a
* mapping that only sets properties in `DEFAULT_SETUP_CONFIG_SCHEMA`, with values of the expected
* types.
*/
export function matchesDefaultSetupConfigSchema(config: UserConfig): boolean {
// Unless validation is enabled, `parseUserConfig` doesn't check that the YAML is a mapping.
if (!json.isObject(config)) {
return false;
}
const result = json.checkSchema(
DEFAULT_SETUP_CONFIG_SCHEMA,
config as json.UnvalidatedObject<any>,
);
// `valid` doesn't account for unknown properties.
return result.valid && result.unknownKeys.length === 0;
}
/**
* Merges supported properties from two configuration files. This is intended only for
* use with merging the `config` input provided by Default Setup with a potentially
@@ -468,60 +437,63 @@ export async function calculateAugmentation(
languages,
packsInputCombines,
);
const queries = parseQueriesFromInput(rawQueriesInput);
const repoPropertyQueries = parseQueriesFromInput(
repositoryProperties[RepositoryPropertyName.EXTRA_QUERIES],
RepositoryPropertyName.EXTRA_QUERIES,
const queriesInputCombines = shouldCombine(rawQueriesInput);
const queriesInput = parseQueriesFromInput(
rawQueriesInput,
queriesInputCombines,
);
const repoExtraQueries =
repositoryProperties[RepositoryPropertyName.EXTRA_QUERIES];
const repoExtraQueriesCombines = shouldCombine(repoExtraQueries);
const repoPropertyQueries = {
combines: repoExtraQueriesCombines,
input: parseQueriesFromInput(
repoExtraQueries,
repoExtraQueriesCombines,
new ConfigurationError(
errorMessages.getRepoPropertyError(
RepositoryPropertyName.EXTRA_QUERIES,
errorMessages.getEmptyCombinesError(),
),
),
),
};
return {
packsInputCombines,
packsInput: packsInput?.[languages[0]],
queriesInput: queries.input,
queriesInputCombines: queries.combines,
queriesInput,
queriesInputCombines,
repoPropertyQueries,
};
}
/**
* Parses a comma-separated list of queries, which may have a '+' prefix. Entries aren't validated,
* so an empty entry becomes `{ uses: "" }`.
*
* @param value The list of queries.
* @param repositoryProperty The repository property that `value` comes from, if any. Error messages
* refer to this property, or to the `queries` input if no property is given.
* @returns An `Augmentation` containing the parsed queries and whether `value` has a '+' prefix.
* The queries are `undefined` if `value` is unset or empty.
* @throws A `ConfigurationError` if `value` is a '+' with no queries after it.
*/
export function parseQueriesFromInput(
value: string | undefined,
repositoryProperty?: RepositoryPropertyName,
): Augmentation<QuerySpec[]> {
if (!value) {
return { combines: false, input: undefined };
function parseQueriesFromInput(
rawQueriesInput: string | undefined,
queriesInputCombines: boolean,
errorToThrow?: ConfigurationError,
) {
if (!rawQueriesInput) {
return undefined;
}
const combines = shouldCombine(value);
const trimmedInput = combines ? value.trim().slice(1).trim() : value.trim();
if (combines && trimmedInput.length === 0) {
const trimmedInput = queriesInputCombines
? rawQueriesInput.trim().slice(1).trim()
: (rawQueriesInput?.trim() ?? "");
if (queriesInputCombines && trimmedInput.length === 0) {
if (errorToThrow) {
throw errorToThrow;
}
throw new ConfigurationError(
repositoryProperty !== undefined
? errorMessages.getRepoPropertyError(
repositoryProperty,
errorMessages.getEmptyCombinesError(),
)
: errorMessages.getConfigFilePropertyError(
undefined,
"queries",
"A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs.",
),
errorMessages.getConfigFilePropertyError(
undefined,
"queries",
"A '+' was used in the 'queries' input to specify that you wished to add some packs to your CodeQL analysis. However, no packs were specified. Please either remove the '+' or specify some packs.",
),
);
}
return {
combines,
input: trimmedInput.split(",").map((query) => ({ uses: query.trim() })),
};
return trimmedInput.split(",").map((query) => ({ uses: query.trim() }));
}
/**
@@ -638,13 +610,11 @@ export function generateCodeScanningConfig(
* Attempts to parse `contents` into a `UserConfig` value.
*
* @param logger The logger to use.
* @param pathInput Where `contents` came from, such as the path to a file, for use in error messages.
* @param contents The YAML to try and parse as a `UserConfig`.
* @param validateConfig Whether to validate the configuration against the schema.
* @returns The `UserConfig` corresponding to `contents`, if parsing was successful. Unless
* `validateConfig` is set, the result might not be a mapping.
* @throws A `ConfigurationError` if `contents` isn't valid YAML or, when `validateConfig` is set,
* isn't a valid configuration.
* @param pathInput The path to the file where `contents` was obtained from, for use in error messages.
* @param contents The string contents of a YAML file to try and parse as a `UserConfig`.
* @param validateConfig Whether to validate the configuration file against the schema.
* @returns The `UserConfig` corresponding to `contents`, if parsing was successful.
* @throws A `ConfigurationError` if parsing failed.
*/
export function parseUserConfig(
logger: Logger,

View File

@@ -1,5 +1,4 @@
import fs from "fs";
import path from "path";
import * as fs from "fs";
import * as github from "@actions/github";
import test from "ava";
@@ -11,11 +10,7 @@ import { GitHubApiDetails } from "./api-client";
import * as apiClient from "./api-client";
import { createStubCodeQL } from "./codeql";
import { Config } from "./config-utils";
import {
cleanupAndUploadDatabases,
uploadBundledDatabase,
} from "./database-upload";
import { getEnv } from "./environment";
import { cleanupAndUploadDatabases } from "./database-upload";
import { Feature } from "./feature-flags";
import * as gitUtils from "./git-utils";
import { BuiltInLanguage } from "./languages";
@@ -28,16 +23,21 @@ import {
getTestEnv,
initAllState,
RecordingLogger,
SAMPLE_DOTCOM_API_DETAILS,
setupActionsVars,
setupTests,
} from "./testing-utils";
import { CleanupLevel, GitHubVariant, HTTPError, withTmpDir } from "./util";
import {
CleanupLevel,
GitHubVariant,
HTTPError,
initializeEnvironment,
withTmpDir,
} from "./util";
setupTests(test);
test.beforeEach(() => {
getEnv().initialise("1.2.3");
initializeEnvironment("1.2.3");
});
const testRepoName: RepositoryNwo = { owner: "github", repo: "example" };
@@ -550,86 +550,3 @@ test.serial(
});
},
);
test.serial(
"uploadBundledDatabase provides expected request arguments",
async (t) =>
withTmpDir(async (tmpDir) => {
// Write some file that `uploadBundledDatabase` can use for its `fs.createReadStream(bundledDb)` call
// so we don't have to stub that or create a fake `ReadStream`.
const dbPath = path.join(tmpDir, "db");
const content = JSON.stringify({});
fs.writeFileSync(dbPath, content);
// A simple stub for `fetch` that satisfies Octokit when it inspects the response.
const fetchStub = sinon.stub().resolves({
status: 200,
headers: new Headers(),
text: async () => "",
});
// Construct a real `ApiClient`.
const client = apiClient.getApiClient(
getTestEnv(),
SAMPLE_DOTCOM_API_DETAILS,
);
// Then wrap the real `request` method in a stub that calls it with our stubbed `fetch`.
// This ensures that we have a real `ApiClient` with a mostly real `request`, but which
// does not perform any actual requests.
const request = client.request;
sinon.stub(client, "request").callsFake(async (route, options) =>
request(route, {
...options,
request: { ...options?.request, fetch: fetchStub },
}),
);
// Stub `getApiClient` to return our modified `ApiClient`.
const getApiClient = sinon
.stub(apiClient, "getApiClient")
.returns(client);
// Calling `uploadBundledDatabase` shouldn't throw.
const nwo: RepositoryNwo = { owner: "test", repo: "foo" };
const language: BuiltInLanguage = BuiltInLanguage.java;
await t.notThrowsAsync(async () => {
await uploadBundledDatabase(
nwo,
language,
"123",
dbPath,
content.length,
SAMPLE_DOTCOM_API_DETAILS,
);
});
// Check that our stubs were called and that they received the expected arguments.
t.is(getApiClient.callCount, 1);
t.is(fetchStub.callCount, 1);
const args = fetchStub.args[0];
t.is(args.length, 2);
const url = args[0];
t.is(
url,
`https://uploads.github.com/repos/${nwo.owner}/${nwo.repo}/code-scanning/codeql/databases/${language}?name=${language}-database&commit_oid=123`,
);
const options = args[1];
t.like(options, {
// Going via `new Headers` and `Object.fromEntries` ensures we get the same cases
// for the header keys as we are given.
headers: Object.fromEntries(
new Headers({
authorization: `token ${SAMPLE_DOTCOM_API_DETAILS.auth}`,
"Content-Type": "application/zip",
"Content-Length": content.length.toString(),
}).entries(),
),
method: "POST",
} satisfies RequestInit);
}),
);

View File

@@ -12,12 +12,11 @@ import { type CodeQL } from "./codeql";
import { Config } from "./config-utils";
import { Feature } from "./feature-flags";
import * as gitUtils from "./git-utils";
import { parseGitHubUrl } from "./github";
import { Logger, withGroupAsync } from "./logging";
import { OverlayDatabaseMode } from "./overlay/overlay-database-mode";
import { RepositoryNwo } from "./repository";
import * as util from "./util";
import { asHTTPError, bundleDb, CleanupLevel } from "./util";
import { asHTTPError, bundleDb, CleanupLevel, parseGitHubUrl } from "./util";
/** Information about a database upload. */
export interface DatabaseUploadResult {
@@ -47,7 +46,7 @@ export interface DatabaseUploadResult {
}
export async function cleanupAndUploadDatabases(
action: ActionState<["ReadOnlyEnv", "Logger", "FeatureFlags"]>,
action: ActionState<["Logger", "FeatureFlags"]>,
repositoryNwo: RepositoryNwo,
codeql: CodeQL,
config: Config,
@@ -82,7 +81,7 @@ export async function cleanupAndUploadDatabases(
return [];
}
if (!(await gitUtils.isAnalyzingDefaultBranch(action.env, checkoutPath))) {
if (!(await gitUtils.isAnalyzingDefaultBranch())) {
// We only want to upload a database if we are analyzing the default branch.
logger.debug("Not analyzing default branch. Skipping upload.");
return [];
@@ -114,7 +113,7 @@ export async function cleanupAndUploadDatabases(
includeDiagnostics: false,
});
bundledDbSize = fs.statSync(bundledDb).size;
const commitOid = await gitUtils.getCommitOid(action.env, checkoutPath);
const commitOid = await gitUtils.getCommitOid(checkoutPath);
// Upload with manual retry logic. We disable Octokit's built-in retries
// because the request body is a ReadStream, which can only be consumed
// once.
@@ -259,7 +258,7 @@ async function recordClearCleanupSizes(
*
* @returns the duration of the upload in milliseconds
*/
export async function uploadBundledDatabase(
async function uploadBundledDatabase(
repositoryNwo: RepositoryNwo,
language: string,
commitOid: string,
@@ -267,10 +266,7 @@ export async function uploadBundledDatabase(
bundledDbSize: number,
apiDetails: GitHubApiDetails,
): Promise<number> {
// Ensure that the `apiDetails` that `getApiClient` uses match the ones we were given here,
// because we use `apiDetails.auth` below which must be used with the same instance that
// `apiDetails` refers to.
const client = getApiClient(util.getEnv(), apiDetails);
const client = getApiClient();
const uploadsUrl = new URL(parseGitHubUrl(apiDetails.url));
uploadsUrl.hostname = `uploads.${uploadsUrl.hostname}`;
@@ -296,6 +292,7 @@ export async function uploadBundledDatabase(
commit_oid: commitOid,
data: bundledDbReadStream,
headers: {
authorization: `token ${apiDetails.auth}`,
"Content-Type": "application/zip",
"Content-Length": bundledDbSize,
},

View File

@@ -55,20 +55,25 @@ test("getArtifactSuffix", (t) => {
}
});
// These next tests check whether `uploadArtifacts` attempts to upload an artifact. Since it's not
// easy to mock the actual call to upload an artifact, we check that we get an "upload-failed"
// result, instead of actually uploading the artifact.
// These next tests check the correctness of the logic to determine whether or not
// artifacts are uploaded in debug mode. Since it's not easy to mock the actual
// call to upload an artifact, we just check that we get an "upload-failed" result,
// instead of actually uploading the artifact.
//
// For tests where we expect artifact upload to be blocked, we check for a different
// response from the function.
test("uploadArtifacts returns 'no-artifacts-to-upload' when there are no files to upload", async (t) => {
test("uploadDebugArtifacts when artifacts empty should emit 'no-artifacts-to-upload'", async (t) => {
// Test that no error is thrown if artifacts list is empty.
const logger = getActionsLogger();
await t.notThrowsAsync(async () => {
const uploaded = await debugArtifacts.uploadArtifacts(
const uploaded = await debugArtifacts.uploadDebugArtifacts(
logger,
[],
"i-dont-exist",
"artifactName",
GitHubVariant.DOTCOM,
undefined,
);
t.is(
uploaded,
@@ -78,15 +83,17 @@ test("uploadArtifacts returns 'no-artifacts-to-upload' when there are no files t
});
});
test("uploadArtifacts attempts an upload when there are files to upload", async (t) => {
test("uploadDebugArtifacts when no codeql version is used should invoke artifact upload", async (t) => {
// Test that the artifact is uploaded.
const logger = getActionsLogger();
await t.notThrowsAsync(async () => {
const uploaded = await debugArtifacts.uploadArtifacts(
const uploaded = await debugArtifacts.uploadDebugArtifacts(
logger,
["hucairz"],
"i-dont-exist",
"artifactName",
GitHubVariant.DOTCOM,
undefined,
);
t.is(
uploaded,
@@ -96,3 +103,44 @@ test("uploadArtifacts attempts an upload when there are files to upload", async
);
});
});
test("uploadDebugArtifacts when new codeql version is used should invoke artifact upload", async (t) => {
// Test that the artifact is uploaded.
const logger = getActionsLogger();
await t.notThrowsAsync(async () => {
const uploaded = await debugArtifacts.uploadDebugArtifacts(
logger,
["hucairz"],
"i-dont-exist",
"artifactName",
GitHubVariant.DOTCOM,
"2.20.3",
);
t.is(
uploaded,
// The failure is expected since we don't want to actually upload any artifacts in unit tests.
"upload-failed",
"Expect failure to upload artifacts since root dir does not exist",
);
});
});
test("uploadDebugArtifacts when old codeql is used should avoid trying to upload artifacts", async (t) => {
// Test that the artifact is not uploaded.
const logger = getActionsLogger();
await t.notThrowsAsync(async () => {
const uploaded = await debugArtifacts.uploadDebugArtifacts(
logger,
["hucairz"],
"i-dont-exist",
"artifactName",
GitHubVariant.DOTCOM,
"2.20.2",
);
t.is(
uploaded,
"upload-not-supported",
"Expected artifact upload to be blocked because of old CodeQL version",
);
});
});

View File

@@ -10,11 +10,15 @@ import { getOptionalInput, getTemporaryDirectory } from "./actions-util";
import { dbIsFinalized } from "./analyze";
import { scanArtifactsForTokens } from "./artifact-scanner";
import { type CodeQL } from "./codeql";
import type { ActionConfig } from "./config/action-config";
import { EnvVar, exportEnvVar } from "./environment";
import { Config } from "./config-utils";
import { EnvVar } from "./environment";
import * as json from "./json";
import { Language } from "./languages";
import { Logger, withGroup } from "./logging";
import {
isSafeArtifactUpload,
SafeArtifactUploadVersion,
} from "./tools-features";
import {
bundleDb,
doesDirectoryExist,
@@ -36,6 +40,7 @@ export function sanitizeArtifactName(name: string): string {
export async function uploadCombinedSarifArtifacts(
logger: Logger,
gitHubVariant: GitHubVariant,
codeQlVersion: string | undefined,
) {
const tempDir = getTemporaryDirectory();
@@ -65,12 +70,13 @@ export async function uploadCombinedSarifArtifacts(
}
try {
await uploadArtifacts(
await uploadDebugArtifacts(
logger,
toUpload,
baseTempDir,
"combined-sarif-artifacts",
gitHubVariant,
codeQlVersion,
);
} catch (e) {
logger.warning(
@@ -89,7 +95,7 @@ export async function uploadCombinedSarifArtifacts(
* @return The path to that debug artifact, or undefined if an error occurs.
*/
function tryPrepareSarifDebugArtifact(
config: ActionConfig<"dbLocation">,
config: Config,
language: Language,
logger: Logger,
): string | undefined {
@@ -131,7 +137,7 @@ function tryPrepareSarifDebugArtifact(
*/
async function tryBundleDatabase(
codeql: CodeQL,
config: ActionConfig<"dbLocation">,
config: Config,
language: Language,
logger: Logger,
): Promise<string | undefined> {
@@ -157,11 +163,6 @@ async function tryBundleDatabase(
}
}
/** The minimal configuration needed for `tryUploadAllAvailableDebugArtifacts`. */
export type UploadDebugArtifactsConfig = ActionConfig<
"languages" | "gitHubVersion" | "dbLocation" | "debugArtifactName"
>;
/**
* Attempt to upload all available debug artifacts.
*
@@ -169,8 +170,9 @@ export type UploadDebugArtifactsConfig = ActionConfig<
*/
export async function tryUploadAllAvailableDebugArtifacts(
codeql: CodeQL,
config: UploadDebugArtifactsConfig,
config: Config,
logger: Logger,
codeQlVersion: string | undefined,
) {
const filesToUpload: string[] = [];
try {
@@ -229,12 +231,13 @@ export async function tryUploadAllAvailableDebugArtifacts(
try {
await withGroup("Uploading debug artifacts", async () =>
uploadArtifacts(
uploadDebugArtifacts(
logger,
filesToUpload,
config.dbLocation,
config.debugArtifactName,
config.gitHubVersion.type,
codeQlVersion,
),
);
} catch (e) {
@@ -280,6 +283,26 @@ export type UploadArtifactsResult =
| "upload-successful"
| "upload-failed";
export async function uploadDebugArtifacts(
logger: Logger,
toUpload: string[],
rootDir: string,
artifactName: string,
ghVariant: GitHubVariant,
codeQlVersion: string | undefined,
): Promise<UploadArtifactsResult | "upload-not-supported"> {
const uploadSupported = isSafeArtifactUpload(codeQlVersion);
if (!uploadSupported) {
core.info(
`Skipping debug artifact upload because the current CLI does not support safe upload. Please upgrade to CLI v${SafeArtifactUploadVersion} or later.`,
);
return "upload-not-supported";
}
return uploadArtifacts(logger, toUpload, rootDir, artifactName, ghVariant);
}
/**
* Uploads the specified files as a single workflow artifact.
*
@@ -307,7 +330,7 @@ export async function uploadArtifacts(
// some issues early.
if (isInTestMode()) {
await scanArtifactsForTokens(toUpload, logger);
exportEnvVar("CODEQL_ACTION_ARTIFACT_SCAN_FINISHED", "true");
core.exportVariable("CODEQL_ACTION_ARTIFACT_SCAN_FINISHED", "true");
}
const suffix = getArtifactSuffix(getOptionalInput("matrix"));
@@ -358,7 +381,7 @@ export async function getArtifactUploaderClient(
* all files in the database folder and return the path.
*/
async function createPartialDatabaseBundle(
config: ActionConfig<"dbLocation">,
config: Config,
language: Language,
): Promise<string> {
const databasePath = getCodeQLDatabasePath(config, language);
@@ -399,7 +422,7 @@ async function createPartialDatabaseBundle(
*/
async function createDatabaseBundleCli(
codeql: CodeQL,
config: ActionConfig<"dbLocation">,
config: Config,
language: Language,
): Promise<string> {
const databaseBundlePath = await bundleDb(

View File

@@ -1,6 +1,6 @@
{
"bundleVersion": "codeql-bundle-v2.27.2",
"cliVersion": "2.27.2",
"priorBundleVersion": "codeql-bundle-v2.27.1",
"priorCliVersion": "2.27.1"
"bundleVersion": "codeql-bundle-v2.27.1",
"cliVersion": "2.27.1",
"priorBundleVersion": "codeql-bundle-v2.27.0",
"priorCliVersion": "2.27.0"
}

View File

@@ -313,7 +313,6 @@ export async function downloadDependencyCaches(
const primaryKey = await cacheKey(codeql, features, language, patterns);
const restoreKeys: string[] = [
primaryKey,
await cachePrefix(codeql, features, language),
];

View File

@@ -1,12 +0,0 @@
import test from "ava";
import { Env, ReadOnlyEnv } from "./environment";
import { getTestEnv, setupTests } from "./testing-utils";
setupTests(test);
test("isTestingEnv() is true", (t) => {
t.true(new ReadOnlyEnv(process.env).isTestingEnv());
t.true(new Env(process.env).isTestingEnv());
t.true(getTestEnv().isTestingEnv());
});

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