From 6109c0cf066b9a654256dcd8a57a319494811a4d Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Thu, 26 Feb 2026 18:24:52 -0500 Subject: [PATCH 1/4] Convert v-e-c task to script instead of command I'm doing this first in its own separate commit because it will make the next commit easier to understand and review. There's no functional change happening, we're just defining the task step in a different way. Note: - There are some clear inconsistencies in the way we use `--arg=value` or `--arg value` but I'm keeping all that as-is, since I want this change to be as small as possible. - For the same reason I'm keeping the commentary, and the timeout param, which I think could be removed now. Not touching it. - I'm focussing on just the verify-enterprise-contract task only here. My plan is to get that working first, then tackle the other tasks. Ref: https://issues.redhat.com/browse/EC-1652 Co-authored-by: Claude Code --- .../0.1/verify-enterprise-contract.yaml | 105 +++++++++++------- 1 file changed, 63 insertions(+), 42 deletions(-) diff --git a/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml b/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml index dd53433d7..ebe67b5c0 100644 --- a/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml +++ b/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml @@ -236,49 +236,70 @@ spec: - name: validate image: quay.io/conforma/cli:latest onError: continue # progress even if the step fails so we can see the debug logs - command: [ec] - args: - - validate - - image - - "--images" - - "/tekton/home/snapshot.json" - - "--policy" - - "$(params.POLICY_CONFIGURATION)" - - "--public-key" - - "$(params.PUBLIC_KEY)" - - "--rekor-url" - - "$(params.REKOR_HOST)" - - "--ignore-rekor=$(params.IGNORE_REKOR)" - - "--workers" - - "$(params.WORKERS)" - # NOTE: The syntax below is required to negate boolean parameters - - "--info=$(params.INFO)" - # Fresh versions of ec support "--timeout=0" to indicate no timeout, but this would break - # the task if it's used with an older version of ec. In an abundance of caution, let's set - # an arbitrary high value instead of using 0 here. In future we can change it to 0. - # (The reason to not use an explicit timeout for ec is so Tekton can handle the timeouts). - - "--timeout=100h" - - "--strict=false" - - "--show-successes" - - "--effective-time=$(params.EFFECTIVE_TIME)" - - "--extra-rule-data=$(params.EXTRA_RULE_DATA)" - - "--retry-max-wait" - - "$(params.RETRY_MAX_WAIT)" - - "--retry-max-retry" - - "$(params.RETRY_MAX_RETRY)" - - "--retry-duration" - - "$(params.RETRY_DURATION)" - - "--retry-factor" - - "$(params.RETRY_FACTOR)" - - "--retry-jitter" - - "$(params.RETRY_JITTER)" - - "--output" - - "text=$(params.HOMEDIR)/text-report.txt?show-successes=false" - - "--output" - - "appstudio=$(results.TEST_OUTPUT.path)" - - "--output" - - "json=$(params.HOMEDIR)/report-json.json" + script: | + #!/bin/bash + set -euo pipefail + + cmd_args=( + "validate" + "image" + "--images" "/tekton/home/snapshot.json" + "--policy" "${POLICY_CONFIGURATION}" + "--public-key" "${PUBLIC_KEY}" + "--rekor-url" "${REKOR_HOST}" + "--ignore-rekor=${IGNORE_REKOR}" + "--workers" "${WORKERS}" + # NOTE: The syntax below is required to negate boolean parameters + "--info=${INFO}" + # Fresh versions of ec support "--timeout=0" to indicate no timeout, but this would break + # the task if it's used with an older version of ec. In an abundance of caution, let's set + # an arbitrary high value instead of using 0 here. In future we can change it to 0. + # (The reason to not use an explicit timeout for ec is so Tekton can handle the timeouts). + "--timeout=100h" + "--strict=false" + "--show-successes" + "--effective-time=${EFFECTIVE_TIME}" + "--extra-rule-data=${EXTRA_RULE_DATA}" + "--retry-max-wait" "${RETRY_MAX_WAIT}" + "--retry-max-retry" "${RETRY_MAX_RETRY}" + "--retry-duration" "${RETRY_DURATION}" + "--retry-factor" "${RETRY_FACTOR}" + "--retry-jitter" "${RETRY_JITTER}" + "--output" "text=${HOMEDIR}/text-report.txt?show-successes=false" + "--output" "appstudio=$(results.TEST_OUTPUT.path)" + "--output" "json=${HOMEDIR}/report-json.json" + ) + + exec ec "${cmd_args[@]}" env: + - name: POLICY_CONFIGURATION + value: "$(params.POLICY_CONFIGURATION)" + - name: PUBLIC_KEY + value: "$(params.PUBLIC_KEY)" + - name: REKOR_HOST + value: "$(params.REKOR_HOST)" + - name: IGNORE_REKOR + value: "$(params.IGNORE_REKOR)" + - name: WORKERS + value: "$(params.WORKERS)" + - name: INFO + value: "$(params.INFO)" + - name: EFFECTIVE_TIME + value: "$(params.EFFECTIVE_TIME)" + - name: EXTRA_RULE_DATA + value: "$(params.EXTRA_RULE_DATA)" + - name: RETRY_MAX_WAIT + value: "$(params.RETRY_MAX_WAIT)" + - name: RETRY_MAX_RETRY + value: "$(params.RETRY_MAX_RETRY)" + - name: RETRY_DURATION + value: "$(params.RETRY_DURATION)" + - name: RETRY_FACTOR + value: "$(params.RETRY_FACTOR)" + - name: RETRY_JITTER + value: "$(params.RETRY_JITTER)" + - name: HOMEDIR + value: "$(params.HOMEDIR)" - name: SSL_CERT_DIR # The Tekton Operator automatically sets the SSL_CERT_DIR env to the value below but, # of course, without the $(param.SSL_CERT_DIR) bit. When a Task Step sets it to a From da68f18a091003b1d7d82567f610a2a2c5655245 Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Thu, 26 Feb 2026 18:17:46 -0500 Subject: [PATCH 2/4] Tekton task support for keyless sig checks We're keeping the new param handling bash as light as possible. My thinking is that ec should produce a good enough error if the params are wrong or incorrectly specified, so we don't want or need a layer messy bash to check that they are correct. Ref: https://issues.redhat.com/browse/EC-1652 Co-authored-by: Claude Code --- .../pages/verify-enterprise-contract.adoc | 2 ++ .../0.1/verify-enterprise-contract.yaml | 35 ++++++++++++++++++- 2 files changed, 36 insertions(+), 1 deletion(-) diff --git a/docs/modules/ROOT/pages/verify-enterprise-contract.adoc b/docs/modules/ROOT/pages/verify-enterprise-contract.adoc index 8af4427e3..fbf48ced0 100644 --- a/docs/modules/ROOT/pages/verify-enterprise-contract.adoc +++ b/docs/modules/ROOT/pages/verify-enterprise-contract.adoc @@ -34,6 +34,8 @@ You can also specify a policy configuration using a git url, e.g. *Default*: `enterprise-contract-service/default` *PUBLIC_KEY* (`string`):: Public key used to verify signatures. Must be a valid k8s cosign reference, e.g. k8s://my-space/my-secret where my-secret contains the expected cosign.pub attribute. *REKOR_HOST* (`string`):: Rekor host for transparency log lookups +*CERTIFICATE_IDENTITY* (`string`):: Expected identity in the signing certificate for keyless verification. This should be the email or URI that was used when signing. +*CERTIFICATE_OIDC_ISSUER* (`string`):: Expected OIDC issuer in the signing certificate for keyless verification. This should match the issuer that provided the identity token used for signing. *IGNORE_REKOR* (`string`):: Skip Rekor transparency log checks during validation. + *Default*: `false` diff --git a/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml b/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml index ebe67b5c0..d7a4e1624 100644 --- a/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml +++ b/tasks/verify-enterprise-contract/0.1/verify-enterprise-contract.yaml @@ -69,6 +69,20 @@ spec: description: Rekor host for transparency log lookups default: "" + - name: CERTIFICATE_IDENTITY + type: string + description: >- + Expected identity in the signing certificate for keyless verification. + This should be the email or URI that was used when signing. + default: "" + + - name: CERTIFICATE_OIDC_ISSUER + type: string + description: >- + Expected OIDC issuer in the signing certificate for keyless verification. + This should match the issuer that provided the identity token used for signing. + default: "" + - name: IGNORE_REKOR type: string description: >- @@ -245,7 +259,22 @@ spec: "image" "--images" "/tekton/home/snapshot.json" "--policy" "${POLICY_CONFIGURATION}" - "--public-key" "${PUBLIC_KEY}" + ) + + # To keep bash logic as thin as possible we deliberately don't sanitize + # these params. If something is wrong or missing let Conforma handle it. + if [ -n "${CERTIFICATE_IDENTITY}" ] && [ -n "${CERTIFICATE_OIDC_ISSUER}" ]; then + cmd_args+=( + "--certificate-identity" "${CERTIFICATE_IDENTITY}" + "--certificate-oidc-issuer" "${CERTIFICATE_OIDC_ISSUER}" + ) + elif [ -n "${PUBLIC_KEY}" ]; then + cmd_args+=( + "--public-key" "${PUBLIC_KEY}" + ) + fi + + cmd_args+=( "--rekor-url" "${REKOR_HOST}" "--ignore-rekor=${IGNORE_REKOR}" "--workers" "${WORKERS}" @@ -276,6 +305,10 @@ spec: value: "$(params.POLICY_CONFIGURATION)" - name: PUBLIC_KEY value: "$(params.PUBLIC_KEY)" + - name: CERTIFICATE_IDENTITY + value: "$(params.CERTIFICATE_IDENTITY)" + - name: CERTIFICATE_OIDC_ISSUER + value: "$(params.CERTIFICATE_OIDC_ISSUER)" - name: REKOR_HOST value: "$(params.REKOR_HOST)" - name: IGNORE_REKOR From 0c413e703ccde73f47bb87fa76d05cc00d2d1401 Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Fri, 27 Feb 2026 15:43:05 -0500 Subject: [PATCH 3/4] Script to create keyless signed images for testing As per the comments, I'm creating an image that we can use with the acceptance tests. Unlike the "golden-container" it wasn't built in Konflux and hence it doesn't have a realistic Chains style attestation. But it does have a keylessly sig and an a valid attestation. And actually there are two images, one created with cosign v2, and one with cosign v3. This should be useful since we need to support the new sigstore bundle introduced in cosign v3. The verify.sh isn't important for anything, but I want to check it in anyhow, since it serves as a nice instruction on how to verify the keyless signed images and attestations, and it's useful to sanity check the images when/if they need recreating. Ref: https://issues.redhat.com/browse/EC-1652 --- hack/keyless-test-image/create.sh | 89 ++++++++++++++++++++++++++++++ hack/keyless-test-image/helpers.sh | 42 ++++++++++++++ hack/keyless-test-image/verify.sh | 74 +++++++++++++++++++++++++ 3 files changed, 205 insertions(+) create mode 100755 hack/keyless-test-image/create.sh create mode 100644 hack/keyless-test-image/helpers.sh create mode 100755 hack/keyless-test-image/verify.sh diff --git a/hack/keyless-test-image/create.sh b/hack/keyless-test-image/create.sh new file mode 100755 index 000000000..abe23f733 --- /dev/null +++ b/hack/keyless-test-image/create.sh @@ -0,0 +1,89 @@ +#!/usr/bin/env bash +# Copyright The Conforma Contributors +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +set -euo pipefail + +source "$(dirname ${BASH_SOURCE[0]})/helpers.sh" + +# This script creates two keylessly signed images that we use in our acceptance +# tests. One created with cosign v2 and one with cosign v3 using the newer +# sigstore bundle and OCI referrers + +# Prereqs if you want to recreate these images: +# - A working push credential for quay.io/conforma/test +# - The ability to authenticate as the "conformacommunity@gmail.com" Google account + +# Note: Ideally we would not rely on external images in the tests, but this is +# the quickest way to get some meaningful acceptance tests for the keyless +# image verification in the Tekton task. Also, we already have some other +# external images used in the tests, so I figure adding one more isn't such a +# big deal. + +REPO=quay.io/conforma/test + +# Todo: Maybe we can we specify these explicitly when signing +# CERT_IDENITY="conformacommunity@gmail.com" +# CERT_OIDC_ISSUER="https://accounts.google.com" + +# Todo maybe: Pin the versions of cosign, (perhaps with a go.mod file?) instead +# of using @latest. + +for ver in v2 v3; do + LABEL="keyless_$ver" + COSIGN="go run github.com/sigstore/cosign/$ver/cmd/cosign@latest" + GIT_VER=$($COSIGN version --json | jq -r .gitVersion) + DATE_STR=$(date) + + + h1 "Creating image ($ver)" + podman build -t "$REPO:$LABEL" -f - . < /hello.txt +CMD ["cat", "/hello.txt"] +EOF + + h1 "Pushing image ($ver)" + podman push "$REPO:$LABEL" + + h1 "Signing image ($ver)" + # Use the digest otherwise cosign complains + DIGEST=$(skopeo inspect "docker://quay.io/conforma/test:keyless_$ver" | jq -r .Digest) + $COSIGN sign -y "$REPO@$DIGEST" + + h1 "Creating a signed attestation ($ver)" + # Push a minimal attestation + $COSIGN attest -y \ + --predicate - \ + --type "https://slsa.dev/provenance/v1" \ + $REPO@$DIGEST < /dev/null +$COSIGN_V3 verify-attestation "$IMAGE_V2" --type "$SLSA" "${CERT_ARGS[@]}" > /dev/null +pause + +h1 "Forwards compatibility does not work (v3 sig with v2 cosign)" +set +e +$COSIGN_V2 verify "$IMAGE_V3" "${CERT_ARGS[@]}" +$COSIGN_V2 verify-attestation "$IMAGE_V3" --type "$SLSA" "${CERT_ARGS[@]}" +set -e +pause From 63baa3410b9fdf6fa530c83cf193cf7593a10bc3 Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Thu, 26 Feb 2026 19:27:23 -0500 Subject: [PATCH 4/4] Add acceptance test for task keyless support Note that the snapshot output reveals there are some bugs related to to how we output image signatures and attestation signature for the image with the v3 style sigstore bundle. I want to fix this later since this PR already has a lot of changes, so I filed https://issues.redhat.com/browse/EC-1690 to track it. Ref: https://issues.redhat.com/browse/EC-1652 Co-authored-by: Claude Code --- .../__snapshots__/task_validate_image.snap | 273 ++++++++++++++++++ features/task_validate_image.feature | 75 +++++ 2 files changed, 348 insertions(+) diff --git a/features/__snapshots__/task_validate_image.snap b/features/__snapshots__/task_validate_image.snap index 13b2bcb53..91a7a9e69 100755 --- a/features/__snapshots__/task_validate_image.snap +++ b/features/__snapshots__/task_validate_image.snap @@ -180,3 +180,276 @@ true "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":3,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" } --- + +[Keyless signing verification cosign v3 style:report-json - 1] +{ + "success": true, + "components": [ + { + "name": "", + "containerImage": "quay.io/conforma/test@sha256:712ca3a7fcd41fe6b3e6f434a31f738743b6c31f1d81ad458502d6b0239a8903", + "source": {}, + "successes": [ + { + "msg": "Pass", + "metadata": { + "code": "builtin.attestation.signature_check", + "description": "The attestation signature matches available signing materials.", + "title": "Attestation signature check passed" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "builtin.attestation.syntax_check", + "description": "The attestation has correct syntax.", + "title": "Attestation syntax check passed" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "builtin.image.signature_check", + "description": "The image signature matches available signing materials.", + "title": "Image signature check passed" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "slsa_provenance_available.allowed_predicate_types_provided", + "collections": [ + "minimal", + "slsa3", + "redhat", + "redhat_rpms", + "policy_data" + ], + "description": "Confirm the `allowed_predicate_types` rule data was provided, since it is required by the policy rules in this package.", + "title": "Allowed predicate types provided" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "slsa_provenance_available.attestation_predicate_type_accepted", + "collections": [ + "minimal", + "slsa3", + "redhat", + "redhat_rpms" + ], + "depends_on": [ + "attestation_type.known_attestation_type" + ], + "description": "Verify that the predicateType field of the attestation indicates the in-toto SLSA Provenance format was used to attest the PipelineRun.", + "title": "Expected attestation predicate type found" + } + } + ], + "success": true, + "signatures": [ + { + "keyid": "", + "sig": "" + }, + { + "keyid": "", + "sig": "" + } + ], + "attestations": [ + { + "type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v1", + "signatures": [ + { + "keyid": "", + "sig": "MEUCIQC5bGm4zzbExXBMrZCmqZ98iqUhi8TV/maq/8dJ/c3POAIgCNw+RkeO7PAkT6JDWIvISZ2AjILu9YuPQ0qqfNwCqug=" + } + ] + }, + { + "type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://sigstore.dev/cosign/sign/v1", + "signatures": [ + { + "keyid": "", + "sig": "MEUCID1cJkxyk1oGvXcoAVkDST9A1vfX2gxPEz+LUzN10nDmAiEAxh9rp79yr4fZmAWWOit0dZ5QWK+uYIU8fQVb0/rLIyM=" + } + ] + } + ] + } + ], + "key": "", + "policy": { + "sources": [ + { + "policy": [ + "git::github.com/conforma/policy//policy/release?ref=0de5461c14413484575e63e96ddb514d8ab954b5", + "git::github.com/conforma/policy//policy/lib?ref=0de5461c14413484575e63e96ddb514d8ab954b5" + ], + "config": { + "include": [ + "slsa_provenance_available" + ] + } + } + ], + "rekorUrl": "https://rekor.sigstore.dev" + }, + "ec-version": "${EC_VERSION}", + "effective-time": "${TIMESTAMP}" +} +--- + +[Keyless signing verification cosign v3 style:results - 1] +{ + "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" +} +--- + +[Keyless signing verification cosign v2 style:report-json - 1] +{ + "success": true, + "components": [ + { + "name": "", + "containerImage": "quay.io/conforma/test@sha256:03a10dff06ae364ef9727d562e7077b135b00c7a978e571c4354519e6d0f23b8", + "source": {}, + "successes": [ + { + "msg": "Pass", + "metadata": { + "code": "builtin.attestation.signature_check", + "description": "The attestation signature matches available signing materials.", + "title": "Attestation signature check passed" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "builtin.attestation.syntax_check", + "description": "The attestation has correct syntax.", + "title": "Attestation syntax check passed" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "builtin.image.signature_check", + "description": "The image signature matches available signing materials.", + "title": "Image signature check passed" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "slsa_provenance_available.allowed_predicate_types_provided", + "collections": [ + "minimal", + "slsa3", + "redhat", + "redhat_rpms", + "policy_data" + ], + "description": "Confirm the `allowed_predicate_types` rule data was provided, since it is required by the policy rules in this package.", + "title": "Allowed predicate types provided" + } + }, + { + "msg": "Pass", + "metadata": { + "code": "slsa_provenance_available.attestation_predicate_type_accepted", + "collections": [ + "minimal", + "slsa3", + "redhat", + "redhat_rpms" + ], + "depends_on": [ + "attestation_type.known_attestation_type" + ], + "description": "Verify that the predicateType field of the attestation indicates the in-toto SLSA Provenance format was used to attest the PipelineRun.", + "title": "Expected attestation predicate type found" + } + } + ], + "success": true, + "signatures": [ + { + "keyid": "dc5f3121f1f76f0d687877532ce44ff55aab2050", + "sig": "MEUCIQDV4du9T+vV6dtN1LsCrZgByokRslw43oxscniN3wbaigIgMV+NFgix7ZjqhIpXFIMVFl1CQuya8JQsYP96ByA5iAc=", + "certificate": "-----BEGIN CERTIFICATE-----\nMIIC0zCCAlqgAwIBAgIUfPJP4pJfIr6Pgt2Q2J9hu4DqoJcwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjYwMzAzMTkxNjUyWhcNMjYwMzAzMTkyNjUyWjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAEGMk9duvfPU07wcRpBWKXUi8bmr833N3pKhP2\nGCVBlFxZIRcD01FKT4TEMvlRIq8gZJO4eQ/WvEL/NpNmkk+PzaOCAXkwggF1MA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQU3F8x\nIfH3bw1oeHdTLORP9VqrIFAwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wKQYDVR0RAQH/BB8wHYEbY29uZm9ybWFjb21tdW5pdHlAZ21haWwuY29tMCkG\nCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgorBgEE\nAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBigYKKwYBBAHW\neQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAAB\nnLUhueMAAAQDAEcwRQIgARu6tEmE0vUHU+MhCQB6tzwROaEn4VdlfGBFWQxxcygC\nIQCHm2/lgszmmt2gC6Pl2bfvCRDKewUQDvWjzNqq8WtPczAKBggqhkjOPQQDAwNn\nADBkAjAMnyVwJVMQflB7Iwfte7cuOYYN2uvmEibKwjmmPgZOq43vSH9Y9gtUvyJk\nZ23vTpwCMHKChuWjhTQgxczH7MhKUO2IphbaHeJYmeFa4rrswhv6h9z6v5IIPovF\nsdbKg+sEHw==\n-----END CERTIFICATE-----\n", + "chain": [ + "-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\nBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\nKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\nzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\nnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\nmygUY7Ii2zbdCdliiow=\n-----END CERTIFICATE-----\n", + "-----BEGIN CERTIFICATE-----\nMIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\nXeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\nX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\nYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\nwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\nKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\nWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\nTNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n-----END CERTIFICATE-----\n" + ], + "metadata": { + "Fulcio Issuer": "https://accounts.google.com", + "Fulcio Issuer (V2)": "https://accounts.google.com", + "Issuer": "CN=sigstore-intermediate,O=sigstore.dev", + "Not After": "${TIMESTAMP}", + "Not Before": "${TIMESTAMP}", + "Serial Number": "7cf24fe2925f22be8f82dd90d89f61bb80eaa097", + "Subject Alternative Name": "Email Addresses:conformacommunity@gmail.com" + } + } + ], + "attestations": [ + { + "type": "https://in-toto.io/Statement/v0.1", + "predicateType": "https://slsa.dev/provenance/v1", + "predicateBuildType": "https://example.com/build-type/v1", + "signatures": [ + { + "keyid": "17d7418e0517e21e30f4fe144128b7ca1d1bb2ac", + "sig": "MEUCIBvsTgzJ5DOVIEAH/u5eav7C3QXx6ttR0tZxFQlJe6c4AiEAtIid+gk+EqgxSYNBLquaq2dfdWBL28yR1EOjn/Fi1T8=", + "certificate": "-----BEGIN CERTIFICATE-----\nMIIC1TCCAlqgAwIBAgIUPUQSAPNDQoKF8C3ufUx0Jta8GvEwCgYIKoZIzj0EAwMw\nNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRl\ncm1lZGlhdGUwHhcNMjYwMzAzMTkxNzA1WhcNMjYwMzAzMTkyNzA1WjAAMFkwEwYH\nKoZIzj0CAQYIKoZIzj0DAQcDQgAE81mfg8hXUQRHdZpbbST2ckHT4YrcRPRvM+tc\nRmcvvexGuwm0yIOBZqIqXeyd/YrJn9MjBdHrmyKIztdR9mdpUaOCAXkwggF1MA4G\nA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUF9dB\njgUX4h4w9P4UQSi3yh0bsqwwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4Y\nZD8wKQYDVR0RAQH/BB8wHYEbY29uZm9ybWFjb21tdW5pdHlAZ21haWwuY29tMCkG\nCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgorBgEE\nAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBigYKKwYBBAHW\neQIEAgR8BHoAeAB2AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAAB\nnLUh7ZUAAAQDAEcwRQIgY5+UpYgU0LsrAiTQSoeLquv9EVJ8lH4rtxQupmSWDWwC\nIQC6zpOJpx/ryldrjdpfycB9wBWIexg+/XC8Avdv9W2D3jAKBggqhkjOPQQDAwNp\nADBmAjEA/LIHzfKog0PwRohtlpLV32CpVyWrTt9jK84quvooFP5dgeegze/A4mrk\n0bO73KdEAjEA94BFoAYPJw1RTmIw5VnZXbYKqhlt0hm4nTx9pVoGQMFEtnIguX7f\nNnaoX2+paxVF\n-----END CERTIFICATE-----\n", + "chain": [ + "-----BEGIN CERTIFICATE-----\nMIICGjCCAaGgAwIBAgIUALnViVfnU0brJasmRkHrn/UnfaQwCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMjA0MTMyMDA2MTVaFw0zMTEwMDUxMzU2NThaMDcxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjEeMBwGA1UEAxMVc2lnc3RvcmUtaW50ZXJtZWRpYXRlMHYwEAYHKoZIzj0C\nAQYFK4EEACIDYgAE8RVS/ysH+NOvuDZyPIZtilgUF9NlarYpAd9HP1vBBH1U5CV7\n7LSS7s0ZiH4nE7Hv7ptS6LvvR/STk798LVgMzLlJ4HeIfF3tHSaexLcYpSASr1kS\n0N/RgBJz/9jWCiXno3sweTAOBgNVHQ8BAf8EBAMCAQYwEwYDVR0lBAwwCgYIKwYB\nBQUHAwMwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQU39Ppz1YkEZb5qNjp\nKFWixi4YZD8wHwYDVR0jBBgwFoAUWMAeX5FFpWapesyQoZMi0CrFxfowCgYIKoZI\nzj0EAwMDZwAwZAIwPCsQK4DYiZYDPIaDi5HFKnfxXx6ASSVmERfsynYBiX2X6SJR\nnZU84/9DZdnFvvxmAjBOt6QpBlc4J/0DxvkTCqpclvziL6BCCPnjdlIB3Pu3BxsP\nmygUY7Ii2zbdCdliiow=\n-----END CERTIFICATE-----\n", + "-----BEGIN CERTIFICATE-----\nMIIB9zCCAXygAwIBAgIUALZNAPFdxHPwjeDloDwyYChAO/4wCgYIKoZIzj0EAwMw\nKjEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MREwDwYDVQQDEwhzaWdzdG9yZTAeFw0y\nMTEwMDcxMzU2NTlaFw0zMTEwMDUxMzU2NThaMCoxFTATBgNVBAoTDHNpZ3N0b3Jl\nLmRldjERMA8GA1UEAxMIc2lnc3RvcmUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAT7\nXeFT4rb3PQGwS4IajtLk3/OlnpgangaBclYpsYBr5i+4ynB07ceb3LP0OIOZdxex\nX69c5iVuyJRQ+Hz05yi+UF3uBWAlHpiS5sh0+H2GHE7SXrk1EC5m1Tr19L9gg92j\nYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRY\nwB5fkUWlZql6zJChkyLQKsXF+jAfBgNVHSMEGDAWgBRYwB5fkUWlZql6zJChkyLQ\nKsXF+jAKBggqhkjOPQQDAwNpADBmAjEAj1nHeXZp+13NWBNa+EDsDP8G1WWg1tCM\nWP/WHPqpaVo0jhsweNFZgSs0eE7wYI4qAjEA2WB9ot98sIkoF3vZYdd3/VtWB5b9\nTNMea7Ix/stJ5TfcLLeABLE4BNJOsQ4vnBHJ\n-----END CERTIFICATE-----\n" + ], + "metadata": { + "Fulcio Issuer": "https://accounts.google.com", + "Fulcio Issuer (V2)": "https://accounts.google.com", + "Issuer": "CN=sigstore-intermediate,O=sigstore.dev", + "Not After": "${TIMESTAMP}", + "Not Before": "${TIMESTAMP}", + "Serial Number": "3d441200f343428285f02dee7d4c7426d6bc1af1", + "Subject Alternative Name": "Email Addresses:conformacommunity@gmail.com" + } + } + ] + } + ] + } + ], + "key": "", + "policy": { + "sources": [ + { + "policy": [ + "git::github.com/conforma/policy//policy/release?ref=0de5461c14413484575e63e96ddb514d8ab954b5", + "git::github.com/conforma/policy//policy/lib?ref=0de5461c14413484575e63e96ddb514d8ab954b5" + ], + "config": { + "include": [ + "slsa_provenance_available" + ] + } + } + ], + "rekorUrl": "https://rekor.sigstore.dev" + }, + "ec-version": "${EC_VERSION}", + "effective-time": "${TIMESTAMP}" +} +--- + +[Keyless signing verification cosign v2 style:results - 1] +{ + "TEST_OUTPUT": "{\"timestamp\":\"${TIMESTAMP}\",\"namespace\":\"\",\"successes\":5,\"failures\":0,\"warnings\":0,\"result\":\"SUCCESS\"}\n" +} +--- diff --git a/features/task_validate_image.feature b/features/task_validate_image.feature index 1a63f289b..de205d33b 100644 --- a/features/task_validate_image.feature +++ b/features/task_validate_image.feature @@ -337,3 +337,78 @@ Feature: Verify Enterprise Contract Tekton Tasks Then the task should succeed And the task logs for step "report" should match the snapshot And the task results should match the snapshot + + # See hack/keyless-test-image for how the quay.io/conforma/test:keyless_v2 + # and quay.io/conforma/test:keyless_v3 test images where created. It's not + # ideal that this test requires an external image, but we already do this + # elsewhere, so I guess one more is okay. + + # Todo: We should be able test this also with an internally built image + # similar to how it's done in the "happy day with keyless" scenario in the + # validate_image feature. + + # Confirm we can verify the signatures on a keylessly signed image signed with cosign v2 + Scenario: Keyless signing verification cosign v2 style + Given a working namespace + Given a cluster policy with content: + ``` + { + "sources": [ + { + "policy": [ + "github.com/conforma/policy//policy/release?ref=0de5461c14413484575e63e96ddb514d8ab954b5", + "github.com/conforma/policy//policy/lib?ref=0de5461c14413484575e63e96ddb514d8ab954b5" + ], + "config": { + "include": [ + "slsa_provenance_available" + ] + } + } + ] + } + ``` + When version 0.1 of the task named "verify-enterprise-contract" is run with parameters: + | IMAGES | {"components": [{"containerImage": "quay.io/conforma/test:keyless_v2@sha256:03a10dff06ae364ef9727d562e7077b135b00c7a978e571c4354519e6d0f23b8"}]} | + | POLICY_CONFIGURATION | ${NAMESPACE}/${POLICY_NAME} | + | CERTIFICATE_IDENTITY | conformacommunity@gmail.com | + | CERTIFICATE_OIDC_ISSUER | https://accounts.google.com | + | REKOR_HOST | https://rekor.sigstore.dev | + | IGNORE_REKOR | false | + | STRICT | true | + Then the task should succeed + And the task logs for step "report-json" should match the snapshot + And the task results should match the snapshot + + # Confirm we can verify the signatures on a keylessly signed image signed with cosign v3 + Scenario: Keyless signing verification cosign v3 style + Given a working namespace + Given a cluster policy with content: + ``` + { + "sources": [ + { + "policy": [ + "github.com/conforma/policy//policy/release?ref=0de5461c14413484575e63e96ddb514d8ab954b5", + "github.com/conforma/policy//policy/lib?ref=0de5461c14413484575e63e96ddb514d8ab954b5" + ], + "config": { + "include": [ + "slsa_provenance_available" + ] + } + } + ] + } + ``` + When version 0.1 of the task named "verify-enterprise-contract" is run with parameters: + | IMAGES | {"components": [{"containerImage": "quay.io/conforma/test:keyless_v3@sha256:712ca3a7fcd41fe6b3e6f434a31f738743b6c31f1d81ad458502d6b0239a8903"}]} | + | POLICY_CONFIGURATION | ${NAMESPACE}/${POLICY_NAME} | + | CERTIFICATE_IDENTITY | conformacommunity@gmail.com | + | CERTIFICATE_OIDC_ISSUER | https://accounts.google.com | + | REKOR_HOST | https://rekor.sigstore.dev | + | IGNORE_REKOR | false | + | STRICT | true | + Then the task should succeed + And the task logs for step "report-json" should match the snapshot + And the task results should match the snapshot