The sealed-bundle repository machinery, written once.
holger's two airgap handlers — Skidbladnir deploy bundles and Rust-toolchain
dev bundles — are the same repository: one sealed .znippy per
(name, version), served whole, with a classifier that can say what any
path inside it is. Only three things differ between them, so only those
three are a [BundleKind]:
- the handler's name,
- whether a filename looks like one of its bundles,
- the member classifier.
Everything else — the store key, the coordinate parse, the HTTP routes,
fetch/put/list — lives here and is reached by both. Writing it twice
would have been ~90% duplication across two crates (LAW 5), and the two
copies would then need a guard to watch them agree; one writer needs none.
This crate is dependency-free apart from [holger_plugin_abi], so it
compiles for wasm32-unknown-unknown unchanged and each handler's wasm shim
reaches exactly the same code the native backend does.
The path scheme, shared by every bundle handler
GET /{repo}/ → newline list of bundle files
GET /{repo}/{name}/{version} → the sealed bundle bytes
GET /{repo}/{name}/{version}/classify/{path…} → what that member IS
PUT /{repo}/{name}/{version} → store a bundle
classify is the route that puts the shared classifier on the wire: it
is pure path logic, it needs no index read, and it is what the native/wasm
agreement guard compares field by field. A /members route that enumerated a
bundle's contents would need to parse the znippy Arrow index — storage, which
a sandboxed module has no business doing and which would have had to answer
with an empty list on the wasm side. An endpoint that can only ever answer
"nothing" is the NOT RUN → true shape; it is deliberately absent.