Compare commits

..

21 Commits

Author SHA1 Message Date
Julien HENRY f55d92a8a1 SQSCANGHA-149 Add scannerBinariesAuthHeader input for authenticated binary downloads
Organisations using private Artifactory mirrors require authentication to
download the SonarScanner CLI. This adds an optional scannerBinariesAuthHeader
input whose value is forwarded as the Authorization HTTP header to both the
binary and GPG signature downloads via tc.downloadTool's built-in auth
parameter. No new dependencies are introduced.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-29 16:40:55 +02:00
SonarTech 7006c4492b Update SonarScanner CLI to 8.1.0.6389 2026-05-19 09:24:23 +02:00
dependabot[bot] edd319f284 NO-JIRA Bump actions/setup-node from 6.3.0 to 6.4.0 (#234)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-19 09:23:47 +02:00
dependabot[bot] e050aa9e69 NO-JIRA Bump actions/cache from 5.0.4 to 5.0.5 (#231)
Signed-off-by: dependabot[bot] <support@github.com>
2026-05-19 09:23:25 +02:00
dependabot[bot] 6cd3d8f2ae NO-JIRA Bump madhead/semver-utils from 4.3.0 to 5.0.0
Bumps [madhead/semver-utils](https://github.com/madhead/semver-utils) from 4.3.0 to 5.0.0.
- [Release notes](https://github.com/madhead/semver-utils/releases)
- [Commits](https://github.com/madhead/semver-utils/compare/36d1e0ed361bd7b4b77665de8093092eaeabe6ba...4cf918affe9106ea59f86c6250e5ec4570ac4389)

---
updated-dependencies:
- dependency-name: madhead/semver-utils
  dependency-version: 5.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2026-05-19 09:20:24 +02:00
Julien HENRY 56568530ed SQSCANGHA-146 Add proxy support for GPG keyserver access (#244)
Co-authored-by: Marius Boden <marius.boden@xebia.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-19 09:11:36 +02:00
Claire Villard c444753899 SQSCANGHA-140 Add the missing requirements in README.md (#243) 2026-05-11 12:13:30 +02:00
Antoine Vinot 59db25f34e SQSCANGHA-145 Set skipSignatureVerification default value to false (#241) 2026-04-29 14:23:12 +02:00
Pavel Mikula ca30b65f4e SQSCANGHA-143 SubmitReview: Use Vault token (#238) 2026-04-29 11:16:25 +02:00
Antoine Vinot c7ee0f9df9 SQSCANGHA-140 Set skipSignatureVerification default value to true to avoid breaking change (#240)
Co-authored-by: Gustavo Cunha <dev@gustavocunha.dev>
2026-04-29 10:13:05 +02:00
Claire Villard 55e44800a8 SQSCANGHA-140 Add OpenPGP signature verification for scanner downloads (#235) 2026-04-28 15:49:48 +02:00
Antoine Vinot 30dbe5c9ee SQSCANGHA-138 Update dist and add ci test (#233)
Co-authored-by: Jarek Potiuk <jarek@potiuk.com>
2026-04-23 14:20:12 +02:00
Claire Villard c8357220fa SQSCANGHA-134 Upgrade the libraries to latest version (#227)
Co-authored-by: Julien Carsique <julien.carsique@sonarsource.com>
2026-04-14 15:21:19 +02:00
Claire Villard f00de44f57 SC-45750 Migrate to dateless license headers (#229) 2026-04-10 13:57:27 +02:00
Claire Villard f099b44166 SQSCANGHA-133 Upgrade the Node version used in UTs + contribution guide (#226) 2026-04-03 10:34:00 +02:00
tomverin d899ed2996 BUILD-10861 Dependabot 5-day cooldown + internal excludes (#225) 2026-04-02 15:07:08 +02:00
Claire Villard 299e4b793a SQSCANGHA-132 Upgrade Node to 24 (#224) 2026-04-01 11:14:54 +02:00
dependabot[bot] 3988e54db2 SQSCANGHA-131 Bump picomatch from 4.0.3 to 4.0.4 (#223)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-31 08:58:59 +02:00
dependabot[bot] 9598b8a83f SQSCANGHA-130 Bump rollup from 4.50.1 to 4.59.0 (#221)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-03-06 10:07:15 +01:00
dependabot[bot] dcc5211de5 SQSCANGHA-128 NO-JIRA Bump actions/cache from 4 to 5 (#219)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-02-16 20:53:44 +01:00
Claire Villard b9f37f9de0 SQSCANGHA-129 Fix the Analysis Processing team name in CODEOWNERS (#220)
Co-authored-by: Claude Sonnet 4.5 <noreply@anthropic.com>
2026-02-11 11:37:16 +01:00
52 changed files with 22382 additions and 14178 deletions
+1 -1
View File
@@ -1 +1 @@
.github/* @sonarsource/orchestration-processing-squad
.github/* @sonarsource/quality-processing-squad
+4
View File
@@ -12,5 +12,9 @@ updates:
interval: "daily"
timezone: "CET"
open-pull-requests-limit: 100
cooldown:
default-days: 5
exclude:
- "SonarSource/*"
commit-message:
prefix: "NO-JIRA "
+2 -2
View File
@@ -10,7 +10,6 @@ jobs:
runs-on: github-ubuntu-latest-s
permissions:
id-token: write
pull-requests: read
# For external PR, ticket should be moved manually
if: |
github.event.pull_request.head.repo.full_name == github.repository
@@ -21,10 +20,11 @@ jobs:
uses: SonarSource/vault-action-wrapper@v3
with:
secrets: |
development/github/token/{REPO_OWNER_NAME_DASH}-jira token | GITHUB_TOKEN;
development/kv/data/jira user | JIRA_USER;
development/kv/data/jira token | JIRA_TOKEN;
- uses: sonarsource/gh-action-lt-backlog/SubmitReview@v2
with:
github-token: ${{secrets.GITHUB_TOKEN}}
github-token: ${{ fromJSON(steps.secrets.outputs.vault).GITHUB_TOKEN }}
jira-user: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_USER }}
jira-token: ${{ fromJSON(steps.secrets.outputs.vault).JIRA_TOKEN }}
+1 -1
View File
@@ -34,7 +34,7 @@ jobs:
exit 1
fi
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
@@ -34,7 +34,7 @@ jobs:
exit 1
fi
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
+24 -24
View File
@@ -17,7 +17,7 @@ jobs:
os: [github-ubuntu-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action without args
@@ -37,7 +37,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
@@ -66,7 +66,7 @@ jobs:
]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
@@ -93,7 +93,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
@@ -121,7 +121,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
@@ -148,7 +148,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with args
@@ -178,7 +178,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- run: mkdir -p ./baseDir
@@ -198,7 +198,7 @@ jobs:
'scannerVersion' input
runs-on: github-ubuntu-latest-s # assumes default RUNNER_ARCH for linux is X64
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with scannerVersion
@@ -222,7 +222,7 @@ jobs:
'scannerBinariesUrl' input with invalid URL
runs-on: github-ubuntu-latest-s # assumes default RUNNER_ARCH for linux is X64
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with scannerBinariesUrl
@@ -250,7 +250,7 @@ jobs:
'scannerBinariesUrl' is escaped with wget so special chars are not injected in the download command
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with scannerBinariesUrl
@@ -271,7 +271,7 @@ jobs:
'scannerBinariesUrl' is escaped with curl so special chars are not injected in the download command
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Remove wget
@@ -300,7 +300,7 @@ jobs:
Don't fail on Gradle project
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action on Gradle project
@@ -321,7 +321,7 @@ jobs:
Don't fail on Kotlin Gradle project
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action on Kotlin Gradle project
@@ -342,7 +342,7 @@ jobs:
Don't fail on Maven project
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action on Maven project
@@ -375,7 +375,7 @@ jobs:
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action on sample project
@@ -398,7 +398,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with debug mode
@@ -429,11 +429,11 @@ jobs:
--health-timeout 5s
--health-retries 10
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: SonarQube Cache
uses: actions/cache@v4
uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
with:
path: ${{ github.workspace }}/.sonar/cache
key: ${{ runner.os }}-${{ runner.arch }}-sonar
@@ -458,7 +458,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with SONARCLOUD_URL
@@ -477,7 +477,7 @@ jobs:
curl performs redirect when scannerBinariesUrl returns 3xx
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Remove wget
@@ -521,7 +521,7 @@ jobs:
os: [github-ubuntu-latest-s, github-windows-latest-s, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with SSL certificate
@@ -572,7 +572,7 @@ jobs:
Analysis takes into account 'SONAR_ROOT_CERT'
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Generate server certificate
@@ -680,7 +680,7 @@ jobs:
truststore.p12 is updated when present
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Create SONAR_SSL_FOLDER with a file in it (not-truststore.p12)
@@ -809,7 +809,7 @@ jobs:
'scannerVersion' input validation
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Run action with invalid scannerVersion
+4 -4
View File
@@ -12,7 +12,7 @@ jobs:
name: create_install_path.sh
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
@@ -123,7 +123,7 @@ jobs:
SONAR_SCANNER_URL_MACOSX_AARCH64: 'https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-vX.Y.Z.MMMM-macosx-aarch64.zip'
SONAR_SCANNER_SHA_MACOSX_AARCH64: 'DOWNLOAD-SHA-MACOSX-AARCH64'
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
@@ -252,7 +252,7 @@ jobs:
name: download.sh
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
@@ -321,7 +321,7 @@ jobs:
name: fetch_latest_version.sh
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- name: Test script
+21 -4
View File
@@ -7,19 +7,36 @@ on:
jobs:
test:
runs-on: ubuntu-latest
runs-on: github-ubuntu-latest-s
permissions:
id-token: write
contents: read
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Setup Node.js
uses: actions/setup-node@v6
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e #v6.4.0
with:
node-version: "20"
node-version: "24"
cache: "npm"
- name: Configure NPM with Repox
uses: SonarSource/ci-github-actions/config-npm@v1
- name: Install dependencies
run: npm ci
- name: Build
run: npm run build
- name: Check dist/ is up-to-date
run: |
if ! git diff --exit-code dist/ || [ -n "$(git status --porcelain dist/)" ]; then
echo "::error::dist/ is out of date. Run 'npm run build' and commit the changes."
git status --short dist/
exit 1
fi
- name: Run tests
run: npm test
+2 -2
View File
@@ -13,10 +13,10 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v5
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Parse semver
uses: madhead/semver-utils@36d1e0ed361bd7b4b77665de8093092eaeabe6ba # v4.3.0
uses: madhead/semver-utils@4cf918affe9106ea59f86c6250e5ec4570ac4389 # v5.0.0
id: version
with:
version: ${{ github.ref_name }}
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
new-version: ${{ steps.latest-version.outputs.sonar-scanner-version }}
steps:
- run: sudo apt install -y jq
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: master
fetch-depth: 0
@@ -49,7 +49,7 @@ jobs:
pull-requests: write
if: needs.check-version.outputs.should_update == 'true'
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
ref: master
persist-credentials: true
+22
View File
@@ -0,0 +1,22 @@
# Path to sources
sonar.sources=src
sonar.exclusions=src/**/__tests__/*
# sonar.inclusions=
# Path to tests
sonar.tests=test,src
# sonar.test.exclusions=
sonar.test.inclusions=src/**/__tests__/*
# Source encoding
# sonar.sourceEncoding=
# Exclusions for copy-paste detection
# sonar.cpd.exclusions=
# Python version (for python projects only)
# sonar.python.version=
# C++ standard version (for C++ projects only)
# If not specified, it defaults to the latest supported standard
# sonar.cfamily.reportingCppStandardOverride=c++98|c++11|c++14|c++17|c++20
+40 -5
View File
@@ -55,7 +55,7 @@ jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
# Disabling shallow clones is recommended for improving the relevancy of reporting
fetch-depth: 0
@@ -200,6 +200,39 @@ This can be useful when the runner executing the action is self-hosted and has r
scannerBinariesUrl: https://my.custom.binaries.url.com/Distribution/sonar-scanner-cli/
```
#### `scannerBinariesAuthHeader`
If the server specified by `scannerBinariesUrl` requires authentication, you can provide an `Authorization` header value using the `scannerBinariesAuthHeader` option.
The value is passed directly as the `Authorization` HTTP header, so you must include the scheme (e.g. `Bearer`, `Basic`):
```yaml
- uses: SonarSource/sonarqube-scan-action@<action version>
with:
scannerBinariesUrl: https://my.custom.binaries.url.com/Distribution/sonar-scanner-cli/
scannerBinariesAuthHeader: ${{ secrets.BINARIES_AUTH_HEADER }}
```
Store the full header value (e.g. `Bearer mytoken`) in the GitHub secret to avoid exposing credentials.
#### `skipSignatureVerification`
By default, the action verifies the OpenPGP signature of the SonarScanner CLI binary before executing it. You can disable this verification using the `skipSignatureVerification` option:
```yaml
- uses: SonarSource/sonarqube-scan-action@<action version>
with:
skipSignatureVerification: true
```
> [!NOTE]
> Signature verification requires `gpg` and `dirmngr` to be installed on the runner. GitHub-hosted runners include both, but some self-hosted runners or containers may not.
>
> If your runner accesses the internet through a proxy, the action automatically picks up the `HTTPS_PROXY` or `https_proxy` environment variable when fetching the public key from the keyserver. `HTTP_PROXY` is intentionally not used as a fallback, since keyservers are accessed over TLS (`hkps://`).
>
> **Version history:**
> - Introduced in **v7.2** with a default value of `true` to avoid breaking existing workflows on runners without `dirmngr`.
> - Changed to `false` by default in **v8** (breaking change). If your runner does not have `gpg` or `dirmngr` installed, set this option to `true` explicitly.
More information about possible analysis parameters can be found:
* in the [Analysis parameters page](https://docs.sonarsource.com/sonarqube-server/latest/analyzing-source-code/analysis-parameters/) of the SonarQube Server documentation
* in the [Analysis parameters page](https://docs.sonarsource.com/sonarqube-cloud/advanced-setup/analysis-parameters/) of the SonarQube Cloud documentation
@@ -273,7 +306,7 @@ jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
# Disabling shallow clones is recommended for improving the relevancy of reporting
fetch-depth: 0
@@ -305,7 +338,7 @@ jobs:
env:
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
# Disabling shallow clone is recommended for improving relevancy of reporting
fetch-depth: 0
@@ -366,7 +399,7 @@ jobs:
sonarqube:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
# Disabling shallow clones is recommended for improving the relevancy of reporting
fetch-depth: 0
@@ -406,7 +439,7 @@ jobs:
env:
BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
with:
# Disabling shallow clone is recommended for improving relevancy of reporting
fetch-depth: 0
@@ -452,6 +485,8 @@ When running the action in a self-hosted runner or container, please ensure that
* **curl** or **wget**
* **unzip**
* **gpg**
* **dirmngr**
### Additional information
+13 -2
View File
@@ -19,11 +19,22 @@ inputs:
description: Version of the Sonar Scanner CLI to use
required: false
# to be kept in sync with sonar-scanner-version
default: 8.0.1.6346
default: 8.1.0.6389
scannerBinariesUrl:
description: URL to download the Sonar Scanner CLI binaries from
required: false
default: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli
skipSignatureVerification:
description: Skip GPG signature verification (not recommended for security)
required: false
default: "false"
scannerBinariesAuthHeader:
description: >
Authorization header value to use when downloading the SonarScanner CLI binaries
(e.g. 'Bearer mytoken' or 'Basic base64creds'). Use this when scannerBinariesUrl
points to a private server that requires authentication.
required: false
default: ""
runs:
using: node20
using: node24
main: dist/index.js
+1 -1
View File
@@ -32,7 +32,7 @@ Both the main action and the secondary _install-build-wrapper_ action are [Javas
### Requirements
Make sure you have node 20 & npm installed. We recommend using [nvm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#using-a-node-version-manager-to-install-nodejs-and-npm) for that.
Make sure you have node 24 & npm installed. We recommend using [nvm](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#using-a-node-version-manager-to-install-nodejs-and-npm) for that.
### Building & testing
+1 -1
View File
@@ -71,7 +71,7 @@ runs:
- name: Cache sonar-scanner installation
id: cache-sonar-tools
if: inputs.cache-binaries == 'true'
uses: actions/cache@v4
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4
env:
# The default value is 60mins. Reaching timeout is treated the same as a cache miss.
SEGMENT_DOWNLOAD_TIMEOUT_MINS: 1
-1
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
View File
File diff suppressed because one or more lines are too long
+4062 -2479
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
File diff suppressed because one or more lines are too long
+64 -23
View File
@@ -1,4 +1,4 @@
import { f as execExports, e as coreExports } from './exec-BTlTa8sL.js';
import { f as execExports, h as addPath, a as info, o as setOutput, j as setFailed, p as startGroup, q as endGroup } from './exec-BeYcktvA.js';
import * as fs from 'fs';
import * as path from 'path';
import 'os';
@@ -10,25 +10,47 @@ import 'tls';
import 'events';
import 'assert';
import 'util';
import 'stream';
import 'buffer';
import 'querystring';
import 'stream/web';
import 'node:assert';
import 'node:net';
import 'node:http';
import 'node:stream';
import 'node:buffer';
import 'node:util';
import 'node:querystring';
import 'node:events';
import 'worker_threads';
import 'perf_hooks';
import 'util/types';
import 'async_hooks';
import 'console';
import 'url';
import 'zlib';
import 'node:diagnostics_channel';
import 'node:tls';
import 'node:zlib';
import 'node:perf_hooks';
import 'node:util/types';
import 'node:worker_threads';
import 'node:url';
import 'node:async_hooks';
import 'node:console';
import 'node:dns';
import 'string_decoder';
import 'diagnostics_channel';
import 'child_process';
import 'timers';
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/**
* Compute all names and paths related to the build wrapper
* based on the runner environment
@@ -125,9 +147,28 @@ async function getRealPath(filePath, runnerOS) {
}
}
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
async function installMacOSPackages() {
if (process.platform === "darwin") {
coreExports.info("Installing required packages for macOS");
info("Installing required packages for macOS");
await execExports.exec("brew", ["install", "coreutils"]);
}
}
@@ -158,9 +199,9 @@ async function downloadAndInstallBuildWrapper(downloadUrl, runnerEnv) {
`build-wrapper-${runnerOS}-${runnerArch}.zip`
);
coreExports.startGroup(`Download ${downloadUrl}`);
startGroup(`Download ${downloadUrl}`);
coreExports.info(`Downloading '${downloadUrl}'`);
info(`Downloading '${downloadUrl}'`);
if (!fs.existsSync(runnerTemp)) {
fs.mkdirSync(runnerTemp, { recursive: true });
@@ -168,10 +209,10 @@ async function downloadAndInstallBuildWrapper(downloadUrl, runnerEnv) {
await execExports.exec("curl", ["-sSLo", tmpZipPath, downloadUrl]);
coreExports.info("Decompressing");
info("Decompressing");
await execExports.exec("unzip", ["-o", "-d", runnerTemp, tmpZipPath]);
coreExports.endGroup();
endGroup();
}
async function run() {
@@ -189,17 +230,17 @@ async function run() {
buildWrapperDir,
envVariables.runnerOS
);
coreExports.addPath(buildWrapperBinDir);
coreExports.info(`'${buildWrapperBinDir}' added to the path`);
addPath(buildWrapperBinDir);
info(`'${buildWrapperBinDir}' added to the path`);
const buildWrapperBinPath = await getRealPath(
buildWrapperBin,
envVariables.runnerOS
);
coreExports.setOutput("build-wrapper-binary", buildWrapperBinPath);
coreExports.info(`'build-wrapper-binary' output set to '${buildWrapperBinPath}'`);
setOutput("build-wrapper-binary", buildWrapperBinPath);
info(`'build-wrapper-binary' output set to '${buildWrapperBinPath}'`);
} catch (error) {
coreExports.setFailed(error.message);
setFailed(error.message);
}
}
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -9,5 +9,5 @@ outputs:
build-wrapper-binary:
description: "Absolute path to Build Wrapper binary."
runs:
using: node20
using: node24
main: ../dist/install-build-wrapper.js
+370 -274
View File
@@ -9,88 +9,114 @@
"version": "6.0.0",
"license": "LGPL-3.0-only",
"dependencies": {
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"@actions/tool-cache": "2.0.2",
"@actions/core": "3.0.0",
"@actions/exec": "2.0.0",
"@actions/github": "9.0.0",
"@actions/tool-cache": "4.0.0",
"string-argv": "0.3.2"
},
"devDependencies": {
"@rollup/plugin-commonjs": "28.0.6",
"@rollup/plugin-node-resolve": "16.0.1",
"@rollup/plugin-commonjs": "29.0.2",
"@rollup/plugin-node-resolve": "16.0.3",
"mock-fs": "5.5.0",
"rollup": "4.50.1"
"rollup": "4.60.1"
}
},
"node_modules/@actions/core": {
"version": "1.11.1",
"resolved": "https://registry.npmjs.org/@actions/core/-/core-1.11.1.tgz",
"integrity": "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A==",
"version": "3.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/core/-/core-3.0.0.tgz",
"integrity": "sha512-zYt6cz+ivnTmiT/ksRVriMBOiuoUpDCJJlZ5KPl2/FRdvwU3f7MPh9qftvbkXJThragzUZieit2nyHUyw53Seg==",
"license": "MIT",
"dependencies": {
"@actions/exec": "^1.1.1",
"@actions/http-client": "^2.0.1"
"@actions/exec": "^3.0.0",
"@actions/http-client": "^4.0.0"
}
},
"node_modules/@actions/core/node_modules/@actions/exec": {
"version": "3.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/exec/-/exec-3.0.0.tgz",
"integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==",
"license": "MIT",
"dependencies": {
"@actions/io": "^3.0.2"
}
},
"node_modules/@actions/exec": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@actions/exec/-/exec-1.1.1.tgz",
"integrity": "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w==",
"version": "2.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/exec/-/exec-2.0.0.tgz",
"integrity": "sha512-k8ngrX2voJ/RIN6r9xB82NVqKpnMRtxDoiO+g3olkIUpQNqjArXrCQceduQZCQj3P3xm32pChRLqRrtXTlqhIw==",
"license": "MIT",
"dependencies": {
"@actions/io": "^1.0.1"
"@actions/io": "^2.0.0"
}
},
"node_modules/@actions/exec/node_modules/@actions/io": {
"version": "2.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/io/-/io-2.0.0.tgz",
"integrity": "sha512-Jv33IN09XLO+0HS79aaODsvIRyduiF7NY/F6LYeK5oeUmrsz7aFdRphQjFoESF4jS7lMauDOttKALcpapVDIAg==",
"license": "MIT"
},
"node_modules/@actions/github": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/@actions/github/-/github-6.0.1.tgz",
"integrity": "sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw==",
"version": "9.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/github/-/github-9.0.0.tgz",
"integrity": "sha512-yJ0RoswsAaKcvkmpCE4XxBRiy/whH2SdTBHWzs0gi4wkqTDhXMChjSdqBz/F4AeiDlP28rQqL33iHb+kjAMX6w==",
"license": "MIT",
"dependencies": {
"@actions/http-client": "^2.2.0",
"@octokit/core": "^5.0.1",
"@octokit/plugin-paginate-rest": "^9.2.2",
"@octokit/plugin-rest-endpoint-methods": "^10.4.0",
"@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.1.1",
"undici": "^5.28.5"
"@actions/http-client": "^3.0.2",
"@octokit/core": "^7.0.6",
"@octokit/plugin-paginate-rest": "^14.0.0",
"@octokit/plugin-rest-endpoint-methods": "^17.0.0",
"@octokit/request": "^10.0.7",
"@octokit/request-error": "^7.1.0",
"undici": "^6.23.0"
}
},
"node_modules/@actions/http-client": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.2.3.tgz",
"integrity": "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA==",
"node_modules/@actions/github/node_modules/@actions/http-client": {
"version": "3.0.2",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/http-client/-/http-client-3.0.2.tgz",
"integrity": "sha512-JP38FYYpyqvUsz+Igqlc/JG6YO9PaKuvqjM3iGvaLqFnJ7TFmcLyy2IDrY0bI0qCQug8E9K+elv5ZNfw62ZJzA==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^5.25.4"
"undici": "^6.23.0"
}
},
"node_modules/@actions/http-client": {
"version": "4.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/http-client/-/http-client-4.0.0.tgz",
"integrity": "sha512-QuwPsgVMsD6qaPD57GLZi9sqzAZCtiJT8kVBCDpLtxhL5MydQ4gS+DrejtZZPdIYyB1e95uCK9Luyds7ybHI3g==",
"license": "MIT",
"dependencies": {
"tunnel": "^0.0.6",
"undici": "^6.23.0"
}
},
"node_modules/@actions/io": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@actions/io/-/io-1.1.3.tgz",
"integrity": "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q==",
"version": "3.0.2",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/io/-/io-3.0.2.tgz",
"integrity": "sha512-nRBchcMM+QK1pdjO7/idu86rbJI5YHUKCvKs0KxnSYbVe3F51UfGxuZX4Qy/fWlp6l7gWFwIkrOzN+oUK03kfw==",
"license": "MIT"
},
"node_modules/@actions/tool-cache": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.2.tgz",
"integrity": "sha512-fBhNNOWxuoLxztQebpOaWu6WeVmuwa77Z+DxIZ1B+OYvGkGQon6kTVg6Z32Cb13WCuw0szqonK+hh03mJV7Z6w==",
"version": "4.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/tool-cache/-/tool-cache-4.0.0.tgz",
"integrity": "sha512-L8P9HbXvpvqjZDveb/fdsa55IVC0trfPgQ4ZwGo6r5af6YDVdM9vMGPZ7rgY2fAT9gGj4PSYd6bYlg3p3jD78A==",
"license": "MIT",
"dependencies": {
"@actions/core": "^1.11.1",
"@actions/exec": "^1.0.0",
"@actions/http-client": "^2.0.1",
"@actions/io": "^1.1.1",
"semver": "^6.1.0"
"@actions/core": "^3.0.0",
"@actions/exec": "^3.0.0",
"@actions/http-client": "^4.0.0",
"@actions/io": "^3.0.0",
"semver": "^7.7.3"
}
},
"node_modules/@fastify/busboy": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz",
"integrity": "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==",
"node_modules/@actions/tool-cache/node_modules/@actions/exec": {
"version": "3.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@actions/exec/-/exec-3.0.0.tgz",
"integrity": "sha512-6xH/puSoNBXb72VPlZVm7vQ+svQpFyA96qdDBvhB8eNZOE8LtPf9L4oAsfzK/crCL8YZ+19fKYVnM63Sl+Xzlw==",
"license": "MIT",
"engines": {
"node": ">=14"
"dependencies": {
"@actions/io": "^3.0.2"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
@@ -101,167 +127,137 @@
"license": "MIT"
},
"node_modules/@octokit/auth-token": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-4.0.0.tgz",
"integrity": "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA==",
"version": "6.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/auth-token/-/auth-token-6.0.0.tgz",
"integrity": "sha512-P4YJBPdPSpWTQ1NU4XYdvHvXJJDxM6YwpS0FZHRgP7YFkdVxsWcpWGy/NVqlAA7PcPCnMacXlRm1y2PFZRWL/w==",
"license": "MIT",
"engines": {
"node": ">= 18"
"node": ">= 20"
}
},
"node_modules/@octokit/core": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/@octokit/core/-/core-5.2.2.tgz",
"integrity": "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg==",
"version": "7.0.6",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/core/-/core-7.0.6.tgz",
"integrity": "sha512-DhGl4xMVFGVIyMwswXeyzdL4uXD5OGILGX5N8Y+f6W7LhC1Ze2poSNrkF/fedpVDHEEZ+PHFW0vL14I+mm8K3Q==",
"license": "MIT",
"dependencies": {
"@octokit/auth-token": "^4.0.0",
"@octokit/graphql": "^7.1.0",
"@octokit/request": "^8.4.1",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.0.0",
"before-after-hook": "^2.2.0",
"universal-user-agent": "^6.0.0"
"@octokit/auth-token": "^6.0.0",
"@octokit/graphql": "^9.0.3",
"@octokit/request": "^10.0.6",
"@octokit/request-error": "^7.0.2",
"@octokit/types": "^16.0.0",
"before-after-hook": "^4.0.0",
"universal-user-agent": "^7.0.0"
},
"engines": {
"node": ">= 18"
"node": ">= 20"
}
},
"node_modules/@octokit/endpoint": {
"version": "9.0.6",
"resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-9.0.6.tgz",
"integrity": "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw==",
"version": "11.0.3",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/endpoint/-/endpoint-11.0.3.tgz",
"integrity": "sha512-FWFlNxghg4HrXkD3ifYbS/IdL/mDHjh9QcsNyhQjN8dplUoZbejsdpmuqdA76nxj2xoWPs7p8uX2SNr9rYu0Ag==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
"@octokit/types": "^16.0.0",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
"node": ">= 20"
}
},
"node_modules/@octokit/graphql": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-7.1.1.tgz",
"integrity": "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g==",
"version": "9.0.3",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/graphql/-/graphql-9.0.3.tgz",
"integrity": "sha512-grAEuupr/C1rALFnXTv6ZQhFuL1D8G5y8CN04RgrO4FIPMrtm+mcZzFG7dcBm+nq+1ppNixu+Jd78aeJOYxlGA==",
"license": "MIT",
"dependencies": {
"@octokit/request": "^8.4.1",
"@octokit/types": "^13.0.0",
"universal-user-agent": "^6.0.0"
"@octokit/request": "^10.0.6",
"@octokit/types": "^16.0.0",
"universal-user-agent": "^7.0.0"
},
"engines": {
"node": ">= 18"
"node": ">= 20"
}
},
"node_modules/@octokit/openapi-types": {
"version": "24.2.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-24.2.0.tgz",
"integrity": "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg==",
"version": "27.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/openapi-types/-/openapi-types-27.0.0.tgz",
"integrity": "sha512-whrdktVs1h6gtR+09+QsNk2+FO+49j6ga1c55YZudfEG+oKJVvJLQi3zkOm5JjiUXAagWK2tI2kTGKJ2Ys7MGA==",
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-9.2.2.tgz",
"integrity": "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ==",
"version": "14.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-14.0.0.tgz",
"integrity": "sha512-fNVRE7ufJiAA3XUrha2omTA39M6IXIc6GIZLvlbsm8QOQCYvpq/LkMNGyFlB1d8hTDzsAXa3OKtybdMAYsV/fw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^12.6.0"
"@octokit/types": "^16.0.0"
},
"engines": {
"node": ">= 18"
"node": ">= 20"
},
"peerDependencies": {
"@octokit/core": "5"
}
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
"license": "MIT"
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
"@octokit/core": ">=6"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "10.4.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-10.4.1.tgz",
"integrity": "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg==",
"version": "17.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-17.0.0.tgz",
"integrity": "sha512-B5yCyIlOJFPqUUeiD0cnBJwWJO8lkJs5d8+ze9QDP6SvfiXSz1BF+91+0MeI1d2yxgOhU/O+CvtiZ9jSkHhFAw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^12.6.0"
"@octokit/types": "^16.0.0"
},
"engines": {
"node": ">= 18"
"node": ">= 20"
},
"peerDependencies": {
"@octokit/core": "5"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
"version": "20.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-20.0.0.tgz",
"integrity": "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA==",
"license": "MIT"
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
"version": "12.6.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-12.6.0.tgz",
"integrity": "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^20.0.0"
"@octokit/core": ">=6"
}
},
"node_modules/@octokit/request": {
"version": "8.4.1",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-8.4.1.tgz",
"integrity": "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw==",
"version": "10.0.8",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/request/-/request-10.0.8.tgz",
"integrity": "sha512-SJZNwY9pur9Agf7l87ywFi14W+Hd9Jg6Ifivsd33+/bGUQIjNujdFiXII2/qSlN2ybqUHfp5xpekMEjIBTjlSw==",
"license": "MIT",
"dependencies": {
"@octokit/endpoint": "^9.0.6",
"@octokit/request-error": "^5.1.1",
"@octokit/types": "^13.1.0",
"universal-user-agent": "^6.0.0"
"@octokit/endpoint": "^11.0.3",
"@octokit/request-error": "^7.0.2",
"@octokit/types": "^16.0.0",
"fast-content-type-parse": "^3.0.0",
"json-with-bigint": "^3.5.3",
"universal-user-agent": "^7.0.2"
},
"engines": {
"node": ">= 18"
"node": ">= 20"
}
},
"node_modules/@octokit/request-error": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-5.1.1.tgz",
"integrity": "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g==",
"version": "7.1.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/request-error/-/request-error-7.1.0.tgz",
"integrity": "sha512-KMQIfq5sOPpkQYajXHwnhjCC0slzCNScLHs9JafXc4RAJI+9f+jNDlBNaIMTvazOPLgb4BnlhGJOTbnN0wIjPw==",
"license": "MIT",
"dependencies": {
"@octokit/types": "^13.1.0",
"deprecation": "^2.0.0",
"once": "^1.4.0"
"@octokit/types": "^16.0.0"
},
"engines": {
"node": ">= 18"
"node": ">= 20"
}
},
"node_modules/@octokit/types": {
"version": "13.10.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-13.10.0.tgz",
"integrity": "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA==",
"version": "16.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@octokit/types/-/types-16.0.0.tgz",
"integrity": "sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==",
"license": "MIT",
"dependencies": {
"@octokit/openapi-types": "^24.2.0"
"@octokit/openapi-types": "^27.0.0"
}
},
"node_modules/@rollup/plugin-commonjs": {
"version": "28.0.6",
"resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-28.0.6.tgz",
"integrity": "sha512-XSQB1K7FUU5QP+3lOQmVCE3I0FcbbNvmNT4VJSj93iUjayaARrTQeoRdiYQoftAJBLrR9t2agwAd3ekaTgHNlw==",
"version": "29.0.2",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/plugin-commonjs/-/plugin-commonjs-29.0.2.tgz",
"integrity": "sha512-S/ggWH1LU7jTyi9DxZOKyxpVd4hF/OZ0JrEbeLjXk/DFXwRny0tjD2c992zOUYQobLrVkRVMDdmHP16HKP7GRg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -286,9 +282,9 @@
}
},
"node_modules/@rollup/plugin-node-resolve": {
"version": "16.0.1",
"resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.1.tgz",
"integrity": "sha512-tk5YCxJWIG81umIvNkSod2qK5KyQW19qcBF/B78n1bjtOON6gzKoVeSzAE8yHCZEDmqkHKkxplExA8KzdJLJpA==",
"version": "16.0.3",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/plugin-node-resolve/-/plugin-node-resolve-16.0.3.tgz",
"integrity": "sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -334,9 +330,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.50.1.tgz",
"integrity": "sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.1.tgz",
"integrity": "sha512-d6FinEBLdIiK+1uACUttJKfgZREXrF0Qc2SmLII7W2AD8FfiZ9Wjd+rD/iRuf5s5dWrr1GgwXCvPqOuDquOowA==",
"cpu": [
"arm"
],
@@ -348,9 +344,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.50.1.tgz",
"integrity": "sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.1.tgz",
"integrity": "sha512-YjG/EwIDvvYI1YvYbHvDz/BYHtkY4ygUIXHnTdLhG+hKIQFBiosfWiACWortsKPKU/+dUwQQCKQM3qrDe8c9BA==",
"cpu": [
"arm64"
],
@@ -362,9 +358,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.50.1.tgz",
"integrity": "sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.1.tgz",
"integrity": "sha512-mjCpF7GmkRtSJwon+Rq1N8+pI+8l7w5g9Z3vWj4T7abguC4Czwi3Yu/pFaLvA3TTeMVjnu3ctigusqWUfjZzvw==",
"cpu": [
"arm64"
],
@@ -376,9 +372,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.50.1.tgz",
"integrity": "sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.1.tgz",
"integrity": "sha512-haZ7hJ1JT4e9hqkoT9R/19XW2QKqjfJVv+i5AGg57S+nLk9lQnJ1F/eZloRO3o9Scy9CM3wQ9l+dkXtcBgN5Ew==",
"cpu": [
"x64"
],
@@ -390,9 +386,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-arm64": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.50.1.tgz",
"integrity": "sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.1.tgz",
"integrity": "sha512-czw90wpQq3ZsAVBlinZjAYTKduOjTywlG7fEeWKUA7oCmpA8xdTkxZZlwNJKWqILlq0wehoZcJYfBvOyhPTQ6w==",
"cpu": [
"arm64"
],
@@ -404,9 +400,9 @@
]
},
"node_modules/@rollup/rollup-freebsd-x64": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.50.1.tgz",
"integrity": "sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.1.tgz",
"integrity": "sha512-KVB2rqsxTHuBtfOeySEyzEOB7ltlB/ux38iu2rBQzkjbwRVlkhAGIEDiiYnO2kFOkJp+Z7pUXKyrRRFuFUKt+g==",
"cpu": [
"x64"
],
@@ -418,13 +414,16 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.50.1.tgz",
"integrity": "sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.1.tgz",
"integrity": "sha512-L+34Qqil+v5uC0zEubW7uByo78WOCIrBvci69E7sFASRl0X7b/MB6Cqd1lky/CtcSVTydWa2WZwFuWexjS5o6g==",
"cpu": [
"arm"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -432,13 +431,16 @@
]
},
"node_modules/@rollup/rollup-linux-arm-musleabihf": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.50.1.tgz",
"integrity": "sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.1.tgz",
"integrity": "sha512-n83O8rt4v34hgFzlkb1ycniJh7IR5RCIqt6mz1VRJD6pmhRi0CXdmfnLu9dIUS6buzh60IvACM842Ffb3xd6Gg==",
"cpu": [
"arm"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -446,13 +448,16 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.50.1.tgz",
"integrity": "sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.1.tgz",
"integrity": "sha512-Nql7sTeAzhTAja3QXeAI48+/+GjBJ+QmAH13snn0AJSNL50JsDqotyudHyMbO2RbJkskbMbFJfIJKWA6R1LCJQ==",
"cpu": [
"arm64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -460,27 +465,50 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.50.1.tgz",
"integrity": "sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.1.tgz",
"integrity": "sha512-+pUymDhd0ys9GcKZPPWlFiZ67sTWV5UU6zOJat02M1+PiuSGDziyRuI/pPue3hoUwm2uGfxdL+trT6Z9rxnlMA==",
"cpu": [
"arm64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loongarch64-gnu": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.50.1.tgz",
"integrity": "sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==",
"node_modules/@rollup/rollup-linux-loong64-gnu": {
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.1.tgz",
"integrity": "sha512-VSvgvQeIcsEvY4bKDHEDWcpW4Yw7BtlKG1GUT4FzBUlEKQK0rWHYBqQt6Fm2taXS+1bXvJT6kICu5ZwqKCnvlQ==",
"cpu": [
"loong64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-loong64-musl": {
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.1.tgz",
"integrity": "sha512-4LqhUomJqwe641gsPp6xLfhqWMbQV04KtPp7/dIp0nzPxAkNY1AbwL5W0MQpcalLYk07vaW9Kp1PBhdpZYYcEw==",
"cpu": [
"loong64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -488,13 +516,33 @@
]
},
"node_modules/@rollup/rollup-linux-ppc64-gnu": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.50.1.tgz",
"integrity": "sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.1.tgz",
"integrity": "sha512-tLQQ9aPvkBxOc/EUT6j3pyeMD6Hb8QF2BTBnCQWP/uu1lhc9AIrIjKnLYMEroIz/JvtGYgI9dF3AxHZNaEH0rw==",
"cpu": [
"ppc64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-linux-ppc64-musl": {
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.1.tgz",
"integrity": "sha512-RMxFhJwc9fSXP6PqmAz4cbv3kAyvD1etJFjTx4ONqFP9DkTkXsAMU4v3Vyc5BgzC+anz7nS/9tp4obsKfqkDHg==",
"cpu": [
"ppc64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -502,13 +550,16 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.50.1.tgz",
"integrity": "sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.1.tgz",
"integrity": "sha512-QKgFl+Yc1eEk6MmOBfRHYF6lTxiiiV3/z/BRrbSiW2I7AFTXoBFvdMEyglohPj//2mZS4hDOqeB0H1ACh3sBbg==",
"cpu": [
"riscv64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -516,13 +567,16 @@
]
},
"node_modules/@rollup/rollup-linux-riscv64-musl": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.50.1.tgz",
"integrity": "sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.1.tgz",
"integrity": "sha512-RAjXjP/8c6ZtzatZcA1RaQr6O1TRhzC+adn8YZDnChliZHviqIjmvFwHcxi4JKPSDAt6Uhf/7vqcBzQJy0PDJg==",
"cpu": [
"riscv64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
@@ -530,13 +584,16 @@
]
},
"node_modules/@rollup/rollup-linux-s390x-gnu": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.50.1.tgz",
"integrity": "sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.1.tgz",
"integrity": "sha512-wcuocpaOlaL1COBYiA89O6yfjlp3RwKDeTIA0hM7OpmhR1Bjo9j31G1uQVpDlTvwxGn2nQs65fBFL5UFd76FcQ==",
"cpu": [
"s390x"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -544,13 +601,16 @@
]
},
"node_modules/@rollup/rollup-linux-x64-gnu": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.50.1.tgz",
"integrity": "sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.1.tgz",
"integrity": "sha512-77PpsFQUCOiZR9+LQEFg9GClyfkNXj1MP6wRnzYs0EeWbPcHs02AXu4xuUbM1zhwn3wqaizle3AEYg5aeoohhg==",
"cpu": [
"x64"
],
"dev": true,
"libc": [
"glibc"
],
"license": "MIT",
"optional": true,
"os": [
@@ -558,9 +618,26 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.50.1.tgz",
"integrity": "sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.1.tgz",
"integrity": "sha512-5cIATbk5vynAjqqmyBjlciMJl1+R/CwX9oLk/EyiFXDWd95KpHdrOJT//rnUl4cUcskrd0jCCw3wpZnhIHdD9w==",
"cpu": [
"x64"
],
"dev": true,
"libc": [
"musl"
],
"license": "MIT",
"optional": true,
"os": [
"linux"
]
},
"node_modules/@rollup/rollup-openbsd-x64": {
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.1.tgz",
"integrity": "sha512-cl0w09WsCi17mcmWqqglez9Gk8isgeWvoUZ3WiJFYSR3zjBQc2J5/ihSjpl+VLjPqjQ/1hJRcqBfLjssREQILw==",
"cpu": [
"x64"
],
@@ -568,13 +645,13 @@
"license": "MIT",
"optional": true,
"os": [
"linux"
"openbsd"
]
},
"node_modules/@rollup/rollup-openharmony-arm64": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.50.1.tgz",
"integrity": "sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.1.tgz",
"integrity": "sha512-4Cv23ZrONRbNtbZa37mLSueXUCtN7MXccChtKpUnQNgF010rjrjfHx3QxkS2PI7LqGT5xXyYs1a7LbzAwT0iCA==",
"cpu": [
"arm64"
],
@@ -586,9 +663,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.50.1.tgz",
"integrity": "sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.1.tgz",
"integrity": "sha512-i1okWYkA4FJICtr7KpYzFpRTHgy5jdDbZiWfvny21iIKky5YExiDXP+zbXzm3dUcFpkEeYNHgQ5fuG236JPq0g==",
"cpu": [
"arm64"
],
@@ -600,9 +677,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.50.1.tgz",
"integrity": "sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.1.tgz",
"integrity": "sha512-u09m3CuwLzShA0EYKMNiFgcjjzwqtUMLmuCJLeZWjjOYA3IT2Di09KaxGBTP9xVztWyIWjVdsB2E9goMjZvTQg==",
"cpu": [
"ia32"
],
@@ -613,10 +690,24 @@
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-gnu": {
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.1.tgz",
"integrity": "sha512-k+600V9Zl1CM7eZxJgMyTUzmrmhB/0XZnF4pRypKAlAgxmedUA+1v9R+XOFv56W4SlHEzfeMtzujLJD22Uz5zg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.50.1.tgz",
"integrity": "sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.1.tgz",
"integrity": "sha512-lWMnixq/QzxyhTV6NjQJ4SFo1J6PvOX8vUx5Wb4bBPsEb+8xZ89Bz6kOXpfXj9ak9AHTQVQzlgzBEc1SyM27xQ==",
"cpu": [
"x64"
],
@@ -642,9 +733,9 @@
"license": "MIT"
},
"node_modules/before-after-hook": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
"integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==",
"version": "4.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/before-after-hook/-/before-after-hook-4.0.0.tgz",
"integrity": "sha512-q6tR3RPqIB1pMiTRMFcZwuG5T8vwp+vUvEG0vuI6B+Rikh5BfPp2fQ82c925FOs+b0lcFQ8CFrL+KbilfZFhOQ==",
"license": "Apache-2.0"
},
"node_modules/commondir": {
@@ -664,12 +755,6 @@
"node": ">=0.10.0"
}
},
"node_modules/deprecation": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
"integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ==",
"license": "ISC"
},
"node_modules/estree-walker": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
@@ -677,6 +762,22 @@
"dev": true,
"license": "MIT"
},
"node_modules/fast-content-type-parse": {
"version": "3.0.0",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/fast-content-type-parse/-/fast-content-type-parse-3.0.0.tgz",
"integrity": "sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/fastify"
},
{
"type": "opencollective",
"url": "https://opencollective.com/fastify"
}
],
"license": "MIT"
},
"node_modules/fdir": {
"version": "6.5.0",
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
@@ -766,6 +867,12 @@
"@types/estree": "*"
}
},
"node_modules/json-with-bigint": {
"version": "3.5.8",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/json-with-bigint/-/json-with-bigint-3.5.8.tgz",
"integrity": "sha512-eq/4KP6K34kwa7TcFdtvnftvHCD9KvHOGGICWwMFc4dOOKF5t4iYqnfLK8otCRCRv06FXOzGGyqE8h8ElMvvdw==",
"license": "MIT"
},
"node_modules/magic-string": {
"version": "0.30.18",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.18.tgz",
@@ -786,15 +893,6 @@
"node": ">=12.0.0"
}
},
"node_modules/once": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
"license": "ISC",
"dependencies": {
"wrappy": "1"
}
},
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
@@ -803,9 +901,9 @@
"license": "MIT"
},
"node_modules/picomatch": {
"version": "4.0.3",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -837,9 +935,9 @@
}
},
"node_modules/rollup": {
"version": "4.50.1",
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.50.1.tgz",
"integrity": "sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==",
"version": "4.60.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/rollup/-/rollup-4.60.1.tgz",
"integrity": "sha512-VmtB2rFU/GroZ4oL8+ZqXgSA38O6GR8KSIvWmEFv63pQ0G6KaBH9s07PO8XTXP4vI+3UJUEypOfjkGfmSBBR0w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -853,37 +951,44 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
"@rollup/rollup-android-arm-eabi": "4.50.1",
"@rollup/rollup-android-arm64": "4.50.1",
"@rollup/rollup-darwin-arm64": "4.50.1",
"@rollup/rollup-darwin-x64": "4.50.1",
"@rollup/rollup-freebsd-arm64": "4.50.1",
"@rollup/rollup-freebsd-x64": "4.50.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.50.1",
"@rollup/rollup-linux-arm-musleabihf": "4.50.1",
"@rollup/rollup-linux-arm64-gnu": "4.50.1",
"@rollup/rollup-linux-arm64-musl": "4.50.1",
"@rollup/rollup-linux-loongarch64-gnu": "4.50.1",
"@rollup/rollup-linux-ppc64-gnu": "4.50.1",
"@rollup/rollup-linux-riscv64-gnu": "4.50.1",
"@rollup/rollup-linux-riscv64-musl": "4.50.1",
"@rollup/rollup-linux-s390x-gnu": "4.50.1",
"@rollup/rollup-linux-x64-gnu": "4.50.1",
"@rollup/rollup-linux-x64-musl": "4.50.1",
"@rollup/rollup-openharmony-arm64": "4.50.1",
"@rollup/rollup-win32-arm64-msvc": "4.50.1",
"@rollup/rollup-win32-ia32-msvc": "4.50.1",
"@rollup/rollup-win32-x64-msvc": "4.50.1",
"@rollup/rollup-android-arm-eabi": "4.60.1",
"@rollup/rollup-android-arm64": "4.60.1",
"@rollup/rollup-darwin-arm64": "4.60.1",
"@rollup/rollup-darwin-x64": "4.60.1",
"@rollup/rollup-freebsd-arm64": "4.60.1",
"@rollup/rollup-freebsd-x64": "4.60.1",
"@rollup/rollup-linux-arm-gnueabihf": "4.60.1",
"@rollup/rollup-linux-arm-musleabihf": "4.60.1",
"@rollup/rollup-linux-arm64-gnu": "4.60.1",
"@rollup/rollup-linux-arm64-musl": "4.60.1",
"@rollup/rollup-linux-loong64-gnu": "4.60.1",
"@rollup/rollup-linux-loong64-musl": "4.60.1",
"@rollup/rollup-linux-ppc64-gnu": "4.60.1",
"@rollup/rollup-linux-ppc64-musl": "4.60.1",
"@rollup/rollup-linux-riscv64-gnu": "4.60.1",
"@rollup/rollup-linux-riscv64-musl": "4.60.1",
"@rollup/rollup-linux-s390x-gnu": "4.60.1",
"@rollup/rollup-linux-x64-gnu": "4.60.1",
"@rollup/rollup-linux-x64-musl": "4.60.1",
"@rollup/rollup-openbsd-x64": "4.60.1",
"@rollup/rollup-openharmony-arm64": "4.60.1",
"@rollup/rollup-win32-arm64-msvc": "4.60.1",
"@rollup/rollup-win32-ia32-msvc": "4.60.1",
"@rollup/rollup-win32-x64-gnu": "4.60.1",
"@rollup/rollup-win32-x64-msvc": "4.60.1",
"fsevents": "~2.3.2"
}
},
"node_modules/semver": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"version": "7.7.4",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/string-argv": {
@@ -918,27 +1023,18 @@
}
},
"node_modules/undici": {
"version": "5.29.0",
"resolved": "https://registry.npmjs.org/undici/-/undici-5.29.0.tgz",
"integrity": "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg==",
"version": "6.24.1",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/undici/-/undici-6.24.1.tgz",
"integrity": "sha512-sC+b0tB1whOCzbtlx20fx3WgCXwkW627p4EA9uM+/tNNPkSS+eSEld6pAs9nDv7WbY1UUljBMYPtu9BCOrCWKA==",
"license": "MIT",
"dependencies": {
"@fastify/busboy": "^2.0.0"
},
"engines": {
"node": ">=14.0"
"node": ">=18.17"
}
},
"node_modules/universal-user-agent": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.1.tgz",
"integrity": "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ==",
"license": "ISC"
},
"node_modules/wrappy": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"version": "7.0.3",
"resolved": "https://repox.jfrog.io/artifactory/api/npm/npm/universal-user-agent/-/universal-user-agent-7.0.3.tgz",
"integrity": "sha512-TmnEAEAsBJVZM/AADELsK76llnwcf9vMKuPz8JflO1frO8Lchitr0fNaN9d+Ap0BjKtqWqd/J17qeDnXh8CL2A==",
"license": "ISC"
}
}
+8 -7
View File
@@ -6,19 +6,20 @@
"main": "src/main/index.js",
"scripts": {
"build": "rollup --config rollup.config.js",
"test": "node --test"
"test": "node --experimental-test-module-mocks --test"
},
"license": "LGPL-3.0-only",
"dependencies": {
"@actions/core": "1.11.1",
"@actions/github": "6.0.1",
"@actions/tool-cache": "2.0.2",
"@actions/core": "3.0.0",
"@actions/exec": "2.0.0",
"@actions/github": "9.0.0",
"@actions/tool-cache": "4.0.0",
"string-argv": "0.3.2"
},
"devDependencies": {
"@rollup/plugin-commonjs": "28.0.6",
"@rollup/plugin-node-resolve": "16.0.1",
"@rollup/plugin-commonjs": "29.0.2",
"@rollup/plugin-node-resolve": "16.0.3",
"mock-fs": "5.5.0",
"rollup": "4.50.1"
"rollup": "4.60.1"
}
}
+33 -1
View File
@@ -1,6 +1,38 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import { readFileSync } from "node:fs";
import commonjs from "@rollup/plugin-commonjs";
import { nodeResolve } from "@rollup/plugin-node-resolve";
// Ensures CRLF line endings from a Windows checkout don't leak into the
// bundle or the source map's sourcesContent, so the build is reproducible
// across operating systems. Uses `load` rather than `transform` so the
// normalized text is also what Rollup embeds in sourcesContent.
const normalizeLineEndings = {
name: "normalize-line-endings",
load(id) {
if (id.startsWith("\0") || id.includes("?")) return null;
const code = readFileSync(id, "utf8");
return code.includes("\r") ? code.replaceAll("\r\n", "\n") : null;
},
};
const config = {
input: [
"src/main/index.js",
@@ -12,7 +44,7 @@ const config = {
format: "es",
sourcemap: true,
},
plugins: [commonjs(), nodeResolve({ preferBuiltins: true })],
plugins: [normalizeLineEndings, commonjs(), nodeResolve({ preferBuiltins: true })],
};
export default config;
+18
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
if [[ -n "${SONAR_ROOT_CERT}" ]]; then
echo "Adding custom root certificate to java certificate store"
rm -f /tmp/tmpcert.pem
+18
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
if [[ ${ARCH} != "X64" && ! (${ARCH} == "ARM64" && (${OS} == "macOS" || ${OS} == "Linux")) ]]; then
echo "::error::Architecture '${ARCH}' is unsupported by build-wrapper"
exit 1
+18
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
source "$(dirname -- "$0")/utils.sh"
echo "Installation path is '${INSTALL_PATH}'"
+18
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
source "$(dirname -- "$0")/utils.sh"
VERIFY_CORRECTNESS=false
+18
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
source "$(dirname -- "$0")/utils.sh"
SONAR_SCANNER_VERSION=$(curl -sSL -H "Accept: application/vnd.github+json" \
+18
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
check_status() {
exit_status=$?
if [ $exit_status -ne 0 ]; then
+11 -11
View File
@@ -1,11 +1,11 @@
sonar-scanner-version=8.0.1.6346
sonar-scanner-url-windows-x64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.0.1.6346-windows-x64.zip
sonar-scanner-sha-windows-x64=52b35b24be4ce5ec2e2933b32683db45db139581c46945546d9739b0c8866231
sonar-scanner-url-linux-x64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.0.1.6346-linux-x64.zip
sonar-scanner-sha-linux-x64=4bd40bf8411ed104853e94a3746ec92bc92845fde2b27dbf5c33fb5cfa8ecbe9
sonar-scanner-url-linux-aarch64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.0.1.6346-linux-aarch64.zip
sonar-scanner-sha-linux-aarch64=ae2b062ed6d640ab9014ab576042385d54c910857de952f5cb2592d2a2d7c8d8
sonar-scanner-url-macosx-x64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.0.1.6346-macosx-x64.zip
sonar-scanner-sha-macosx-x64=aa9065347ba834ff6f3d461183eb40a67a321e6996206875fd257e8e7d5745b2
sonar-scanner-url-macosx-aarch64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.0.1.6346-macosx-aarch64.zip
sonar-scanner-sha-macosx-aarch64=2d65d49c327ec8ca5ec7c6dc2af17749f5b43c596fd906501bba5a0b09edc5e2
sonar-scanner-version=8.1.0.6389
sonar-scanner-url-windows-x64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.1.0.6389-windows-x64.zip
sonar-scanner-sha-windows-x64=73f0e71928673d5b2f39bb86213342a30e51a14c8eec345164016bb29c8df8ee
sonar-scanner-url-linux-x64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.1.0.6389-linux-x64.zip
sonar-scanner-sha-linux-x64=bb8f709f9cb73352f8d1260a3b3c506c0f41146754bc630762c126d795499d0b
sonar-scanner-url-linux-aarch64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.1.0.6389-linux-aarch64.zip
sonar-scanner-sha-linux-aarch64=5e1c9328f4e261838de778c9e586ee608cca45ff7f0538108642219214628ba5
sonar-scanner-url-macosx-x64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.1.0.6389-macosx-x64.zip
sonar-scanner-sha-macosx-x64=8afc8bbff9008434e53b31cb681333ff643b999f84ca537db573d0fae8883cdc
sonar-scanner-url-macosx-aarch64=https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-8.1.0.6389-macosx-aarch64.zip
sonar-scanner-sha-macosx-aarch64=20d12be4081896b337cd873d98ebd3d554be666086a45e31dd84a12ef51c3688
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { getBuildWrapperInfo } from "../utils.js";
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import * as core from "@actions/core";
import * as exec from "@actions/exec";
import * as fs from "fs";
+18
View File
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import * as exec from "@actions/exec";
import * as path from "path";
@@ -0,0 +1,705 @@
/*
* sonarqube-scan-action
* Copyright (C) 2025 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import assert from "node:assert/strict";
import * as fs from "node:fs";
import { afterEach, describe, it, mock } from "node:test";
import { getProxyFromEnv, setupGpgHome, } from "../gpg-verification.js";
/**
* Helper function to create a temporary GPG home directory for testing.
* @param {Array} tempDirs - Array to track temp directories for cleanup
* @returns {string} Path to the created GPG home directory
*/
function createTrackedGpgHome(tempDirs) {
const gpgHome = setupGpgHome();
tempDirs.push(gpgHome);
assert.ok(fs.existsSync(gpgHome));
return gpgHome;
}
describe("gpg-verification with mocked exec", () => {
let tempDirs = [];
const proxyVars = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy"];
function clearProxyEnv() {
for (const v of proxyVars) {
delete process.env[v];
}
}
afterEach(() => {
// Clean up temporary directories
tempDirs.forEach((dir) => {
try {
if (fs.existsSync(dir)) {
fs.rmSync(dir, { recursive: true, force: true });
}
} catch (error) {
// Ignore cleanup errors
}
});
tempDirs = [];
});
describe("isGpgAvailable", () => {
it("should return true when GPG is available", async (t) => {
const execFn = mock.fn(async () => 0);
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { isGpgAvailable } = await import("../gpg-verification.js?test=gpg-available");
const result = await isGpgAvailable();
assert.equal(result, true);
assert.equal(execFn.mock.calls.length, 1);
assert.equal(execFn.mock.calls[0].arguments[0], "gpg");
assert.deepEqual(execFn.mock.calls[0].arguments[1], ["--version"]);
});
it("should return false when GPG is not available", async (t) => {
const execFn = mock.fn(async () => {
throw new Error("GPG not found");
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { isGpgAvailable } = await import("../gpg-verification.js?test=gpg-unavailable");
const result = await isGpgAvailable();
assert.equal(result, false);
});
});
describe("runGpgVerify", () => {
it("should successfully verify valid signature", async (t) => {
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { runGpgVerify } = await import("../gpg-verification.js?test=verify-success");
const gpgHome = createTrackedGpgHome(tempDirs);
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
await runGpgVerify(zipPath, signaturePath, gpgHome);
assert.equal(execCalls.length, 1);
assert.equal(execCalls[0].command, "gpg");
assert.ok(execCalls[0].args.includes("--verify"));
assert.ok(execCalls[0].args.includes(signaturePath));
assert.ok(execCalls[0].args.includes(zipPath));
});
it("should throw error when signature verification fails", async (t) => {
const execFn = mock.fn(async () => {
throw new Error("BAD signature");
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { runGpgVerify } = await import("../gpg-verification.js?test=verify-fail");
const gpgHome = createTrackedGpgHome(tempDirs);
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
await assert.rejects(
() => runGpgVerify(zipPath, signaturePath, gpgHome),
{
message: /GPG signature verification failed - file may be corrupted or tampered/
}
);
});
it("should convert Windows paths for GPG", async (t) => {
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { runGpgVerify } = await import("../gpg-verification.js?test=verify-windows");
const originalPlatform = process.platform;
Object.defineProperty(process, "platform", {
value: "win32",
writable: true,
configurable: true,
});
try {
const gpgHome = createTrackedGpgHome(tempDirs);
const zipPath = String.raw`C:\temp\scanner.zip`;
const signaturePath = String.raw`C:\temp\scanner.zip.asc`;
await runGpgVerify(zipPath, signaturePath, gpgHome);
// Verify paths were converted to Unix format
const args = execCalls[0].args;
const homeDirIndex = args.indexOf("--homedir");
const zipIndex = args.indexOf("--verify") + 1;
// Check that Windows paths are converted (should start with /c/ instead of C:\)
assert.ok(!args[homeDirIndex + 1].includes("\\"));
assert.ok(!args[zipIndex].includes("\\"));
assert.ok(!args[zipIndex + 1].includes("\\"));
} finally {
Object.defineProperty(process, "platform", {
value: originalPlatform,
writable: true,
configurable: true,
});
}
});
});
describe("verifySignature", () => {
it("should successfully verify signature with GPG available", async (t) => {
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { verifySignature } = await import("../gpg-verification.js?test=full-verify-success");
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
await verifySignature(zipPath, signaturePath);
assert.equal(execCalls.length, 3);
assert.deepEqual(execCalls[0].args, ["--version"]);
assert.ok(execCalls[1].args.includes("--recv-keys"));
assert.ok(execCalls[2].args.includes("--verify"));
});
it("should throw error when GPG is not available", async (t) => {
const execFn = mock.fn(async (command, args) => {
if (args.includes("--version")) {
throw new Error("GPG not found");
}
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { verifySignature } = await import("../gpg-verification.js?test=no-gpg");
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
await assert.rejects(
() => verifySignature(zipPath, signaturePath),
{
message: /GPG is not available/
}
);
});
it("should throw error when signature verification fails", async (t) => {
let callCount = 0;
const execFn = mock.fn(async () => {
callCount++;
// First call: gpg --version (success)
if (callCount === 1) {
return 0;
}
// Second call: recv-keys (success)
if (callCount === 2) {
return 0;
}
// Third call: verify (failure - bad signature)
throw new Error("BAD signature from 679F1EE92B19609DE816FDE81DB198F93525EC1A");
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { verifySignature } = await import("../gpg-verification.js?test=bad-signature");
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
await assert.rejects(
() => verifySignature(zipPath, signaturePath),
{
message: /GPG signature verification failed - file may be corrupted or tampered/
}
);
});
it("should cleanup GPG home directory even on failure", async (t) => {
let createdGpgHome;
let callCount = 0;
const execFn = mock.fn(async (command, args) => {
callCount++;
// First call: gpg --version (success)
if (callCount === 1) {
return 0;
}
// Second call: recv-keys (success)
if (callCount === 2) {
// Capture the GPG home directory from the args
const homeDirIndex = args.indexOf("--homedir");
if (homeDirIndex !== -1) {
createdGpgHome = args[homeDirIndex + 1];
}
return 0;
}
// Third call: verify (failure)
throw new Error("BAD signature");
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { verifySignature } = await import("../gpg-verification.js?test=cleanup-on-fail");
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
await assert.rejects(
() => verifySignature(zipPath, signaturePath),
{
message: /GPG signature verification failed/
}
);
assert.ok(!fs.existsSync(createdGpgHome), "GPG home should have been deleted after failure");
});
it("should use custom keyserver and fingerprint when provided", async (t) => {
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { verifySignature } = await import("../gpg-verification.js?test=custom-options");
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
const customKeyserver = "hkps://custom.keyserver.example.com";
const customFingerprint = "ABCD1234ABCD1234ABCD1234ABCD1234ABCD1234";
await verifySignature(zipPath, signaturePath, {
keyserver: customKeyserver,
keyFingerprint: customFingerprint,
});
const recvKeysCall = execCalls.find(call => call.args.includes("--recv-keys"));
assert.ok(recvKeysCall, "Should have recv-keys call");
assert.ok(recvKeysCall.args.includes(customKeyserver));
assert.ok(recvKeysCall.args.includes(customFingerprint));
});
it("should use default keyserver and fingerprint when not provided", async (t) => {
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { verifySignature } = await import("../gpg-verification.js?test=default-options");
const zipPath = "/tmp/scanner.zip";
const signaturePath = "/tmp/scanner.zip.asc";
await verifySignature(zipPath, signaturePath);
const recvKeysCall = execCalls.find(call => call.args.includes("--recv-keys"));
assert.ok(recvKeysCall, "Should have recv-keys call");
assert.ok(recvKeysCall.args.includes("hkps://keyserver.ubuntu.com"));
assert.ok(recvKeysCall.args.includes("679F1EE92B19609DE816FDE81DB198F93525EC1A"));
});
});
describe("importSonarSourceKey", () => {
it("should use fallback keyserver when primary fails", async (t) => {
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
const argsString = args.join(" ");
if (argsString.includes("invalid.keyserver.that.does.not.exist.example.com")) {
throw new Error("Failed to import key from invalid keyserver");
}
if (argsString.includes("keys.openpgp.org")) {
return 0;
}
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=fallback");
const gpgHome = createTrackedGpgHome(tempDirs);
const invalidKeyserver = "hkps://invalid.keyserver.that.does.not.exist.example.com";
const keyFingerprint = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
await importSonarSourceKey(gpgHome, keyFingerprint, invalidKeyserver);
assert.equal(execCalls.length, 2, "Should attempt two keyservers");
// Verify primary keyserver call
assert.equal(execCalls[0].command, "gpg");
assert.ok(execCalls[0].args.includes(invalidKeyserver));
assert.ok(execCalls[0].args.includes(keyFingerprint));
// Verify fallback keyserver call
assert.equal(execCalls[1].command, "gpg");
assert.ok(execCalls[1].args.includes("hkps://keys.openpgp.org"));
assert.ok(execCalls[1].args.includes(keyFingerprint));
});
it("should succeed with valid keyserver", async (t) => {
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=valid");
const gpgHome = createTrackedGpgHome(tempDirs);
const keyserver = "hkps://keyserver.ubuntu.com";
const keyFingerprint = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
await importSonarSourceKey(gpgHome, keyFingerprint, keyserver);
assert.equal(execCalls.length, 1);
assert.equal(execCalls[0].command, "gpg");
assert.ok(execCalls[0].args.includes(keyserver));
assert.ok(execCalls[0].args.includes(keyFingerprint));
assert.ok(execCalls[0].args.includes("--recv-keys"));
});
it("should throw error when both keyservers fail", async (t) => {
const execFn = mock.fn(async () => {
throw new Error("Connection failed");
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=both-fail");
const gpgHome = createTrackedGpgHome(tempDirs);
const keyserver = "hkps://keyserver.ubuntu.com";
const keyFingerprint = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
await assert.rejects(
() => importSonarSourceKey(gpgHome, keyFingerprint, keyserver),
{
message: /Failed to import SonarSource public key from all keyservers/
}
);
});
});
describe("getProxyFromEnv", () => {
afterEach(() => {
clearProxyEnv();
});
it("should return undefined when no proxy is set", () => {
clearProxyEnv();
assert.equal(getProxyFromEnv(), undefined);
});
it("should prefer HTTPS_PROXY over https_proxy", () => {
clearProxyEnv();
process.env.HTTPS_PROXY = "http://proxy-https:8080";
process.env.https_proxy = "http://proxy-lower:8080";
assert.equal(getProxyFromEnv(), "http://proxy-https:8080");
});
it("should use https_proxy (lowercase)", () => {
clearProxyEnv();
process.env.https_proxy = "http://proxy-lower:8080";
assert.equal(getProxyFromEnv(), "http://proxy-lower:8080");
});
it("should not fall back to HTTP_PROXY", () => {
clearProxyEnv();
process.env.HTTP_PROXY = "http://proxy-http:3128";
assert.equal(getProxyFromEnv(), undefined);
});
it("should not fall back to http_proxy (lowercase)", () => {
clearProxyEnv();
process.env.http_proxy = "http://proxy-lower-http:3128";
assert.equal(getProxyFromEnv(), undefined);
});
it("should ignore HTTP_PROXY when only HTTP proxy is configured", () => {
clearProxyEnv();
process.env.HTTP_PROXY = "http://http-only-proxy:3128";
process.env.http_proxy = "http://http-only-proxy:3128";
assert.equal(getProxyFromEnv(), undefined);
});
});
describe("tryImportKey with proxy", () => {
afterEach(() => {
clearProxyEnv();
});
it("should not pass --keyserver-options when no proxy env is set", async (t) => {
clearProxyEnv();
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=no-proxy");
const gpgHome = createTrackedGpgHome(tempDirs);
const keyserver = "hkps://keyserver.ubuntu.com";
const keyFingerprint = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
await importSonarSourceKey(gpgHome, keyFingerprint, keyserver);
assert.equal(execCalls.length, 1);
const args = execCalls[0].args;
assert.ok(!args.includes("--keyserver-options"), "Should NOT include --keyserver-options");
});
it("should use HTTPS_PROXY when set", async (t) => {
clearProxyEnv();
process.env.HTTPS_PROXY = "http://corporate-proxy:8080";
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=proxy-https-upper");
const gpgHome = createTrackedGpgHome(tempDirs);
await importSonarSourceKey(gpgHome, "ABCD1234", "hkps://keyserver.ubuntu.com");
const args = execCalls[0].args;
const optIdx = args.indexOf("--keyserver-options");
assert.ok(optIdx !== -1, "Should include --keyserver-options");
assert.equal(args[optIdx + 1], "http-proxy=http://corporate-proxy:8080");
});
it("should use https_proxy (lowercase) when set", async (t) => {
clearProxyEnv();
process.env.https_proxy = "http://lowercase-proxy:3128";
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=proxy-https-lower");
const gpgHome = createTrackedGpgHome(tempDirs);
await importSonarSourceKey(gpgHome, "ABCD1234", "hkps://keyserver.ubuntu.com");
const args = execCalls[0].args;
const optIdx = args.indexOf("--keyserver-options");
assert.ok(optIdx !== -1);
assert.equal(args[optIdx + 1], "http-proxy=http://lowercase-proxy:3128");
});
it("should not use proxy when only HTTP_PROXY is set", async (t) => {
clearProxyEnv();
process.env.HTTP_PROXY = "http://http-only-proxy:9090";
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=proxy-http-upper");
const gpgHome = createTrackedGpgHome(tempDirs);
await importSonarSourceKey(gpgHome, "ABCD1234", "hkps://keyserver.ubuntu.com");
const args = execCalls[0].args;
assert.ok(!args.includes("--keyserver-options"), "Should NOT include --keyserver-options when only HTTP_PROXY is set");
});
it("should not use proxy when only http_proxy (lowercase) is set", async (t) => {
clearProxyEnv();
process.env.http_proxy = "http://last-resort-proxy:1080";
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=proxy-http-lower");
const gpgHome = createTrackedGpgHome(tempDirs);
await importSonarSourceKey(gpgHome, "ABCD1234", "hkps://keyserver.ubuntu.com");
const args = execCalls[0].args;
assert.ok(!args.includes("--keyserver-options"), "Should NOT include --keyserver-options when only http_proxy is set");
});
it("should prefer HTTPS_PROXY over https_proxy and ignore HTTP variants", async (t) => {
clearProxyEnv();
process.env.HTTPS_PROXY = "http://preferred:8080";
process.env.https_proxy = "http://not-this-one:8080";
process.env.HTTP_PROXY = "http://also-not:3128";
process.env.http_proxy = "http://nope:1080";
const execCalls = [];
const execFn = mock.fn(async (command, args) => {
execCalls.push({ command, args });
return 0;
});
t.mock.module("@actions/exec", {
namedExports: {
exec: execFn,
},
});
const { importSonarSourceKey } = await import("../gpg-verification.js?test=proxy-precedence");
const gpgHome = createTrackedGpgHome(tempDirs);
await importSonarSourceKey(gpgHome, "ABCD1234", "hkps://keyserver.ubuntu.com");
const args = execCalls[0].args;
const optIdx = args.indexOf("--keyserver-options");
assert.ok(optIdx !== -1);
assert.equal(args[optIdx + 1], "http-proxy=http://preferred:8080");
});
});
});
+228
View File
@@ -0,0 +1,228 @@
/*
* sonarqube-scan-action
* Copyright (C) 2025 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import { describe, it, afterEach } from "node:test";
import assert from "node:assert/strict";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import {
getGpgCommand,
setupGpgHome,
cleanupGpgHome,
convertToUnixPath,
} from "../gpg-verification.js";
/**
* Helper function to temporarily mock process.platform for a test.
* Automatically restores the original platform value after the test.
* @param {string} platform - The platform to mock (e.g., "win32", "linux")
* @param {Function} testFn - The test function to run with the mocked platform
*/
function withMockedPlatform(platform, testFn) {
const originalPlatform = process.platform;
Object.defineProperty(process, "platform", {
value: platform,
writable: true,
configurable: true,
});
try {
testFn();
} finally {
Object.defineProperty(process, "platform", {
value: originalPlatform,
writable: true,
configurable: true,
});
}
}
/**
* Helper function to create a GPG home directory and track it for cleanup.
* @param {Array} tempDirs - Array to track temporary directories for cleanup
* @returns {string} The path to the created GPG home directory
*/
function createTrackedGpgHome(tempDirs) {
const gpgHome = setupGpgHome();
tempDirs.push(gpgHome);
assert.ok(fs.existsSync(gpgHome));
return gpgHome;
}
/**
* Helper function to temporarily mock environment variables for a test.
* Automatically restores or deletes environment variables after the test.
* @param {Object} envVars - Object with environment variable names as keys and values as values
* @param {Function} testFn - The async test function to run with the mocked environment
*/
async function withMockedEnv(envVars, testFn) {
const originalValues = {};
// Save original values and set new ones
for (const [key, value] of Object.entries(envVars)) {
originalValues[key] = process.env[key];
process.env[key] = value;
}
try {
await testFn();
} finally {
// Restore or delete environment variables
for (const [key, originalValue] of Object.entries(originalValues)) {
if (originalValue === undefined) {
delete process.env[key];
} else {
process.env[key] = originalValue;
}
}
}
}
/**
* Helper function to create a temporary directory.
* @returns {string} The path to the created temporary directory
*/
function createTempDir() {
const tempDir = path.join(os.tmpdir(), `test-runner-temp-${Date.now()}`);
fs.mkdirSync(tempDir, { recursive: true });
return tempDir;
}
describe("gpg-verification", () => {
let tempDirs = [];
afterEach(() => {
// Clean up any temporary directories created during tests
tempDirs.forEach((dir) => {
try {
if (fs.existsSync(dir)) {
fs.rmSync(dir, { recursive: true, force: true });
}
} catch (error) {
// Ignore cleanup errors
}
});
tempDirs = [];
});
describe("getGpgCommand", () => {
it("should return 'gpg' as the command", () => {
const command = getGpgCommand();
assert.equal(command, "gpg");
});
});
describe("convertToUnixPath", () => {
it("should convert Windows path with drive letter to Unix path", () => {
withMockedPlatform("win32", () => {
assert.equal(
convertToUnixPath(String.raw`C:\a\_temp\gpg-home`),
"/c/a/_temp/gpg-home"
);
assert.equal(
convertToUnixPath(String.raw`D:\Users\test\file.txt`),
"/d/Users/test/file.txt"
);
});
});
it("should handle mixed slashes on Windows", () => {
withMockedPlatform("win32", () => {
assert.equal(
convertToUnixPath(String.raw`C:\a/_temp\gpg-home`),
"/c/a/_temp/gpg-home"
);
});
});
it("should return path unchanged on non-Windows platforms", () => {
withMockedPlatform("linux", () => {
assert.equal(
convertToUnixPath("/tmp/gpg-home"),
"/tmp/gpg-home"
);
});
});
});
describe("setupGpgHome", () => {
it("should create a temporary GPG home directory", () => {
const gpgHome = createTrackedGpgHome(tempDirs);
assert.ok(fs.statSync(gpgHome).isDirectory());
// Check directory permissions (on Unix systems)
if (process.platform !== "win32") {
const stats = fs.statSync(gpgHome);
const mode = stats.mode & Number.parseInt("777", 8);
assert.equal(mode, Number.parseInt("700", 8));
}
});
it("should create unique directories on multiple calls", async () => {
const gpgHome1 = createTrackedGpgHome(tempDirs);
// Small delay to ensure different timestamps
await new Promise((resolve) => setTimeout(resolve, 10));
const gpgHome2 = createTrackedGpgHome(tempDirs);
assert.notEqual(gpgHome1, gpgHome2);
});
it("should use RUNNER_TEMP if available", async () => {
const testTemp = createTempDir();
await withMockedEnv({ RUNNER_TEMP: testTemp }, async () => {
const gpgHome = createTrackedGpgHome(tempDirs);
assert.ok(gpgHome.startsWith(testTemp));
});
if (fs.existsSync(testTemp)) {
fs.rmSync(testTemp, { recursive: true, force: true });
}
});
});
describe("cleanupGpgHome", () => {
it("should remove the GPG home directory", () => {
const gpgHome = setupGpgHome();
assert.ok(fs.existsSync(gpgHome));
cleanupGpgHome(gpgHome);
assert.ok(!fs.existsSync(gpgHome));
});
it("should not throw if directory does not exist", () => {
const nonExistentDir = path.join(os.tmpdir(), `non-existent-${Date.now()}`);
assert.doesNotThrow(() => {
cleanupGpgHome(nonExistentDir);
});
});
it("should handle cleanup errors gracefully", () => {
// This test verifies the function doesn't throw on permission errors
// In practice, permission errors are rare in test environments
assert.doesNotThrow(() => {
cleanupGpgHome("/invalid/path/that/does/not/exist");
});
});
});
});
@@ -0,0 +1,207 @@
/*
* sonarqube-scan-action
* Copyright (C) 2025 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import assert from "node:assert/strict";
import { describe, it, mock } from "node:test";
const SCANNER_VERSION = "6.2.0.4584";
const BINARIES_URL = "https://my.artifactory.example.com/sonar-scanner-cli";
const BINARY_DOWNLOAD_URL = `${BINARIES_URL}/sonar-scanner-cli-${SCANNER_VERSION}-linux-x64.zip`;
function mockUtils(t) {
t.mock.module("../utils.js", {
namedExports: {
getPlatformFlavor: mock.fn(() => "linux-x64"),
getScannerDownloadURL: mock.fn(() => BINARY_DOWNLOAD_URL),
scannerDirName: mock.fn(() => `sonar-scanner-${SCANNER_VERSION}-linux-x64`),
},
});
}
describe("installSonarScanner", () => {
it("should forward scannerBinariesAuthHeader to both binary and signature downloads", async (t) => {
const downloadCalls = [];
const downloadToolFn = mock.fn(async (url, dest, auth) => {
downloadCalls.push({ url, auth });
return `/tmp/downloaded-${downloadCalls.length}`;
});
mockUtils(t);
t.mock.module("@actions/tool-cache", {
namedExports: {
find: mock.fn(() => null),
downloadTool: downloadToolFn,
extractZip: mock.fn(async () => "/tmp/extracted"),
cacheDir: mock.fn(async () => "/tmp/cached"),
},
});
t.mock.module("@actions/core", {
namedExports: {
info: mock.fn(),
warning: mock.fn(),
addPath: mock.fn(),
},
});
t.mock.module("../gpg-verification.js", {
namedExports: {
verifySignature: mock.fn(async () => {}),
},
});
const { installSonarScanner } = await import(
`../install-sonar-scanner.js?test=auth-header`
);
await installSonarScanner({
scannerVersion: SCANNER_VERSION,
scannerBinariesUrl: BINARIES_URL,
scannerBinariesAuthHeader: "Bearer mytoken",
});
assert.equal(downloadCalls.length, 2, "Should download binary and signature");
assert.equal(downloadCalls[0].auth, "Bearer mytoken", "Binary download should use auth header");
assert.equal(downloadCalls[1].auth, "Bearer mytoken", "Signature download should use auth header");
assert.ok(downloadCalls[1].url.endsWith(".asc"), "Second download should be the signature");
});
it("should not set auth header when scannerBinariesAuthHeader is not provided", async (t) => {
const downloadCalls = [];
const downloadToolFn = mock.fn(async (url, dest, auth) => {
downloadCalls.push({ url, auth });
return `/tmp/downloaded-${downloadCalls.length}`;
});
mockUtils(t);
t.mock.module("@actions/tool-cache", {
namedExports: {
find: mock.fn(() => null),
downloadTool: downloadToolFn,
extractZip: mock.fn(async () => "/tmp/extracted"),
cacheDir: mock.fn(async () => "/tmp/cached"),
},
});
t.mock.module("@actions/core", {
namedExports: {
info: mock.fn(),
warning: mock.fn(),
addPath: mock.fn(),
},
});
t.mock.module("../gpg-verification.js", {
namedExports: {
verifySignature: mock.fn(async () => {}),
},
});
const { installSonarScanner } = await import(
`../install-sonar-scanner.js?test=no-auth-header`
);
await installSonarScanner({
scannerVersion: SCANNER_VERSION,
scannerBinariesUrl: BINARIES_URL,
});
assert.equal(downloadCalls.length, 2);
assert.equal(downloadCalls[0].auth, undefined, "Binary download should have no auth header");
assert.equal(downloadCalls[1].auth, undefined, "Signature download should have no auth header");
});
it("should skip signature download when skipSignatureVerification is true", async (t) => {
const downloadCalls = [];
const downloadToolFn = mock.fn(async (url, dest, auth) => {
downloadCalls.push({ url, auth });
return `/tmp/downloaded-${downloadCalls.length}`;
});
mockUtils(t);
t.mock.module("@actions/tool-cache", {
namedExports: {
find: mock.fn(() => null),
downloadTool: downloadToolFn,
extractZip: mock.fn(async () => "/tmp/extracted"),
cacheDir: mock.fn(async () => "/tmp/cached"),
},
});
t.mock.module("@actions/core", {
namedExports: {
info: mock.fn(),
warning: mock.fn(),
addPath: mock.fn(),
},
});
const { installSonarScanner } = await import(
`../install-sonar-scanner.js?test=skip-sig`
);
await installSonarScanner({
scannerVersion: SCANNER_VERSION,
scannerBinariesUrl: BINARIES_URL,
scannerBinariesAuthHeader: "Bearer mytoken",
skipSignatureVerification: true,
});
assert.equal(downloadCalls.length, 1, "Should only download binary, not signature");
assert.equal(downloadCalls[0].auth, "Bearer mytoken");
});
it("should use cached tool when available and skip download", async (t) => {
const downloadToolFn = mock.fn();
mockUtils(t);
t.mock.module("@actions/tool-cache", {
namedExports: {
find: mock.fn(() => "/tmp/cached-tool"),
downloadTool: downloadToolFn,
extractZip: mock.fn(),
cacheDir: mock.fn(),
},
});
t.mock.module("@actions/core", {
namedExports: {
info: mock.fn(),
warning: mock.fn(),
addPath: mock.fn(),
},
});
const { installSonarScanner } = await import(
`../install-sonar-scanner.js?test=cached`
);
await installSonarScanner({
scannerVersion: SCANNER_VERSION,
scannerBinariesUrl: BINARIES_URL,
});
assert.equal(downloadToolFn.mock.calls.length, 0, "Should not download when cached");
});
});
+18
View File
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
export function mockCore(overrides = {}) {
return {
setFailed: (msg) => console.error(msg),
+18
View File
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import mockfs from "mock-fs";
import assert from "node:assert/strict";
import { describe, it, mock } from "node:test";
+18
View File
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import {
+262
View File
@@ -0,0 +1,262 @@
/*
* sonarqube-scan-action
* Copyright (C) 2025 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as core from "@actions/core";
import * as exec from "@actions/exec";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
const SONARSOURCE_KEY_FINGERPRINT = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
const DEFAULT_KEYSERVER = "hkps://keyserver.ubuntu.com";
const FALLBACK_KEYSERVER = "hkps://keys.openpgp.org";
/**
* Verifies the GPG signature of a downloaded file
* @param {string} zipPath - Path to the downloaded ZIP file
* @param {string} signaturePath - Path to the .asc signature file
* @param {object} options - Verification options
* @param {string} options.keyFingerprint - GPG key fingerprint (default: SonarSource key)
* @param {string} options.keyserver - Primary keyserver URL (default: keyserver.ubuntu.com, with fallback to keys.openpgp.org)
* @returns {Promise<void>}
* @throws {Error} If GPG is unavailable or verification fails
*/
export async function verifySignature(zipPath, signaturePath, options = {}) {
const keyFingerprint = options.keyFingerprint || SONARSOURCE_KEY_FINGERPRINT;
const keyserver = options.keyserver || DEFAULT_KEYSERVER;
if (!(await isGpgAvailable())) {
throw new Error(
"GPG is not available. Install GPG or set skipSignatureVerification: true"
);
}
let gpgHome;
try {
gpgHome = setupGpgHome();
core.debug(`Created temporary GPG home: ${gpgHome}`);
await importSonarSourceKey(gpgHome, keyFingerprint, keyserver);
core.info("✓ SonarSource public key imported successfully");
await runGpgVerify(zipPath, signaturePath, gpgHome);
core.info("✓ GPG signature verification passed");
} finally {
if (gpgHome) {
cleanupGpgHome(gpgHome);
}
}
}
/**
* Checks if GPG is available on the system
* @returns {Promise<boolean>} True if GPG is available
*/
export async function isGpgAvailable() {
try {
const gpgCommand = getGpgCommand();
await exec.exec(gpgCommand, ["--version"], {
silent: true,
ignoreReturnCode: false,
});
return true;
} catch (error) {
core.debug(`GPG not available: ${error.message}`);
return false;
}
}
/**
* Gets the GPG command for the current platform
* @returns {string} GPG command name
*/
export function getGpgCommand() {
// GPG is available as 'gpg' on all GitHub-hosted runners
return "gpg";
}
/**
* Converts a Windows path to Unix-style path for GPG
* GPG on Windows (from Git for Windows) expects Unix-style paths
* @param {string} windowsPath - Windows path (e.g., C:\a\_temp\gpg-home)
* @returns {string} Unix-style path (e.g., /c/a/_temp/gpg-home)
*/
export function convertToUnixPath(windowsPath) {
if (process.platform !== "win32") {
return windowsPath;
}
let unixPath = windowsPath.replaceAll('\\', "/");
unixPath = unixPath.replace(/^([A-Za-z]):/, (match, drive) => {
return `/${drive.toLowerCase()}`;
});
return unixPath;
}
/**
* Creates a temporary GPG home directory
* @returns {string} Path to the temporary GPG home directory
*/
export function setupGpgHome() {
const tempDir = process.env.RUNNER_TEMP || os.tmpdir();
const gpgHome = path.join(tempDir, `gpg-home-${Date.now()}-${process.pid}`);
fs.mkdirSync(gpgHome, { recursive: true, mode: 0o700 });
return gpgHome;
}
/**
* Detects HTTPS proxy from environment variables.
* Checks both upper and lower case variants (HTTPS_PROXY, https_proxy).
* Only HTTPS proxy is used since keyservers use hkps:// (TLS).
* HTTP_PROXY is intentionally not used as a fallback to avoid routing
* HTTPS traffic through a proxy not intended for TLS connections.
* @returns {string|undefined} Proxy URL or undefined if not set
*/
export function getProxyFromEnv() {
return process.env.HTTPS_PROXY || process.env.https_proxy;
}
/**
* Attempts to import a public key from a specific keyserver
* @param {string} gpgHome - Path to GPG home directory
* @param {string} keyFingerprint - Public key fingerprint
* @param {string} keyserver - Keyserver URL
* @returns {Promise<void>}
* @throws {Error} If key import fails
*/
async function tryImportKey(gpgHome, keyFingerprint, keyserver) {
const gpgCommand = getGpgCommand();
const gpgHomePath = convertToUnixPath(gpgHome);
const proxyUrl = getProxyFromEnv();
if (proxyUrl) {
// The URL may carry credentials (e.g. http://user:pass@proxy:8080).
// Register it as a secret so future logging (here or downstream) is
// automatically redacted
core.setSecret(proxyUrl);
core.info("Using HTTPS_PROXY for keyserver access");
}
await exec.exec(
gpgCommand,
[
"--homedir",
gpgHomePath,
"--batch",
"--keyserver",
keyserver,
...(proxyUrl ? ["--keyserver-options", `http-proxy=${proxyUrl}`] : []),
"--recv-keys",
keyFingerprint,
],
{
silent: false,
}
);
}
/**
* Imports the SonarSource public key from a keyserver
* @param {string} gpgHome - Path to GPG home directory
* @param {string} keyFingerprint - Public key fingerprint
* @param {string} keyserver - Keyserver URL
* @returns {Promise<void>}
* @throws {Error} If key import fails
*/
export async function importSonarSourceKey(gpgHome, keyFingerprint, keyserver) {
let primaryError;
try {
core.info(`Importing SonarSource public key from ${keyserver}...`);
await tryImportKey(gpgHome, keyFingerprint, keyserver);
core.info(`Successfully imported key from ${keyserver}`);
return;
} catch (error) {
primaryError = error;
core.warning(
`Failed to import key from ${keyserver}: ${error.message}`
);
}
try {
core.info(`Attempting fallback keyserver ${FALLBACK_KEYSERVER}...`);
await tryImportKey(gpgHome, keyFingerprint, FALLBACK_KEYSERVER);
core.info(`Successfully imported key from fallback keyserver ${FALLBACK_KEYSERVER}`);
} catch (fallbackError) {
throw new Error(
`Failed to import SonarSource public key from all keyservers. ` +
`Primary (${keyserver}): ${primaryError.message}. ` +
`Fallback (${FALLBACK_KEYSERVER}): ${fallbackError.message}`
);
}
}
/**
* Runs GPG verification on the downloaded file
* @param {string} zipPath - Path to the ZIP file
* @param {string} signaturePath - Path to the signature file
* @param {string} gpgHome - Path to GPG home directory
* @returns {Promise<void>}
* @throws {Error} If verification fails
*/
export async function runGpgVerify(zipPath, signaturePath, gpgHome) {
const gpgCommand = getGpgCommand();
try {
core.info("Verifying GPG signature...");
await exec.exec(
gpgCommand,
[
"--homedir",
convertToUnixPath(gpgHome),
"--batch",
"--verify",
convertToUnixPath(signaturePath),
convertToUnixPath(zipPath),
],
{
silent: false,
}
);
} catch (error) {
throw new Error(
`GPG signature verification failed - file may be corrupted or tampered: ${error.message}`
);
}
}
/**
* Cleans up the temporary GPG home directory
* @param {string} gpgHome - Path to GPG home directory
*/
export function cleanupGpgHome(gpgHome) {
try {
if (fs.existsSync(gpgHome)) {
fs.rmSync(gpgHome, { recursive: true, force: true });
core.debug(`Cleaned up temporary GPG home: ${gpgHome}`);
}
} catch (error) {
core.warning(`Failed to cleanup temporary GPG home: ${error.message}`);
}
}
+24 -2
View File
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import * as core from "@actions/core";
import { installSonarScanner } from "./install-sonar-scanner";
import { runSonarScanner } from "./run-sonar-scanner";
@@ -15,9 +33,11 @@ function getInputs() {
const args = core.getInput("args");
const projectBaseDir = core.getInput("projectBaseDir");
const scannerBinariesUrl = core.getInput("scannerBinariesUrl");
const scannerBinariesAuthHeader = core.getInput("scannerBinariesAuthHeader") || undefined;
const scannerVersion = core.getInput("scannerVersion");
const skipSignatureVerification = core.getBooleanInput("skipSignatureVerification");
return { args, projectBaseDir, scannerBinariesUrl, scannerVersion };
return { args, projectBaseDir, scannerBinariesUrl, scannerBinariesAuthHeader, scannerVersion, skipSignatureVerification };
}
/**
@@ -53,7 +73,7 @@ function runSanityChecks(inputs) {
async function run() {
try {
const { args, projectBaseDir, scannerVersion, scannerBinariesUrl } =
const { args, projectBaseDir, scannerVersion, scannerBinariesUrl, scannerBinariesAuthHeader, skipSignatureVerification } =
getInputs();
const runnerEnv = getEnvVariables();
const { sonarToken } = runnerEnv;
@@ -63,6 +83,8 @@ async function run() {
const scannerDir = await installSonarScanner({
scannerVersion,
scannerBinariesUrl,
scannerBinariesAuthHeader,
skipSignatureVerification,
});
await runSonarScanner(args, projectBaseDir, scannerDir, runnerEnv);
+44 -4
View File
@@ -1,12 +1,31 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import * as core from "@actions/core";
import * as tc from "@actions/tool-cache";
import * as os from "os";
import * as path from "path";
import * as os from "node:os";
import * as path from "node:path";
import {
getPlatformFlavor,
getScannerDownloadURL,
scannerDirName,
} from "./utils";
} from "./utils.js";
import { verifySignature } from "./gpg-verification.js";
const TOOLNAME = "sonar-scanner-cli";
@@ -16,6 +35,8 @@ const TOOLNAME = "sonar-scanner-cli";
export async function installSonarScanner({
scannerVersion,
scannerBinariesUrl,
scannerBinariesAuthHeader,
skipSignatureVerification = false,
}) {
const flavor = getPlatformFlavor(os.platform(), os.arch());
@@ -35,7 +56,26 @@ export async function installSonarScanner({
core.info(`Downloading from: ${downloadUrl}`);
const downloadPath = await tc.downloadTool(downloadUrl);
const downloadPath = await tc.downloadTool(downloadUrl, undefined, scannerBinariesAuthHeader);
if (skipSignatureVerification) {
core.warning("⚠ Skipping GPG signature verification (not recommended)");
} else {
const signatureUrl = `${downloadUrl}.asc`;
core.info(`Downloading signature from: ${signatureUrl}`);
let signaturePath;
try {
signaturePath = await tc.downloadTool(signatureUrl, undefined, scannerBinariesAuthHeader);
} catch (error) {
throw new Error(
`Failed to download signature file from ${signatureUrl}: ${error.message}`
);
}
await verifySignature(downloadPath, signaturePath);
}
const extractedPath = await tc.extractZip(downloadPath);
// Find the actual scanner directory inside the extracted folder
+21 -3
View File
@@ -1,8 +1,26 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import * as core from "@actions/core";
import * as exec from "@actions/exec";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as fs from "node:fs";
import * as os from "node:os";
import * as path from "node:path";
import { parseArgsStringToArgv } from "string-argv";
const KEYTOOL_MAIN_CLASS = "sun.security.tools.keytool.Main";
+20 -2
View File
@@ -1,5 +1,23 @@
import fs from "fs";
import { join } from "path";
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
import fs from "node:fs";
import { join } from "node:path";
export function validateScannerVersion(version) {
if (!version) {
+18
View File
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
const platformFlavor = {
linux: {
x64: "linux-x64",
+19 -1
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
set -eou pipefail
error() { echo -e "\\e[31m✗ $*\\e[0m"; }
@@ -11,4 +29,4 @@ $scriptDir/assertFileExists "$1"
if ! grep -q "$2" "$1"; then
error "'$2' not found in '$1'"
exit 1
fi
fi
+19 -1
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
set -eou pipefail
error() { echo -e "\\e[31m✗ $*\\e[0m"; }
@@ -7,4 +25,4 @@ error() { echo -e "\\e[31m✗ $*\\e[0m"; }
if [ -f "$1" ]; then
error "File '$1' found"
exit 1
fi
fi
+19 -1
View File
@@ -1,5 +1,23 @@
#!/usr/bin/env bash
# SonarQube Scan Action
# Copyright (C) SonarSource Sàrl
# mailto:contact AT sonarsource DOT com
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
set -eou pipefail
error() { echo -e "\\e[31m✗ $*\\e[0m"; }
@@ -7,4 +25,4 @@ error() { echo -e "\\e[31m✗ $*\\e[0m"; }
if [ ! -f "$1" ]; then
error "File '$1' not found"
exit 1
fi
fi
+18
View File
@@ -1,3 +1,21 @@
// SonarQube Scan Action
// Copyright (C) SonarSource Sàrl
// mailto:contact AT sonarsource DOT com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
// along with this program; if not, write to the Free Software Foundation,
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
function main() {
console.log("Hello World");
}