From fd4fd8a26c5c2c2c6c4b5cb4089da5f2bc5d26ec Mon Sep 17 00:00:00 2001 From: Khushboo Sancheti Date: Fri, 9 Oct 2026 21:29:42 -0700 Subject: [PATCH] ROX-37162: add Groovy e2e for Job workload kind exclusion Co-authored-by: Cursor --- .../PolicyWorkloadKindExclusionTest.groovy | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 qa-tests-backend/src/test/groovy/PolicyWorkloadKindExclusionTest.groovy diff --git a/qa-tests-backend/src/test/groovy/PolicyWorkloadKindExclusionTest.groovy b/qa-tests-backend/src/test/groovy/PolicyWorkloadKindExclusionTest.groovy new file mode 100644 index 0000000000000..02b1e3d5cb0c6 --- /dev/null +++ b/qa-tests-backend/src/test/groovy/PolicyWorkloadKindExclusionTest.groovy @@ -0,0 +1,112 @@ +import static Services.checkForNoActiveViolations +import static Services.waitForViolation + +import io.stackrox.proto.storage.PolicyOuterClass +import io.stackrox.proto.storage.PolicyOuterClass.Exclusion +import io.stackrox.proto.storage.PolicyOuterClass.LifecycleStage +import io.stackrox.proto.storage.PolicyOuterClass.Policy + +import objects.Deployment +import objects.Job +import services.FeatureFlagService +import services.PolicyService + +import org.junit.Assume +import spock.lang.Tag + +@Tag("PZ") +class PolicyWorkloadKindExclusionTest extends BaseSpecification { + static final private Integer WAIT_FOR_VIOLATION_TIMEOUT = isRaceBuild() ? 450 : 90 + + static final private Deployment DEPLOYMENT = new Deployment() + .setName("wte-deploy-${RUN_ID}") + .setImagePrefetcherAffinity() + .setImage(TEST_IMAGE) + .addLabel("app", "wte") + + // Keep the Job running. The only other Job helper usage creates a short-lived Job that + // completes and is then deleted from StackRox (DeploymentTest). + static final private Job JOB = new Job() + .setName("wte-job-${RUN_ID}") + .setImagePrefetcherAffinity() + .setImage(TEST_IMAGE) + .addLabel("app", "wte") + .setCommand(["/bin/sh", "-c", "sleep 600"]) + + def setupSpec() { + Assume.assumeTrue( + "ROX_POLICY_WORKLOAD_KIND_EXCLUSION is disabled", + FeatureFlagService.isFeatureFlagEnabled("ROX_POLICY_WORKLOAD_KIND_EXCLUSION")) + + orchestrator.createDeployment(DEPLOYMENT) + assert Services.waitForDeployment(DEPLOYMENT) + + def createdJob = orchestrator.createJob(JOB) + assert createdJob != null + assert Services.waitForDeploymentByID(createdJob.getMetadata().getUid(), JOB.name) + } + + def cleanupSpec() { + orchestrator.deleteDeployment(DEPLOYMENT) + orchestrator.deleteJob(JOB) + } + + @Tag("BAT") + def "exclude-by-kind JOB suppresses Job violations and still fires on Deployments"() { + given: + def baselineID + def policyID + def baselineName = "wte-baseline-${RUN_ID}" + def policyName = "wte-job-kind-${RUN_ID}" + + when: + "the Job is evaluated like any other workload when no kind exclusion is set" + baselineID = PolicyService.createNewPolicy(imageTagPolicy(baselineName).build()) + assert baselineID != null + + then: + waitForViolation(DEPLOYMENT.name, baselineName, WAIT_FOR_VIOLATION_TIMEOUT) + waitForViolation(JOB.name, baselineName, WAIT_FOR_VIOLATION_TIMEOUT) + + when: + "a matching policy excludes all Jobs" + policyID = PolicyService.createNewPolicy(imageTagPolicy(policyName) + .addExclusions(Exclusion.newBuilder() + .setExcludeByKind(Exclusion.ExcludeByKind.newBuilder() + .addKinds(Exclusion.WorkloadKind.JOB) + .build()) + .build()) + .build()) + assert policyID != null + + then: + "the Deployment is still in violation and the Job is not" + waitForViolation(DEPLOYMENT.name, policyName, WAIT_FOR_VIOLATION_TIMEOUT) + checkForNoActiveViolations(JOB.name, policyName, WAIT_FOR_VIOLATION_TIMEOUT) + + cleanup: + baselineID == null ?: PolicyService.deletePolicy(baselineID) + policyID == null ?: PolicyService.deletePolicy(policyID) + } + + private static Policy.Builder imageTagPolicy(String name) { + return Policy.newBuilder() + .setName(name) + .setDescription("Workload kind exclusion e2e") + .setRationale("Workload kind exclusion e2e") + .addLifecycleStages(LifecycleStage.DEPLOY) + .addCategories("DevOps Best Practices") + .setDisabled(false) + .setSeverityValue(2) + .addPolicySections( + PolicyOuterClass.PolicySection.newBuilder().addPolicyGroups( + PolicyOuterClass.PolicyGroup.newBuilder() + .setFieldName("Image Tag") + .addValues(PolicyOuterClass.PolicyValue.newBuilder() + .setValue("nginx-2.0.3") + .build()) + .build() + ).build() + ) + } +}