Skip to content

Commit 858e61f

Browse files
authored
Change execution mode to allow rootless docker (#15)
* [SSPROD-8053] Change tail execution mode for rootless docker compatibility * Create different check runs if multiple images are scanned
1 parent 1ce9a32 commit 858e61f

File tree

8 files changed

+242
-352
lines changed

8 files changed

+242
-352
lines changed

dist/index.js

Lines changed: 58 additions & 257 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

dist/licenses.txt

Lines changed: 0 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

index.js

Lines changed: 58 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ const github = require('@actions/github')
55
const path = require('path');
66
const performance = require('perf_hooks').performance;
77
const process = require('process');
8-
const Tail = require('tail').Tail;
98

109
const toolVersion = "3.0.0";
1110
const dottedQuadToolVersion = "3.0.0.0";
@@ -68,8 +67,8 @@ function printOptions(opts) {
6867
}
6968

7069
function composeFlags(opts) {
71-
let dockerFlags = `--rm -v ${process.cwd()}/scan-output:/tmp/logs -e LOGS_DIR=/tmp/logs`;
72-
let runFlags = `--sysdig-token=${opts.sysdigSecureToken || ""} --format=JSON`;
70+
let dockerFlags = `--rm -e SYSDIG_API_TOKEN=${opts.sysdigSecureToken || ""}`;
71+
let runFlags = `--format=JSON`;
7372

7473
if (opts.sysdigSecureURL) {
7574
runFlags += ` --sysdig-url ${opts.sysdigSecureURL}`;
@@ -191,8 +190,8 @@ async function processScanResult(result) {
191190
}
192191
}
193192

194-
generateSARIFReport(vulnerabilities);
195-
await generateChecks(scanResult, evaluationResults, vulnerabilities);
193+
generateSARIFReport(report.tag, vulnerabilities);
194+
await generateChecks(report.tag, scanResult, evaluationResults, vulnerabilities);
196195
}
197196

198197
return result.ReturnCode == 0;
@@ -211,14 +210,21 @@ async function executeInlineScan(scanImage, dockerFlags, runFlags) {
211210
let execOutput = '';
212211
let errOutput = '';
213212

214-
fs.mkdirSync("./scan-output", { recursive: true });
215-
fs.closeSync(fs.openSync("./scan-output/info.log", 'w'));
216-
let tail = new Tail("./scan-output/info.log", { fromBeginning: true, follow: true });
217-
tail.on("line", function (data) {
218-
console.log(data);
219-
});
213+
const tailOptions = {
214+
silent: true,
215+
ignoreReturnCode: true,
216+
listeners: {
217+
stdout: (data) => {
218+
process.stdout.write(data);
219+
},
220+
stderr: (data) => {
221+
process.stderr.write(data);
222+
}
223+
}
224+
225+
}
220226

221-
const options = {
227+
const scanOptions = {
222228
silent: true,
223229
ignoreReturnCode: true,
224230
listeners: {
@@ -231,17 +237,42 @@ async function executeInlineScan(scanImage, dockerFlags, runFlags) {
231237
}
232238
};
233239

240+
241+
let retCode = await exec.exec(`docker run -d --entrypoint /bin/cat -ti ${dockerFlags} ${scanImage}`, null, scanOptions);
242+
if (retCode != 0) {
243+
return { ReturnCode: -1, Output: execOutput, Error: errOutput };
244+
}
245+
246+
let containerId = execOutput.trim();
247+
await exec.exec(`docker exec ${containerId} mkdir -p /tmp/sysdig-inline-scan/logs/`, null, {silent: true, ignoreReturnCode: true});
248+
await exec.exec(`docker exec ${containerId} touch /tmp/sysdig-inline-scan/logs/info.log`, null, {silent: true, ignoreReturnCode: true});
249+
let tailExec = exec.exec(`docker exec ${containerId} tail -f /tmp/sysdig-inline-scan/logs/info.log`, null, tailOptions);
250+
251+
execOutput = '';
234252
let start = performance.now();
235-
let cmd = `docker run ${dockerFlags} ${scanImage} ${runFlags}`;
253+
let cmd = `docker exec ${containerId} /sysdig-inline-scan.sh ${runFlags}`;
236254
core.debug("Executing: " + cmd);
237-
let retCode = await exec.exec(cmd, null, options);
255+
retCode = await exec.exec(cmd, null, scanOptions);
238256
core.info("Image analysis took " + Math.round(performance.now() - start) + " milliseconds.");
239-
tail.unwatch();
257+
258+
await function () {
259+
return new Promise((resolve) => {
260+
setTimeout(resolve, 1000);
261+
});
262+
}();
263+
264+
try {
265+
await exec.exec(`docker stop ${containerId} -t 0`, null, {silent: true, ignoreReturnCode: true});
266+
await exec.exec(`docker rm ${containerId}`, null, {silent: true, ignoreReturnCode: true});
267+
await tailExec;
268+
} catch (error) {
269+
core.info("Error stopping container: " + error);
270+
}
240271

241272
return { ReturnCode: retCode, Output: execOutput, Error: errOutput };
242273
}
243274

244-
function vulnerabilities2SARIF(vulnerabilities) {
275+
function vulnerabilities2SARIF(tag, vulnerabilities) {
245276

246277
const sarifOutput = {
247278
"$schema": "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
@@ -264,7 +295,7 @@ function vulnerabilities2SARIF(vulnerabilities) {
264295
kind: "namespace"
265296
}
266297
],
267-
results: vulnerabilities2SARIFResults(vulnerabilities),
298+
results: vulnerabilities2SARIFResults(tag, vulnerabilities),
268299
columnKind: "utf16CodeUnits"
269300
}]
270301
};
@@ -292,7 +323,7 @@ function vulnerabilities2SARIFRules(vulnerabilities) {
292323
return (ret);
293324
}
294325

295-
function vulnerabilities2SARIFResults(vulnerabilities) {
326+
function vulnerabilities2SARIFResults(tag, vulnerabilities) {
296327
var ret = {};
297328

298329
if (vulnerabilities) {
@@ -306,14 +337,14 @@ function vulnerabilities2SARIFResults(vulnerabilities) {
306337
id: "default",
307338
},
308339
analysisTarget: {
309-
uri: "Container image",
340+
uri: `Container image ${tag}`,
310341
index: 0,
311342
},
312343
locations: [
313344
{
314345
physicalLocation: {
315346
artifactLocation: {
316-
uri: "Container image",
347+
uri: `Container image ${tag}`,
317348
},
318349
region: {
319350
startLine: 1,
@@ -326,7 +357,7 @@ function vulnerabilities2SARIFResults(vulnerabilities) {
326357
},
327358
logicalLocations: [
328359
{
329-
fullyQualifiedName: "container-image",
360+
fullyQualifiedName: `Container image ${tag}`,
330361
},
331362
],
332363
},
@@ -380,13 +411,13 @@ function getRuleId(v) {
380411
return "VULN_" + v.vuln + "_" + v.package_type + "_" + v.package;
381412
}
382413

383-
function generateSARIFReport(vulnerabilities) {
384-
let sarifOutput = vulnerabilities2SARIF(vulnerabilities);
414+
function generateSARIFReport(tag, vulnerabilities) {
415+
let sarifOutput = vulnerabilities2SARIF(tag, vulnerabilities);
385416
core.setOutput("sarifReport", "./sarif.json");
386417
fs.writeFileSync("./sarif.json", JSON.stringify(sarifOutput, null, 2));
387418
}
388419

389-
async function generateChecks(scanResult, evaluationResults, vulnerabilities) {
420+
async function generateChecks(tag, scanResult, evaluationResults, vulnerabilities) {
390421
const githubToken = core.getInput('github-token');
391422
if (!githubToken) {
392423
core.warning("No github-token provided. Skipping creation of check run");
@@ -413,12 +444,12 @@ async function generateChecks(scanResult, evaluationResults, vulnerabilities) {
413444
check_run = await octokit.rest.checks.create({
414445
owner: github.context.repo.owner,
415446
repo: github.context.repo.repo,
416-
name: "Scan results",
447+
name: `Scan results for ${tag}`,
417448
head_sha: github.context.sha,
418449
status: "completed",
419450
conclusion: conclusion,
420451
output: {
421-
title: "Inline scan results",
452+
title: `Inline scan results for ${tag}`,
422453
summary: "Scan result is " + scanResult,
423454
annotations: annotations.slice(0,50)
424455
}
@@ -452,7 +483,7 @@ function getReportAnnotations(evaluationResults, vulnerabilities) {
452483
let outputCol = evaluationResults.header.indexOf("Check_Output");
453484
let gates = evaluationResults.rows.map(g => {
454485
let action = g[actionCol];
455-
let level = "notice"
486+
let level = "notice"
456487
if (action == "warn") {
457488
level = "warning";
458489
} else if (action == "stop") {

package-lock.json

Lines changed: 1 addition & 15 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,7 @@
3030
"dependencies": {
3131
"@actions/core": "^1.4.0",
3232
"@actions/exec": "^1.1.0",
33-
"@actions/github": "^5.0.0",
34-
"tail": "^2.0.4"
33+
"@actions/github": "^5.0.0"
3534
},
3635
"devDependencies": {
3736
"@vercel/ncc": "^0.28.6",

tests/fixtures/report.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"status": "foo",
3+
"tag": "myimage:mytag",
34
"scanReport": [
45
{
56
"foo-digest": {

0 commit comments

Comments
 (0)