Skip to main content

Module provision

Module provision 

Source
Expand description

Provisioning of the agentd daemon binary: one call that returns verified aarch64 bytes for the version a client drives (BIND-17 through BIND-20, issue #219).

§Why the client stack fetches its own daemon

The daemon is this product’s own component, versioned in this workspace and shipped from this repository’s releases. A harness that bakes it into an image should not need a hard-coded release URL, an ELF check, and a cache of its own; docker run takes an image name, and Dagger’s CLI provisions its matching-version engine itself. So resolve answers a request from, in order:

  1. a caller-supplied path: Request::binary, else $MICROVM_AGENTD (a path, for the caller who manages the binary themselves);
  2. the cache entry for the requested version under the state directory;
  3. a fetch of this repository’s GitHub release asset for that version, or, with $MICROVM_RELEASE_DIR set, a read of that release’s assets from the directory it names, proven the same way (RELEASE_DIR_VARIABLE).

The version defaults to crate::VERSION, the core’s own. The daemon and the client share one workspace version, so v{VERSION} is the one tag whose protocol this client is proven against; a “latest” fetch would reintroduce exactly the skew the shared version exists to prevent.

A refused caller-supplied binary is an error, never a fall-through to the cache or a fetch: a caller who named a binary manages it, and running a different one would run a daemon they did not choose.

§What proves a fetch

The policy is microvms_app::provision::fetch_release, re-exported here as fetch_release, and the shipped Fetch is HttpsFetch: reqwest for the release’s files and sigstore-verify for its attestation, both in-process. In order:

  • Provenance, from the Sigstore bundle the release workflow published for the asset, verified against that workflow’s identity at the requested tag. A bundle that doesn’t verify is a hard stop, never a fall-through: bytes that exist but don’t verify are the one state a fallback must not launder. So is a release that answers it has no bundle for the bytes, which is what a replaced asset with its bundle deleted looks like.
  • Integrity, only when no answer about a bundle can be had at all (a transport failure, a rate limit, a server error): the release’s SHA256SUMS entry, hashed in-process. That guards against corruption, which is weaker than provenance, and Verification says which of the two the caller got. A release with no SHA256SUMS (every tag before v0.5.0) fails closed.

A fetch that can’t be verified is an error (BIND-18), never a warning.

Nothing here spawns a tool. Until #284 this fetch ran gh release download and gh attestation verify, then curl and SHA256SUMS when gh couldn’t download, so a machine without a gh login never got an attestation check.

§What is checked no matter where the bytes came from

Every binary this module returns is an aarch64 ELF (BIND-20): MicroVMs are ARM64-only, and a wrong binary baked into an image fails 45 minutes later as a run-hook timeout that says nothing about architecture. Twenty bytes of header now is the whole cost of never finding out.

§The cache serves only what it verified

An install is write-to-partial-then-rename, so an interrupted download never leaves a truncated binary where the next request reads. Beside each entry sits a digest record written after verification, and a cache hit is served only when the bytes still hash to it (BIND-19). An entry that does not match, or that has no record (one an older client installed), is ignored and fetched again. The record lives in the same directory as the binary, so this catches corruption and a binary copied over the entry, not a writer who replaces both; such a writer could replace a caller-supplied binary just as well.

crates/model/src/provision.rs checks this policy against the ways it could be written instead, and crates/microvms-core/tests/features/provision.feature drives it through a fake release.

§The seams

Fetch is the download-and-prove seam the CLI’s guards script. Under it, the app’s ReleaseSource and AttestationVerifier are the seams PolicyFetch runs the policy over: HttpsFetch is that over GitHub and the public-good Sigstore root, the edges tests answer them with a committed release, and the Gherkin runner with a fake one. None of them lets a test open a socket to GitHub.

Structs§

Fetched
The asset’s bytes, and how they were proven.
GitHubRelease
The release’s files over HTTPS: the public download URLs for assets, and GitHub’s attestations API for a bundle the release doesn’t carry.
HttpsFetch
The shipped Fetch: PolicyFetch over GitHubRelease and SigstoreVerifier, or over the release directory RELEASE_DIR_VARIABLE names when it’s set.
PolicyFetch
A Fetch that runs fetch_release over any source and verifier, writing the proven bytes to the destination the cache gave it, and nothing when the policy refuses. HttpsFetch is this over GitHub and the public-good root; a test answers with a release of its own.
ProvisionError
A refusal, with the remedies a person or agent can act on.
Provisioned
A provisioned daemon binary and how it got here.
Request
What a caller asks for. Every field is optional; Request::default asks for the core’s own version under the default state directory.
Signer
Who must have signed a release’s attestation, and what it must attest.
SigstoreVerifier
The Sigstore check, in-process, against the public-good trusted root sigstore-trust-root embeds.

Enums§

Bundles
What a lookup of the attestation bundles for one digest found. Each reason is prose; the policy adds what it means.
Failure
Which step refused, so a caller can attach its own remedies.
Source
Where a provisioned binary came from.
Supplier
How a caller supplied a binary.
Verification
How a fetched binary’s bytes were proven.

Constants§

ASSET
The release asset’s name: a literal, because the README’s --pattern agentd and the checksum lookup both match it exactly.
BUNDLE_ASSET
The release asset holding the Sigstore bundle for ASSET, from v0.5.0 on.
ENV_OVERRIDE
The environment variable naming a caller-managed binary, used when a request carries no Request::binary.
RELEASE_DIR_VARIABLE
The variable naming a directory of downloaded releases, read in place of GitHub: release <tag>’s files are in <dir>/<tag>/. See the module docs.
RELEASE_REPO
The repository whose releases carry the daemon asset.
REQUIRED_ELF_MACHINE
The e_machine of an aarch64 ELF (EM_AARCH64).
TOKEN_VARIABLE
The variable whose token raises the attestations API’s rate limit.

Traits§

AttestationVerifier
The Sigstore check over one bundle.
Fetch
The download-and-prove seam. The shipped client carries HttpsFetch; the CLI’s guards script this, which keeps cargo test off the network the way its CoreSeam keeps it off AWS.
ReleaseSource
Where a release’s files come from. The error is prose; the policy adds what it means.

Functions§

agentd
The one call. The daemon binary for version (default: crate::VERSION) under state_dir (default: the CLI’s), from $MICROVM_AGENTD, the cache, or a verified fetch over HTTPS (HttpsFetch, with $GITHUB_TOKEN when it’s set).
agentd_with
agentd with a caller-supplied binary as well: the bindings’ entry point.
cache_path
The cache path for version, under state_dir.
elf_machine
The e_machine field of an ELF header, or None if bytes does not start with one.
fetch_release
Release tag’s ASSET, proven by attestation or, when no answer about its bundle can be had, by checksum. See the module docs for the order and why it’s that order.
normalize_version
A version as a release tag spells it, without the leading v, or a refusal.
not_aarch64
Why bytes is not an aarch64 ELF, or None when it is.
resolve
Answers request from the caller’s binary, the cache, or the release, in that order.
sha256_hex
The lowercase hex SHA-256 of bytes.
verify_sha256
Checks bytes against asset’s entry in a SHA256SUMS body (<64 hex> <name> per line, sha256sum’s own format). In-process, because sha256sum the tool doesn’t exist on Windows.