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:
- a caller-supplied path:
Request::binary, else$MICROVM_AGENTD(a path, for the caller who manages the binary themselves); - the cache entry for the requested version under the state directory;
- a fetch of this repository’s GitHub release asset for that version, or, with
$MICROVM_RELEASE_DIRset, 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
SHA256SUMSentry, hashed in-process. That guards against corruption, which is weaker than provenance, andVerificationsays which of the two the caller got. A release with noSHA256SUMS(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.
- GitHub
Release - 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.
- Https
Fetch - The shipped
Fetch:PolicyFetchoverGitHubReleaseandSigstoreVerifier, or over the release directoryRELEASE_DIR_VARIABLEnames when it’s set. - Policy
Fetch - A
Fetchthat runsfetch_releaseover any source and verifier, writing the proven bytes to the destination the cache gave it, and nothing when the policy refuses.HttpsFetchis this over GitHub and the public-good root; a test answers with a release of its own. - Provision
Error - 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::defaultasks 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.
- Sigstore
Verifier - The Sigstore check, in-process, against the public-good trusted root
sigstore-trust-rootembeds.
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 agentdand 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_machineof an aarch64 ELF (EM_AARCH64). - TOKEN_
VARIABLE - The variable whose token raises the attestations API’s rate limit.
Traits§
- Attestation
Verifier - The Sigstore check over one bundle.
- Fetch
- The download-and-prove seam. The shipped client carries
HttpsFetch; the CLI’s guards script this, which keepscargo testoff the network the way itsCoreSeamkeeps it off AWS. - Release
Source - 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) understate_dir(default: the CLI’s), from$MICROVM_AGENTD, the cache, or a verified fetch over HTTPS (HttpsFetch, with$GITHUB_TOKENwhen it’s set). - agentd_
with agentdwith a caller-supplied binary as well: the bindings’ entry point.- cache_
path - The cache path for
version, understate_dir. - elf_
machine - The
e_machinefield of an ELF header, orNoneifbytesdoes not start with one. - fetch_
release - Release
tag’sASSET, 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
bytesis not an aarch64 ELF, orNonewhen it is. - resolve
- Answers
requestfrom the caller’s binary, the cache, or the release, in that order. - sha256_
hex - The lowercase hex SHA-256 of
bytes. - verify_
sha256 - Checks
bytesagainstasset’s entry in aSHA256SUMSbody (<64 hex> <name>per line, sha256sum’s own format). In-process, becausesha256sumthe tool doesn’t exist on Windows.