Prefetching package manager dependencies for hermetic builds
In Konflux, you can run a hermetic build by restricting network access to the build, but without network a build can’t fetch component dependencies from a repository and might fail. To avoid that, Konflux can prefetch dependencies for your hermetic builds using Cachi2.
For every build, Cachi2 generates a software bill of materials (SBOM) where all dependencies are properly declared and pinned to specific versions. Also, Cachi2 ensures that arbitrary code is never executed during the prefetch, meaning, for example, that the build doesn’t pull any undeclared dependencies. Such measures result in very accurate SBOMs and improve the build reproducibility. For more information about SBOMs, see Inspecting SBOMs.
Package manager |
Programming language |
|
|
|
|
|
|
|
|
|
|
|
|
|
*The rpm-lockfile-prototype and the rpm package manager for cachi2 are not fully supported. You can use them to prefetch rpms for your hermetic builds, but the file format and technology may change in the future. If you’re interested in the future of this topic, join the discussion at rpm-software-management/dnf5#833. |
Enabling prefetch builds for gomod
-
You have a
go.mod
file in your repository that lists all the dependencies.
To prefetch dependencies for a component build, complete the following steps:
-
Go to the
.tekton
directory in your component repository and find the.yaml
files related to both thepull request
andpush
processes. -
To configure the hermetic pipeline in both
.yaml
files, add the following hermetic pipelineprefetch-input
parameters to thespec.params
sections:spec: params: - ... - name: prefetch-input value: '{"type": "gomod", "path": "."}' (1)
1 The prefetch-input
parameter specifies the path to the directory that has the lockfile and the package metadata files. In this example, the.
indicates that the package manager lockfile is in the repository root. Additionally, if you have multiple directories, you can provide the path to those directories in the JSON array format. For example,[{"path": ".", "type": "gomod"}, {"path": "subpath/to/the/other/directory", "type": "gomod"}]
. -
Create a pull request by committing your changes to the repository of the component.
-
Review and merge the pull request.
-
From the Konflux Applications view, go to Activity > Pipeline runs.
-
Go to the pipeline run with Build in the Type column and confirm that the
prefetch-dependencies
stage displays a green checkmark. This indicates that the build process successfully fetched all dependencies.
-
-
From the Konflux Applications view, go to Activity > Latest commits.
Enabling prefetch builds for pip
Cachi2 supports pip by parsing of pip
requirements files, including but not limited to, requirements.txt
files placed in the root of your repository. By generically parsing pip
requirements files, Cachi2 downloads the specified dependencies.
The requirements file can have a different name because you can use multiple files to provide the dependencies. These requirements files function as lockfiles, encompassing all transitive dependencies. You must actively pin each transitive dependency listed in the requirements file to a specific version. |
-
You have an environment that closely matches the environment in the container build, meaning it has the same operating system and the same python $major.$minor version.
-
You have installed the pip-tools package.
To prefetch dependencies for a component build, complete the following steps:
-
Download the pip_find_builddeps.py script directly from GitHub.
This script has no runtime dependency other than pip
. -
Add the script that you downloaded in a directory that is already included in your $PATH. For example, you can use the
~/bin
directory in your home folder. Ensure that it exists or create it if needed. To add it to the $PATH permanently, you can modify the shell configuration file (for example,.bashrc
,.bash_profile
, or.zshrc
) and restart the terminal after appending the following line:export PATH="$HOME/bin:$PATH"
-
Open the terminal and go to the directory where you placed the
pip_find_builddeps.py
script and run the following command to make it executable:chmod +x pip_find_builddeps.py
-
Go to your component’s source code.
-
Review the root of your repository for a metadata file, for example,
pyproject.toml
,setup.py
, orsetup.cfg
. If there is no metadata file, create one, because Cachi2 looks for the name and version of your project in the metadata files.[metadata] name = "my_package" version = "0.1.0"
Instead of a pyproject.toml
file, you can also create asetup.py
orsetup.cfg
file. For information about the metadata of these files, see Project metadata. -
Generate a fully resolved
requirements.txt
file that contains all the transitive dependencies and pins them to a specific version and hash by using the following command:$ pip-compile pyproject.toml --generate-hashes
-
To successfully run the previous command, your environment must be as close as possible to the environment in the container build. That is, the environment should have the same operating system and the same Python $major.$minor version.
-
The previous command assumes that you have defined project dependencies in
pyproject.toml
. However, if you have defined the project dependencies in either thesetup.py
,requirements.txt
, orrequirements.in
files, make sure you update the command accordingly.
-
-
Add the
requirements.txt
file to the root of your component source code. -
In the root of your repository create a
requirements-build.in
file. -
Copy the build system requirements from the
pyproject.toml
file to therequirements-build.in
file.
-
Run the
pip_find_builddeps.py
script andpip-compile
the outputs by using the following command:$ pip_find_builddeps.py requirements.txt \ --append \ --only-write-on-update \ -o requirements-build.in
-
Use the
pip-compile
command to convert therequirements-build.in
file in to therequirements-build.txt
file by using the following command:$ pip-compile requirements-build.in --allow-unsafe --generate-hashes
-
Add the
requirement-build.txt
file to your project. It does not require any changes to your build process.pip
automatically installs the build dependencies when needed for explicit installation. The purpose of therequirement-build.txt
file is to enable Cachi2 to fetch the build dependencies and provide them topip
for offline installation in a network-isolated environment. -
Go to the
.tekton
directory and locate the.yaml
files related to thepull request
andpush
processes. -
Configure the hermetic pipeline.
-
Add the following hermetic pipeline
prefetch-input
parameters in both the.yaml
files:spec: params: - ... - name: prefetch-input value: '{"type": "pip", "path": "."}' (1)
1 The prefetch-input
parameter specifies the path to the directory that has the lockfile and the package metadata files. In the previous example, the.
indicates that the package manager lockfile is located in the root of the repository. Additionally, if you have multiple directories, you can provide the path to those directories in the JSON array format. For example,[{"path": ".", "type": "pip"}, {"path": "subpath/to/the/other/directory", "type": "pip"}]
.-
By default, Cachi2 processes
requirements.txt
andrequirements-build.txt
at a specified path. -
When adding these parameters, you can safely ignore the default values for the
pipelineSpec.params
in the.yaml
files.
-
-
Optional: For requirements files without default names and path, add the following hermetic pipeline
prefetch-input
parameters in both the.yaml
files:spec: params: - ... - name: prefetch-input value: '{"type": "pip", "path": ".", "requirements_files": ["requirements.txt", "requirements-extras.txt", "tests/requirements.txt"]}' (1)
1 The prefetch-input
parameter specifies the path to the directory that has the lockfile and the package metadata files. In the previous example, the.
indicates that the package manager lockfile is located in the root of the repository. Additionally, if you have multiple directories, you can provide the path to those directories in the JSON array format. For example,[{"path": ".", "type": "pip", , "requirements_files": ["requirements.txt", "requirements-extras.txt", "tests/requirements.txt"]}, {"path": "subpath/to/the/other/directory", "type": "pip", "requirements_files": ["requirements.txt", "requirements-extras.txt", "tests/requirements.txt"]}]
.
-
-
Create a pull request by committing your changes to the repository of the component.
-
Review and merge the pull request.
-
From the Konflux Applications view, go to Activity > Pipeline runs.
-
Go to the pipeline run with Build in the Type column and confirm that the
prefetch-dependencies
stage displays a green checkmark. This indicates that the build process successfully fetched all dependencies.
-
-
From the Konflux Applications view, go to Activity > Latest commits.
Prefetching pip
dependencies from custom index servers
Cachi2 supports the --index-url option.
You can add this option to your requirements.txt
file(s), instructing Cachi2 to download packages from the specified
index server. For example:
--index-url=https://example.pypi.org/simple/
requests==2.32.2 \
--hash=sha256:dd951ff5ecf3e3b3aa26b40703ba77495dab41da839ae72ef3c8e5d8e2433289 \
--hash=sha256:fc06670dd0ed212426dfeb94fc1b983d917c4f9847c863f313c9dfaaffb7c23c
# ...other packages
Do not include credentials in the index url. If needed, provide authentication through a .netrc file (as described below).
|
To provide .netrc
authentication for the index server:
-
Create a key/value secret (see creating secrets for your builds). Set
.netrc
as the key. Upload the content of your.netrc
file as the value. For more details on netrc files, review the pip documentation for netrc support. -
In your
.tekton/
PipelineRun files, add the newly created secret to the.spec.workspaces
section:spec: # ... workspaces: # ... - name: netrc secret: secretName: my-netrc # the name you assigned to the secret in step 1
-
In the
.spec.pipelineSpec.tasks
section, find the entry withname: prefetch-dependencies
. Add thenetrc
workspace to the list of workspaces (if not present):tasks: # ... - name: prefetch-dependencies # ... workspaces: # ... - name: netrc workspace: netrc
Enabling prefetch builds for npm
Cachi2 supports npm
by fetching any dependencies you declare in your package.json
and package-lock.json
project files. The npm CLI manages the package-lock.json
file automatically, and Cachi2 fetches any dependencies and enables your build to install them without network access.
-
You have an up-to-date
package-lock.json
file, newer than version 1, in your source repository. To make sure that you have the latestpackage-lock.json
file, or to create a lockfile, run thenpm-install
command. You can also look at thelockfileVersion
attribute in yourpackage-lock.json
file to make sure its value is a number greater than1
.
To prefetch dependencies for a component build, complete the following steps:
-
Go to the
.tekton
directory and find the.yaml
files related to thepull request
andpush
processes. -
Configure the hermetic pipeline by adding the following parameters in both
.yaml
files:spec: params: - ... - name: prefetch-input value: '{"type": "npm", "path": "."}' (1)
1 The prefetch-input
parameter specifies the path to the directory that has the lockfile and the package metadata files. In this example, the.
indicates that the package manager lockfile is in the repository root. Additionally, if you have multiple directories, you can provide the path to those directories in the JSON array format. For example,[{"path": ".", "type": "npm"}, {"path": "subpath/to/the/other/directory", "type": "npm"}]
. -
Create a pull request by committing your changes to the repository of the component.
-
Review and merge the pull request.
-
From the Konflux Applications view, go to Activity > Pipeline runs.
-
Go to the pipeline run with Build in the Type column and confirm that the
prefetch-dependencies
stage displays a green checkmark. This indicates that the build process successfully fetched all dependencies.
-
-
From the Konflux Applications view, go to Activity > Latest commits.
Enabling prefetch builds for yarn
Supported versions: 1.x and 3.x. Cachi2 automatically detects the version of yarn
and fetches any dependencies you declare in your package.json
and yarn.lock
project files.
-
You have an up-to-date
yarn.lock
file in your source repository. To ensure you have the latestyarn.lock
file or to create it, run theyarn install
command. Ifyarn.lock
is not up-to-date, Cachi2 will not fetch the dependencies.
To prefetch dependencies for a component build, complete the following steps:
-
Go to the
.tekton
directory and find the.yaml
files related to thepull request
andpush
processes. -
Configure the hermetic pipeline by adding the following parameters in both
.yaml
files:spec: params: - ... - name: prefetch-input value: '{"type": "yarn", "path": "."}'
Enabling prefetch builds for bundler
You have a Gemfile
and a Gemfile.lock
file in your repository that lists all the dependencies. The Gemfile.lock
is generated from the Gemfile
and contains all transitive dependencies pinned to specific versions.
To prefetch dependencies for a component build, complete the following steps:
-
Go to the
.tekton
directory and find the.yaml
files related to thepull request
andpush
processes. -
Configure the hermetic pipeline by adding the following parameters in both
.yaml
files:spec: params: - ... - name: prefetch-input value: '{"type": "bundler", "path": ".", "allow_binary": "false"}' (1)
1 The allow_binary
parameter specifies whether to allow gems for specific platforms. By default, the value isfalse
. If you want to allow gems for specific platforms, set the value totrue
. -
Create a pull request by committing your changes to the repository of the component.
-
Review and merge the pull request.
Enabling prefetch builds for rpm
Cachi2 has a dev-preview package manager capable of fetching rpm
dependencies. This requires the use of a pair of rpms.in.yaml
and rpms.lock.yaml
files to be committed to your repository. You write a rpms.in.yaml
file and the rpm-lockfile-prototype CLI tool resolves that to produce a rpms.lock.yaml
file. Cachi2 fetches those specific rpms and enables your build to install them without network access.
-
You have an up-to-date installation of rpm-lockfile-prototype.
To prefetch dependencies for a component build, complete the following steps:
-
Create a
rpms.in.yaml
file in your git repository, with the following contents:packages: [nethack] (1) contentOrigin: repofiles: ["./fedora.repo"] (2)
1 The packages
list is the list of packages you want to install in your Container. You don’t have to declare transitive dependencies here. The rpm-lockfile-prototype tool will resolve them for you.2 This should be a reference to a repo file, like those found in /etc/yum.repos.d/
. This tells the tooling where to find your rpm and its dependencies. -
Copy any necessary yum/dnf repo files into your git repository. If you are using a fedora rawhide base image, that looks like:
$ BASE_IMAGE=quay.io/fedora/fedora:rawhide $ podman run -it $BASE_IMAGE cat /etc/yum.repos.d/fedora.repo > fedora.repo
For every repository defined in your set of repo files, make sure to add the corresponding sources repo (or make sure to enable them, if they’re already present). Otherwise, the lockfile generator will not include any SRPMs in your lockfile, cachi2 won’t download any SRPMs and the source container for your build will be incomplete. -
Run the following command to resolve your
rpms.in.yaml
file and produce arpms.lock.yaml
file.$ BASE_IMAGE=quay.io/fedora/fedora:rawhide $ rpm-lockfile-prototype --image $BASE_IMAGE rpms.in.yaml (1)
1 The produced rpms.lock.yaml
file will include only your requested dependency plus its transitive dependencies, minus any rpms that are already installed in the provided base image. -
Go to the
.tekton
directory and find the.yaml
files related to thepull request
andpush
processes. -
Configure the hermetic pipeline by adding the following parameters in both
.yaml
files:spec: params: - ... - name: prefetch-input value: '{"type": "rpm", "path": "."}' (1)
1 The prefetch-input
parameter specifies the path to the directory that has the lockfile. In this example, the.
indicates that the rpm lockfile is in the repository root. Additionally, if you have multiple directories, you can provide the path to those directories in the JSON array format. For example,[{"path": ".", "type": "rpm"}, {"path": "subpath/to/the/other/directory", "type": "rpm"}]
. -
Additionally, pass an extra parameter to the
prefetch-dependencies
task in the.spec.pipelineSpec.tasks
section to indicate that "dev package managers" should be enabled.tasks: - ... - name: prefetch-dependencies params: - ... - name: dev-package-managers (1) value: "true"
1 You won’t find dev-package-managers
as a param on theprefetch-dependencies
task. You have to add it, and set it to true. This is because Cachi2 hasn’t declared stable support for rpm lockfile processing yet. It’s new technology and the conversation about which way forward in the dnf community is still ongoing. -
Create a pull request by committing your changes to the repository of the component.
-
Review and merge the pull request.
-
From the Konflux Applications view, go to Activity > Pipeline runs.
-
Go to the pipeline run with Build in the Type column and confirm that the
prefetch-dependencies
stage displays a green checkmark. This indicates that the build process successfully fetched all configured dependencies.
-
-
From the Konflux Applications view, go to Activity > Latest commits.
If your build fails, be sure to look at your logs:
In Konflux, from the Applications view, select the application build you want to troubleshoot, then from the resulting Overview page, select the Activity tab. From there, under Activity By, select Pipeline runs. From the Name column, select the build whose logs you want to check, then from the resulting Pipeline run details view, do one of the following:
-
Select the Logs tab.
-
Alternatively, you can click build-container. When the right panel opens, select the Logs tab to see a partial view of the log for that build.
Konflux also supports prefetching RPM content which requires a Red Hat subscription. For more information see Using Red Hat activation keys to access subscription content. |
Enabling prefetch builds for generic fetcher
If you need to prefetch arbitrary files for your build, Cachi2 supports generic fetcher
for that purpose. It uses a custom lockfile named artifacts.lock.yaml
to achieve this. This file needs to be either commited in the source repository, or explicitly specified as an absolute path. The latter is useful in case you for some reason need the lockfile to be dynamic and committing it to the repository would be problematic. For more information on supported types of artifacts, see Cachi2 documentation.
To prefetch dependencies for a component build, complete the following steps:
-
Create a
artifacts.lock.yaml
file in your git repository, with a list of files to prefetch, their checksums, and optionally their filenames. See Cachi2 documentation for complete overview of the lockfile format.--- metadata: (1) version: "1.0" artifacts: - download_url: "https://github.com/jeremylong/DependencyCheck/releases/download/v11.1.0/dependency-check-11.1.0-release.zip" checksum: "sha256:c5b5b9e592682b700e17c28f489fe50644ef54370edeb2c53d18b70824de1e22" (2) filename: "dependency-check.zip" (3)
1 metadata
section is required and needs to specify lockfile version2 checksum
is expected to be specified asalgorith:hash
3 If no filename
is specified, it will be derived from the URL. -
Go to the
.tekton
directory and find the.yaml
files related to thepull request
andpush
processes. -
Configure the hermetic pipeline by adding the following parameters in both
.yaml
files:spec: params: - ... - name: prefetch-input value: '{"type": "generic", "path": "."}' (1)
1 The prefetch-input
parameter specifies the path to the directory that has the lockfile. In this example, the.
indicates that the lockfile is in the repository root. Additionally, if you have multiple directories, you can provide the path to those directories in the JSON array format. For example,[{"path": ".", "type": "generic"}, {"path": "subpath/to/the/other/directory", "type": "generic"}]
. Alternatively, if your lockfile is generated as part of your pipeline and is not commited to the repository, you can specify an absolute path to it, like this:{"type": "generic", "path": ".", "lockfile": "/absolute/path/to/artifacts.lock.yaml"}
.
-
From the Konflux Applications view, go to Activity > Pipeline runs.
-
Go to the pipeline run with Build in the Type column and confirm that the
prefetch-dependencies
stage displays a green checkmark. This indicates that the build process successfully fetched all dependencies.
-
-
From the Konflux Applications view, go to Activity > Latest commits.
If your build fails, be sure to look at your logs:
In Konflux, from the Applications view, select the application build you want to troubleshoot, then from the resulting Overview page, select the Activity tab. From there, under Activity By, select Pipeline runs. From the Name column, select the build whose logs you want to check, then from the resulting Pipeline run details view, do one of the following:
-
Select the Logs tab.
-
Alternatively, you can click build-container. When the right panel opens, select the Logs tab to see a partial view of the log for that build.
Additional resources
-
To troubleshoot any issues you might experience when you enable prefetch builds for
pip
orpip
with source dependencies, see Troubleshooting. -
For more information about Cachi2, see Cachi2.