mirror of
https://github.com/SonarSource/sonarqube-scan-action.git
synced 2026-05-23 10:25:56 +00:00
Commit 1 of SonarQube suggestions Fully fixed issues: - [javascript:S7780] AZ3P6TLCKPJHm3wzH1C-: `String.raw` should be used to avoid escaping `\`. - [javascript:S7780] AZ3P6TLCKPJHm3wzH1C_: `String.raw` should be used to avoid escaping `\`. - [javascript:S7780] AZ3P6TLCKPJHm3wzH1DA: `String.raw` should be used to avoid escaping `\`. Generated by SonarQube Agent
261 lines
8.4 KiB
JavaScript
261 lines
8.4 KiB
JavaScript
/*
|
|
* 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,
|
|
importSonarSourceKey,
|
|
convertToUnixPath,
|
|
} from "../gpg-verification.js";
|
|
|
|
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", () => {
|
|
// 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(String.raw`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(String.raw`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();
|
|
tempDirs.push(gpgHome);
|
|
|
|
assert.ok(fs.existsSync(gpgHome));
|
|
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 = setupGpgHome();
|
|
// Small delay to ensure different timestamps
|
|
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
const gpgHome2 = setupGpgHome();
|
|
tempDirs.push(gpgHome1, gpgHome2);
|
|
|
|
assert.notEqual(gpgHome1, gpgHome2);
|
|
assert.ok(fs.existsSync(gpgHome1));
|
|
assert.ok(fs.existsSync(gpgHome2));
|
|
});
|
|
|
|
it("should use RUNNER_TEMP if available", () => {
|
|
const originalRunnerTemp = process.env.RUNNER_TEMP;
|
|
const testTemp = path.join(os.tmpdir(), `test-runner-temp-${Date.now()}`);
|
|
|
|
try {
|
|
fs.mkdirSync(testTemp, { recursive: true });
|
|
process.env.RUNNER_TEMP = testTemp;
|
|
|
|
const gpgHome = setupGpgHome();
|
|
tempDirs.push(gpgHome);
|
|
|
|
assert.ok(gpgHome.startsWith(testTemp));
|
|
assert.ok(fs.existsSync(gpgHome));
|
|
} finally {
|
|
process.env.RUNNER_TEMP = originalRunnerTemp;
|
|
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");
|
|
});
|
|
});
|
|
});
|
|
|
|
describe("importSonarSourceKey - fallback behavior", () => {
|
|
it("should use fallback keyserver when primary fails", async () => {
|
|
const gpgHome = setupGpgHome();
|
|
tempDirs.push(gpgHome);
|
|
|
|
// Use an invalid keyserver as primary that will definitely fail
|
|
const invalidKeyserver = "hkps://invalid.keyserver.that.does.not.exist.example.com";
|
|
const keyFingerprint = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
|
|
|
|
// This should:
|
|
// 1. Try invalid primary keyserver (fail)
|
|
// 2. Fall back to hkps://keys.openpgp.org (succeed)
|
|
// Since the fallback should succeed, this won't throw
|
|
await importSonarSourceKey(gpgHome, keyFingerprint, invalidKeyserver);
|
|
|
|
// If we get here, the fallback mechanism worked correctly
|
|
assert.ok(true, "Fallback keyserver was successfully used");
|
|
});
|
|
|
|
it("should succeed with valid keyserver (when GPG and network available)", async () => {
|
|
// This is more of an integration test - only runs if GPG is available
|
|
// Skip if running in environment without GPG or network access
|
|
try {
|
|
const gpgHome = setupGpgHome();
|
|
tempDirs.push(gpgHome);
|
|
|
|
const keyserver = "hkps://keyserver.ubuntu.com";
|
|
const keyFingerprint = "679F1EE92B19609DE816FDE81DB198F93525EC1A";
|
|
|
|
// This test will succeed if:
|
|
// 1. GPG is available
|
|
// 2. Network is available
|
|
// 3. Primary keyserver works
|
|
// It demonstrates that the happy path works correctly
|
|
await importSonarSourceKey(gpgHome, keyFingerprint, keyserver);
|
|
|
|
// If we get here, import succeeded - test passes
|
|
assert.ok(true, "Key import succeeded from primary keyserver");
|
|
} catch (error) {
|
|
// If this fails, it could be due to:
|
|
// - No GPG installed (unlikely in CI)
|
|
// - No network (possible in some test environments)
|
|
// - Keyserver down (possible but rare)
|
|
// We allow the test to pass if it's a network/GPG issue
|
|
if (error.message.includes("Failed to import SonarSource public key from all keyservers")) {
|
|
// This means fallback was attempted, which is what we want to verify
|
|
assert.ok(true, "Fallback mechanism was triggered");
|
|
} else {
|
|
// Some other error - let it fail
|
|
throw error;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
});
|