Fix the four findings of the second review
check / check (push) In progress

README.md: the opening no longer says the private key is needed only to
restore; a backup never needs it, a deep verify does.

ARCHITECTURE.md: the concurrency note says each open database uses one
connection, since the metadata export opens a second one.

docs/REPOSTRUCTURE.md: the size leak is about a secret near the
outsider's data in the same blob, not the same chunk, because all new
chunks of a blob share one zstd stream.

Every path used as link text in the four documents is in backticks.

Model: fable-5-1
This commit is contained in:
sneak committed 2026-11-08 23:29:37 +00:00
1 parent 1ecfe12e78
commit 34d7d13d3e
4 files changed
+17 -17

No files matched your search

+6 -7
View File
@@ -9,8 +9,8 @@ things:
Two other documents cover the stored data:
- [docs/DATAMODEL.md](docs/DATAMODEL.md) describes the local index.
- [docs/REPOSTRUCTURE.md](docs/REPOSTRUCTURE.md) describes the layout of the
- [`docs/DATAMODEL.md`](docs/DATAMODEL.md) describes the local index.
- [`docs/REPOSTRUCTURE.md`](docs/REPOSTRUCTURE.md) describes the layout of the
destination.
## Terms
@@ -60,7 +60,7 @@ source files
and the reader that reverses it.
- `internal/database`: the local index. It holds the schema and the repository
types that read and write the tables.
[docs/DATAMODEL.md](docs/DATAMODEL.md#code) says which type serves which
[`docs/DATAMODEL.md`](docs/DATAMODEL.md#code) says which type serves which
table.
- `internal/storage`: the `Storer` interface and its three implementations, for
S3, a local directory and rclone.
@@ -225,7 +225,7 @@ file is never held in memory.
The blob's name is `hex(SHA256(SHA256(uncompressed contents)))`. It is computed
from the chunk data before compression and encryption.
[docs/REPOSTRUCTURE.md](docs/REPOSTRUCTURE.md#blobs) says what follows from
[`docs/REPOSTRUCTURE.md`](docs/REPOSTRUCTURE.md#blobs) says what follows from
that.
When a blob is closed, `Scanner.handleBlobReady` stores it:
@@ -353,7 +353,7 @@ of object, once they are older than `prune_grace_period`:
in the local index
It deletes nothing when any manifest cannot be read.
[docs/REPOSTRUCTURE.md](docs/REPOSTRUCTURE.md#pruning) explains why this is
[`docs/REPOSTRUCTURE.md`](docs/REPOSTRUCTURE.md#pruning) explains why this is
safe, and where it is not.
## The destination
@@ -390,8 +390,7 @@ Every command that changes data calls `EnsureStorageBinding` first.
## Concurrency
- The local index is opened with one connection, so its queries run one at a
time.
- Each open database uses one connection, so its queries run one at a time.
- The index runs in SQLite's WAL mode. A second process can therefore read it
while a backup writes to it.
- `Packer` guards its state with a mutex.
+5 -5
View File
@@ -6,7 +6,7 @@ with a public key and uploads them to an S3-compatible object store, a local
directory or an rclone remote.
The machine being backed up holds only the public key. It cannot decrypt its own
backups. You keep the private key somewhere else and need it only to restore.
backups. You keep the private key somewhere else. A backup never needs it.
## Rationale
@@ -1167,7 +1167,7 @@ destination still learns these:
The last point holds because a remote key is a plain hash of the snapshot ID,
made without a secret.
[docs/REPOSTRUCTURE.md](docs/REPOSTRUCTURE.md) describes the layout of the
[`docs/REPOSTRUCTURE.md`](docs/REPOSTRUCTURE.md) describes the layout of the
destination, what it protects and the risks it accepts.
## Limitations
@@ -1207,9 +1207,9 @@ is a trimmed, encrypted copy of the local index.
These documents give the detail:
- [ARCHITECTURE.md](ARCHITECTURE.md) describes how the code is organised.
- [docs/DATAMODEL.md](docs/DATAMODEL.md) describes the local index.
- [docs/REPOSTRUCTURE.md](docs/REPOSTRUCTURE.md) describes the layout of the
- [`ARCHITECTURE.md`](ARCHITECTURE.md) describes how the code is organised.
- [`docs/DATAMODEL.md`](docs/DATAMODEL.md) describes the local index.
- [`docs/REPOSTRUCTURE.md`](docs/REPOSTRUCTURE.md) describes the layout of the
destination.
## Development
+1 -1
View File
@@ -135,7 +135,7 @@ One row for each blob.
- `uploaded_ts`: when the upload finished. It is `NULL` before that.
`blob_hash` is `hex(SHA256(SHA256(uncompressed contents)))`. See
[REPOSTRUCTURE.md](REPOSTRUCTURE.md#blobs).
[`REPOSTRUCTURE.md`](REPOSTRUCTURE.md#blobs).
Once a blob is uploaded, `compressed_size` is the size of the object at the
destination. A blob that was already there can have a different size from the
+5 -4
View File
@@ -149,7 +149,7 @@ The snapshot's database. A restore needs it.
age.
It is encrypted because it holds file paths, permissions and owners.
[DATAMODEL.md](DATAMODEL.md) describes its tables.
[`DATAMODEL.md`](DATAMODEL.md) describes its tables.
### `manifest.json.zst`
@@ -261,15 +261,16 @@ MiB, or 4 MiB at compression levels 1 and 2. A blob is closed at
`blob_size_limit` and at the end of each configured path. A chunk that is
already stored is never packed again.
Data that an outsider writes compresses smaller when it matches a secret in the
same chunk, so the blob gets smaller. The blob's size therefore shows the
Data that an outsider writes compresses smaller when it matches a secret near it
in the same blob, so the blob gets smaller. The blob's size therefore shows the
outsider whether their data matched the secret.
This works only when all of these hold:
- The outsider can write into a backed-up file.
- The outsider can see the blob sizes at the destination.
- The outsider's data and the secret land in the same chunk.
- The outsider's data and the secret are in the same blob, no further apart than
the stream looks back.
- The file keeps changing.
Back up a directory that outsiders can write to as a snapshot of its own.