# Backup archive format Backups are uncompressed tar archives with a versioned TOML manifest. Version 1 uses only fixed logical member names and is parsed without extracting files. The archive is an opaque saved-state copy; its tar checksum detects accidental header damage but does not authenticate contents or make the archive tamper-proof. ## Members and limits The first member is always `manifest.toml`. The only permitted payload names are `settings.toml`, `server.conf`, `internal-state.toml`, and `vault.toml`, in that order when present. Settings and server configuration are required. Internal state and vault are optional components: a missing component is recorded as `present = false` and `length = none`, which means restore removes that owned component. Absence is not represented by an empty placeholder file. | Member | Maximum bytes | Presence | | --- | ---: | --- | | `manifest.toml` | 64 KiB | Required, first | | `settings.toml` | 1 MiB | Required | | `server.conf` | 4 MiB | Required | | `internal-state.toml` | 2 MiB | Optional | | `vault.toml` | 16 MiB | Optional | The archive is limited to 26 MiB and five entries. Only checksummed UStar regular files are accepted. Absolute names, path separators, traversal, links, device or special entries, sparse entries, GNU/PAX extension headers, nonzero path prefixes, unexpected metadata fields, duplicate/missing/unexpected members, size mismatches, truncation, nonzero padding, and nonzero trailing data are rejected. The reader checks declared sizes before allocating payload buffers and never follows a tar-supplied path. It does not restore files or validate their application semantics; restoration must run settings, configuration, state, and vault validators before mutation. ## Manifest v1 The manifest is UTF-8 TOML with unknown fields denied: ```toml version = 1 created_at_utc = "2026-10-19T12:30:00Z" reason = "pre-commit" [historical_apply] status = "unknown" [[members]] name = "settings.toml" present = true length = 420 [[members]] name = "server.conf" present = true length = 640 [[members]] name = "internal-state.toml" present = false [[members]] name = "vault.toml" present = true length = 8192 ``` `reason` is one of `manual`, `pre-commit`, `pre-restore`, or `pre-restart`. Timestamps are canonical RFC 3339 UTC values with whole-second precision. The historical apply record is either `status = "unknown"` or `status = "verified"` with a `verified_at_utc` timestamp. It is historical metadata only: a pre-operation reason or a verified marker does not establish that these bytes match the currently running interface. Application-created backups derive this record from the timestamp stored in the internal-state bytes captured with the saved set. A successful Commit or restore clears that timestamp for its new saved generation; a failed operation leaves it intact. Reopening may show the saved generation's historical verification time, but runtime observation always begins as unknown. The inventory always has exactly four records in the specified order. Required members have `present = true` and an exact byte `length`; optional absence has `present = false` and omits `length` (TOML has no null value). Present optional members follow the required members in fixed order. The manifest itself is excluded from its payload inventory. Readers reject unsupported versions and any discrepancy between inventory and tar entries. ## Publication and trust boundary Creation receives exact saved bytes from a trusted caller. It does not discover files, inspect the current working directory, recurse into the archive directory, or read client source/output directories. The caller must supply installed bytes, never a proposed draft or decrypted vault records. New archives are fully serialized and synced in a private temporary file, then published without replacement under a timestamped collision-safe name; the archive directory is synced after publication. The archive file is mode `0600` from temporary-file creation. A write or file-sync failure removes the unpublished temporary file; a publication or directory-sync failure returns an error and blocks the protected operation. A complete archive may already be visible if failure occurs after its atomic publication, and a failed temporary cleanup may leave a hidden `0600` temporary file. Neither condition is reported as backup success. Readers should expose the list and preview without passwords, but must keep payload bytes out of Debug output and logs. The application restore preview validates both the archive structure and its settings, server document, optional internal state, and opaque vault before it returns an opaque confirmation value. That value owns the validated payload bytes, so confirmation applies the exact content shown during preview even if the selected archive path changes afterward. Confirmation first completes a `pre-restore` archive and then uses the saved-file transaction journal for the full replacement. Dropping the preview is cancellation and does not discard a draft. Historical verification metadata is informational; opening or restoring an archive always leaves current runtime state unknown. This module only creates, lists, and validates archives. It does not write saved state, apply WireGuard changes, or restore content. A backup is not encrypted: it can contain the server's private configuration and the encrypted vault, so filesystem access must remain restricted to root.