Skip to content

quarry: add rule for building a TUF targets release - #382

Merged
martinpitt merged 4 commits into
mainfrom
quarry-release
Nov 4, 2026
Merged

martinpitt merged 4 commits into
mainfrom
quarry-release

Conversation

@martinpitt

Copy link
Copy Markdown
Member

A quarry release needs TUF targets that describe its files with quarry's marks. Add quarry.release(), which gathers the release folder and adds the targets to it. The marks come from the release's description: files are selected by kind and subkind, and the version is the one all of the release's images share.

Comment thread quarry/BUCK Resolved
@martinpitt

Copy link
Copy Markdown
Member Author

Added another commit which makes the target files reproducible.

Comment thread docs/user/quarry.md Outdated
| --- | --- |
| `version` | every file: the version of the release's images, which must all have the same one |
| `update` | what systemd-sysupdate installs: UKIs, usr partitions and their verity partitions, extensions of any class, portable images |
| `test-input` | what `test_inputs` selects |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before we add this here I think we should rework this to be per test, so that a vmspawn test and a cloud test don't get everything but only what they need.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly, let's just kill this. It's confusing, mostly redundant, other projects would need it as well, and we don't even need it. I sent an internal infra PR to stop using it. Dropped.

Comment thread docs/user/quarry.md
| `update` | what systemd-sysupdate installs: UKIs, usr partitions and their verity partitions, extensions of any class, portable images |
| `test-input` | what `test_inputs` selects |
| `supplemented-by` | what a client fetches alongside: a UKI brings its usr partition and the initrd's SBOMs and package database, a usr partition its verity partitions and the image's SBOMs and package database, an extension or a portable image its own SBOMs and package database. Each names its media type where it has one |
| `verity-root-hash` | the usr partition, extensions and portable images |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is duplicated information from the generated file, maybe not needed, too.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a bit tricky, and needs discussion. I captured it in https://linear.app/amutable/issue/ENG-742 . For now, let's keep it as-is, it doesn't hurt, there is no direct replacement, and we currently rely on it.

Prerequisite for building TUF repositories. Pin quarry and add a hardhat
build rule, together with the boxes that it needs.

Signed-off-by: Martin Pitt <martin@amutable.com>
A quarry release needs TUF targets that describe its files with quarry's
marks. Add `quarry.release()`, which gathers the release folder and adds
the targets to it. The marks come from the release's description: files
are selected by kind and subkind, and the version is the one all of the
release's images share.

Signed-off-by: Martin Pitt <martin@amutable.com>
This exercises the new rule. Check the targets that it writes.

Signed-off-by: Martin Pitt <martin@amutable.com>
hardhat versions the targets by the wall-clock time, so every build of a
release wrote a different file. It shouldn't do that with `--unsigned`,
see <amutable/quarry#97>.

Until that lands, let's hand it SOURCE_DATE_EPOCH as its reference time
instead. Importing the targets into a repository keeps only their
entries, so their version does not matter.

Signed-off-by: Martin Pitt <martin@amutable.com>
@martinpitt
martinpitt merged commit ae280d5 into main Nov 4, 2026
5 checks passed
@martinpitt
martinpitt deleted the quarry-release branch November 4, 2026 12:09

@cyphar cyphar left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not quite sure how I feel about making the transfer file stuff so central to the API, the Quarry side of it is a little bit "let's just stick with this for now" but it would've been nice to avoid letting it seep out all the way to tine as well. :/

Comment thread quarry/defs.bzl
def hardhat_compatible_with() -> Select:
"""`target_compatible_with` of hardhat and of everything that runs it.
hardhat binds libpathrs through cgo. Debian packages only its Rust crate, not the C library.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Huh, it seems they haven't updated past runc 1.4 in testing so they haven't yet noticed the need to package it. That sucks...

# quarry-sysupdate replaces Path= with its local proxy.
[Source]
Type=url-file
Path=http://localhost/

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's generally a bit nicer to make this an obviously-invalid path like Path=__quarry_will_replace_this__ to make sure it doesn't get used by accident.

Comment thread docs/user/quarry.md
Comment on lines +8 to +13
[quarry](https://github.com/amutable/quarry) delivers updates over
[TUF](https://theupdateframework.io/): machines run systemd-sysupdate against a local quarry proxy,
which serves only files that the repository's signed targets list. `quarry.release` turns an
[`image.artifacts`](images.md#imagedisk) release folder into one that carries those targets. Whoever
publishes the release imports them into its repository and signs them with its own keys, so the
build holds no signing key.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This description is not really that great for user-facing docs -- the quarry-client http proxy is an implementation detail of quarry that users don't need to care about.

Suggested change
[quarry](https://github.com/amutable/quarry) delivers updates over
[TUF](https://theupdateframework.io/): machines run systemd-sysupdate against a local quarry proxy,
which serves only files that the repository's signed targets list. `quarry.release` turns an
[`image.artifacts`](images.md#imagedisk) release folder into one that carries those targets. Whoever
publishes the release imports them into its repository and signs them with its own keys, so the
build holds no signing key.
[Quarry](https://github.com/amutable/quarry) delivers image updates using
[TUF](https://theupdateframework.io/), with `systemd-sysupdate` powering the
installation.
`quarry.release` adds to an [`image.artifacts`](images.md#imagedisk) release
folder an *unsigned* TUF `targets_<arch>.json` manifest of the targets for
Quarry to consume. The build doesn't hold the necessary _targets_ role signing
key so the publisher needs to sign or otherwise merge the produced
`targets_<arch>.json` file with the one used for the final release state.
`systemd-sysupdate` also requires transfer files in order to understand how to
install an image, so builds using `quarry.release` will usually need provide a
`transfers` argument (usually containing paths exported with `export_file`).
See [the `sysupdate.d` man page](https://www.freedesktop.org/software/systemd/man/latest/sysupdate.d.html)
for more details on how these files are ingested and how components and
features can defined.

Comment thread docs/user/quarry.md
Comment on lines +30 to +34
- `transfers` maps a component dir, `sysupdate.d` or `sysupdate.<component>.d`, to the directory of its
sysupdate definitions. hardhat inlines them in the targets as `.quarry/<component dir>/<file>`,
without a version. A component's `.component` and `.feature` files decide on which machines it is
enabled. A transfer's `MatchPattern=` starts with `**/`, because the publisher decides in which
directory of the repository the files of a release end up.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last line seems a little weird to include -- AFAIU quarry.release doesn't rewrite the MatchPattern= so this is more up to the publisher not tine. In practice MatchPattern=**/... might not always be desirable.

@cyphar

cyphar commented Nov 5, 2026

Copy link
Copy Markdown
Member

Ah damn, this got merged overnight. I can send follow-ups I guess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants