Compare commits

..
Author SHA1 Message Date
Alban Auzeill f85f58d535 Fix invalid '--no-progress' 2026-08-03 12:21:04 +02:00
Alban Auzeill bbc1dc389a remove progress bar 2026-08-03 12:19:00 +02:00
Alban Auzeill e0c4e7abeb uses winget instead of Chocolatey 2026-08-03 12:15:40 +02:00
Alban Auzeill 280d6fc5b8 Try --install-arguments "/S" 2026-08-03 12:05:14 +02:00
Alban Auzeill 154f7918a7 Try --params "/S" 2026-08-03 12:03:28 +02:00
Alban Auzeill 2448e3394c Retry to install gnupg 3 times 2026-08-03 11:33:19 +02:00
Alban Auzeill 62d06e46aa Try github-windows-latest-s 2026-08-03 11:26:48 +02:00
Alban Auzeill f8132da3be Use powershell 2026-08-03 11:22:56 +02:00
Alban Auzeill f9b74a459a Try another runner 2026-08-03 11:14:25 +02:00
Alban Auzeill bf5bc7ceac Revert "Harden reproducer: install native GnuPG via multiple strategies"
This reverts commit 8b19b74547.
2026-08-03 11:13:53 +02:00
Alban AuzeillandClaude Opus 4.8 8b19b74547 Harden reproducer: install native GnuPG via multiple strategies
The choco community feed can return transient 503s (as it did on the first
run), which left gpg.exe missing and failed the step. Install Gpg4win via a
feed-independent direct download first, then winget, then choco with retries;
succeed if any strategy yields gpg.exe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 11:03:28 +02:00
Alban AuzeillandClaude Opus 4.8 78aa5797b9 Investigate Windows GPG path bug (#186785) + CI reproducer
convertToUnixPath() rewrites drive letters to MSYS form (R:\ -> /r/),
which native GnuPG (Gpg4win) cannot resolve. Add investigation.md and a
windows-latest reproducer workflow that installs native GnuPG and expects
the action to fail at GPG signature verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-03 10:44:46 +02:00
2 changed files with 215 additions and 0 deletions
+90
View File
@@ -0,0 +1,90 @@
# Reproducer for: "sonarqube-scan-action GPG check not working on Windows runner"
# https://community.sonarsource.com/t/sonarqube-scan-action-gpg-check-not-working-on-windows-runner/186785
#
# Root cause (see investigation.md): on Windows, convertToUnixPath() rewrites drive
# letters into MSYS/Git-Bash form (R:\... -> /r/...). The native GnuPG (Gpg4win) that
# the reporter has on PATH (C:\Program Files (x86)\GnuPG\bin\gpg.exe) cannot resolve
# that form, so GPG signature verification fails.
#
# This workflow reproduces the failure by installing native GnuPG and putting it first
# on PATH, matching the reporter's environment. It runs the local action (which executes
# the committed dist/index.js) and expects it to FAIL during signature verification.
name: Reproduce GPG check failure on Windows
on:
push:
permissions:
contents: read
jobs:
reproduce-windows-gpg-bug:
runs-on: github-windows-latest-s
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Install native GnuPG (winget GnuPG.GnuPG) and put it first on PATH
shell: powershell
run: |
# Install native GnuPG via winget. The choco 'gnupg' package hangs at
# "Installing gnupg..." (its installer blocks in the non-interactive runner
# session), so we use winget's GnuPG.GnuPG package instead.
winget install --id GnuPG.GnuPG --exact --silent --accept-source-agreements --accept-package-agreements --disable-interactivity
# winget exits non-zero for benign cases (e.g. already installed); don't fail
# here on that. The gpg.exe presence check below is the real gate.
Write-Host "winget exit code: $LASTEXITCODE"
# The reporter's gpg lives at C:\Program Files (x86)\GnuPG\bin\gpg.exe.
# Prepend the native GnuPG dir to PATH so `gpg` resolves to it (and NOT to
# the Git-for-Windows build, which would mask the bug by accepting /r/... paths).
$candidates = @(
"C:\Program Files (x86)\GnuPG\bin",
"C:\Program Files\GnuPG\bin"
)
$gpgDir = $candidates | Where-Object { Test-Path (Join-Path $_ "gpg.exe") } | Select-Object -First 1
if (-not $gpgDir) { Write-Error "Native GnuPG not found after install"; exit 1 }
Write-Host "Using native GnuPG from: $gpgDir"
Add-Content -Path $env:GITHUB_PATH -Value $gpgDir
- name: Confirm `gpg` resolves to native GnuPG
shell: powershell
run: |
$g = Get-Command gpg
Write-Host "gpg resolves to: $($g.Source)"
gpg --version
if ($g.Source -notmatch "GnuPG") {
Write-Error "Expected native GnuPG on PATH but got: $($g.Source)"
exit 1
}
- name: Root-cause demo — native gpg rejects an MSYS-style --homedir
shell: powershell
continue-on-error: true
run: |
# convertToUnixPath() would turn e.g. C:\...\gpg-home into /c/.../gpg-home.
# Show that native GnuPG cannot use such a --homedir.
$msysHome = "/c/Users/runneradmin/gpg-home-demo"
Write-Host "Running: gpg --homedir '$msysHome' --batch --list-keys"
gpg --homedir "$msysHome" --batch --list-keys
Write-Host "native-gpg exit code with MSYS-style homedir: $LASTEXITCODE"
- name: Run the action (expected to FAIL at GPG signature verification)
id: action
continue-on-error: true
# No SONAR_TOKEN / server needed: the failure happens during signature
# verification in installSonarScanner, before the scanner is ever invoked.
uses: ./
with:
skipSignatureVerification: false
- name: Assert the bug reproduced
shell: powershell
run: |
Write-Host "Action step outcome: ${{ steps.action.outcome }}"
if ("${{ steps.action.outcome }}" -eq "failure") {
Write-Host "OK - Bug reproduced: the action failed on Windows with native GnuPG."
} else {
Write-Error "Bug did NOT reproduce (outcome: ${{ steps.action.outcome }}). The GPG path handling may have been fixed."
exit 1
}
+125
View File
@@ -0,0 +1,125 @@
# Investigation: GPG check not working on Windows runner
- **Reported:** https://community.sonarsource.com/t/sonarqube-scan-action-gpg-check-not-working-on-windows-runner/186785
- **Affected version:** `SonarSource/sonarqube-scan-action@v8.2.1`
- **Environment:** Windows runner with native GnuPG (Gpg4win) at `C:\Program Files (x86)\GnuPG\bin\gpg.exe`
- **Verdict:** ✅ **Confirmed bug** in `src/main/gpg-verification.js`
## Summary
On Windows, the action converts every path it hands to `gpg` (the `--homedir`, the
signature file, and the ZIP file) into an **MSYS/Git-Bash-style path** such as
`/r/GHEC/Build_B1/_temp/gpg-957091c8`. That format is only understood by the
**Git-for-Windows** build of GPG. When the `gpg` on `PATH` is the **native GnuPG
(Gpg4win)** — as in the reporter's environment — those paths are meaningless, so GPG
cannot create/read its home directory, keyring, sockets, or lock files, and signature
verification fails.
## Root cause
`convertToUnixPath()` in `src/main/gpg-verification.js:106-118`:
```js
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()}`; // R:\... -> /r/...
});
return unixPath;
}
```
For the reporter's temp dir `R:\GHEC\Build_B1\_temp\gpg-957091c8` this produces:
```
R:\GHEC\Build_B1\_temp\gpg-957091c8 → /r/GHEC/Build_B1/_temp/gpg-957091c8
```
which is exactly the path seen in the failure logs.
The function's own comment states the assumption:
> `GPG on Windows (from Git for Windows) expects Unix-style paths` — `src/main/gpg-verification.js:102`
That assumption is wrong for the common case. There are two GPG builds on Windows:
| GPG build | Understands `/r/GHEC/...` (MSYS) | Understands `R:/GHEC/...` (native) |
|---|---|---|
| Git for Windows / MSYS2 `gpg` | ✅ | ✅ |
| **Native GnuPG / Gpg4win** (`C:\Program Files (x86)\GnuPG\bin\gpg.exe`) | ❌ | ✅ |
The MSYS drive-letter form (`/r/...`) is understood by *only one* of the two builds,
whereas the plain Windows form with forward slashes (`R:/...`) is understood by **both**.
By rewriting `R:``/r`, the action picks the form that breaks native GnuPG.
## How the converted path is used
All three call sites feed native GnuPG a path it cannot resolve:
- `src/main/gpg-verification.js:165``--homedir` for `--recv-keys` (key import)
- `src/main/gpg-verification.js:247``--homedir` for `--verify`
- `src/main/gpg-verification.js:250-251` — the `.asc` signature path and the ZIP path
## Mapping to the reported errors
With `--homedir /r/GHEC/Build_B1/_temp/gpg-957091c8`, native GnuPG treats the argument
as a bogus location and cannot create/open its home dir. That directly explains every
symptom in the report:
| Reported symptom | Explanation |
|---|---|
| `pubring.kbx`*No such file or directory* | Keyring cannot be created/read under the bogus homedir |
| `can't create '…/gnupg_spawn_dirmngr_sentinel.lock'`*The system cannot find the path specified* | Native Windows API cannot resolve `/r/...`; parent path does not exist |
| `can't connect to the dirmngr: No such file or directory` | `dirmngr` socket cannot be created under the bogus homedir |
| `Kein Dirmngr` (keyserver retrieval failed) | Consequence of dirmngr never starting → `--recv-keys` fails |
The reporter's own suggested fix — use `R:/GHEC/Build_B1/_temp/gpg-957091c8` — matches
the analysis above.
## Why it isn't caught by CI / existing tests
- The unit tests in `src/main/__tests__/gpg-verification.test.js:132-163` only assert the
transformation itself (`C:\a\_temp\gpg-home``/c/a/_temp/gpg-home`). They **encode the
buggy behaviour as the expected behaviour**, so they pass while the real bug persists.
- GitHub-hosted `windows-latest` runners resolve `gpg` to the **Git-for-Windows** build,
which happens to accept `/r/...`. The bug only surfaces when the native GnuPG (Gpg4win)
is first on `PATH` — the reporter's self-hosted setup. This is why it escaped testing.
## Suggested fix (not applied — investigation only)
On Windows, do **not** rewrite the drive letter. Normalise separators only, keeping a
native Windows path with forward slashes, which both GPG builds accept:
```js
export function convertToUnixPath(windowsPath) {
if (process.platform !== "win32") {
return windowsPath;
}
// Keep the drive letter (R:/...). Native GnuPG (Gpg4win) cannot resolve the
// MSYS "/r/..." form, and Git-for-Windows GPG understands "R:/..." too.
return windowsPath.replaceAll("\\", "/");
}
```
The corresponding tests at `src/main/__tests__/gpg-verification.test.js:132-153` should be
updated to expect `C:/a/_temp/gpg-home` (and the function likely renamed, since it no
longer produces a Unix path).
## Secondary observation (not the reported bug)
`src/main/run-sonar-scanner.js:147` invokes `${scannerDir}/jre/bin/java` without a `.exe`
suffix and with forward slashes. This only runs when `SONAR_ROOT_CERT` is set (truststore
handling) and is unrelated to the GPG failure, but is worth a separate look for Windows
robustness.
## Reproducer
A CI reproducer is provided in `.github/workflows/issue-reproduced.yml`. It runs on
`windows-latest`, installs the **native GnuPG (Gpg4win)** and puts it first on `PATH` to
match the reporter's environment, then runs the action (`uses: ./`, which executes the
committed `dist/index.js`). It expects the action to **fail at GPG signature
verification**. It also includes a direct step showing native `gpg` rejecting an
MSYS-style `--homedir`, isolating the root cause. The workflow triggers `on: push`.