Skip to content

Commit

Permalink
Add new v2alpha4 version for TaskRuns
Browse files Browse the repository at this point in the history
This new version will now process the information from any associated StepAction from the executed TaskRun.

Also, the way chains read results from TaskRun to populate the `subjects` field is changing: now the user has to explicitly mark a result as a subject using an bject type-hinted tag (*ARTIFACT_OUTPUTS) + the new `isBuildArtifact` property in the value
  • Loading branch information
renzodavid9 committed May 6, 2024
1 parent 5986f44 commit ad42c97
Show file tree
Hide file tree
Showing 32 changed files with 2,390 additions and 40 deletions.
5 changes: 3 additions & 2 deletions docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,16 @@ 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/v2alpha2`, `slsa/v2alpha3`, `slsa/v2alpha4` | `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.
> - `slsa/v2alpha3` corresponds to the slsav1.0 spec. and uses latest [`v1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1).
> - `slsa/v2alpha4` corresponds to the slsav1.0 spec. and uses latest [`v1` Tekton Objects](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1). It reads type-hinted results from [StepActions](https://tekton.dev/docs/pipelines/pipeline-api/#tekton.dev/v1alpha1.StepAction). Recommended format for new chains users who want the slsav1.0 spec.
### PipelineRun Configuration

Expand Down
95 changes: 94 additions & 1 deletion docs/slsa-provenance.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ The following shows the mapping between slsa version and formatter name.

| SLSA Version | Formatter Name |
| ------------ | ---------------------- |
| v1.0 | `slsa/v2alpha3` |
| v1.0 | `slsa/v2alpha3` and `slsa/v2alpha4` |
| v0.2 | `slsa/v1` or `in-toto` |

To configure Task-level provenance version
Expand Down Expand Up @@ -319,6 +319,99 @@ spec:
</details>
## `v2alpha4` formatter
Starting with version `v2alpha4`, the type-hinted object results value now can include a new boolean flag called `isBuildArtifact`. When set to `true`, this flag indicates the output artifact should be considered as `subject` in the executed TaskRun/PipelineRun.
The `isBuildArtifact` can be set in results whose type-hint uses the `*ARTIFACT_OUTPUTS` format. For results not using this format, the associated result will be automatically classified as a `byProduct`.
For instance, in the following TaskRun:
```yaml
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: image-build
spec:
taskSpec:
results:
- name: first-ARTIFACT_OUTPUTS
description: The first artifact built
type: object
properties:
uri: {}
digest: {}
- name: second-ARTIFACT_OUTPUTS
description: The second artifact built
type: object
properties:
uri: {}
digest: {}
isBuildArtifact: {}
- name: third-IMAGE_URL
type: string
- name: third-IMAGE_DIGEST
type: string
steps:
- name: dummy-build
image: bash:latest
script: |
echo -n "{\"uri\":\"gcr.io/foo/img1\", \"digest\":\"sha256:586789aa031fafc7d78a5393cdc772e0b55107ea54bb8bcf3f2cdac6c6da51ee\"}" > $(results.first-ARTIFACT_OUTPUTS.path)
echo -n "{\"uri\":\"gcr.io/foo/img2\", \"digest\":\"sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b5\", \"isBuildArtifact\":\"true\"}" > $(results.second-ARTIFACT_OUTPUTS.path)
echo -n "gcr.io/foo/bar" | tee $(results.third-IMAGE_URL.path)
echo -n "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b6" | tee $(results.third-IMAGE_DIGEST.path)
```
Only the result `second-ARTIFACT_OUTPUTS` will be considered as a `subject` due to it uses the `*ARTIFACT_OUTPUTS` type hint format, and has `isBuildArtifact` set to `true`.
Chains' `v2alpha4` formatter now automatically reads type-hinted results from StepActions associated to the executed TaskRun; users no longer need to manually surface these results from the StepActions when the appropriate type hints are in place. For instance, the following TaskRun:
```yaml
apiVersion: tekton.dev/v1alpha1
kind: StepAction
metadata:
name: img-builder
spec:
image: busybox:glibc
results:
- name: first-ARTIFACT_OUTPUTS
description: The first artifact built
type: object
properties:
uri: {}
digest: {}
- name: second-IMAGE_URL
type: string
- name: second-IMAGE_DIGEST
type: string
script: |
echo -n "{\"uri\":\"gcr.io/foo/img1\", \"digest\":\"sha256:586789aa031fafc7d78a5393cdc772e0b55107ea54bb8bcf3f2cdac6c6da51ee\", \"isBuildArtifact\": \"true\" }" > $(step.results.first-ARTIFACT_OUTPUTS.path)
echo -n "gcr.io/foo/bar" > $(step.results.second-IMAGE_URL.path)
echo -n "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b6" > $(step.results.second-IMAGE_DIGEST.path)
---
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: taskrun
spec:
taskSpec:
steps:
- name: action-runner
ref:
name: img-builder
```
Will read `first-ARTIFACT_OUTPUTS` from the StepAction and clasify it as a `subject`.
## Besides inputs/outputs
Tekton Chains is also able to capture the feature flags being used for Tekton Pipelines controller and the origin of the build configuration file with immutable references such as task.yaml and pipeline.yaml. However, those fields in Tekton Pipelines are gated by a dedicated feature flag. Therefore, the feature flag needs to be enabled to let Tekton Pipelines controller to populate these fields.
Expand Down
24 changes: 24 additions & 0 deletions examples/stepactions/step-image-builder.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
apiVersion: tekton.dev/v1alpha1
kind: StepAction
metadata:
name: img-builder
spec:
image: busybox:glibc

results:
- name: first-ARTIFACT_OUTPUTS
description: The first artifact built
type: object
properties:
uri: {}
digest: {}

- name: second-IMAGE_URL
type: string
- name: second-IMAGE_DIGEST
type: string

script: |
echo -n "{\"uri\":\"gcr.io/foo/img1\", \"digest\":\"sha256:586789aa031fafc7d78a5393cdc772e0b55107ea54bb8bcf3f2cdac6c6da51ee\", \"isBuildArtifact\": \"true\" }" > $(step.results.first-ARTIFACT_OUTPUTS.path)
echo -n "gcr.io/foo/bar" > $(step.results.second-IMAGE_URL.path)
echo -n "sha256:05f95b26ed10668b7183c1e2da98610e91372fa9f510046d4ce5812addad86b6" > $(step.results.second-IMAGE_DIGEST.path)
10 changes: 10 additions & 0 deletions examples/stepactions/taskrun-image-builder.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: taskrun
spec:
taskSpec:
steps:
- name: action-runner
ref:
name: img-builder
43 changes: 38 additions & 5 deletions pkg/artifacts/signable.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ const (
ArtifactsOutputsResultName = "ARTIFACT_OUTPUTS"
OCIScheme = "oci://"
GitSchemePrefix = "git+"
isBuildArtifactField = "isBuildArtifact"
)

var (
Expand Down Expand Up @@ -264,12 +265,12 @@ func (s *StructuredSignable) FullRef() string {
return fmt.Sprintf("%s@%s", s.URI, s.Digest)
}

// RetrieveMaterialsFromStructuredResults retrieves structured results from Tekton Object, and convert them into materials.
func RetrieveMaterialsFromStructuredResults(ctx context.Context, obj objects.TektonObject, categoryMarker string) []common.ProvenanceMaterial {
// RetrieveMaterialsFromStructuredResults retrieves structured results from Object Results, and convert them into materials.
func RetrieveMaterialsFromStructuredResults(ctx context.Context, objResults []objects.Result) []common.ProvenanceMaterial {
logger := logging.FromContext(ctx)
// Retrieve structured provenance for inputs.
mats := []common.ProvenanceMaterial{}
ssts := ExtractStructuredTargetFromResults(ctx, obj, ArtifactsInputsResultName)
ssts := ExtractStructuredTargetFromResults(ctx, objResults, ArtifactsInputsResultName)
for _, s := range ssts {
alg, digest, err := ParseDigest(s.Digest)
if err != nil {
Expand All @@ -286,7 +287,7 @@ func RetrieveMaterialsFromStructuredResults(ctx context.Context, obj objects.Tek

// ExtractStructuredTargetFromResults extracts structured signable targets aim to generate intoto provenance as materials within TaskRun results and store them as StructuredSignable.
// categoryMarker categorizes signable targets into inputs and outputs.
func ExtractStructuredTargetFromResults(ctx context.Context, obj objects.TektonObject, categoryMarker string) []*StructuredSignable {
func ExtractStructuredTargetFromResults(ctx context.Context, objResults []objects.Result, categoryMarker string) []*StructuredSignable {
logger := logging.FromContext(ctx)
objs := []*StructuredSignable{}
if categoryMarker != ArtifactsInputsResultName && categoryMarker != ArtifactsOutputsResultName {
Expand All @@ -295,7 +296,7 @@ func ExtractStructuredTargetFromResults(ctx context.Context, obj objects.TektonO

// TODO(#592): support structured results using Run
results := []objects.Result{}
for _, res := range obj.GetResults() {
for _, res := range objResults {
results = append(results, objects.Result{
Name: res.Name,
Value: res.Value,
Expand All @@ -316,6 +317,38 @@ func ExtractStructuredTargetFromResults(ctx context.Context, obj objects.TektonO
return objs
}

// ExtractBuildArtifactsFromResults extracts all the structured signable targets from the given results, only processing the ones marked as build artifacts.
func ExtractBuildArtifactsFromResults(ctx context.Context, results []objects.Result) (objs []*StructuredSignable) {
logger := logging.FromContext(ctx)

for _, res := range results {
valid, err := IsBuildArtifact(res)
if err != nil {
logger.Debugf("ExtractBuildArtifactsFromResults: %v", err)
}
if valid {
logger.Debugf("Extracted Build artifact data from Result %s, %s", res.Value.ObjectVal["uri"], res.Value.ObjectVal["digest"])
objs = append(objs, &StructuredSignable{URI: res.Value.ObjectVal["uri"], Digest: res.Value.ObjectVal["digest"]})
}
}
return
}

// IsBuildArtifact indicates if a given result was marked as a Build Artifact.
func IsBuildArtifact(res objects.Result) (bool, error) {
isObjResult, err := isStructuredResult(res, ArtifactsOutputsResultName)
if err != nil {
return false, err
}

if !isObjResult {
return false, nil
}

isBuildArtifact := res.Value.ObjectVal[isBuildArtifactField]
return isBuildArtifact == "true", nil
}

func isStructuredResult(res objects.Result, categoryMarker string) (bool, error) {
if !strings.HasSuffix(res.Name, categoryMarker) {
return false, nil
Expand Down
Loading

0 comments on commit ad42c97

Please sign in to comment.