Building Tekton tasks as bundles in Konflux

This document provides a step-by-step guide on how to onboard your Tekton tasks to Konflux, build them as OCI bundles and release them.

Prerequisites

Before you begin, ensure you have the following:

  • A GitHub repository containing your Tekton tasks. Use a flat layout with one YAML file per task, along with supporting files:

    task/
    └── echo/
        ├── echo.yaml
        ├── CHANGELOG.md
        ├── README.md
        ├── USAGE.md
        └── TROUBLESHOOT.md

    If you maintain multiple version streams, use a subdirectory for the older stream:

    task/
    └── echo/
        ├── 1.x/
        │   └── echo.yaml
        ├── echo.yaml
        ├── CHANGELOG.md
        └── README.md
  • Konflux GitHub application installed in the repository GitHub App

  • Access to the Konflux environment.

  • Necessary permissions to create and manage components in Konflux.

  • An OCI registry to contain the artifacts

Onboarding Steps

Onboarding tasks to Konflux is similar to onboarding other applications and components, except that you do not need a Containerfile since you are not building container images.

Application, Components and ImageRepository

Tekton tasks are built as standard OCI artifacts in Konflux.

Refer to the Creating applications and components page for information on how to create an Application for your tasks and a Component for each task within this Application, as well as an ImageRepository resource.

  • Each task is represented by a component. Set the pipeline to tekton-bundle-builder-oci-ta and the context to the task directory within the repository (for example, task/echo).

  • Use the naming convention <task-name> for the component (for example, task-echo).

Once these resources are created, a PR with on-pr and push PipelineRuns is sent to your repository.

  • The on-pr PipelineRun is created with the context defined for the component and with on-cel-expression to run the PipelineRun only when a change is detected in the component. For example:

pipelinesascode.tekton.dev/on-cel-expression: |
    event == "pull_request"
    && target_branch == "main"
    && (
    "task/echo/***".pathChanged() || ".tekton/echo-pull-request.yaml".pathChanged()
    )

However, a conflict can arise when using on-cel-expression to control the execution of a pipeline in conjunction with a GitHub branch protection rule that mandates the pipeline’s successful completion. If the conditions of the on-cel-expression are not met, the pipeline does not run. However, the branch protection rule still expects a "passing" status, causing the check to remain pending and blocking the merge. For example:

  • Branch protection rule expects echo-pull-request to end successfully before merge.

  • on-cel-expression is set to run only if changes occur in the task/echo/*** path.

  • A PR with changes in another path is submitted.

The echo-pull-request does not run because the condition in the on-cel-expression is not met, but the GitHub branch protection expects it to run and end successfully before merge.

In this case, update the on-cel-expression in the on-pr PipelineRun:

pipelinesascode.tekton.dev/on-cel-expression: event == "pull_request" && target_branch == "main"
  • The push PipelineRun is created with a default on-cel-expression. Update it to run only if changes were made in the context. For example:

pipelinesascode.tekton.dev/on-cel-expression: |
    event == "push"
    && target_branch == "main"
    && (
    "task/echo/***".pathChanged() || ".tekton/echo-push.yaml".pathChanged()
      )

Versioning

Each meaningful change to a task requires a version bump. Define version numbers statically in the app.kubernetes.io/version label of the Task YAML. The build pipeline reads this label and sets the org.opencontainers.image.version OCI annotation on the bundle automatically.

For tasks in initial development (0.x):

  • Bump the minor version for breaking changes (for example, 0.1 to 0.2).

  • Bump the patch version for non-breaking changes (for example, 0.1.0 to 0.1.1).

Once a task is mature, move it to 1.0 and follow Semantic Versioning.

Non-meaningful changes such as formatting or description updates do not require a version bump.

Changelog

Maintain a CHANGELOG.md file for each task at the root of the task directory (for example, task/echo/CHANGELOG.md). Follow the Keep a Changelog format: use a heading for each version with a release date, and group changes under standard categories.

Example:

# Changelog

All notable changes to this project will be documented in this file.

## 0.2.0

### Changed

- BREAKING: Replaced the `verbose` parameter with `log-level` for finer control
  over output verbosity. To migrate, replace `verbose: "true"` with
  `log-level: "debug"` in your PipelineRun parameters.

### Fixed

- Fixed incorrect exit code when the task times out.

## 0.1.0

### Added

- Initial release of the echo task.

Prefix breaking changes with BREAKING: and include migration instructions so that users know what to update in their PipelineRuns or configurations. For automated migrations, see the pipeline-migration-tool.

Release

Release tasks only when their version number changes. Each released bundle should correspond to a deliberate, versioned change. When merging changes to a task, include a version bump in the app.kubernetes.io/version label and a changelog entry.

By default, Konflux automatically releases every merge. To release only when the version changes, you can either trigger releases manually or use automatic version-based releases.

Automatic version-based releases, where the build pipeline detects version bumps and skips the release when the version has not changed, are currently in a final stage of development. See Auto-release logic for details.

Manual releases

To trigger releases manually, set auto-release to "false" in the ReleasePlan. After merging a PR that bumps the task version, trigger the release:

  • Through the Konflux UI: navigate to Applications → select the application → Snapshots → click the three-dot menu on the snapshot → Trigger release.

  • By creating a Release CR. See Creating a release for details.

Release resources

The release process for bundles includes both the release of Tekton tasks as bundles and updating the list of trusted-tasks OCI artifacts.

This list is used to notify the Conforma policies of your trusted tasks. As a preparation for the release, choose a repository path in your public registry organization to hold this artifact.

The repository should be in the same level as our released tasks. For example, if our tasks are released to <OCI registry>/<Organization>/my-team-tasks, we should publish the list to a public repository named <OCI registry>/<Organization>/my-team-tasks/data-acceptable-bundles

So that the structure will be:

OCI registry/
└── Organization/
    └── my-team-tasks/
        ├── task1
        ├── task2
        ├── task3
        └── data-acceptable-bundles

To release Tekton tasks as bundles, create the following resources:

Example:

apiVersion: appstudio.redhat.com/v1alpha1
kind: ReleasePlan
metadata:
  labels:
    release.appstudio.openshift.io/auto-release: "true"
    release.appstudio.openshift.io/releasePlanAdmission: my-tasks
    release.appstudio.openshift.io/standing-attribution: "true"
  name: my-tasks-release-to-quay-konflux-ser
  namespace: my-tasks-tenant
spec:
  application: my-tasks
  target: rhtap-releng-tenant

Example:

apiVersion: appstudio.redhat.com/v1alpha1
kind: ReleasePlanAdmission
metadata:
  name: my-tasks
  namespace: rhtap-releng-tenant
  labels:
    release.appstudio.openshift.io/block-releases: 'false'
    pp.engineering.redhat.com/business-unit: application-developer
spec:
  applications:
    - my-tasks
  policy: tekton-bundle-standard
  origin: my-tasks-tenant
  data:
    releaseNotes:
      product_name: My-Tasks
      product_version: "0.1"
    mapping:
      registrySecret: <Secret to your registry organization> (1)
      defaults:
        public: true
        pushSourceContainer: false (2)
      components:
        - name: echo
          repository: "quay.io/konflux-ci/my-team-tasks/task-echo"
          tags:
            - "{{ oci_version }}"
            - "{{ oci_version }}-{{ timestamp }}"
    pyxis:
      secret: pyxis-prod-secret
      server: production
    intention: production
  pipeline:
    pipelineRef:
      resolver: git
      params:
        - name: url
          value: "https://github.com/konflux-ci/release-service-catalog.git"
        - name: revision
          value: production
        - name: pathInRepo
          value: "pipelines/managed/push-tekton-task-bundles-to-external-registry/push-tekton-task-bundles-to-external-registry.yaml"
    serviceAccountName: konflux-ci-servicerelease-sa
    timeouts:
      pipeline: "4h0m0s"
      tasks: 4h0m0s
1 Use registrySecret to provide a secret for the release pipeline to make image repositories public. To skip this operation, assign an empty string "".
2 Set pushSourceContainer to false to prevent releasing source container images. The source image build is irrelevant to a Tekton bundle build.
  • Map your components (tasks) to the release repository.

  • Use the pipelines/managed/push-tekton-task-bundles-to-external-registry/push-tekton-task-bundles-to-external-registry.yaml pipeline to push the bundles to a registry.

These resources are required for managing and approving the release of Tekton task bundles.

Post actions

You may want to verify that the tasks are pushed as bundles correctly and that the trusted tasks list was updated. To do so after a release, use Tekton CLI and oras to verify the OCI artifacts.

To get your bundle as a YAML file task definition, run:

tkn bundle list <task's repository url> -o yaml

Example:

tkn bundle list quay.io/konflux-ci/my-team-tasks/task-echo:0.1@sha256:d9a056f1ec3e6a8f60347a91f142ec90a54a324cc7fde3e37336ae35a1521234 -o yaml

To get the list of trusted tasks, run:

oras pull <release repository>/data-acceptable-bundles:latest

Example:

oras pull quay.io/konflux-ci/my-team-tasks/data-acceptable-bundles:latest

The command extracts the list of trusted tasks to data/data/trusted_tekton_tasks.yml in your working directory.

Use onboarded tasks as trusted tasks

To use the onboarded tasks and let Conforma identify them as trusted tasks, update the policies and add the new trusted data sources. Use the data-acceptable-bundles OCI artifact that was created or updated during the release process.

Example of a policy that adds quay.io/konflux-ci/my-team-tasks/data-acceptable-bundles:latest as a trusted source:

apiVersion: appstudio.redhat.com/v1alpha1
kind: EnterpriseContractPolicy
metadata:
  name: default
  namespace: enterprise-contract-service
spec:
  description: Conforma policy with the addition of
  oci::quay.io/konflux-ci/my-team-tasks/data-acceptable-bundles:latest as another data source
  name: Default
  publicKey: k8s://openshift-pipelines/public-key
  sources:
  - config:
      exclude: []
      include:
      - '@slsa3'
    data:
    - oci::quay.io/konflux-ci/tekton-catalog/data-acceptable-bundles:latest
    - github.com/release-engineering/rhtap-ec-policy//data
    - oci::quay.io/konflux-ci/my-team-tasks/data-acceptable-bundles:latest
    name: Default
    policy:
    - oci::quay.io/enterprise-contract/ec-release-policy:git-fe45153@sha256:94b62b263b947a762b08d5aa2715f37ff3ba25ff7462850dba9d9a8eec1b4c49

After completing all the steps above you should now have:

  • A task released as a bundle in your release repository.

  • An OCI artifact named data-acceptable-bundles in your release repository, containing a SHA reference of the latest task release as a trusted task. All previous versions of the task appear with the expires_on parameter.