Skip to content

konflux-ci/task-runner

Task Runner Image

A container image with CLI tools commonly used by Konflux Tasks. Released to quay.io/konflux-ci/task-runner.

This project implements ADR-0046: Common Task Runner Image.

Purpose

The Task Runner image consolidates multiple CLI tools into a single container image, simplifying Task creation and reducing the maintenance overhead of managing multiple tool-specific images.

You can use it directly as the runtime image for Konflux Tasks or as a base image for more specialized runner images.

Included Tools

See Installed-Software.md for the complete list of tools and their versions.

Note

In main, this file is always up to date with the latest commit. To see the software installed in a specific version of the runner image, switch to the corresponding version tag.

Adding New Tools

Criteria

Tools must meet the following requirements for inclusion:

  • Must be a standalone CLI tool
    • Language runtimes are also acceptable (e.g. Python)
  • Must be installable hermetically
  • Must follow a versioning scheme (preferably semantic versioning)
  • Should have release notes or a changelog

Installation Methods

Tools are organized by installation method:

RPM Packages

RPM packages use a lockfile-based approach for hermeticity and reproducibility.

Process:

  1. Add the package name to deps/rpm/rpms.in.yaml under either:

    • packages - for new packages
    • reinstallPackages - for packages already in the base image (we want control over their versions)
  2. Regenerate the lockfile:

    make rpms.lock.yaml
  3. Regenerate auto-generated files:

    devtool gen --all

The install-rpms.sh script reads the infile and the lockfile and automatically installs the exact package versions specified.

Go Tools

If the tool is installable via go install, prefer this approach. Compared to the submodule approach, this results in more accurate SBOMs.

Each tool has its own directory with go.mod/go.sum, which is crucial for independent version management. Go's MVS ensures we get the same versions of dependencies used upstream. Combining multiple tools in one go.mod file would break that.

Process:

  1. Create a directory under deps/go-tools/ with the tool name

  2. Inside, create go.mod and go.sum that reference the tool's CLI package. Example:

    mkdir deps/go-tools/cosign
    cd deps/go-tools/cosign
    go mod init github.com/konflux-ci/task-runner/deps/go-tools/cosign
    go get -tool github.com/sigstore/cosign/v3/cmd/cosign@v3.0.2
    go mod tidy

    Note: Use go get -tool (not just go get). Specify the package with the CLI binary, which is often a sub-package of the module (e.g. github.com/sigstore/cosign/v3/cmd/cosign, not github.com/sigstore/cosign/v3).

  3. Add the tool to install-tools.sh:

    install_tool <name> [version_ldflags_attribute]

    The version_ldflags_attribute injects the version into the binary and is required for tools that use this approach (otherwise tests will fail when checking version output). To find the correct attribute, inspect the tool's upstream build process (often found in the Makefile or build scripts).

  4. Regenerate auto-generated files:

    devtool gen --all

Git Submodules (Go)

If the tool is not installable with go install, e.g. due to the use of replace directives in the tool's go.mod or due to incorrectly formatted semver tags, fall back to git submodules.

Process:

  1. Add the submodule and check out a semver(-ish) tag:

    cd deps/go-submodules
    git submodule add <repository-url> <tool-name>
    cd <tool-name>
    git checkout v1.2.3
  2. In .gitmodules, set the branch field to the current tag (Renovate uses this for updates). If the submodule doesn't use correct semver tags (like oc), add corresponding Renovate configuration in devtool/renovate.py with a custom versioning regex.

  3. Add build commands to install-submodules.sh

  4. Regenerate auto-generated files:

    devtool gen --all

Pip Packages

Pip packages use a lockfile-based approach similar to RPM packages. Direct dependencies go in requirements.in, and resolved transitive dependencies go in requirements.txt. Konflux's Hermeto can pre-fetch pip packages from requirements.txt for hermetic builds.

Because we re-build the packages from source rather than using pre-built wheels, we also need a requirements-build.txt file listing the build dependencies. Both of the requirements*.txt files can be auto-generated with make pip-requirements.

Process:

  1. Add the package name to deps/pip/requirements.in:

    awscli
    
  2. Regenerate requirements.txt and requirements-build.txt

    make pip-requirements
  3. Regenerate auto-generated files:

    devtool gen --all

Local Tools

Konflux Tasks have come to depend on two crucial scripts:

  • select-oci-auth, a workaround for tools that do not handle containers-auth.json correctly (such as oras and cosign)
  • retry for retrying commands, especially those that interact with quay.io as this interaction can be rather unreliable
    • Note: the image sets RETRY_STOP_IF_STDERR_MATCHES=unauthorized for backwards compatibility with the original retry script, which would abort on 'unauthorized'

While including arbitrary Bash scripts goes against the Criteria for tool inclusion, these two are so ubiquitous that, for practicality, the runner image has to include them.

They have, at least, become more legitimate standalone tools:

  • They each have their own version and CHANGELOG.md
  • They will be following semantic versioning
  • They have tests (in tests/local-tools)

These two are an exception to the rule. We don't intend to add more local tools.

Development Workflow

Prerequisites

  • Python 3.12+
  • uv (Python package manager)
  • Podman

Setup

Initialize/update git submodules:

make submodules

Create a virtual environment and install dependencies:

make venv
source .venv/bin/activate

Helper Tool

The devtool CLI assists with common development tasks:

devtool ls         # List all tools to be installed
devtool gen --all  # Generate files (e.g. Installed-Software.md)

Building the Image

Locally:

podman build -t task-runner .

For production: we use Konflux CI. See the pipelines in .tekton/.

Testing

There are two types of tests:

  • Tests for the built task-runner image
  • Tests for local tools (in tests/local-tools)

Run them all at once with:

pytest

Tests for the built image

pytest --ignore=tests/local-tools

By default, tests build the image and tag it localhost/task-runner:test. To skip rebuilding and test an existing image, set the TEST_IMAGE environment variable:

# Build once
podman build -t localhost/task-runner:latest .

# Run tests against the existing image
TEST_IMAGE=localhost/task-runner:latest pytest

# Set it in .env for persistent use (if you use direnv or similar shell integration)
echo 'TEST_IMAGE=localhost/task-runner:latest' >> .env

Tests automatically discover packages and their expected versions using the code in devtool/software_list.py. If a new package isn't detected properly, you may need to update the discovery logic there. You may also need to update test configuration (e.g. version_arg_overrides in tests/test_installed_packages.py for tools that don't support the standard --version flag).

Tests for local tools

pytest tests/local-tools

These are tests for the tools in local-tools/. They execute the tools directly on your machine and verify the expected behavior.

Updating RPM Lockfile

After modifying deps/rpm/rpms.in.yaml:

make rpms.lock.yaml

This uses rpm-lockfile-prototype to resolve and lock package versions.

Releasing

Versioning

  • The version of the runner image is tracked in the VERSION file
    • The Konflux build pipeline automatically sets the org.opencontainer.image.version annotation (and label as well) on the built image using our custom .tekton/tasks/get-build-params.yaml Task
  • All notable changes are tracked in the CHANGELOG.md file

When making a new release, bump the version according to the first matching rule:

  • Removed a tool / updated the major version of any tool -> bump the major version
  • Added a new tool / updated the minor version of any tool -> bump the minor version
  • Otherwise -> bump the patch version

To bump the version automatically based on the changes in installed software, use:

devtool prep-release

The tool will automatically update the VERSION file and output a markdown list with the changes since the last release. Include this list when updating CHANGELOG.md.

If there are no relevant changes to the installed software (i.e. the Installed-Software.md file did not change), the tool will abort without doing any changes. In that case, if you do want to do a release, please update the VERSION file manually and write the changelog content yourself.

Release process

  1. Determine what has changed since last release and update the VERSION and CHANGELOG.md files accordingly (see above).
  2. Send a PR to update the version and changelog.
  3. Once merged, create the GitHub release as v{version} (e.g. v0.1.0). In the release notes, just link the relevant heading in CHANGELOG.md.
  4. Merging the PR will have triggered a Konflux on-push pipeline, which will automatically trigger a release to https://quay.io/konflux-ci/task-runner upon success. Verify that the build and release succeed.

About

Common runner image to use for Tekton tasks

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

No packages published

Contributors 7