Merge feature/vanity-import-readme
All checks were successful
check / check (push) Successful in 2m36s
All checks were successful
check / check (push) Successful in 2m36s
This commit is contained in:
@@ -20,8 +20,8 @@ builds:
|
|||||||
- arm64
|
- arm64
|
||||||
ldflags:
|
ldflags:
|
||||||
- -s -w
|
- -s -w
|
||||||
- -X 'git.eeqj.de/sneak/vaultik/internal/globals.Version={{ .Version }}'
|
- -X 'sneak.berlin/go/vaultik/internal/globals.Version={{ .Version }}'
|
||||||
- -X 'git.eeqj.de/sneak/vaultik/internal/globals.Commit={{ .Commit }}'
|
- -X 'sneak.berlin/go/vaultik/internal/globals.Commit={{ .Commit }}'
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- id: default
|
- id: default
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ COPY . .
|
|||||||
RUN make test
|
RUN make test
|
||||||
|
|
||||||
# Build with CGO enabled (required for mattn/go-sqlite3)
|
# Build with CGO enabled (required for mattn/go-sqlite3)
|
||||||
RUN CGO_ENABLED=1 go build -ldflags "-X 'git.eeqj.de/sneak/vaultik/internal/globals.Version=${VERSION}' -X 'git.eeqj.de/sneak/vaultik/internal/globals.Commit=$(git rev-parse HEAD 2>/dev/null || echo unknown)'" -o /vaultik ./cmd/vaultik
|
RUN CGO_ENABLED=0 go build -ldflags "-X 'sneak.berlin/go/vaultik/internal/globals.Version=${VERSION}' -X 'sneak.berlin/go/vaultik/internal/globals.Commit=$(git rev-parse HEAD 2>/dev/null || echo unknown)'" -o /vaultik ./cmd/vaultik
|
||||||
|
|
||||||
# Runtime stage
|
# Runtime stage
|
||||||
# alpine:3.21, 2026-02-25
|
# alpine:3.21, 2026-02-25
|
||||||
|
|||||||
4
Makefile
4
Makefile
@@ -7,8 +7,8 @@ VERSION := 1.0.0-rc.1
|
|||||||
GIT_REVISION := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
|
GIT_REVISION := $(shell git rev-parse HEAD 2>/dev/null || echo "unknown")
|
||||||
|
|
||||||
# Linker flags
|
# Linker flags
|
||||||
LDFLAGS := -X 'git.eeqj.de/sneak/vaultik/internal/globals.Version=$(VERSION)' \
|
LDFLAGS := -X 'sneak.berlin/go/vaultik/internal/globals.Version=$(VERSION)' \
|
||||||
-X 'git.eeqj.de/sneak/vaultik/internal/globals.Commit=$(GIT_REVISION)'
|
-X 'sneak.berlin/go/vaultik/internal/globals.Commit=$(GIT_REVISION)'
|
||||||
|
|
||||||
# Default target
|
# Default target
|
||||||
all: vaultik
|
all: vaultik
|
||||||
|
|||||||
107
README.md
107
README.md
@@ -6,6 +6,32 @@ remote S3-compatible object store. It requires no private keys, secrets, or
|
|||||||
credentials (other than those required to PUT to encrypted object storage,
|
credentials (other than those required to PUT to encrypted object storage,
|
||||||
such as S3 API keys) stored on the backed-up system.
|
such as S3 API keys) stored on the backed-up system.
|
||||||
|
|
||||||
|
## quickstart
|
||||||
|
|
||||||
|
```sh
|
||||||
|
# install
|
||||||
|
go install sneak.berlin/go/vaultik/cmd/vaultik@latest
|
||||||
|
|
||||||
|
# create a default config file (prints the path it wrote to)
|
||||||
|
vaultik config init
|
||||||
|
|
||||||
|
# generate an age keypair; keep key.txt somewhere safe and offline —
|
||||||
|
# you need it to restore, and the backed-up machine does not need it
|
||||||
|
age-keygen -o key.txt
|
||||||
|
grep 'public key' key.txt
|
||||||
|
|
||||||
|
# configure the encryption key and backup destination
|
||||||
|
vaultik config set age_recipients.0 age1YOUR_PUBLIC_KEY_HERE
|
||||||
|
vaultik config set storage_url "file:///Volumes/usbstick/mybackup"
|
||||||
|
|
||||||
|
# back up your home directory (the default config includes a "home"
|
||||||
|
# snapshot of ~ with sensible excludes)
|
||||||
|
vaultik snapshot create
|
||||||
|
|
||||||
|
# see what you have
|
||||||
|
vaultik snapshot list
|
||||||
|
```
|
||||||
|
|
||||||
Features:
|
Features:
|
||||||
|
|
||||||
* modern encryption ([age](https://age-encryption.org/), X25519 + XChaCha20-Poly1305)
|
* modern encryption ([age](https://age-encryption.org/), X25519 + XChaCha20-Poly1305)
|
||||||
@@ -38,43 +64,19 @@ Requirements that no existing tool meets:
|
|||||||
* encrypted
|
* encrypted
|
||||||
* s3 compatible without an intermediate step or tool
|
* s3 compatible without an intermediate step or tool
|
||||||
|
|
||||||
## install
|
## daily use
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
go install git.eeqj.de/sneak/vaultik@latest
|
# verify a snapshot (shallow: checks all blobs exist)
|
||||||
```
|
|
||||||
|
|
||||||
## quick start
|
|
||||||
|
|
||||||
```sh
|
|
||||||
# 1. Install
|
|
||||||
go install git.eeqj.de/sneak/vaultik@latest
|
|
||||||
|
|
||||||
# 2. Generate an age keypair (store the private key somewhere safe, offline)
|
|
||||||
age-keygen -o key.txt
|
|
||||||
# the public key is printed to stdout and also in key.txt
|
|
||||||
|
|
||||||
# 3. Create a default config file
|
|
||||||
vaultik config init
|
|
||||||
# Writes to the platform config directory with commented defaults:
|
|
||||||
# macOS: ~/Library/Application Support/vaultik/config.yml
|
|
||||||
# Linux: ~/.config/vaultik/config.yml
|
|
||||||
# root: /etc/vaultik/config.yml
|
|
||||||
|
|
||||||
# 4. Edit the config: set age_recipients, snapshots, and storage_url
|
|
||||||
vaultik config edit # opens $EDITOR
|
|
||||||
# or set individual values:
|
|
||||||
vaultik config set storage_url "file:///mnt/backups"
|
|
||||||
vaultik config get storage_url
|
|
||||||
|
|
||||||
# 5. Run your first backup
|
|
||||||
vaultik snapshot create
|
|
||||||
|
|
||||||
# 6. Verify it worked
|
|
||||||
vaultik snapshot list
|
|
||||||
vaultik snapshot verify <snapshot-id>
|
vaultik snapshot verify <snapshot-id>
|
||||||
|
|
||||||
# 7. Set up a daily cron job (keeps last 4 weeks of snapshots)
|
# deep verify (downloads and cryptographically verifies every blob)
|
||||||
|
VAULTIK_AGE_SECRET_KEY='AGE-SECRET-KEY-...' vaultik snapshot verify --deep <snapshot-id>
|
||||||
|
|
||||||
|
# restore (requires the private key)
|
||||||
|
VAULTIK_AGE_SECRET_KEY='AGE-SECRET-KEY-...' vaultik restore <snapshot-id> /tmp/restored
|
||||||
|
|
||||||
|
# daily cron job: back up, keep a 4-week rolling window of snapshots
|
||||||
# 0 3 * * * vaultik snapshot create --cron --prune --keep-newer-than 4w
|
# 0 3 * * * vaultik snapshot create --cron --prune --keep-newer-than 4w
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -120,22 +122,22 @@ vaultik version
|
|||||||
|
|
||||||
### command details
|
### command details
|
||||||
|
|
||||||
**config init**: Write a default config file with commented explanations for
|
**`config init`**: Write a default config file with commented explanations for
|
||||||
every setting. Writes to the path from `--config`, `$VAULTIK_CONFIG`, or the
|
every setting. Writes to the path from `--config`, `$VAULTIK_CONFIG`, or the
|
||||||
platform config directory (`~/Library/Application Support/vaultik/` on macOS,
|
platform config directory (`~/Library/Application Support/vaultik/` on macOS,
|
||||||
`~/.config/vaultik/` on Linux, `/etc/vaultik/` as root). Refuses to overwrite an
|
`~/.config/vaultik/` on Linux, `/etc/vaultik/` as root). Refuses to overwrite an
|
||||||
existing file. Created with mode `0600` since it will contain credentials.
|
existing file. Created with mode `0600` since it will contain credentials.
|
||||||
|
|
||||||
**config edit**: Open the config file in `$EDITOR` (falls back to `vi`).
|
**`config edit`**: Open the config file in `$EDITOR` (falls back to `vi`).
|
||||||
|
|
||||||
**config get**: Print a config value addressed by dotted YAML path
|
**`config get`**: Print a config value addressed by dotted YAML path
|
||||||
(e.g. `vaultik config get s3.bucket`). Non-scalar values print as YAML.
|
(e.g. `vaultik config get s3.bucket`). Non-scalar values print as YAML.
|
||||||
|
|
||||||
**config set**: Set a scalar config value by dotted YAML path
|
**`config set`**: Set a scalar config value by dotted YAML path
|
||||||
(e.g. `vaultik config set compression_level 9`). Comments and formatting
|
(e.g. `vaultik config set compression_level 9`). Comments and formatting
|
||||||
in the file are preserved; intermediate maps are created as needed.
|
in the file are preserved; intermediate maps are created as needed.
|
||||||
|
|
||||||
**snapshot create**: Perform incremental backup of configured snapshots.
|
**`snapshot create`**: Perform incremental backup of configured snapshots.
|
||||||
* Optional snapshot names argument to create specific snapshots (default: all)
|
* Optional snapshot names argument to create specific snapshots (default: all)
|
||||||
* `--cron`: Silent unless error (for crontab)
|
* `--cron`: Silent unless error (for crontab)
|
||||||
* `--prune`: After backup, drop older snapshots of each backed-up name and
|
* `--prune`: After backup, drop older snapshots of each backed-up name and
|
||||||
@@ -145,16 +147,16 @@ in the file are preserved; intermediate maps are created as needed.
|
|||||||
this duration instead of only the latest (e.g. `4w`, `30d`, `6mo`, `1y`)
|
this duration instead of only the latest (e.g. `4w`, `30d`, `6mo`, `1y`)
|
||||||
* `--skip-errors`: Skip file read errors (log them loudly but continue)
|
* `--skip-errors`: Skip file read errors (log them loudly but continue)
|
||||||
|
|
||||||
**snapshot list**: List all snapshots with their timestamps and sizes.
|
**`snapshot list`**: List all snapshots with their timestamps and sizes.
|
||||||
* `--json`: Output in JSON format
|
* `--json`: Output in JSON format
|
||||||
|
|
||||||
**snapshot verify**: Verify snapshot integrity.
|
**`snapshot verify`**: Verify snapshot integrity.
|
||||||
* Default (shallow): checks that all blobs referenced in the manifest exist in storage
|
* Default (shallow): checks that all blobs referenced in the manifest exist in storage
|
||||||
* `--deep`: Downloads and decrypts each blob, verifies chunk hashes against the
|
* `--deep`: Downloads and decrypts each blob, verifies chunk hashes against the
|
||||||
encrypted metadata database
|
encrypted metadata database
|
||||||
* `--json`: Output results as JSON
|
* `--json`: Output results as JSON
|
||||||
|
|
||||||
**snapshot purge**: Remove old snapshots based on criteria. Retention is
|
**`snapshot purge`**: Remove old snapshots based on criteria. Retention is
|
||||||
per-snapshot-name (`--keep-latest` keeps the latest of each name, not the
|
per-snapshot-name (`--keep-latest` keeps the latest of each name, not the
|
||||||
latest globally).
|
latest globally).
|
||||||
* `--keep-latest`: Keep only the most recent snapshot of each name
|
* `--keep-latest`: Keep only the most recent snapshot of each name
|
||||||
@@ -162,42 +164,42 @@ latest globally).
|
|||||||
* `--snapshot <name>`: Restrict to specific snapshot names (repeat for multiple)
|
* `--snapshot <name>`: Restrict to specific snapshot names (repeat for multiple)
|
||||||
* `--force`: Skip confirmation prompt
|
* `--force`: Skip confirmation prompt
|
||||||
|
|
||||||
**snapshot remove**: Remove a specific snapshot from the local database.
|
**`snapshot remove`**: Remove a specific snapshot from the local database.
|
||||||
* `--remote`: Also remove snapshot metadata from remote storage
|
* `--remote`: Also remove snapshot metadata from remote storage
|
||||||
* `--all`: Remove all snapshots (requires `--force`)
|
* `--all`: Remove all snapshots (requires `--force`)
|
||||||
* `--dry-run`: Show what would be deleted without deleting
|
* `--dry-run`: Show what would be deleted without deleting
|
||||||
* `--force`: Skip confirmation prompt
|
* `--force`: Skip confirmation prompt
|
||||||
* `--json`: Output result as JSON
|
* `--json`: Output result as JSON
|
||||||
|
|
||||||
**snapshot prune**: Clean orphaned data from the local database (files,
|
**`snapshot prune`**: Clean orphaned data from the local database (files,
|
||||||
chunks, blobs not referenced by any snapshot).
|
chunks, blobs not referenced by any snapshot).
|
||||||
|
|
||||||
**snapshot cleanup**: Remove stale local snapshot records that have no
|
**`snapshot cleanup`**: Remove stale local snapshot records that have no
|
||||||
corresponding metadata in remote storage. These are typically left behind
|
corresponding metadata in remote storage. These are typically left behind
|
||||||
by incomplete or interrupted backups. Does not touch remote storage.
|
by incomplete or interrupted backups. Does not touch remote storage.
|
||||||
|
|
||||||
**restore**: Restore files from a backup snapshot.
|
**`restore`**: Restore files from a backup snapshot.
|
||||||
* Requires `VAULTIK_AGE_SECRET_KEY` environment variable
|
* Requires `VAULTIK_AGE_SECRET_KEY` environment variable
|
||||||
* Optional path arguments to restore specific files/directories (default: all)
|
* Optional path arguments to restore specific files/directories (default: all)
|
||||||
* Preserves file permissions, timestamps, ownership (ownership requires root),
|
* Preserves file permissions, timestamps, ownership (ownership requires root),
|
||||||
symlinks, and empty directories
|
symlinks, and empty directories
|
||||||
* `--verify`: After restoring, verify every file's chunk hashes match
|
* `--verify`: After restoring, verify every file's chunk hashes match
|
||||||
|
|
||||||
**prune**: Remove unreferenced blobs from remote storage.
|
**`prune`**: Remove unreferenced blobs from remote storage.
|
||||||
* Scans all snapshot manifests for referenced blobs, deletes any blob not referenced
|
* Scans all snapshot manifests for referenced blobs, deletes any blob not referenced
|
||||||
* `--force`: Skip confirmation prompt
|
* `--force`: Skip confirmation prompt
|
||||||
* `--json`: Output stats as JSON
|
* `--json`: Output stats as JSON
|
||||||
|
|
||||||
**info**: Display system configuration, storage settings, encryption
|
**`info`**: Display system configuration, storage settings, encryption
|
||||||
recipients, and local database statistics.
|
recipients, and local database statistics.
|
||||||
|
|
||||||
**remote info**: Show detailed remote storage information including per-snapshot
|
**`remote info`**: Show detailed remote storage information including per-snapshot
|
||||||
metadata sizes, blob counts, and orphaned blob detection.
|
metadata sizes, blob counts, and orphaned blob detection.
|
||||||
* `--json`: Output as JSON
|
* `--json`: Output as JSON
|
||||||
|
|
||||||
**store info**: Display storage backend type and statistics.
|
**`store info`**: Display storage backend type and statistics.
|
||||||
|
|
||||||
**database purge**: Delete the local SQLite state database entirely. Remote
|
**`database purge`**: Delete the local SQLite state database entirely. Remote
|
||||||
storage is unaffected; the next backup will do a full scan and re-deduplicate
|
storage is unaffected; the next backup will do a full scan and re-deduplicate
|
||||||
against existing remote blobs.
|
against existing remote blobs.
|
||||||
* `--force`: Skip confirmation prompt
|
* `--force`: Skip confirmation prompt
|
||||||
@@ -300,7 +302,8 @@ Snapshot IDs follow the format `<hostname>_<snapshot-name>_<RFC3339-timestamp>`
|
|||||||
|
|
||||||
## configuration reference
|
## configuration reference
|
||||||
|
|
||||||
See `config.example.yml` for a complete annotated example. Key fields:
|
Run `vaultik config init` to generate a fully commented config file.
|
||||||
|
Key fields:
|
||||||
|
|
||||||
| Field | Default | Description |
|
| Field | Default | Description |
|
||||||
|-------|---------|-------------|
|
|-------|---------|-------------|
|
||||||
@@ -313,7 +316,7 @@ See `config.example.yml` for a complete annotated example. Key fields:
|
|||||||
| `blob_size_limit` | `10GB` | Maximum blob size before splitting |
|
| `blob_size_limit` | `10GB` | Maximum blob size before splitting |
|
||||||
| `compression_level` | `3` | zstd compression level (1-19) |
|
| `compression_level` | `3` | zstd compression level (1-19) |
|
||||||
| `hostname` | system hostname | Hostname used in snapshot IDs |
|
| `hostname` | system hostname | Hostname used in snapshot IDs |
|
||||||
| `index_path` | `~/.local/share/.../index.sqlite` | Local SQLite index path |
|
| `index_path` | platform data dir | Local SQLite index path |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"runtime"
|
"runtime"
|
||||||
"runtime/pprof"
|
"runtime/pprof"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/cli"
|
"sneak.berlin/go/vaultik/internal/cli"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
|||||||
2
go.mod
2
go.mod
@@ -1,4 +1,4 @@
|
|||||||
module git.eeqj.de/sneak/vaultik
|
module sneak.berlin/go/vaultik
|
||||||
|
|
||||||
go 1.26.1
|
go 1.26.1
|
||||||
|
|
||||||
|
|||||||
@@ -23,12 +23,12 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/blobgen"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
"sneak.berlin/go/vaultik/internal/blobgen"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// BlobHandler is a callback function invoked when a blob is finalized and ready for upload.
|
// BlobHandler is a callback function invoked when a blob is finalized and ready for upload.
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -10,16 +10,16 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/globals"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/pidlock"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/adrg/xdg"
|
"github.com/adrg/xdg"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/globals"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/pidlock"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// AppOptions contains common options for creating the fx application.
|
// AppOptions contains common options for creating the fx application.
|
||||||
@@ -125,7 +125,7 @@ func RunApp(ctx context.Context, app *fx.App) error {
|
|||||||
// It acquires a PID lock before starting to prevent concurrent instances.
|
// It acquires a PID lock before starting to prevent concurrent instances.
|
||||||
func RunWithApp(ctx context.Context, opts AppOptions) error {
|
func RunWithApp(ctx context.Context, opts AppOptions) error {
|
||||||
// Acquire PID lock to prevent concurrent instances
|
// Acquire PID lock to prevent concurrent instances
|
||||||
lockDir := filepath.Join(xdg.DataHome, "berlin.sneak.app.vaultik")
|
lockDir := filepath.Join(xdg.DataHome, "vaultik")
|
||||||
lock, err := pidlock.Acquire(lockDir)
|
lock, err := pidlock.Acquire(lockDir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if errors.Is(err, pidlock.ErrAlreadyRunning) {
|
if errors.Is(err, pidlock.ErrAlreadyRunning) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
@@ -12,7 +13,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const defaultConfigTemplate = `# vaultik configuration
|
const defaultConfigTemplate = `# vaultik configuration
|
||||||
# Documentation: https://git.eeqj.de/sneak/vaultik
|
# Documentation: https://sneak.berlin/go/vaultik
|
||||||
|
|
||||||
# ─── REQUIRED ────────────────────────────────────────────────────────────────
|
# ─── REQUIRED ────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -195,7 +196,9 @@ storage_url: ""
|
|||||||
# hostname: myserver
|
# hostname: myserver
|
||||||
|
|
||||||
# Path to the local SQLite index database.
|
# Path to the local SQLite index database.
|
||||||
# Default: ~/.local/share/berlin.sneak.app.vaultik/index.sqlite
|
# Default: the platform data directory, e.g.
|
||||||
|
# macOS: ~/Library/Application Support/vaultik/index.sqlite
|
||||||
|
# Linux: ~/.local/share/vaultik/index.sqlite
|
||||||
# index_path: /path/to/index.sqlite
|
# index_path: /path/to/index.sqlite
|
||||||
`
|
`
|
||||||
|
|
||||||
@@ -387,8 +390,9 @@ func loadYAMLFile(path string) (*yaml.Node, error) {
|
|||||||
return &root, nil
|
return &root, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// yamlPathGet navigates a dotted key path through mapping nodes and
|
// yamlPathGet navigates a dotted key path through mapping and sequence
|
||||||
// returns the value node.
|
// nodes and returns the value node. Numeric path components index into
|
||||||
|
// sequences (e.g. "age_recipients.0").
|
||||||
func yamlPathGet(root *yaml.Node, keys []string) (*yaml.Node, error) {
|
func yamlPathGet(root *yaml.Node, keys []string) (*yaml.Node, error) {
|
||||||
node := root
|
node := root
|
||||||
if node.Kind == yaml.DocumentNode {
|
if node.Kind == yaml.DocumentNode {
|
||||||
@@ -399,19 +403,30 @@ func yamlPathGet(root *yaml.Node, keys []string) (*yaml.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, key := range keys {
|
for i, key := range keys {
|
||||||
if node.Kind != yaml.MappingNode {
|
switch node.Kind {
|
||||||
return nil, fmt.Errorf("key %q is not a map", strings.Join(keys[:i], "."))
|
case yaml.MappingNode:
|
||||||
}
|
found := false
|
||||||
found := false
|
for j := 0; j+1 < len(node.Content); j += 2 {
|
||||||
for j := 0; j+1 < len(node.Content); j += 2 {
|
if node.Content[j].Value == key {
|
||||||
if node.Content[j].Value == key {
|
node = node.Content[j+1]
|
||||||
node = node.Content[j+1]
|
found = true
|
||||||
found = true
|
break
|
||||||
break
|
}
|
||||||
}
|
}
|
||||||
}
|
if !found {
|
||||||
if !found {
|
return nil, fmt.Errorf("key not found: %s", strings.Join(keys[:i+1], "."))
|
||||||
return nil, fmt.Errorf("key not found: %s", strings.Join(keys[:i+1], "."))
|
}
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
idx, err := strconv.Atoi(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("key %q is a list; use a numeric index", strings.Join(keys[:i], "."))
|
||||||
|
}
|
||||||
|
if idx < 0 || idx >= len(node.Content) {
|
||||||
|
return nil, fmt.Errorf("index %d out of range for %s (len %d)", idx, strings.Join(keys[:i], "."), len(node.Content))
|
||||||
|
}
|
||||||
|
node = node.Content[idx]
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("key %q is not a map or list", strings.Join(keys[:i], "."))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -419,7 +434,9 @@ func yamlPathGet(root *yaml.Node, keys []string) (*yaml.Node, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// yamlPathSet navigates a dotted key path, creating intermediate maps as
|
// yamlPathSet navigates a dotted key path, creating intermediate maps as
|
||||||
// needed, and sets the final key to the given scalar value.
|
// needed, and sets the final key to the given scalar value. Numeric path
|
||||||
|
// components index into sequences; an index equal to the sequence length
|
||||||
|
// appends a new element (e.g. "age_recipients.1" on a 1-element list).
|
||||||
func yamlPathSet(root *yaml.Node, keys []string, value string) error {
|
func yamlPathSet(root *yaml.Node, keys []string, value string) error {
|
||||||
node := root
|
node := root
|
||||||
if node.Kind == yaml.DocumentNode {
|
if node.Kind == yaml.DocumentNode {
|
||||||
@@ -430,41 +447,67 @@ func yamlPathSet(root *yaml.Node, keys []string, value string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for i, key := range keys {
|
for i, key := range keys {
|
||||||
if node.Kind != yaml.MappingNode {
|
|
||||||
return fmt.Errorf("key %q is not a map", strings.Join(keys[:i], "."))
|
|
||||||
}
|
|
||||||
|
|
||||||
last := i == len(keys)-1
|
last := i == len(keys)-1
|
||||||
|
|
||||||
var valueNode *yaml.Node
|
switch node.Kind {
|
||||||
for j := 0; j+1 < len(node.Content); j += 2 {
|
case yaml.MappingNode:
|
||||||
if node.Content[j].Value == key {
|
var valueNode *yaml.Node
|
||||||
valueNode = node.Content[j+1]
|
for j := 0; j+1 < len(node.Content); j += 2 {
|
||||||
break
|
if node.Content[j].Value == key {
|
||||||
|
valueNode = node.Content[j+1]
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if valueNode == nil {
|
if valueNode == nil {
|
||||||
keyNode := &yaml.Node{Kind: yaml.ScalarNode, Value: key}
|
keyNode := &yaml.Node{Kind: yaml.ScalarNode, Value: key}
|
||||||
valueNode = &yaml.Node{Kind: yaml.MappingNode}
|
valueNode = &yaml.Node{Kind: yaml.MappingNode}
|
||||||
if last {
|
if last {
|
||||||
valueNode = &yaml.Node{Kind: yaml.ScalarNode, Value: value}
|
valueNode = &yaml.Node{Kind: yaml.ScalarNode, Value: value}
|
||||||
|
}
|
||||||
|
node.Content = append(node.Content, keyNode, valueNode)
|
||||||
|
} else if last {
|
||||||
|
setScalar(valueNode, value)
|
||||||
}
|
}
|
||||||
node.Content = append(node.Content, keyNode, valueNode)
|
|
||||||
} else if last {
|
|
||||||
valueNode.Kind = yaml.ScalarNode
|
|
||||||
valueNode.Tag = ""
|
|
||||||
valueNode.Value = value
|
|
||||||
valueNode.Content = nil
|
|
||||||
valueNode.Style = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
node = valueNode
|
node = valueNode
|
||||||
|
|
||||||
|
case yaml.SequenceNode:
|
||||||
|
idx, err := strconv.Atoi(key)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("key %q is a list; use a numeric index", strings.Join(keys[:i], "."))
|
||||||
|
}
|
||||||
|
if idx < 0 || idx > len(node.Content) {
|
||||||
|
return fmt.Errorf("index %d out of range for %s (len %d)", idx, strings.Join(keys[:i], "."), len(node.Content))
|
||||||
|
}
|
||||||
|
if idx == len(node.Content) {
|
||||||
|
newNode := &yaml.Node{Kind: yaml.MappingNode}
|
||||||
|
if last {
|
||||||
|
newNode = &yaml.Node{Kind: yaml.ScalarNode, Value: value}
|
||||||
|
}
|
||||||
|
node.Content = append(node.Content, newNode)
|
||||||
|
} else if last {
|
||||||
|
setScalar(node.Content[idx], value)
|
||||||
|
}
|
||||||
|
node = node.Content[idx]
|
||||||
|
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("key %q is not a map or list", strings.Join(keys[:i], "."))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setScalar overwrites a node in place with a plain scalar value.
|
||||||
|
func setScalar(n *yaml.Node, value string) {
|
||||||
|
n.Kind = yaml.ScalarNode
|
||||||
|
n.Tag = ""
|
||||||
|
n.Value = value
|
||||||
|
n.Content = nil
|
||||||
|
n.Style = 0
|
||||||
|
}
|
||||||
|
|
||||||
// configPathForInit returns the config path to write, checking --config flag,
|
// configPathForInit returns the config path to write, checking --config flag,
|
||||||
// VAULTIK_CONFIG env, and the platform default.
|
// VAULTIK_CONFIG env, and the platform default.
|
||||||
func configPathForInit() string {
|
func configPathForInit() string {
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestDefaultConfigTemplateParses ensures the init template is valid YAML
|
// TestDefaultConfigTemplateParses ensures the init template is valid YAML
|
||||||
@@ -45,6 +45,8 @@ func TestDefaultConfigTemplateParses(t *testing.T) {
|
|||||||
|
|
||||||
const testYAML = `# top comment
|
const testYAML = `# top comment
|
||||||
compression_level: 3
|
compression_level: 3
|
||||||
|
age_recipients:
|
||||||
|
- age1aaa
|
||||||
s3:
|
s3:
|
||||||
bucket: oldbucket # inline comment
|
bucket: oldbucket # inline comment
|
||||||
region: us-east-1
|
region: us-east-1
|
||||||
@@ -74,6 +76,9 @@ func TestYAMLPathGet(t *testing.T) {
|
|||||||
{"compression_level", "3", false},
|
{"compression_level", "3", false},
|
||||||
{"s3.bucket", "oldbucket", false},
|
{"s3.bucket", "oldbucket", false},
|
||||||
{"s3.region", "us-east-1", false},
|
{"s3.region", "us-east-1", false},
|
||||||
|
{"age_recipients.0", "age1aaa", false},
|
||||||
|
{"age_recipients.5", "", true},
|
||||||
|
{"age_recipients.notanumber", "", true},
|
||||||
{"s3.nonexistent", "", true},
|
{"s3.nonexistent", "", true},
|
||||||
{"nonexistent", "", true},
|
{"nonexistent", "", true},
|
||||||
{"compression_level.sub", "", true},
|
{"compression_level.sub", "", true},
|
||||||
@@ -114,6 +119,17 @@ func TestYAMLPathSet(t *testing.T) {
|
|||||||
t.Fatalf("set newmap.newkey: %v", err)
|
t.Fatalf("set newmap.newkey: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Overwrite a sequence element and append a new one
|
||||||
|
if err := yamlPathSet(root, splitPath("age_recipients.0"), "age1bbb"); err != nil {
|
||||||
|
t.Fatalf("set age_recipients.0: %v", err)
|
||||||
|
}
|
||||||
|
if err := yamlPathSet(root, splitPath("age_recipients.1"), "age1ccc"); err != nil {
|
||||||
|
t.Fatalf("append age_recipients.1: %v", err)
|
||||||
|
}
|
||||||
|
if err := yamlPathSet(root, splitPath("age_recipients.5"), "age1ddd"); err == nil {
|
||||||
|
t.Error("expected out-of-range append to fail")
|
||||||
|
}
|
||||||
|
|
||||||
// Round-trip and verify values + comment preservation
|
// Round-trip and verify values + comment preservation
|
||||||
out, err := yaml.Marshal(root)
|
out, err := yaml.Marshal(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -121,7 +137,7 @@ func TestYAMLPathSet(t *testing.T) {
|
|||||||
}
|
}
|
||||||
text := string(out)
|
text := string(out)
|
||||||
|
|
||||||
for _, want := range []string{"newbucket", "s3.example.com", "newkey: val", "# top comment", "# inline comment"} {
|
for _, want := range []string{"newbucket", "s3.example.com", "newkey: val", "# top comment", "# inline comment", "age1bbb", "age1ccc"} {
|
||||||
if !contains(text, want) {
|
if !contains(text, want) {
|
||||||
t.Errorf("round-tripped YAML missing %q:\n%s", want, text)
|
t.Errorf("round-tripped YAML missing %q:\n%s", want, text)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDatabaseCommand creates the database command group
|
// NewDatabaseCommand creates the database command group
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewInfoCommand creates the info command
|
// NewInfoCommand creates the info command
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewPruneCommand creates the prune command
|
// NewPruneCommand creates the prune command
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewRemoteCommand creates the remote command and subcommands
|
// NewRemoteCommand creates the remote command and subcommands
|
||||||
|
|||||||
@@ -4,13 +4,13 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/globals"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/globals"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// RestoreOptions contains options for the restore command
|
// RestoreOptions contains options for the restore command
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewSnapshotCommand creates the snapshot command and subcommands
|
// NewSnapshotCommand creates the snapshot command and subcommands
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// StoreApp contains dependencies for store commands
|
// StoreApp contains dependencies for store commands
|
||||||
|
|||||||
@@ -4,8 +4,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"runtime"
|
"runtime"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/globals"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"sneak.berlin/go/vaultik/internal/globals"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewVersionCommand creates the version command
|
// NewVersionCommand creates the version command
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ import (
|
|||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
"git.eeqj.de/sneak/smartconfig"
|
"git.eeqj.de/sneak/smartconfig"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"github.com/adrg/xdg"
|
"github.com/adrg/xdg"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const appName = "berlin.sneak.app.vaultik"
|
const appName = "vaultik"
|
||||||
|
|
||||||
// expandTilde expands ~ at the start of a path to the user's home directory.
|
// expandTilde expands ~ at the start of a path to the user's home directory.
|
||||||
func expandTilde(path string) string {
|
func expandTilde(path string) string {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBlobChunkRepository(t *testing.T) {
|
func TestBlobChunkRepository(t *testing.T) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type BlobRepository struct {
|
type BlobRepository struct {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBlobRepository(t *testing.T) {
|
func TestBlobRepository(t *testing.T) {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestCascadeDeleteDebug tests cascade delete with debug output
|
// TestCascadeDeleteDebug tests cascade delete with debug output
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChunkFileRepository struct {
|
type ChunkFileRepository struct {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChunkFileRepository(t *testing.T) {
|
func TestChunkFileRepository(t *testing.T) {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ChunkRepository struct {
|
type ChunkRepository struct {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestChunkRepository(t *testing.T) {
|
func TestChunkRepository(t *testing.T) {
|
||||||
|
|||||||
@@ -22,8 +22,8 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
//go:embed schema/*.sql
|
//go:embed schema/*.sql
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileChunkRepository struct {
|
type FileChunkRepository struct {
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestFileChunkRepository(t *testing.T) {
|
func TestFileChunkRepository(t *testing.T) {
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type FileRepository struct {
|
type FileRepository struct {
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ package database
|
|||||||
import (
|
import (
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// File represents a file or directory in the backup system.
|
// File represents a file or directory in the backup system.
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Module provides database dependencies
|
// Module provides database dependencies
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestRepositoriesTransaction(t *testing.T) {
|
func TestRepositoriesTransaction(t *testing.T) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestFileRepositoryUUIDGeneration tests that files get unique UUIDs
|
// TestFileRepositoryUUIDGeneration tests that files get unique UUIDs
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestFileRepositoryEdgeCases tests edge cases for file repository
|
// TestFileRepositoryEdgeCases tests edge cases for file repository
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
type SnapshotRepository struct {
|
type SnapshotRepository struct {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"database/sql"
|
"database/sql"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Upload represents a blob upload record
|
// Upload represents a blob upload record
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/s3"
|
"sneak.berlin/go/vaultik/internal/s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestClient(t *testing.T) {
|
func TestClient(t *testing.T) {
|
||||||
|
|||||||
@@ -3,8 +3,8 @@ package s3
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Module exports S3 functionality as an fx module.
|
// Module exports S3 functionality as an fx module.
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ import (
|
|||||||
"testing/fstest"
|
"testing/fstest"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockS3Client is a mock implementation of S3 operations for testing
|
// MockS3Client is a mock implementation of S3 operations for testing
|
||||||
|
|||||||
@@ -7,12 +7,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func setupExcludeTestFS(t *testing.T) afero.Fs {
|
func setupExcludeTestFS(t *testing.T) afero.Fs {
|
||||||
|
|||||||
@@ -6,13 +6,13 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestFileContentChange verifies that when a file's content changes,
|
// TestFileContentChange verifies that when a file's content changes,
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package snapshot
|
package snapshot
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ScannerParams holds parameters for scanner creation
|
// ScannerParams holds parameters for scanner creation
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/blob"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/chunker"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/gobwas/glob"
|
"github.com/gobwas/glob"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
"sneak.berlin/go/vaultik/internal/blob"
|
||||||
|
"sneak.berlin/go/vaultik/internal/chunker"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileToProcess holds information about a file that needs processing
|
// FileToProcess holds information about a file that needs processing
|
||||||
|
|||||||
@@ -7,11 +7,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestScannerSimpleDirectory(t *testing.T) {
|
func TestScannerSimpleDirectory(t *testing.T) {
|
||||||
|
|||||||
@@ -44,15 +44,15 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/blobgen"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/blobgen"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SnapshotManager handles snapshot creation and metadata export
|
// SnapshotManager handles snapshot creation and metadata export
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ import (
|
|||||||
"path/filepath"
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/s3"
|
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Module exports storage functionality as an fx module.
|
// Module exports storage functionality as an fx module.
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/s3"
|
"sneak.berlin/go/vaultik/internal/s3"
|
||||||
)
|
)
|
||||||
|
|
||||||
// S3Storer wraps the existing s3.Client to implement Storer.
|
// S3Storer wraps the existing s3.Client to implement Storer.
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/blobgen"
|
"sneak.berlin/go/vaultik/internal/blobgen"
|
||||||
)
|
)
|
||||||
|
|
||||||
// hashVerifyReader wraps a blobgen.Reader and verifies the double-SHA-256 hash
|
// hashVerifyReader wraps a blobgen.Reader and verifies the double-SHA-256 hash
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/blobgen"
|
"sneak.berlin/go/vaultik/internal/blobgen"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestFetchAndDecryptBlobVerifiesHash verifies that FetchAndDecryptBlob checks
|
// TestFetchAndDecryptBlobVerifiesHash verifies that FetchAndDecryptBlob checks
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SnapshotInfo contains information about a snapshot
|
// SnapshotInfo contains information about a snapshot
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ShowInfo displays system and configuration information
|
// ShowInfo displays system and configuration information
|
||||||
|
|||||||
@@ -11,16 +11,16 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// MockStorer implements storage.Storer for testing
|
// MockStorer implements storage.Storer for testing
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
// PruneOptions contains options for the prune command
|
// PruneOptions contains options for the prune command
|
||||||
|
|||||||
@@ -8,12 +8,12 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// setupPurgeTest creates a Vaultik instance with an in-memory database and mock
|
// setupPurgeTest creates a Vaultik instance with an in-memory database and mock
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ import (
|
|||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/vaultik"
|
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
|
"sneak.berlin/go/vaultik/internal/vaultik"
|
||||||
)
|
)
|
||||||
|
|
||||||
// testStorer implements storage.Storer for testing
|
// testStorer implements storage.Storer for testing
|
||||||
|
|||||||
@@ -12,14 +12,14 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"filippo.io/age"
|
"filippo.io/age"
|
||||||
"git.eeqj.de/sneak/vaultik/internal/blobgen"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"golang.org/x/term"
|
"golang.org/x/term"
|
||||||
|
"sneak.berlin/go/vaultik/internal/blobgen"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|||||||
@@ -12,12 +12,12 @@ import (
|
|||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/types"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"golang.org/x/sync/errgroup"
|
"golang.org/x/sync/errgroup"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// SnapshotCreateOptions contains options for the snapshot create command
|
// SnapshotCreateOptions contains options for the snapshot create command
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/config"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/crypto"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/database"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/globals"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/storage"
|
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"go.uber.org/fx"
|
"go.uber.org/fx"
|
||||||
|
"sneak.berlin/go/vaultik/internal/config"
|
||||||
|
"sneak.berlin/go/vaultik/internal/crypto"
|
||||||
|
"sneak.berlin/go/vaultik/internal/database"
|
||||||
|
"sneak.berlin/go/vaultik/internal/globals"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
|
"sneak.berlin/go/vaultik/internal/storage"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Vaultik contains all dependencies needed for vaultik operations
|
// Vaultik contains all dependencies needed for vaultik operations
|
||||||
|
|||||||
@@ -10,11 +10,11 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/log"
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/snapshot"
|
|
||||||
"github.com/dustin/go-humanize"
|
"github.com/dustin/go-humanize"
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
_ "modernc.org/sqlite"
|
_ "modernc.org/sqlite"
|
||||||
|
"sneak.berlin/go/vaultik/internal/log"
|
||||||
|
"sneak.berlin/go/vaultik/internal/snapshot"
|
||||||
)
|
)
|
||||||
|
|
||||||
// VerifyOptions contains options for the verify command
|
// VerifyOptions contains options for the verify command
|
||||||
|
|||||||
@@ -8,10 +8,10 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"git.eeqj.de/sneak/vaultik/internal/crypto"
|
|
||||||
"github.com/klauspost/compress/zstd"
|
"github.com/klauspost/compress/zstd"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
|
"sneak.berlin/go/vaultik/internal/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestTeeReaderWithDecryption tests that TeeReader correctly hashes all encrypted
|
// TestTeeReaderWithDecryption tests that TeeReader correctly hashes all encrypted
|
||||||
|
|||||||
Reference in New Issue
Block a user