All checks were successful
check / check (push) Successful in 6s
ListSnapshots built its table entirely from the local SQLite index. The only remote access, reportRemoteDrift, was gated on AgeSecretKey != "", so on a correctly configured host - which by design holds no private key - snapshot list never contacted the destination store at all. A user who lost their local index could not see their own backups, and the "<remote only>" cell the README documents was unreachable dead code. The listing is now the union of the local index and the destination store, with no age_secret_key gate. Remote-only snapshots cannot have their hostname or name recovered - RemoteSnapshotKey is one-way and the manifest stores the hash - so they are listed by abbreviated remote key with the real timestamp and compressed size from the manifest, and "<remote only>" in the two columns that require the local index. Nothing new is written to remote storage and the human ID is never fabricated. An unreachable destination degrades to local-only with a warning and a zero exit code. remote_present is null rather than false in that case, so "absent" and "unknown" stay distinguishable and no drift is claimed from a listing that never happened. Also: - Snapshot timestamps are normalised to UTC in scanSnapshotRows, the single point where they enter the domain. Previously one of three scanners omitted .UTC(), so on a non-UTC host the same snapshot rendered a different time depending on whether it was locally tracked. - The 1000-row cap and the unreadable-manifest count are reported in --json mode as well as table mode, so machine consumers cannot be silently truncated. The JSON shape is unchanged. - Warnings raised while listing are routed to stderr rather than the logger, which writes to stdout and would corrupt the JSON document. This is a local workaround for the logger bug tracked in #82 and should be removed when that lands. - downloadManifestByKey is now the only remote manifest reader, so the manifest privacy question in #81 has a single call site to change. - The orphaned "vaultik snapshot cleanup" hint now names vaultik prune; that command was folded into prune by the 2026-07-02 consolidation.
115 lines
6.2 KiB
Markdown
115 lines
6.2 KiB
Markdown
# Workflow
|
|
|
|
* branch (from `main`)
|
|
* do the work in Next Step
|
|
* move Next Step to the top of Completed Steps
|
|
* move the top item of Future Steps into Next Step
|
|
* commit (`TODO.md` changes in the same commit as the work)
|
|
* merge to `main` if the branch is not protected, otherwise open a PR
|
|
* push
|
|
|
|
# Status
|
|
|
|
pre-1.0
|
|
|
|
# Next Step
|
|
|
|
Triage the stale remote branches (issue #71): for each, merge the work
|
|
or delete the branch.
|
|
|
|
# Completed Steps
|
|
|
|
- 2026-08-09: Made `snapshot list` list the destination store without
|
|
the private key (issue #64). The listing is now the union of the
|
|
local index and a single streamed listing of the `metadata/` prefix,
|
|
with no `age_secret_key` gate — the manifest is unencrypted, so a
|
|
host holding only the public key can enumerate its own backups and a
|
|
host that lost its local index can still see them. A remote-only
|
|
snapshot's hostname and name are deliberately not recovered (they are
|
|
not recoverable without the private key, and making them so would
|
|
undo the privacy property tracked in issue #81); such rows are
|
|
labelled by an abbreviation of their remote key and carry the real
|
|
timestamp and compressed size from the manifest, with `<remote only>`
|
|
in the two columns that require the local index. Local-only snapshots
|
|
are reported as drift, and the hint now names `vaultik prune`, which
|
|
exists, instead of `vaultik snapshot cleanup`, which does not.
|
|
`reportRemoteDrift` collapsed into the merged view. Every remote
|
|
manifest read in the codebase now goes through
|
|
`downloadManifestByKey`, so issue #81 has one call site to change.
|
|
Review rework: snapshot timestamps now normalize to UTC in
|
|
`scanSnapshotRows`, the one place they enter the domain, so the merged
|
|
TIMESTAMP column cannot show local time for a locally tracked row and
|
|
UTC for a remote-only row on a non-UTC host; `GetIncompleteByHostname`
|
|
was folded onto that same scanner. `--json` now reports the
|
|
unreadable-manifest count and the 1000-row truncation on stderr
|
|
instead of returning a silently short document (the document's shape
|
|
is unchanged). The two per-snapshot `log.Warn` calls on the listing
|
|
path now route through the same JSON-aware writer as the existing
|
|
workaround, so one corrupt manifest can no longer put a log line on
|
|
stdout ahead of the document and break `| jq` — still a local
|
|
workaround pending issue #82. Verified with `script/cibuild` and with
|
|
an uncached `make check` (`0 issues.`, no cached test packages), plus
|
|
end to end against a `file://` destination with no secret key present.
|
|
- 2026-08-09: Closed the gap between `make lint` and CI (issue #78).
|
|
`script/lint` now runs the digest-pinned `golangci-lint` image taken
|
|
from the `Dockerfile` lint stage, which is the single source of truth
|
|
for the linter version; the duplicate pin in the `Makefile` `deps`
|
|
target and the unpinned `golangci-lint` install in `script/bootstrap`
|
|
are gone. A `golangci-lint` on `PATH` is used only when its version is
|
|
exactly the pinned one (which is how the lint stage runs it inside the
|
|
container); anything else goes through Docker, and a missing or
|
|
unreachable Docker daemon is a hard error rather than a silent
|
|
fallback. `make check` is therefore now as trustworthy as
|
|
`script/cibuild`.
|
|
- 2026-08-09: Finished the lint remediation under the canonical
|
|
`.golangci.yml` (issue #61, which also unblocks issue #59). The
|
|
remaining findings were fixed behavior-preservingly: `wsl_v5`
|
|
whitespace, `sqlclosecheck`, and `prealloc`. The `sqlclosecheck` sites
|
|
now close `sql.Rows` in a deferred closure instead of via the
|
|
`CloseRows` helper, which the linter could not see through. Only the
|
|
`revive` package-name findings remain suppressed, with per-site
|
|
`//nolint` directives; the package-rename question behind them is
|
|
tracked in issue #76. Verified with `script/cibuild`, which exits 0 —
|
|
that is the only trustworthy gate, because `script/lint` runs whatever
|
|
`golangci-lint` happens to be on `PATH` rather than the pinned
|
|
v2.12.2 that CI and the `Dockerfile` use, so `make check` can report
|
|
green on findings CI still fails. That tooling gap is tracked in issue
|
|
#78.
|
|
- 2026-08-09: The earlier next step "reconcile the uncommitted
|
|
`ARCHITECTURE.md` edits on `main`" needed no work: the working tree is
|
|
clean and `ARCHITECTURE.md` is committed on `main`.
|
|
- 2026-08-07: Updated golangci-lint to v2.12.2 everywhere it is pinned
|
|
(`Dockerfile` lint stage, `Makefile` deps target), replaced
|
|
`.golangci.yml` with the canonical config (v2 schema, `default: all`),
|
|
and remediated the bulk of the lint findings it surfaced (issue #61):
|
|
behavior-preserving fixes across every package, 2,990 findings down to
|
|
80. `make test` and `make fmt-check` were green at that point but
|
|
`make lint` was still red; the commit message claiming `make check`
|
|
was green was wrong.
|
|
- 2026-08-07: Added the standard `.golangci.yml` and `.editorconfig`
|
|
(issue #59); lint findings under the new config are tracked in issue
|
|
#61. `script/bootstrap` now installs sqlite3 (needed by tests).
|
|
- 2026-07-07 Adopted scripts-to-rule-them-all: `script/` entrypoints,
|
|
Makefile shims, README Entrypoints section
|
|
- 2026-07-02: Consolidated CLI verbs, retired overlapping commands; bound
|
|
the local index to its backup destination URL.
|
|
- 2026-06-28: snapshot rm now removes metadata only and prints the prune
|
|
command; restore skips chown when running as non-root.
|
|
- 2026-06-26: Snapshot IDs hashed at the storage boundary; snapshot list
|
|
made resilient to bad remote entries.
|
|
- 2026-06-24: Collapsed snapshot prune into vaultik prune; restore streams
|
|
blobs to disk and restores files in blob-locality order; cron output
|
|
fixes.
|
|
- 2026-06-17: Restore overhaul: ReadAt chunk reads from cached blobs,
|
|
reference-counted blob sweeper, integration tests; new internal/ui
|
|
output layer, banner, and progress lines.
|
|
- 2025-12-18: Added ARCHITECTURE.md and godoc coverage for exported API.
|
|
- 2025-07-26: End-to-end integration tests; manifest format refactor;
|
|
renamed backup to snapshot; afero filesystem abstraction.
|
|
- 2025-07-20: Initial design and implementation: cobra + fx CLI skeleton,
|
|
SQLite index database, UUID blob storage with streaming chunking.
|
|
|
|
# Future Steps
|
|
|
|
- Define remaining scope for a first tagged release and cut v0.1.0.
|