From 63d3d420b723faa00ad60e3b3ce989ee9209b55d Mon Sep 17 00:00:00 2001 From: arewm Date: Fri, 27 Feb 2026 21:10:28 -0500 Subject: [PATCH] tasks/verify-conforma-konflux-ta: Fix VSA generation, add acceptance test coverage The ENABLE_VSA code path had several bugs that together prevented VSA files from being produced and archived correctly. The ec CLI rejects output paths outside /tmp or cwd, --vsa-upload must only be passed for dsse format since the local@ backend requires a signing key, and echo without -n writes a trailing newline that breaks Tekton When Expression matching. The trusted artifact archival was also broken: workDir was hardcoded to /var/workdir rather than $(params.TRUSTED_ARTIFACTS_EXTRACT_DIR), so downstream tasks would find the snapshot nested under a conforma/ prefix instead of at the archive root. The VSA_UPLOAD default was similarly misaligned, pointing outside the extract dir so VSA files were never captured in the archive. The report-json.json is now also copied into the VSA directory so downstream tasks can generate SLSA VSAs from the Conforma evaluation report. Adds an acceptance test scenario for ENABLE_VSA=true with predicate format, a new taskResultShouldEqual step definition for targeted result assertions, and updates the existing snapshot for the echo -n fix. Assisted-by: Claude Code (Sonnet 4.6) Signed-off-by: arewm --- acceptance/kubernetes/kubernetes.go | 25 ++++++++++++ .../pages/verify-conforma-konflux-ta.adoc | 2 +- .../__snapshots__/ta_task_validate_image.snap | 2 +- features/ta_task_validate_image.feature | 26 +++++++++++++ .../0.1/verify-conforma-konflux-ta.yaml | 38 ++++++++++++++++--- 5 files changed, 86 insertions(+), 7 deletions(-) diff --git a/acceptance/kubernetes/kubernetes.go b/acceptance/kubernetes/kubernetes.go index 23acb865d..eb5507a84 100644 --- a/acceptance/kubernetes/kubernetes.go +++ b/acceptance/kubernetes/kubernetes.go @@ -395,6 +395,30 @@ func taskResultsShouldMatchTheSnapshot(ctx context.Context) error { return snaps.MatchSnapshot(ctx, "results", string(j), nil) } +func taskResultShouldEqual(ctx context.Context, resultName, expectedValue string) error { + c := testenv.FetchState[ClusterState](ctx) + + if err := mustBeUp(ctx, *c); err != nil { + return err + } + + info, err := c.cluster.TaskInfo(ctx) + if err != nil { + return err + } + + actual, ok := info.Results[resultName] + if !ok { + return fmt.Errorf("result %q not found in task results", resultName) + } + + if fmt.Sprintf("%v", actual) != expectedValue { + return fmt.Errorf("result %q: expected %q, got %q", resultName, expectedValue, actual) + } + + return nil +} + func taskLogsShouldContain(ctx context.Context, stepName, needle string) error { c := testenv.FetchState[ClusterState](ctx) @@ -467,6 +491,7 @@ func AddStepsTo(sc *godog.ScenarioContext) { sc.Step("^the task logs for step \"([^\"]*)\" should contain `([^`]+)`$", taskLogsShouldContain) sc.Step(`^the task env var for step "([^"]*)" named "([^"]*)" should be set to "([^"]*)"$`, stepEnvVarShouldBe) sc.Step(`^the task results should match the snapshot$`, taskResultsShouldMatchTheSnapshot) + sc.Step(`^the task result "([^"]*)" should equal "([^"]*)"$`, taskResultShouldEqual) sc.Step(`^policy configuration named "([^"]*)" with (\d+) policy sources from "([^"]*)"(?:, patched with)$`, createNamedPolicyWithManySources) // stop usage of the cluster once a test is done, godog will call this // function on failure and on the last step, so more than once if the diff --git a/docs/modules/ROOT/pages/verify-conforma-konflux-ta.adoc b/docs/modules/ROOT/pages/verify-conforma-konflux-ta.adoc index c0aedfaca..0a466266c 100644 --- a/docs/modules/ROOT/pages/verify-conforma-konflux-ta.adoc +++ b/docs/modules/ROOT/pages/verify-conforma-konflux-ta.adoc @@ -95,7 +95,7 @@ paths can be provided by using the `:` separator. *VSA_SIGNING_KEY* (`string`):: Signing key for format=dsse (k8s:// or file:// URL) *VSA_UPLOAD* (`string`):: VSA upload destination + -*Default*: `local@/var/workdir/vsa` +*Default*: `local@/var/workdir/conforma/vsa` *ociStorage* (`string`):: OCI storage URL for trusted artifacts == Results diff --git a/features/__snapshots__/ta_task_validate_image.snap b/features/__snapshots__/ta_task_validate_image.snap index 3b50328a5..45b2ae93a 100755 --- a/features/__snapshots__/ta_task_validate_image.snap +++ b/features/__snapshots__/ta_task_validate_image.snap @@ -134,7 +134,7 @@ [Golden container image with trusted artifacts:results - 1] { "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n", - "VSA_GENERATED": "false\n" + "VSA_GENERATED": "false" } --- diff --git a/features/ta_task_validate_image.feature b/features/ta_task_validate_image.feature index 672ddadaa..96c4721be 100644 --- a/features/ta_task_validate_image.feature +++ b/features/ta_task_validate_image.feature @@ -50,6 +50,32 @@ Feature: Verify Conforma Trusted Artifact Tekton Task And the task results should match the snapshot And the task logs for step "show-config" should match the snapshot + Scenario: VSA generation with predicate format + Given a working namespace + Given a snapshot artifact with content: + ``` + { + "components": [ + { + "containerImage": "quay.io/hacbs-contract-demo/golden-container@sha256:e76a4ae9dd8a52a0d191fd34ca133af5b4f2609536d32200a4a40a09fdc93a0d" + } + ] + } + ``` + When version 0.1 of the task named "verify-conforma-konflux-ta" is run with parameters: + | SNAPSHOT_FILENAME | snapshotartifact | + | SOURCE_DATA_ARTIFACT | oci:${REGISTRY}/acceptance/snapshotartifact@${BUILD_SNAPSHOT_DIGEST} | + | POLICY_CONFIGURATION | {"publicKey":"-----BEGIN PUBLIC KEY-----\\nMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERhr8Zj4dZW67zucg8fDr11M4lmRp\\nzN6SIcIjkvH39siYg1DkCoa2h2xMUZ10ecbM3/ECqvBV55YwQ2rcIEa7XQ==\\n-----END PUBLIC KEY-----","sources":[{"policy":["git::github.com/conforma/policy//policy/release?ref=d34eab36b23d43748e451004177ca144296bf323","git::github.com/conforma/policy//policy/lib?ref=d34eab36b23d43748e451004177ca144296bf323"],"config":{"include":["slsa_provenance_available"]}}]} | + | STRICT | true | + | IGNORE_REKOR | true | + | ENABLE_VSA | true | + | ATTESTATION_FORMAT | predicate | + | TRUSTED_ARTIFACTS_DEBUG | "true" | + | ORAS_OPTIONS | --plain-http | + Then the task should succeed + And the task result "VSA_GENERATED" should equal "true" + And the task logs for step "report-json" should match the snapshot + Scenario: Policy configuration passed as JSON string Given a working namespace Given a snapshot artifact with content: diff --git a/tasks/verify-conforma-konflux-ta/0.1/verify-conforma-konflux-ta.yaml b/tasks/verify-conforma-konflux-ta/0.1/verify-conforma-konflux-ta.yaml index 06507423d..b4bb60d4e 100644 --- a/tasks/verify-conforma-konflux-ta/0.1/verify-conforma-konflux-ta.yaml +++ b/tasks/verify-conforma-konflux-ta/0.1/verify-conforma-konflux-ta.yaml @@ -203,7 +203,7 @@ spec: - name: VSA_UPLOAD type: string description: VSA upload destination - default: "local@/var/workdir/vsa" + default: "local@/var/workdir/conforma/vsa" - name: ociStorage type: string @@ -322,22 +322,48 @@ spec: if [[ "$(params.ENABLE_VSA)" == "true" ]]; then EC_ARGS+=(--vsa --attestation-format=$(params.ATTESTATION_FORMAT)) + # Extract local path from VSA_UPLOAD for output directory + # VSA_UPLOAD format is "local@/path/to/dir" + VSA_LOCAL_PATH=$(echo "$(params.VSA_UPLOAD)" | grep -oE '^local@[^ ]+' | sed 's/^local@//' | head -n1) + if [[ "$(params.ATTESTATION_FORMAT)" == "dsse" ]]; then if [[ -z "$(params.VSA_SIGNING_KEY)" ]]; then echo "ERROR: VSA_SIGNING_KEY required for format=dsse" >&2 exit 1 fi EC_ARGS+=(--vsa-signing-key "$(params.VSA_SIGNING_KEY)") + EC_ARGS+=(--vsa-upload "$(params.VSA_UPLOAD)") + fi + + # ec requires --attestation-output-dir to be under /tmp or cwd. + # Write there first, then copy to the workdir so + # create-trusted-artifact includes them in the archive. + VSA_TMP_DIR="/tmp/vsa-output" + mkdir -p "$VSA_TMP_DIR" + EC_ARGS+=(--attestation-output-dir "$VSA_TMP_DIR") + + if [[ -n "$VSA_LOCAL_PATH" ]]; then + echo "$VSA_LOCAL_PATH" > $(results.sourceDataArtifact.path) fi - EC_ARGS+=(--vsa-upload "$(params.VSA_UPLOAD)") - echo "true" > $(results.VSA_GENERATED.path) + echo -n "true" > $(results.VSA_GENERATED.path) else - echo "false" > $(results.VSA_GENERATED.path) + echo -n "false" > $(results.VSA_GENERATED.path) fi # Execute EC with constructed arguments ec "${EC_ARGS[@]}" + + # Copy VSA output from /tmp to workdir for trusted artifact archival + if [[ "$(params.ENABLE_VSA)" == "true" ]]; then + VSA_LOCAL_PATH=$(echo "$(params.VSA_UPLOAD)" | grep -oE '^local@[^ ]+' | sed 's/^local@//' | head -n1) + if [[ -n "$VSA_LOCAL_PATH" && -d "/tmp/vsa-output" ]]; then + mkdir -p "$VSA_LOCAL_PATH" + cp -r /tmp/vsa-output/* "$VSA_LOCAL_PATH"/ 2>/dev/null || true + # Include raw JSON report for downstream SLSA VSA generation + cp "$(params.HOMEDIR)/report-json.json" "$VSA_LOCAL_PATH"/ 2>/dev/null || true + fi + fi env: # POLICY_CONFIGURATION is passed via environment variable to safely handle JSON strings # This avoids shell quoting issues when Tekton substitutes parameter values directly in scripts @@ -449,7 +475,9 @@ spec: - name: ociStorage value: $(params.ociStorage) - name: workDir - value: /var/workdir + value: $(params.TRUSTED_ARTIFACTS_EXTRACT_DIR) + - name: sourceDataArtifact + value: $(results.sourceDataArtifact.path) volumes: - name: trusted-ca