Skip to content

Commit

Permalink
fix: correct execution within remote k8s workers (#112)
Browse files Browse the repository at this point in the history
  • Loading branch information
tembleking authored Dec 4, 2024
1 parent e600d25 commit b5dbba0
Show file tree
Hide file tree
Showing 11 changed files with 54 additions and 81 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
package com.sysdig.jenkins.plugins.sysdig.application.vm;

import com.sysdig.jenkins.plugins.sysdig.application.vm.report.PolicyReportProcessor;
import com.sysdig.jenkins.plugins.sysdig.domain.SysdigLogger;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanner;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningResult;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningService;
import com.sysdig.jenkins.plugins.sysdig.domain.SysdigLogger;
import hudson.AbortException;

import javax.annotation.Nonnull;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
package com.sysdig.jenkins.plugins.sysdig.application.vm.report;

import com.sysdig.jenkins.plugins.sysdig.application.vm.ReportProcessor;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningResult;
import com.sysdig.jenkins.plugins.sysdig.domain.SysdigLogger;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningResult;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.report.Bundle;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.report.PolicyEvaluation;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.report.Predicate;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,12 @@

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.Serializable;
import java.net.*;
import java.util.Arrays;
import java.util.Map;
import java.util.stream.Stream;

public class RemoteDownloader implements Serializable {
public class RemoteDownloader {
private final RunContext runContext;
protected final SysdigLogger logger;
private final EnvVars envVars;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,16 +31,13 @@

import javax.annotation.Nonnull;
import java.io.IOException;
import java.io.Serializable;
import java.util.Collections;

/**
* Wraps the context of a Jenkins run.
* A run represents the runtime execution of a Jenkins job.
*/
public class RunContext implements Serializable {
private static final long serialVersionUID = 1;

public class RunContext {
// The Jenkins run associated with this context
private final transient Run<?, ?> run;

Expand All @@ -56,6 +53,9 @@ public class RunContext implements Serializable {
// Custom logger for Sysdig-specific logging
private final SysdigLogger logger;

// Launcher to launch processes;
private final Launcher launcher;

/**
* Constructs a new RunContext with the given parameters.
*
Expand All @@ -64,11 +64,12 @@ public class RunContext implements Serializable {
* @param envVars The environment variables of the run execution.
* @param listener The task listener for logging.
*/
public RunContext(@Nonnull Run<?, ?> run, @Nonnull FilePath workspace, @Nonnull EnvVars envVars, @Nonnull TaskListener listener) {
public RunContext(@Nonnull Run<?, ?> run, @Nonnull FilePath workspace, @Nonnull EnvVars envVars, @Nonnull Launcher launcher, @Nonnull TaskListener listener) {
this.run = run;
this.workspace = workspace;
this.listener = listener;
this.envVars = envVars;
this.launcher = launcher;
this.logger = new ConsoleLog("SysdigSecurePlugin", listener, false);
}

Expand Down Expand Up @@ -186,7 +187,12 @@ public <V, E extends Throwable> V call(@Nonnull Callable<V, E> act) throws IOExc
return workspace.act(act);
}

public Launcher getLauncher() throws IOException, InterruptedException {
return workspace.createLauncher(listener);
/**
* Returns a launcher that is able to perform commands either locally or remotely, based on the context of the run.
*
* @return The launcher to perform commands.
*/
public Launcher getLauncher() {
return launcher;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ private void severity(Vector<String> cmd) {
@Override
public void perform(@Nonnull Run<?, ?> run, @Nonnull FilePath workspace, @Nonnull EnvVars envVars, @Nonnull Launcher launcher, @Nonnull TaskListener listener)
throws InterruptedException, IOException {
RunContext runContext = new RunContext(run, workspace, envVars, listener);
RunContext runContext = new RunContext(run, workspace, envVars, launcher, listener);
SysdigLogger logger = runContext.getLogger();

logger.logInfo("Attempting to download CLI");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
package com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.vm;

import com.google.common.base.Strings;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.RunContext;
import com.sysdig.jenkins.plugins.sysdig.domain.SysdigLogger;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.RunContext;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.vm.entrypoint.ImageScanningBuilder;
import hudson.AbortException;
import hudson.PluginWrapper;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,14 @@

import com.google.common.base.Strings;
import com.google.gson.JsonObject;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.RunContext;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.vm.ui.SysdigAction;
import com.sysdig.jenkins.plugins.sysdig.application.vm.ReportStorage;
import com.sysdig.jenkins.plugins.sysdig.application.vm.report.PolicyEvaluationReport;
import com.sysdig.jenkins.plugins.sysdig.application.vm.report.PolicyEvaluationSummary;
import com.sysdig.jenkins.plugins.sysdig.application.vm.report.VulnerabilityReportProcessor;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningResult;
import com.sysdig.jenkins.plugins.sysdig.application.vm.ReportStorage;
import com.sysdig.jenkins.plugins.sysdig.domain.SysdigLogger;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningResult;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.RunContext;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.vm.ui.SysdigAction;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.json.GsonBuilder;
import hudson.AbortException;
import hudson.FilePath;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,7 @@ public void setScannerBinaryPath(String scannerBinaryPath) {

@Override
public void perform(@Nonnull Run<?, ?> run, @Nonnull FilePath workspace, @Nonnull EnvVars envVars, @Nonnull Launcher launcher, @Nonnull TaskListener listener) throws IOException, InterruptedException {
var runContext = new RunContext(run, workspace, envVars, listener);
var runContext = new RunContext(run, workspace, envVars, launcher, listener);
var logger = runContext.getLogger();
ImageImageScanningConfig config = new ImageImageScanningConfig(runContext, this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;

class LogOutputStreamAdapter extends OutputStream {
public class LogOutputStreamAdapter extends OutputStream {
private final SysdigLogger logger;
private final StringBuilder buffer = new StringBuilder();
private final String newline = System.lineSeparator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,15 @@
import com.sysdig.jenkins.plugins.sysdig.infrastructure.json.GsonBuilder;
import hudson.AbortException;
import hudson.FilePath;
import hudson.remoting.Callable;
import org.apache.commons.io.FileUtils;
import org.jenkinsci.remoting.RoleChecker;

import javax.annotation.Nonnull;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Paths;


public class RemoteSysdigImageScanner implements Callable<ImageScanningResult, Exception> {
public class RemoteSysdigImageScanner {
private static final String FIXED_SCANNED_VERSION = "1.16.1";
private final ScannerPaths scannerPaths;
private final String imageName;
Expand All @@ -58,24 +51,15 @@ public RemoteSysdigImageScanner(@Nonnull RunContext runContext, RetriableRemoteD
this.logger = runContext.getLogger();
}

@Override
public void checkRoles(RoleChecker checker) throws SecurityException {
}

@Override
public ImageScanningResult call() throws AbortException {
try {
// Create all the necessary folders to store execution temp files and such
createExecutionWorkspace();
// Retrieve the scanner bin file
final FilePath scannerBinaryFile = retrieveScannerBinFile();
// Execute the scanner bin file and retrieves its json output
String imageScanningResultJSON = executeScan(scannerBinaryFile);
JsonScanResult jsonScanResult = GsonBuilder.build().fromJson(imageScanningResultJSON, JsonScanResult.class);
return ImageScanningResult.fromReportResult(jsonScanResult.getResult().orElseThrow(() -> new AbortException(String.format("unable to obtain result from scan: %s", imageScanningResultJSON))));
} finally {
purgeExecutionWorkspace();
}
public ImageScanningResult performScan() throws AbortException {
// Create all the necessary folders to store execution temp files and such
createExecutionWorkspace();
// Retrieve the scanner bin file
final FilePath scannerBinaryFile = retrieveScannerBinFile();
// Execute the scanner bin file and retrieves its json output
String imageScanningResultJSON = executeScan(scannerBinaryFile);
JsonScanResult jsonScanResult = GsonBuilder.build().fromJson(imageScanningResultJSON, JsonScanResult.class);
return ImageScanningResult.fromReportResult(jsonScanResult.getResult().orElseThrow(() -> new AbortException(String.format("unable to obtain result from scan: %s", imageScanningResultJSON))));
}

private FilePath downloadInlineScan(String latestVersion) throws IOException, UnsupportedOperationException, InterruptedException {
Expand Down Expand Up @@ -119,14 +103,6 @@ private void createExecutionWorkspace() throws AbortException {
}
}

private void purgeExecutionWorkspace() {
try {
this.scannerPaths.purge();
} catch (IOException e) {
logger.logError("Unable to delete scanner execution workspace", e);
}
}

private FilePath retrieveScannerBinFile() throws AbortException {
if (!Strings.isNullOrEmpty(config.getScannerBinaryPath())) {
FilePath scannerBinaryPath = runContext.getPathFromWorkspace(config.getScannerBinaryPath());
Expand All @@ -148,15 +124,16 @@ private FilePath retrieveScannerBinFile() throws AbortException {

private String executeScan(final FilePath scannerBinFile) throws AbortException {
try {
final File scannerJsonOutputFile = Files.createFile(Paths.get(this.scannerPaths.getBaseFolder(), "inlinescan.json")).toFile();
final FilePath scannerJsonOutputFile = this.scannerPaths.getBaseFolder().child("inlinescan.json");
SysdigImageScanningProcessBuilder processBuilder = createProcessBuilder(scannerBinFile, scannerJsonOutputFile);

logger.logInfo("Executing: " + String.join(" ", processBuilder.toCommandLineArguments()));
logger.logInfo("Waiting for scanner execution to be completed...");
int scannerExitCode = processBuilder.launchAndWait(this.runContext.getLauncher());
logger.logInfo(String.format("Scanner exit code: %d", scannerExitCode));

String jsonOutput = Files.readString(Paths.get(scannerJsonOutputFile.getAbsolutePath()), Charset.defaultCharset());
String jsonOutput = "";
if (scannerJsonOutputFile.exists()) jsonOutput = scannerJsonOutputFile.readToString();

Check warning on line 136 in src/main/java/com/sysdig/jenkins/plugins/sysdig/infrastructure/scanner/RemoteSysdigImageScanner.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Partially covered line

Line 136 is only partially covered, one branch is missing
logger.logDebug("Inline scan JSON output:\n" + jsonOutput);

if (scannerExitCode == 2) {
Expand All @@ -173,13 +150,13 @@ private String executeScan(final FilePath scannerBinFile) throws AbortException
}
}

private SysdigImageScanningProcessBuilder createProcessBuilder(FilePath scannerBinFile, File scannerJsonOutputFile) {
private SysdigImageScanningProcessBuilder createProcessBuilder(FilePath scannerBinFile, FilePath scannerJsonOutputFile) {
SysdigImageScanningProcessBuilder processBuilder = new SysdigImageScanningProcessBuilder(scannerBinFile.getRemote(), this.config.getSysdigToken())
.withExtraEnvVars(this.runContext.getEnvVars())
.withEngineURL(this.config.getEngineurl())
.withDBPath(this.scannerPaths.getDatabaseFolder())
.withCachePath(this.scannerPaths.getCacheFolder())
.withScanResultOutputPath(scannerJsonOutputFile.getAbsolutePath())
.withDBPath(this.scannerPaths.getDatabaseFolder().getRemote())
.withCachePath(this.scannerPaths.getCacheFolder().getRemote())
.withScanResultOutputPath(scannerJsonOutputFile.getRemote())
.withConsoleLog()
.withExtraParametersSeparatedBySpace(this.config.getInlineScanExtraParams())
.withPoliciesToApplySeparatedBySpace(this.config.getPoliciesToApply())
Expand All @@ -193,36 +170,32 @@ private SysdigImageScanningProcessBuilder createProcessBuilder(FilePath scannerB

private static class ScannerPaths implements Serializable {
private static final String SCANNER_EXEC_FOLDER_BASE_PATH_PATTERN = "sysdig-secure-scan-%d";
private final String baseFolder;
private final String databaseFolder;
private final String cacheFolder;
private final FilePath baseFolder;
private final FilePath databaseFolder;
private final FilePath cacheFolder;

public ScannerPaths(final FilePath basePath) {
this.baseFolder = Paths.get(basePath.getRemote(), String.format(SCANNER_EXEC_FOLDER_BASE_PATH_PATTERN, System.currentTimeMillis())).toString();
this.databaseFolder = Paths.get(this.baseFolder, "db").toString();
this.cacheFolder = Paths.get(this.baseFolder, "cache").toString();
this.baseFolder = basePath.child(String.format(SCANNER_EXEC_FOLDER_BASE_PATH_PATTERN, System.currentTimeMillis()));
this.databaseFolder = baseFolder.child("db");
this.cacheFolder = baseFolder.child("cache");
}

public String getBaseFolder() {
public FilePath getBaseFolder() {
return this.baseFolder;
}

public String getDatabaseFolder() {
public FilePath getDatabaseFolder() {
return this.databaseFolder;
}

public String getCacheFolder() {
public FilePath getCacheFolder() {
return this.cacheFolder;
}

public void create() throws Exception {
Files.createDirectories(Paths.get(this.baseFolder));
Files.createDirectory(Paths.get(this.databaseFolder));
Files.createDirectory(Paths.get(this.cacheFolder));
}

public void purge() throws IOException {
FileUtils.deleteDirectory(new File(this.baseFolder));
this.baseFolder.mkdirs();
this.databaseFolder.mkdirs();
this.cacheFolder.mkdirs();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@

import com.sysdig.jenkins.plugins.sysdig.application.vm.ImageScanningConfig;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanner;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningException;
import com.sysdig.jenkins.plugins.sysdig.domain.vm.ImageScanningResult;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.http.RetriableRemoteDownloader;
import com.sysdig.jenkins.plugins.sysdig.infrastructure.jenkins.RunContext;
Expand All @@ -38,14 +37,10 @@ public ImageScanningResult scanImage(String imageTag) throws InterruptedExceptio
try {
RetriableRemoteDownloader downloader = new RetriableRemoteDownloader(this.runContext);
RemoteSysdigImageScanner task = new RemoteSysdigImageScanner(runContext, downloader, imageTag, config);
return runContext.call(task);
} catch (ImageScanningException e) {
runContext.getLogger().logError(e.getMessage());
throw new InterruptedException("Failed to perform inline-scan due to an unexpected error. Please refer to above logs for more information");
return task.performScan();

Check warning on line 40 in src/main/java/com/sysdig/jenkins/plugins/sysdig/infrastructure/scanner/SysdigImageScanner.java

View check run for this annotation

ci.jenkins.io / Code Coverage

Not covered line

Line 40 is not covered by tests
} catch (Exception e) {
runContext.getLogger().logError("Failed to perform inline-scan due to an unexpected error", e);
throw new InterruptedException("Failed to perform inline-scan due to an unexpected error. Please refer to above logs for more information");
}
}
}

0 comments on commit b5dbba0

Please sign in to comment.