From 9f39974a54813273721733aaae1214a0eb291c7e Mon Sep 17 00:00:00 2001 From: Renzo Rojas Silva Date: Fri, 17 May 2024 17:12:53 -0400 Subject: [PATCH] Deprecate v2alpha1 and v2alpha2 Deprecating v2alpha1 and v2alpha2 formatter versions --- docs/config.md | 6 +- pkg/chains/formats/all/all.go | 2 - pkg/chains/formats/format.go | 4 - pkg/chains/formats/slsa/README.md | 5 +- pkg/chains/formats/slsa/v2alpha1/README.md | 383 ------------- pkg/chains/formats/slsa/v2alpha1/slsav2.go | 72 --- .../formats/slsa/v2alpha1/slsav2_test.go | 422 --------------- .../formats/slsa/v2alpha1/taskrun/taskrun.go | 118 ---- .../slsa/v2alpha1/taskrun/taskrun_test.go | 367 ------------- .../external_parameters.go | 44 -- .../external_parameters_test.go | 92 ---- .../internal/pipelinerun/pipelinerun.go | 137 ----- .../internal/pipelinerun/pipelinerun_test.go | 360 ------------- .../resolved_dependencies.go | 224 -------- .../resolved_dependencies_test.go | 406 -------------- .../slsa/v2alpha2/internal/taskrun/taskrun.go | 133 ----- .../v2alpha2/internal/taskrun/taskrun_test.go | 332 ------------ pkg/chains/formats/slsa/v2alpha2/slsav2.go | 95 ---- .../formats/slsa/v2alpha2/slsav2_test.go | 503 ------------------ pkg/config/config.go | 4 +- test/examples_test.go | 36 -- .../slsa/v2alpha2/pipeline-output-image.json | 124 ----- .../slsa/v2alpha2/task-output-image.json | 74 --- 23 files changed, 7 insertions(+), 3936 deletions(-) delete mode 100644 pkg/chains/formats/slsa/v2alpha1/README.md delete mode 100644 pkg/chains/formats/slsa/v2alpha1/slsav2.go delete mode 100644 pkg/chains/formats/slsa/v2alpha1/slsav2_test.go delete mode 100644 pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun.go delete mode 100644 pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun_test.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters_test.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun_test.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies_test.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun_test.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/slsav2.go delete mode 100644 pkg/chains/formats/slsa/v2alpha2/slsav2_test.go delete mode 100644 test/testdata/slsa/v2alpha2/pipeline-output-image.json delete mode 100644 test/testdata/slsa/v2alpha2/task-output-image.json diff --git a/docs/config.md b/docs/config.md index 03b0099df9..2f8e70433c 100644 --- a/docs/config.md +++ b/docs/config.md @@ -21,21 +21,20 @@ Supported keys include: | Key | Description | Supported Values | Default | | :-------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :----------------------------------------- | :-------- | -| `artifacts.taskrun.format` | The format to store `TaskRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha2`, `slsa/v2alpha3` | `in-toto` | +| `artifacts.taskrun.format` | The format to store `TaskRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha3` | `in-toto` | | `artifacts.taskrun.storage` | The storage backend to store `TaskRun` signatures in. Multiple backends can be specified with comma-separated list ("tekton,oci"). To disable the `TaskRun` artifact input an empty string (""). | `tekton`, `oci`, `gcs`, `docdb`, `grafeas` | `tekton` | | `artifacts.taskrun.signer` | The signature backend to sign `TaskRun` payloads with. | `x509`, `kms` | `x509` | > NOTE: > > - `slsa/v1` is an alias of `in-toto` for backwards compatibility. -> - `slsa/v2alpha2` corresponds to the slsav1.0 spec. and uses now deprecated [`v1beta1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1beta1). > - `slsa/v2alpha3` corresponds to the slsav1.0 spec. and uses latest [`v1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1). Recommended format for new chains users who want the slsav1.0 spec. ### PipelineRun Configuration | Key | Description | Supported Values | Default | | :--------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | :----------------------------------------- | :-------- | -| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha2`, `slsa/v2alpha3` | `in-toto` | +| `artifacts.pipelinerun.format` | The format to store `PipelineRun` payloads in. | `in-toto`, `slsa/v1`, `slsa/v2alpha3` | `in-toto` | | `artifacts.pipelinerun.storage` | The storage backend to store `PipelineRun` signatures in. Multiple backends can be specified with comma-separated list ("tekton,oci"). To disable the `PipelineRun` artifact input an empty string (""). | `tekton`, `oci`, `gcs`, `docdb`, `grafeas` | `tekton` | | `artifacts.pipelinerun.signer` | The signature backend to sign `PipelineRun` payloads with. | `x509`, `kms` | `x509` | | `artifacts.pipelinerun.enable-deep-inspection` | This boolean option will configure whether Chains should inspect child taskruns in order to capture inputs/outputs within a pipelinerun. `"false"` means that Chains only checks pipeline level results, whereas `"true"` means Chains inspects both pipeline level and task level results. | `"true"`, `"false"` | `"false"` | @@ -44,7 +43,6 @@ Supported keys include: > > - For grafeas storage backend, currently we only support Container Analysis. We will make grafeas server address configurabe within a short time. > - `slsa/v1` is an alias of `in-toto` for backwards compatibility. -> - `slsa/v2alpha2` corresponds to the slsav1.0 spec. and uses now deprecated [`v1beta1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1beta1) > - `slsa/v2alpha3` corresponds to the slsav1.0 spec. and uses latest [`v1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1). Recommended format for new chains users who want the slsav1.0 spec. diff --git a/pkg/chains/formats/all/all.go b/pkg/chains/formats/all/all.go index 2d15efc893..0ba9226420 100644 --- a/pkg/chains/formats/all/all.go +++ b/pkg/chains/formats/all/all.go @@ -17,7 +17,5 @@ package all import ( _ "github.com/tektoncd/chains/pkg/chains/formats/simple" _ "github.com/tektoncd/chains/pkg/chains/formats/slsa/v1" - _ "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha1" - _ "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2" _ "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha3" ) diff --git a/pkg/chains/formats/format.go b/pkg/chains/formats/format.go index fccb396853..00c3990cda 100644 --- a/pkg/chains/formats/format.go +++ b/pkg/chains/formats/format.go @@ -32,8 +32,6 @@ const ( PayloadTypeSimpleSigning config.PayloadType = "simplesigning" PayloadTypeInTotoIte6 config.PayloadType = "in-toto" PayloadTypeSlsav1 config.PayloadType = "slsa/v1" - PayloadTypeSlsav2alpha1 config.PayloadType = "slsa/v2alpha1" - PayloadTypeSlsav2alpha2 config.PayloadType = "slsa/v2alpha2" PayloadTypeSlsav2alpha3 config.PayloadType = "slsa/v2alpha3" ) @@ -41,8 +39,6 @@ var ( IntotoAttestationSet = map[config.PayloadType]struct{}{ PayloadTypeInTotoIte6: {}, PayloadTypeSlsav1: {}, - PayloadTypeSlsav2alpha1: {}, - PayloadTypeSlsav2alpha2: {}, PayloadTypeSlsav2alpha3: {}, } payloaderMap = map[config.PayloadType]PayloaderInit{} diff --git a/pkg/chains/formats/slsa/README.md b/pkg/chains/formats/slsa/README.md index 3c50c07235..41d4757471 100644 --- a/pkg/chains/formats/slsa/README.md +++ b/pkg/chains/formats/slsa/README.md @@ -12,5 +12,6 @@ Shown below is the mapping between Tekton chains proveance and SLSA predicate. |Tekton Chains Provenance Format version | SLSA predicate | Notes | |:------------------------------------------|---------------:|------:| |**slsa/v1**| **slsa v0.2** | same as currently supported `in-toto` format| -|**slsa/v2alpha1**| **slsa v0.2** | contains complete build instructions as in [TEP0122](https://github.com/tektoncd/community/pull/820). This is still a WIP and currently only available for taskrun level provenance. | -|**slsa/v2alpha2**| **slsa v1.0** | contains SLSAv1.0 predicate. The parameters are complete. Support still needs to be added for surfacing builder version and builder dependencies information.| +|**slsa/v2alpha1** [DEPRECATED]| **slsa v0.2** | contains complete build instructions as in [TEP0122](https://github.com/tektoncd/community/pull/820). This is still a WIP and currently only available for taskrun level provenance. | +|**slsa/v2alpha2** [DEPRECATED]| **slsa v1.0** | contains SLSAv1.0 predicate. The parameters are complete. Support still needs to be added for surfacing builder version and builder dependencies information.| +|**slsa/v2alpha3**| **slsa v1.0** | contains SLSAv1.0 predicate. The parameters are complete. Support still needs to be added for surfacing builder version and builder dependencies information. Support for V1 Tekton Objects| diff --git a/pkg/chains/formats/slsa/v2alpha1/README.md b/pkg/chains/formats/slsa/v2alpha1/README.md deleted file mode 100644 index fe0060aa26..0000000000 --- a/pkg/chains/formats/slsa/v2alpha1/README.md +++ /dev/null @@ -1,383 +0,0 @@ -# Provenance Format Example for slsa/v2alpha1 -When running the following taskrun with bundle resolver referencing the [remote task](https://github.com/tektoncd/catalog/tree/main/task/git-clone/0.9): - -```yaml -apiVersion: tekton.dev/v1 -kind: TaskRun -metadata: - generateName: bundles-resolver- -spec: - workspaces: - - name: output - emptyDir: {} - podTemplate: - securityContext: - fsGroup: 65532 - taskRef: - resolver: bundles - params: - - name: bundle - value: gcr.io/tekton-releases/catalog/upstream/git-clone:0.9 - - name: name - value: git-clone - - name: kind - value: task - params: - - name: url - value: https://github.com/kelseyhightower/nocode - - name: revision - value: master -``` - -The following output was generated. Notice the following below: -1. `ConfigSource` is correctly populated. -2. `Invocation.Parameters` contains `workspaces and podTemplate` from above spec correctly populated. -3. `Invocation.Environment` contains `tekton-pipelines-feature-flags` to indicate which feature flags were enabled during the taskrun. -4. `BuildConfig` contains the resolved `taskSpec`. - -```json -{ - "_type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v0.2", - "subject": null, - "predicate": { - "builder": { - "id": "https://tekton.dev/chains/v2" - }, - "buildType": "https://chains.tekton.dev/format/slsa/v2alpha1/type/tekton.dev/v1/TaskRun", - "invocation": { - "configSource": { - "uri": "gcr.io/tekton-releases/catalog/upstream/git-clone", - "digest": { - "sha256": "1ee0f45892faf152aa631b0745f192e353c684408286bc55e9041edfaf22cb5e" - }, - "entryPoint": "git-clone" - }, - "parameters": { - "ComputeResources": null, - "Debug": null, - "Params": [ - { - "name": "url", - "value": "https://github.com/kelseyhightower/nocode" - }, - { - "name": "revision", - "value": "master" - } - ], - "PodTemplate": { - "securityContext": { - "fsGroup": 65532 - } - }, - "Resources": null, - "Retries": 0, - "ServiceAccountName": "default", - "SidecarOverrides": null, - "Status": "", - "StatusMessage": "", - "StepOverrides": null, - "Timeout": "1h0m0s", - "Workspaces": [ - { - "name": "output", - "emptyDir": {} - } - ] - }, - "environment": { - "tekton-pipelines-feature-flags": { - "DisableAffinityAssistant": false, - "DisableCredsInit": false, - "RunningInEnvWithInjectedSidecars": true, - "RequireGitSSHSecretKnownHosts": false, - "EnableTektonOCIBundles": true, - "ScopeWhenExpressionsToTask": false, - "EnableAPIFields": "alpha", - "SendCloudEventsForRuns": false, - "AwaitSidecarReadiness": true, - "EnforceNonfalsifiability": "", - "ResourceVerificationMode": "skip", - "EnableProvenanceInStatus": true, - "ResultExtractionMethod": "termination-message", - "MaxResultSize": 4096, - "CustomTaskVersion": "v1" - } - } - }, - "buildConfig": { - "taskSpec": { - "params": [ - { - "name": "url", - "type": "string", - "description": "Repository URL to clone from." - }, - { - "name": "revision", - "type": "string", - "description": "Revision to checkout. (branch, tag, sha, ref, etc...)", - "default": "" - }, - { - "name": "refspec", - "type": "string", - "description": "Refspec to fetch before checking out revision.", - "default": "" - }, - { - "name": "submodules", - "type": "string", - "description": "Initialize and fetch git submodules.", - "default": "true" - }, - { - "name": "depth", - "type": "string", - "description": "Perform a shallow clone, fetching only the most recent N commits.", - "default": "1" - }, - { - "name": "sslVerify", - "type": "string", - "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.", - "default": "true" - }, - { - "name": "crtFileName", - "type": "string", - "description": "file name of mounted crt using ssl-ca-directory workspace. default value is ca-bundle.crt.", - "default": "ca-bundle.crt" - }, - { - "name": "subdirectory", - "type": "string", - "description": "Subdirectory inside the `output` Workspace to clone the repo into.", - "default": "" - }, - { - "name": "sparseCheckoutDirectories", - "type": "string", - "description": "Define the directory patterns to match or exclude when performing a sparse checkout.", - "default": "" - }, - { - "name": "deleteExisting", - "type": "string", - "description": "Clean out the contents of the destination directory if it already exists before cloning.", - "default": "true" - }, - { - "name": "httpProxy", - "type": "string", - "description": "HTTP proxy server for non-SSL requests.", - "default": "" - }, - { - "name": "httpsProxy", - "type": "string", - "description": "HTTPS proxy server for SSL requests.", - "default": "" - }, - { - "name": "noProxy", - "type": "string", - "description": "Opt out of proxying HTTP/HTTPS requests.", - "default": "" - }, - { - "name": "verbose", - "type": "string", - "description": "Log the commands that are executed during `git-clone`'s operation.", - "default": "true" - }, - { - "name": "gitInitImage", - "type": "string", - "description": "The image providing the git-init binary that this Task runs.", - "default": "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.40.2" - }, - { - "name": "userHome", - "type": "string", - "description": "Absolute path to the user's home directory.\n", - "default": "/home/git" - } - ], - "description": "These Tasks are Git tasks to work with repositories used by other tasks in your Pipeline.\nThe 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. You can clone into a subdirectory by setting this Task's subdirectory param. This Task also supports sparse checkouts. To perform a sparse checkout, pass a list of comma separated directory patterns to this Task's sparseCheckoutDirectories param.", - "steps": [ - { - "name": "clone", - "image": "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init:v0.40.2", - "env": [ - { - "name": "HOME", - "value": "/home/git" - }, - { - "name": "PARAM_URL", - "value": "https://github.com/kelseyhightower/nocode" - }, - { - "name": "PARAM_REVISION", - "value": "master" - }, - { - "name": "PARAM_REFSPEC" - }, - { - "name": "PARAM_SUBMODULES", - "value": "true" - }, - { - "name": "PARAM_DEPTH", - "value": "1" - }, - { - "name": "PARAM_SSL_VERIFY", - "value": "true" - }, - { - "name": "PARAM_CRT_FILENAME", - "value": "ca-bundle.crt" - }, - { - "name": "PARAM_SUBDIRECTORY" - }, - { - "name": "PARAM_DELETE_EXISTING", - "value": "true" - }, - { - "name": "PARAM_HTTP_PROXY" - }, - { - "name": "PARAM_HTTPS_PROXY" - }, - { - "name": "PARAM_NO_PROXY" - }, - { - "name": "PARAM_VERBOSE", - "value": "true" - }, - { - "name": "PARAM_SPARSE_CHECKOUT_DIRECTORIES" - }, - { - "name": "PARAM_USER_HOME", - "value": "/home/git" - }, - { - "name": "WORKSPACE_OUTPUT_PATH", - "value": "/workspace/output" - }, - { - "name": "WORKSPACE_SSH_DIRECTORY_BOUND", - "value": "false" - }, - { - "name": "WORKSPACE_SSH_DIRECTORY_PATH" - }, - { - "name": "WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND", - "value": "false" - }, - { - "name": "WORKSPACE_BASIC_AUTH_DIRECTORY_PATH" - }, - { - "name": "WORKSPACE_SSL_CA_DIRECTORY_BOUND", - "value": "false" - }, - { - "name": "WORKSPACE_SSL_CA_DIRECTORY_PATH" - } - ], - "resources": {}, - "securityContext": { - "runAsUser": 65532, - "runAsNonRoot": true - }, - "script": "#!/usr/bin/env sh\nset -eu\n\nif [ \"${PARAM_VERBOSE}\" = \"true\" ] ; then\n set -x\nfi\n\nif [ \"${WORKSPACE_BASIC_AUTH_DIRECTORY_BOUND}\" = \"true\" ] ; then\n cp \"${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.git-credentials\" \"${PARAM_USER_HOME}/.git-credentials\"\n cp \"${WORKSPACE_BASIC_AUTH_DIRECTORY_PATH}/.gitconfig\" \"${PARAM_USER_HOME}/.gitconfig\"\n chmod 400 \"${PARAM_USER_HOME}/.git-credentials\"\n chmod 400 \"${PARAM_USER_HOME}/.gitconfig\"\nfi\n\nif [ \"${WORKSPACE_SSH_DIRECTORY_BOUND}\" = \"true\" ] ; then\n cp -R \"${WORKSPACE_SSH_DIRECTORY_PATH}\" \"${PARAM_USER_HOME}\"/.ssh\n chmod 700 \"${PARAM_USER_HOME}\"/.ssh\n chmod -R 400 \"${PARAM_USER_HOME}\"/.ssh/*\nfi\n\nif [ \"${WORKSPACE_SSL_CA_DIRECTORY_BOUND}\" = \"true\" ] ; then\n export GIT_SSL_CAPATH=\"${WORKSPACE_SSL_CA_DIRECTORY_PATH}\"\n if [ \"${PARAM_CRT_FILENAME}\" != \"\" ] ; then\n export GIT_SSL_CAINFO=\"${WORKSPACE_SSL_CA_DIRECTORY_PATH}/${PARAM_CRT_FILENAME}\"\n fi\nfi\nCHECKOUT_DIR=\"${WORKSPACE_OUTPUT_PATH}/${PARAM_SUBDIRECTORY}\"\n\ncleandir() {\n # Delete any existing contents of the repo directory if it exists.\n #\n # We don't just \"rm -rf ${CHECKOUT_DIR}\" because ${CHECKOUT_DIR} might be \"/\"\n # or the root of a mounted volume.\n if [ -d \"${CHECKOUT_DIR}\" ] ; then\n # Delete non-hidden files and directories\n rm -rf \"${CHECKOUT_DIR:?}\"/*\n # Delete files and directories starting with . but excluding ..\n rm -rf \"${CHECKOUT_DIR}\"/.[!.]*\n # Delete files and directories starting with .. plus any other character\n rm -rf \"${CHECKOUT_DIR}\"/..?*\n fi\n}\n\nif [ \"${PARAM_DELETE_EXISTING}\" = \"true\" ] ; then\n cleandir || true\nfi\n\ntest -z \"${PARAM_HTTP_PROXY}\" || export HTTP_PROXY=\"${PARAM_HTTP_PROXY}\"\ntest -z \"${PARAM_HTTPS_PROXY}\" || export HTTPS_PROXY=\"${PARAM_HTTPS_PROXY}\"\ntest -z \"${PARAM_NO_PROXY}\" || export NO_PROXY=\"${PARAM_NO_PROXY}\"\n\ngit config --global --add safe.directory \"${WORKSPACE_OUTPUT_PATH}\"\n/ko-app/git-init \\\n -url=\"${PARAM_URL}\" \\\n -revision=\"${PARAM_REVISION}\" \\\n -refspec=\"${PARAM_REFSPEC}\" \\\n -path=\"${CHECKOUT_DIR}\" \\\n -sslVerify=\"${PARAM_SSL_VERIFY}\" \\\n -submodules=\"${PARAM_SUBMODULES}\" \\\n -depth=\"${PARAM_DEPTH}\" \\\n -sparseCheckoutDirectories=\"${PARAM_SPARSE_CHECKOUT_DIRECTORIES}\"\ncd \"${CHECKOUT_DIR}\"\nRESULT_SHA=\"$(git rev-parse HEAD)\"\nEXIT_CODE=\"$?\"\nif [ \"${EXIT_CODE}\" != 0 ] ; then\n exit \"${EXIT_CODE}\"\nfi\nRESULT_COMMITTER_DATE=\"$(git log -1 --pretty=%ct)\"\nprintf \"%s\" \"${RESULT_COMMITTER_DATE}\" > \"/tekton/results/committer-date\"\nprintf \"%s\" \"${RESULT_SHA}\" > \"/tekton/results/commit\"\nprintf \"%s\" \"${PARAM_URL}\" > \"/tekton/results/url\"\n" - } - ], - "workspaces": [ - { - "name": "output", - "description": "The git repo will be cloned onto the volume backing this Workspace." - }, - { - "name": "ssh-directory", - "description": "A .ssh directory with private key, known_hosts, config, etc. Copied to\nthe user's home before git commands are executed. Used to authenticate\nwith the git remote when performing the clone. Binding a Secret to this\nWorkspace is strongly recommended over other volume types.\n", - "optional": true - }, - { - "name": "basic-auth", - "description": "A Workspace containing a .gitconfig and .git-credentials file. These\nwill be copied to the user's home before any git commands are run. Any\nother files in this Workspace are ignored. It is strongly recommended\nto use ssh-directory over basic-auth whenever possible and to bind a\nSecret to this Workspace over other volume types.\n", - "optional": true - }, - { - "name": "ssl-ca-directory", - "description": "A workspace containing CA certificates, this will be used by Git to\nverify the peer with when fetching or pushing over HTTPS.\n", - "optional": true - } - ], - "results": [ - { - "name": "commit", - "type": "string", - "description": "The precise commit SHA that was fetched by this Task." - }, - { - "name": "url", - "type": "string", - "description": "The precise URL that was fetched by this Task." - }, - { - "name": "committer-date", - "type": "string", - "description": "The epoch timestamp of the commit that was fetched by this Task." - } - ] - }, - "taskRunResults": [ - { - "name": "commit", - "type": "string", - "value": "6c073b08f7987018cbb2cb9a5747c84913b3608e" - }, - { - "name": "committer-date", - "type": "string", - "value": "1579634710" - }, - { - "name": "url", - "type": "string", - "value": "https://github.com/kelseyhightower/nocode" - } - ] - }, - "metadata": { - "buildStartedOn": "2023-02-24T03:34:21Z", - "buildFinishedOn": "2023-02-24T03:34:27Z", - "completeness": { - "parameters": false, - "environment": false, - "materials": false - }, - "reproducible": false - }, - "materials": [ - { - "uri": "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", - "digest": { - "sha256": "28ff94e63e4058afc3f15b4c11c08cf3b54fa91faa646a4bbac90380cd7158df" - } - } - ] - } -} -``` diff --git a/pkg/chains/formats/slsa/v2alpha1/slsav2.go b/pkg/chains/formats/slsa/v2alpha1/slsav2.go deleted file mode 100644 index 30bd808971..0000000000 --- a/pkg/chains/formats/slsa/v2alpha1/slsav2.go +++ /dev/null @@ -1,72 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v2alpha1 - -import ( - "context" - "fmt" - - "github.com/tektoncd/chains/pkg/chains/formats" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha1/taskrun" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/config" - v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" -) - -const ( - PayloadTypeSlsav2alpha1 = formats.PayloadTypeSlsav2alpha1 -) - -func init() { - formats.RegisterPayloader(PayloadTypeSlsav2alpha1, NewFormatter) -} - -type Slsa struct { - builderID string -} - -func NewFormatter(cfg config.Config) (formats.Payloader, error) { - return &Slsa{ - builderID: cfg.Builder.ID, - }, nil -} - -func (s *Slsa) Wrap() bool { - return true -} - -func (s *Slsa) CreatePayload(ctx context.Context, obj interface{}) (interface{}, error) { - switch v := obj.(type) { - case *objects.TaskRunObjectV1: - tro := obj.(*objects.TaskRunObjectV1) - trV1Beta1 := &v1beta1.TaskRun{} //nolint:staticcheck - if err := trV1Beta1.ConvertFrom(ctx, tro.GetObject().(*v1.TaskRun)); err != nil { - return nil, fmt.Errorf("error converting Tekton TaskRun from version v1 to v1beta1: %s", err) - } - return taskrun.GenerateAttestation(ctx, s.builderID, s.Type(), objects.NewTaskRunObjectV1Beta1(trV1Beta1)) - case *objects.TaskRunObjectV1Beta1: - return taskrun.GenerateAttestation(ctx, s.builderID, s.Type(), v) - - default: - return nil, fmt.Errorf("intoto does not support type: %s", v) - } -} - -func (s *Slsa) Type() config.PayloadType { - return formats.PayloadTypeSlsav2alpha1 -} diff --git a/pkg/chains/formats/slsa/v2alpha1/slsav2_test.go b/pkg/chains/formats/slsa/v2alpha1/slsav2_test.go deleted file mode 100644 index 7055377d00..0000000000 --- a/pkg/chains/formats/slsa/v2alpha1/slsav2_test.go +++ /dev/null @@ -1,422 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v2alpha1 - -import ( - "testing" - "time" - - "github.com/tektoncd/chains/pkg/artifacts" - "github.com/tektoncd/chains/pkg/chains/formats" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha1/taskrun" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/config" - "github.com/tektoncd/chains/pkg/internal/objectloader" - corev1 "k8s.io/api/core/v1" - v1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - - "github.com/google/go-cmp/cmp" - "github.com/in-toto/in-toto-golang/in_toto" - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - logtesting "knative.dev/pkg/logging/testing" -) - -var ( - e1BuildStart = time.Unix(1617011400, 0) - e1BuildFinished = time.Unix(1617011415, 0) -) - -func TestTaskRunCreatePayload1(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - - tr, err := objectloader.TaskRunV1Beta1FromFile("../testdata/pipeline-v1beta1/taskrun1.json") - if err != nil { - t.Fatal(err) - } - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "test_builder-1", - }, - } - expected := in_toto.ProvenanceStatement{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: []in_toto.Subject{ - { - Name: "gcr.io/my/image", - Digest: common.DigestSet{ - "sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7", - }, - }, - }, - }, - Predicate: slsa.ProvenancePredicate{ - Metadata: &slsa.ProvenanceMetadata{ - BuildStartedOn: &e1BuildStart, - BuildFinishedOn: &e1BuildFinished, - Completeness: slsa.ProvenanceComplete{ - Parameters: true, - }, - }, - Materials: []common.ProvenanceMaterial{ - { - URI: artifacts.OCIScheme + "gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - { - URI: artifacts.OCIScheme + "gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: artifacts.OCIScheme + "gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - {URI: artifacts.GitSchemePrefix + "https://git.test.com.git", Digest: common.DigestSet{"sha1": "sha:taskrun"}}, - }, - Invocation: slsa.ProvenanceInvocation{ - ConfigSource: slsa.ConfigSource{ - URI: "github.com/test", - Digest: map[string]string{"sha1": "ab123"}, - EntryPoint: "build.yaml", - }, - Parameters: map[string]any{ - "ComputeResources": (*corev1.ResourceRequirements)(nil), - "Debug": (*v1beta1.TaskRunDebug)(nil), - "Params": v1beta1.Params{ - { - Name: "IMAGE", - Value: v1beta1.ParamValue{Type: "string", StringVal: "test.io/test/image"}, - }, - { - Name: "CHAINS-GIT_COMMIT", - Value: v1beta1.ParamValue{Type: "string", StringVal: "sha:taskrun"}, - }, - { - Name: "CHAINS-GIT_URL", - Value: v1beta1.ParamValue{Type: "string", StringVal: "https://git.test.com"}, - }, - }, - "PodTemplate": (*pod.Template)(nil), - "Resources": (*v1beta1.TaskRunResources)(nil), //nolint:staticcheck - "Retries": 0, - "ServiceAccountName": "default", - "SidecarOverrides": []v1beta1.TaskRunSidecarOverride(nil), - "Status": v1beta1.TaskRunSpecStatus(""), - "StatusMessage": v1beta1.TaskRunSpecStatusMessage(""), - "StepOverrides": []v1beta1.TaskRunStepOverride(nil), - "Timeout": (*metav1.Duration)(nil), - "Workspaces": []v1beta1.WorkspaceBinding(nil), - }, - }, - Builder: common.ProvenanceBuilder{ - ID: "test_builder-1", - }, - BuildType: "https://chains.tekton.dev/format/slsa/v2alpha1/type/tekton.dev/v1beta1/TaskRun", - BuildConfig: taskrun.BuildConfig{ - TaskSpec: &v1beta1.TaskSpec{ - Params: []v1beta1.ParamSpec{ - {Name: "IMAGE", Type: "string"}, {Name: "filename", Type: "string"}, - {Name: "DOCKERFILE", Type: "string"}, {Name: "CONTEXT", Type: "string"}, - {Name: "EXTRA_ARGS", Type: "string"}, {Name: "BUILDER_IMAGE", Type: "string"}, - {Name: "CHAINS-GIT_COMMIT", Type: "string", Default: &v1beta1.ParamValue{Type: "string", StringVal: "sha:task"}}, - {Name: "CHAINS-GIT_URL", Type: "string", Default: &v1beta1.ParamValue{Type: "string", StringVal: "https://defaultgit.test.com"}}, - }, - Steps: []v1beta1.Step{{Name: "step1"}, {Name: "step2"}, {Name: "step3"}}, - Results: []v1beta1.TaskResult{ - {Name: "IMAGE_DIGEST", Description: "Digest of the image just built."}, - {Name: "filename_DIGEST", Description: "Digest of the file just built."}, - }, - }, - TaskRunResults: []v1beta1.TaskRunResult{ - { - Name: "IMAGE_DIGEST", - Value: v1beta1.ParamValue{Type: "string", StringVal: "sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}, - }, - { - Name: "IMAGE_URL", - Value: v1beta1.ParamValue{Type: "string", StringVal: "gcr.io/my/image"}, - }, - }, - }, - }, - } - i, _ := NewFormatter(cfg) - - got, err := i.CreatePayload(ctx, objects.NewTaskRunObjectV1Beta1(tr)) - - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - if diff := cmp.Diff(expected, got); diff != "" { - t.Errorf("Slsa.CreatePayload(): -want +got: %s", diff) - } -} - -func TestTaskRunCreatePayload2(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - tr, err := objectloader.TaskRunV1Beta1FromFile("../testdata/pipeline-v1beta1/taskrun2.json") - if err != nil { - t.Fatal(err) - } - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "test_builder-2", - }, - } - expected := in_toto.ProvenanceStatement{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: nil, - }, - Predicate: slsa.ProvenancePredicate{ - Metadata: &slsa.ProvenanceMetadata{ - BuildStartedOn: &e1BuildStart, - BuildFinishedOn: &e1BuildFinished, - Completeness: slsa.ProvenanceComplete{ - Parameters: true, - }, - }, - Builder: common.ProvenanceBuilder{ - ID: "test_builder-2", - }, - Materials: []common.ProvenanceMaterial{ - { - URI: artifacts.OCIScheme + "gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {URI: artifacts.GitSchemePrefix + "https://git.test.com.git", Digest: common.DigestSet{"sha1": "sha:taskdefault"}}, - }, - Invocation: slsa.ProvenanceInvocation{ - ConfigSource: slsa.ConfigSource{ - URI: "github.com/catalog", - Digest: common.DigestSet{"sha1": "x123"}, - EntryPoint: "git-clone.yaml", - }, - Parameters: map[string]any{ - "ComputeResources": (*corev1.ResourceRequirements)(nil), - "Debug": (*v1beta1.TaskRunDebug)(nil), - "Params": v1beta1.Params{ - { - Name: "url", - Value: v1beta1.ParamValue{Type: "string", StringVal: "https://git.test.com"}, - }, - {Name: "revision", Value: v1beta1.ParamValue{Type: "string"}}, - }, - "PodTemplate": (*pod.Template)(nil), - "Resources": (*v1beta1.TaskRunResources)(nil), //nolint:staticcheck - "Retries": 0, - "ServiceAccountName": "default", - "SidecarOverrides": []v1beta1.TaskRunSidecarOverride(nil), - "Status": v1beta1.TaskRunSpecStatus(""), - "StatusMessage": v1beta1.TaskRunSpecStatusMessage(""), - "StepOverrides": []v1beta1.TaskRunStepOverride(nil), - "Timeout": (*metav1.Duration)(nil), - "Workspaces": []v1beta1.WorkspaceBinding(nil), - }, - }, - BuildType: "https://chains.tekton.dev/format/slsa/v2alpha1/type/tekton.dev/v1beta1/TaskRun", - BuildConfig: taskrun.BuildConfig{ - TaskSpec: &v1beta1.TaskSpec{ - Params: []v1beta1.ParamSpec{ - {Name: "CHAINS-GIT_COMMIT", Type: "string", Default: &v1beta1.ParamValue{Type: "string", StringVal: "sha:taskdefault"}}, - {Name: "CHAINS-GIT_URL", Type: "string", Default: &v1beta1.ParamValue{Type: "string", StringVal: "https://git.test.com"}}, - }, - Steps: []v1beta1.Step{{Name: "step1", Env: []v1.EnvVar{{Name: "HOME", Value: "$(params.userHome)"}, {Name: "PARAM_URL", Value: "$(params.url)"}}, Script: "git clone"}}, - Results: []v1beta1.TaskResult{ - {Name: "some-uri_DIGEST", Description: "Digest of a file to push."}, - {Name: "some-uri", Description: "some calculated uri"}, - }, - }, - TaskRunResults: []v1beta1.TaskRunResult{ - { - Name: "some-uri_DIGEST", - Value: v1beta1.ParamValue{Type: "string", StringVal: "sha256:d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - { - Name: "some-uri", - Value: v1beta1.ParamValue{Type: "string", StringVal: "pkg:deb/debian/curl@7.50.3-1"}, - }, - }, - }, - }, - } - i, _ := NewFormatter(cfg) - got, err := i.CreatePayload(ctx, objects.NewTaskRunObjectV1Beta1(tr)) - - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - if diff := cmp.Diff(expected, got); diff != "" { - t.Errorf("Slsa.CreatePayload(): -want +got: %s", diff) - } -} - -func TestMultipleSubjects(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - - tr, err := objectloader.TaskRunV1Beta1FromFile("../testdata/pipeline-v1beta1/taskrun-multiple-subjects.json") - if err != nil { - t.Fatal(err) - } - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "test_builder-multiple", - }, - } - expected := in_toto.ProvenanceStatement{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: []in_toto.Subject{ - { - Name: "gcr.io/myimage1", - Digest: common.DigestSet{ - "sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6", - }, - }, { - Name: "gcr.io/myimage2", - Digest: common.DigestSet{ - "sha256": "daa1a56e13c85cf164e7d9e595006649e3a04c47fe4a8261320e18a0bf3b0367", - }, - }, - }, - }, - Predicate: slsa.ProvenancePredicate{ - BuildType: "https://chains.tekton.dev/format/slsa/v2alpha1/type/tekton.dev/v1beta1/TaskRun", - Metadata: &slsa.ProvenanceMetadata{ - Completeness: slsa.ProvenanceComplete{ - Parameters: true, - }, - }, - Builder: common.ProvenanceBuilder{ - ID: "test_builder-multiple", - }, - Materials: []common.ProvenanceMaterial{ - { - URI: artifacts.OCIScheme + "gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - }, - Invocation: slsa.ProvenanceInvocation{ - Parameters: map[string]any{ - "ComputeResources": (*corev1.ResourceRequirements)(nil), - "Debug": (*v1beta1.TaskRunDebug)(nil), - "Params": v1beta1.Params{}, - "PodTemplate": (*pod.Template)(nil), - "Resources": (*v1beta1.TaskRunResources)(nil), //nolint:staticcheck - "Retries": 0, - "ServiceAccountName": "default", - "SidecarOverrides": []v1beta1.TaskRunSidecarOverride(nil), - "Status": v1beta1.TaskRunSpecStatus(""), - "StatusMessage": v1beta1.TaskRunSpecStatusMessage(""), - "StepOverrides": []v1beta1.TaskRunStepOverride(nil), - "Timeout": (*metav1.Duration)(nil), - "Workspaces": []v1beta1.WorkspaceBinding(nil), - }, - }, - BuildConfig: taskrun.BuildConfig{ - TaskSpec: &v1beta1.TaskSpec{ - Params: []v1beta1.ParamSpec{}, - Results: []v1beta1.TaskResult{ - {Name: "file1_DIGEST", Description: "Digest of a file to push."}, - {Name: "file1", Description: "some assembled file"}, - {Name: "file2_DIGEST", Description: "Digest of a file to push."}, - {Name: "file2", Description: "some assembled file"}, - }, - }, - TaskRunResults: []v1beta1.TaskRunResult{ - { - Name: "IMAGES", - Value: v1beta1.ParamValue{ - Type: "string", - StringVal: "gcr.io/myimage1@sha256:d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6,gcr.io/myimage2@sha256:daa1a56e13c85cf164e7d9e595006649e3a04c47fe4a8261320e18a0bf3b0367", - }, - }, - }, - }, - }, - } - - i, _ := NewFormatter(cfg) - got, err := i.CreatePayload(ctx, objects.NewTaskRunObjectV1Beta1(tr)) - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - if diff := cmp.Diff(expected, got); diff != "" { - t.Errorf("Slsa.CreatePayload(): -want +got: %s", diff) - } -} - -func TestNewFormatter(t *testing.T) { - t.Run("Ok", func(t *testing.T) { - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "testid", - }, - } - f, err := NewFormatter(cfg) - if f == nil { - t.Error("Failed to create formatter") - } - if err != nil { - t.Errorf("Error creating formatter: %s", err) - } - }) -} - -func TestCreatePayloadError(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "testid", - }, - } - f, _ := NewFormatter(cfg) - - t.Run("Invalid type", func(t *testing.T) { - p, err := f.CreatePayload(ctx, "not a task ref") - - if p != nil { - t.Errorf("Unexpected payload") - } - if err == nil { - t.Errorf("Expected error") - } else { - if err.Error() != "intoto does not support type: not a task ref" { - t.Errorf("wrong error returned: '%s'", err.Error()) - } - } - }) - -} - -func TestCorrectPayloadType(t *testing.T) { - var i Slsa - if i.Type() != formats.PayloadTypeSlsav2alpha1 { - t.Errorf("Invalid type returned: %s", i.Type()) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun.go b/pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun.go deleted file mode 100644 index fe63e4f019..0000000000 --- a/pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun.go +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright 2022 The Tekton Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package taskrun - -import ( - "context" - "fmt" - "reflect" - - intoto "github.com/in-toto/in-toto-golang/in_toto" - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" - materialv1beta1 "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/material/v1beta1" - slsav1 "github.com/tektoncd/chains/pkg/chains/formats/slsa/v1/taskrun" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/config" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - "k8s.io/apimachinery/pkg/util/sets" -) - -// BuildConfig is the custom Chains format to fill out the -// "buildConfig" section of the slsa-provenance predicate -type BuildConfig struct { - TaskSpec *v1beta1.TaskSpec `json:"taskSpec"` - TaskRunResults []v1beta1.TaskRunResult `json:"taskRunResults"` -} - -func GenerateAttestation(ctx context.Context, builderID string, payloadType config.PayloadType, tro *objects.TaskRunObjectV1Beta1) (interface{}, error) { - subjects := extract.SubjectDigests(ctx, tro, nil) - mat, err := materialv1beta1.TaskMaterials(ctx, tro) - if err != nil { - return nil, err - } - att := intoto.ProvenanceStatement{ - StatementHeader: intoto.StatementHeader{ - Type: intoto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: subjects, - }, - Predicate: slsa.ProvenancePredicate{ - Builder: common.ProvenanceBuilder{ - ID: builderID, - }, - BuildType: fmt.Sprintf("https://chains.tekton.dev/format/%v/type/%s", payloadType, tro.GetGVK()), - Invocation: invocation(tro), - BuildConfig: BuildConfig{TaskSpec: tro.Status.TaskSpec, TaskRunResults: tro.Status.TaskRunResults}, - Metadata: metadata(tro), - Materials: mat, - }, - } - return att, nil -} - -func metadata(tro *objects.TaskRunObjectV1Beta1) *slsa.ProvenanceMetadata { - m := slsav1.Metadata(tro) - m.Completeness = slsa.ProvenanceComplete{ - Parameters: true, - } - return m -} - -// invocation describes the event that kicked off the build -// we currently don't set ConfigSource because we don't know -// which material the Task definition came from -func invocation(tro *objects.TaskRunObjectV1Beta1) slsa.ProvenanceInvocation { - i := slsa.ProvenanceInvocation{} - if p := tro.Status.Provenance; p != nil && p.RefSource != nil { - i.ConfigSource = slsa.ConfigSource{ - URI: p.RefSource.URI, - Digest: p.RefSource.Digest, - EntryPoint: p.RefSource.EntryPoint, - } - } - i.Parameters = invocationParams(tro) - env := invocationEnv(tro) - if len(env) > 0 { - i.Environment = env - } - return i -} - -// invocationEnv adds the tekton feature flags that were enabled -// for the taskrun. In the future, we can populate versioning information -// here as well. -func invocationEnv(tro *objects.TaskRunObjectV1Beta1) map[string]any { - var iEnv map[string]any = make(map[string]any) - if tro.Status.Provenance != nil && tro.Status.Provenance.FeatureFlags != nil { - iEnv["tekton-pipelines-feature-flags"] = tro.Status.Provenance.FeatureFlags - } - return iEnv -} - -// invocationParams adds all fields from the task run object except -// TaskRef or TaskSpec since they are in the ConfigSource or buildConfig. -func invocationParams(tro *objects.TaskRunObjectV1Beta1) map[string]any { - var iParams map[string]any = make(map[string]any) - skipFields := sets.NewString("TaskRef", "TaskSpec") - v := reflect.ValueOf(tro.Spec) - for i := 0; i < v.NumField(); i++ { - fieldName := v.Type().Field(i).Name - if !skipFields.Has(v.Type().Field(i).Name) { - iParams[fieldName] = v.Field(i).Interface() - } - } - return iParams -} diff --git a/pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun_test.go b/pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun_test.go deleted file mode 100644 index 2aff0c355d..0000000000 --- a/pkg/chains/formats/slsa/v2alpha1/taskrun/taskrun_test.go +++ /dev/null @@ -1,367 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package taskrun - -import ( - "reflect" - "strings" - "testing" - "time" - - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v0.2" - - "github.com/google/go-cmp/cmp" - "github.com/in-toto/in-toto-golang/in_toto" - "github.com/tektoncd/chains/internal/backport" - "github.com/tektoncd/chains/pkg/artifacts" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/compare" - slsav1 "github.com/tektoncd/chains/pkg/chains/formats/slsa/v1/taskrun" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/pipeline/pkg/apis/config" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/pod" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" - corev1 "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - logtesting "knative.dev/pkg/logging/testing" - "sigs.k8s.io/yaml" -) - -const ( - digest1 = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5" - digest2 = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b6" - digest3 = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b7" - digest4 = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b8" - digest5 = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b9" -) - -func TestMetadata(t *testing.T) { - tr := &v1beta1.TaskRun{ //nolint:staticcheck - ObjectMeta: v1.ObjectMeta{ - Name: "my-taskrun", - Namespace: "my-namespace", - Annotations: map[string]string{ - "chains.tekton.dev/reproducible": "true", - }, - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - StartTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)}, - CompletionTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)}, - }, - }, - } - start := time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC) - end := time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC) - expected := &slsa.ProvenanceMetadata{ - BuildStartedOn: &start, - BuildFinishedOn: &end, - } - got := slsav1.Metadata(objects.NewTaskRunObjectV1Beta1(tr)) - if !reflect.DeepEqual(expected, got) { - t.Fatalf("expected %v got %v", expected, got) - } -} - -func TestMetadataInTimeZone(t *testing.T) { - tz := time.FixedZone("Test Time", int((12 * time.Hour).Seconds())) - tr := &v1beta1.TaskRun{ //nolint:staticcheck - ObjectMeta: v1.ObjectMeta{ - Name: "my-taskrun", - Namespace: "my-namespace", - Annotations: map[string]string{ - "chains.tekton.dev/reproducible": "true", - }, - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - StartTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, tz)}, - CompletionTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, tz)}, - }, - }, - } - start := time.Date(1995, time.December, 24, 6, 12, 12, 12, tz).UTC() - end := time.Date(1995, time.December, 24, 6, 12, 12, 24, tz).UTC() - expected := &slsa.ProvenanceMetadata{ - BuildStartedOn: &start, - BuildFinishedOn: &end, - } - got := slsav1.Metadata(objects.NewTaskRunObjectV1Beta1(tr)) - if !reflect.DeepEqual(expected, got) { - t.Fatalf("expected %v got %v", expected, got) - } -} - -func TestInvocation(t *testing.T) { - taskrun := `apiVersion: tekton.dev/v1beta1 -kind: TaskRun -metadata: - uid: my-uid -spec: - params: - - name: my-param - value: string-param - - name: my-array-param - value: - - "my" - - "array" - - name: my-empty-string-param - value: "" - - name: my-empty-array-param - value: [] -status: - taskSpec: - params: - - name: my-param - default: ignored - - name: my-array-param - type: array - default: - - "also" - - "ignored" - - name: my-default-param - default: string-default-param - - name: my-default-array-param - type: array - default: - - "array" - - "default" - - "param" - - name: my-empty-string-param - default: "ignored" - - name: my-empty-array-param - type: array - default: - - "also" - - "ignored" - - name: my-default-empty-string-param - default: "" - - name: my-default-empty-array-param - type: array - default: [] - provenance: - featureFlags: - AwaitSidecarReadiness: true - EnableAPIFields: stable - EnableProvenanceInStatus: true - MaxResultSize: 4096 - VerificationNoMatchPolicy: skip - ResultExtractionMethod: termination-message - RunningInEnvWithInjectedSidecars: true -` - - var taskRun *v1beta1.TaskRun //nolint:staticcheck - if err := yaml.Unmarshal([]byte(taskrun), &taskRun); err != nil { - t.Fatal(err) - } - - expected := slsa.ProvenanceInvocation{ - Parameters: map[string]any{ - "Params": v1beta1.Params{ - { - Name: "my-param", - Value: v1beta1.ParamValue{Type: "string", StringVal: "string-param"}, - }, - { - Name: "my-array-param", - Value: v1beta1.ParamValue{Type: "array", ArrayVal: []string{"my", "array"}}, - }, - {Name: "my-empty-string-param", Value: v1beta1.ParamValue{Type: "string"}}, - { - Name: "my-empty-array-param", - Value: v1beta1.ParamValue{Type: "array", ArrayVal: []string{}}, - }, - }, - "ComputeResources": (*corev1.ResourceRequirements)(nil), - "Debug": (*v1beta1.TaskRunDebug)(nil), - "PodTemplate": (*pod.Template)(nil), - "Resources": (*v1beta1.TaskRunResources)(nil), //nolint:staticcheck - "Retries": 0, - "ServiceAccountName": "", - "SidecarOverrides": []v1beta1.TaskRunSidecarOverride(nil), - "Status": v1beta1.TaskRunSpecStatus(""), - "StatusMessage": v1beta1.TaskRunSpecStatusMessage(""), - "StepOverrides": []v1beta1.TaskRunStepOverride(nil), - "Timeout": (*metav1.Duration)(nil), - "Workspaces": []v1beta1.WorkspaceBinding(nil), - }, - Environment: map[string]any{ - "tekton-pipelines-feature-flags": &config.FeatureFlags{ - RunningInEnvWithInjectedSidecars: true, - EnableAPIFields: "stable", - AwaitSidecarReadiness: true, - VerificationNoMatchPolicy: "skip", - EnableProvenanceInStatus: true, - ResultExtractionMethod: "termination-message", - MaxResultSize: 4096, - }, - }, - } - got := invocation(objects.NewTaskRunObjectV1Beta1(taskRun)) - if !reflect.DeepEqual(expected, got) { - if d := cmp.Diff(expected, got); d != "" { - t.Log(d) - } - t.Fatalf("expected \n%v\n got \n%v\n", expected, got) - } -} - -func TestGetSubjectDigests(t *testing.T) { - tr := &v1beta1.TaskRun{ //nolint:staticcheck - Spec: v1beta1.TaskRunSpec{ - Resources: &v1beta1.TaskRunResources{ //nolint:staticcheck - Outputs: []v1beta1.TaskResourceBinding{ //nolint:staticcheck - { - PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:staticcheck - Name: "nil-check", - }, - }, { - PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:staticcheck - Name: "built-image", - ResourceSpec: &v1alpha1.PipelineResourceSpec{ //nolint:staticcheck - Type: backport.PipelineResourceTypeImage, - }, - }, - }, - }, - }, - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - TaskRunResults: []v1beta1.TaskRunResult{ - { - Name: "IMAGE_URL", - Value: *v1beta1.NewStructuredValues("registry/myimage"), - }, - { - Name: "IMAGE_DIGEST", - Value: *v1beta1.NewStructuredValues(digest1), - }, - { - Name: "mvn1_ARTIFACT_URI", - Value: *v1beta1.NewStructuredValues("maven-test-0.1.1.jar"), - }, - { - Name: "mvn1_ARTIFACT_DIGEST", - Value: *v1beta1.NewStructuredValues(digest3), - }, - { - Name: "mvn1_pom_ARTIFACT_URI", - Value: *v1beta1.NewStructuredValues("maven-test-0.1.1.pom"), - }, - { - Name: "mvn1_pom_ARTIFACT_DIGEST", - Value: *v1beta1.NewStructuredValues(digest4), - }, - { - Name: "mvn1_src_ARTIFACT_URI", - Value: *v1beta1.NewStructuredValues("maven-test-0.1.1-sources.jar"), - }, - { - Name: "mvn1_src_ARTIFACT_DIGEST", - Value: *v1beta1.NewStructuredValues(digest5), - }, - { - Name: "invalid_ARTIFACT_DIGEST", - Value: *v1beta1.NewStructuredValues(digest5), - }, - { - Name: "mvn1_pkg" + "-" + artifacts.ArtifactsOutputsResultName, - Value: *v1beta1.NewObject(map[string]string{ - "uri": "projects/test-project-1/locations/us-west4/repositories/test-repo/mavenArtifacts/com.google.guava:guava:31.0-jre", - "digest": digest1, - }), - }, - { - Name: "mvn1_pom_sha512" + "-" + artifacts.ArtifactsOutputsResultName, - Value: *v1beta1.NewObject(map[string]string{ - "uri": "com.google.guava:guava:1.0-jre.pom", - "digest": digest2, - }), - }, - { - Name: "img1_input" + "-" + artifacts.ArtifactsInputsResultName, - Value: *v1beta1.NewObject(map[string]string{ - "uri": "gcr.io/foo/bar", - "digest": digest3, - }), - }, - }, - ResourcesResult: []v1beta1.PipelineResourceResult{ - { - ResourceName: "built-image", - Key: "url", - Value: "registry/resource-image", - }, { - ResourceName: "built-image", - Key: "digest", - Value: digest2, - }, - }, - }, - }, - } - - want := []in_toto.Subject{ - { - Name: "com.google.guava:guava:1.0-jre.pom", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest2, "sha256:"), - }, - }, { - Name: "index.docker.io/registry/myimage", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest1, "sha256:"), - }, - }, { - Name: "maven-test-0.1.1-sources.jar", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest5, "sha256:"), - }, - }, { - Name: "maven-test-0.1.1.jar", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest3, "sha256:"), - }, - }, { - Name: "maven-test-0.1.1.pom", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest4, "sha256:"), - }, - }, { - Name: "projects/test-project-1/locations/us-west4/repositories/test-repo/mavenArtifacts/com.google.guava:guava:31.0-jre", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest1, "sha256:"), - }, - }, { - Name: "registry/resource-image", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest2, "sha256:"), - }, - }, - } - tro := objects.NewTaskRunObjectV1Beta1(tr) - ctx := logtesting.TestContextWithLogger(t) - got := extract.SubjectDigests(ctx, tro, nil) - - if d := cmp.Diff(want, got, compare.SubjectCompareOption()); d != "" { - t.Errorf("Wrong subjects extracted, diff=%s", d) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters.go b/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters.go deleted file mode 100644 index 1cbbb041b9..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters.go +++ /dev/null @@ -1,44 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package externalparameters - -import ( - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/external_parameters" - "github.com/tektoncd/chains/pkg/chains/objects" -) - -// PipelineRun adds the pipeline run spec and provenance if available -func PipelineRun(pro *objects.PipelineRunObjectV1Beta1) map[string]any { - externalParams := make(map[string]any) - - if provenance := pro.GetRemoteProvenance(); provenance != nil { - externalParams["buildConfigSource"] = externalparameters.BuildConfigSource(provenance) - } - externalParams["runSpec"] = pro.Spec - return externalParams -} - -// TaskRun adds the task run spec and provenance if available -func TaskRun(tro *objects.TaskRunObjectV1Beta1) map[string]any { - externalParams := make(map[string]any) - - if provenance := tro.GetRemoteProvenance(); provenance != nil { - externalParams["buildConfigSource"] = externalparameters.BuildConfigSource(provenance) - } - externalParams["runSpec"] = tro.Spec - return externalParams -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters_test.go b/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters_test.go deleted file mode 100644 index ef261b3750..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters/external_parameters_test.go +++ /dev/null @@ -1,92 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package externalparameters - -import ( - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/internal/objectloader" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" -) - -func createPro(path string) *objects.PipelineRunObjectV1Beta1 { - pr, err := objectloader.PipelineRunV1Beta1FromFile(path) - if err != nil { - panic(err) - } - tr1, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - panic(err) - } - tr2, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun2.json") - if err != nil { - panic(err) - } - p := objects.NewPipelineRunObjectV1Beta1(pr) - p.AppendTaskRun(tr1) - p.AppendTaskRun(tr2) - return p -} - -func TestPipelineRun(t *testing.T) { - pro := createPro("../../../testdata/slsa-v2alpha2/pipelinerun1.json") - - got := PipelineRun(pro) - - want := map[string]any{ - "runSpec": v1beta1.PipelineRunSpec{ - PipelineRef: &v1beta1.PipelineRef{Name: "test-pipeline"}, - Params: v1beta1.Params{ - { - Name: "IMAGE", - Value: v1beta1.ParamValue{Type: "string", StringVal: "test.io/test/image"}, - }, - }, - ServiceAccountName: "pipeline", - }, - } - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("PipelineRun(): -want +got: %s", diff) - } -} - -func TestTaskRun(t *testing.T) { - tr, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - t.Fatal(err) - } - got := TaskRun(objects.NewTaskRunObjectV1Beta1(tr)) - - want := map[string]any{ - "runSpec": v1beta1.TaskRunSpec{ - Params: v1beta1.Params{ - {Name: "IMAGE", Value: v1beta1.ParamValue{Type: "string", StringVal: "test.io/test/image"}}, - {Name: "CHAINS-GIT_COMMIT", Value: v1beta1.ParamValue{Type: "string", StringVal: "taskrun"}}, - {Name: "CHAINS-GIT_URL", Value: v1beta1.ParamValue{Type: "string", StringVal: "https://git.test.com"}}, - }, - ServiceAccountName: "default", - TaskRef: &v1beta1.TaskRef{Name: "build", Kind: "Task"}, - }, - } - - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("TaskRun(): -want +got: %s", diff) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun.go b/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun.go deleted file mode 100644 index ef4df5eb89..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun.go +++ /dev/null @@ -1,137 +0,0 @@ -/* -Copyright 2023 The Tekton Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package pipelinerun - -import ( - "context" - "encoding/json" - "fmt" - - intoto "github.com/in-toto/in-toto-golang/in_toto" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" - buildtypes "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/build_types" - internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies" - "github.com/tektoncd/chains/pkg/chains/objects" -) - -const ( - pipelineRunResults = "pipelineRunResults/%s" - // JsonMediaType is the media type of json encoded content used in resource descriptors - JsonMediaType = "application/json" -) - -// GenerateAttestation generates a provenance statement with SLSA v1.0 predicate for a pipeline run. -func GenerateAttestation(ctx context.Context, pro *objects.PipelineRunObjectV1Beta1, slsaconfig *slsaconfig.SlsaConfig) (interface{}, error) { - bp, err := byproducts(pro) - if err != nil { - return nil, err - } - - bd, err := getBuildDefinition(ctx, slsaconfig, pro) - if err != nil { - return nil, err - } - - att := intoto.ProvenanceStatementSLSA1{ - StatementHeader: intoto.StatementHeader{ - Type: intoto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: extract.SubjectDigests(ctx, pro, slsaconfig), - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: bd, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: slsaconfig.BuilderID, - }, - BuildMetadata: metadata(pro), - Byproducts: bp, - }, - }, - } - return att, nil -} - -func metadata(pro *objects.PipelineRunObjectV1Beta1) slsa.BuildMetadata { - m := slsa.BuildMetadata{ - InvocationID: string(pro.ObjectMeta.UID), - } - if pro.Status.StartTime != nil { - utc := pro.Status.StartTime.Time.UTC() - m.StartedOn = &utc - } - if pro.Status.CompletionTime != nil { - utc := pro.Status.CompletionTime.Time.UTC() - m.FinishedOn = &utc - } - return m -} - -// byproducts contains the pipelineRunResults -func byproducts(pro *objects.PipelineRunObjectV1Beta1) ([]slsa.ResourceDescriptor, error) { - byProd := []slsa.ResourceDescriptor{} - for _, key := range pro.Status.PipelineResults { - content, err := json.Marshal(key.Value) - if err != nil { - return nil, err - } - bp := slsa.ResourceDescriptor{ - Name: fmt.Sprintf(pipelineRunResults, key.Name), - Content: content, - MediaType: JsonMediaType, - } - byProd = append(byProd, bp) - } - return byProd, nil -} - -// getBuildDefinition get the buildDefinition based on the configured buildType. This will default to the slsa buildType -func getBuildDefinition(ctx context.Context, slsaconfig *slsaconfig.SlsaConfig, pro *objects.PipelineRunObjectV1Beta1) (slsa.ProvenanceBuildDefinition, error) { - // if buildType is not set in the chains-config, default to slsa build type - buildDefinitionType := slsaconfig.BuildType - if slsaconfig.BuildType == "" { - buildDefinitionType = buildtypes.SlsaBuildType - } - - switch buildDefinitionType { - case buildtypes.SlsaBuildType: - rd, err := resolveddependencies.PipelineRun(ctx, pro, slsaconfig, resolveddependencies.AddSLSATaskDescriptor) - if err != nil { - return slsa.ProvenanceBuildDefinition{}, err - } - return slsa.ProvenanceBuildDefinition{ - BuildType: buildDefinitionType, - ExternalParameters: externalparameters.PipelineRun(pro), - InternalParameters: internalparameters.SLSAInternalParameters(pro), - ResolvedDependencies: rd, - }, nil - case buildtypes.TektonBuildType: - rd, err := resolveddependencies.PipelineRun(ctx, pro, slsaconfig, resolveddependencies.AddTektonTaskDescriptor) - if err != nil { - return slsa.ProvenanceBuildDefinition{}, err - } - return slsa.ProvenanceBuildDefinition{ - BuildType: buildDefinitionType, - ExternalParameters: externalparameters.PipelineRun(pro), - InternalParameters: internalparameters.TektonInternalParameters(pro), - ResolvedDependencies: rd, - }, nil - default: - return slsa.ProvenanceBuildDefinition{}, fmt.Errorf("unsupported buildType %v", buildDefinitionType) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun_test.go b/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun_test.go deleted file mode 100644 index c4f6a0b1e0..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun/pipelinerun_test.go +++ /dev/null @@ -1,360 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package pipelinerun - -import ( - "context" - "encoding/json" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/in-toto/in-toto-golang/in_toto" - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - v1resourcedescriptor "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/compare" - internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/internal/objectloader" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - logtesting "knative.dev/pkg/logging/testing" -) - -func TestMetadata(t *testing.T) { - pr := &v1beta1.PipelineRun{ //nolint:staticcheck - ObjectMeta: v1.ObjectMeta{ - Name: "my-taskrun", - Namespace: "my-namespace", - Annotations: map[string]string{ - "chains.tekton.dev/reproducible": "true", - }, - UID: "abhhf-12354-asjsdbjs23-3435353n", - }, - Status: v1beta1.PipelineRunStatus{ - PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ - StartTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)}, - CompletionTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)}, - }, - }, - } - start := time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC) - end := time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC) - want := slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &start, - FinishedOn: &end, - } - got := metadata(objects.NewPipelineRunObjectV1Beta1(pr)) - if d := cmp.Diff(want, got); d != "" { - t.Fatalf("metadata (-want, +got):\n%s", d) - } -} - -func TestMetadataInTimeZone(t *testing.T) { - tz := time.FixedZone("Test Time", int((12 * time.Hour).Seconds())) - pr := &v1beta1.PipelineRun{ //nolint:staticcheck - ObjectMeta: v1.ObjectMeta{ - Name: "my-taskrun", - Namespace: "my-namespace", - Annotations: map[string]string{ - "chains.tekton.dev/reproducible": "true", - }, - UID: "abhhf-12354-asjsdbjs23-3435353n", - }, - Status: v1beta1.PipelineRunStatus{ - PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ - StartTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, tz)}, - CompletionTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, tz)}, - }, - }, - } - start := time.Date(1995, time.December, 24, 6, 12, 12, 12, tz).UTC() - end := time.Date(1995, time.December, 24, 6, 12, 12, 24, tz).UTC() - want := slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &start, - FinishedOn: &end, - } - got := metadata(objects.NewPipelineRunObjectV1Beta1(pr)) - if d := cmp.Diff(want, got); d != "" { - t.Fatalf("metadata (-want, +got):\n%s", d) - } -} - -func TestByProducts(t *testing.T) { - resultValue := v1beta1.ResultValue{Type: "string", StringVal: "result-value"} - pr := &v1beta1.PipelineRun{ //nolint:staticcheck - Status: v1beta1.PipelineRunStatus{ - PipelineRunStatusFields: v1beta1.PipelineRunStatusFields{ - PipelineResults: []v1beta1.PipelineRunResult{ - { - Name: "result-name", - Value: resultValue, - }, - }, - }, - }, - } - - resultBytes, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - want := []slsa.ResourceDescriptor{ - { - Name: "pipelineRunResults/result-name", - Content: resultBytes, - MediaType: JsonMediaType, - }, - } - got, err := byproducts(objects.NewPipelineRunObjectV1Beta1(pr)) - if err != nil { - t.Fatalf("Could not extract byproducts: %s", err) - } - if d := cmp.Diff(want, got); d != "" { - t.Fatalf("byproducts (-want, +got):\n%s", d) - } -} - -func createPro(path string) *objects.PipelineRunObjectV1Beta1 { - pr, err := objectloader.PipelineRunV1Beta1FromFile(path) - if err != nil { - panic(err) - } - tr1, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - panic(err) - } - tr2, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun2.json") - if err != nil { - panic(err) - } - p := objects.NewPipelineRunObjectV1Beta1(pr) - p.AppendTaskRun(tr1) - p.AppendTaskRun(tr2) - return p -} - -func TestGenerateAttestation(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - pr := createPro("../../../testdata/slsa-v2alpha2/pipelinerun1.json") - - e1BuildStart := time.Unix(1617011400, 0) - e1BuildFinished := time.Unix(1617011415, 0) - - want := in_toto.ProvenanceStatementSLSA1{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: []in_toto.Subject{ - { - Name: "test.io/test/image", - Digest: common.DigestSet{ - "sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7", - }, - }, - }, - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: map[string]any{ - "runSpec": pr.Spec, - }, - InternalParameters: map[string]any{}, - ResolvedDependencies: []slsa.ResourceDescriptor{ - { - URI: "git+https://github.com/test", - Digest: common.DigestSet{"sha1": "28b123"}, - Name: "pipeline", - }, - { - URI: "git+https://github.com/catalog", - Digest: common.DigestSet{"sha1": "x123"}, - Name: "pipelineTask", - }, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - { - URI: "git+https://github.com/test", - Digest: common.DigestSet{"sha1": "ab123"}, - Name: "pipelineTask", - }, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - { - URI: "abc", - Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}, - Name: "inputs/result", - }, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, - }, - }, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: "test_builder-1", - }, - BuildMetadata: slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &e1BuildStart, - FinishedOn: &e1BuildFinished, - }, - Byproducts: []slsa.ResourceDescriptor{ - { - Name: "pipelineRunResults/CHAINS-GIT_COMMIT", - Content: []uint8(`"abcd"`), - MediaType: JsonMediaType, - }, { - Name: "pipelineRunResults/CHAINS-GIT_URL", - Content: []uint8(`"https://git.test.com"`), - MediaType: JsonMediaType, - }, { - Name: "pipelineRunResults/IMAGE_URL", - Content: []uint8(`"test.io/test/image"`), - MediaType: JsonMediaType, - }, { - Name: "pipelineRunResults/IMAGE_DIGEST", - Content: []uint8(`"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"`), - MediaType: JsonMediaType, - }, { - Name: "pipelineRunResults/img-ARTIFACT_INPUTS", - Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7","uri":"abc"}`), - MediaType: JsonMediaType, - }, { - Name: "pipelineRunResults/img2-ARTIFACT_OUTPUTS", - Content: []uint8(`{"digest":"sha256:","uri":"def"}`), - MediaType: JsonMediaType, - }, { - Name: "pipelineRunResults/img_no_uri-ARTIFACT_OUTPUTS", - Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}`), - MediaType: JsonMediaType, - }, - }, - }, - }, - } - - got, err := GenerateAttestation(ctx, pr, &slsaconfig.SlsaConfig{ - BuilderID: "test_builder-1", - DeepInspectionEnabled: false, - BuildType: "https://tekton.dev/chains/v2/slsa", - }) - - if err != nil { - t.Errorf("unwant error: %s", err.Error()) - } - if diff := cmp.Diff(want, got, compare.SLSAV1CompareOptions()...); diff != "" { - t.Errorf("GenerateAttestation(): -want +got: %s", diff) - } -} - -func getResolvedDependencies(addTasks func(*objects.TaskRunObjectV1Beta1) (*v1resourcedescriptor.ResourceDescriptor, error)) []v1resourcedescriptor.ResourceDescriptor { //nolint:staticcheck - pr := createPro("../../../testdata/slsa-v2alpha2/pipelinerun1.json") - rd, err := resolveddependencies.PipelineRun(context.Background(), pr, &slsaconfig.SlsaConfig{DeepInspectionEnabled: false}, addTasks) - if err != nil { - return []v1resourcedescriptor.ResourceDescriptor{} - } - return rd -} - -func TestGetBuildDefinition(t *testing.T) { - pr := createPro("../../../testdata/slsa-v2alpha2/pipelinerun1.json") - pr.Annotations = map[string]string{ - "annotation1": "annotation1", - } - pr.Labels = map[string]string{ - "label1": "label1", - } - tests := []struct { - name string - taskContent func(*objects.TaskRunObjectV1Beta1) (*v1resourcedescriptor.ResourceDescriptor, error) //nolint:staticcheck - config *slsaconfig.SlsaConfig - want slsa.ProvenanceBuildDefinition - }{ - { - name: "test slsa build type", - taskContent: resolveddependencies.AddSLSATaskDescriptor, - config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa"}, - want: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: externalparameters.PipelineRun(pr), - InternalParameters: internalparameters.SLSAInternalParameters(pr), - ResolvedDependencies: getResolvedDependencies(resolveddependencies.AddSLSATaskDescriptor), - }, - }, - { - name: "test tekton build type", - config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa-tekton"}, - taskContent: resolveddependencies.AddSLSATaskDescriptor, - want: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa-tekton", - ExternalParameters: externalparameters.PipelineRun(pr), - InternalParameters: internalparameters.TektonInternalParameters(pr), - ResolvedDependencies: getResolvedDependencies(resolveddependencies.AddTektonTaskDescriptor), - }, - }, - { - name: "test default build type", - config: &slsaconfig.SlsaConfig{BuildType: "https://tekton.dev/chains/v2/slsa"}, - taskContent: resolveddependencies.AddSLSATaskDescriptor, - want: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: externalparameters.PipelineRun(pr), - InternalParameters: internalparameters.SLSAInternalParameters(pr), - ResolvedDependencies: getResolvedDependencies(resolveddependencies.AddSLSATaskDescriptor), - }, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - bd, err := getBuildDefinition(context.Background(), tc.config, pr) - if err != nil { - t.Fatalf("Did not expect an error but got %v", err) - } - - if diff := cmp.Diff(tc.want, bd); diff != "" { - t.Errorf("getBuildDefinition(): -want +got: %v", diff) - } - }) - } -} - -func TestUnsupportedBuildType(t *testing.T) { - pr := createPro("../../../testdata/slsa-v2alpha2/pipelinerun1.json") - - got, err := getBuildDefinition(context.Background(), &slsaconfig.SlsaConfig{BuildType: "bad-buildtype"}, pr) - if err == nil { - t.Error("getBuildDefinition(): expected error got nil") - } - if diff := cmp.Diff(slsa.ProvenanceBuildDefinition{}, got); diff != "" { - t.Errorf("getBuildDefinition(): -want +got: %s", diff) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies.go b/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies.go deleted file mode 100644 index cef8975277..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies.go +++ /dev/null @@ -1,224 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resolveddependencies - -import ( - "context" - "encoding/json" - - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - v1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - materialv1beta1 "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/material/v1beta1" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/resolved_dependencies" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - "github.com/tektoncd/chains/pkg/chains/objects" - "go.uber.org/zap" - "knative.dev/pkg/logging" -) - -const ( - // pipelineConfigName is the name of the resolved dependency of the pipelineRef. - pipelineConfigName = "pipeline" - // taskConfigName is the name of the resolved dependency of the top level taskRef. - taskConfigName = "task" - // pipelineTaskConfigName is the name of the resolved dependency of the pipeline task. - pipelineTaskConfigName = "pipelineTask" - // inputResultName is the name of the resolved dependency generated from Type hinted parameters or results. - inputResultName = "inputs/result" - // pipelineResourceName is the name of the resolved dependency of pipeline resource. - pipelineResourceName = "pipelineResource" -) - -// used to toggle the fields in resolvedDependencies. see AddTektonTaskDescriptor -// and AddSLSATaskDescriptor -type addTaskDescriptorContent func(*objects.TaskRunObjectV1Beta1) (*v1.ResourceDescriptor, error) //nolint:staticcheck - -// the more verbose resolved dependency content. this adds the name, uri, digest -// and content if possible. -func AddTektonTaskDescriptor(tr *objects.TaskRunObjectV1Beta1) (*v1.ResourceDescriptor, error) { //nolint:staticcheck - rd := v1.ResourceDescriptor{} - storedTr, err := json.Marshal(tr) - if err != nil { - return nil, err - } - - rd.Name = pipelineTaskConfigName - rd.Content = storedTr - if tr.Status.Provenance != nil && tr.Status.Provenance.RefSource != nil { - rd.URI = tr.Status.Provenance.RefSource.URI - rd.Digest = tr.Status.Provenance.RefSource.Digest - } - - return &rd, nil -} - -// resolved dependency content for the more generic slsa verifiers. just logs -// the name, uri and digest. -func AddSLSATaskDescriptor(tr *objects.TaskRunObjectV1Beta1) (*v1.ResourceDescriptor, error) { //nolint:staticcheck - if tr.Status.Provenance != nil && tr.Status.Provenance.RefSource != nil { - return &v1.ResourceDescriptor{ - Name: pipelineTaskConfigName, - URI: tr.Status.Provenance.RefSource.URI, - Digest: tr.Status.Provenance.RefSource.Digest, - }, nil - } - return nil, nil -} - -// fromPipelineTask adds the resolved dependencies from pipeline tasks -// such as pipeline task uri/digest for remote pipeline tasks and step and sidecar images. -func fromPipelineTask(logger *zap.SugaredLogger, pro *objects.PipelineRunObjectV1Beta1, addTasks addTaskDescriptorContent) ([]v1.ResourceDescriptor, error) { - pSpec := pro.Status.PipelineSpec - resolvedDependencies := []v1.ResourceDescriptor{} - if pSpec != nil { - pipelineTasks := append(pSpec.Tasks, pSpec.Finally...) - for _, t := range pipelineTasks { - tr := pro.GetTaskRunFromTask(t.Name) - // Ignore Tasks that did not execute during the PipelineRun. - if tr == nil || tr.Status.CompletionTime == nil { - logger.Infof("taskrun status not found for task %s", t.Name) - continue - } - rd, err := addTasks(tr) - if err != nil { - logger.Errorf("error storing taskRun %s, error: %s", t.Name, err) - continue - } - - if rd != nil { - resolvedDependencies = append(resolvedDependencies, *rd) - } - - mats := []common.ProvenanceMaterial{} - - // add step images - stepMaterials, err := materialv1beta1.FromStepImages(tr) - if err != nil { - return nil, err - } - mats = append(mats, stepMaterials...) - - // add sidecar images - sidecarMaterials, err := materialv1beta1.FromSidecarImages(tr) - if err != nil { - return nil, err - } - mats = append(mats, sidecarMaterials...) - - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, "")...) - } - } - return resolvedDependencies, nil -} - -// taskDependencies gather all dependencies in a task and adds them to resolvedDependencies -func taskDependencies(ctx context.Context, tr *objects.TaskRunObjectV1Beta1) ([]v1.ResourceDescriptor, error) { - var resolvedDependencies []v1.ResourceDescriptor - var err error - mats := []common.ProvenanceMaterial{} - - // add step and sidecar images - stepMaterials, err := materialv1beta1.FromStepImages(tr) - mats = append(mats, stepMaterials...) - if err != nil { - return nil, err - } - sidecarMaterials, err := materialv1beta1.FromSidecarImages(tr) - if err != nil { - return nil, err - } - mats = append(mats, sidecarMaterials...) - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, "")...) - - mats = materialv1beta1.FromTaskParamsAndResults(ctx, tr) - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, inputResultName)...) - - // add task resources - mats = materialv1beta1.FromTaskResources(ctx, tr) - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, pipelineResourceName)...) - - // remove duplicate resolved dependencies - resolvedDependencies, err = resolveddependencies.RemoveDuplicateResolvedDependencies(resolvedDependencies) - if err != nil { - return nil, err - } - - return resolvedDependencies, nil -} - -// TaskRun constructs `predicate.resolvedDependencies` section by collecting all the artifacts that influence a taskrun such as source code repo and step&sidecar base images. -func TaskRun(ctx context.Context, tro *objects.TaskRunObjectV1Beta1) ([]v1.ResourceDescriptor, error) { - var resolvedDependencies []v1.ResourceDescriptor - var err error - - // add top level task config - if p := tro.Status.Provenance; p != nil && p.RefSource != nil { - rd := v1.ResourceDescriptor{ - Name: taskConfigName, - URI: p.RefSource.URI, - Digest: p.RefSource.Digest, - } - resolvedDependencies = append(resolvedDependencies, rd) - } - - rds, err := taskDependencies(ctx, tro) - if err != nil { - return nil, err - } - resolvedDependencies = append(resolvedDependencies, rds...) - - return resolvedDependencies, nil -} - -// PipelineRun constructs `predicate.resolvedDependencies` section by collecting all the artifacts that influence a pipeline run such as source code repo and step&sidecar base images. -func PipelineRun(ctx context.Context, pro *objects.PipelineRunObjectV1Beta1, slsaconfig *slsaconfig.SlsaConfig, addTasks addTaskDescriptorContent) ([]v1.ResourceDescriptor, error) { - var err error - var resolvedDependencies []v1.ResourceDescriptor - logger := logging.FromContext(ctx) - - // add pipeline config to resolved dependencies - if p := pro.Status.Provenance; p != nil && p.RefSource != nil { - rd := v1.ResourceDescriptor{ - Name: pipelineConfigName, - URI: p.RefSource.URI, - Digest: p.RefSource.Digest, - } - resolvedDependencies = append(resolvedDependencies, rd) - } - - // add resolved dependencies from pipeline tasks - rds, err := fromPipelineTask(logger, pro, addTasks) - if err != nil { - return nil, err - } - resolvedDependencies = append(resolvedDependencies, rds...) - - // add resolved dependencies from pipeline results - mats := materialv1beta1.FromPipelineParamsAndResults(ctx, pro, slsaconfig) - // convert materials to resolved dependencies - resolvedDependencies = append(resolvedDependencies, resolveddependencies.ConvertMaterialsToResolvedDependencies(mats, inputResultName)...) - - // remove duplicate resolved dependencies - resolvedDependencies, err = resolveddependencies.RemoveDuplicateResolvedDependencies(resolvedDependencies) - if err != nil { - return nil, err - } - return resolvedDependencies, nil -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies_test.go b/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies_test.go deleted file mode 100644 index 3f68bdb573..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies/resolved_dependencies_test.go +++ /dev/null @@ -1,406 +0,0 @@ -/* -Copyright 2023 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package resolveddependencies - -import ( - "encoding/json" - "strings" - "testing" - - "github.com/google/go-cmp/cmp" - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - v1 "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - v1slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - "github.com/tektoncd/chains/internal/backport" - "github.com/tektoncd/chains/pkg/artifacts" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/compare" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/internal/objectloader" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - "github.com/tektoncd/pipeline/pkg/apis/resource/v1alpha1" - logtesting "knative.dev/pkg/logging/testing" -) - -const digest = "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b7" - -var pro *objects.PipelineRunObjectV1Beta1 -var proStructuredResults *objects.PipelineRunObjectV1Beta1 - -func init() { - pro = createPro("../../../testdata/slsa-v2alpha2/pipelinerun1.json") - proStructuredResults = createPro("../../../testdata/slsa-v2alpha2/pipelinerun_structured_results.json") -} - -func createPro(path string) *objects.PipelineRunObjectV1Beta1 { - var err error - pr, err := objectloader.PipelineRunV1Beta1FromFile(path) - if err != nil { - panic(err) - } - tr1, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - panic(err) - } - tr2, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun2.json") - if err != nil { - panic(err) - } - p := objects.NewPipelineRunObjectV1Beta1(pr) - p.AppendTaskRun(tr1) - p.AppendTaskRun(tr2) - return p -} - -func tektonTaskRuns() map[string][]byte { - trs := make(map[string][]byte) - tr1, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - panic(err) - } - tr2, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun2.json") - if err != nil { - panic(err) - } - - tr1Desc, err := json.Marshal(tr1) - if err != nil { - panic(err) - } - trs[tr1.Name] = tr1Desc - - tr2Desc, err := json.Marshal(tr2) - if err != nil { - panic(err) - } - trs[tr2.Name] = tr2Desc - - return trs -} - -func TestTaskRun(t *testing.T) { - tests := []struct { - name string - taskRun *v1beta1.TaskRun //nolint:staticcheck - want []v1.ResourceDescriptor - }{{ - name: "resolvedDependencies from pipeline resources", - taskRun: &v1beta1.TaskRun{ //nolint:staticcheck - Spec: v1beta1.TaskRunSpec{ - Resources: &v1beta1.TaskRunResources{ //nolint:all //incompatible with pipelines v0.45 - Inputs: []v1beta1.TaskResourceBinding{ //nolint:all //incompatible with pipelines v0.45 - { - PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:all //incompatible with pipelines v0.45 - Name: "nil-resource-spec", - }, - }, { - PipelineResourceBinding: v1beta1.PipelineResourceBinding{ //nolint:all //incompatible with pipelines v0.45 - Name: "repo", - ResourceSpec: &v1alpha1.PipelineResourceSpec{ //nolint:all //incompatible with pipelines v0.45 - Params: []v1alpha1.ResourceParam{ //nolint:all //incompatible with pipelines v0.45 - {Name: "url", Value: "https://github.com/GoogleContainerTools/distroless"}, - }, - Type: backport.PipelineResourceTypeGit, - }, - }, - }, - }, - }, - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - TaskRunResults: []v1beta1.TaskRunResult{ - { - Name: "img1_input" + "-" + artifacts.ArtifactsInputsResultName, - Value: *v1beta1.NewObject(map[string]string{ - "uri": "gcr.io/foo/bar", - "digest": digest, - }), - }, - }, - ResourcesResult: []v1beta1.PipelineResourceResult{ - { - ResourceName: "repo", - Key: "commit", - Value: "50c56a48cfb3a5a80fa36ed91c739bdac8381cbe", - }, { - ResourceName: "repo", - Key: "url", - Value: "https://github.com/GoogleContainerTools/distroless", - }, - }, - }, - }, - }, - want: []v1.ResourceDescriptor{ - { - Name: "inputs/result", - URI: "gcr.io/foo/bar", - Digest: common.DigestSet{ - "sha256": strings.TrimPrefix(digest, "sha256:"), - }, - }, - { - Name: "pipelineResource", - URI: "git+https://github.com/GoogleContainerTools/distroless.git", - Digest: common.DigestSet{ - "sha1": "50c56a48cfb3a5a80fa36ed91c739bdac8381cbe", - }, - }, - }, - }, { - name: "resolvedDependencies from remote task", - taskRun: &v1beta1.TaskRun{ //nolint:staticcheck - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - Provenance: &v1beta1.Provenance{ - RefSource: &v1beta1.RefSource{ - URI: "git+github.com/something.git", - Digest: map[string]string{ - "sha1": "abcd1234", - }, - }, - }, - }, - }, - }, - want: []v1.ResourceDescriptor{ - { - Name: "task", - URI: "git+github.com/something.git", - Digest: common.DigestSet{ - "sha1": "abcd1234", - }, - }, - }, - }, { - name: "git resolvedDependencies from taskrun params", - taskRun: &v1beta1.TaskRun{ //nolint:staticcheck - Spec: v1beta1.TaskRunSpec{ - Params: []v1beta1.Param{{ - Name: "CHAINS-GIT_COMMIT", - Value: *v1beta1.NewStructuredValues("my-commit"), - }, { - Name: "CHAINS-GIT_URL", - Value: *v1beta1.NewStructuredValues("github.com/something"), - }}, - }, - }, - want: []v1.ResourceDescriptor{ - { - Name: "inputs/result", - URI: "git+github.com/something.git", - Digest: common.DigestSet{ - "sha1": "my-commit", - }, - }, - }, - }, { - name: "resolvedDependencies from step images", - taskRun: &v1beta1.TaskRun{ //nolint:staticcheck - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - Steps: []v1beta1.StepState{{ - Name: "git-source-repo-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "git-source-repo-repeat-again-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "build", - ImageID: "gcr.io/cloud-marketplace-containers/google/bazel@sha256:010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }}, - }, - }, - }, - want: []v1.ResourceDescriptor{ - { - URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", - Digest: common.DigestSet{ - "sha256": "b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, - }, - { - URI: "oci://gcr.io/cloud-marketplace-containers/google/bazel", - Digest: common.DigestSet{ - "sha256": "010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }, - }, - }, - }, { - name: "resolvedDependencies from step and sidecar images", - taskRun: &v1beta1.TaskRun{ //nolint:staticcheck - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - Steps: []v1beta1.StepState{{ - Name: "git-source-repo-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "git-source-repo-repeat-again-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init@sha256:b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, { - Name: "build", - ImageID: "gcr.io/cloud-marketplace-containers/google/bazel@sha256:010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }}, - Sidecars: []v1beta1.SidecarState{{ - Name: "sidecar-jwqcl", - ImageID: "gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/sidecar-git-init@sha256:a1234f6e7a69617db57b685893256f978436277094c21d43b153994acd8a09567", - }}, - }, - }, - }, - want: []v1.ResourceDescriptor{ - { - URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/git-init", - Digest: common.DigestSet{ - "sha256": "b963f6e7a69617db57b685893256f978436277094c21d43b153994acd8a01247", - }, - }, { - URI: "oci://gcr.io/cloud-marketplace-containers/google/bazel", - Digest: common.DigestSet{ - "sha256": "010a1ecd1a8c3610f12039a25b823e3a17bd3e8ae455a53e340dcfdd37a49964", - }, - }, { - URI: "oci://gcr.io/tekton-releases/github.com/tektoncd/pipeline/cmd/sidecar-git-init", - Digest: common.DigestSet{ - "sha256": "a1234f6e7a69617db57b685893256f978436277094c21d43b153994acd8a09567", - }, - }, - }, - }} - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - rd, err := TaskRun(ctx, objects.NewTaskRunObjectV1Beta1(tc.taskRun)) - if err != nil { - t.Fatalf("Did not expect an error but got %v", err) - } - if diff := cmp.Diff(tc.want, rd); diff != "" { - t.Errorf("ResolvedDependencies(): -want +got: %s", diff) - } - }) - } -} - -func TestPipelineRun(t *testing.T) { - taskRuns := tektonTaskRuns() - tests := []struct { - name string - taskDescriptor addTaskDescriptorContent - want []v1slsa.ResourceDescriptor - }{ - { - name: "test slsa build type", - taskDescriptor: AddSLSATaskDescriptor, - want: []v1slsa.ResourceDescriptor{ - {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, - {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}}, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}}, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - {Name: "inputs/result", URI: "abc", Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}}, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, - }, - }, - { - name: "test tekton build type", - taskDescriptor: AddTektonTaskDescriptor, - want: []v1slsa.ResourceDescriptor{ - {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, - {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}, Content: taskRuns["git-clone"]}, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}, Content: taskRuns["taskrun-build"]}, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - {Name: "inputs/result", URI: "abc", Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}}, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, - }, - }, - } - - ctx := logtesting.TestContextWithLogger(t) - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - got, err := PipelineRun(ctx, pro, &slsaconfig.SlsaConfig{DeepInspectionEnabled: false}, tc.taskDescriptor) - if err != nil { - t.Error(err) - } - if d := cmp.Diff(tc.want, got); d != "" { - t.Errorf("PipelineRunResolvedDependencies(): -want +got: %s", got) - } - }) - } -} - -func TestPipelineRunStructuredResult(t *testing.T) { - want := []v1slsa.ResourceDescriptor{ - {Name: "pipeline", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "28b123"}}, - {Name: "pipelineTask", URI: "git+https://github.com/catalog", Digest: common.DigestSet{"sha1": "x123"}}, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {Name: "pipelineTask", URI: "git+https://github.com/test", Digest: common.DigestSet{"sha1": "ab123"}}, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - { - Name: "inputs/result", - URI: "abc", - Digest: common.DigestSet{ - "sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7", - }, - }, - { - URI: "git+https://git.test.com.git", - Digest: common.DigestSet{"sha1": "abcd"}, - Name: "inputs/result", - }, - } - ctx := logtesting.TestContextWithLogger(t) - got, err := PipelineRun(ctx, pro, &slsaconfig.SlsaConfig{DeepInspectionEnabled: false}, AddSLSATaskDescriptor) - if err != nil { - t.Errorf("error while extracting resolvedDependencies: %v", err) - } - if diff := cmp.Diff(want, got, compare.SLSAV1CompareOptions()...); diff != "" { - t.Errorf("resolvedDependencies(): -want +got: %s", diff) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun.go b/pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun.go deleted file mode 100644 index af54758b96..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun.go +++ /dev/null @@ -1,133 +0,0 @@ -/* -Copyright 2023 The Tekton Authors -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - http://www.apache.org/licenses/LICENSE-2.0 -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package taskrun - -import ( - "context" - "encoding/json" - "fmt" - - intoto "github.com/in-toto/in-toto-golang/in_toto" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/extract" - buildtypes "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/build_types" - internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies" - "github.com/tektoncd/chains/pkg/chains/objects" -) - -const taskRunResults = "taskRunResults/%s" - -// GenerateAttestation generates a provenance statement with SLSA v1.0 predicate for a task run. -func GenerateAttestation(ctx context.Context, tro *objects.TaskRunObjectV1Beta1, slsaConfig *slsaconfig.SlsaConfig) (interface{}, error) { - bp, err := byproducts(tro) - if err != nil { - return nil, err - } - - bd, err := getBuildDefinition(ctx, slsaConfig.BuildType, tro) - if err != nil { - return nil, err - } - - att := intoto.ProvenanceStatementSLSA1{ - StatementHeader: intoto.StatementHeader{ - Type: intoto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: extract.SubjectDigests(ctx, tro, slsaConfig), - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: bd, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: slsaConfig.BuilderID, - }, - BuildMetadata: metadata(tro), - Byproducts: bp, - }, - }, - } - return att, nil -} - -func metadata(tro *objects.TaskRunObjectV1Beta1) slsa.BuildMetadata { - m := slsa.BuildMetadata{ - InvocationID: string(tro.ObjectMeta.UID), - } - if tro.Status.StartTime != nil { - utc := tro.Status.StartTime.Time.UTC() - m.StartedOn = &utc - } - if tro.Status.CompletionTime != nil { - utc := tro.Status.CompletionTime.Time.UTC() - m.FinishedOn = &utc - } - return m -} - -// byproducts contains the taskRunResults -func byproducts(tro *objects.TaskRunObjectV1Beta1) ([]slsa.ResourceDescriptor, error) { - byProd := []slsa.ResourceDescriptor{} - for _, key := range tro.Status.TaskRunResults { - content, err := json.Marshal(key.Value) - if err != nil { - return nil, err - } - bp := slsa.ResourceDescriptor{ - Name: fmt.Sprintf(taskRunResults, key.Name), - Content: content, - MediaType: "application/json", - } - byProd = append(byProd, bp) - } - return byProd, nil -} - -// getBuildDefinition get the buildDefinition based on the configured buildType. This will default to the slsa buildType -func getBuildDefinition(ctx context.Context, buildType string, tro *objects.TaskRunObjectV1Beta1) (slsa.ProvenanceBuildDefinition, error) { - // if buildType is not set in the chains-config, default to slsa build type - buildDefinitionType := buildType - if buildType == "" { - buildDefinitionType = buildtypes.SlsaBuildType - } - - switch buildDefinitionType { - case buildtypes.SlsaBuildType: - rd, err := resolveddependencies.TaskRun(ctx, tro) - if err != nil { - return slsa.ProvenanceBuildDefinition{}, err - } - return slsa.ProvenanceBuildDefinition{ - BuildType: buildDefinitionType, - ExternalParameters: externalparameters.TaskRun(tro), - InternalParameters: internalparameters.SLSAInternalParameters(tro), - ResolvedDependencies: rd, - }, nil - case buildtypes.TektonBuildType: - rd, err := resolveddependencies.TaskRun(ctx, tro) - if err != nil { - return slsa.ProvenanceBuildDefinition{}, err - } - return slsa.ProvenanceBuildDefinition{ - BuildType: buildDefinitionType, - ExternalParameters: externalparameters.TaskRun(tro), - InternalParameters: internalparameters.TektonInternalParameters(tro), - ResolvedDependencies: rd, - }, nil - default: - return slsa.ProvenanceBuildDefinition{}, fmt.Errorf("unsupported buildType %v", buildType) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun_test.go b/pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun_test.go deleted file mode 100644 index d74ef53865..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/internal/taskrun/taskrun_test.go +++ /dev/null @@ -1,332 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package taskrun - -import ( - "context" - "encoding/json" - "testing" - "time" - - "github.com/google/go-cmp/cmp" - "github.com/in-toto/in-toto-golang/in_toto" - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - - v1resourcedescriptor "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - internalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/internal_parameters" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - externalparameters "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/external_parameters" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun" - resolveddependencies "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/resolved_dependencies" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/internal/objectloader" - "github.com/tektoncd/pipeline/pkg/apis/config" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" - logtesting "knative.dev/pkg/logging/testing" -) - -func TestMetadata(t *testing.T) { - tr := &v1beta1.TaskRun{ //nolint:staticcheck - ObjectMeta: v1.ObjectMeta{ - Name: "my-taskrun", - Namespace: "my-namespace", - Annotations: map[string]string{ - "chains.tekton.dev/reproducible": "true", - }, - UID: "abhhf-12354-asjsdbjs23-3435353n", - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - StartTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC)}, - CompletionTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC)}, - }, - }, - } - start := time.Date(1995, time.December, 24, 6, 12, 12, 12, time.UTC) - end := time.Date(1995, time.December, 24, 6, 12, 12, 24, time.UTC) - want := slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &start, - FinishedOn: &end, - } - got := metadata(objects.NewTaskRunObjectV1Beta1(tr)) - if d := cmp.Diff(want, got); d != "" { - t.Fatalf("metadata (-want, +got):\n%s", d) - } -} - -func TestMetadataInTimeZone(t *testing.T) { - tz := time.FixedZone("Test Time", int((12 * time.Hour).Seconds())) - tr := &v1beta1.TaskRun{ //nolint:staticcheck - ObjectMeta: v1.ObjectMeta{ - Name: "my-taskrun", - Namespace: "my-namespace", - Annotations: map[string]string{ - "chains.tekton.dev/reproducible": "true", - }, - UID: "abhhf-12354-asjsdbjs23-3435353n", - }, - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - StartTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 12, tz)}, - CompletionTime: &v1.Time{Time: time.Date(1995, time.December, 24, 6, 12, 12, 24, tz)}, - }, - }, - } - start := time.Date(1995, time.December, 24, 6, 12, 12, 12, tz).UTC() - end := time.Date(1995, time.December, 24, 6, 12, 12, 24, tz).UTC() - want := slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &start, - FinishedOn: &end, - } - got := metadata(objects.NewTaskRunObjectV1Beta1(tr)) - if d := cmp.Diff(want, got); d != "" { - t.Fatalf("metadata (-want, +got):\n%s", d) - } -} - -func TestByProducts(t *testing.T) { - resultValue := v1beta1.ResultValue{Type: "string", StringVal: "result-value"} - tr := &v1beta1.TaskRun{ //nolint:staticcheck - Status: v1beta1.TaskRunStatus{ - TaskRunStatusFields: v1beta1.TaskRunStatusFields{ - TaskRunResults: []v1beta1.TaskRunResult{ - { - Name: "result-name", - Value: resultValue, - }, - }, - }, - }, - } - - resultBytes, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - want := []slsa.ResourceDescriptor{ - { - Name: "taskRunResults/result-name", - Content: resultBytes, - MediaType: pipelinerun.JsonMediaType, - }, - } - got, err := byproducts(objects.NewTaskRunObjectV1Beta1(tr)) - if err != nil { - t.Fatalf("Could not extract byproducts: %s", err) - } - if d := cmp.Diff(want, got); d != "" { - t.Fatalf("byproducts (-want, +got):\n%s", d) - } -} - -func TestTaskRunGenerateAttestation(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - tr, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - t.Fatal(err) - } - e1BuildStart := time.Unix(1617011400, 0) - e1BuildFinished := time.Unix(1617011415, 0) - - resultValue := v1beta1.ResultValue{Type: "string", StringVal: "sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"} - resultBytesDigest, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - resultValue = v1beta1.ResultValue{Type: "string", StringVal: "gcr.io/my/image"} - resultBytesUri, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - - want := in_toto.ProvenanceStatementSLSA1{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: []in_toto.Subject{ - { - Name: "gcr.io/my/image", - Digest: common.DigestSet{ - "sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7", - }, - }, - }, - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: map[string]any{ - "runSpec": tr.Spec, - }, - InternalParameters: map[string]any{ - "tekton-pipelines-feature-flags": config.FeatureFlags{EnableAPIFields: "beta", ResultExtractionMethod: "termination-message"}, - }, - ResolvedDependencies: []slsa.ResourceDescriptor{ - { - URI: "git+https://github.com/test", - Digest: common.DigestSet{"sha1": "ab123"}, - Name: "task", - }, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "taskrun"}}, - }, - }, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: "test_builder-1", - }, - BuildMetadata: slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &e1BuildStart, - FinishedOn: &e1BuildFinished, - }, - Byproducts: []slsa.ResourceDescriptor{ - { - Name: "taskRunResults/IMAGE_DIGEST", - Content: resultBytesDigest, - MediaType: pipelinerun.JsonMediaType, - }, - { - Name: "taskRunResults/IMAGE_URL", - Content: resultBytesUri, - MediaType: pipelinerun.JsonMediaType, - }, - }, - }, - }, - } - - got, err := GenerateAttestation(ctx, objects.NewTaskRunObjectV1Beta1(tr), &slsaconfig.SlsaConfig{ - BuilderID: "test_builder-1", - BuildType: "https://tekton.dev/chains/v2/slsa", - }) - - if err != nil { - t.Errorf("unwant error: %s", err.Error()) - } - if diff := cmp.Diff(want, got); diff != "" { - t.Errorf("GenerateAttestation(): -want +got: %s", diff) - } -} - -func getResolvedDependencies(tro *objects.TaskRunObjectV1Beta1) []v1resourcedescriptor.ResourceDescriptor { - rd, err := resolveddependencies.TaskRun(context.Background(), tro) - if err != nil { - return []v1resourcedescriptor.ResourceDescriptor{} - } - return rd -} - -func TestGetBuildDefinition(t *testing.T) { - tr, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - t.Fatal(err) - } - - tr.Annotations = map[string]string{ - "annotation1": "annotation1", - } - tr.Labels = map[string]string{ - "label1": "label1", - } - - tro := objects.NewTaskRunObjectV1Beta1(tr) - tests := []struct { - name string - buildType string - want slsa.ProvenanceBuildDefinition - err error - }{ - { - name: "test slsa build type", - buildType: "https://tekton.dev/chains/v2/slsa", - want: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: externalparameters.TaskRun(tro), - InternalParameters: internalparameters.SLSAInternalParameters(tro), - ResolvedDependencies: getResolvedDependencies(tro), - }, - err: nil, - }, - { - name: "test default build type", - buildType: "", - want: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: externalparameters.TaskRun(tro), - InternalParameters: internalparameters.SLSAInternalParameters(tro), - ResolvedDependencies: getResolvedDependencies(tro), - }, - err: nil, - }, - { - name: "test tekton build type", - buildType: "https://tekton.dev/chains/v2/slsa-tekton", - want: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa-tekton", - ExternalParameters: externalparameters.TaskRun(tro), - InternalParameters: internalparameters.TektonInternalParameters(tro), - ResolvedDependencies: getResolvedDependencies(tro), - }, - err: nil, - }, - } - - for _, tc := range tests { - t.Run(tc.name, func(t *testing.T) { - bd, err := getBuildDefinition(context.Background(), tc.buildType, tro) - if err != nil { - t.Fatalf("Did not expect an error but got %v", err) - } - - if diff := cmp.Diff(tc.want, bd); diff != "" { - t.Errorf("getBuildDefinition(): -want +got: %v", diff) - } - - }) - } -} - -func TestUnsupportedBuildType(t *testing.T) { - tr, err := objectloader.TaskRunV1Beta1FromFile("../../../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - t.Fatal(err) - } - - got, err := getBuildDefinition(context.Background(), "bad-buildType", objects.NewTaskRunObjectV1Beta1(tr)) - if err == nil { - t.Error("getBuildDefinition(): expected error got nil") - } - if diff := cmp.Diff(slsa.ProvenanceBuildDefinition{}, got); diff != "" { - t.Errorf("getBuildDefinition(): -want +got: %s", diff) - } -} diff --git a/pkg/chains/formats/slsa/v2alpha2/slsav2.go b/pkg/chains/formats/slsa/v2alpha2/slsav2.go deleted file mode 100644 index 561c191ff5..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/slsav2.go +++ /dev/null @@ -1,95 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v2alpha2 - -import ( - "context" - "fmt" - - "github.com/tektoncd/chains/pkg/chains/formats" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/slsaconfig" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/taskrun" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/config" - v1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" -) - -const ( - PayloadTypeSlsav2alpha2 = formats.PayloadTypeSlsav2alpha2 -) - -func init() { - formats.RegisterPayloader(PayloadTypeSlsav2alpha2, NewFormatter) -} - -type Slsa struct { - slsaConfig *slsaconfig.SlsaConfig -} - -func NewFormatter(cfg config.Config) (formats.Payloader, error) { - return &Slsa{ - slsaConfig: &slsaconfig.SlsaConfig{ - BuilderID: cfg.Builder.ID, - DeepInspectionEnabled: cfg.Artifacts.PipelineRuns.DeepInspectionEnabled, - BuildType: cfg.BuildDefinition.BuildType, - }, - }, nil -} - -func (s *Slsa) Wrap() bool { - return true -} - -func (s *Slsa) CreatePayload(ctx context.Context, obj interface{}) (interface{}, error) { - switch v := obj.(type) { - case *objects.TaskRunObjectV1: - tro := obj.(*objects.TaskRunObjectV1) - trV1Beta1 := &v1beta1.TaskRun{} //nolint:staticcheck - if err := trV1Beta1.ConvertFrom(ctx, tro.GetObject().(*v1.TaskRun)); err != nil { - return nil, fmt.Errorf("error converting Tekton TaskRun from version v1 to v1beta1: %s", err) - } - return taskrun.GenerateAttestation(ctx, objects.NewTaskRunObjectV1Beta1(trV1Beta1), s.slsaConfig) - case *objects.PipelineRunObjectV1: - pro := obj.(*objects.PipelineRunObjectV1) - prV1Beta1 := &v1beta1.PipelineRun{} //nolint:staticcheck - if err := prV1Beta1.ConvertFrom(ctx, pro.GetObject().(*v1.PipelineRun)); err != nil { - return nil, fmt.Errorf("error converting Tekton PipelineRun from version v1 to v1beta1: %s", err) - } - proV1Beta1 := objects.NewPipelineRunObjectV1Beta1(prV1Beta1) - trs := pro.GetTaskRuns() - for _, tr := range trs { - trV1Beta1 := &v1beta1.TaskRun{} //nolint:staticcheck - if err := trV1Beta1.ConvertFrom(ctx, tr); err != nil { - return nil, fmt.Errorf("error converting Tekton TaskRun from version v1 to v1beta1: %s", err) - } - proV1Beta1.AppendTaskRun(trV1Beta1) - } - return pipelinerun.GenerateAttestation(ctx, proV1Beta1, s.slsaConfig) - case *objects.TaskRunObjectV1Beta1: - return taskrun.GenerateAttestation(ctx, v, s.slsaConfig) - case *objects.PipelineRunObjectV1Beta1: - return pipelinerun.GenerateAttestation(ctx, v, s.slsaConfig) - default: - return nil, fmt.Errorf("intoto does not support type: %s", v) - } -} - -func (s *Slsa) Type() config.PayloadType { - return formats.PayloadTypeSlsav2alpha2 -} diff --git a/pkg/chains/formats/slsa/v2alpha2/slsav2_test.go b/pkg/chains/formats/slsa/v2alpha2/slsav2_test.go deleted file mode 100644 index 3f932350d1..0000000000 --- a/pkg/chains/formats/slsa/v2alpha2/slsav2_test.go +++ /dev/null @@ -1,503 +0,0 @@ -/* -Copyright 2021 The Tekton Authors - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package v2alpha2 - -import ( - "encoding/json" - "testing" - "time" - - "github.com/tektoncd/chains/pkg/chains/formats" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/internal/compare" - "github.com/tektoncd/chains/pkg/chains/formats/slsa/v2alpha2/internal/pipelinerun" - "github.com/tektoncd/chains/pkg/chains/objects" - "github.com/tektoncd/chains/pkg/config" - "github.com/tektoncd/chains/pkg/internal/objectloader" - - "github.com/google/go-cmp/cmp" - "github.com/in-toto/in-toto-golang/in_toto" - "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/common" - slsa "github.com/in-toto/in-toto-golang/in_toto/slsa_provenance/v1" - pipelineConfig "github.com/tektoncd/pipeline/pkg/apis/config" - "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1beta1" - logtesting "knative.dev/pkg/logging/testing" -) - -var ( - e1BuildStart = time.Unix(1617011400, 0) - e1BuildFinished = time.Unix(1617011415, 0) -) - -func TestNewFormatter(t *testing.T) { - t.Run("Ok", func(t *testing.T) { - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "testid", - }, - } - f, err := NewFormatter(cfg) - if err != nil { - t.Errorf("Error creating formatter: %s", err) - } - if f == nil { - t.Error("Failed to create formatter") - } - }) -} - -func TestCreatePayloadError(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "testid", - }, - } - f, _ := NewFormatter(cfg) - - t.Run("Invalid type", func(t *testing.T) { - p, err := f.CreatePayload(ctx, "not a task ref") - - if p != nil { - t.Errorf("Unexpected payload") - } - if err == nil { - t.Errorf("Expected error") - } else { - if err.Error() != "intoto does not support type: not a task ref" { - t.Errorf("wrong error returned: '%s'", err.Error()) - } - } - }) - -} - -func TestCorrectPayloadType(t *testing.T) { - var i Slsa - if i.Type() != formats.PayloadTypeSlsav2alpha2 { - t.Errorf("Invalid type returned: %s", i.Type()) - } -} - -func TestTaskRunCreatePayload1(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - - tr, err := objectloader.TaskRunV1Beta1FromFile("../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - t.Fatal(err) - } - - resultValue := v1beta1.ParamValue{Type: "string", StringVal: "sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"} - resultBytesDigest, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - resultValue = v1beta1.ParamValue{Type: "string", StringVal: "gcr.io/my/image"} - resultBytesUri, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "test_builder-1", - }, - } - expected := in_toto.ProvenanceStatementSLSA1{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: []in_toto.Subject{ - { - Name: "gcr.io/my/image", - Digest: common.DigestSet{ - "sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7", - }, - }, - }, - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: map[string]any{ - "runSpec": tr.Spec, - }, - InternalParameters: map[string]any{ - "tekton-pipelines-feature-flags": pipelineConfig.FeatureFlags{EnableAPIFields: "beta", ResultExtractionMethod: "termination-message"}, - }, - ResolvedDependencies: []slsa.ResourceDescriptor{ - { - URI: "git+https://github.com/test", - Digest: common.DigestSet{"sha1": "ab123"}, - Name: "task", - }, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "taskrun"}}, - }, - }, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: "test_builder-1", - }, - BuildMetadata: slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &e1BuildStart, - FinishedOn: &e1BuildFinished, - }, - Byproducts: []slsa.ResourceDescriptor{ - { - Name: "taskRunResults/IMAGE_DIGEST", - Content: resultBytesDigest, - MediaType: pipelinerun.JsonMediaType, - }, - { - Name: "taskRunResults/IMAGE_URL", - Content: resultBytesUri, - MediaType: pipelinerun.JsonMediaType, - }, - }, - }, - }, - } - - i, _ := NewFormatter(cfg) - - got, err := i.CreatePayload(ctx, objects.NewTaskRunObjectV1Beta1(tr)) - - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - if diff := cmp.Diff(expected, got); diff != "" { - t.Errorf("Slsa.CreatePayload(): -want +got: %s", diff) - } -} - -func TestTaskRunCreatePayload2(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - tr, err := objectloader.TaskRunV1Beta1FromFile("../testdata/slsa-v2alpha2/taskrun2.json") - if err != nil { - t.Fatal(err) - } - - resultValue := v1beta1.ParamValue{Type: "string", StringVal: "sha256:d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"} - resultBytesDigest, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - resultValue = v1beta1.ParamValue{Type: "string", StringVal: "pkg:deb/debian/curl@7.50.3-1"} - resultBytesUri, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "test_builder-2", - }, - } - expected := in_toto.ProvenanceStatementSLSA1{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: nil, - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: map[string]any{ - "runSpec": tr.Spec, - }, - InternalParameters: map[string]any{}, - ResolvedDependencies: []slsa.ResourceDescriptor{ - { - URI: "git+https://github.com/catalog", - Digest: common.DigestSet{"sha1": "x123"}, - Name: "task", - }, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "sha:taskdefault"}}, - }, - }, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: "test_builder-2", - }, - BuildMetadata: slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &e1BuildStart, - FinishedOn: &e1BuildFinished, - }, - Byproducts: []slsa.ResourceDescriptor{ - { - Name: "taskRunResults/some-uri_DIGEST", - Content: resultBytesDigest, - MediaType: pipelinerun.JsonMediaType, - }, - { - Name: "taskRunResults/some-uri", - Content: resultBytesUri, - MediaType: pipelinerun.JsonMediaType, - }, - }, - }, - }, - } - - i, _ := NewFormatter(cfg) - got, err := i.CreatePayload(ctx, objects.NewTaskRunObjectV1Beta1(tr)) - - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - if diff := cmp.Diff(expected, got); diff != "" { - t.Errorf("Slsa.CreatePayload(): -want +got: %s", diff) - } -} - -func TestMultipleSubjects(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - - tr, err := objectloader.TaskRunV1Beta1FromFile("../testdata/slsa-v2alpha2/taskrun-multiple-subjects.json") - if err != nil { - t.Fatal(err) - } - - resultValue := v1beta1.ParamValue{ - Type: "string", - StringVal: "gcr.io/myimage1@sha256:d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6,gcr.io/myimage2@sha256:daa1a56e13c85cf164e7d9e595006649e3a04c47fe4a8261320e18a0bf3b0367", - } - resultBytes, err := json.Marshal(resultValue) - if err != nil { - t.Fatalf("Could not marshal results: %s", err) - } - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "test_builder-multiple", - }, - } - expected := in_toto.ProvenanceStatementSLSA1{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: []in_toto.Subject{ - { - Name: "gcr.io/myimage1", - Digest: common.DigestSet{ - "sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6", - }, - }, { - Name: "gcr.io/myimage2", - Digest: common.DigestSet{ - "sha256": "daa1a56e13c85cf164e7d9e595006649e3a04c47fe4a8261320e18a0bf3b0367", - }, - }, - }, - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: map[string]any{ - "runSpec": tr.Spec, - }, - InternalParameters: map[string]any{}, - ResolvedDependencies: []slsa.ResourceDescriptor{ - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - }, - }, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: "test_builder-multiple", - }, - BuildMetadata: slsa.BuildMetadata{}, - Byproducts: []slsa.ResourceDescriptor{ - { - Name: "taskRunResults/IMAGES", - Content: resultBytes, - MediaType: pipelinerun.JsonMediaType, - }, - }, - }, - }, - } - - i, _ := NewFormatter(cfg) - got, err := i.CreatePayload(ctx, objects.NewTaskRunObjectV1Beta1(tr)) - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - if diff := cmp.Diff(expected, got); diff != "" { - t.Errorf("Slsa.CreatePayload(): -want +got: %s", diff) - } -} - -func createPro(path string) *objects.PipelineRunObjectV1Beta1 { - pr, err := objectloader.PipelineRunV1Beta1FromFile(path) - if err != nil { - panic(err) - } - tr1, err := objectloader.TaskRunV1Beta1FromFile("../testdata/slsa-v2alpha2/taskrun1.json") - if err != nil { - panic(err) - } - tr2, err := objectloader.TaskRunV1Beta1FromFile("../testdata/slsa-v2alpha2/taskrun2.json") - if err != nil { - panic(err) - } - p := objects.NewPipelineRunObjectV1Beta1(pr) - p.AppendTaskRun(tr1) - p.AppendTaskRun(tr2) - return p -} - -func TestPipelineRunCreatePayload1(t *testing.T) { - ctx := logtesting.TestContextWithLogger(t) - - pr := createPro("../testdata/slsa-v2alpha2/pipelinerun1.json") - - cfg := config.Config{ - Builder: config.BuilderConfig{ - ID: "test_builder-1", - }, - } - expected := in_toto.ProvenanceStatementSLSA1{ - StatementHeader: in_toto.StatementHeader{ - Type: in_toto.StatementInTotoV01, - PredicateType: slsa.PredicateSLSAProvenance, - Subject: []in_toto.Subject{ - { - Name: "test.io/test/image", - Digest: common.DigestSet{ - "sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7", - }, - }, - }, - }, - Predicate: slsa.ProvenancePredicate{ - BuildDefinition: slsa.ProvenanceBuildDefinition{ - BuildType: "https://tekton.dev/chains/v2/slsa", - ExternalParameters: map[string]any{ - "runSpec": pr.Spec, - }, - InternalParameters: map[string]any{}, - ResolvedDependencies: []slsa.ResourceDescriptor{ - { - URI: "git+https://github.com/test", - Digest: common.DigestSet{"sha1": "28b123"}, - Name: "pipeline", - }, - { - URI: "git+https://github.com/catalog", - Digest: common.DigestSet{"sha1": "x123"}, - Name: "pipelineTask", - }, - { - URI: "oci://gcr.io/test1/test1", - Digest: common.DigestSet{"sha256": "d4b63d3e24d6eef04a6dc0795cf8a73470688803d97c52cffa3c8d4efd3397b6"}, - }, - { - URI: "git+https://github.com/test", - Digest: common.DigestSet{"sha1": "ab123"}, - Name: "pipelineTask", - }, - { - URI: "oci://gcr.io/test2/test2", - Digest: common.DigestSet{"sha256": "4d6dd704ef58cb214dd826519929e92a978a57cdee43693006139c0080fd6fac"}, - }, - { - URI: "oci://gcr.io/test3/test3", - Digest: common.DigestSet{"sha256": "f1a8b8549c179f41e27ff3db0fe1a1793e4b109da46586501a8343637b1d0478"}, - }, - { - URI: "abc", - Digest: common.DigestSet{"sha256": "827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}, - Name: "inputs/result", - }, - {Name: "inputs/result", URI: "git+https://git.test.com.git", Digest: common.DigestSet{"sha1": "abcd"}}, - }, - }, - RunDetails: slsa.ProvenanceRunDetails{ - Builder: slsa.Builder{ - ID: "test_builder-1", - }, - BuildMetadata: slsa.BuildMetadata{ - InvocationID: "abhhf-12354-asjsdbjs23-3435353n", - StartedOn: &e1BuildStart, - FinishedOn: &e1BuildFinished, - }, - Byproducts: []slsa.ResourceDescriptor{ - { - Name: "pipelineRunResults/CHAINS-GIT_COMMIT", - Content: []uint8(`"abcd"`), - MediaType: pipelinerun.JsonMediaType, - }, { - Name: "pipelineRunResults/CHAINS-GIT_URL", - Content: []uint8(`"https://git.test.com"`), - MediaType: pipelinerun.JsonMediaType, - }, { - Name: "pipelineRunResults/IMAGE_URL", - Content: []uint8(`"test.io/test/image"`), - MediaType: pipelinerun.JsonMediaType, - }, { - Name: "pipelineRunResults/IMAGE_DIGEST", - Content: []uint8(`"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"`), - MediaType: pipelinerun.JsonMediaType, - }, { - Name: "pipelineRunResults/img-ARTIFACT_INPUTS", - Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7","uri":"abc"}`), - MediaType: pipelinerun.JsonMediaType, - }, { - Name: "pipelineRunResults/img2-ARTIFACT_OUTPUTS", - Content: []uint8(`{"digest":"sha256:","uri":"def"}`), - MediaType: pipelinerun.JsonMediaType, - }, { - Name: "pipelineRunResults/img_no_uri-ARTIFACT_OUTPUTS", - Content: []uint8(`{"digest":"sha256:827521c857fdcd4374f4da5442fbae2edb01e7fbae285c3ec15673d4c1daecb7"}`), - MediaType: pipelinerun.JsonMediaType, - }, - }, - }, - }, - } - - i, _ := NewFormatter(cfg) - - got, err := i.CreatePayload(ctx, pr) - - if err != nil { - t.Errorf("unexpected error: %s", err.Error()) - } - if diff := cmp.Diff(expected, got, compare.SLSAV1CompareOptions()...); diff != "" { - t.Errorf("Slsa.CreatePayload(): -want +got: %s", diff) - } -} diff --git a/pkg/config/config.go b/pkg/config/config.go index 1d3cb3fbc9..15dc3697da 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -266,12 +266,12 @@ func NewConfigFromMap(data map[string]string) (*Config, error) { if err := cm.Parse(data, // Artifact-specific configs // TaskRuns - asString(taskrunFormatKey, &cfg.Artifacts.TaskRuns.Format, "in-toto", "slsa/v1", "slsa/v2alpha1", "slsa/v2alpha2", "slsa/v2alpha3"), + asString(taskrunFormatKey, &cfg.Artifacts.TaskRuns.Format, "in-toto", "slsa/v1", "slsa/v2alpha3"), asStringSet(taskrunStorageKey, &cfg.Artifacts.TaskRuns.StorageBackend, sets.New[string]("tekton", "oci", "gcs", "docdb", "grafeas", "kafka")), asString(taskrunSignerKey, &cfg.Artifacts.TaskRuns.Signer, "x509", "kms"), // PipelineRuns - asString(pipelinerunFormatKey, &cfg.Artifacts.PipelineRuns.Format, "in-toto", "slsa/v1", "slsa/v2alpha2", "slsa/v2alpha3"), + asString(pipelinerunFormatKey, &cfg.Artifacts.PipelineRuns.Format, "in-toto", "slsa/v1", "slsa/v2alpha3"), asStringSet(pipelinerunStorageKey, &cfg.Artifacts.PipelineRuns.StorageBackend, sets.New[string]("tekton", "oci", "gcs", "docdb", "grafeas")), asString(pipelinerunSignerKey, &cfg.Artifacts.PipelineRuns.Signer, "x509", "kms"), asBool(pipelinerunEnableDeepInspectionKey, &cfg.Artifacts.PipelineRuns.DeepInspectionEnabled), diff --git a/test/examples_test.go b/test/examples_test.go index e7384c2bb0..433fe01f1b 100644 --- a/test/examples_test.go +++ b/test/examples_test.go @@ -95,42 +95,6 @@ func TestExamples(t *testing.T) { outputLocation: "slsa/v1", predicate: "slsav0.1", }, - { - name: "taskrun-examples-slsa-v2", - cm: map[string]string{ - "artifacts.taskrun.format": "slsa/v2alpha1", - "artifacts.oci.storage": "tekton", - }, - getExampleObjects: getTaskRunExamples, - payloadKey: "chains.tekton.dev/payload-taskrun-%s", - signatureKey: "chains.tekton.dev/signature-taskrun-%s", - outputLocation: "slsa/v2", - predicate: "slsav0.2", - }, - { - name: "taskrun-examples-slsa-v2alpha2", - cm: map[string]string{ - "artifacts.taskrun.format": "slsa/v2alpha2", - "artifacts.oci.storage": "tekton", - }, - getExampleObjects: getTaskRunExamples, - payloadKey: "chains.tekton.dev/payload-taskrun-%s", - signatureKey: "chains.tekton.dev/signature-taskrun-%s", - outputLocation: "slsa/v2alpha2", - predicate: "slsav1.0", - }, - { - name: "pipelinerun-examples-slsa-v2alpha2", - cm: map[string]string{ - "artifacts.pipelinerun.format": "slsa/v2alpha2", - "artifacts.oci.storage": "tekton", - }, - getExampleObjects: getPipelineRunExamples, - payloadKey: "chains.tekton.dev/payload-pipelinerun-%s", - signatureKey: "chains.tekton.dev/signature-pipelinerun-%s", - outputLocation: "slsa/v2alpha2", - predicate: "slsav1.0", - }, { name: "taskrun-examples-slsa-v2alpha3", cm: map[string]string{ diff --git a/test/testdata/slsa/v2alpha2/pipeline-output-image.json b/test/testdata/slsa/v2alpha2/pipeline-output-image.json deleted file mode 100644 index 67a67f4f2c..0000000000 --- a/test/testdata/slsa/v2alpha2/pipeline-output-image.json +++ /dev/null @@ -1,124 +0,0 @@ -{ - "_type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v1", - "subject": [ - { - "name": "gcr.io/foo/bar", - "digest": { - "sha256": "05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5" - } - } - ], - "predicate": { - "buildDefinition": { - "buildType": "https://tekton.dev/chains/v2/slsa", - "externalParameters": { - "runSpec": { - "serviceAccountName": "default", - "params": [ - { - "name": "CHAINS-GIT_COMMIT", - "value": "my-git-commit" - },{ - "name": "CHAINS-GIT_URL", - "value": "https://my-git-url" - } - ], - "pipelineSpec": { - "results": [ - { - "name": "IMAGE_URL", - "description": "", - "value": "$(tasks.buildimage.results.IMAGE_URL)" - }, - { - "name": "IMAGE_DIGEST", - "description": "", - "value": "$(tasks.buildimage.results.IMAGE_DIGEST)" - } - ], - "tasks": [ - { - "name": "buildimage", - "taskSpec": { - "metadata": {}, - "steps": [ - { - "name": "create-dockerfile", - "image": "distroless.dev/busybox@sha256:186312fcf3f381b5fc1dd80b1afc0d316f3ed39fb4add8ff900d1f0c7c49a92c", - "resources": {}, - "script": "#!/usr/bin/env sh\necho 'gcr.io/foo/bar' | tee $(results.IMAGE_URL.path)\necho 'sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5' | tee $(results.IMAGE_DIGEST.path)", - "volumeMounts": [ - { - "mountPath": "/dockerfile", - "name": "dockerfile" - } - ] - } - ], - "spec": null, - "results": [ - { - "name": "IMAGE_URL", - "type": "string" - },{ - "name": "IMAGE_DIGEST", - "type": "string" - } - ], - "volumes": [ - { - "emptyDir": {}, - "name": "dockerfile" - } - ] - - } - } - ] - }, - "timeouts": { - "pipeline": "1h0m0s" - } - } - }, - "resolvedDependencies": [ - {{range .URIDigest}} - { - "uri": "{{.URI}}", - "digest": { - "sha256": "{{.Digest}}" - } - }, - {{end}} - { - "uri": "git+https://my-git-url.git", - "digest": {"sha1": "my-git-commit"}, - "name": "inputs/result" - } - ] - }, - "runDetails": { - "builder": { - "id": "https://tekton.dev/chains/v2" - }, - "metadata": { - "invocationID": "{{.UID}}", - "startedOn": "{{.PipelineStartedOn}}", - "finishedOn": "{{.PipelineFinishedOn}}" - }, - "byproducts": [ - { - "name": "pipelineRunResults/IMAGE_URL", - "mediaType": "application/json", - "content": "Imdjci5pby9mb28vYmFyXG4i" - }, - { - "name": "pipelineRunResults/IMAGE_DIGEST", - "mediaType": "application/json", - "content": "InNoYTI1NjowNWY5NWIyNmVkMTA2NjhiNzE4M2MxZTJkYTk4NjEwZTkxMzcyZmE5ZjUxMDA0NmQ0Y2U1ODEyYWRkYWQ4NmI1XG4i" - } - ] - } - } -} diff --git a/test/testdata/slsa/v2alpha2/task-output-image.json b/test/testdata/slsa/v2alpha2/task-output-image.json deleted file mode 100644 index 6eeb2167c1..0000000000 --- a/test/testdata/slsa/v2alpha2/task-output-image.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "_type": "https://in-toto.io/Statement/v0.1", - "predicateType": "https://slsa.dev/provenance/v1", - "subject": [ - { - "name": "gcr.io/foo/bar", - "digest": { - "sha256": "05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5" - } - } - ], - "predicate": { - "buildDefinition": { - "buildType": "https://tekton.dev/chains/v2/slsa", - "externalParameters": { - "runSpec": { - "serviceAccountName": "default", - "taskSpec": { - "steps": [ - { - "name": "create-image", - "image": "busybox", - "resources": {}, - "script": "#!/usr/bin/env sh\necho 'gcr.io/foo/bar' | tee $(results.IMAGE_URL.path)\necho 'sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5' | tee $(results.IMAGE_DIGEST.path)" - } - ], - "results": [ - { - "name": "IMAGE_URL", - "type": "string" - },{ - "name": "IMAGE_DIGEST", - "type": "string" - } - ] - }, - "timeout": "1h0m0s" - } - }, - "resolvedDependencies": [ - {{range .URIDigest}} - { - "uri": "{{.URI}}", - "digest": { - "sha256": "{{.Digest}}" - } - } - {{end}} - ] - }, - "runDetails": { - "builder": { - "id": "https://tekton.dev/chains/v2" - }, - "metadata": { - "invocationID": "{{.UID}}", - "startedOn": "{{index .BuildStartTimes 0}}", - "finishedOn": "{{index .BuildFinishedTimes 0}}" - }, - "byproducts": [ - { - "name": "taskRunResults/IMAGE_DIGEST", - "mediaType": "application/json", - "content": "InNoYTI1NjowNWY5NWIyNmVkMTA2NjhiNzE4M2MxZTJkYTk4NjEwZTkxMzcyZmE5ZjUxMDA0NmQ0Y2U1ODEyYWRkYWQ4NmI1XG4i" - }, - { - "name": "taskRunResults/IMAGE_URL", - "mediaType": "application/json", - "content": "Imdjci5pby9mb28vYmFyXG4i" - } - ] - } - } -}