Skip to main content

microvms_protocol/
lib.rs

1// SPDX-License-Identifier: Apache-2.0
2//! The `microvms-agentd` wire contract as types, shared by the daemon and every
3//! Rust client of it.
4//!
5//! # Why this is a crate rather than a copy on each side
6//!
7//! The daemon serializes these shapes and a client deserializes them, and for as
8//! long as each side owned its own definitions the only thing keeping them in step
9//! was review. That is the failure mode `docs/schema.json` was built to catch after
10//! the fact; this crate makes the class of error unavailable in the first place. A
11//! field renamed here breaks compilation on whichever side has not caught up, which
12//! is the earliest and cheapest place a protocol change can fail.
13//!
14//! # What lives here and what does not
15//!
16//! Pure data only: serde plus schemars, no tokio, no axum, no base64. The rule is
17//! whether the type is *what travels* or *machinery for making it travel*. So the
18//! SSE event payloads are here and the stream that emits them is not; the base64
19//! field is here as a `String` and the encoding is in the daemon's handler; the
20//! error body is here and the `fail(status, slug, detail)` helper that pairs it with
21//! an axum `StatusCode` is not.
22//!
23//! Every type derives both `Serialize` and `Deserialize` even where one side needs
24//! only one of them, because the missing half is exactly what a client would have to
25//! hand-write. `docs/schema.json` is generated from these attributes under both
26//! contracts and byte-compared in CI, so a shape that reads differently than it
27//! writes is a test failure rather than a consumer's problem.
28
29pub mod exec;
30pub mod fs;
31pub mod health;
32pub mod hook;
33pub mod identity;
34pub mod tunnel;
35
36/// Protocol version, distinct from the daemon version.
37///
38/// It tracks the wire contract, including verified tunnel framing, rather than the crate version: a patch to
39/// the daemon does not change the wire format, and a client that pinned a daemon
40/// version would refuse an upgrade it is compatible with.
41///
42/// What a client should do on a mismatch, stated here because it is the question a
43/// version number exists to answer:
44///
45/// * **Same `protocol_version`, different `daemon_version`** — proceed. The path
46///   namespace, framing, and shapes in `$defs` are compatible; only the implementation
47///   moved. This is the normal case and must not be treated as an error.
48/// * **Different `protocol_version`** — do not proceed against `/v1/`. A new
49///   protocol version means a shape or a status code changed meaning, and a client
50///   built for `1` cannot tell a changed meaning from a bug. Fetch `/v1/schema`,
51///   which stays unauthenticated precisely so this is diagnosable, and fail with
52///   the two versions named.
53/// * **The `microvms-agentd-version` response header disagrees with the schema
54///   document's `daemon_version`** — you are talking to two daemons through one
55///   endpoint, or to a proxy that rewrote a response. Treat it as a transport
56///   fault, not a version negotiation.
57///
58/// There is deliberately no negotiation *request*: the daemon serves exactly one
59/// protocol version, and a client that has read this document already knows which.
60pub const PROTOCOL_VERSION: &str = "2";
61
62/// The response header carrying the daemon version, on every response including
63/// errors.
64///
65/// Lowercase because HTTP/2 requires it and hyper normalizes anyway; naming it
66/// once here keeps the layer, the schema document, and any test asserting on it
67/// from drifting into three spellings of the same header.
68pub const VERSION_HEADER: &str = "microvms-agentd-version";