---
# System prepended metadata

title: 'TEP-NNNN: Tekton OCI bundles'
tags: [tep, tektoncd]

---

###### tags: `tektoncd` `tep`
<!--
**Note:** When your TEP is complete, all of these comment blocks should be removed.

To get started with this template:

- [ ] **Fill out this file as best you can.**
  At minimum, you should fill in the "Summary", and "Motivation" sections.
  These should be easy if you've preflighted the idea of the TEP with the
  appropriate Working Group.
- [ ] **Create a PR for this TEP.**
  Assign it to people in the SIG that are sponsoring this process.
- [ ] **Merge early and iterate.**
  Avoid getting hung up on specific details and instead aim to get the goals of
  the TEP clarified and merged quickly.  The best way to do this is to just
  start with the high-level sections and fill out details incrementally in
  subsequent PRs.

Just because a TEP is merged does not mean it is complete or approved.  Any TEP
marked as a `proposed` is a working document and subject to change.  You can
denote sections that are under active debate as follows:

```
<<[UNRESOLVED optional short context or usernames ]>>
Stuff that is being argued.
<<[/UNRESOLVED]>>
```

When editing TEPS, aim for tightly-scoped, single-topic PRs to keep discussions
focused.  If you disagree with what is already in a document, open a new PR
with suggested changes.

If there are new details that belong in the TEP, edit the TEP.  Once a
feature has become "implemented", major changes should get new TEPs.

The canonical place for the latest set of instructions (and the likely source
of this file) is [here](/teps/NNNN-TEP-template/README.md).

-->
# TEP-NNNN: Tekton OCI bundles

<!-- toc -->
- [Summary](#summary)
- [Motivation](#motivation)
  - [Goals](#goals)
  - [Non-Goals](#non-goals)
- [Requirements](#requirements)
- [Proposal](#proposal)
  - [Contract](#contract)
  - [User Stories (optional)](#user-stories-optional)
  - [Risks and Mitigations](#risks-and-mitigations)
- [Design Details](#design-details)
- [Test Plan](#test-plan)
- [Drawbacks](#drawbacks)
- [Alternatives](#alternatives)
<!-- /toc -->

## Summary

This proposal is to be able to bundle Tasks (and Pipelines, and
Resources, and potentially other future config objects) into an [OCI
Artifact](https://github.com/opencontainers/artifacts), pushed to an
image registry, and referenced from that registry.

This is a TEP for the **Spec** of the Tekton OCI bundle that were
discussed in the following docs:

- [Tekton OCI Image Catalog](https://docs.google.com/document/d/1zUVrIbGZh2R9dawKQ9Hm1Cx3GevKIfOcRO3fFLdmBDc/edit#heading=h.tp9mko2koenr)
- [Tekton OCI Image Design](https://docs.google.com/document/d/1lXF_SvLwl6OqqGy8JbpSXRj4hWJ6CSImlxlIl4V9rnM/edit?pl=1#)

This will be based from the knowledge acquired on the [experimental oci
project](https://github.com/tektoncd/experimental/tree/master/oci) we ran.

## Motivation

Today, TaskRuns can be defined completely (user specifies
`.spec.taskSpec.steps` etc.), or by referencing a Task that must have
previously been defined in the cluster's API server (user specifies
`.spec.taskRef.name` and optionally `.namespace` -- if a Task doesn't
exist with the specified name in the TaskRun's namespace, we check if
it's a ClusterTask).

This is overly limiting. It makes versioning hard, and it makes
rolling out changes to Task definitions hard.

We can leverage existing tooling and infrastructure used for sharing
OCI images. An OCI image is really just a format for a set
of binary files that can be uploaded to a registry (think DockerHub)
with a tagged version and digest. It can easily be used to version and
share Tasks and other Tekton resources.

### Goals

The goal of this TEP is to define the specification for the Tekton OCI
bundles. The goal of the Tekton OCI bundles is to define a Spec on top
of a known, widely used transport mechanisms, which are the OCI
artifact (OCI images, …).

### Non-Goals

How Tekton OCI bundles are used (referred to) in the different Tekton
components is out of scope and will be the subject for an additional
TEP. Some examples in the doc might suggest how we would reference
those in Pipeline CRDs but they are only examples, not propositions.

The tooling around Tekton OCI bundles is also out of scope.


## Requirements

- Images have a defined format that allows Tasks, Pipelines, and any
  other Tekton specific types to be written in, and read out.
- The spec should be documented well enough such that any user could
  write tooling to generate a valid Tekton Bundle

## Proposal

When using a Tekton Bundle in a task or pipeline reference, the OCI artifact backing the
bundle must adhere to the following contract.

Our most important capability is enabling references of remote Tasks
from within TaskRuns or Pipelines and Pipelines from within
PipelineRuns.

With that in mind, a little background on the OCI format is
necessary. For a deeper understanding see
https://github.com/opencontainers/image-spec. At its most basic an
image is a manifest specifying a set of Layers referenced by a sha256
digest. Each Layer has a media type and can have annotations. Looking
at other similar projects (eg Helm 3) and building off of the
knowledge from our experiment, we have arrived at the following spec:

- An image will store each resource as a new layer
  This allows us to quickly store and retrieve individual resources
  because we can key the layer they reside in against its metadata
- Each layer will have a org.opencontainers.image.title annotation
  (this a commonly used annotation: link) that contains the
  ObjectMetadata.Name field of the resource
- Each layer will have a cdf.tekton.image.kind annotation which
  specifies the Kind of the resource. For example Kind: Task would
  become “task” and Kind: Pipeline would become “pipeline”.
- Each layer will have a cdf.tekton.image.apiVersion annotation which
  specifies the apiVersion of the object (eg, v1beta1).

This choice presents some tradeoffs:

- Two objects of the same {name, type, apiVersion} will be
  rejected. This is purposeful because it replicates existing
  in-cluster functionality. You wouldn’t be able to store two Tekton
  Tasks of the same name and apiVersion in a namespace so to make the
  task references easier to reason about, we enforce the same
  characteristic on the images.
- We are not using any metadata about how the task was generated such
  as the name of any tooling, the location of the task definition on
  disk when it was uploaded (like a file path), etc. Nothing prevents
  us from adding this metadata in the future but for a better user
  experience and to make the feature easier to reason about, we choose
  not to use that metadata when referencing a remote image right now.

We do not add a custom MIME type. This is something that helm does do
but it presents a challenge of needing to get most registries to
support this mime type. Most will simply reject it as one they do not
understand which presents a challenge to adoption. We can always add
this later but we can still do all of the same things with the default
MIME type.

### Contract

Only Tekton CRDs (eg, `Task` or `Pipeline`) may reside in a Tekton Bundle used as a Tekton
bundle reference.Each layer of the image must map 1:1 with a single Tekton resource.Each
layer must contain the following annotations:

- `org.opencontainers.image.title` =>`ObjectMeta.Name` of the resource
- `cdf.tekton.image.kind` => `TypeMeta.Kind` of the resource, all lowercased (eg, `task`)
- `cdf.tekton.image.apiVersion` => `TypeMeta.APIVersion` of the resource (eg
  "tekton.dev/v1alpha1")

Each { `apiVersion`, `kind`, `title` } must be unique in the image. No resources of the
same version and kind can be named the same.

The contents of each layer must be the parsed YAML of the corresponding Tekton
resource. If the resource is missing any identifying fields (missing an `apiVersion` for
instance) than it will not be parseable.


### User Stories (optional)

<!--
Detail the things that people will be able to do if this TEP is implemented.
Include as much detail as possible so that people can understand the "how" of
the system.  The goal here is to make this feel real for users without getting
bogged down.
-->

**To be completed**

### Risks and Mitigations

<!--
What are the risks of this proposal and how do we mitigate.  Think broadly.
For example, consider both security and how this will impact the larger
kubernetes ecosystem.

How will security be reviewed and by whom?

How will UX be reviewed and by whom?

Consider including folks that also work outside the WGs or subproject.
-->

**To be completed**

## Design Details

<!--
This section should contain enough information that the specifics of your
change are understandable.  This may include API specs (though not always
required) or even code snippets.  If there's any ambiguity about HOW your
proposal will be implemented, this is the place to discuss them.
-->

**To be completed**

## Test Plan

<!--
**Note:** *Not required until targeted at a release.*

Consider the following in developing a test plan for this enhancement:
- Will there be e2e and integration tests, in addition to unit tests?
- How will it be tested in isolation vs with other components?

No need to outline all of the test cases, just the general strategy.  Anything
that would count as tricky in the implementation and anything particularly
challenging to test should be called out.

All code is expected to have adequate tests (eventually with coverage
expectations).
-->

**To be completed**

## Drawbacks

<!--
Why should this TEP _not_ be implemented?
-->

**To be completed**

## Alternatives

<!--
What other approaches did you consider and why did you rule them out?  These do
not need to be as detailed as the proposal, but should include enough
information to express the idea and why it was not acceptable.
-->

**To be completed**
