From dd67b649f6dbbc54938ccfb645c60ace8502578f Mon Sep 17 00:00:00 2001 From: Xin Jiang Date: Thu, 26 Sep 2024 16:45:31 +0800 Subject: [PATCH] fix yamllint issues --- .github/workflows/build-definitions-sync.yaml | 2 +- .../kustomization.yaml | 1 - .../verify-enterprise-contract/patch.yaml | 21 +- .../docker-pull-request.yaml | 16 +- pac/docker-build-rhtap/docker-push.yaml | 16 +- pac/gitops-repo/gitops-on-pull-request.yaml | 38 +- pac/pipelines/gitops-pull-request-rhtap.yaml | 298 +++++----- pac/repository.yaml | 4 +- pac/source-repo/docker-pull-request.yaml | 16 +- pac/source-repo/docker-push.yaml | 16 +- pac/tasks/buildah-rhtap.yaml | 392 ++++++------- ...download-sbom-from-url-in-attestation.yaml | 324 +++++------ pac/tasks/gather-deploy-images.yaml | 84 +-- pac/tasks/git-clone.yaml | 530 +++++++++--------- pac/tasks/show-sbom-rhdh.yaml | 74 ++- pac/tasks/upload-sbom-to-trustification.yaml | 370 ++++++------ pac/tasks/verify-enterprise-contract.yaml | 340 +++++------ yamllint.yaml | 30 + 18 files changed, 1299 insertions(+), 1273 deletions(-) create mode 100644 yamllint.yaml diff --git a/.github/workflows/build-definitions-sync.yaml b/.github/workflows/build-definitions-sync.yaml index 1000d6e..c0b481b 100644 --- a/.github/workflows/build-definitions-sync.yaml +++ b/.github/workflows/build-definitions-sync.yaml @@ -2,7 +2,7 @@ name: Pull changes from build-definitions on: schedule: - - cron: "0 0 * * *" + - cron: "0 0 * * *" workflow_dispatch: permissions: diff --git a/hack/patches/tasks/verify-enterprise-contract/kustomization.yaml b/hack/patches/tasks/verify-enterprise-contract/kustomization.yaml index 0174b38..0306218 100644 --- a/hack/patches/tasks/verify-enterprise-contract/kustomization.yaml +++ b/hack/patches/tasks/verify-enterprise-contract/kustomization.yaml @@ -6,4 +6,3 @@ patches: - path: patch.yaml target: kind: Task - \ No newline at end of file diff --git a/hack/patches/tasks/verify-enterprise-contract/patch.yaml b/hack/patches/tasks/verify-enterprise-contract/patch.yaml index 5dc643c..44cd043 100644 --- a/hack/patches/tasks/verify-enterprise-contract/patch.yaml +++ b/hack/patches/tasks/verify-enterprise-contract/patch.yaml @@ -1,12 +1,9 @@ - - op: add - path: /spec/steps/- - value: - name: annotate-task - image: registry.redhat.io/openshift4/ose-cli:4.13@sha256:73df37794ffff7de1101016c23dc623e4990810390ebdabcbbfa065214352c7c - script: | - #!/usr/bin/env bash - echo "verify-enterprise-contract $(context.taskRun.name)" - oc annotate taskrun $(context.taskRun.name) task.results.format=application/json - oc annotate taskrun $(context.taskRun.name) task.results.type=ec - oc annotate taskrun $(context.taskRun.name) task.results.container=step-report-json - oc annotate taskrun $(context.taskRun.name) task.output.location=logs +- op: add + path: /spec/steps/- + value: + name: annotate-task + image: registry.redhat.io/openshift4/ose-cli:4.13@sha256:73df37794ffff7de1101016c23dc623e4990810390ebdabcbbfa065214352c7c + script: | + #!/usr/bin/env bash + echo "verify-enterprise-contract $(context.taskRun.name)" + oc annotate taskrun $(context.taskRun.name) task.results.format=application/json diff --git a/pac/docker-build-rhtap/docker-pull-request.yaml b/pac/docker-build-rhtap/docker-pull-request.yaml index 48584c9..953c23b 100644 --- a/pac/docker-build-rhtap/docker-pull-request.yaml +++ b/pac/docker-build-rhtap/docker-pull-request.yaml @@ -1,10 +1,10 @@ apiVersion: tekton.dev/v1 kind: PipelineRun metadata: - name: {{ values.name }}-on-pull-request + name: "{{values.name}}-on-pull-request" annotations: pipelinesascode.tekton.dev/on-event: "[pull_request]" - pipelinesascode.tekton.dev/on-target-branch: "[{{ values.defaultBranch }}]" + pipelinesascode.tekton.dev/on-target-branch: "[{{values.defaultBranch}}]" pipelinesascode.tekton.dev/max-keep-runs: "2" pipelinesascode.tekton.dev/pipeline: "{{values.rawUrl}}/pac/pipelines/docker-build-rhtap.yaml" pipelinesascode.tekton.dev/task-0: "{{values.rawUrl}}/pac/tasks/init.yaml" @@ -19,32 +19,32 @@ metadata: spec: params: - name: dockerfile - value: {{ values.dockerfile }} + value: {{values.dockerfile}} - name: git-url value: '{{repo_url}}' - name: image-expires-after value: 5d - name: output-image - value: {{ values.image }}:on-pr-{{revision}} + value: "{{values.image}}:on-pr-{{revision}}" - name: path-context - value: {{ values.buildContext }} + value: {{values.buildContext}} - name: revision value: '{{revision}}' - name: event-type value: '{{event_type}}' - name: gitops-auth-secret-name - value: {{ values.gitopsSecretName }} + value: {{values.gitopsSecretName}} pipelineRef: name: docker-build-rhtap workspaces: - name: git-auth secret: - secretName: "{{ git_auth_secret }}" + secretName: "{{git_auth_secret}}" - name: workspace volumeClaimTemplate: spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 1Gi diff --git a/pac/docker-build-rhtap/docker-push.yaml b/pac/docker-build-rhtap/docker-push.yaml index fa2a9c1..e3cefd1 100644 --- a/pac/docker-build-rhtap/docker-push.yaml +++ b/pac/docker-build-rhtap/docker-push.yaml @@ -1,10 +1,10 @@ apiVersion: tekton.dev/v1 kind: PipelineRun metadata: - name: {{ values.name }}-on-push + name: "{{values.name}}-on-push" annotations: pipelinesascode.tekton.dev/on-event: "[push]" - pipelinesascode.tekton.dev/on-target-branch: "[{{ values.defaultBranch }}]" + pipelinesascode.tekton.dev/on-target-branch: "[{{values.defaultBranch}}]" pipelinesascode.tekton.dev/max-keep-runs: "2" pipelinesascode.tekton.dev/pipeline: "{{values.rawUrl}}/pac/pipelines/docker-build-rhtap.yaml" pipelinesascode.tekton.dev/task-0: "{{values.rawUrl}}/pac/tasks/init.yaml" @@ -19,21 +19,21 @@ metadata: spec: params: - name: dockerfile - value: {{ values.dockerfile }} + value: {{values.dockerfile}} - name: git-url value: '{{repo_url}}' - name: image-expires-after value: 5d - name: output-image - value: {{ values.image }}:{{revision}} + value: "{{values.image}}:{{revision}}" - name: path-context - value: {{ values.buildContext }} + value: {{values.buildContext}} - name: revision value: '{{revision}}' - name: event-type value: '{{event_type}}' - name: gitops-auth-secret-name - value: {{ values.gitopsSecretName }} + value: {{values.gitopsSecretName}} pipelineRef: name: docker-build-rhtap workspaces: @@ -42,12 +42,12 @@ spec: secretName: $(params.gitops-auth-secret-name) - name: git-auth secret: - secretName: "{{ git_auth_secret }}" + secretName: "{{git_auth_secret}}" - name: workspace volumeClaimTemplate: spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 1Gi diff --git a/pac/gitops-repo/gitops-on-pull-request.yaml b/pac/gitops-repo/gitops-on-pull-request.yaml index 4b3ba97..76b3ed6 100644 --- a/pac/gitops-repo/gitops-on-pull-request.yaml +++ b/pac/gitops-repo/gitops-on-pull-request.yaml @@ -1,38 +1,42 @@ apiVersion: tekton.dev/v1 kind: PipelineRun metadata: - name: {{ values.name }}-gitops-on-pull-request + name: "{{values.name}}-gitops-on-pull-request" annotations: pipelinesascode.tekton.dev/on-event: "[pull_request]" - pipelinesascode.tekton.dev/on-target-branch: "[{{ values.defaultBranch }}]" + pipelinesascode.tekton.dev/on-target-branch: "[{{values.defaultBranch}}]" pipelinesascode.tekton.dev/pipeline: "{{values.rawUrl}}/pac/pipelines/gitops-pull-request-rhtap.yaml" pipelinesascode.tekton.dev/task-0: "{{values.rawUrl}}/pac/tasks/git-clone.yaml" pipelinesascode.tekton.dev/task-1: "{{values.rawUrl}}/pac/tasks/gather-deploy-images.yaml" - pipelinesascode.tekton.dev/task-2: "{{values.rawUrl}}/pac/tasks/verify-enterprise-contract.yaml" - pipelinesascode.tekton.dev/task-3: "{{values.rawUrl}}/pac/tasks/gather-deploy-images.yaml" - pipelinesascode.tekton.dev/task-4: "{{values.rawUrl}}/pac/tasks/download-sbom-from-url-in-attestation.yaml" - pipelinesascode.tekton.dev/task-5: "{{values.rawUrl}}/pac/tasks/upload-sbom-to-trustification.yaml" spec: params: - - name: git-url - value: '{{repo_url}}' - - name: revision - value: '{{revision}}' - - name: target-branch - value: '{{target_branch}}' - - name: fail-if-trustification-not-configured - value: 'false' + - name: dockerfile + value: {{values.dockerfile}} + - name: git-url + value: '{{repo_url}}' + - name: image-expires-after + value: 5d + - name: output-image + value: "{{values.image}}:on-pr-{{revision}}" + - name: path-context + value: {{values.buildContext}} + - name: revision + value: '{{revision}}' + - name: event-type + value: '{{event_type}}' + - name: gitops-auth-secret-name + value: {{values.gitopsSecretName}} pipelineRef: - name: gitops-pull-request + name: docker-build-rhtap workspaces: - name: git-auth secret: - secretName: "{{ git_auth_secret }}" + secretName: "{{git_auth_secret}}" - name: workspace volumeClaimTemplate: spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 1Gi diff --git a/pac/pipelines/gitops-pull-request-rhtap.yaml b/pac/pipelines/gitops-pull-request-rhtap.yaml index 565af89..1342481 100644 --- a/pac/pipelines/gitops-pull-request-rhtap.yaml +++ b/pac/pipelines/gitops-pull-request-rhtap.yaml @@ -4,153 +4,153 @@ metadata: name: gitops-pull-request spec: params: - - description: Gitops repo url - name: git-url - type: string - - default: "" - description: Gitops repo revision - name: revision - type: string - - default: main - description: The target branch for the pull request - name: target-branch - type: string - - default: github.com/enterprise-contract/config//default-v0.4 - description: Enterprise Contract policy to validate against - name: ec-policy-configuration - type: string - - default: "true" - description: Should EC violations cause the pipeline to fail? - name: ec-strict - type: string - - default: k8s://$(context.pipelineRun.namespace)/cosign-pub - description: The public key that EC should use to verify signatures - name: ec-public-key - type: string - - default: http://rekor-server.rhtap-tas.svc - description: The Rekor host that EC should use to look up transparency logs - name: ec-rekor-host - type: string - - default: http://tuf.rhtap-tas.svc - description: The TUF mirror that EC should use - name: ec-tuf-mirror - type: string - - default: tpa-secret - description: The name of the Secret that contains Trustification (TPA) configuration - name: trustification-secret-name - type: string - - default: "true" - description: Should the pipeline fail when there are SBOMs to upload but Trustification - is not properly configured (i.e. the secret is missing or doesn't have all the - required keys)? - name: fail-if-trustification-not-configured - type: string + - description: Gitops repo url + name: git-url + type: string + - default: "" + description: Gitops repo revision + name: revision + type: string + - default: main + description: The target branch for the pull request + name: target-branch + type: string + - default: github.com/enterprise-contract/config//default-v0.4 + description: Enterprise Contract policy to validate against + name: ec-policy-configuration + type: string + - default: "true" + description: Should EC violations cause the pipeline to fail? + name: ec-strict + type: string + - default: k8s://$(context.pipelineRun.namespace)/cosign-pub + description: The public key that EC should use to verify signatures + name: ec-public-key + type: string + - default: http://rekor-server.rhtap-tas.svc + description: The Rekor host that EC should use to look up transparency logs + name: ec-rekor-host + type: string + - default: http://tuf.rhtap-tas.svc + description: The TUF mirror that EC should use + name: ec-tuf-mirror + type: string + - default: tpa-secret + description: The name of the Secret that contains Trustification (TPA) configuration + name: trustification-secret-name + type: string + - default: "true" + description: Should the pipeline fail when there are SBOMs to upload but Trustification + is not properly configured (i.e. the secret is missing or doesn't have all the + required keys)? + name: fail-if-trustification-not-configured + type: string tasks: - - name: clone-repository - params: - - name: url - value: $(params.git-url) - - name: revision - value: $(params.revision) - - name: fetchTags - value: "true" - taskRef: - name: git-clone - workspaces: - - name: output - workspace: workspace - - name: basic-auth - workspace: git-auth - - name: get-images-to-verify - params: - - name: TARGET_BRANCH - value: $(params.target-branch) - runAfter: - - clone-repository - taskRef: - name: gather-deploy-images - workspaces: - - name: source - workspace: workspace - - name: verify-enteprise-contract - params: - - name: IMAGES - value: $(tasks.get-images-to-verify.results.IMAGES_TO_VERIFY) - - name: STRICT - value: $(params.ec-strict) - - name: POLICY_CONFIGURATION - value: $(params.ec-policy-configuration) - - name: PUBLIC_KEY - value: $(params.ec-public-key) - - name: REKOR_HOST - value: $(params.ec-rekor-host) - - name: TUF_MIRROR - value: $(params.ec-tuf-mirror) - runAfter: - - get-images-to-verify - taskRef: - name: verify-enterprise-contract - when: - - input: $(tasks.get-images-to-verify.results.IMAGES_TO_VERIFY) - operator: notin - values: - - "" - - name: get-images-to-upload-sbom - params: - - name: TARGET_BRANCH - value: $(params.target-branch) - - name: FROM_ENVIRONMENTS - value: - - stage - - prod - runAfter: - - clone-repository - taskRef: - name: gather-deploy-images - workspaces: - - name: source - workspace: workspace - - name: download-sboms - params: - - name: IMAGES - value: $(tasks.get-images-to-upload-sbom.results.IMAGES_TO_VERIFY) - - name: SBOMS_DIR - value: sboms - - name: PUBLIC_KEY - value: $(params.ec-public-key) - - name: REKOR_HOST - value: $(params.ec-rekor-host) - - name: TUF_MIRROR - value: $(params.ec-tuf-mirror) - runAfter: - - get-images-to-upload-sbom - taskRef: - name: download-sbom-from-url-in-attestation - when: - - input: $(tasks.get-images-to-upload-sbom.results.IMAGES_TO_VERIFY) - operator: notin - values: - - "" - workspaces: - - name: sboms - workspace: workspace - - name: upload-sboms-to-trustification - params: - - name: SBOMS_DIR - value: sboms - - name: TRUSTIFICATION_SECRET_NAME - value: $(params.trustification-secret-name) - - name: FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED - value: $(params.fail-if-trustification-not-configured) - runAfter: - - download-sboms - taskRef: - name: upload-sbom-to-trustification - when: - - input: $(tasks.get-images-to-upload-sbom.results.IMAGES_TO_VERIFY) - operator: notin - values: - - "" - workspaces: - - name: sboms - workspace: workspace + - name: clone-repository + params: + - name: url + value: $(params.git-url) + - name: revision + value: $(params.revision) + - name: fetchTags + value: "true" + taskRef: + name: git-clone + workspaces: + - name: output + workspace: workspace + - name: basic-auth + workspace: git-auth + - name: get-images-to-verify + params: + - name: TARGET_BRANCH + value: $(params.target-branch) + runAfter: + - clone-repository + taskRef: + name: gather-deploy-images + workspaces: + - name: source + workspace: workspace + - name: verify-enteprise-contract + params: + - name: IMAGES + value: $(tasks.get-images-to-verify.results.IMAGES_TO_VERIFY) + - name: STRICT + value: $(params.ec-strict) + - name: POLICY_CONFIGURATION + value: $(params.ec-policy-configuration) + - name: PUBLIC_KEY + value: $(params.ec-public-key) + - name: REKOR_HOST + value: $(params.ec-rekor-host) + - name: TUF_MIRROR + value: $(params.ec-tuf-mirror) + runAfter: + - get-images-to-verify + taskRef: + name: verify-enterprise-contract + when: + - input: $(tasks.get-images-to-verify.results.IMAGES_TO_VERIFY) + operator: notin + values: + - "" + - name: get-images-to-upload-sbom + params: + - name: TARGET_BRANCH + value: $(params.target-branch) + - name: FROM_ENVIRONMENTS + value: + - stage + - prod + runAfter: + - clone-repository + taskRef: + name: gather-deploy-images + workspaces: + - name: source + workspace: workspace + - name: download-sboms + params: + - name: IMAGES + value: $(tasks.get-images-to-upload-sbom.results.IMAGES_TO_VERIFY) + - name: SBOMS_DIR + value: sboms + - name: PUBLIC_KEY + value: $(params.ec-public-key) + - name: REKOR_HOST + value: $(params.ec-rekor-host) + - name: TUF_MIRROR + value: $(params.ec-tuf-mirror) + runAfter: + - get-images-to-upload-sbom + taskRef: + name: download-sbom-from-url-in-attestation + when: + - input: $(tasks.get-images-to-upload-sbom.results.IMAGES_TO_VERIFY) + operator: notin + values: + - "" + workspaces: + - name: sboms + workspace: workspace + - name: upload-sboms-to-trustification + params: + - name: SBOMS_DIR + value: sboms + - name: TRUSTIFICATION_SECRET_NAME + value: $(params.trustification-secret-name) + - name: FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED + value: $(params.fail-if-trustification-not-configured) + runAfter: + - download-sboms + taskRef: + name: upload-sbom-to-trustification + when: + - input: $(tasks.get-images-to-upload-sbom.results.IMAGES_TO_VERIFY) + operator: notin + values: + - "" + workspaces: + - name: sboms + workspace: workspace diff --git a/pac/repository.yaml b/pac/repository.yaml index 5449abb..023e8fc 100644 --- a/pac/repository.yaml +++ b/pac/repository.yaml @@ -1,8 +1,6 @@ apiVersion: "pipelinesascode.tekton.dev/v1alpha1" kind: Repository metadata: - name: {{values.name}} + name: {{values.name}} spec: url: {{values.repoURL}} - - \ No newline at end of file diff --git a/pac/source-repo/docker-pull-request.yaml b/pac/source-repo/docker-pull-request.yaml index 48584c9..953c23b 100644 --- a/pac/source-repo/docker-pull-request.yaml +++ b/pac/source-repo/docker-pull-request.yaml @@ -1,10 +1,10 @@ apiVersion: tekton.dev/v1 kind: PipelineRun metadata: - name: {{ values.name }}-on-pull-request + name: "{{values.name}}-on-pull-request" annotations: pipelinesascode.tekton.dev/on-event: "[pull_request]" - pipelinesascode.tekton.dev/on-target-branch: "[{{ values.defaultBranch }}]" + pipelinesascode.tekton.dev/on-target-branch: "[{{values.defaultBranch}}]" pipelinesascode.tekton.dev/max-keep-runs: "2" pipelinesascode.tekton.dev/pipeline: "{{values.rawUrl}}/pac/pipelines/docker-build-rhtap.yaml" pipelinesascode.tekton.dev/task-0: "{{values.rawUrl}}/pac/tasks/init.yaml" @@ -19,32 +19,32 @@ metadata: spec: params: - name: dockerfile - value: {{ values.dockerfile }} + value: {{values.dockerfile}} - name: git-url value: '{{repo_url}}' - name: image-expires-after value: 5d - name: output-image - value: {{ values.image }}:on-pr-{{revision}} + value: "{{values.image}}:on-pr-{{revision}}" - name: path-context - value: {{ values.buildContext }} + value: {{values.buildContext}} - name: revision value: '{{revision}}' - name: event-type value: '{{event_type}}' - name: gitops-auth-secret-name - value: {{ values.gitopsSecretName }} + value: {{values.gitopsSecretName}} pipelineRef: name: docker-build-rhtap workspaces: - name: git-auth secret: - secretName: "{{ git_auth_secret }}" + secretName: "{{git_auth_secret}}" - name: workspace volumeClaimTemplate: spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 1Gi diff --git a/pac/source-repo/docker-push.yaml b/pac/source-repo/docker-push.yaml index fa2a9c1..e3cefd1 100644 --- a/pac/source-repo/docker-push.yaml +++ b/pac/source-repo/docker-push.yaml @@ -1,10 +1,10 @@ apiVersion: tekton.dev/v1 kind: PipelineRun metadata: - name: {{ values.name }}-on-push + name: "{{values.name}}-on-push" annotations: pipelinesascode.tekton.dev/on-event: "[push]" - pipelinesascode.tekton.dev/on-target-branch: "[{{ values.defaultBranch }}]" + pipelinesascode.tekton.dev/on-target-branch: "[{{values.defaultBranch}}]" pipelinesascode.tekton.dev/max-keep-runs: "2" pipelinesascode.tekton.dev/pipeline: "{{values.rawUrl}}/pac/pipelines/docker-build-rhtap.yaml" pipelinesascode.tekton.dev/task-0: "{{values.rawUrl}}/pac/tasks/init.yaml" @@ -19,21 +19,21 @@ metadata: spec: params: - name: dockerfile - value: {{ values.dockerfile }} + value: {{values.dockerfile}} - name: git-url value: '{{repo_url}}' - name: image-expires-after value: 5d - name: output-image - value: {{ values.image }}:{{revision}} + value: "{{values.image}}:{{revision}}" - name: path-context - value: {{ values.buildContext }} + value: {{values.buildContext}} - name: revision value: '{{revision}}' - name: event-type value: '{{event_type}}' - name: gitops-auth-secret-name - value: {{ values.gitopsSecretName }} + value: {{values.gitopsSecretName}} pipelineRef: name: docker-build-rhtap workspaces: @@ -42,12 +42,12 @@ spec: secretName: $(params.gitops-auth-secret-name) - name: git-auth secret: - secretName: "{{ git_auth_secret }}" + secretName: "{{git_auth_secret}}" - name: workspace volumeClaimTemplate: spec: accessModes: - - ReadWriteOnce + - ReadWriteOnce resources: requests: storage: 1Gi diff --git a/pac/tasks/buildah-rhtap.yaml b/pac/tasks/buildah-rhtap.yaml index 218bbca..dd25678 100644 --- a/pac/tasks/buildah-rhtap.yaml +++ b/pac/tasks/buildah-rhtap.yaml @@ -13,218 +13,218 @@ spec: Buildah task builds source code into a container image and pushes the image into container registry using buildah tool. In addition it generates a SBOM file, injects the SBOM file into final container image and pushes the SBOM file as separate image using cosign tool. params: - - description: Reference of the image buildah will produce. - name: IMAGE - type: string - - default: ./Dockerfile - description: Path to the Dockerfile to build. - name: DOCKERFILE - type: string - - default: . - description: Path to the directory to use as context. - name: CONTEXT - type: string - - default: "true" - description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry) - name: TLSVERIFY - type: string - - name: BUILD_ARGS - description: Array of --build-arg values ("arg=value" strings) - type: array - default: [] - - name: BUILD_ARGS_FILE - description: Path to a file with build arguments, see https://www.mankier.com/1/buildah-build#--build-arg-file - type: string - default: "" - - name: STORAGE_DRIVER - description: Storage driver to configure for buildah - type: string - default: vfs + - description: Reference of the image buildah will produce. + name: IMAGE + type: string + - default: ./Dockerfile + description: Path to the Dockerfile to build. + name: DOCKERFILE + type: string + - default: . + description: Path to the directory to use as context. + name: CONTEXT + type: string + - default: "true" + description: Verify the TLS on the registry endpoint (for push/pull to a non-TLS registry) + name: TLSVERIFY + type: string + - name: BUILD_ARGS + description: Array of --build-arg values ("arg=value" strings) + type: array + default: [] + - name: BUILD_ARGS_FILE + description: Path to a file with build arguments, see https://www.mankier.com/1/buildah-build#--build-arg-file + type: string + default: "" + - name: STORAGE_DRIVER + description: Storage driver to configure for buildah + type: string + default: vfs results: - - description: Digest of the image just built - name: IMAGE_DIGEST - - description: Image repository and tag where the built image was pushed - name: IMAGE_URL - - description: Digests of the base images used for build - name: BASE_IMAGES_DIGESTS - - description: Link to the SBOM layer pushed to the registry as part of an OCI artifact. - name: SBOM_BLOB_URL + - description: Digest of the image just built + name: IMAGE_DIGEST + - description: Image repository and tag where the built image was pushed + name: IMAGE_URL + - description: Digests of the base images used for build + name: BASE_IMAGES_DIGESTS + - description: Link to the SBOM layer pushed to the registry as part of an OCI artifact. + name: SBOM_BLOB_URL stepTemplate: env: - - name: STORAGE_DRIVER - value: $(params.STORAGE_DRIVER) - - name: CONTEXT - value: $(params.CONTEXT) - - name: DOCKERFILE - value: $(params.DOCKERFILE) - - name: IMAGE - value: $(params.IMAGE) - - name: TLSVERIFY - value: $(params.TLSVERIFY) - - name: BUILD_ARGS_FILE - value: $(params.BUILD_ARGS_FILE) + - name: STORAGE_DRIVER + value: $(params.STORAGE_DRIVER) + - name: CONTEXT + value: $(params.CONTEXT) + - name: DOCKERFILE + value: $(params.DOCKERFILE) + - name: IMAGE + value: $(params.IMAGE) + - name: TLSVERIFY + value: $(params.TLSVERIFY) + - name: BUILD_ARGS_FILE + value: $(params.BUILD_ARGS_FILE) steps: - - name: build - image: registry.access.redhat.com/ubi9/buildah@sha256:29402688af2b394a8400d946751520dbaea64759bbce2ef6928dc58ede6020e6 - args: - - $(params.BUILD_ARGS[*]) - script: | - # Check if the Dockerfile exists - SOURCE_CODE_DIR=source - if [ -e "$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" ]; then - dockerfile_path="$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" - elif [ -e "$SOURCE_CODE_DIR/$DOCKERFILE" ]; then - dockerfile_path="$SOURCE_CODE_DIR/$DOCKERFILE" - else - echo "Cannot find Dockerfile $DOCKERFILE" - exit 1 - fi - - BUILDAH_ARGS=() - if [ -n "${BUILD_ARGS_FILE}" ]; then - BUILDAH_ARGS+=("--build-arg-file=${SOURCE_CODE_DIR}/${BUILD_ARGS_FILE}") - fi - - for build_arg in "$@"; do - BUILDAH_ARGS+=("--build-arg=$build_arg") - done - - # Build the image - buildah build \ - "${BUILDAH_ARGS[@]}" \ - --tls-verify=$TLSVERIFY \ - --ulimit nofile=4096:4096 \ - -f "$dockerfile_path" -t $IMAGE $SOURCE_CODE_DIR/$CONTEXT - - # Push the image - buildah push \ - --tls-verify=$TLSVERIFY \ - --retry=5 \ - --digestfile /tmp/files/image-digest $IMAGE \ - docker://$IMAGE - - # Set task results - buildah images --format '{{ .Name }}:{{ .Tag }}@{{ .Digest }}' | grep -v $IMAGE > $(results.BASE_IMAGES_DIGESTS.path) - cat /tmp/files/image-digest | tee $(results.IMAGE_DIGEST.path) - echo -n "$IMAGE" | tee $(results.IMAGE_URL.path) - - # Save the image so it can be used in the generate-sbom step - buildah push "$IMAGE" oci:/tmp/files/image - securityContext: - capabilities: - add: - # this is needed so that buildah can write to the mounted /var/lib/containers directory - - SETFCAP - volumeMounts: - - mountPath: /var/lib/containers - name: varlibcontainers - - mountPath: /tmp/files - name: tmpfiles - workingDir: $(workspaces.source.path) - - - name: generate-sboms - image: registry.redhat.io/rh-syft-tech-preview/syft-rhel9:1.0.1@sha256:27c268d678103a27b6964c2cd5169040941b7304d0078f9727789ffb8ffba370 - # Respect Syft configuration if the user has it in the root of their repository - # (need to set the workdir, see https://github.com/anchore/syft/issues/2465) - workingDir: $(workspaces.source.path)/source - script: | - syft dir:$(workspaces.source.path)/source --output cyclonedx-json@1.5=/tmp/files/sbom-source.json - syft oci-dir:/tmp/files/image --output cyclonedx-json@1.5=/tmp/files/sbom-image.json - volumeMounts: - - mountPath: /var/lib/containers - name: varlibcontainers - - mountPath: /tmp/files - name: tmpfiles - - - name: merge-sboms - image: registry.access.redhat.com/ubi8/python-311@sha256:6cc79822da3610cb30e5fa1f5afebe2b36c69db3f03841638139a54b3c307e42 - env: - - name: RESULT_PATH - value: $(results.SBOM_BLOB_URL.path) - script: | - #!/bin/python3 - import hashlib - import json - import os - import re - - ### load SBOMs ### - - with open("./sbom-image.json") as f: - image_sbom = json.load(f) - - with open("./sbom-source.json") as f: - source_sbom = json.load(f) - - - ### attempt to deduplicate components ### - - component_list = image_sbom.get("components", []) - existing_purls = [c["purl"] for c in component_list if "purl" in c] - - for component in source_sbom.get("components", []): - if "purl" in component: - if component["purl"] not in existing_purls: + - name: build + image: registry.access.redhat.com/ubi9/buildah@sha256:29402688af2b394a8400d946751520dbaea64759bbce2ef6928dc58ede6020e6 + args: + - $(params.BUILD_ARGS[*]) + script: | + # Check if the Dockerfile exists + SOURCE_CODE_DIR=source + if [ -e "$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" ]; then + dockerfile_path="$SOURCE_CODE_DIR/$CONTEXT/$DOCKERFILE" + elif [ -e "$SOURCE_CODE_DIR/$DOCKERFILE" ]; then + dockerfile_path="$SOURCE_CODE_DIR/$DOCKERFILE" + else + echo "Cannot find Dockerfile $DOCKERFILE" + exit 1 + fi + + BUILDAH_ARGS=() + if [ -n "${BUILD_ARGS_FILE}" ]; then + BUILDAH_ARGS+=("--build-arg-file=${SOURCE_CODE_DIR}/${BUILD_ARGS_FILE}") + fi + + for build_arg in "$@"; do + BUILDAH_ARGS+=("--build-arg=$build_arg") + done + + # Build the image + buildah build \ + "${BUILDAH_ARGS[@]}" \ + --tls-verify=$TLSVERIFY \ + --ulimit nofile=4096:4096 \ + -f "$dockerfile_path" -t $IMAGE $SOURCE_CODE_DIR/$CONTEXT + + # Push the image + buildah push \ + --tls-verify=$TLSVERIFY \ + --retry=5 \ + --digestfile /tmp/files/image-digest $IMAGE \ + docker://$IMAGE + + # Set task results + buildah images --format '{{ .Name }}:{{ .Tag }}@{{ .Digest }}' | grep -v $IMAGE > $(results.BASE_IMAGES_DIGESTS.path) + cat /tmp/files/image-digest | tee $(results.IMAGE_DIGEST.path) + echo -n "$IMAGE" | tee $(results.IMAGE_URL.path) + + # Save the image so it can be used in the generate-sbom step + buildah push "$IMAGE" oci:/tmp/files/image + securityContext: + capabilities: + add: + # this is needed so that buildah can write to the mounted /var/lib/containers directory + - SETFCAP + volumeMounts: + - mountPath: /var/lib/containers + name: varlibcontainers + - mountPath: /tmp/files + name: tmpfiles + workingDir: $(workspaces.source.path) + + - name: generate-sboms + image: registry.redhat.io/rh-syft-tech-preview/syft-rhel9:1.0.1@sha256:27c268d678103a27b6964c2cd5169040941b7304d0078f9727789ffb8ffba370 + # Respect Syft configuration if the user has it in the root of their repository + # (need to set the workdir, see https://github.com/anchore/syft/issues/2465) + workingDir: $(workspaces.source.path)/source + script: | + syft dir:$(workspaces.source.path)/source --output cyclonedx-json@1.5=/tmp/files/sbom-source.json + syft oci-dir:/tmp/files/image --output cyclonedx-json@1.5=/tmp/files/sbom-image.json + volumeMounts: + - mountPath: /var/lib/containers + name: varlibcontainers + - mountPath: /tmp/files + name: tmpfiles + + - name: merge-sboms + image: registry.access.redhat.com/ubi8/python-311@sha256:6cc79822da3610cb30e5fa1f5afebe2b36c69db3f03841638139a54b3c307e42 + env: + - name: RESULT_PATH + value: $(results.SBOM_BLOB_URL.path) + script: | + #!/bin/python3 + import hashlib + import json + import os + import re + + ### load SBOMs ### + + with open("./sbom-image.json") as f: + image_sbom = json.load(f) + + with open("./sbom-source.json") as f: + source_sbom = json.load(f) + + + ### attempt to deduplicate components ### + + component_list = image_sbom.get("components", []) + existing_purls = [c["purl"] for c in component_list if "purl" in c] + + for component in source_sbom.get("components", []): + if "purl" in component: + if component["purl"] not in existing_purls: + component_list.append(component) + existing_purls.append(component["purl"]) + else: + # We won't try to deduplicate components that lack a purl. + # This should only happen with operating-system type components, + # which are only reported in the image SBOM. component_list.append(component) - existing_purls.append(component["purl"]) - else: - # We won't try to deduplicate components that lack a purl. - # This should only happen with operating-system type components, - # which are only reported in the image SBOM. - component_list.append(component) - component_list.sort(key=lambda c: c["type"] + c["name"]) - image_sbom["components"] = component_list + component_list.sort(key=lambda c: c["type"] + c["name"]) + image_sbom["components"] = component_list - ### write the CycloneDX unified SBOM ### + ### write the CycloneDX unified SBOM ### - with open("./sbom-cyclonedx.json", "w") as f: - json.dump(image_sbom, f, indent=4) + with open("./sbom-cyclonedx.json", "w") as f: + json.dump(image_sbom, f, indent=4) - ### write the SBOM blob URL result ### + ### write the SBOM blob URL result ### - with open("./sbom-cyclonedx.json", "rb") as f: - sbom_digest = hashlib.file_digest(f, "sha256").hexdigest() + with open("./sbom-cyclonedx.json", "rb") as f: + sbom_digest = hashlib.file_digest(f, "sha256").hexdigest() - # https://github.com/opencontainers/distribution-spec/blob/main/spec.md?plain=1#L160 - tag_regex = "[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}" + # https://github.com/opencontainers/distribution-spec/blob/main/spec.md?plain=1#L160 + tag_regex = "[a-zA-Z0-9_][a-zA-Z0-9._-]{0,127}" - # the tag must be after a colon, but always at the end of the string - # this avoids conflict with port numbers - image_without_tag = re.sub(f":{tag_regex}$", "", os.getenv("IMAGE")) + # the tag must be after a colon, but always at the end of the string + # this avoids conflict with port numbers + image_without_tag = re.sub(f":{tag_regex}$", "", os.getenv("IMAGE")) - sbom_blob_url = f"{image_without_tag}@sha256:{sbom_digest}" + sbom_blob_url = f"{image_without_tag}@sha256:{sbom_digest}" - with open(os.getenv("RESULT_PATH"), "w") as f: - f.write(sbom_blob_url) - volumeMounts: - - mountPath: /tmp/files - name: tmpfiles - workingDir: /tmp/files - - - name: upload-sbom - image: registry.redhat.io/rhtas-tech-preview/cosign-rhel9:0.0.2@sha256:151f4a1e721b644bafe47bf5bfb8844ff27b95ca098cc37f3f6cbedcda79a897 - command: [cosign] - args: - - attach - - sbom - - --sbom - - sbom-cyclonedx.json - - --type - - cyclonedx - - $(params.IMAGE) - volumeMounts: - - mountPath: /tmp/files - name: tmpfiles - workingDir: /tmp/files + with open(os.getenv("RESULT_PATH"), "w") as f: + f.write(sbom_blob_url) + volumeMounts: + - mountPath: /tmp/files + name: tmpfiles + workingDir: /tmp/files + + - name: upload-sbom + image: registry.redhat.io/rhtas-tech-preview/cosign-rhel9:0.0.2@sha256:151f4a1e721b644bafe47bf5bfb8844ff27b95ca098cc37f3f6cbedcda79a897 + command: [cosign] + args: + - attach + - sbom + - --sbom + - sbom-cyclonedx.json + - --type + - cyclonedx + - $(params.IMAGE) + volumeMounts: + - mountPath: /tmp/files + name: tmpfiles + workingDir: /tmp/files volumes: - - emptyDir: {} - name: varlibcontainers - - emptyDir: {} - name: tmpfiles + - emptyDir: {} + name: varlibcontainers + - emptyDir: {} + name: tmpfiles workspaces: - - name: source - description: Workspace containing the source code to build. + - name: source + description: Workspace containing the source code to build. diff --git a/pac/tasks/download-sbom-from-url-in-attestation.yaml b/pac/tasks/download-sbom-from-url-in-attestation.yaml index ff87acd..c33550a 100644 --- a/pac/tasks/download-sbom-from-url-in-attestation.yaml +++ b/pac/tasks/download-sbom-from-url-in-attestation.yaml @@ -32,110 +32,110 @@ spec: [gather-deploy-images]: https://github.com/redhat-appstudio/build-definitions/tree/main/task/gather-deploy-images params: - - name: IMAGES - description: >- - JSON object containing the array of images whose SBOMs should be downloaded. - See the description for more details. - type: string - - - name: SBOMS_DIR - default: "." - description: >- - Path to directory (relative to the 'sboms' workspace) where SBOMs should be downloaded. - type: string - - - name: HTTP_RETRIES - default: "3" - description: "Maximum number of retries for transient HTTP(S) errors" - type: string - - - name: PUBLIC_KEY - type: string - description: >- - 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. - default: "" - - - name: REKOR_HOST - type: string - description: Rekor host for transparency log lookups - default: "" - - - name: IGNORE_REKOR - type: string - description: >- - Skip Rekor transparency log checks during validation. - default: "false" - - - name: TUF_MIRROR - type: string - description: TUF mirror URL. Provide a value when NOT using public sigstore deployment. - default: "" - workspaces: - - name: sboms - description: SBOMs will be downloaded to (a subdirectory of) this workspace. - stepTemplate: - env: - name: IMAGES - value: $(params.IMAGES) + description: >- + JSON object containing the array of images whose SBOMs should be downloaded. + See the description for more details. + type: string + - name: SBOMS_DIR - value: $(workspaces.sboms.path)/$(params.SBOMS_DIR) + default: "." + description: >- + Path to directory (relative to the 'sboms' workspace) where SBOMs should be downloaded. + type: string + - name: HTTP_RETRIES - value: $(params.HTTP_RETRIES) + default: "3" + description: "Maximum number of retries for transient HTTP(S) errors" + type: string + - name: PUBLIC_KEY - value: $(params.PUBLIC_KEY) + type: string + description: >- + 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. + default: "" + - name: REKOR_HOST - value: $(params.REKOR_HOST) + type: string + description: Rekor host for transparency log lookups + default: "" + - name: IGNORE_REKOR - value: $(params.IGNORE_REKOR) + type: string + description: >- + Skip Rekor transparency log checks during validation. + default: "false" + - name: TUF_MIRROR - value: $(params.TUF_MIRROR) - - name: WORKDIR - value: /tekton/home + type: string + description: TUF mirror URL. Provide a value when NOT using public sigstore deployment. + default: "" + workspaces: + - name: sboms + description: SBOMs will be downloaded to (a subdirectory of) this workspace. + stepTemplate: + env: + - name: IMAGES + value: $(params.IMAGES) + - name: SBOMS_DIR + value: $(workspaces.sboms.path)/$(params.SBOMS_DIR) + - name: HTTP_RETRIES + value: $(params.HTTP_RETRIES) + - name: PUBLIC_KEY + value: $(params.PUBLIC_KEY) + - name: REKOR_HOST + value: $(params.REKOR_HOST) + - name: IGNORE_REKOR + value: $(params.IGNORE_REKOR) + - name: TUF_MIRROR + value: $(params.TUF_MIRROR) + - name: WORKDIR + value: /tekton/home steps: - - name: download-attestations - image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 - script: | - #!/usr/bin/env bash - set -o errexit -o nounset -o pipefail - - if [[ -z "$PUBLIC_KEY" ]]; then - echo "No public key set, cannot verify attestation." >&2 - exit 1 - fi - - cosign_args=(--key "$PUBLIC_KEY") - - if [[ -n "$REKOR_HOST" ]]; then - cosign_args+=(--rekor-url "$REKOR_HOST") - elif [[ "$IGNORE_REKOR" = "true" ]]; then - cosign_args+=(--insecure-ignore-tlog) - else - cosign_args+=() - fi - - if [[ -n "${TUF_MIRROR:-}" ]]; then - echo 'Initializing TUF root...' - cosign initialize --mirror "${TUF_MIRROR}" --root "${TUF_MIRROR}/root.json" - fi - - jq -r '.components[].containerImage' <<< "$IMAGES" | while read -r image; do - echo "Getting attestation for $image" - mkdir -p "$WORKDIR/$image" - cosign verify-attestation \ - --type slsaprovenance \ - "${cosign_args[@]}" \ - "$image" > "$WORKDIR/$image/attestation.json" - done - - - name: download-sboms - image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 - script: | - #!/usr/bin/env bash - set -o errexit -o nounset -o pipefail - - get_from_www_auth_header() { + - name: download-attestations + image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 + script: | + #!/usr/bin/env bash + set -o errexit -o nounset -o pipefail + + if [[ -z "$PUBLIC_KEY" ]]; then + echo "No public key set, cannot verify attestation." >&2 + exit 1 + fi + + cosign_args=(--key "$PUBLIC_KEY") + + if [[ -n "$REKOR_HOST" ]]; then + cosign_args+=(--rekor-url "$REKOR_HOST") + elif [[ "$IGNORE_REKOR" = "true" ]]; then + cosign_args+=(--insecure-ignore-tlog) + else + cosign_args+=() + fi + + if [[ -n "${TUF_MIRROR:-}" ]]; then + echo 'Initializing TUF root...' + cosign initialize --mirror "${TUF_MIRROR}" --root "${TUF_MIRROR}/root.json" + fi + + jq -r '.components[].containerImage' <<< "$IMAGES" | while read -r image; do + echo "Getting attestation for $image" + mkdir -p "$WORKDIR/$image" + cosign verify-attestation \ + --type slsaprovenance \ + "${cosign_args[@]}" \ + "$image" > "$WORKDIR/$image/attestation.json" + done + + - name: download-sboms + image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 + script: | + #!/usr/bin/env bash + set -o errexit -o nounset -o pipefail + + get_from_www_auth_header() { local www_authenticate=$1 local key=$2 # shellcheck disable=SC2001 @@ -144,9 +144,9 @@ spec: # key=service # -> ghcr.io sed "s/.*$key=\"\([^\"]*\)\".*/\1/" <<< "$www_authenticate" - } + } - get_container_auth() { + get_container_auth() { # https://man.archlinux.org/man/containers-auth.json.5 local image=$1 @@ -154,80 +154,80 @@ spec: local runtime_dir="${XDG_RUNTIME_DIR:-}" local config_home="${XDG_CONFIG_HOME:-$HOME/.config}" if [[ -n "$runtime_dir" ]]; then - default_authfile="${runtime_dir}/containers/auth.json" + default_authfile="${runtime_dir}/containers/auth.json" else - default_authfile="$config_home/containers/auth.json" + default_authfile="$config_home/containers/auth.json" fi local maybe_auth_files=( - "$default_authfile" - "$config_home/containers/auth.json" - "$HOME/.docker/config.json" - "$HOME/.dockercfg" + "$default_authfile" + "$config_home/containers/auth.json" + "$HOME/.docker/config.json" + "$HOME/.dockercfg" ) local auth_files=() for file in "${maybe_auth_files[@]}"; do - if [[ -r "$file" ]]; then - auth_files+=("$file") - fi + if [[ -r "$file" ]]; then + auth_files+=("$file") + fi done # registry.com/namespace/repo@sha256:digest -> registry.com/namespace/repo local auth_key=${image%@*} while true; do - for auth_file in "${auth_files[@]}"; do - if jq -r -e --arg key "$auth_key" '.auths[$key].auth // empty' "$auth_file"; then - echo "Found auth for $auth_key in $auth_file" >&2 - return 0 - fi - done - - # Try less specific key, e.g. registry.com/namespace/repo -> registry.com/namespace - local new_key=${auth_key%/*} - if [[ "$new_key" = "$auth_key" ]]; then - # Already tried all possible keys, no auth found - echo "No auth found for $auth_key" >&2 - return 1 + for auth_file in "${auth_files[@]}"; do + if jq -r -e --arg key "$auth_key" '.auths[$key].auth // empty' "$auth_file"; then + echo "Found auth for $auth_key in $auth_file" >&2 + return 0 fi + done + + # Try less specific key, e.g. registry.com/namespace/repo -> registry.com/namespace + local new_key=${auth_key%/*} + if [[ "$new_key" = "$auth_key" ]]; then + # Already tried all possible keys, no auth found + echo "No auth found for $auth_key" >&2 + return 1 + fi - auth_key=$new_key + auth_key=$new_key done - } + } - download_blob() { - local blob_ref=$1 - local dest=$2 + download_blob() { + local blob_ref=$1 + local dest=$2 - # convert: - # registry.com/namespace/repo@sha256:digest - # -> https://registry.com/v2/namespace/repo/blobs/sha256:digest - blob_url=$(sed -E 's;([^/]*)/(.*)@(.*);https://\1/v2/\2/blobs/\3;' <<< "$blob_ref") + # convert: + # registry.com/namespace/repo@sha256:digest + # -> https://registry.com/v2/namespace/repo/blobs/sha256:digest + blob_url=$(sed -E 's;([^/]*)/(.*)@(.*);https://\1/v2/\2/blobs/\3;' <<< "$blob_ref") - local tmp_dest - tmp_dest=$(mktemp --tmpdir download-sbom-task.out.XXXXXX) + local tmp_dest + tmp_dest=$(mktemp --tmpdir download-sbom-task.out.XXXXXX) - local headers_file - headers_file=$(mktemp --tmpdir download-sbom-task.headers.XXXXXX) + local headers_file + headers_file=$(mktemp --tmpdir download-sbom-task.headers.XXXXXX) - local common_curl_opts=(--silent --show-error --retry "${HTTP_RETRIES:-3}") + local common_curl_opts=(--silent --show-error --retry "${HTTP_RETRIES:-3}") - echo "GET $blob_url" >&2 - local response_code - response_code=$(curl \ + echo "GET $blob_url" >&2 + local response_code + response_code=$(curl \ "${common_curl_opts[@]}" \ -L \ --write-out '%{response_code}' \ --output "$tmp_dest" \ --dump-header "$headers_file" \ "$blob_url" - ) + ) - if [[ "$response_code" -eq 200 ]]; then + if [[ "$response_code" -eq 200 ]]; then # Blob download didn't require auth, we're done : - elif [[ "$response_code" -eq 401 ]]; then + elif [[ "$response_code" -eq 401 ]]; then echo "Got 401, trying to authenticate" >&2 local www_authenticate @@ -238,42 +238,42 @@ spec: service=$(get_from_www_auth_header "$www_authenticate" service) scope=$(get_from_www_auth_header "$www_authenticate" scope) token_url=$(jq -n -r --arg realm "$realm" --arg service "$service" --arg scope "$scope" \ - '"\($realm)?service=\($service | @uri)&scope=\($scope | @uri)"' + '"\($realm)?service=\($service | @uri)&scope=\($scope | @uri)"' ) local basic_auth token_auth if basic_auth=$(get_container_auth "$blob_ref"); then - token_auth=(-H "authorization: Basic $basic_auth") + token_auth=(-H "authorization: Basic $basic_auth") else - echo "Trying to get token anonymously" >&2 - token_auth=() + echo "Trying to get token anonymously" >&2 + token_auth=() fi echo "GET $token_url" >&2 token=$(curl \ - "${common_curl_opts[@]}" \ - "${token_auth[@]}" \ - --fail \ - "$token_url" | jq -r .token + "${common_curl_opts[@]}" \ + "${token_auth[@]}" \ + --fail \ + "$token_url" | jq -r .token ) echo "GET $blob_url" >&2 curl \ - "${common_curl_opts[@]}" \ - -L \ - --output "$tmp_dest" \ - --fail \ - -H "authorization: Bearer $token" \ - "$blob_url" - else + "${common_curl_opts[@]}" \ + -L \ + --output "$tmp_dest" \ + --fail \ + -H "authorization: Bearer $token" \ + "$blob_url" + else echo "Error: unexpected response code: $response_code!" >&2 return 1 - fi + fi - cp "$tmp_dest" "$dest" - } + cp "$tmp_dest" "$dest" + } - find_blob_url() { + find_blob_url() { local attestation_file=$1 jq -r --slurp < "$attestation_file" ' @@ -287,12 +287,12 @@ spec: else error("Expected to find exactly one SBOM_BLOB_URL result, found \(length): \(.)") end' - } + } - jq -r '.components[].containerImage' <<< "$IMAGES" | while read -r image; do + jq -r '.components[].containerImage' <<< "$IMAGES" | while read -r image; do echo "Looking for SBOM_BLOB_URL result in the attestation for $image" attestation_file="$WORKDIR/$image/attestation.json" sbom_blob_url=$(find_blob_url "$attestation_file") mkdir -p "$SBOMS_DIR/$image" download_blob "$sbom_blob_url" "$SBOMS_DIR/$image/sbom.json" - done + done diff --git a/pac/tasks/gather-deploy-images.yaml b/pac/tasks/gather-deploy-images.yaml index 7ac989e..fa368a6 100644 --- a/pac/tasks/gather-deploy-images.yaml +++ b/pac/tasks/gather-deploy-images.yaml @@ -27,53 +27,53 @@ spec: https://github.com/konflux-ci/build-definitions/tree/main/task/verify-enterprise-contract/0.1. When there are no images to verify, this is an empty string. steps: - - name: get-images-per-env - image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 - workingDir: $(workspaces.source.path)/source - env: - - name: TARGET_BRANCH - value: $(params.TARGET_BRANCH) - args: - - $(params.ENVIRONMENTS[*]) - script: | - #!/bin/bash - set -euo pipefail + - name: get-images-per-env + image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 + workingDir: $(workspaces.source.path)/source + env: + - name: TARGET_BRANCH + value: $(params.TARGET_BRANCH) + args: + - $(params.ENVIRONMENTS[*]) + script: | + #!/bin/bash + set -euo pipefail - IMAGE_PATH='.spec.template.spec.containers[0].image' - IMAGES_FILE='/tmp/all-images.txt' - component_name=$(yq .metadata.name application.yaml) + IMAGE_PATH='.spec.template.spec.containers[0].image' + IMAGES_FILE='/tmp/all-images.txt' + component_name=$(yq .metadata.name application.yaml) - for env in "$@"; do - yaml_path=components/${component_name}/overlays/${env}/deployment-patch.yaml - image=$(yq "$IMAGE_PATH" "$yaml_path") + for env in "$@"; do + yaml_path=components/${component_name}/overlays/${env}/deployment-patch.yaml + image=$(yq "$IMAGE_PATH" "$yaml_path") - if [ -n "$TARGET_BRANCH" ]; then - prev_image=$(git show "origin/$TARGET_BRANCH:$yaml_path" | yq "$IMAGE_PATH") - if [ "$prev_image" = "$image" ]; then - # don't check images that didn't change between the current revision and the target branch - continue + if [ -n "$TARGET_BRANCH" ]; then + prev_image=$(git show "origin/$TARGET_BRANCH:$yaml_path" | yq "$IMAGE_PATH") + if [ "$prev_image" = "$image" ]; then + # don't check images that didn't change between the current revision and the target branch + continue + fi fi - fi - printf "%s\n" "$image" - done | sort -u > $IMAGES_FILE + printf "%s\n" "$image" + done | sort -u > $IMAGES_FILE - if [ ! -s $IMAGES_FILE ]; then - echo "No images to verify" - touch $(results.IMAGES_TO_VERIFY.path) - exit 0 - fi + if [ ! -s $IMAGES_FILE ]; then + echo "No images to verify" + touch $(results.IMAGES_TO_VERIFY.path) + exit 0 + fi - # TODO: each component needs a {"source": {"git": {"url": "...", "revision": "..."}}} - # will that be too large for Tekton results? + # TODO: each component needs a {"source": {"git": {"url": "...", "revision": "..."}}} + # will that be too large for Tekton results? - jq --compact-output --raw-input --slurp < $IMAGES_FILE ' - # split input file - split("\n") | - # drop empty lines - map(select(length > 0)) | - # convert into EC-compatible format - { - "components": map({"containerImage": .}) - } - ' | tee $(results.IMAGES_TO_VERIFY.path) + jq --compact-output --raw-input --slurp < $IMAGES_FILE ' + # split input file + split("\n") | + # drop empty lines + map(select(length > 0)) | + # convert into EC-compatible format + { + "components": map({"containerImage": .}) + } + ' | tee $(results.IMAGES_TO_VERIFY.path) diff --git a/pac/tasks/git-clone.yaml b/pac/tasks/git-clone.yaml index 5ecb436..a3cecd0 100644 --- a/pac/tasks/git-clone.yaml +++ b/pac/tasks/git-clone.yaml @@ -14,290 +14,290 @@ spec: description: |- The git-clone Task will clone a repo from the provided url into the output Workspace. By default the repo will be cloned into the root of your Workspace. params: - - description: Repository URL to clone from. - name: url - type: string - - default: "" - description: Revision to checkout. (branch, tag, sha, ref, etc...) - name: revision - type: string - - default: "" - description: Refspec to fetch before checking out revision. - name: refspec - type: string - - default: "true" - description: Initialize and fetch git submodules. - name: submodules - type: string - - default: "1" - description: Perform a shallow clone, fetching only the most recent N commits. - name: depth - type: string - - default: "true" - description: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote. - name: sslVerify - type: string - - default: "source" - description: Subdirectory inside the `output` Workspace to clone the repo into. - name: subdirectory - type: string - - default: "" - description: Define the directory patterns to match or exclude when performing a sparse checkout. - name: sparseCheckoutDirectories - type: string - - default: "true" - description: Clean out the contents of the destination directory if it already exists before cloning. - name: deleteExisting - type: string - - default: "" - description: HTTP proxy server for non-SSL requests. - name: httpProxy - type: string - - default: "" - description: HTTPS proxy server for SSL requests. - name: httpsProxy - type: string - - default: "" - description: Opt out of proxying HTTP/HTTPS requests. - name: noProxy - type: string - - default: "false" - description: Log the commands that are executed during `git-clone`'s operation. - name: verbose - type: string - - default: "" - description: Deprecated. Has no effect. Will be removed in the future. - name: gitInitImage - type: string - - default: /tekton/home - description: | - Absolute path to the user's home directory. Set this explicitly if you are running the image as a non-root user. - name: userHome - type: string - - default: "true" - description: | - Check symlinks in the repo. If they're pointing outside of the repo, the build will fail. - name: enableSymlinkCheck - type: string - - default: "false" - description: Fetch all tags for the repo. - name: fetchTags - type: string - - name: caTrustConfigMapName - type: string - description: The name of the ConfigMap to read CA bundle data from. - default: trusted-ca - - name: caTrustConfigMapKey - type: string - description: The name of the key in the ConfigMap that contains the CA bundle data. - default: ca-bundle.crt + - description: Repository URL to clone from. + name: url + type: string + - default: "" + description: Revision to checkout. (branch, tag, sha, ref, etc...) + name: revision + type: string + - default: "" + description: Refspec to fetch before checking out revision. + name: refspec + type: string + - default: "true" + description: Initialize and fetch git submodules. + name: submodules + type: string + - default: "1" + description: Perform a shallow clone, fetching only the most recent N commits. + name: depth + type: string + - default: "true" + description: Set the `http.sslVerify` global git config. Setting this to `false` is not advised unless you are sure that you trust your git remote. + name: sslVerify + type: string + - default: "source" + description: Subdirectory inside the `output` Workspace to clone the repo into. + name: subdirectory + type: string + - default: "" + description: Define the directory patterns to match or exclude when performing a sparse checkout. + name: sparseCheckoutDirectories + type: string + - default: "true" + description: Clean out the contents of the destination directory if it already exists before cloning. + name: deleteExisting + type: string + - default: "" + description: HTTP proxy server for non-SSL requests. + name: httpProxy + type: string + - default: "" + description: HTTPS proxy server for SSL requests. + name: httpsProxy + type: string + - default: "" + description: Opt out of proxying HTTP/HTTPS requests. + name: noProxy + type: string + - default: "false" + description: Log the commands that are executed during `git-clone`'s operation. + name: verbose + type: string + - default: "" + description: Deprecated. Has no effect. Will be removed in the future. + name: gitInitImage + type: string + - default: /tekton/home + description: | + Absolute path to the user's home directory. Set this explicitly if you are running the image as a non-root user. + name: userHome + type: string + - default: "true" + description: | + Check symlinks in the repo. If they're pointing outside of the repo, the build will fail. + name: enableSymlinkCheck + type: string + - default: "false" + description: Fetch all tags for the repo. + name: fetchTags + type: string + - name: caTrustConfigMapName + type: string + description: The name of the ConfigMap to read CA bundle data from. + default: trusted-ca + - name: caTrustConfigMapKey + type: string + description: The name of the key in the ConfigMap that contains the CA bundle data. + default: ca-bundle.crt results: - - description: The precise commit SHA that was fetched by this Task. - name: commit - - description: The precise URL that was fetched by this Task. - name: url - - description: The commit timestamp of the checkout - name: commit-timestamp + - description: The precise commit SHA that was fetched by this Task. + name: commit + - description: The precise URL that was fetched by this Task. + name: url + - description: The commit timestamp of the checkout + name: commit-timestamp steps: - - name: clone - env: - - name: HOME - value: $(params.userHome) - - name: PARAM_URL - value: $(params.url) - - name: PARAM_REVISION - value: $(params.revision) - - name: PARAM_REFSPEC - value: $(params.refspec) - - name: PARAM_SUBMODULES - value: $(params.submodules) - - name: PARAM_DEPTH - value: $(params.depth) - - name: PARAM_SSL_VERIFY - value: $(params.sslVerify) - - name: PARAM_SUBDIRECTORY - value: $(params.subdirectory) - - name: PARAM_DELETE_EXISTING - value: $(params.deleteExisting) - - name: PARAM_HTTP_PROXY - value: $(params.httpProxy) - - name: PARAM_HTTPS_PROXY - value: $(params.httpsProxy) - - name: PARAM_NO_PROXY - value: $(params.noProxy) - - name: PARAM_VERBOSE - value: $(params.verbose) - - name: PARAM_SPARSE_CHECKOUT_DIRECTORIES - value: $(params.sparseCheckoutDirectories) - - name: PARAM_USER_HOME - value: $(params.userHome) - - name: PARAM_FETCH_TAGS - value: $(params.fetchTags) - - name: PARAM_GIT_INIT_IMAGE - value: $(params.gitInitImage) - - name: WORKSPACE_OUTPUT_PATH - value: $(workspaces.output.path) - - name: WORKSPACE_SSH_DIRECTORY_BOUND - value: $(workspaces.ssh-directory.bound) - - name: WORKSPACE_SSH_DIRECTORY_PATH - value: $(workspaces.ssh-directory.path) - - name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND - value: $(workspaces.basic-auth.bound) - - name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH - value: $(workspaces.basic-auth.path) - image: quay.io/konflux-ci/git-clone@sha256:4e53ebd9242f05ca55bfc8d58b3363d8b9d9bc3ab439d9ab76cdbdf5b1fd42d9 - computeResources: {} - securityContext: - runAsUser: 0 - volumeMounts: - - name: trusted-ca - mountPath: /mnt/trusted-ca - readOnly: true - script: | - #!/usr/bin/env sh - set -eu + - name: clone + env: + - name: HOME + value: $(params.userHome) + - name: PARAM_URL + value: $(params.url) + - name: PARAM_REVISION + value: $(params.revision) + - name: PARAM_REFSPEC + value: $(params.refspec) + - name: PARAM_SUBMODULES + value: $(params.submodules) + - name: PARAM_DEPTH + value: $(params.depth) + - name: PARAM_SSL_VERIFY + value: $(params.sslVerify) + - name: PARAM_SUBDIRECTORY + value: $(params.subdirectory) + - name: PARAM_DELETE_EXISTING + value: $(params.deleteExisting) + - name: PARAM_HTTP_PROXY + value: $(params.httpProxy) + - name: PARAM_HTTPS_PROXY + value: $(params.httpsProxy) + - name: PARAM_NO_PROXY + value: $(params.noProxy) + - name: PARAM_VERBOSE + value: $(params.verbose) + - name: PARAM_SPARSE_CHECKOUT_DIRECTORIES + value: $(params.sparseCheckoutDirectories) + - name: PARAM_USER_HOME + value: $(params.userHome) + - name: PARAM_FETCH_TAGS + value: $(params.fetchTags) + - name: PARAM_GIT_INIT_IMAGE + value: $(params.gitInitImage) + - name: WORKSPACE_OUTPUT_PATH + value: $(workspaces.output.path) + - name: WORKSPACE_SSH_DIRECTORY_BOUND + value: $(workspaces.ssh-directory.bound) + - name: WORKSPACE_SSH_DIRECTORY_PATH + value: $(workspaces.ssh-directory.path) + - name: WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND + value: $(workspaces.basic-auth.bound) + - name: WORKSPACE_BASIC_AUTH_DIRECTORY_PATH + value: $(workspaces.basic-auth.path) + image: quay.io/konflux-ci/git-clone@sha256:4e53ebd9242f05ca55bfc8d58b3363d8b9d9bc3ab439d9ab76cdbdf5b1fd42d9 + computeResources: {} + securityContext: + runAsUser: 0 + volumeMounts: + - name: trusted-ca + mountPath: /mnt/trusted-ca + readOnly: true + script: | + #!/usr/bin/env sh + set -eu - if [ "${PARAM_VERBOSE}" = "true" ] ; then - set -x - fi + if [ "${PARAM_VERBOSE}" = "true" ] ; then + set -x + fi - if [ -n "${PARAM_GIT_INIT_IMAGE}" ]; then - echo "WARNING: provided deprecated gitInitImage parameter has no effect." - fi + if [ -n "${PARAM_GIT_INIT_IMAGE}" ]; then + echo "WARNING: provided deprecated gitInitImage parameter has no effect." + fi - if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ] ; then - if [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" ]; then - cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" "${PARAM_USER_HOME}/.git-credentials" - cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" "${PARAM_USER_HOME}/.gitconfig" - # Compatibility with kubernetes.io/basic-auth secrets - elif [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password" ]; then - HOSTNAME=$(echo $PARAM_URL | awk -F/ '{print $3}') - echo "https://$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username):$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password)@$HOSTNAME" > "${PARAM_USER_HOME}/.git-credentials" - echo -e "[credential \"https://$HOSTNAME\"]\n helper = store" > "${PARAM_USER_HOME}/.gitconfig" - else - echo "Unknown basic-auth workspace format" - exit 1 + if [ "${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}" = "true" ] ; then + if [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" ]; then + cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials" "${PARAM_USER_HOME}/.git-credentials" + cp "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig" "${PARAM_USER_HOME}/.gitconfig" + # Compatibility with kubernetes.io/basic-auth secrets + elif [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username" ] && [ -f "${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password" ]; then + HOSTNAME=$(echo $PARAM_URL | awk -F/ '{print $3}') + echo "https://$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/username):$(cat ${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/password)@$HOSTNAME" > "${PARAM_USER_HOME}/.git-credentials" + echo -e "[credential \"https://$HOSTNAME\"]\n helper = store" > "${PARAM_USER_HOME}/.gitconfig" + else + echo "Unknown basic-auth workspace format" + exit 1 + fi + chmod 400 "${PARAM_USER_HOME}/.git-credentials" + chmod 400 "${PARAM_USER_HOME}/.gitconfig" fi - chmod 400 "${PARAM_USER_HOME}/.git-credentials" - chmod 400 "${PARAM_USER_HOME}/.gitconfig" - fi - # Should be called after the gitconfig is copied from the repository secret - ca_bundle=/mnt/trusted-ca/ca-bundle.crt - if [ -f "$ca_bundle" ]; then - echo "INFO: Using mounted CA bundle: $ca_bundle" - git config --global http.sslCAInfo "$ca_bundle" - fi + # Should be called after the gitconfig is copied from the repository secret + ca_bundle=/mnt/trusted-ca/ca-bundle.crt + if [ -f "$ca_bundle" ]; then + echo "INFO: Using mounted CA bundle: $ca_bundle" + git config --global http.sslCAInfo "$ca_bundle" + fi - if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then - cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}" "${PARAM_USER_HOME}"/.ssh - chmod 700 "${PARAM_USER_HOME}"/.ssh - chmod -R 400 "${PARAM_USER_HOME}"/.ssh/* - fi + if [ "${WORKSPACE_SSH_DIRECTORY_BOUND}" = "true" ] ; then + cp -R "${WORKSPACE_SSH_DIRECTORY_PATH}" "${PARAM_USER_HOME}"/.ssh + chmod 700 "${PARAM_USER_HOME}"/.ssh + chmod -R 400 "${PARAM_USER_HOME}"/.ssh/* + fi - CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}" + CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}" - cleandir() { - # Delete any existing contents of the repo directory if it exists. - # - # We don't just "rm -rf ${CHECKOUT_DIR}" because ${CHECKOUT_DIR} might be "/" - # or the root of a mounted volume. - if [ -d "${CHECKOUT_DIR}" ] ; then - # Delete non-hidden files and directories - rm -rf "${CHECKOUT_DIR:?}"/* - # Delete files and directories starting with . but excluding .. - rm -rf "${CHECKOUT_DIR}"/.[!.]* - # Delete files and directories starting with .. plus any other character - rm -rf "${CHECKOUT_DIR}"/..?* - fi - } + cleandir() { + # Delete any existing contents of the repo directory if it exists. + # + # We don't just "rm -rf ${CHECKOUT_DIR}" because ${CHECKOUT_DIR} might be "/" + # or the root of a mounted volume. + if [ -d "${CHECKOUT_DIR}" ] ; then + # Delete non-hidden files and directories + rm -rf "${CHECKOUT_DIR:?}"/* + # Delete files and directories starting with . but excluding .. + rm -rf "${CHECKOUT_DIR}"/.[!.]* + # Delete files and directories starting with .. plus any other character + rm -rf "${CHECKOUT_DIR}"/..?* + fi + } - if [ "${PARAM_DELETE_EXISTING}" = "true" ] ; then - cleandir - fi + if [ "${PARAM_DELETE_EXISTING}" = "true" ] ; then + cleandir + fi - test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}" - test -z "${PARAM_HTTPS_PROXY}" || export HTTPS_PROXY="${PARAM_HTTPS_PROXY}" - test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}" + test -z "${PARAM_HTTP_PROXY}" || export HTTP_PROXY="${PARAM_HTTP_PROXY}" + test -z "${PARAM_HTTPS_PROXY}" || export HTTPS_PROXY="${PARAM_HTTPS_PROXY}" + test -z "${PARAM_NO_PROXY}" || export NO_PROXY="${PARAM_NO_PROXY}" - /ko-app/git-init \ - -url="${PARAM_URL}" \ - -revision="${PARAM_REVISION}" \ - -refspec="${PARAM_REFSPEC}" \ - -path="${CHECKOUT_DIR}" \ - -sslVerify="${PARAM_SSL_VERIFY}" \ - -submodules="${PARAM_SUBMODULES}" \ - -depth="${PARAM_DEPTH}" \ - -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}" - cd "${CHECKOUT_DIR}" - RESULT_SHA="$(git rev-parse HEAD)" - EXIT_CODE="$?" - if [ "${EXIT_CODE}" != 0 ] ; then - exit "${EXIT_CODE}" - fi - printf "%s" "${RESULT_SHA}" > "$(results.commit.path)" - printf "%s" "${PARAM_URL}" > "$(results.url.path)" - printf "%s" "$(git log -1 --pretty=%ct)" > "$(results.commit-timestamp.path)" + /ko-app/git-init \ + -url="${PARAM_URL}" \ + -revision="${PARAM_REVISION}" \ + -refspec="${PARAM_REFSPEC}" \ + -path="${CHECKOUT_DIR}" \ + -sslVerify="${PARAM_SSL_VERIFY}" \ + -submodules="${PARAM_SUBMODULES}" \ + -depth="${PARAM_DEPTH}" \ + -sparseCheckoutDirectories="${PARAM_SPARSE_CHECKOUT_DIRECTORIES}" + cd "${CHECKOUT_DIR}" + RESULT_SHA="$(git rev-parse HEAD)" + EXIT_CODE="$?" + if [ "${EXIT_CODE}" != 0 ] ; then + exit "${EXIT_CODE}" + fi + printf "%s" "${RESULT_SHA}" > "$(results.commit.path)" + printf "%s" "${PARAM_URL}" > "$(results.url.path)" + printf "%s" "$(git log -1 --pretty=%ct)" > "$(results.commit-timestamp.path)" - if [ "${PARAM_FETCH_TAGS}" = "true" ] ; then - echo "Fetching tags" - git fetch --tags - fi + if [ "${PARAM_FETCH_TAGS}" = "true" ] ; then + echo "Fetching tags" + git fetch --tags + fi - - name: symlink-check - image: quay.io/konflux-ci/git-clone@sha256:4e53ebd9242f05ca55bfc8d58b3363d8b9d9bc3ab439d9ab76cdbdf5b1fd42d9 - # per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting - # the cluster will set imagePullPolicy to IfNotPresent - env: - - name: PARAM_ENABLE_SYMLINK_CHECK - value: $(params.enableSymlinkCheck) - - name: PARAM_SUBDIRECTORY - value: $(params.subdirectory) - - name: WORKSPACE_OUTPUT_PATH - value: $(workspaces.output.path) - computeResources: {} - script: | - #!/usr/bin/env bash - set -euo pipefail + - name: symlink-check + image: quay.io/konflux-ci/git-clone@sha256:4e53ebd9242f05ca55bfc8d58b3363d8b9d9bc3ab439d9ab76cdbdf5b1fd42d9 + # per https://kubernetes.io/docs/concepts/containers/images/#imagepullpolicy-defaulting + # the cluster will set imagePullPolicy to IfNotPresent + env: + - name: PARAM_ENABLE_SYMLINK_CHECK + value: $(params.enableSymlinkCheck) + - name: PARAM_SUBDIRECTORY + value: $(params.subdirectory) + - name: WORKSPACE_OUTPUT_PATH + value: $(workspaces.output.path) + computeResources: {} + script: | + #!/usr/bin/env bash + set -euo pipefail - CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}" - check_symlinks() { - FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=false - while read symlink - do - target=$(readlink -m "$symlink") - if ! [[ "$target" =~ ^$CHECKOUT_DIR ]]; then - echo "The cloned repository contains symlink pointing outside of the cloned repository: $symlink" - FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=true + CHECKOUT_DIR="${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}" + check_symlinks() { + FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=false + while read symlink + do + target=$(readlink -m "$symlink") + if ! [[ "$target" =~ ^$CHECKOUT_DIR ]]; then + echo "The cloned repository contains symlink pointing outside of the cloned repository: $symlink" + FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO=true + fi + done < <(find $CHECKOUT_DIR -type l -print) + if [ "$FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO" = true ] ; then + return 1 fi - done < <(find $CHECKOUT_DIR -type l -print) - if [ "$FOUND_SYMLINK_POINTING_OUTSIDE_OF_REPO" = true ] ; then - return 1 - fi - } + } - if [ "${PARAM_ENABLE_SYMLINK_CHECK}" = "true" ] ; then - echo "Running symlink check" - check_symlinks - fi + if [ "${PARAM_ENABLE_SYMLINK_CHECK}" = "true" ] ; then + echo "Running symlink check" + check_symlinks + fi workspaces: - - description: The git repo will be cloned onto the volume backing this Workspace. - name: output - - description: | - A .ssh directory with private key, known_hosts, config, etc. Copied to - the user's home before git commands are executed. Used to authenticate - with the git remote when performing the clone. Binding a Secret to this - Workspace is strongly recommended over other volume types. - name: ssh-directory - optional: true - - description: | - A Workspace containing a .gitconfig and .git-credentials file or username and password. - These will be copied to the user's home before any git commands are run. Any - other files in this Workspace are ignored. It is strongly recommended - to use ssh-directory over basic-auth whenever possible and to bind a - Secret to this Workspace over other volume types. - name: basic-auth - optional: true + - description: The git repo will be cloned onto the volume backing this Workspace. + name: output + - description: | + A .ssh directory with private key, known_hosts, config, etc. Copied to + the user's home before git commands are executed. Used to authenticate + with the git remote when performing the clone. Binding a Secret to this + Workspace is strongly recommended over other volume types. + name: ssh-directory + optional: true + - description: | + A Workspace containing a .gitconfig and .git-credentials file or username and password. + These will be copied to the user's home before any git commands are run. Any + other files in this Workspace are ignored. It is strongly recommended + to use ssh-directory over basic-auth whenever possible and to bind a + Secret to this Workspace over other volume types. + name: basic-auth + optional: true volumes: - name: trusted-ca configMap: diff --git a/pac/tasks/show-sbom-rhdh.yaml b/pac/tasks/show-sbom-rhdh.yaml index ceeb583..9059f75 100644 --- a/pac/tasks/show-sbom-rhdh.yaml +++ b/pac/tasks/show-sbom-rhdh.yaml @@ -21,43 +21,41 @@ spec: description: Fully qualified image name to show SBOM for. type: string results: - - description: Placeholder result meant to make RHDH identify this task as the producer of the SBOM logs. - name: LINK_TO_SBOM + - description: Placeholder result meant to make RHDH identify this task as the producer of the SBOM logs. + name: LINK_TO_SBOM steps: - - name: annotate-task - image: registry.redhat.io/openshift4/ose-cli:4.13@sha256:73df37794ffff7de1101016c23dc623e4990810390ebdabcbbfa065214352c7c - script: | - #!/usr/bin/env bash - - # When this task is used in a pipelineRun triggered by Pipelines as Code, the annotations will be cleared, - # so we're re-adding them here - oc annotate taskrun $(context.taskRun.name) task.results.format=application/text - oc annotate taskrun $(context.taskRun.name) task.results.key=LINK_TO_SBOM - oc annotate taskrun $(context.taskRun.name) task.output.location=results - - name: show-sbom - image: registry.redhat.io/rhtas-tech-preview/cosign-rhel9@sha256:151f4a1e721b644bafe47bf5bfb8844ff27b95ca098cc37f3f6cbedcda79a897 - env: - - name: IMAGE_URL - value: $(params.IMAGE_URL) - script: | - #!/bin/bash - status=-1 - max_try=5 - wait_sec=2 - for run in $(seq 1 $max_try); do - status=0 - cosign download sbom $IMAGE_URL 2>>err - status=$? - if [ "$status" -eq 0 ]; then - break + - name: annotate-task + image: registry.redhat.io/openshift4/ose-cli:4.13@sha256:73df37794ffff7de1101016c23dc623e4990810390ebdabcbbfa065214352c7c + script: | + #!/usr/bin/env bash + # When this task is used in a pipelineRun triggered by Pipelines as Code, the annotations will be cleared, + # so we're re-adding them here + oc annotate taskrun $(context.taskRun.name) task.results.format=application/text + oc annotate taskrun $(context.taskRun.name) task.results.key=LINK_TO_SBOM + oc annotate taskrun $(context.taskRun.name) task.output.location=results + - name: show-sbom + image: registry.redhat.io/rhtas-tech-preview/cosign-rhel9@sha256:151f4a1e721b644bafe47bf5bfb8844ff27b95ca098cc37f3f6cbedcda79a897 + env: + - name: IMAGE_URL + value: $(params.IMAGE_URL) + script: | + #!/bin/bash + status=-1 + max_try=5 + wait_sec=2 + for run in $(seq 1 $max_try); do + status=0 + cosign download sbom $IMAGE_URL 2>>err + status=$? + if [ "$status" -eq 0 ]; then + break + fi + sleep $wait_sec + done + if [ "$status" -ne 0 ]; then + echo "Failed to get SBOM after ${max_try} tries" >&2 + cat err >&2 fi - sleep $wait_sec - done - if [ "$status" -ne 0 ]; then - echo "Failed to get SBOM after ${max_try} tries" >&2 - cat err >&2 - fi - - # This result will be ignored by RHDH, but having it set is actually necessary for the task to be properly - # identified. For now, we're adding the image URL to the result so it won't be empty. - echo -n "$IMAGE_URL" > $(results.LINK_TO_SBOM.path) + # This result will be ignored by RHDH, but having it set is actually necessary for the task to be properly + # identified. For now, we're adding the image URL to the result so it won't be empty. + echo -n "$IMAGE_URL" > $(results.LINK_TO_SBOM.path) diff --git a/pac/tasks/upload-sbom-to-trustification.yaml b/pac/tasks/upload-sbom-to-trustification.yaml index aabc8ad..62e72b7 100644 --- a/pac/tasks/upload-sbom-to-trustification.yaml +++ b/pac/tasks/upload-sbom-to-trustification.yaml @@ -29,216 +29,216 @@ spec: - supported_cyclonedx_version: If the SBOM uses a higher CycloneDX version, `syft convert` to the supported version before uploading. params: - - name: SBOMS_DIR - default: "." - description: >- - Directory containing SBOM files. The task will search for CycloneDX JSON - SBOMs recursively in this directory and upload them all to Trustification. - The path is relative to the 'sboms' workspace. - type: string - - name: HTTP_RETRIES - default: "3" - description: "Maximum number of retries for transient HTTP(S) errors" - type: string - - name: TRUSTIFICATION_SECRET_NAME - default: trustification-secret - description: Name of the Secret containing auth and configuration - type: string - - name: FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED - default: "true" - description: >- - Should the task fail if the Secret does not contain the required keys? - (Set "true" to fail, "false" to skip uploading and exit with success). - type: string - workspaces: - - name: sboms - description: Directory containing the SBOMs to upload - volumes: - - name: trustification-secret - secret: - secretName: $(params.TRUSTIFICATION_SECRET_NAME) - optional: true - stepTemplate: - env: - name: SBOMS_DIR - value: $(workspaces.sboms.path)/$(params.SBOMS_DIR) + default: "." + description: >- + Directory containing SBOM files. The task will search for CycloneDX JSON + SBOMs recursively in this directory and upload them all to Trustification. + The path is relative to the 'sboms' workspace. + type: string - name: HTTP_RETRIES - value: $(params.HTTP_RETRIES) + default: "3" + description: "Maximum number of retries for transient HTTP(S) errors" + type: string - name: TRUSTIFICATION_SECRET_NAME - value: $(params.TRUSTIFICATION_SECRET_NAME) - - name: TRUSTIFICATION_SECRET_PATH - value: /run/secrets/trustification + default: trustification-secret + description: Name of the Secret containing auth and configuration + type: string - name: FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED - value: $(params.FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED) - - name: WORKDIR - value: /tekton/home - volumeMounts: + default: "true" + description: >- + Should the task fail if the Secret does not contain the required keys? + (Set "true" to fail, "false" to skip uploading and exit with success). + type: string + workspaces: + - name: sboms + description: Directory containing the SBOMs to upload + volumes: - name: trustification-secret - mountPath: /run/secrets/trustification + secret: + secretName: $(params.TRUSTIFICATION_SECRET_NAME) + optional: true + stepTemplate: + env: + - name: SBOMS_DIR + value: $(workspaces.sboms.path)/$(params.SBOMS_DIR) + - name: HTTP_RETRIES + value: $(params.HTTP_RETRIES) + - name: TRUSTIFICATION_SECRET_NAME + value: $(params.TRUSTIFICATION_SECRET_NAME) + - name: TRUSTIFICATION_SECRET_PATH + value: /run/secrets/trustification + - name: FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED + value: $(params.FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED) + - name: WORKDIR + value: /tekton/home + volumeMounts: + - name: trustification-secret + mountPath: /run/secrets/trustification steps: - - name: gather-sboms - image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 - script: | - #!/usr/bin/env bash - set -o errexit -o nounset -o pipefail - - version_lesser_equal() { - local first - first="$(printf "%s\n%s" "$1" "$2" | sort --version-sort | head -n 1)" - [ "$1" = "$first" ] - } - - if [[ -f "$TRUSTIFICATION_SECRET_PATH/supported_cyclonedx_version" ]]; then - supported_version="$(cat "$TRUSTIFICATION_SECRET_PATH/supported_cyclonedx_version")" - else - echo "The '$TRUSTIFICATION_SECRET_NAME' secret does not set supported_cyclonedx_version, will not check SBOM versions" - supported_version="" - fi - - echo "Looking for CycloneDX SBOMs in $SBOMS_DIR" - - find "$SBOMS_DIR" -type f | while read -r filepath; do - file_relpath=$(realpath "$filepath" --relative-base="$SBOMS_DIR") - if ! jq empty "$filepath" 2>/dev/null; then - echo "$file_relpath: not JSON" - continue - fi - - if ! jq -e '.bomFormat == "CycloneDX"' "$filepath" >/dev/null; then - echo "$file_relpath: not a CycloneDX SBOM" - continue + - name: gather-sboms + image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 + script: | + #!/usr/bin/env bash + set -o errexit -o nounset -o pipefail + + version_lesser_equal() { + local first + first="$(printf "%s\n%s" "$1" "$2" | sort --version-sort | head -n 1)" + [ "$1" = "$first" ] + } + + if [[ -f "$TRUSTIFICATION_SECRET_PATH/supported_cyclonedx_version" ]]; then + supported_version="$(cat "$TRUSTIFICATION_SECRET_PATH/supported_cyclonedx_version")" + else + echo "The '$TRUSTIFICATION_SECRET_NAME' secret does not set supported_cyclonedx_version, will not check SBOM versions" + supported_version="" fi - echo "Found CycloneDX SBOM: $file_relpath" - # The 'id' of each SBOM is checksum of the original content, before (possibly) - # downgrading the CycloneDX version. The conversion always updates some metadata - # (timestamp, UUID), changing the checksum. To avoid duplication, use the original - # checksum. - sbom_id="sha256:$(sha256sum "$filepath" | cut -d ' ' -f 1)" + echo "Looking for CycloneDX SBOMs in $SBOMS_DIR" - # Symlink the discovered SBOMS to ${WORKDIR}/${sbom_id}.json so that subsequent steps - # don't have to look for them again. - sbom_path="$WORKDIR/$sbom_id.json" - ln -s "$(realpath "$filepath")" "$sbom_path" + find "$SBOMS_DIR" -type f | while read -r filepath; do + file_relpath=$(realpath "$filepath" --relative-base="$SBOMS_DIR") + if ! jq empty "$filepath" 2>/dev/null; then + echo "$file_relpath: not JSON" + continue + fi - if [[ -n "$supported_version" ]]; then - sbom_version="$(jq -r ".specVersion" "$sbom_path")" + if ! jq -e '.bomFormat == "CycloneDX"' "$filepath" >/dev/null; then + echo "$file_relpath: not a CycloneDX SBOM" + continue + fi - if version_lesser_equal "$sbom_version" "$supported_version"; then - echo "SBOM version ($sbom_version) is supported (<= $supported_version), will not convert" - else - echo "SBOM version ($sbom_version) is not supported, will convert to $supported_version" - printf "%s" "$supported_version" > "${sbom_path}.convert_to_version" + echo "Found CycloneDX SBOM: $file_relpath" + # The 'id' of each SBOM is checksum of the original content, before (possibly) + # downgrading the CycloneDX version. The conversion always updates some metadata + # (timestamp, UUID), changing the checksum. To avoid duplication, use the original + # checksum. + sbom_id="sha256:$(sha256sum "$filepath" | cut -d ' ' -f 1)" + + # Symlink the discovered SBOMS to ${WORKDIR}/${sbom_id}.json so that subsequent steps + # don't have to look for them again. + sbom_path="$WORKDIR/$sbom_id.json" + ln -s "$(realpath "$filepath")" "$sbom_path" + + if [[ -n "$supported_version" ]]; then + sbom_version="$(jq -r ".specVersion" "$sbom_path")" + + if version_lesser_equal "$sbom_version" "$supported_version"; then + echo "SBOM version ($sbom_version) is supported (<= $supported_version), will not convert" + else + echo "SBOM version ($sbom_version) is not supported, will convert to $supported_version" + printf "%s" "$supported_version" > "${sbom_path}.convert_to_version" + fi fi - fi - done + done - echo "Found $(find "$WORKDIR" -name "*.json" | wc -l) CycloneDX SBOMs" + echo "Found $(find "$WORKDIR" -name "*.json" | wc -l) CycloneDX SBOMs" - # Needs syft, which is in a different image => has to be a separate step - - name: convert-sboms-if-needed - image: registry.redhat.io/rh-syft-tech-preview/syft-rhel9:1.0.1@sha256:27c268d678103a27b6964c2cd5169040941b7304d0078f9727789ffb8ffba370 - script: | - #!/usr/bin/env bash - set -o errexit -o nounset -o pipefail + # Needs syft, which is in a different image => has to be a separate step + - name: convert-sboms-if-needed + image: registry.redhat.io/rh-syft-tech-preview/syft-rhel9:1.0.1@sha256:27c268d678103a27b6964c2cd5169040941b7304d0078f9727789ffb8ffba370 + script: | + #!/usr/bin/env bash + set -o errexit -o nounset -o pipefail - # Return zero matches when a glob doesn't match rather than returning the glob itself - shopt -s nullglob + # Return zero matches when a glob doesn't match rather than returning the glob itself + shopt -s nullglob - for sbom_path in "$WORKDIR"/*.json; do - conversion_attr="${sbom_path}.convert_to_version" + for sbom_path in "$WORKDIR"/*.json; do + conversion_attr="${sbom_path}.convert_to_version" - if [[ -f "$conversion_attr" ]]; then - cdx_version="$(cat "$conversion_attr")" - original_sbom_path="$(realpath "$sbom_path")" - original_sbom_relpath="$(realpath "$sbom_path" --relative-base="$SBOMS_DIR")" + if [[ -f "$conversion_attr" ]]; then + cdx_version="$(cat "$conversion_attr")" + original_sbom_path="$(realpath "$sbom_path")" + original_sbom_relpath="$(realpath "$sbom_path" --relative-base="$SBOMS_DIR")" - echo "Converting $original_sbom_relpath to CycloneDX $cdx_version" - syft convert "$original_sbom_path" -o "cyclonedx-json@${cdx_version}=${sbom_path}.supported_version" - else - # Just duplicate the symlink, the original SBOM already has a supported CDX version - cp --no-dereference "$sbom_path" "${sbom_path}.supported_version" + echo "Converting $original_sbom_relpath to CycloneDX $cdx_version" + syft convert "$original_sbom_path" -o "cyclonedx-json@${cdx_version}=${sbom_path}.supported_version" + else + # Just duplicate the symlink, the original SBOM already has a supported CDX version + cp --no-dereference "$sbom_path" "${sbom_path}.supported_version" + fi + done + + - name: upload-sboms + image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 + script: | + #!/usr/bin/env bash + set -o errexit -o nounset -o pipefail + + shopt -s nullglob + sboms_to_upload=("$WORKDIR"/*.json) + + if [[ "${#sboms_to_upload[@]}" -eq 0 ]]; then + echo "No SBOMs to upload" + exit 0 fi - done - - - name: upload-sboms - image: quay.io/konflux-ci/appstudio-utils:ab6b0b8e40e440158e7288c73aff1cf83a2cc8a9@sha256:24179f0efd06c65d16868c2d7eb82573cce8e43533de6cea14fec3b7446e0b14 - script: | - #!/usr/bin/env bash - set -o errexit -o nounset -o pipefail - - shopt -s nullglob - sboms_to_upload=("$WORKDIR"/*.json) - - if [[ "${#sboms_to_upload[@]}" -eq 0 ]]; then - echo "No SBOMs to upload" - exit 0 - fi - - read_required_secret_key() { - local key="$1" - if [[ -f "$TRUSTIFICATION_SECRET_PATH/$key" ]]; then - cat "$TRUSTIFICATION_SECRET_PATH/$key" - else - echo "Missing configuration: $key" >&2 - echo "Does the '$TRUSTIFICATION_SECRET_NAME' secret exist in your namespace and contain the required keys?" >&2 - echo "Refer to the description of this Task for details." >&2 - if [[ "$FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED" == "false" ]]; then - echo "WARNING: FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED=false; exiting with success" >&2 - exit 0 + read_required_secret_key() { + local key="$1" + if [[ -f "$TRUSTIFICATION_SECRET_PATH/$key" ]]; then + cat "$TRUSTIFICATION_SECRET_PATH/$key" else - exit 1 + echo "Missing configuration: $key" >&2 + echo "Does the '$TRUSTIFICATION_SECRET_NAME' secret exist in your namespace and contain the required keys?" >&2 + echo "Refer to the description of this Task for details." >&2 + + if [[ "$FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED" == "false" ]]; then + echo "WARNING: FAIL_IF_TRUSTIFICATION_NOT_CONFIGURED=false; exiting with success" >&2 + exit 0 + else + exit 1 + fi fi - fi - } + } - bombastic_api_url="$(read_required_secret_key bombastic_api_url)" - oidc_issuer_url="$(read_required_secret_key oidc_issuer_url)" - oidc_client_id="$(read_required_secret_key oidc_client_id)" - oidc_client_secret="$(read_required_secret_key oidc_client_secret)" + bombastic_api_url="$(read_required_secret_key bombastic_api_url)" + oidc_issuer_url="$(read_required_secret_key oidc_issuer_url)" + oidc_client_id="$(read_required_secret_key oidc_client_id)" + oidc_client_secret="$(read_required_secret_key oidc_client_secret)" - curl_opts=(--silent --show-error --fail-with-body --retry "$HTTP_RETRIES") + curl_opts=(--silent --show-error --fail-with-body --retry "$HTTP_RETRIES") - # https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig - openid_configuration_url="${oidc_issuer_url%/}/.well-known/openid-configuration" - echo "Getting OIDC issuer configuration from $openid_configuration_url" - # https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata - token_endpoint="$(curl "${curl_opts[@]}" "$openid_configuration_url" | jq -r .token_endpoint)" + # https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderConfig + openid_configuration_url="${oidc_issuer_url%/}/.well-known/openid-configuration" + echo "Getting OIDC issuer configuration from $openid_configuration_url" + # https://openid.net/specs/openid-connect-discovery-1_0.html#ProviderMetadata + token_endpoint="$(curl "${curl_opts[@]}" "$openid_configuration_url" | jq -r .token_endpoint)" - for sbom_path in "${sboms_to_upload[@]}"; do - original_sbom_relpath="$(realpath "$sbom_path" --relative-base="$SBOMS_DIR")" - echo - echo "--- Processing $original_sbom_relpath ---" + for sbom_path in "${sboms_to_upload[@]}"; do + original_sbom_relpath="$(realpath "$sbom_path" --relative-base="$SBOMS_DIR")" + echo + echo "--- Processing $original_sbom_relpath ---" + + echo "Getting OIDC token from $token_endpoint" + token_response="$( + curl "${curl_opts[@]}" \ + -u "${oidc_client_id}:${oidc_client_secret}" \ + -d "grant_type=client_credentials" \ + "$token_endpoint" + )" + # https://www.rfc-editor.org/rfc/rfc6749.html#section-5.1 + access_token="$(jq -r .access_token <<< "$token_response")" + token_type="$(jq -r .token_type <<< "$token_response")" + expires_in="$(jq -r ".expires_in // empty" <<< "$token_response")" + + retry_max_time=0 # no limit + if [[ -n "$expires_in" ]]; then + retry_max_time="$expires_in" + fi - echo "Getting OIDC token from $token_endpoint" - token_response="$( - curl "${curl_opts[@]}" \ - -u "${oidc_client_id}:${oidc_client_secret}" \ - -d "grant_type=client_credentials" \ - "$token_endpoint" - )" - # https://www.rfc-editor.org/rfc/rfc6749.html#section-5.1 - access_token="$(jq -r .access_token <<< "$token_response")" - token_type="$(jq -r .token_type <<< "$token_response")" - expires_in="$(jq -r ".expires_in // empty" <<< "$token_response")" - - retry_max_time=0 # no limit - if [[ -n "$expires_in" ]]; then - retry_max_time="$expires_in" - fi + # This sbom_id is the one created in the gather-sboms step - sha256:${checksum} + sbom_id="$(basename -s .json "$sbom_path")" + supported_version_of_sbom="${sbom_path}.supported_version" - # This sbom_id is the one created in the gather-sboms step - sha256:${checksum} - sbom_id="$(basename -s .json "$sbom_path")" - supported_version_of_sbom="${sbom_path}.supported_version" - - echo "Uploading SBOM to $bombastic_api_url (with id=$sbom_id)" - # https://docs.trustification.dev/trustification/user/bombastic.html#publishing-an-sbom-doc - curl "${curl_opts[@]}" \ - --retry-max-time "$retry_max_time" \ - -H "authorization: $token_type $access_token" \ - -H "transfer-encoding: chunked" \ - -H "content-type: application/json" \ - --data "@$supported_version_of_sbom" \ - "$bombastic_api_url/api/v1/sbom?id=$sbom_id" - done + echo "Uploading SBOM to $bombastic_api_url (with id=$sbom_id)" + # https://docs.trustification.dev/trustification/user/bombastic.html#publishing-an-sbom-doc + curl "${curl_opts[@]}" \ + --retry-max-time "$retry_max_time" \ + -H "authorization: $token_type $access_token" \ + -H "transfer-encoding: chunked" \ + -H "content-type: application/json" \ + --data "@$supported_version_of_sbom" \ + "$bombastic_api_url/api/v1/sbom?id=$sbom_id" + done diff --git a/pac/tasks/verify-enterprise-contract.yaml b/pac/tasks/verify-enterprise-contract.yaml index 2cc0a14..ecc48d5 100644 --- a/pac/tasks/verify-enterprise-contract.yaml +++ b/pac/tasks/verify-enterprise-contract.yaml @@ -11,180 +11,180 @@ metadata: spec: description: Verify the enterprise contract is met params: - - description: | - Spec section of an ApplicationSnapshot resource. Not all fields of the - resource are required. A minimal example: - { - "components": [ - { - "containerImage": "quay.io/example/repo:latest" - } - ] - } - Each "containerImage" in the "components" array is validated. - name: IMAGES - type: string - - default: enterprise-contract-service/default - description: | - Name of the policy configuration (EnterpriseContractPolicy - resource) to use. `namespace/name` or `name` syntax supported. If - namespace is omitted the namespace where the task runs is used. - name: POLICY_CONFIGURATION - type: string - - default: "" - description: 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. - name: PUBLIC_KEY - type: string - - default: "" - description: Rekor host for transparency log lookups - name: REKOR_HOST - type: string - - default: "false" - description: Skip Rekor transparency log checks during validation. - name: IGNORE_REKOR - type: string - - default: "" - description: TUF mirror URL. Provide a value when NOT using public sigstore deployment. - name: TUF_MIRROR - type: string - - default: "" - description: | - Path to a directory containing SSL certs to be used when communicating - with external services. This is useful when using the integrated registry - and a local instance of Rekor on a development cluster which may use - certificates issued by a not-commonly trusted root CA. In such cases, - "/var/run/secrets/kubernetes.io/serviceaccount" is a good value. Multiple - paths can be provided by using the ":" separator. - name: SSL_CERT_DIR - type: string - - default: "true" - description: Include rule titles and descriptions in the output. Set to "false" - to disable it. - name: INFO - type: string - - default: "true" - description: Fail the task if policy fails. Set to "false" to disable it. - name: STRICT - type: string - - default: /tekton/home - description: Value for the HOME environment variable. - name: HOMEDIR - type: string - - default: now - description: Run policy checks with the provided time. - name: EFFECTIVE_TIME - 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:latest" + } + ] + } + Each "containerImage" in the "components" array is validated. + name: IMAGES + type: string + - default: enterprise-contract-service/default + description: | + Name of the policy configuration (EnterpriseContractPolicy + resource) to use. `namespace/name` or `name` syntax supported. If + namespace is omitted the namespace where the task runs is used. + name: POLICY_CONFIGURATION + type: string + - default: "" + description: 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. + name: PUBLIC_KEY + type: string + - default: "" + description: Rekor host for transparency log lookups + name: REKOR_HOST + type: string + - default: "false" + description: Skip Rekor transparency log checks during validation. + name: IGNORE_REKOR + type: string + - default: "" + description: TUF mirror URL. Provide a value when NOT using public sigstore deployment. + name: TUF_MIRROR + type: string + - default: "" + description: | + Path to a directory containing SSL certs to be used when communicating + with external services. This is useful when using the integrated registry + and a local instance of Rekor on a development cluster which may use + certificates issued by a not-commonly trusted root CA. In such cases, + "/var/run/secrets/kubernetes.io/serviceaccount" is a good value. Multiple + paths can be provided by using the ":" separator. + name: SSL_CERT_DIR + type: string + - default: "true" + description: Include rule titles and descriptions in the output. Set to "false" + to disable it. + name: INFO + type: string + - default: "true" + description: Fail the task if policy fails. Set to "false" to disable it. + name: STRICT + type: string + - default: /tekton/home + description: Value for the HOME environment variable. + name: HOMEDIR + type: string + - default: now + description: Run policy checks with the provided time. + name: EFFECTIVE_TIME + type: string results: - - description: Short summary of the policy evaluation for each image - name: TEST_OUTPUT + - description: Short summary of the policy evaluation for each image + name: TEST_OUTPUT stepTemplate: env: - - name: HOME - value: $(params.HOMEDIR) + - name: HOME + value: $(params.HOMEDIR) steps: - - args: - - version - command: - - ec - image: registry.redhat.io/rhtas/ec-rhel9:0.2 - name: version - - env: - - name: TUF_MIRROR - value: $(params.TUF_MIRROR) - image: registry.redhat.io/rhtas/ec-rhel9:0.2 - name: initialize-tuf - script: |- - set -euo pipefail + - args: + - version + command: + - ec + image: registry.redhat.io/rhtas/ec-rhel9:0.2 + name: version + - env: + - name: TUF_MIRROR + value: $(params.TUF_MIRROR) + image: registry.redhat.io/rhtas/ec-rhel9:0.2 + name: initialize-tuf + script: |- + set -euo pipefail - if [[ -z "${TUF_MIRROR:-}" ]]; then - echo 'TUF_MIRROR not set. Skipping TUF root initialization.' - exit - fi + if [[ -z "${TUF_MIRROR:-}" ]]; then + echo 'TUF_MIRROR not set. Skipping TUF root initialization.' + exit + fi - echo 'Initializing TUF root...' - cosign initialize --mirror "${TUF_MIRROR}" --root "${TUF_MIRROR}/root.json" - echo 'Done!' - - args: - - validate - - image - - --verbose - - --images - - $(params.IMAGES) - - --policy - - $(params.POLICY_CONFIGURATION) - - --public-key - - $(params.PUBLIC_KEY) - - --rekor-url - - $(params.REKOR_HOST) - - --ignore-rekor=$(params.IGNORE_REKOR) - - --info=$(params.INFO) - - --strict=false - - --show-successes - - --effective-time=$(params.EFFECTIVE_TIME) - - --output - - yaml=$(params.HOMEDIR)/report.yaml - - --output - - appstudio=$(results.TEST_OUTPUT.path) - - --output - - json=$(params.HOMEDIR)/report-json.json - command: - - ec - computeResources: - limits: - memory: 2Gi - requests: - cpu: 250m - memory: 2Gi - env: - - name: SSL_CERT_DIR - value: /tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts:$(params.SSL_CERT_DIR) - - name: EC_CACHE - value: "false" - image: registry.redhat.io/rhtas/ec-rhel9:0.2 - name: validate - - args: - - $(params.HOMEDIR)/report.yaml - command: - - cat - image: registry.redhat.io/rhtas/ec-rhel9:0.2 - name: report - - args: - - $(params.HOMEDIR)/report-json.json - command: - - cat - image: registry.redhat.io/rhtas/ec-rhel9:0.2 - name: report-json - - args: - - . - - $(results.TEST_OUTPUT.path) - command: - - jq - image: registry.redhat.io/rhtas/ec-rhel9:0.2 - name: summary - - args: - - --argjson - - strict - - $(params.STRICT) - - -e - - | - .result == "SUCCESS" or .result == "WARNING" or ($strict | not) - - $(results.TEST_OUTPUT.path) - command: - - jq - image: registry.redhat.io/rhtas/ec-rhel9:0.2 - name: assert - - image: registry.redhat.io/openshift4/ose-cli:4.13@sha256:73df37794ffff7de1101016c23dc623e4990810390ebdabcbbfa065214352c7c - name: annotate-task - script: | - #!/usr/bin/env bash - echo "verify-enterprise-contract $(context.taskRun.name)" - oc annotate taskrun $(context.taskRun.name) task.results.format=application/json - oc annotate taskrun $(context.taskRun.name) task.results.type=ec - oc annotate taskrun $(context.taskRun.name) task.results.container=step-report-json - oc annotate taskrun $(context.taskRun.name) task.output.location=logs + echo 'Initializing TUF root...' + cosign initialize --mirror "${TUF_MIRROR}" --root "${TUF_MIRROR}/root.json" + echo 'Done!' + - args: + - validate + - image + - --verbose + - --images + - $(params.IMAGES) + - --policy + - $(params.POLICY_CONFIGURATION) + - --public-key + - $(params.PUBLIC_KEY) + - --rekor-url + - $(params.REKOR_HOST) + - --ignore-rekor=$(params.IGNORE_REKOR) + - --info=$(params.INFO) + - --strict=false + - --show-successes + - --effective-time=$(params.EFFECTIVE_TIME) + - --output + - yaml=$(params.HOMEDIR)/report.yaml + - --output + - appstudio=$(results.TEST_OUTPUT.path) + - --output + - json=$(params.HOMEDIR)/report-json.json + command: + - ec + computeResources: + limits: + memory: 2Gi + requests: + cpu: 250m + memory: 2Gi + env: + - name: SSL_CERT_DIR + value: /tekton-custom-certs:/etc/ssl/certs:/etc/pki/tls/certs:/system/etc/security/cacerts:$(params.SSL_CERT_DIR) + - name: EC_CACHE + value: "false" + image: registry.redhat.io/rhtas/ec-rhel9:0.2 + name: validate + - args: + - $(params.HOMEDIR)/report.yaml + command: + - cat + image: registry.redhat.io/rhtas/ec-rhel9:0.2 + name: report + - args: + - $(params.HOMEDIR)/report-json.json + command: + - cat + image: registry.redhat.io/rhtas/ec-rhel9:0.2 + name: report-json + - args: + - . + - $(results.TEST_OUTPUT.path) + command: + - jq + image: registry.redhat.io/rhtas/ec-rhel9:0.2 + name: summary + - args: + - --argjson + - strict + - $(params.STRICT) + - -e + - | + .result == "SUCCESS" or .result == "WARNING" or ($strict | not) + - $(results.TEST_OUTPUT.path) + command: + - jq + image: registry.redhat.io/rhtas/ec-rhel9:0.2 + name: assert + - image: registry.redhat.io/openshift4/ose-cli:4.13@sha256:73df37794ffff7de1101016c23dc623e4990810390ebdabcbbfa065214352c7c + name: annotate-task + script: | + #!/usr/bin/env bash + echo "verify-enterprise-contract $(context.taskRun.name)" + oc annotate taskrun $(context.taskRun.name) task.results.format=application/json + oc annotate taskrun $(context.taskRun.name) task.results.type=ec + oc annotate taskrun $(context.taskRun.name) task.results.container=step-report-json + oc annotate taskrun $(context.taskRun.name) task.output.location=logs workspaces: - - description: The workspace where the snapshot spec json file resides - name: data - optional: true + - description: The workspace where the snapshot spec json file resides + name: data + optional: true diff --git a/yamllint.yaml b/yamllint.yaml new file mode 100644 index 0000000..f117c86 --- /dev/null +++ b/yamllint.yaml @@ -0,0 +1,30 @@ +yaml-files: + - '*.yaml' + - '*.yml' +rules: + braces: enable + brackets: enable + colons: enable + commas: enable + comments: + require-starting-space: true + ignore-shebangs: true + min-spaces-from-content: 1 + comments-indentation: enable + document-end: disable + document-start: disable + empty-lines: enable + empty-values: disable + float-values: disable + hyphens: enable + indentation: enable + key-duplicates: enable + key-ordering: disable + line-length: disable + new-line-at-end-of-file: enable + new-lines: enable + octal-values: disable + quoted-strings: disable + trailing-spaces: enable + truthy: + check-keys: false