Artifacts

Overview

🌱 Artifacts is an alpha feature. The enable-artifacts feature flag must be set to "true" to read or write artifacts in a step.

Artifacts provide a way to track the origin of data produced and consumed within your Tekton Tasks.

Artifact Provenance Data

Artifacts fall into two categories:

  • Inputs: Artifacts downloaded and used by the Step/Task.
  • Outputs: Artifacts created and uploaded by the Step/Task.

Example Structure:

{
  "inputs":[
    {
      "name": "<input-category-name>", 
      "values": [
        {
          "uri": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c", 
          "digest": { "sha256": "b35caccc..." }
        }
      ]
    }
  ],
  "outputs": [
    {
      "name": "<output-category-name>",
      "values": [
        {
          "uri": "pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library",
          "digest": {
            "sha256": "df85b9e3...",
            "sha1": "95588b8f..."
          }
        }
      ]
    }
  ]
}

The content is written by the Step to a file $(step.artifacts.path):

apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: step-artifacts-
spec:
  taskSpec:
    description: |
            A simple task that populates artifacts to TaskRun stepState
    steps:
      - name: artifacts-producer
        image: bash:latest
        script: |
          cat > $(step.artifacts.path) << EOF
          {
            "inputs":[
              {
                "name":"source",
                "values":[
                  {
                    "uri":"pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c",
                    "digest":{
                      "sha256":"b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
                    }
                  }
                ]
              }
            ],
            "outputs":[
              {
                "name":"image",
                "values":[
                  {
                    "uri":"pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library",
                    "digest":{
                      "sha256":"df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48",
                      "sha1":"95588b8f34c31eb7d62c92aaa4e6506639b06ef2"
                    }
                  }
                ]
              }
            ]
          }
          EOF          

The content is written by the Step to a file $(artifacts.path):

apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: step-artifacts-
spec:
  taskSpec:
    description: |
            A simple task that populates artifacts to TaskRun stepState
    steps:
      - name: artifacts-producer
        image: bash:latest
        script: |
          cat > $(artifacts.path) << EOF
          {
            "inputs":[
              {
                "name":"source",
                "values":[
                  {
                    "uri":"pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c",
                    "digest":{
                      "sha256":"b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
                    }
                  }
                ]
              }
            ],
            "outputs":[
              {
                "name":"image",
                "values":[
                  {
                    "uri":"pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library",
                    "digest":{
                      "sha256":"df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48",
                      "sha1":"95588b8f34c31eb7d62c92aaa4e6506639b06ef2"
                    }
                  }
                ]
              }
            ]
          }
          EOF          

It is recommended to use purl format for artifacts uri as shown in the example.

Output Artifacts in SLSA Provenance

Artifacts are classified as either:

  • Build Outputs - packages, images, etc. that are being published by the build.
  • Build Byproducts - logs, caches, etc. that are incidental artifacts that are produced by the build.

By default, Tekton Chains will consider all output artifacts as byProducts when generating in the SLSA provenance. In order to treat an artifact as a subject of the build, you must set a boolean field "buildOutput": true for the output artifact.

e.g.

apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: step-artifacts-
spec:
  taskSpec:
    description: |
            A simple task that populates artifacts to TaskRun stepState
    steps:
      - name: artifacts-producer
        image: bash:latest
        script: |
          cat > $(artifacts.path) << EOF
          {
            "outputs":[
              {
                "name":"image",
                "buildOutput": true,
                "values":[
                  {
                    "uri":"pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library",
                    "digest":{
                      "sha256":"df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48",
                      "sha1":"95588b8f34c31eb7d62c92aaa4e6506639b06ef2"
                    }
                  }
                ]
              }
            ]
          }
          EOF          

This informs Tekton Chains your desire to handle the artifact.

[!TIP] When authoring a StepAction or a Task, you can parametrize this field to allow users to indicate their desire depending on what they are uploading - this can be useful for actions that may produce either a build output or a byproduct depending on the context!

Passing Artifacts between Steps

You can pass artifacts from one step to the next using:

  • Specific Artifact: $(steps.<step-name>.inputs.<artifact-category-name>) or $(steps.<step-name>.outputs.<artifact-category-name>)

The example below shows how to access the previous’ step artifacts from another step in the same task

apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
  generateName: step-artifacts-
spec:
  taskSpec:
    description: |
            A simple task that populates artifacts to TaskRun stepState
    steps:
      - name: artifacts-producer
        image: bash:latest
        script: |
          # the script is for creating the output artifacts
          cat > $(step.artifacts.path) << EOF
          {
            "inputs":[
              {
                "name":"source",
                "values":[
                  {
                    "uri":"pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c",
                    "digest":{
                      "sha256":"b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
                    }
                  }
                ]
              }
            ],
            "outputs":[
              {
                "name":"image",
                "values":[
                  {
                    "uri":"pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library",
                    "digest":{
                      "sha256":"df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48",
                      "sha1":"95588b8f34c31eb7d62c92aaa4e6506639b06ef2"
                    }
                  }
                ]
              }
            ]
          }
          EOF          
      - name: artifacts-consumer
        image: bash:latest
        script: |
                    echo $(steps.artifacts-producer.outputs.image)

The resolved value of $(steps.<step-name>.outputs.<artifact-category-name>) is the values of an artifact. For this example, $(steps.artifacts-producer.outputs.image) is resolved to

[
                  {
                    "uri":"pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library",
                    "digest":{
                      "sha256":"df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48",
                      "sha1":"95588b8f34c31eb7d62c92aaa4e6506639b06ef2"
                    }
                  }
]

Upon resolution and execution of the TaskRun, the Status will look something like:

{
  "artifacts": {
    "inputs": [
      {
        "name": "source",
        "values": [
          {
            "digest": {
              "sha256": "b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
            },
            "uri": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c"
          }
        ]
      }
    ],
    "outputs": [
      {
        "name": "image",
        "values": [
          {
            "digest": {
              "sha1": "95588b8f34c31eb7d62c92aaa4e6506639b06ef2",
              "sha256": "df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48"
            },
            "uri": "pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library"
          }
        ]
      }
    ]
  },
  "steps": [
    {
      "container": "step-artifacts-producer",
      "imageID": "docker.io/library/bash@sha256:5353512b79d2963e92a2b97d9cb52df72d32f94661aa825fcfa0aede73304743",
      "inputs": [
        {
          "name": "source",
          "values": [
            {
              "digest": {
                "sha256": "b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
              },
              "uri": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c"
            }
          ]
        }
      ],
      "name": "artifacts-producer",
      "outputs": [
        {
          "name": "image",
          "values": [
            {
              "digest": {
                "sha1": "95588b8f34c31eb7d62c92aaa4e6506639b06ef2",
                "sha256": "df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48"
              },
              "uri": "pkg:oci/nginx:stable-alpine3.17-slim?repository_url=docker.io/library"
            }
          ]
        }
      ],
      "terminated": {
        "containerID": "containerd://010f02d103d1db48531327a1fe09797c87c1d50b6a216892319b3af93e0f56e7",
        "exitCode": 0,
        "finishedAt": "2024-03-18T17:05:06Z",
        "message": "...",
        "reason": "Completed",
        "startedAt": "2024-03-18T17:05:06Z"
      },
      "terminationReason": "Completed"
    },
    {
      "container": "step-artifacts-consumer",
      "imageID": "docker.io/library/bash@sha256:5353512b79d2963e92a2b97d9cb52df72d32f94661aa825fcfa0aede73304743",
      "name": "artifacts-consumer",
      "terminated": {
        "containerID": "containerd://42428aa7e5a507eba924239f213d185dd4bc0882b6f217a79e6792f7fec3586e",
        "exitCode": 0,
        "finishedAt": "2024-03-18T17:05:06Z",
        "reason": "Completed",
        "startedAt": "2024-03-18T17:05:06Z"
      },
      "terminationReason": "Completed"
    }
  ]
}

Passing Artifacts between Tasks

You can pass artifacts from one task to the another using:

  • Specific Artifact: $(tasks.<task-name>.inputs.<artifact-category-name>) or $(tasks.<task-name>.outputs.<artifact-category-name>)

The example below shows how to access the previous’ task artifacts from another task in a pipeline

apiVersion: tekton.dev/v1
kind: PipelineRun
metadata:
  generateName: pipelinerun-consume-tasks-artifacts
spec:
  pipelineSpec:
    tasks:
      - name: produce-artifacts-task
        taskSpec:
          description: |
                        A simple task that produces artifacts
          steps:
            - name: produce-artifacts
              image: bash:latest
              script: |
                #!/usr/bin/env bash
                cat > $(artifacts.path) << EOF
                {
                  "inputs":[
                    {
                      "name":"input-artifacts",
                      "values":[
                        {
                          "uri":"pkg:example.github.com/inputs",
                          "digest":{
                            "sha256":"b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
                          }
                        }
                      ]
                    }
                  ],
                  "outputs":[
                    {
                      "name":"image",
                      "values":[
                        {
                          "uri":"pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c",
                          "digest":{
                            "sha256":"df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48",
                            "sha1":"95588b8f34c31eb7d62c92aaa4e6506639b06ef2"
                          }
                        }
                      ]
                    }
                  ]
                }
                EOF                
      - name: consume-artifacts
        runAfter:
          - produce-artifacts-task
        taskSpec:
          steps:
            - name: artifacts-consumer-python
              image: python:latest
              script: |
                #!/usr/bin/env python3
                import json
                data = json.loads('$(tasks.produce-artifacts-task.outputs.image)')
                if data[0]['uri'] != "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c":
                  exit(1)                

Similar to Step Artifacts. The resolved value of $(tasks.<task-name>.outputs.<artifact-category-name>) is the values of an artifact. For this example, $(tasks.produce-artifacts-task.outputs.image) is resolved to

[
  {
    "uri":"pkg:example.github.com/inputs",
    "digest":{
      "sha256":"b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
    }
 }
]

Upon resolution and execution of the TaskRun, the Status will look something like:

{
 "artifacts": {
      "inputs": [
        {
          "name": "input-artifacts",
          "values": [
            {
              "digest": {
                "sha256": "b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0"
              },
              "uri": "pkg:example.github.com/inputs"
            }
          ]
        }
      ],
      "outputs": [
        {
          "name": "image",
          "values": [
            {
              "digest": {
                "sha1": "95588b8f34c31eb7d62c92aaa4e6506639b06ef2",
                "sha256": "df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48"
              },
              "uri": "pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c"
            }
          ]
        }
      ]
    },
    "completionTime": "2024-05-28T14:10:58Z",
    "conditions": [
      {
        "lastTransitionTime": "2024-05-28T14:10:58Z",
        "message": "All Steps have completed executing",
        "reason": "Succeeded",
        "status": "True",
        "type": "Succeeded"
      }
    ],
    "podName": "pipelinerun-consume-tasks-a41ee44e4f964e95adfd3aea417d52f90-pod",
    "provenance": {
      "featureFlags": {
        "AwaitSidecarReadiness": true,
        "Coschedule": "workspaces",
        "DisableAffinityAssistant": false,
        "DisableCredsInit": false,
        "DisableInlineSpec": "",
        "EnableAPIFields": "beta",
        "EnableArtifacts": true,
        "EnableCELInWhenExpression": false,
        "EnableConciseResolverSyntax": false,
        "EnableKeepPodOnCancel": false,
        "EnableParamEnum": false,
        "EnableProvenanceInStatus": true,
        "EnableStepActions": true,
        "EnableTektonOCIBundles": false,
        "EnforceNonfalsifiability": "none",
        "MaxResultSize": 4096,
        "RequireGitSSHSecretKnownHosts": false,
        "ResultExtractionMethod": "termination-message",
        "RunningInEnvWithInjectedSidecars": true,
        "ScopeWhenExpressionsToTask": false,
        "SendCloudEventsForRuns": false,
        "SetSecurityContext": false,
        "VerificationNoMatchPolicy": "ignore"
      }
    },
    "startTime": "2024-05-28T14:10:48Z",
    "steps": [
      {
        "container": "step-produce-artifacts",
        "imageID": "docker.io/library/bash@sha256:23f90212fd89e4c292d7b41386ef1a6ac2b8a02bbc6947680bfe184cbc1a2899",
        "name": "produce-artifacts",
        "terminated": {
          "containerID": "containerd://1291ce07b175a7897beee6ba62eaa1528427bacb1f76b31435eeba68828c445a",
          "exitCode": 0,
          "finishedAt": "2024-05-28T14:10:57Z",
          "message": "...",
          "reason": "Completed",
          "startedAt": "2024-05-28T14:10:57Z"
        },
        "terminationReason": "Completed"
      }
    ],
    "taskSpec": {
      "description": "A simple task that produces artifacts\n",
      "steps": [
        {
          "computeResources": {},
          "image": "bash:latest",
          "name": "produce-artifacts",
          "script": "#!/usr/bin/env bash\ncat > /tekton/artifacts/provenance.json << EOF\n{\n  \"inputs\":[\n    {\n      \"name\":\"input-artifacts\",\n      \"values\":[\n        {\n          \"uri\":\"pkg:example.github.com/inputs\",\n          \"digest\":{\n            \"sha256\":\"b35cacccfdb1e24dc497d15d553891345fd155713ffe647c281c583269eaaae0\"\n          }\n        }\n      ]\n    }\n  ],\n  \"outputs\":[\n    {\n      \"name\":\"image\",\n      \"values\":[\n        {\n          \"uri\":\"pkg:github/package-url/purl-spec@244fd47e07d1004f0aed9c\",\n          \"digest\":{\n            \"sha256\":\"df85b9e3983fe2ce20ef76ad675ecf435cc99fc9350adc54fa230bae8c32ce48\",\n            \"sha1\":\"95588b8f34c31eb7d62c92aaa4e6506639b06ef2\"\n          }\n        }\n      ]\n    }\n  ]\n}\nEOF\n"
        }
      ]
    }
}