Implement backups, commit and restoration
This commit is contained in:
@@ -0,0 +1,116 @@
|
||||
# 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.
|
||||
Reference in New Issue
Block a user