From fbe5816de46402507f9ebb0559cea9928a0af688 Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Fri, 7 Aug 2026 18:45:36 -0400 Subject: [PATCH 1/2] DNM: Skip CI test jobs for POC branch Co-Authored-By: Claude Opus 4.6 --- .github/workflows/checks-codecov.yaml | 3 +++ .github/workflows/codeql.yaml | 1 + 2 files changed, 4 insertions(+) diff --git a/.github/workflows/checks-codecov.yaml b/.github/workflows/checks-codecov.yaml index f5aeb70fb..11e6480f2 100644 --- a/.github/workflows/checks-codecov.yaml +++ b/.github/workflows/checks-codecov.yaml @@ -34,6 +34,7 @@ permissions: jobs: Test: + if: false # skipped for POC branch runs-on: ubuntu-latest steps: - name: Harden Runner @@ -96,6 +97,7 @@ jobs: retention-days: 1 Acceptance: + if: false # skipped for POC branch runs-on: ubuntu-latest steps: # Disabled until we figure out the "Could not resolve host: github.com" in @@ -164,6 +166,7 @@ jobs: Upload: name: "Upload Coverage Statistics" + if: false # skipped for POC branch runs-on: ubuntu-latest needs: [Test, Acceptance] steps: diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml index 86d2df8b4..7f68d0a03 100644 --- a/.github/workflows/codeql.yaml +++ b/.github/workflows/codeql.yaml @@ -32,6 +32,7 @@ permissions: jobs: analyze: + if: false # skipped for POC branch name: Analyze runs-on: ubuntu-latest permissions: From fbf23a6ca4806197f9930f5931fbd8a3cc17874f Mon Sep 17 00:00:00 2001 From: Simon Baird Date: Fri, 7 Aug 2026 18:22:17 -0400 Subject: [PATCH 2/2] WIP Add dummy task, pipeline, and ITS for EC-2011 Adds a dummy-check Tekton task that produces configurable pass/fail/warn results with a test-result attestation step, a pipeline that parses a Snapshot and runs the task, and a script to create the IntegrationTestScenario in the cluster. To provide a push secret for the oras attach, there is some new Service Account setup also. The goal is to dogfood the new method for required tasks to be run in ITS pipelines with their results visible to Conforma with a secure chain of trust. Ref: https://redhat.atlassian.net/browse/EC-2011 Co-Authored-By: Claude Opus 4.6 --- hack/create-dummy-its.sh | 104 ++++++++++ hack/modify-sa-for-dummy-its.sh | 142 +++++++++++++ .../0.1/dummy-integration-test.yaml | 102 ++++++++++ tasks/dummy-check/0.1/dummy-check.yaml | 188 ++++++++++++++++++ 4 files changed, 536 insertions(+) create mode 100755 hack/create-dummy-its.sh create mode 100755 hack/modify-sa-for-dummy-its.sh create mode 100644 pipelines/dummy-integration-test/0.1/dummy-integration-test.yaml create mode 100644 tasks/dummy-check/0.1/dummy-check.yaml diff --git a/hack/create-dummy-its.sh b/hack/create-dummy-its.sh new file mode 100755 index 000000000..269b838fd --- /dev/null +++ b/hack/create-dummy-its.sh @@ -0,0 +1,104 @@ +#!/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 + +# Creates (or deletes) the dummy IntegrationTestScenario for the EC-2011 POC. +# +# This script ONLY manages the IntegrationTestScenario object. The ITS pipeline's +# attest-test-result step also needs push access, which requires patching the +# shared konflux-integration-runner ServiceAccount — a separate, security- +# sensitive, namespace-wide change handled by hack/modify-sa-for-dummy-its.sh. +# Run that script after this one to grant push access. + +set -euo pipefail + +NAMESPACE="${NAMESPACE:-rhtap-contract-tenant}" +APPLICATION="${APPLICATION:-ec-main}" +ITS_NAME="${ITS_NAME:-reqd-task-poc-ec2011}" + +GIT_URL="${GIT_URL:-https://github.com/simonbaird/conforma-cli}" +GIT_REVISION="${GIT_REVISION:-reqd-task-its-poc}" +PIPELINE_PATH="${PIPELINE_PATH:-pipelines/dummy-integration-test/0.1/dummy-integration-test.yaml}" + +usage() { + cat <&2; echo ""; usage; exit 1 ;; +esac diff --git a/hack/modify-sa-for-dummy-its.sh b/hack/modify-sa-for-dummy-its.sh new file mode 100755 index 000000000..878666215 --- /dev/null +++ b/hack/modify-sa-for-dummy-its.sh @@ -0,0 +1,142 @@ +#!/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 + +# Grants (or revokes) push access for the EC-2011 POC ITS pipeline by patching +# the shared konflux-integration-runner ServiceAccount. +# +# The integration service runs all ITS pipelines using the +# konflux-integration-runner ServiceAccount. There's currently no way to +# specify a per-ITS ServiceAccount, so we have to patch the shared SA to +# include the push secret needed by the attest-test-result step action. +# +# NOTE: This is a security hazard, not just a broad-scope inconvenience. ITS +# pipelines are BYO/arbitrary by design, so any secret on the shared runner SA +# is a secret handed to untrusted code. This patch is acceptable only for this +# POC under a "trusted pipeline" assumption; a real solution must keep push +# credentials off the runner SA entirely (e.g. platform-side push). It is kept +# in its own script (separate from create-dummy-its.sh) precisely because it is +# a shared, namespace-wide, security-sensitive change. +# +# TODO: Ideally only specific ITS pipelines that need push access should +# get it, not every ITS in the namespace. This requires either: +# - A per-ITS ServiceAccount field in the IntegrationTestScenario spec +# (integration-service is one field away: the `if ServiceAccountName == ""` +# guard in tekton/integration_pipeline.go already exists, nothing feeds it) +# - A dedicated SA created and wired up per pipeline +# For now we accept the broader scope for this POC. + +set -euo pipefail + +NAMESPACE="${NAMESPACE:-rhtap-contract-tenant}" +INTEGRATION_SA="konflux-integration-runner" +PUSH_SECRET="${PUSH_SECRET:-imagerepository-for-ec-main-cli-main-image-push}" + +# The pull-only secret "ec-main-pull" covers the same registry path as the +# push secret. Tekton merges all SA secrets into a single docker config, and +# if the pull-only credential wins the merge for that registry, oras attach +# fails with "unauthorized". Removing the pull-only secret avoids the +# conflict — the push secret includes pull permission so nothing is lost. +# +# NOTE: select-oci-auth (used by the oras attach step action) does NOT avoid +# this. Both secrets key their auth at the identical repo path, so Tekton's +# merge keeps only one token; select-oci-auth only disambiguates across +# *different* keys and runs after the merge. So this removal is still required. +PULL_SECRET="${PULL_SECRET:-ec-main-pull}" + +usage() { + cat <&2; echo ""; usage; exit 1 ;; +esac diff --git a/pipelines/dummy-integration-test/0.1/dummy-integration-test.yaml b/pipelines/dummy-integration-test/0.1/dummy-integration-test.yaml new file mode 100644 index 000000000..a9dadf83d --- /dev/null +++ b/pipelines/dummy-integration-test/0.1/dummy-integration-test.yaml @@ -0,0 +1,102 @@ +# 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 + +--- +apiVersion: tekton.dev/v1 +kind: Pipeline +metadata: + name: reqd-task-poc-ec2011 + labels: + build.appstudio.redhat.com/pipeline: "reqd-task-poc-ec2011" +spec: + params: + - name: SNAPSHOT + type: string + description: | + Spec section of an ApplicationSnapshot resource. Not all fields of the + resource are required. A minimal example: + { + "components": [ + { + "containerImage": "quay.io/example/repo@sha256:abc123..." + } + ] + } + Each "containerImage" in the "components" array is validated. + - name: RESULT + type: string + description: >- + The desired result of the dummy check. Must be one of: SUCCESS, + FAILURE, WARNING, ERROR, or SKIPPED. + default: "SUCCESS" + results: + - name: TEST_OUTPUT + value: "$(tasks.dummy-check.results.TEST_OUTPUT)" + tasks: + - name: parse-snapshot + taskSpec: + params: + - name: SNAPSHOT + type: string + results: + - name: image-url + - name: image-digest + steps: + - name: parse + image: quay.io/konflux-ci/task-runner:v3 + env: + - name: SNAPSHOT + value: $(params.SNAPSHOT) + script: | + #!/usr/bin/env bash + set -euo pipefail + + IMAGE=$(jq -r '.components[0].containerImage // empty' <<<"${SNAPSHOT}") + if [[ -z "${IMAGE}" ]]; then + echo "ERROR: No containerImage found in SNAPSHOT" >&2 + exit 1 + fi + + IMAGE_URL="${IMAGE%%@*}" + IMAGE_DIGEST="${IMAGE##*@}" + + echo "Parsed image-url: ${IMAGE_URL}" + echo "Parsed image-digest: ${IMAGE_DIGEST}" + + echo -n "${IMAGE_URL}" > "$(results.image-url.path)" + echo -n "${IMAGE_DIGEST}" > "$(results.image-digest.path)" + params: + - name: SNAPSHOT + value: "$(params.SNAPSHOT)" + - name: dummy-check + runAfter: + - parse-snapshot + params: + - name: RESULT + value: "$(params.RESULT)" + - name: image-url + value: "$(tasks.parse-snapshot.results.image-url)" + - name: image-digest + value: "$(tasks.parse-snapshot.results.image-digest)" + taskRef: + resolver: git + params: + - name: url + value: https://github.com/simonbaird/conforma-cli + - name: revision + value: reqd-task-its-poc + - name: pathInRepo + value: tasks/dummy-check/0.1/dummy-check.yaml diff --git a/tasks/dummy-check/0.1/dummy-check.yaml b/tasks/dummy-check/0.1/dummy-check.yaml new file mode 100644 index 000000000..511133a92 --- /dev/null +++ b/tasks/dummy-check/0.1/dummy-check.yaml @@ -0,0 +1,188 @@ +# 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 + +--- +apiVersion: tekton.dev/v1 +kind: Task +metadata: + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/tags: "konflux" + name: dummy-check +spec: + description: >- + A dummy task for testing purposes. Instead of performing a real check, it + produces a pass, fail, or warn result based on the RESULT param. Mimics the + output format of real SAST tasks (e.g. sast-snyk-check) so it can be used + as a stand-in during pipeline development and testing. + results: + - description: Tekton task test output. + name: TEST_OUTPUT + - name: TEST_OUTPUT_ARTIFACT_OUTPUTS + description: >- + JSON object with uri and digest referencing the pushed attestation. + Tekton Chains uses this for SLSA provenance. + type: object + properties: + uri: {} + digest: {} + params: + - name: RESULT + type: string + description: >- + The desired result of this dummy check. Must be one of: SUCCESS, + FAILURE, WARNING, ERROR, or SKIPPED. + default: "SUCCESS" + - name: NOTE + type: string + description: >- + Optional note to include in the test output. If not provided, a default + message is generated based on the RESULT value. + default: "" + - name: SUCCESSES + type: string + description: Number of successes to report in the test output. + default: "1" + - name: FAILURES + type: string + description: Number of failures to report in the test output. + default: "0" + - name: WARNINGS + type: string + description: Number of warnings to report in the test output. + default: "0" + - name: image-url + description: Image URL. + type: string + default: "" + - name: image-digest + description: Digest of the image. + type: string + default: "" + - name: PUSH_SECRET_NAME + description: >- + Name of the Kubernetes secret containing push credentials for the + image registry. Needed because the integration runner SA merges + multiple credentials and the pull-only one can take precedence. + type: string + default: "imagerepository-for-ec-main-cli-main-image-push" + volumes: + - name: push-credentials + secret: + secretName: $(params.PUSH_SECRET_NAME) + optional: true + stepTemplate: + volumeMounts: + - name: push-credentials + mountPath: /etc/push-credentials + readOnly: true + steps: + - name: dummy-check + results: + - name: TEST_OUTPUT + description: JSON test results for consumption by subsequent steps. + image: registry.access.redhat.com/ubi9/ubi-minimal:latest + env: + - name: RESULT + value: $(params.RESULT) + - name: NOTE + value: $(params.NOTE) + - name: SUCCESSES + value: $(params.SUCCESSES) + - name: FAILURES + value: $(params.FAILURES) + - name: WARNINGS + value: $(params.WARNINGS) + computeResources: + limits: + memory: 256Mi + requests: + cpu: 100m + memory: 128Mi + script: | + #!/usr/bin/env bash + set -euo pipefail + + VALID_RESULTS="SUCCESS FAILURE WARNING ERROR SKIPPED" + if ! echo "${VALID_RESULTS}" | grep -qw "${RESULT}"; then + echo "ERROR: Invalid RESULT '${RESULT}'. Must be one of: ${VALID_RESULTS}" >&2 + exit 1 + fi + + if [[ -z "${NOTE}" ]]; then + case "${RESULT}" in + SUCCESS) NOTE="Task $(context.task.name) completed successfully. This is a dummy check." ;; + FAILURE) NOTE="Task $(context.task.name) failed. This is a dummy check." ;; + WARNING) NOTE="Task $(context.task.name) produced warnings. This is a dummy check." ;; + ERROR) NOTE="Task $(context.task.name) encountered an error. This is a dummy check." ;; + SKIPPED) NOTE="Task $(context.task.name) was skipped. This is a dummy check." ;; + esac + fi + + # Adjust counts based on RESULT if user left defaults + case "${RESULT}" in + FAILURE) + if [[ "${FAILURES}" == "0" ]]; then FAILURES="1"; fi + if [[ "${SUCCESSES}" == "1" ]]; then SUCCESSES="0"; fi + ;; + WARNING) + if [[ "${WARNINGS}" == "0" ]]; then WARNINGS="1"; fi + ;; + ERROR|SKIPPED) + SUCCESSES="0" + FAILURES="0" + WARNINGS="0" + ;; + esac + + TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%S") + + TEST_OUTPUT=$(printf '{ + "result": "%s", + "timestamp": "%s", + "note": "%s", + "namespace": "default", + "successes": %d, + "failures": %d, + "warnings": %d + }' "${RESULT}" "${TIMESTAMP}" "${NOTE}" "${SUCCESSES}" "${FAILURES}" "${WARNINGS}") + + echo "Dummy check result: ${RESULT}" + echo "${TEST_OUTPUT}" | tee "$(results.TEST_OUTPUT.path)" + echo -n "${TEST_OUTPUT}" > "$(step.results.TEST_OUTPUT.path)" + - name: create-test-result-attestation + ref: + resolver: git + params: + - name: url + # Todo: Stop using fork once https://github.com/conforma/step-actions/pull/6 is merged + value: https://github.com/simonbaird/step-actions + - name: revision + value: task-runner-select-oci-auth + #value: oras-runner-and-push-secret-fix + - name: pathInRepo + value: stepactions/attest-test-result/0.1/attest-test-result.yaml + params: + - name: image-url + value: $(params.image-url) + - name: image-digest + value: $(params.image-digest) + - name: test-name + value: $(context.task.name) + - name: test-output + value: $(steps.dummy-check.results.TEST_OUTPUT)