SQSCANGHA-113 Migrate scanner run step

This commit is contained in:
Jeremy Davis 2025-09-10 11:28:29 +02:00
parent 557ebf1d22
commit 2261a564dc
9 changed files with 448 additions and 137 deletions

View file

@ -10,4 +10,4 @@ services:
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 20 retries: 20
start_period: 2m start_period: 2m

View file

@ -490,7 +490,7 @@ jobs:
uses: ./ uses: ./
with: with:
scannerVersion: 6.2.1.4610 scannerVersion: 6.2.1.4610
scannerBinariesUrl: https://localhost:8080/clientRedirectToSonarBinaries scannerBinariesUrl: http://localhost:8080/clientRedirectToSonarBinaries
env: env:
NO_CACHE: true NO_CACHE: true
SONAR_HOST_URL: http://not_actually_used SONAR_HOST_URL: http://not_actually_used
@ -660,40 +660,6 @@ jobs:
- name: Assert failure of previous step - name: Assert failure of previous step
if: steps.wrong_ssl_certificate.outcome == 'success' if: steps.wrong_ssl_certificate.outcome == 'success'
run: exit 1 run: exit 1
overridesScannerLocalFolderWhenPresent: # can happen in uncleaned self-hosted runners
name: >
'SCANNER_LOCAL_FOLDER' is cleaned with warning when present
runs-on: github-ubuntu-latest-s
steps:
- uses: actions/checkout@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Create a dummy SCANNER_LOCAL_FOLDER with dummy content in it
run: |
SCANNER_VERSION="6.2.1.4610"
SCANNER_LOCAL_FOLDER="$RUNNER_TEMP/sonar-scanner-cli-$SCANNER_VERSION-$RUNNER_OS-$RUNNER_ARCH"
# emit SCANNER_VERSION and SCANNER_LOCAL_FOLDER to be able to read them in the next steps
echo "SCANNER_VERSION=$SCANNER_VERSION" >> $GITHUB_ENV
echo "SCANNER_LOCAL_FOLDER=$SCANNER_LOCAL_FOLDER" >> $GITHUB_ENV
mkdir -p "$SCANNER_LOCAL_FOLDER"
touch "$SCANNER_LOCAL_FOLDER/some_content.txt"
- name: Assert SCANNER_LOCAL_FOLDER exists and dummy file is in it
run: |
[ -d "$SCANNER_LOCAL_FOLDER" ] || exit 1
[ -f "$SCANNER_LOCAL_FOLDER/some_content.txt" ] || exit 1
- name: Run action with SONAR_SCANNER_TEMP
uses: ./
env:
NO_CACHE: true # force install-sonar-scanner-cli.sh execution
SONAR_SCANNER_TEMP: /tmp/sonar-scanner
SONAR_HOST_URL: http://not_actually_used
with:
args: -Dsonar.scanner.internal.dumpToFile=./output.properties
scannerVersion: ${{ env.SCANNER_VERSION }}
- name: Assert SCANNER_LOCAL_FOLDER exists and dummy file is not in it
run: |
[ -d "$SCANNER_LOCAL_FOLDER" ] || exit 1
[ ! -f "$SCANNER_LOCAL_FOLDER/some_content.txt" ] || exit 1
updateTruststoreWhenPresent: # can happen in uncleaned self-hosted runners updateTruststoreWhenPresent: # can happen in uncleaned self-hosted runners
name: > name: >
truststore.p12 is updated when present truststore.p12 is updated when present

View file

@ -10,9 +10,11 @@ inputs:
args: args:
description: Additional arguments to the Sonar Scanner CLI description: Additional arguments to the Sonar Scanner CLI
required: false required: false
default: ""
projectBaseDir: projectBaseDir:
description: Set the sonar.projectBaseDir analysis property description: Set the sonar.projectBaseDir analysis property
required: false required: false
default: "."
scannerVersion: scannerVersion:
description: Version of the Sonar Scanner CLI to use description: Version of the Sonar Scanner CLI to use
required: false required: false
@ -23,25 +25,5 @@ inputs:
required: false required: false
default: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli default: https://binaries.sonarsource.com/Distribution/sonar-scanner-cli
runs: runs:
using: "composite" using: node20
steps: main: dist/index.js
# - name: Checkout
# uses: actions/checkout@v5
# with:
# ref: "jay/js-rewrite"
- name: Sanity checks & setup
run: node ./dist/index.js
shell: bash
env:
INPUT_PROJECTBASEDIR: ${{ inputs.projectBaseDir }}
INPUT_SCANNERVERSION: ${{ inputs.scannerVersion }}
INPUT_SCANNERBINARIESURL: ${{ inputs.scannerBinariesUrl }}
- name: Run SonarScanner
run: ${GITHUB_ACTION_PATH}/scripts/run-sonar-scanner.sh
shell: bash
env:
INPUT_ARGS: ${{ inputs.args }}
INPUT_PROJECTBASEDIR: ${{ inputs.projectBaseDir }}
SONAR_SCANNER_JRE: ${{ runner.temp }}/sonar-scanner-cli-${{ inputs.scannerVersion }}-${{ runner.os }}-${{ runner.arch }}/jre

315
dist/index.js vendored
View file

@ -1,13 +1,14 @@
import * as require$$0 from 'os'; import * as require$$0 from 'os';
import require$$0__default from 'os'; import require$$0__default from 'os';
import require$$0$1 from 'crypto'; import require$$0$1 from 'crypto';
import fs from 'fs'; import * as fs from 'fs';
import * as require$$1 from 'path'; import fs__default from 'fs';
import require$$1__default, { join } from 'path'; import * as path from 'path';
import path__default, { join } from 'path';
import require$$2 from 'http'; import require$$2 from 'http';
import require$$3 from 'https'; import require$$3 from 'https';
import require$$0$4 from 'net'; import require$$0$4 from 'net';
import require$$1$1 from 'tls'; import require$$1 from 'tls';
import require$$4 from 'events'; import require$$4 from 'events';
import require$$0$3 from 'assert'; import require$$0$3 from 'assert';
import require$$0$2 from 'util'; import require$$0$2 from 'util';
@ -16,14 +17,14 @@ import require$$7 from 'buffer';
import require$$8 from 'querystring'; import require$$8 from 'querystring';
import require$$14 from 'stream/web'; import require$$14 from 'stream/web';
import require$$0$7 from 'node:stream'; import require$$0$7 from 'node:stream';
import require$$1$2 from 'node:util'; import require$$1$1 from 'node:util';
import require$$0$6 from 'node:events'; import require$$0$6 from 'node:events';
import require$$0$8 from 'worker_threads'; import require$$0$8 from 'worker_threads';
import require$$2$1 from 'perf_hooks'; import require$$2$1 from 'perf_hooks';
import require$$5 from 'util/types'; import require$$5 from 'util/types';
import require$$4$1 from 'async_hooks'; import require$$4$1 from 'async_hooks';
import require$$1$3 from 'console'; import require$$1$2 from 'console';
import require$$1$4 from 'url'; import require$$1$3 from 'url';
import require$$3$1 from 'zlib'; import require$$3$1 from 'zlib';
import require$$6 from 'string_decoder'; import require$$6 from 'string_decoder';
import require$$0$9 from 'diagnostics_channel'; import require$$0$9 from 'diagnostics_channel';
@ -243,7 +244,7 @@ function requireFileCommand () {
// We use any as a valid input type // We use any as a valid input type
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
const crypto = __importStar(require$$0$1); const crypto = __importStar(require$$0$1);
const fs$1 = __importStar(fs); const fs = __importStar(fs__default);
const os = __importStar(require$$0__default); const os = __importStar(require$$0__default);
const utils_1 = requireUtils$1(); const utils_1 = requireUtils$1();
function issueFileCommand(command, message) { function issueFileCommand(command, message) {
@ -251,10 +252,10 @@ function requireFileCommand () {
if (!filePath) { if (!filePath) {
throw new Error(`Unable to find environment variable for file command ${command}`); throw new Error(`Unable to find environment variable for file command ${command}`);
} }
if (!fs$1.existsSync(filePath)) { if (!fs.existsSync(filePath)) {
throw new Error(`Missing file at path: ${filePath}`); throw new Error(`Missing file at path: ${filePath}`);
} }
fs$1.appendFileSync(filePath, `${(0, utils_1.toCommandValue)(message)}${os.EOL}`, { fs.appendFileSync(filePath, `${(0, utils_1.toCommandValue)(message)}${os.EOL}`, {
encoding: 'utf8' encoding: 'utf8'
}); });
} }
@ -393,7 +394,7 @@ var hasRequiredTunnel$1;
function requireTunnel$1 () { function requireTunnel$1 () {
if (hasRequiredTunnel$1) return tunnel$1; if (hasRequiredTunnel$1) return tunnel$1;
hasRequiredTunnel$1 = 1; hasRequiredTunnel$1 = 1;
var tls = require$$1$1; var tls = require$$1;
var http = require$$2; var http = require$$2;
var https = require$$3; var https = require$$3;
var events = require$$4; var events = require$$4;
@ -1775,7 +1776,7 @@ function requireSbmh () {
* by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool * by Hongli Lai at: https://github.com/FooBarWidget/boyer-moore-horspool
*/ */
const EventEmitter = require$$0$6.EventEmitter; const EventEmitter = require$$0$6.EventEmitter;
const inherits = require$$1$2.inherits; const inherits = require$$1$1.inherits;
function SBMH (needle) { function SBMH (needle) {
if (typeof needle === 'string') { if (typeof needle === 'string') {
@ -1984,7 +1985,7 @@ function requirePartStream () {
if (hasRequiredPartStream) return PartStream_1; if (hasRequiredPartStream) return PartStream_1;
hasRequiredPartStream = 1; hasRequiredPartStream = 1;
const inherits = require$$1$2.inherits; const inherits = require$$1$1.inherits;
const ReadableStream = require$$0$7.Readable; const ReadableStream = require$$0$7.Readable;
function PartStream (opts) { function PartStream (opts) {
@ -2030,7 +2031,7 @@ function requireHeaderParser () {
hasRequiredHeaderParser = 1; hasRequiredHeaderParser = 1;
const EventEmitter = require$$0$6.EventEmitter; const EventEmitter = require$$0$6.EventEmitter;
const inherits = require$$1$2.inherits; const inherits = require$$1$1.inherits;
const getLimit = requireGetLimit(); const getLimit = requireGetLimit();
const StreamSearch = requireSbmh(); const StreamSearch = requireSbmh();
@ -2138,7 +2139,7 @@ function requireDicer () {
hasRequiredDicer = 1; hasRequiredDicer = 1;
const WritableStream = require$$0$7.Writable; const WritableStream = require$$0$7.Writable;
const inherits = require$$1$2.inherits; const inherits = require$$1$1.inherits;
const StreamSearch = requireSbmh(); const StreamSearch = requireSbmh();
@ -2715,7 +2716,7 @@ function requireMultipart () {
// -- this will require modifications to utils.parseParams // -- this will require modifications to utils.parseParams
const { Readable } = require$$0$7; const { Readable } = require$$0$7;
const { inherits } = require$$1$2; const { inherits } = require$$1$1;
const Dicer = requireDicer(); const Dicer = requireDicer();
@ -3281,7 +3282,7 @@ function requireMain () {
hasRequiredMain = 1; hasRequiredMain = 1;
const WritableStream = require$$0$7.Writable; const WritableStream = require$$0$7.Writable;
const { inherits } = require$$1$2; const { inherits } = require$$1$1;
const Dicer = requireDicer(); const Dicer = requireDicer();
const MultipartParser = requireMultipart(); const MultipartParser = requireMultipart();
@ -8105,7 +8106,7 @@ function requireConnect () {
let socket; let socket;
if (protocol === 'https:') { if (protocol === 'https:') {
if (!tls) { if (!tls) {
tls = require$$1$1; tls = require$$1;
} }
servername = servername || options.servername || util.getServerName(host) || null; servername = servername || options.servername || util.getServerName(host) || null;
@ -14129,7 +14130,7 @@ function requirePendingInterceptorsFormatter () {
hasRequiredPendingInterceptorsFormatter = 1; hasRequiredPendingInterceptorsFormatter = 1;
const { Transform } = require$$0$5; const { Transform } = require$$0$5;
const { Console } = require$$1$3; const { Console } = require$$1$2;
/** /**
* Gets the output of `console.table(…)` as a string. * Gets the output of `console.table(…)` as a string.
@ -14356,7 +14357,7 @@ function requireProxyAgent () {
hasRequiredProxyAgent = 1; hasRequiredProxyAgent = 1;
const { kProxy, kClose, kDestroy, kInterceptors } = requireSymbols$4(); const { kProxy, kClose, kDestroy, kInterceptors } = requireSymbols$4();
const { URL } = require$$1$4; const { URL } = require$$1$3;
const Agent = requireAgent(); const Agent = requireAgent();
const Pool = requirePool(); const Pool = requirePool();
const DispatcherBase = requireDispatcherBase(); const DispatcherBase = requireDispatcherBase();
@ -25221,7 +25222,7 @@ function requireSummary () {
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.summary = exports.markdownSummary = exports.SUMMARY_DOCS_URL = exports.SUMMARY_ENV_VAR = void 0; exports.summary = exports.markdownSummary = exports.SUMMARY_DOCS_URL = exports.SUMMARY_ENV_VAR = void 0;
const os_1 = require$$0__default; const os_1 = require$$0__default;
const fs_1 = fs; const fs_1 = fs__default;
const { access, appendFile, writeFile } = fs_1.promises; const { access, appendFile, writeFile } = fs_1.promises;
exports.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY'; exports.SUMMARY_ENV_VAR = 'GITHUB_STEP_SUMMARY';
exports.SUMMARY_DOCS_URL = 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary'; exports.SUMMARY_DOCS_URL = 'https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#adding-a-job-summary';
@ -25527,7 +25528,7 @@ function requirePathUtils () {
}; };
Object.defineProperty(pathUtils, "__esModule", { value: true }); Object.defineProperty(pathUtils, "__esModule", { value: true });
pathUtils.toPlatformPath = pathUtils.toWin32Path = pathUtils.toPosixPath = void 0; pathUtils.toPlatformPath = pathUtils.toWin32Path = pathUtils.toPosixPath = void 0;
const path = __importStar(require$$1__default); const path = __importStar(path__default);
/** /**
* toPosixPath converts the given path to the posix form. On Windows, \\ will be * toPosixPath converts the given path to the posix form. On Windows, \\ will be
* replaced with /. * replaced with /.
@ -25613,16 +25614,16 @@ function requireIoUtil () {
var _a; var _a;
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0; exports.getCmdPath = exports.tryGetExecutablePath = exports.isRooted = exports.isDirectory = exports.exists = exports.READONLY = exports.UV_FS_O_EXLOCK = exports.IS_WINDOWS = exports.unlink = exports.symlink = exports.stat = exports.rmdir = exports.rm = exports.rename = exports.readlink = exports.readdir = exports.open = exports.mkdir = exports.lstat = exports.copyFile = exports.chmod = void 0;
const fs$1 = __importStar(fs); const fs = __importStar(fs__default);
const path = __importStar(require$$1__default); const path = __importStar(path__default);
_a = fs$1.promises _a = fs.promises
// export const {open} = 'fs' // export const {open} = 'fs'
, exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink; , exports.chmod = _a.chmod, exports.copyFile = _a.copyFile, exports.lstat = _a.lstat, exports.mkdir = _a.mkdir, exports.open = _a.open, exports.readdir = _a.readdir, exports.readlink = _a.readlink, exports.rename = _a.rename, exports.rm = _a.rm, exports.rmdir = _a.rmdir, exports.stat = _a.stat, exports.symlink = _a.symlink, exports.unlink = _a.unlink;
// export const {open} = 'fs' // export const {open} = 'fs'
exports.IS_WINDOWS = process.platform === 'win32'; exports.IS_WINDOWS = process.platform === 'win32';
// See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691 // See https://github.com/nodejs/node/blob/d0153aee367422d0858105abec186da4dff0a0c5/deps/uv/include/uv/win.h#L691
exports.UV_FS_O_EXLOCK = 0x10000000; exports.UV_FS_O_EXLOCK = 0x10000000;
exports.READONLY = fs$1.constants.O_RDONLY; exports.READONLY = fs.constants.O_RDONLY;
function exists(fsPath) { function exists(fsPath) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
try { try {
@ -25804,7 +25805,7 @@ function requireIo () {
Object.defineProperty(io, "__esModule", { value: true }); Object.defineProperty(io, "__esModule", { value: true });
io.findInPath = io.which = io.mkdirP = io.rmRF = io.mv = io.cp = void 0; io.findInPath = io.which = io.mkdirP = io.rmRF = io.mv = io.cp = void 0;
const assert_1 = require$$0$3; const assert_1 = require$$0$3;
const path = __importStar(require$$1__default); const path = __importStar(path__default);
const ioUtil = __importStar(requireIoUtil()); const ioUtil = __importStar(requireIoUtil());
/** /**
* Copies a file or folder. * Copies a file or folder.
@ -26112,7 +26113,7 @@ function requireToolrunner () {
const os = __importStar(require$$0__default); const os = __importStar(require$$0__default);
const events = __importStar(require$$4); const events = __importStar(require$$4);
const child = __importStar(require$$2$2); const child = __importStar(require$$2$2);
const path = __importStar(require$$1__default); const path = __importStar(path__default);
const io = __importStar(requireIo()); const io = __importStar(requireIo());
const ioUtil = __importStar(requireIoUtil()); const ioUtil = __importStar(requireIoUtil());
const timers_1 = require$$6$1; const timers_1 = require$$6$1;
@ -26956,7 +26957,7 @@ function requireCore () {
const file_command_1 = requireFileCommand(); const file_command_1 = requireFileCommand();
const utils_1 = requireUtils$1(); const utils_1 = requireUtils$1();
const os = __importStar(require$$0__default); const os = __importStar(require$$0__default);
const path = __importStar(require$$1__default); const path = __importStar(path__default);
const oidc_utils_1 = requireOidcUtils(); const oidc_utils_1 = requireOidcUtils();
/** /**
* The code to exit an action * The code to exit an action
@ -28980,7 +28981,7 @@ function requireManifest () {
/* eslint @typescript-eslint/no-require-imports: 0 */ /* eslint @typescript-eslint/no-require-imports: 0 */
const os = require$$0__default; const os = require$$0__default;
const cp = require$$2$2; const cp = require$$2$2;
const fs$1 = fs; const fs = fs__default;
function _findMatch(versionSpec, stable, candidates, archFilter) { function _findMatch(versionSpec, stable, candidates, archFilter) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
const platFilter = os.platform(); const platFilter = os.platform();
@ -29058,11 +29059,11 @@ function requireManifest () {
const lsbReleaseFile = '/etc/lsb-release'; const lsbReleaseFile = '/etc/lsb-release';
const osReleaseFile = '/etc/os-release'; const osReleaseFile = '/etc/os-release';
let contents = ''; let contents = '';
if (fs$1.existsSync(lsbReleaseFile)) { if (fs.existsSync(lsbReleaseFile)) {
contents = fs$1.readFileSync(lsbReleaseFile).toString(); contents = fs.readFileSync(lsbReleaseFile).toString();
} }
else if (fs$1.existsSync(osReleaseFile)) { else if (fs.existsSync(osReleaseFile)) {
contents = fs$1.readFileSync(osReleaseFile).toString(); contents = fs.readFileSync(osReleaseFile).toString();
} }
return contents; return contents;
} }
@ -29210,10 +29211,10 @@ function requireToolCache () {
const core = __importStar(requireCore()); const core = __importStar(requireCore());
const io = __importStar(requireIo()); const io = __importStar(requireIo());
const crypto = __importStar(require$$0$1); const crypto = __importStar(require$$0$1);
const fs$1 = __importStar(fs); const fs = __importStar(fs__default);
const mm = __importStar(requireManifest()); const mm = __importStar(requireManifest());
const os = __importStar(require$$0__default); const os = __importStar(require$$0__default);
const path = __importStar(require$$1__default); const path = __importStar(path__default);
const httpm = __importStar(requireLib()); const httpm = __importStar(requireLib());
const semver = __importStar(requireSemver()); const semver = __importStar(requireSemver());
const stream = __importStar(require$$0$5); const stream = __importStar(require$$0$5);
@ -29270,7 +29271,7 @@ function requireToolCache () {
toolCache.downloadTool = downloadTool; toolCache.downloadTool = downloadTool;
function downloadToolAttempt(url, dest, auth, headers) { function downloadToolAttempt(url, dest, auth, headers) {
return __awaiter(this, void 0, void 0, function* () { return __awaiter(this, void 0, void 0, function* () {
if (fs$1.existsSync(dest)) { if (fs.existsSync(dest)) {
throw new Error(`Destination file path ${dest} already exists`); throw new Error(`Destination file path ${dest} already exists`);
} }
// Get the response headers // Get the response headers
@ -29296,7 +29297,7 @@ function requireToolCache () {
const readStream = responseMessageFactory(); const readStream = responseMessageFactory();
let succeeded = false; let succeeded = false;
try { try {
yield pipeline(readStream, fs$1.createWriteStream(dest)); yield pipeline(readStream, fs.createWriteStream(dest));
core.debug('download complete'); core.debug('download complete');
succeeded = true; succeeded = true;
return dest; return dest;
@ -29577,14 +29578,14 @@ function requireToolCache () {
arch = arch || os.arch(); arch = arch || os.arch();
core.debug(`Caching tool ${tool} ${version} ${arch}`); core.debug(`Caching tool ${tool} ${version} ${arch}`);
core.debug(`source dir: ${sourceDir}`); core.debug(`source dir: ${sourceDir}`);
if (!fs$1.statSync(sourceDir).isDirectory()) { if (!fs.statSync(sourceDir).isDirectory()) {
throw new Error('sourceDir is not a directory'); throw new Error('sourceDir is not a directory');
} }
// Create the tool dir // Create the tool dir
const destPath = yield _createToolPath(tool, version, arch); const destPath = yield _createToolPath(tool, version, arch);
// copy each child item. do not move. move can fail on Windows // copy each child item. do not move. move can fail on Windows
// due to anti-virus software having an open handle on a file. // due to anti-virus software having an open handle on a file.
for (const itemName of fs$1.readdirSync(sourceDir)) { for (const itemName of fs.readdirSync(sourceDir)) {
const s = path.join(sourceDir, itemName); const s = path.join(sourceDir, itemName);
yield io.cp(s, destPath, { recursive: true }); yield io.cp(s, destPath, { recursive: true });
} }
@ -29610,7 +29611,7 @@ function requireToolCache () {
arch = arch || os.arch(); arch = arch || os.arch();
core.debug(`Caching tool ${tool} ${version} ${arch}`); core.debug(`Caching tool ${tool} ${version} ${arch}`);
core.debug(`source file: ${sourceFile}`); core.debug(`source file: ${sourceFile}`);
if (!fs$1.statSync(sourceFile).isFile()) { if (!fs.statSync(sourceFile).isFile()) {
throw new Error('sourceFile is not a file'); throw new Error('sourceFile is not a file');
} }
// create the tool dir // create the tool dir
@ -29653,7 +29654,7 @@ function requireToolCache () {
versionSpec = semver.clean(versionSpec) || ''; versionSpec = semver.clean(versionSpec) || '';
const cachePath = path.join(_getCacheDirectory(), toolName, versionSpec, arch); const cachePath = path.join(_getCacheDirectory(), toolName, versionSpec, arch);
core.debug(`checking cache: ${cachePath}`); core.debug(`checking cache: ${cachePath}`);
if (fs$1.existsSync(cachePath) && fs$1.existsSync(`${cachePath}.complete`)) { if (fs.existsSync(cachePath) && fs.existsSync(`${cachePath}.complete`)) {
core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`); core.debug(`Found tool in cache ${toolName} ${versionSpec} ${arch}`);
toolPath = cachePath; toolPath = cachePath;
} }
@ -29674,12 +29675,12 @@ function requireToolCache () {
const versions = []; const versions = [];
arch = arch || os.arch(); arch = arch || os.arch();
const toolPath = path.join(_getCacheDirectory(), toolName); const toolPath = path.join(_getCacheDirectory(), toolName);
if (fs$1.existsSync(toolPath)) { if (fs.existsSync(toolPath)) {
const children = fs$1.readdirSync(toolPath); const children = fs.readdirSync(toolPath);
for (const child of children) { for (const child of children) {
if (isExplicitVersion(child)) { if (isExplicitVersion(child)) {
const fullPath = path.join(toolPath, child, arch || ''); const fullPath = path.join(toolPath, child, arch || '');
if (fs$1.existsSync(fullPath) && fs$1.existsSync(`${fullPath}.complete`)) { if (fs.existsSync(fullPath) && fs.existsSync(`${fullPath}.complete`)) {
versions.push(child); versions.push(child);
} }
} }
@ -29757,7 +29758,7 @@ function requireToolCache () {
function _completeToolPath(tool, version, arch) { function _completeToolPath(tool, version, arch) {
const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || ''); const folderPath = path.join(_getCacheDirectory(), tool, semver.clean(version) || version, arch || '');
const markerPath = `${folderPath}.complete`; const markerPath = `${folderPath}.complete`;
fs$1.writeFileSync(markerPath, ''); fs.writeFileSync(markerPath, '');
core.debug('finished caching tool'); core.debug('finished caching tool');
} }
/** /**
@ -29843,6 +29844,178 @@ function requireToolCache () {
var toolCacheExports = requireToolCache(); var toolCacheExports = requireToolCache();
var execExports = requireExec();
function parseArgsStringToArgv(value, env, file) {
// ([^\s'"]([^\s'"]*(['"])([^\3]*?)\3)+[^\s'"]*) Matches nested quotes until the first space outside of quotes
// [^\s'"]+ or Match if not a space ' or "
// (['"])([^\5]*?)\5 or Match "quoted text" without quotes
// `\3` and `\5` are a backreference to the quote style (' or ") captured
var myRegexp = /([^\s'"]([^\s'"]*(['"])([^\3]*?)\3)+[^\s'"]*)|[^\s'"]+|(['"])([^\5]*?)\5/gi;
var myString = value;
var myArray = [];
var match;
do {
// Each call to exec returns the next regex match as an array
match = myRegexp.exec(myString);
if (match !== null) {
// Index 1 in the array is the captured group if it exists
// Index 0 is the matched text, which we use if no captured group exists
myArray.push(firstString(match[1], match[6], match[0]));
}
} while (match !== null);
return myArray;
}
// Accepts any number of arguments, and returns the first one that is a string
// (even an empty string)
function firstString() {
var args = [];
for (var _i = 0; _i < arguments.length; _i++) {
args[_i] = arguments[_i];
}
for (var i = 0; i < args.length; i++) {
var arg = args[i];
if (typeof arg === "string") {
return arg;
}
}
}
async function runSonarScanner(
inputArgs,
projectBaseDir,
scannerDir,
runnerEnv = {}
) {
const {
RUNNER_DEBUG,
RUNNER_OS,
RUNNER_TEMP,
SONAR_ROOT_CERT,
SONARCLOUD_URL,
} = runnerEnv;
const scannerBin =
RUNNER_OS === "Windows" ? "sonar-scanner.bat" : "sonar-scanner";
const scannerArgs = [];
if (SONARCLOUD_URL) {
scannerArgs.push(`-Dsonar.scanner.sonarcloudUrl=${SONARCLOUD_URL}`);
}
if (RUNNER_DEBUG === "1") {
scannerArgs.push("--debug");
}
if (projectBaseDir) {
scannerArgs.push(`-Dsonar.projectBaseDir=${projectBaseDir}`);
}
// The SSL folder may exist on an uncleaned self-hosted runner
const sslFolder = path.join(require$$0.homedir(), ".sonar", "ssl");
/**
* Use keytool for now, as SonarQube 10.6 and below doesn't support openssl generated keystores
* keytool requires a password > 6 characters, so we won't use the default password 'sonar'
*/
const keytoolMainClass = "sun.security.tools.keytool.Main";
const truststoreFile = path.join(sslFolder, "truststore.p12");
const truststorePassword = "changeit";
if (fs.existsSync(truststoreFile)) {
let aliasSonarIsPresent = true;
try {
await execExports.exec(
`${scannerDir}/jre/bin/java`,
[
keytoolMainClass,
"-storetype",
"PKCS12",
"-keystore",
truststoreFile,
"-storepass",
truststorePassword,
"-noprompt",
"-trustcacerts",
"-list",
"-v",
"-alias",
"sonar",
],
{ silent: true }
);
} catch (_) {
aliasSonarIsPresent = false;
console.log(
`Existing Scanner truststore ${truststoreFile} does not contain 'sonar' alias`
);
}
if (aliasSonarIsPresent) {
console.log(
`Removing 'sonar' alias from already existing Scanner truststore: ${truststoreFile}`
);
await execExports.exec(`${scannerDir}/jre/bin/java`, [
keytoolMainClass,
"-storetype",
"PKCS12",
"-keystore",
truststoreFile,
"-storepass",
truststorePassword,
"-noprompt",
"-trustcacerts",
"-delete",
"-alias",
"sonar",
]);
}
}
if (SONAR_ROOT_CERT) {
console.log("Adding SSL certificate to the Scanner truststore");
const tempCertPath = path.join(RUNNER_TEMP, "tmpcert.pem");
try {
fs.unlinkSync(tempCertPath);
} catch (_) {
// File doesn't exist, ignore
}
fs.writeFileSync(tempCertPath, SONAR_ROOT_CERT);
fs.mkdirSync(sslFolder, { recursive: true });
await execExports.exec(`${scannerDir}/jre/bin/java`, [
keytoolMainClass,
"-storetype",
"PKCS12",
"-keystore",
truststoreFile,
"-storepass",
truststorePassword,
"-noprompt",
"-trustcacerts",
"-importcert",
"-alias",
"sonar",
"-file",
tempCertPath,
]);
scannerArgs.push(
`-Dsonar.scanner.truststorePassword=${truststorePassword}`
);
}
if (inputArgs) {
const args = parseArgsStringToArgv(inputArgs);
scannerArgs.push(...args);
}
await execExports.exec(scannerBin, scannerArgs);
}
function validateScannerVersion(version) { function validateScannerVersion(version) {
if (!version) { if (!version) {
return; return;
@ -29866,7 +30039,7 @@ function checkSonarToken(core) {
function checkMavenProject(core, projectBaseDir) { function checkMavenProject(core, projectBaseDir) {
const pomPath = join(projectBaseDir.replace(/\/$/, ""), "pom.xml"); const pomPath = join(projectBaseDir.replace(/\/$/, ""), "pom.xml");
if (fs.existsSync(pomPath)) { if (fs__default.existsSync(pomPath)) {
core.warning( core.warning(
"Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action to get more accurate results." "Maven project detected. Sonar recommends running the 'org.sonarsource.scanner.maven:sonar-maven-plugin:sonar' goal during the build process instead of using this GitHub Action to get more accurate results."
); );
@ -29878,7 +30051,7 @@ function checkGradleProject(core, projectBaseDir) {
const gradlePath = join(baseDir, "build.gradle"); const gradlePath = join(baseDir, "build.gradle");
const gradleKtsPath = join(baseDir, "build.gradle.kts"); const gradleKtsPath = join(baseDir, "build.gradle.kts");
if (fs.existsSync(gradlePath) || fs.existsSync(gradleKtsPath)) { if (fs__default.existsSync(gradlePath) || fs__default.existsSync(gradleKtsPath)) {
core.warning( core.warning(
"Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action to get more accurate results." "Gradle project detected. Sonar recommends using the SonarQube plugin for Gradle during the build process instead of using this GitHub Action to get more accurate results."
); );
@ -29923,18 +30096,31 @@ const scannerDirName = (version, flavor) =>
const TOOLNAME = "sonar-scanner-cli"; const TOOLNAME = "sonar-scanner-cli";
/**
* Inputs are defined in action.yml
*/
function getInputs() { function getInputs() {
//FIXME: should not rely on ENV vars const args = coreExports.getInput("args");
const scannerVersion = process.env.INPUT_SCANNERVERSION; // core.getInput("scannerVersion"); const projectBaseDir = coreExports.getInput("projectBaseDir");
const projectBaseDir = process.env.INPUT_PROJECTBASEDIR; // core.getInput("projectBaseDir") || "."; const scannerBinariesUrl = coreExports.getInput("scannerBinariesUrl");
const scannerBinariesUrl = process.env.INPUT_SCANNERBINARIESURL; // core.getInput("scannerBinariesUrl"); const scannerVersion = coreExports.getInput("scannerVersion");
return { scannerVersion, projectBaseDir, scannerBinariesUrl }; return { args, projectBaseDir, scannerBinariesUrl, scannerVersion };
}
function getRunnerEnv() {
return {
RUNNER_OS: process.env.RUNNER_OS,
SONARCLOUD_URL: process.env.SONARCLOUD_URL,
RUNNER_DEBUG: process.env.RUNNER_DEBUG,
SONAR_ROOT_CERT: process.env.SONAR_ROOT_CERT,
RUNNER_TEMP: process.env.RUNNER_TEMP,
};
} }
function runSanityChecks(inputs) { function runSanityChecks(inputs) {
try { try {
const { scannerVersion, projectBaseDir } = inputs; const { projectBaseDir, scannerVersion } = inputs;
validateScannerVersion(scannerVersion); validateScannerVersion(scannerVersion);
checkSonarToken(core$1); checkSonarToken(core$1);
@ -29946,7 +30132,7 @@ function runSanityChecks(inputs) {
} }
} }
async function installSonarScannerCLI(scannerVersion, scannerBinariesUrl) { async function installSonarScannerCLI({ scannerVersion, scannerBinariesUrl }) {
const flavor = getPlatformFlavor(require$$0.platform(), require$$0.arch()); const flavor = getPlatformFlavor(require$$0.platform(), require$$0.arch());
// Check if tool is already cached // Check if tool is already cached
@ -29969,7 +30155,7 @@ async function installSonarScannerCLI(scannerVersion, scannerBinariesUrl) {
const extractedPath = await toolCacheExports.extractZip(downloadPath); const extractedPath = await toolCacheExports.extractZip(downloadPath);
// Find the actual scanner directory inside the extracted folder // Find the actual scanner directory inside the extracted folder
const scannerPath = require$$1.join( const scannerPath = path.join(
extractedPath, extractedPath,
scannerDirName(scannerVersion, flavor) scannerDirName(scannerVersion, flavor)
); );
@ -29982,7 +30168,7 @@ async function installSonarScannerCLI(scannerVersion, scannerBinariesUrl) {
} }
// Add the bin directory to PATH // Add the bin directory to PATH
const binDir = require$$1.join(toolDir, "bin"); const binDir = path.join(toolDir, "bin");
coreExports.addPath(binDir); coreExports.addPath(binDir);
return toolDir; return toolDir;
@ -29990,14 +30176,21 @@ async function installSonarScannerCLI(scannerVersion, scannerBinariesUrl) {
async function run() { async function run() {
try { try {
const inputs = getInputs(); const { args, projectBaseDir, scannerVersion, scannerBinariesUrl } =
const { scannerVersion, scannerBinariesUrl } = inputs; getInputs();
// Run sanity checks first // Run sanity checks first
runSanityChecks(inputs); runSanityChecks({ projectBaseDir, scannerVersion });
// Install Sonar Scanner CLI using @actions/tool-cache // Install Sonar Scanner CLI using @actions/tool-cache
await installSonarScannerCLI(scannerVersion, scannerBinariesUrl); const scannerDir = await installSonarScannerCLI({
scannerVersion,
scannerBinariesUrl,
});
// Run the sonar scanner
const runnerEnv = getRunnerEnv();
await runSonarScanner(args, projectBaseDir, scannerDir, runnerEnv);
} catch (error) { } catch (error) {
coreExports.setFailed(`Action failed: ${error.message}`); coreExports.setFailed(`Action failed: ${error.message}`);
process.exit(1); process.exit(1);

2
dist/index.js.map vendored

File diff suppressed because one or more lines are too long

18
package-lock.json generated
View file

@ -10,13 +10,14 @@
"license": "LGPL-3.0-only", "license": "LGPL-3.0-only",
"dependencies": { "dependencies": {
"@actions/core": "1.11.1", "@actions/core": "1.11.1",
"@actions/github": "6.0.1" "@actions/github": "6.0.1",
"@actions/tool-cache": "2.0.2",
"string-argv": "0.3.2"
}, },
"devDependencies": { "devDependencies": {
"@actions/tool-cache": "^2.0.2",
"@rollup/plugin-commonjs": "28.0.6", "@rollup/plugin-commonjs": "28.0.6",
"@rollup/plugin-node-resolve": "16.0.1", "@rollup/plugin-node-resolve": "16.0.1",
"mock-fs": "^5.5.0", "mock-fs": "5.5.0",
"rollup": "4.50.1" "rollup": "4.50.1"
} }
}, },
@ -74,7 +75,6 @@
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.2.tgz", "resolved": "https://registry.npmjs.org/@actions/tool-cache/-/tool-cache-2.0.2.tgz",
"integrity": "sha512-fBhNNOWxuoLxztQebpOaWu6WeVmuwa77Z+DxIZ1B+OYvGkGQon6kTVg6Z32Cb13WCuw0szqonK+hh03mJV7Z6w==", "integrity": "sha512-fBhNNOWxuoLxztQebpOaWu6WeVmuwa77Z+DxIZ1B+OYvGkGQon6kTVg6Z32Cb13WCuw0szqonK+hh03mJV7Z6w==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@actions/core": "^1.11.1", "@actions/core": "^1.11.1",
@ -881,12 +881,20 @@
"version": "6.3.1", "version": "6.3.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
"license": "ISC", "license": "ISC",
"bin": { "bin": {
"semver": "bin/semver.js" "semver": "bin/semver.js"
} }
}, },
"node_modules/string-argv": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/string-argv/-/string-argv-0.3.2.tgz",
"integrity": "sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==",
"license": "MIT",
"engines": {
"node": ">=0.6.19"
}
},
"node_modules/supports-preserve-symlinks-flag": { "node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",

View file

@ -12,7 +12,8 @@
"dependencies": { "dependencies": {
"@actions/core": "1.11.1", "@actions/core": "1.11.1",
"@actions/github": "6.0.1", "@actions/github": "6.0.1",
"@actions/tool-cache": "2.0.2" "@actions/tool-cache": "2.0.2",
"string-argv": "0.3.2"
}, },
"devDependencies": { "devDependencies": {
"@rollup/plugin-commonjs": "28.0.6", "@rollup/plugin-commonjs": "28.0.6",

View file

@ -2,6 +2,7 @@ import * as core from "@actions/core";
import * as tc from "@actions/tool-cache"; import * as tc from "@actions/tool-cache";
import * as os from "os"; import * as os from "os";
import * as path from "path"; import * as path from "path";
import { runSonarScanner } from "./run-sonar-scanner";
import { import {
checkGradleProject, checkGradleProject,
checkMavenProject, checkMavenProject,
@ -16,18 +17,31 @@ import {
const TOOLNAME = "sonar-scanner-cli"; const TOOLNAME = "sonar-scanner-cli";
/**
* Inputs are defined in action.yml
*/
function getInputs() { function getInputs() {
//FIXME: should not rely on ENV vars const args = core.getInput("args");
const scannerVersion = process.env.INPUT_SCANNERVERSION; // core.getInput("scannerVersion"); const projectBaseDir = core.getInput("projectBaseDir");
const projectBaseDir = process.env.INPUT_PROJECTBASEDIR; // core.getInput("projectBaseDir") || "."; const scannerBinariesUrl = core.getInput("scannerBinariesUrl");
const scannerBinariesUrl = process.env.INPUT_SCANNERBINARIESURL; // core.getInput("scannerBinariesUrl"); const scannerVersion = core.getInput("scannerVersion");
return { scannerVersion, projectBaseDir, scannerBinariesUrl }; return { args, projectBaseDir, scannerBinariesUrl, scannerVersion };
}
function getRunnerEnv() {
return {
RUNNER_OS: process.env.RUNNER_OS,
SONARCLOUD_URL: process.env.SONARCLOUD_URL,
RUNNER_DEBUG: process.env.RUNNER_DEBUG,
SONAR_ROOT_CERT: process.env.SONAR_ROOT_CERT,
RUNNER_TEMP: process.env.RUNNER_TEMP,
};
} }
function runSanityChecks(inputs) { function runSanityChecks(inputs) {
try { try {
const { scannerVersion, projectBaseDir } = inputs; const { projectBaseDir, scannerVersion } = inputs;
validateScannerVersion(scannerVersion); validateScannerVersion(scannerVersion);
checkSonarToken(core); checkSonarToken(core);
@ -39,7 +53,7 @@ function runSanityChecks(inputs) {
} }
} }
async function installSonarScannerCLI(scannerVersion, scannerBinariesUrl) { async function installSonarScannerCLI({ scannerVersion, scannerBinariesUrl }) {
const flavor = getPlatformFlavor(os.platform(), os.arch()); const flavor = getPlatformFlavor(os.platform(), os.arch());
// Check if tool is already cached // Check if tool is already cached
@ -83,14 +97,21 @@ async function installSonarScannerCLI(scannerVersion, scannerBinariesUrl) {
async function run() { async function run() {
try { try {
const inputs = getInputs(); const { args, projectBaseDir, scannerVersion, scannerBinariesUrl } =
const { scannerVersion, scannerBinariesUrl } = inputs; getInputs();
// Run sanity checks first // Run sanity checks first
runSanityChecks(inputs); runSanityChecks({ projectBaseDir, scannerVersion });
// Install Sonar Scanner CLI using @actions/tool-cache // Install Sonar Scanner CLI using @actions/tool-cache
await installSonarScannerCLI(scannerVersion, scannerBinariesUrl); const scannerDir = await installSonarScannerCLI({
scannerVersion,
scannerBinariesUrl,
});
// Run the sonar scanner
const runnerEnv = getRunnerEnv();
await runSonarScanner(args, projectBaseDir, scannerDir, runnerEnv);
} catch (error) { } catch (error) {
core.setFailed(`Action failed: ${error.message}`); core.setFailed(`Action failed: ${error.message}`);
process.exit(1); process.exit(1);

140
src/run-sonar-scanner.js Normal file
View file

@ -0,0 +1,140 @@
import * as exec from "@actions/exec";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { parseArgsStringToArgv } from "string-argv";
export async function runSonarScanner(
inputArgs,
projectBaseDir,
scannerDir,
runnerEnv = {}
) {
const {
RUNNER_DEBUG,
RUNNER_OS,
RUNNER_TEMP,
SONAR_ROOT_CERT,
SONARCLOUD_URL,
} = runnerEnv;
const scannerBin =
RUNNER_OS === "Windows" ? "sonar-scanner.bat" : "sonar-scanner";
const scannerArgs = [];
if (SONARCLOUD_URL) {
scannerArgs.push(`-Dsonar.scanner.sonarcloudUrl=${SONARCLOUD_URL}`);
}
if (RUNNER_DEBUG === "1") {
scannerArgs.push("--debug");
}
if (projectBaseDir) {
scannerArgs.push(`-Dsonar.projectBaseDir=${projectBaseDir}`);
}
// The SSL folder may exist on an uncleaned self-hosted runner
const sslFolder = path.join(os.homedir(), ".sonar", "ssl");
/**
* Use keytool for now, as SonarQube 10.6 and below doesn't support openssl generated keystores
* keytool requires a password > 6 characters, so we won't use the default password 'sonar'
*/
const keytoolMainClass = "sun.security.tools.keytool.Main";
const truststoreFile = path.join(sslFolder, "truststore.p12");
const truststorePassword = "changeit";
if (fs.existsSync(truststoreFile)) {
let aliasSonarIsPresent = true;
try {
await exec.exec(
`${scannerDir}/jre/bin/java`,
[
keytoolMainClass,
"-storetype",
"PKCS12",
"-keystore",
truststoreFile,
"-storepass",
truststorePassword,
"-noprompt",
"-trustcacerts",
"-list",
"-v",
"-alias",
"sonar",
],
{ silent: true }
);
} catch (_) {
aliasSonarIsPresent = false;
console.log(
`Existing Scanner truststore ${truststoreFile} does not contain 'sonar' alias`
);
}
if (aliasSonarIsPresent) {
console.log(
`Removing 'sonar' alias from already existing Scanner truststore: ${truststoreFile}`
);
await exec.exec(`${scannerDir}/jre/bin/java`, [
keytoolMainClass,
"-storetype",
"PKCS12",
"-keystore",
truststoreFile,
"-storepass",
truststorePassword,
"-noprompt",
"-trustcacerts",
"-delete",
"-alias",
"sonar",
]);
}
}
if (SONAR_ROOT_CERT) {
console.log("Adding SSL certificate to the Scanner truststore");
const tempCertPath = path.join(RUNNER_TEMP, "tmpcert.pem");
try {
fs.unlinkSync(tempCertPath);
} catch (_) {
// File doesn't exist, ignore
}
fs.writeFileSync(tempCertPath, SONAR_ROOT_CERT);
fs.mkdirSync(sslFolder, { recursive: true });
await exec.exec(`${scannerDir}/jre/bin/java`, [
keytoolMainClass,
"-storetype",
"PKCS12",
"-keystore",
truststoreFile,
"-storepass",
truststorePassword,
"-noprompt",
"-trustcacerts",
"-importcert",
"-alias",
"sonar",
"-file",
tempCertPath,
]);
scannerArgs.push(
`-Dsonar.scanner.truststorePassword=${truststorePassword}`
);
}
if (inputArgs) {
const args = parseArgsStringToArgv(inputArgs);
scannerArgs.push(...args);
}
await exec.exec(scannerBin, scannerArgs);
}