The first sentence now names the licence, the kind of program, the language and the author. The README gains a Design section, and its sections carry the names REPO_POLICIES.md asks for: Rationale and Getting started, which now holds the install command. Entrypoints opens with the Scripts to Rule Them All statement. Corrected: when a file is read again, the chunk size limits, and the first prune step, which looks for a snapshot's manifest. Two sentences that misparsed are reworded. A test comment that named the README quickstart follows the rename. Model: fable-5-1
This commit is contained in:
@@ -1,13 +1,14 @@
|
||||
# vaultik (ваултик)
|
||||
|
||||
`vaultik` is an incremental backup tool. It encrypts your files with a public
|
||||
key and uploads them to an S3-compatible object store, a local directory or an
|
||||
rclone remote.
|
||||
`vaultik` is an MIT-licensed command-line tool for incremental, encrypted
|
||||
backups, written in Go by [@sneak](https://sneak.berlin). It encrypts your files
|
||||
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.
|
||||
|
||||
## Why
|
||||
## Rationale
|
||||
|
||||
Other backup tools, such as `restic`, `borg` and `duplicity`, are designed for
|
||||
machines that can hold a decryption key. `vaultik` is for machines that should
|
||||
@@ -26,7 +27,8 @@ It was written to meet these requirements together:
|
||||
|
||||
- Encryption with [age](https://age-encryption.org/) (X25519 and
|
||||
ChaCha20-Poly1305), to one or more public keys.
|
||||
- Incremental backups. A file is read again only when it has changed.
|
||||
- Incremental backups. A file is read again only when it has changed, or when
|
||||
part of its content has to be stored again.
|
||||
- Deduplication. Identical content is stored once, across files and across
|
||||
snapshots.
|
||||
- zstd compression at a level you choose.
|
||||
@@ -57,18 +59,15 @@ It was written to meet these requirements together:
|
||||
- **Remote key**: a hash of the snapshot ID. It names the snapshot's directory
|
||||
at the destination, so the destination never shows the snapshot ID.
|
||||
|
||||
## Install
|
||||
## Getting started
|
||||
|
||||
Installing needs Go 1.26.1 or later. Generating a key pair needs `age-keygen`,
|
||||
which comes with [age](https://age-encryption.org/).
|
||||
|
||||
```sh
|
||||
# Install vaultik.
|
||||
go install sneak.berlin/go/vaultik/cmd/vaultik@latest
|
||||
```
|
||||
|
||||
This needs Go 1.26.1 or later. Generating a key pair needs `age-keygen`, which
|
||||
comes with [age](https://age-encryption.org/).
|
||||
|
||||
## Quick start
|
||||
|
||||
```sh
|
||||
# Write a default config file. The command prints the path it wrote.
|
||||
vaultik config init
|
||||
|
||||
@@ -301,13 +300,15 @@ It needs:
|
||||
|
||||
It does not need the private key.
|
||||
|
||||
A file is read again when any of these has changed since the last backup:
|
||||
A file is read again when any of these holds:
|
||||
|
||||
- its size
|
||||
- its modification time
|
||||
- its mode
|
||||
- its owner or group
|
||||
- its link target
|
||||
- Its size has changed since the last backup.
|
||||
- Its modification time has changed.
|
||||
- Its mode has changed.
|
||||
- Its owner or group has changed.
|
||||
- Its link target has changed.
|
||||
- No uploaded blob holds one of its chunks. This happens when the only snapshot
|
||||
that used the blob holding that chunk is removed.
|
||||
|
||||
Every other file is recorded in the new snapshot without being read.
|
||||
|
||||
@@ -596,7 +597,7 @@ destination. It needs no private key.
|
||||
|
||||
It works in three steps:
|
||||
|
||||
- It drops each snapshot from the local index whose directory is gone from the
|
||||
- It drops from the local index each snapshot whose manifest is gone from the
|
||||
destination.
|
||||
- It removes unfinished snapshots from the local index. It also removes the
|
||||
file, chunk and blob records that no snapshot uses.
|
||||
@@ -811,7 +812,8 @@ A path from `--config` or `VAULTIK_CONFIG` must exist.
|
||||
scheme.
|
||||
- `chunk_size`
|
||||
- The average size of a chunk. Default: `10MB`. Minimum: `1MB`.
|
||||
- A chunk is between a quarter of this size and four times this size.
|
||||
- No chunk is larger than four times this size. Only a file's last chunk can
|
||||
be smaller than a quarter of it.
|
||||
- A smaller size finds more duplicate content and makes the index larger.
|
||||
- `blob_size_limit`
|
||||
- The largest size of a blob. Default: `10GB`.
|
||||
@@ -997,8 +999,8 @@ To fix this, mount the volume. If you emptied the destination on purpose, run
|
||||
|
||||
The check is skipped when the look-up fails for any other reason. S3 refuses the
|
||||
look-up to credentials that can only write. A machine with such credentials
|
||||
therefore does not notice an emptied destination. Its next backup would leave
|
||||
out the data its local index records as stored. After you empty a destination,
|
||||
therefore does not notice an emptied destination. Its next backup would not
|
||||
upload data that its local index says is stored. After you empty a destination,
|
||||
run `vaultik database delete` on such a machine before it backs up again.
|
||||
|
||||
### Changing the destination
|
||||
@@ -1006,7 +1008,7 @@ run `vaultik database delete` on such a machine before it backs up again.
|
||||
The local index belongs to one destination. It records which blobs are stored
|
||||
there.
|
||||
|
||||
The first command that changes data records the configured destination in the
|
||||
The first command that changes data saves the configured destination in the
|
||||
local index. Later, these commands refuse to run when the config names a
|
||||
different destination:
|
||||
|
||||
@@ -1187,14 +1189,30 @@ destination, what it protects and the risks it accepts.
|
||||
destination is not affected. See
|
||||
[Schema migrations](docs/DATAMODEL.md#schema-migrations).
|
||||
|
||||
## Development
|
||||
## Design
|
||||
|
||||
These documents are for developers:
|
||||
A backup passes your files through four parts of the program:
|
||||
|
||||
- The `Scanner` walks the configured paths and picks the files to read.
|
||||
- The `Chunker` cuts each of those files into chunks.
|
||||
- The `Packer` collects new chunks into blobs. It compresses and encrypts each
|
||||
blob.
|
||||
- The `Storer` uploads each blob to the destination.
|
||||
|
||||
The backup then uploads the snapshot's database and its manifest. The database
|
||||
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
|
||||
destination.
|
||||
|
||||
## Development
|
||||
|
||||
Two documents give the rules for work on this repository:
|
||||
|
||||
- [`AGENTS.md`](AGENTS.md) holds the rules for AI agents.
|
||||
- [`REPO_POLICIES.md`](REPO_POLICIES.md) holds the repository policies.
|
||||
|
||||
@@ -1216,9 +1234,10 @@ pass.
|
||||
|
||||
### Entrypoints
|
||||
|
||||
The scripts in `script/` are the entrypoints. The `Makefile` targets only call
|
||||
them. The layout follows
|
||||
[Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all).
|
||||
This repository follows the
|
||||
[Scripts to Rule Them All](https://github.com/github/scripts-to-rule-them-all)
|
||||
standard. The scripts in `script/` are the entrypoints. The `Makefile` targets
|
||||
only call them.
|
||||
|
||||
- `script/bootstrap`: installs what development needs. It installs Go from
|
||||
`script/install-go` when the machine has none, and it fails without Docker.
|
||||
|
||||
@@ -61,8 +61,8 @@ func TestDefaultConfigTemplateParses(t *testing.T) {
|
||||
// testRecipient is a valid age public key.
|
||||
const testRecipient = "age1278m9q7dp3chsh2dcy82qk27v047zywyvtxwnj4cvt0z65jw6a7q5dqhfj"
|
||||
|
||||
// TestConfigSetRecipientOnFreshConfig follows the README quickstart: on the
|
||||
// file `config init` writes, `config set age_recipients.0` and
|
||||
// TestConfigSetRecipientOnFreshConfig follows the README's getting started
|
||||
// steps: on the file `config init` writes, `config set age_recipients.0` and
|
||||
// `config set storage_url` give a config that loads with that recipient.
|
||||
// Neither is refused, although the config does not load until both are set;
|
||||
// once it loads, a recipient that is not a valid key is.
|
||||
|
||||
Reference in New Issue
Block a user