diff --git a/.gitignore b/.gitignore
index 442cdf1c..5a71cf4e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -30,5 +30,6 @@ hs_err_pid*
.idea/
cookies.txt
nohup.out
+.DS_Store
!functionaltest-jenkins-plugin/gradle/wrapper/gradle-wrapper.jar
diff --git a/stackrox-container-image-scanner/README.md b/stackrox-container-image-scanner/README.md
index 85a7f4ec..ecc00083 100644
--- a/stackrox-container-image-scanner/README.md
+++ b/stackrox-container-image-scanner/README.md
@@ -156,6 +156,17 @@ freestyle projects and pipelines.
+ cluster
|
+ The Secured Cluster name or ID to delegate image scans to |
+
+ Leave this blank to use the default delegated scanning config.
+
+ Note
+ Requires version 4.3+ of the StackRox Kubernetes Security Platform.
+
+ |
+
+
* Required |
@@ -206,7 +217,8 @@ To use the StackRox Container Image Scanner plugin in your pipeline:
failOnCriticalPluginError: true,
failOnPolicyEvalFailure: true,
portalAddress: 'https://central.stackrox:443',
- imageNames: "nginx:latest,ubuntu:bionic,busybox:stable"
+ imageNames: "nginx:latest,ubuntu:bionic,busybox:stable",
+ cluster: ""
)
}
}
@@ -215,7 +227,7 @@ To use the StackRox Container Image Scanner plugin in your pipeline:
```
- For more information about the variables, see the [plugin
- configuration variables](#plugin-configuration-variables)
+ configuration variables](#freestyle-project)
section.

diff --git a/stackrox-container-image-scanner/api.yaml b/stackrox-container-image-scanner/api.yaml
index 08945a77..cb7a5dad 100644
--- a/stackrox-container-image-scanner/api.yaml
+++ b/stackrox-container-image-scanner/api.yaml
@@ -11139,6 +11139,9 @@ components:
type: array
items:
type: string
+ cluster:
+ type: string
+ description: Cluster to delegate scan to, may be the cluster's name or ID.
v1BuildDetectionResponse:
type: object
properties:
@@ -11968,6 +11971,9 @@ components:
type: boolean
includeSnoozed:
type: boolean
+ cluster:
+ type: string
+ description: Cluster to delegate scan to, may be the cluster's name or ID.
v1WatchImageRequest:
type: object
properties:
diff --git a/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/StackroxBuilder.java b/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/StackroxBuilder.java
index a7207151..dd4bf51e 100644
--- a/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/StackroxBuilder.java
+++ b/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/StackroxBuilder.java
@@ -73,6 +73,8 @@ public class StackroxBuilder extends Builder implements SimpleBuildStep {
private boolean enableTLSVerification;
@DataBoundSetter
private String caCertPEM;
+ @DataBoundSetter
+ private String cluster;
private RunConfig runConfig;
@@ -155,8 +157,8 @@ private List checkImages() throws IOException {
for (String name : runConfig.getImageNames()) {
runConfig.getLog().printf("Checking image %s...%n", name);
- List cves = imageService.getImageScanResults(name);
- List violatedPolicies = detectionService.getPolicyViolations(name);
+ List cves = imageService.getImageScanResults(name, cluster);
+ List violatedPolicies = detectionService.getPolicyViolations(name, cluster);
results.add(new ImageCheckResults(name, cves, violatedPolicies));
}
diff --git a/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/DetectionService.java b/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/DetectionService.java
index 5316e666..97f4129f 100644
--- a/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/DetectionService.java
+++ b/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/DetectionService.java
@@ -27,9 +27,9 @@ public DetectionService(ApiClient client) {
api = new DetectionServiceApi(client);
}
- public List getPolicyViolations(String imageName) throws IOException {
+ public List getPolicyViolations(String imageName, String cluster) throws IOException {
- List alerts = getAlertsForImage(imageName);
+ List alerts = getAlertsForImage(imageName, cluster);
return emptyIfNull(alerts).stream()
.filter(a -> a.getPolicy() != null)
@@ -46,10 +46,12 @@ private String getViolations(StorageAlert a) {
.collect(Collectors.joining(" - "));
}
- private List getAlertsForImage(String imageName) throws ServiceException {
+ private List getAlertsForImage(String imageName, String cluster) throws ServiceException {
try {
return api.detectionServiceDetectBuildTime(new V1BuildDetectionRequest()
- .imageName(imageName))
+ .imageName(imageName)
+ .cluster(cluster)
+ )
.getAlerts();
} catch (ApiException e) {
throw ServiceException.fromApiException("Failed build time detection request", e);
diff --git a/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/ImageService.java b/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/ImageService.java
index 024b1e70..3be57b2a 100644
--- a/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/ImageService.java
+++ b/stackrox-container-image-scanner/src/main/java/com/stackrox/jenkins/plugins/services/ImageService.java
@@ -27,10 +27,11 @@ public ImageService(ApiClient client) {
}
- public List getImageScanResults(String imageName) throws IOException {
+ public List getImageScanResults(String imageName, String cluster) throws IOException {
V1ScanImageRequest request = new V1ScanImageRequest()
.imageName(imageName)
- .force(true);
+ .force(true)
+ .cluster(cluster);
StorageImageScan scan;
try {
scan = api.imageServiceScanImage(request).getScan();
diff --git a/stackrox-container-image-scanner/src/main/resources/com/stackrox/jenkins/plugins/StackroxBuilder/config.jelly b/stackrox-container-image-scanner/src/main/resources/com/stackrox/jenkins/plugins/StackroxBuilder/config.jelly
index 1890d21b..b703eaa2 100644
--- a/stackrox-container-image-scanner/src/main/resources/com/stackrox/jenkins/plugins/StackroxBuilder/config.jelly
+++ b/stackrox-container-image-scanner/src/main/resources/com/stackrox/jenkins/plugins/StackroxBuilder/config.jelly
@@ -12,6 +12,10 @@
help="/plugin/stackrox-container-image-scanner/help/help-imageNames.html">
+
+
+
+ Optionally specify the Secured Cluster name or ID to delegate image scans to.
+
+
+ This may be necessary in certain environments with isolated image registries.
+
diff --git a/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/DetectionServiceTest.java b/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/DetectionServiceTest.java
index 0a79f420..e4bd46ad 100644
--- a/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/DetectionServiceTest.java
+++ b/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/DetectionServiceTest.java
@@ -42,7 +42,7 @@ public void shouldThrowOn500() {
MOCK_SERVER.stubFor(post(anyUrl()).willReturn(serverError()
.withBodyFile("v1/detect/build/error.json")));
- Exception exception = assertThrows(IOException.class, () -> detectionService.getPolicyViolations("jenkins:lts"));
+ Exception exception = assertThrows(IOException.class, () -> detectionService.getPolicyViolations("jenkins:lts", ""));
String expected = "Failed build time detection request. Status code: 500. Error: image enrichment error: error getting metadata for image: docker.io/library/jenkins:lts errors: [error getting metadata from registry: \"Public DockerHub\": Failed to get the manifest digest : Head \"https://registry-1.docker.io/v2/library/jenkins/manifests/lts\": http: non-successful response (status=404 body=\"\"), error getting metadata from registry: \"Autogenerated https://registry-1.docker.io for cluster remote\": Failed to get the manifest digest : Head \"https://registry-1.docker.io/v2/library/jenkins/manifests/lts\": http: non-successful response (status=404 body=\"\")]";
assertEquals(expected, exception.getMessage());
}
@@ -51,7 +51,7 @@ public void shouldThrowOn500() {
public void shouldNotThrowWhenNoDataFor200() throws IOException {
MOCK_SERVER.stubFor(postDetectBuild().willReturn(
ok().withBody("{}")));
- List violations = detectionService.getPolicyViolations("nginx:latest");
+ List violations = detectionService.getPolicyViolations("nginx:latest", "");
assertEquals(0, violations.size());
}
@@ -59,7 +59,7 @@ public void shouldNotThrowWhenNoDataFor200() throws IOException {
public void shouldNotFailOnMissingData() throws IOException {
MOCK_SERVER.stubFor(postDetectBuild().willReturn(
ok().withBodyFile("v1/detect/build/minimal.json")));
- List actual = detectionService.getPolicyViolations("nginx:latest");
+ List actual = detectionService.getPolicyViolations("nginx:latest", "");
List expected = ImmutableList.of(new PolicyViolation(new StoragePolicy().enforcementActions(FAIL_BUILD_ENFORCEMENTS), ""));
@@ -70,7 +70,7 @@ public void shouldNotFailOnMissingData() throws IOException {
public void shouldJoinViolations() throws IOException {
MOCK_SERVER.stubFor(postDetectBuild().willReturn(
ok().withBodyFile("v1/detect/build/violations.json")));
- List actual = detectionService.getPolicyViolations("nginx:latest");
+ List actual = detectionService.getPolicyViolations("nginx:latest", "");
List expected = ImmutableList.of(new PolicyViolation(new StoragePolicy().enforcementActions(Collections.emptyList()), "A - B - C"));
@@ -80,7 +80,7 @@ public void shouldJoinViolations() throws IOException {
private MappingBuilder postDetectBuild() {
return post(urlEqualTo("/v1/detect/build"))
.withHeader("Authorization", equalTo("Bearer {some token}"))
- .withRequestBody(equalToJson("{\"imageName\" : \"nginx:latest\", \"policyCategories\" : [ ]}"));
+ .withRequestBody(equalToJson("{\"imageName\" : \"nginx:latest\", \"policyCategories\" : [ ], \"cluster\" : \"\"}"));
}
}
diff --git a/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/ImageServiceTest.java b/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/ImageServiceTest.java
index 6a6783f4..d3c141a7 100644
--- a/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/ImageServiceTest.java
+++ b/stackrox-container-image-scanner/src/test/java/com/stackrox/jenkins/plugins/services/ImageServiceTest.java
@@ -41,7 +41,7 @@ public void shouldThrowOn500() {
MOCK_SERVER.stubFor(post(anyUrl()).willReturn(serverError()
.withBodyFile("v1/images/scan/error.json")));
- Exception exception = assertThrows(IOException.class, () -> imageService.getImageScanResults("jenkins:lts"));
+ Exception exception = assertThrows(IOException.class, () -> imageService.getImageScanResults("jenkins:lts", ""));
String expected = "Failed image scan request. Status code: 500. Error" +
": image enrichment error" +
": error getting metadata for image: docker.io/library/jenkins:lts errors" +
@@ -58,7 +58,7 @@ public void shouldThrowOn500() {
public void shouldThrowWhenNoDataFor200() throws IOException {
MOCK_SERVER.stubFor(postImagesScan().willReturn(
ok().withBody("{}")));
- Exception exception = assertThrows(NullPointerException.class, () -> imageService.getImageScanResults("nginx:latest"));
+ Exception exception = assertThrows(NullPointerException.class, () -> imageService.getImageScanResults("nginx:latest", ""));
assertEquals("Did not get scan results from StackRox", exception.getMessage());
}
@@ -67,7 +67,7 @@ public void shouldThrowWhenNoDataFor200() throws IOException {
public void shouldNotFailOnMissingData(String file) throws IOException {
MOCK_SERVER.stubFor(postImagesScan().willReturn(
ok().withBodyFile("v1/images/scan/" + file)));
- List actual = imageService.getImageScanResults("nginx:latest");
+ List actual = imageService.getImageScanResults("nginx:latest", "");
ImmutableList expected = ImmutableList.of(
new CVE(null, null, new StorageEmbeddedVulnerability()
.cve("CVE-MISSING-DATA")
@@ -80,7 +80,7 @@ public void shouldNotFailOnMissingData(String file) throws IOException {
public void shouldNotFailOnUnknownEnumValue() throws IOException {
MOCK_SERVER.stubFor(postImagesScan().willReturn(
ok().withBodyFile("v1/images/scan/unknown-enum.json")));
- List actual = imageService.getImageScanResults("nginx:latest");
+ List actual = imageService.getImageScanResults("nginx:latest", "");
ImmutableList expected = ImmutableList.of(
new CVE(null, null, new StorageEmbeddedVulnerability()
.cve("CVE-MISSING-DATA")
@@ -92,6 +92,6 @@ public void shouldNotFailOnUnknownEnumValue() throws IOException {
private MappingBuilder postImagesScan() {
return post(urlEqualTo("/v1/images/scan"))
.withHeader("Authorization", equalTo("Bearer {some token}"))
- .withRequestBody(equalToJson("{\"imageName\" : \"nginx:latest\",\"force\" : true}"));
+ .withRequestBody(equalToJson("{\"imageName\" : \"nginx:latest\",\"force\" : true, \"cluster\" : \"\"}"));
}
}