diff --git a/CODEOWNERS b/CODEOWNERS index 1103b7eeff..4a7d38ea2c 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -52,14 +52,17 @@ /.tekton/tasks/ec-checks.yaml @konflux-ci/ec # renovate groupName=integration -/task/clair-scan @konflux-ci/integration-service-maintainers -/task/clamav-scan @konflux-ci/integration-service-maintainers -/task/deprecated-image-check @konflux-ci/integration-service-maintainers -/task/fbc-related-image-check @konflux-ci/integration-service-maintainers -/task/fbc-validation @konflux-ci/integration-service-maintainers -/task/inspect-image @konflux-ci/integration-service-maintainers -/task/sbom-json-check @konflux-ci/integration-service-maintainers -/task/validate-fbc @konflux-ci/integration-service-maintainers +/task/clair-scan @konflux-ci/integration-service-maintainers +/task/clamav-scan @konflux-ci/integration-service-maintainers +/task/deprecated-image-check @konflux-ci/integration-service-maintainers +/task/fbc-related-image-check @konflux-ci/integration-service-maintainers +/task/fbc-validation @konflux-ci/integration-service-maintainers +/task/inspect-image @konflux-ci/integration-service-maintainers +/task/sbom-json-check @konflux-ci/integration-service-maintainers +/task/validate-fbc @konflux-ci/integration-service-maintainers +/task/fips-operator-bundle-check @konflux-ci/integration-service-maintainers +/task/fips-operator-bundle-check-oci-ta @konflux-ci/integration-service-maintainers +/stepactions/fips-operator-check-step-action @konflux-ci/integration-service-maintainers # renovate groupName=integration /task/coverity-availability-check @konflux-ci/integration-service-maintainers @kdudka diff --git a/renovate.json b/renovate.json index 62da82d92a..7191218b5b 100644 --- a/renovate.json +++ b/renovate.json @@ -80,6 +80,7 @@ { "groupName": "integration", "matchFileNames": [ + "stepactions/fips-operator-check-step-action/**", "task/clair-scan/**", "task/clamav-scan/**", "task/coverity-availability-check-oci-ta/**", @@ -87,6 +88,8 @@ "task/deprecated-image-check/**", "task/fbc-related-image-check/**", "task/fbc-validation/**", + "task/fips-operator-bundle-check-oci-ta/**", + "task/fips-operator-bundle-check/**", "task/inspect-image/**", "task/sast-coverity-check-oci-ta/**", "task/sast-coverity-check/**", diff --git a/stepactions/fips-operator-check-step-action/0.1/README.md b/stepactions/fips-operator-check-step-action/0.1/README.md new file mode 100644 index 0000000000..276f354775 --- /dev/null +++ b/stepactions/fips-operator-check-step-action/0.1/README.md @@ -0,0 +1,16 @@ +## fips-operator-check-step-action + +This stepAction scans relatedImages of operator bundle image builds for FIPS compliance using the check-payload tool. +* The relatedImages are expected to be in a file located at `/tekton/home/unique_related_images.txt`. +* If the check-payload scan is desired to be run with the built-in exception list, the target OCP version (`v4.x`) should be in a file located at `/tekton/home/target_ocp_version.txt`. +* It also supports replacing relatedImages pullspecs with their first mirror. In order to use that, a mapping like {"source_registry_and_repo": ["mirror_registry_and_repo"]} should be stored in a file located at `/tekton/home/related-images-map.txt` + +## Results: + +| name | description | +|--------------------|--------------------------------------| +| TEST_OUTPUT | Tekton task test output. | + + +## Additional links: +https://github.com/openshift/check-payload \ No newline at end of file diff --git a/stepactions/fips-operator-check-step-action/0.1/fips-operator-check-step-action.yaml b/stepactions/fips-operator-check-step-action/0.1/fips-operator-check-step-action.yaml new file mode 100644 index 0000000000..9468230ba9 --- /dev/null +++ b/stepactions/fips-operator-check-step-action/0.1/fips-operator-check-step-action.yaml @@ -0,0 +1,143 @@ +--- +apiVersion: tekton.dev/v1beta1 +kind: StepAction +metadata: + labels: + app.kubernetes.io/version: "0.1" + annotations: + tekton.dev/pipelines.minVersion: "0.12.1" + tekton.dev/tags: "konflux" + name: fips-operator-check-step-action +spec: + description: >- + This stepAction scans relatedImages of operator bundle image builds for FIPS compliance using the check-payload tool. + results: + - name: TEST_OUTPUT + description: Tekton task test output. + image: quay.io/redhat-appstudio/konflux-test:v1.4.10@sha256:a9c8deb7582ac15ce0f0df0c7c7f017c33d8f12113c7efa3ed6811fd65e4706f + securityContext: + capabilities: + add: + - SETFCAP + script: | + #!/usr/bin/env bash + set -euo pipefail + # shellcheck source=/dev/null + . /utils.sh + + success_counter=0 + warnings_counter=0 + error_counter=0 + failure_counter=0 + + if [ ! -e "/tekton/home/unique_related_images.txt" ]; then + echo "No relatedImages to process" + exit 0 + fi + + related_images=$(cat /tekton/home/unique_related_images.txt) + echo "Related images are : ${related_images}" + + # If target OCP version is found, use it to apply the exception list when running check-payload + check_payload_version="" + if [ -f "/tekton/home/target_ocp_version.txt" ]; then + version=$(cat "/tekton/home/target_ocp_version.txt") + check_payload_version="-V=${version}" + echo "Target OCP version found: ${check_payload_version}" + fi + + # Check if an image to mirror map is defined for unreleased images + image_mirror_map="" + if [ -f "/tekton/home/related-images-map.txt" ]; then + image_mirror_map=$(cat "/tekton/home/related-images-map.txt") + echo "Image Mirror Map found: ${image_mirror_map}" + fi + + for related_image in ${related_images}; do + echo "Processing related image : ${related_image}" + + # Replace original pullspec with mirror, if present + if [ -n "${image_mirror_map}" ]; then + reg_and_repo=$(echo "${related_image}" | sed -E 's/^([^:@]+).*$/\1/') + first_mirror=$(echo "$image_mirror_map" | jq -r --arg image "$reg_and_repo" '.[$image][0]') + if [ "$first_mirror" != "null" ]; then + replaced_image=$(replace_image_pullspec "$related_image" "$first_mirror") + echo "Replacing $related_image with $replaced_image" + related_image="$replaced_image" + fi + fi + + if ! image_labels=$(get_image_labels "${related_image}"); then + echo "Error: Could not inspect image ${related_image} for labels" + error_counter=$((error_counter + 1)) + continue + fi + component_label=$(echo "${image_labels}" | grep 'com.redhat.component=' | cut -d= -f2 || true) + echo "Component label is ${component_label}" + + if [ -z "${component_label}" ]; then + echo "Error: Could not get com.redhat.component label for ${related_image}" + error_counter=$((error_counter + 1)) + continue + fi + + # Convert image to OCI format since umoci can only handle the OCI format + if ! skopeo copy --remove-signatures "docker://${related_image}" "oci:///tekton/home/${component_label}:latest"; then + echo "Error: Could not convert image ${related_image} to OCI format" + error_counter=$((error_counter + 1)) + continue + fi + + # Unpack OCI image + if ! umoci raw unpack --rootless \ + --image "/tekton/home/${component_label}:latest" \ + "/tekton/home/unpacked-${component_label}"; then + echo "Error: Could not unpack OCI image ${related_image}" + error_counter=$((error_counter + 1)) + continue + fi + + # Run check-payload on the unpacked image + # The check-payload command fails with exit 1 when the scan for an image is unsuccessful + # or when the image is not FIPS compliant. Hence, count those as failures and not errors + if ! check-payload scan local \ + --path="/tekton/home/unpacked-${component_label}" \ + "${check_payload_version}" \ + --components="${component_label}" \ + --output-format=csv \ + --output-file="/tekton/home/report-${component_label}.csv"; then + echo "check-payload scan failed for ${related_image}" + failure_counter=$((failure_counter + 1)) + continue + fi + + if [ -f "/tekton/home/report-${component_label}.csv" ]; then + if grep -q -- "---- Successful run" "/tekton/home/report-${component_label}.csv"; then + echo "check-payload scan was successful for ${related_image}" + success_counter=$((success_counter + 1)) + elif grep -q -- "---- Successful run with warnings" "/tekton/home/report-${component_label}.csv"; then + echo "check-payload scan was successful with warnings for ${related_image}" + warnings_counter=$((warnings_counter + 1)) + fi + fi + + done + + note="Task $(context.task.name) failed: Some images could not be scanned. For details, check Tekton task log." + ERROR_OUTPUT=$(make_result_json -r ERROR -t "$note") + + note="Task $(context.task.name) completed: Check result for task result." + if [[ "$error_counter" == 0 ]]; + then + if [[ "${failure_counter}" -gt 0 ]]; then + RES="FAILURE" + elif [[ "${warnings_counter}" -gt 0 ]]; then + RES="WARNING" + else + RES="SUCCESS" + fi + TEST_OUTPUT=$(make_result_json \ + -r "${RES}" \ + -s "${success_counter}" -f "${failure_counter}" -w "${warnings_counter}" -t "$note") + fi + echo "${TEST_OUTPUT:-${ERROR_OUTPUT}}" | tee "$(step.results.TEST_OUTPUT.path)" diff --git a/task/fips-operator-bundle-check-oci-ta/0.1/README.md b/task/fips-operator-bundle-check-oci-ta/0.1/README.md new file mode 100644 index 0000000000..c78aaa91ae --- /dev/null +++ b/task/fips-operator-bundle-check-oci-ta/0.1/README.md @@ -0,0 +1,17 @@ +# fips-operator-bundle-check-oci-ta task + +The fips-operator-bundle-check task uses the check-payload tool to verify if an operator bundle image is FIPS compliant. It only scans operator bundle images which either claim to be FIPS compliant by setting the `features.operators.openshift.io/fips-compliant` label to `"true"` on the bundle image or require one of `OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform` subscriptions to run the operator on an Openshift cluster. This task extracts relatedImages from the operator bundle image and scans them. Hence, it is necessary for relatedImages pullspecs to be pullable at build time. In order to resolve them, this task expects a `imageDigestMirrorSet` file located at `.tekton/images-mirror-set.yaml` of your operator bundle git repo. It should map unreleased `registry.redhat.io` pullspecs of relatedImages to their valid `quay.io` pullspecs. + +## Parameters +|name|description|default value|required| +|---|---|---|---| +|SOURCE_ARTIFACT|The Trusted Artifact URI pointing to the artifact with the application source code.||true| +|image-digest|Image digest to scan.||true| +|image-url|Image URL.||true| + +## Results +|name|description| +|---|---| +|IMAGES_PROCESSED|Images processed in the task.| +|TEST_OUTPUT|Tekton task test output.| + diff --git a/task/fips-operator-bundle-check-oci-ta/0.1/fips-operator-bundle-check-oci-ta.yaml b/task/fips-operator-bundle-check-oci-ta/0.1/fips-operator-bundle-check-oci-ta.yaml new file mode 100644 index 0000000000..a59d06f845 --- /dev/null +++ b/task/fips-operator-bundle-check-oci-ta/0.1/fips-operator-bundle-check-oci-ta.yaml @@ -0,0 +1,173 @@ +--- +apiVersion: tekton.dev/v1 +kind: Task +metadata: + name: fips-operator-bundle-check-oci-ta + annotations: + tekton.dev/pipelines.minVersion: 0.12.1 + tekton.dev/tags: konflux + labels: + app.kubernetes.io/version: "0.1" +spec: + description: The fips-operator-bundle-check task uses the check-payload + tool to verify if an operator bundle image is FIPS compliant. It only + scans operator bundle images which either claim to be FIPS compliant by + setting the `features.operators.openshift.io/fips-compliant` label to + `"true"` on the bundle image or require one of `OpenShift Kubernetes Engine, + OpenShift Platform Plus or OpenShift Container Platform` subscriptions + to run the operator on an Openshift cluster. This task extracts relatedImages + from the operator bundle image and scans them. Hence, it is necessary + for relatedImages pullspecs to be pullable at build time. In order to + resolve them, this task expects a `imageDigestMirrorSet` file located + at `.tekton/images-mirror-set.yaml` of your operator bundle git repo. + It should map unreleased `registry.redhat.io` pullspecs of relatedImages + to their valid `quay.io` pullspecs. + params: + - name: SOURCE_ARTIFACT + description: The Trusted Artifact URI pointing to the artifact with + the application source code. + type: string + - name: image-digest + description: Image digest to scan. + - name: image-url + description: Image URL. + results: + - name: IMAGES_PROCESSED + description: Images processed in the task. + - name: TEST_OUTPUT + description: Tekton task test output. + value: $(steps.fips-operator-check-step-action.results.TEST_OUTPUT) + volumes: + - name: workdir + emptyDir: {} + stepTemplate: + volumeMounts: + - mountPath: /var/workdir + name: workdir + steps: + - name: use-trusted-artifact + image: quay.io/redhat-appstudio/build-trusted-artifacts:latest@sha256:b31dc501d5068e30621e51681a2921d4e43f5a030ab78c8991f83a5e774534a3 + args: + - use + - $(params.SOURCE_ARTIFACT)=/var/workdir/source + - name: get-unique-related-images + image: quay.io/redhat-appstudio/konflux-test:v1.4.10@sha256:a9c8deb7582ac15ce0f0df0c7c7f017c33d8f12113c7efa3ed6811fd65e4706f + env: + - name: IMAGE_URL + value: $(params.image-url) + - name: IMAGE_DIGEST + value: $(params.image-digest) + - name: SOURCE_CODE_DIR + value: /var/workdir + script: | + #!/usr/bin/env bash + set -euo pipefail + # shellcheck source=/dev/null + . /utils.sh + + image_without_tag=$(echo -n "${IMAGE_URL}" | sed "s/\(.*\):.*/\1/") + # strip new-line escape symbol from parameter and save it to variable + image_and_digest="${image_without_tag}@${IMAGE_DIGEST}" + + image_and_digest_labels=$(get_image_labels "${image_and_digest}") + if ! echo "${image_and_digest_labels}" | grep -q '^operators.operatorframework.io.bundle.mediatype.v1='; then + echo "The image $image_and_digest is not an operator bundle. Skipping FIPS static check..." + exit 0 + fi + + # Run the FIPS check only if the bundle is part of the Openshift Subscription or has the fips label set + image_and_digest_render_out=$(opm render "$image_and_digest") + subscription_label=$(echo "${image_and_digest_render_out}" | jq -r '.properties[] | select(.value.annotations["operators.openshift.io/valid-subscription"] != null) | (.value.annotations["operators.openshift.io/valid-subscription"] | fromjson)[]') + fips_label=$(echo "${image_and_digest_labels}" | grep '^features.operators.openshift.io/fips-compliant=' | cut -d= -f2 || true) + + if ! echo "${subscription_label}" | grep -e "OpenShift Kubernetes Engine" -e "OpenShift Container Platform" -e "OpenShift Platform Plus"; then + echo "OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform are not present in operators.openshift.io/valid-subscription." + echo "Subscription labels are : $subscription_label" + if [ -z "${fips_label}" ] || [ "${fips_label}" != "true" ]; then + echo "The label features.operators.openshift.io/fips-compliant is also not set to true. Skipping the FIPS static check..." + exit 0 + else + echo "The label features.operators.openshift.io/fips-compliant is set to true. Running the FIPS static check..." + fi + else + echo "OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform are present in operators.openshift.io/valid-subscription. Running the FIPS static check..." + fi + + mirror_set="${SOURCE_CODE_DIR}/source/.tekton/images-mirror-set.yaml" + if [[ -f "${mirror_set}" ]]; then + mirror_set_yaml=$(cat "${mirror_set}") + process_image_digest_mirror_set "${mirror_set_yaml}" >"/tekton/home/related-images-map.txt" + else + echo "Could not find Related Images mirror set at ${mirror_set}. Unreleased relatedImages will fail the scan." + fi + + unique_related_images=() + digests_processed=() + images_processed_template='{"image": {"pullspec": "'"$IMAGE_URL"'", "digests": [%s]}}' + + echo "Inspecting raw image manifest $image_and_digest." + # Get the arch and image manifests by inspecting the image. This is mainly for identifying image indexes + image_manifests=$(get_image_manifests -i "${image_and_digest}") + echo "Image manifests are $image_manifests" + + declare -A seen_related_images + # Extract relatedImages from the bundle image + while read -r _ arch_sha; do + digests_processed+=("\"$arch_sha\"") + manifest_related_images=$(extract_related_images_from_bundle "$image_without_tag@$arch_sha") + if [ -n "$manifest_related_images" ]; then + for img in $manifest_related_images; do + if [ -z "${seen_related_images["$img"]:-}" ]; then + unique_related_images+=("$img") + seen_related_images["$img"]=1 + fi + done + fi + done < <(echo "$image_manifests" | jq -r 'to_entries[] | "\(.key) \(.value)"') + + echo "Unique related images: ${unique_related_images[*]}" + echo "${unique_related_images[*]}" >/tekton/home/unique_related_images.txt + + # If the image is an Image Index, also add the Image Index digest to the list. + if [[ "${digests_processed[*]}" != *"$IMAGE_DIGEST"* ]]; then + digests_processed+=("\"$IMAGE_DIGEST\"") + fi + digests_processed_string=$( + IFS=, + echo "${digests_processed[*]}" + ) + + echo "${images_processed_template/\[%s]/[$digests_processed_string]}" >/tekton/home/images_processed.txt + computeResources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + securityContext: + capabilities: + add: + - SETFCAP + - name: fips-operator-check-step-action + computeResources: + limits: + cpu: 200m + memory: 512Mi + requests: + cpu: 100m + memory: 256Mi + ref: + name: fips-operator-check-step-action + - name: parse-images-processed-result + image: quay.io/redhat-appstudio/konflux-test:v1.4.10@sha256:a9c8deb7582ac15ce0f0df0c7c7f017c33d8f12113c7efa3ed6811fd65e4706f + script: | + #!/usr/bin/env bash + set -euo pipefail + + if [ -e "/tekton/home/images_processed.txt" ]; then + tee "$(results.IMAGES_PROCESSED.path)" - + The fips-operator-bundle-check task uses the check-payload tool to verify if an operator bundle image is FIPS compliant. + It only scans operator bundle images which either claim to be FIPS compliant by setting the `features.operators.openshift.io/fips-compliant` label to `"true"` on the bundle image or require one of `OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform` subscriptions to run the operator on an Openshift cluster. + This task extracts relatedImages from the operator bundle image and scans them. Hence, it is necessary for relatedImages pullspecs to be pullable at build time. In order to resolve them, this task expects a `imageDigestMirrorSet` file located at `.tekton/images-mirror-set.yaml` of your operator bundle git repo. It should map unreleased `registry.redhat.io` pullspecs of relatedImages to their valid `quay.io` pullspecs. + params: + - name: image-digest + description: Image digest to scan. + - name: image-url + description: Image URL. + results: + - name: TEST_OUTPUT + description: Tekton task test output. + value: $(steps.fips-operator-check-step-action.results.TEST_OUTPUT) + - name: IMAGES_PROCESSED + description: Images processed in the task. + steps: + - name: get-unique-related-images + image: quay.io/redhat-appstudio/konflux-test:v1.4.10@sha256:a9c8deb7582ac15ce0f0df0c7c7f017c33d8f12113c7efa3ed6811fd65e4706f + computeResources: + limits: + memory: 512Mi + cpu: 200m + requests: + memory: 256Mi + cpu: 100m + env: + - name: IMAGE_URL + value: $(params.image-url) + - name: IMAGE_DIGEST + value: $(params.image-digest) + - name: SOURCE_CODE_DIR + value: $(workspaces.workspace.path) + securityContext: + capabilities: + add: + - SETFCAP + script: | + #!/usr/bin/env bash + set -euo pipefail + # shellcheck source=/dev/null + . /utils.sh + + image_without_tag=$(echo -n "${IMAGE_URL}" | sed "s/\(.*\):.*/\1/") + # strip new-line escape symbol from parameter and save it to variable + image_and_digest="${image_without_tag}@${IMAGE_DIGEST}" + + image_and_digest_labels=$(get_image_labels "${image_and_digest}") + if ! echo "${image_and_digest_labels}" | grep -q '^operators.operatorframework.io.bundle.mediatype.v1='; then + echo "The image $image_and_digest is not an operator bundle. Skipping FIPS static check..." + exit 0 + fi + + # Run the FIPS check only if the bundle is part of the Openshift Subscription or has the fips label set + image_and_digest_render_out=$(opm render "$image_and_digest") + subscription_label=$(echo "${image_and_digest_render_out}" | jq -r '.properties[] | select(.value.annotations["operators.openshift.io/valid-subscription"] != null) | (.value.annotations["operators.openshift.io/valid-subscription"] | fromjson)[]') + fips_label=$(echo "${image_and_digest_labels}" | grep '^features.operators.openshift.io/fips-compliant=' | cut -d= -f2 || true) + + if ! echo "${subscription_label}" | grep -e "OpenShift Kubernetes Engine" -e "OpenShift Container Platform" -e "OpenShift Platform Plus"; then + echo "OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform are not present in operators.openshift.io/valid-subscription." + echo "Subscription labels are : $subscription_label" + if [ -z "${fips_label}" ] || [ "${fips_label}" != "true" ]; then + echo "The label features.operators.openshift.io/fips-compliant is also not set to true. Skipping the FIPS static check..." + exit 0 + else + echo "The label features.operators.openshift.io/fips-compliant is set to true. Running the FIPS static check..." + fi + else + echo "OpenShift Kubernetes Engine, OpenShift Platform Plus or OpenShift Container Platform are present in operators.openshift.io/valid-subscription. Running the FIPS static check..." + fi + + mirror_set="${SOURCE_CODE_DIR}/source/.tekton/images-mirror-set.yaml" + if [[ -f "${mirror_set}" ]]; then + mirror_set_yaml=$(cat "${mirror_set}") + process_image_digest_mirror_set "${mirror_set_yaml}" > "/tekton/home/related-images-map.txt" + else + echo "Could not find Related Images mirror set at ${mirror_set}. Unreleased relatedImages will fail the scan." + fi + + unique_related_images=() + digests_processed=() + images_processed_template='{"image": {"pullspec": "'"$IMAGE_URL"'", "digests": [%s]}}' + + echo "Inspecting raw image manifest $image_and_digest." + # Get the arch and image manifests by inspecting the image. This is mainly for identifying image indexes + image_manifests=$(get_image_manifests -i "${image_and_digest}") + echo "Image manifests are $image_manifests" + + declare -A seen_related_images + # Extract relatedImages from the bundle image + while read -r _ arch_sha; do + digests_processed+=("\"$arch_sha\"") + manifest_related_images=$(extract_related_images_from_bundle "$image_without_tag@$arch_sha") + if [ -n "$manifest_related_images" ]; then + for img in $manifest_related_images; do + if [ -z "${seen_related_images["$img"]:-}" ]; then + unique_related_images+=("$img") + seen_related_images["$img"]=1 + fi + done + fi + done < <(echo "$image_manifests" | jq -r 'to_entries[] | "\(.key) \(.value)"') + + echo "Unique related images: ${unique_related_images[*]}" + echo "${unique_related_images[*]}" > /tekton/home/unique_related_images.txt + + # If the image is an Image Index, also add the Image Index digest to the list. + if [[ "${digests_processed[*]}" != *"$IMAGE_DIGEST"* ]]; then + digests_processed+=("\"$IMAGE_DIGEST\"") + fi + digests_processed_string=$(IFS=,; echo "${digests_processed[*]}") + + echo "${images_processed_template/\[%s]/[$digests_processed_string]}" > /tekton/home/images_processed.txt + + - name: fips-operator-check-step-action + computeResources: + limits: + memory: 512Mi + cpu: 200m + requests: + memory: 256Mi + cpu: 100m + ref: + name: fips-operator-check-step-action + + - name: parse-images-processed-result + image: quay.io/redhat-appstudio/konflux-test:v1.4.10@sha256:a9c8deb7582ac15ce0f0df0c7c7f017c33d8f12113c7efa3ed6811fd65e4706f + script: | + #!/usr/bin/env bash + set -euo pipefail + + if [ -e "/tekton/home/images_processed.txt" ]; then + tee "$(results.IMAGES_PROCESSED.path)" < /tekton/home/images_processed.txt + else + echo "Task was skipped. Exiting" + exit 0 + fi + workspaces: + - name: workspace