mirror of
https://github.com/SonarSource/sonarqube-scan-action.git
synced 2026-05-23 10:25:56 +00:00
SQSCANGHA-140 Fix GPG path handling for Windows
Fix GPG signature verification on Windows by converting Windows-style paths to Unix-style paths that GPG expects. GPG on Windows (from Git for Windows) is a Unix tool that requires Unix-style paths. Issue: GPG was receiving Windows paths like C:\a\_temp\gpg-home and attempting to use them, resulting in malformed paths like /c/a/sonarqube-scan-action/C:\a\_temp\gpg-home and errors: - "keyblock resource: No such file or directory" - "can't connect to the dirmngr: No such file or directory" - "keyserver receive failed: No dirmngr" Solution: - Add convertToUnixPath() function to convert Windows paths to Unix-style (e.g., C:\a\_temp\gpg -> /c/a/_temp/gpg) - Apply conversion in tryImportKey() and runGpgVerify() before calling GPG - No-op on non-Windows platforms - Add comprehensive tests for path conversion This ensures GPG signature verification works on all platforms (Linux, macOS, and Windows). Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
79d962c4f8
commit
7a11667fa2
4 changed files with 161 additions and 19 deletions
|
|
@ -18,16 +18,17 @@
|
|||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
import { describe, it, afterEach, beforeEach } from "node:test";
|
||||
import { describe, it, afterEach } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as os from "os";
|
||||
import * as fs from "node:fs";
|
||||
import * as os from "node:os";
|
||||
import * as path from "node:path";
|
||||
import {
|
||||
getGpgCommand,
|
||||
setupGpgHome,
|
||||
cleanupGpgHome,
|
||||
importSonarSourceKey,
|
||||
convertToUnixPath,
|
||||
} from "../gpg-verification.js";
|
||||
|
||||
describe("gpg-verification", () => {
|
||||
|
|
@ -54,6 +55,80 @@ describe("gpg-verification", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("convertToUnixPath", () => {
|
||||
it("should convert Windows path with drive letter to Unix path", () => {
|
||||
// Mock Windows platform
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: "win32",
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
try {
|
||||
assert.equal(
|
||||
convertToUnixPath("C:\\a\\_temp\\gpg-home"),
|
||||
"/c/a/_temp/gpg-home"
|
||||
);
|
||||
assert.equal(
|
||||
convertToUnixPath("D:\\Users\\test\\file.txt"),
|
||||
"/d/Users/test/file.txt"
|
||||
);
|
||||
} finally {
|
||||
// Restore original platform
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: originalPlatform,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("should handle mixed slashes on Windows", () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: "win32",
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
try {
|
||||
assert.equal(
|
||||
convertToUnixPath("C:\\a/_temp\\gpg-home"),
|
||||
"/c/a/_temp/gpg-home"
|
||||
);
|
||||
} finally {
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: originalPlatform,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
it("should return path unchanged on non-Windows platforms", () => {
|
||||
const originalPlatform = process.platform;
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: "linux",
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
|
||||
try {
|
||||
assert.equal(
|
||||
convertToUnixPath("/tmp/gpg-home"),
|
||||
"/tmp/gpg-home"
|
||||
);
|
||||
} finally {
|
||||
Object.defineProperty(process, "platform", {
|
||||
value: originalPlatform,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("setupGpgHome", () => {
|
||||
it("should create a temporary GPG home directory", () => {
|
||||
const gpgHome = setupGpgHome();
|
||||
|
|
@ -65,8 +140,8 @@ describe("gpg-verification", () => {
|
|||
// Check directory permissions (on Unix systems)
|
||||
if (process.platform !== "win32") {
|
||||
const stats = fs.statSync(gpgHome);
|
||||
const mode = stats.mode & parseInt("777", 8);
|
||||
assert.equal(mode, parseInt("700", 8));
|
||||
const mode = stats.mode & Number.parseInt("777", 8);
|
||||
assert.equal(mode, Number.parseInt("700", 8));
|
||||
}
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -20,9 +20,9 @@
|
|||
|
||||
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";
|
||||
|
||||
// SonarSource public key fingerprint for verifying scanner signatures
|
||||
const SONARSOURCE_KEY_FINGERPRINT = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
|
||||
|
|
@ -99,6 +99,28 @@ export function getGpgCommand() {
|
|||
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;
|
||||
}
|
||||
|
||||
// Convert backslashes to forward slashes
|
||||
let unixPath = windowsPath.replace(/\\/g, "/");
|
||||
|
||||
// Convert drive letter (e.g., C: -> /c)
|
||||
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
|
||||
|
|
@ -122,12 +144,14 @@ export function setupGpgHome() {
|
|||
*/
|
||||
async function tryImportKey(gpgHome, keyFingerprint, keyserver) {
|
||||
const gpgCommand = getGpgCommand();
|
||||
// Convert Windows paths to Unix-style for GPG compatibility
|
||||
const gpgHomePath = convertToUnixPath(gpgHome);
|
||||
|
||||
await exec.exec(
|
||||
gpgCommand,
|
||||
[
|
||||
"--homedir",
|
||||
gpgHome,
|
||||
gpgHomePath,
|
||||
"--batch",
|
||||
"--keyserver",
|
||||
keyserver,
|
||||
|
|
@ -192,9 +216,17 @@ export async function runGpgVerify(zipPath, signaturePath, gpgHome) {
|
|||
|
||||
try {
|
||||
core.info("Verifying GPG signature...");
|
||||
// Convert Windows paths to Unix-style for GPG compatibility
|
||||
await exec.exec(
|
||||
gpgCommand,
|
||||
["--homedir", gpgHome, "--batch", "--verify", signaturePath, zipPath],
|
||||
[
|
||||
"--homedir",
|
||||
convertToUnixPath(gpgHome),
|
||||
"--batch",
|
||||
"--verify",
|
||||
convertToUnixPath(signaturePath),
|
||||
convertToUnixPath(zipPath),
|
||||
],
|
||||
{
|
||||
silent: false,
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue