Expand description
The BRPROJ project export/import bundle format (tar + JSON MANIFEST + per-member
SHA-256). Dependency-light + testable in every build; the driver that fills it is
feature-gated.
The BRPROJ project export/import bundle — the on-disk format a
project export writes and a project import reads.
A bundle is a plain tar whose FIRST entry is a JSON MANIFEST describing every
other member, followed by the per-engine payloads:
MANIFEST magic "BRPROJ" | format_version | created_at | data_only | members[]
kv.brkvdump the control-plane KV logical slice (kv_dump::export_to_bytes bytes)
sql/<db>.pgc a streamed Postgres dump (pg_dump custom/plain)
libsql/<project>/<site>/<db>.sqlite a VACUUM INTO snapshot of a libsql database
blobs/<...> blob-store objectsDiscipline borrowed from boatramp_core::kv_dump: a loud magic (BRPROJ) and
an explicit format version the reader refuses if unknown (never misreads a
foreign/newer file), plus a per-member SHA-256 checksum the reader VERIFIES on
extraction (byte-integrity, not a size check) — so a truncated/corrupt bundle is
caught before a single row is restored.
The writer takes members already staged on disk (the multi-GB pg_dump stream
lands in a staging file via run_ephemeral’s streaming sink, the libsql VACUUM INTO writes a file, the KV slice + blobs are staged too), so each member is appended
with a known size — correctness over the PAX unknown-length streaming form, and the
staging keeps memory bounded regardless of dump size. All IO is synchronous (the
tar crate is sync); the async driver calls it from a blocking task.
Structs§
- Bundle
Stream Writer - A streaming v2 bundle writer: writes the MANIFEST up front, then appends members ONE AT A
TIME (
append_member), each from a bounded staging temp the caller may delete the instant the call returns — so the node never holds more than the largest single member. The export driver drives it from a blocking task, staging each member just before it appends and deleting the temp just after (see the convenience wrapperwrite_bundle_streaming, which encapsulates exactly that produce→append→delete loop). - Manifest
- The bundle MANIFEST — the first tar entry, describing the whole bundle.
- Manifest
Member - One member described in the MANIFEST.
- Member
Meta - A member’s
.brmetasidecar: the size + SHA-256 the v1 MANIFEST used to carry inline, now written immediately before the member so the reader knows them before the body. - Member
Spec - The upfront-knowable identity of a bundle member — what the v2/v3 MANIFEST lists, in restore
order. Carries no size/SHA (those travel in the member’s
MemberMetasidecar orMemberTrailer), so the MANIFEST can be written before any member is produced. - Member
Trailer - A chunked member’s
.brtrailer: the size + SHA-256 of the whole member, written AFTER its.part{N}chunks so a streaming producer need never stat or buffer the member (the chunked analogue of the v2 leadingMemberMeta). - PgMember
Info - SQL-dump provenance for a
PgDump/MysqlDumpmember: the detected server version, the client image used to produce (and required to restore) it, and the schema-ledger fingerprint for the import schema-skew check. (Field namedpghistorically; it carries MySQL provenance too — the engine is the member’sMemberKind.) - Source
Info - What the bundle was exported from.
- Staged
Member - A member staged on disk, ready to be appended to a bundle.
- Stream
Manifest - The v2 MANIFEST — the first tar entry: the ordered member LIST plus bundle metadata.
Unlike the v1
Manifestit carries NO per-member size/SHA (each member’s live in itsMemberMetasidecar), which is what makes a streaming export possible.
Enums§
- Bundle
Error - A project-bundle error.
- Member
Framing - How a bundle member’s bytes are framed in the tar.
Sidecar(the default, and the only v2 framing) is a leadingMemberMeta.brmetathen a single body entry;ChunkedTraileris a run of.part{N}entries then a trailingMemberTrailer.brtrailer(v3). - Member
Kind - Which engine a bundle member came from.
Constants§
- BUNDLE_
FORMAT_ VERSION - The bundle FORMAT version. Bumped only on an incompatible change; a reader refuses an unknown version rather than misreading it.
- BUNDLE_
FORMAT_ VERSION_ V2 - The streamable bundle format version (see the section comment above).
- BUNDLE_
FORMAT_ VERSION_ V3 - The chunked bundle format version (see the section comment above). Emitted when at least
one member uses
MemberFraming::ChunkedTrailer; a v3 reader reads v1 + v2 + v3. - BUNDLE_
MAGIC - The bundle magic — carried in the MANIFEST so a stray/foreign tar is rejected loud.
- IDENTITY_
MEMBER_ PATH - The identity transport-container’s tar-entry path (
--include-identityonly): the passphrase-wrapped KEK, produced byboatramp_server::envelope::transport_wrap. - KV_
MEMBER_ PATH - The control-plane KV slice’s tar-entry path (the
kv_dump::export_to_bytesbytes). - MANIFEST_
PATH - The manifest’s tar-entry path — MUST be the first entry in the bundle.
- META_
SUFFIX - The suffix of a member’s sidecar tar entry. For a data member at
<path>, its sidecar is<path>.brmeta— a tiny JSONMemberMeta(size + SHA-256) written immediately before<path>, so a single-pass reader learns them before the body arrives. - PART_
INFIX - The infix of a chunked member’s data-part tar entries. Chunk
Nof a member at<path>is the entry<path>.part{N:05}(zero-padded, monotonic from00000). - TRAILER_
SUFFIX - The suffix of a chunked member’s TRAILING trailer entry. For a chunked member at
<path>, its trailer is<path>.brtrailer— a tiny JSONMemberTrailer(size + SHA-256) written AFTER the member’s.part{N}chunks, so the reader verifies integrity once the whole member has streamed (the chunked analogue of the v2 leadingMemberMetasidecar).
Traits§
- Bundle
Restorer - The restore policy the v3-capable single-pass reader
read_bundle_streaming_atomicdrives, one method per member shape. The format layer owns the PARSE + the per-member integrity VERIFY; the implementor (the import driver) owns the APPLY (where a member is re-keyed to the target, scope-enforced, and committed) — so a chunked member and a sidecar member of the same kind route through the SAME driver re-key/enforce, framing being a transport detail, never a tenancy bypass.
Functions§
- extract_
and_ verify - Extract every member of
bundleintoout_dir, VERIFYING each member’s SHA-256 against the MANIFEST as it streams (byte-integrity). Refuses a member the manifest does not describe, and a manifest member the bundle does not contain. Returns the validated MANIFEST. Member files land atout_dir/<member.path>. - read_
bundle_ streaming - Read a bundle from
srcin a SINGLE FORWARD PASS, handing each member torestoreas it streams — never staging the whole bundle. Reads the MANIFEST first, then for each member callsrestore(spec, size, body):bodyis a reader over the member’s bytes andsizeits declared length; the member’s SHA-256 is VERIFIED asbodyis consumed (and any bytesrestoreleaves unread are drained through the hasher), so a corrupt/truncated member is caught before the next. - read_
bundle_ streaming_ atomic - The v3-capable atomic single-pass reader — the inc2 superset of
read_bundle_streaming_staged. Reads v1, v2 AND v3 bundles in one forward pass, dispatching each member torestorerby itsMemberFraming: aSidecarmember is staged to a bounded temp understage_dirand size/SHA-VERIFIED BEFORErestore_sidecar(verify-then-apply, unchanged from v2); aChunkedTrailermember streams chunk-by-chunk throughbegin_chunked/write_chunk(the reader hashing + counting, NEVER staging the whole member) and is committed byfinish_chunkedONLY when the TRAILING trailer matched — so a corrupt/truncated chunked member applies nothing (atomic).on_head(data_only, source)fires once after the MANIFEST, before any member. Enforces the v2/v3 declared order + per-member framing + the v1 completeness, exactly as [read_bundle_core]. - read_
bundle_ streaming_ staged - VERIFY-THEN-APPLY single-pass reader: like
read_bundle_streaming_with_headbut each member is staged to a bounded temp understage_dirand its size + SHA-256 are VERIFIED from that temp BEFORErestore(spec, &verified_temp)is called (and the temp is freed after). This closes the apply-then-verify window — a corrupt/tampered member is rejected before it is applied — while keeping staging bounded to the largest single member. Reads v1 and v2 bundles. NOTE: this is the inc1 staged reader — it verifies-then-applies but does NOT own per-member rollback, so an import aborted mid-stream may have applied EARLIER members. inc2’sread_bundle_streaming_atomicadds the atomic shadow-restore (a FULL managed-DB member is swapped in only after its trailing SHA verifies, so a bad DB member applies NOTHING to live — per-member all-or-nothing); even there, the bundle is not whole-bundle atomic (the cross-member window) and a--data-onlyDB member keeps this non-atomic sidecar path. - read_
bundle_ streaming_ with_ head - Like
read_bundle_streaming, but also surfaces the bundle HEAD — thedata_onlyflag and theSourceInfo— viaon_head, called ONCE after the MANIFEST is parsed and validated, BEFORE any member is handed torestore. The import driver needs both ahead of the first member (to re-key each member to the TARGET project, and to branch the data-only vs full restore), and the v2 MANIFEST (like the v1 one) carries them before any member — so a single forward pass can learn them up front. Reads both v2 and v1 bundles, exactly asread_bundle_streamingdoes. - read_
manifest - Read + validate the MANIFEST (the first tar entry) from
bundle, without extracting any member. - write_
bundle - Write a bundle at
outfrom members already staged on disk: compute each member’s size + SHA-256, build + validate the MANIFEST, then write the tar with the MANIFEST first and every member streamed from its staging file (bounded memory). Returns the MANIFEST that was written. - write_
bundle_ streaming - Stream a v2 bundle to
out, producing each member JUST BEFORE it is appended and freeing its staging temp JUST AFTER — so the transient on-disk staging never exceeds the largest single member (O(largest member), never O(whole bundle)). For eachMemberSpecinspecs(restore order),stage(spec)stages THAT member to a temp and returns its path; the member is appended (sidecar + data) and its temp is then deleted before the next is staged. - write_
bundle_ streaming_ v3 - Stream a v3-capable bundle to
out, dispatching each member by itsMemberFraming— the chunked-aware superset ofwrite_bundle_streamingthe export driver uses. For aSidecarmember,stage(spec)stages it to a bounded temp (returned path), which is appended then deleted (the inc1 O(largest-member) footprint, unchanged); for aChunkedTrailermember,open(spec)yields aBox<dyn Read>over the member’s bytes (an engine dump stream) that is piped STRAIGHT throughappend_member_chunkedinchunk_sizepieces — NO temp, O(chunk) disk + memory. The MANIFEST is v3 iff any member is chunked (else v2 — seeBundleStreamWriter::new).