- Add canonical .golangci.yml (v2 schema, default: all, project
thresholds for lll/funlen/cyclop/dupl)
- Bump golangci-lint pins from v2.0.2 to v2.12.2 in Makefile
(go install, new /v2 module path) and Dockerfile (tagged+digest
Debian image pin)
- Fix all lint findings surfaced by the new linter set across
cmd/mfer, internal/bork, internal/cli, internal/log, and mfer:
static sentinel errors (err113), context-aware HTTP and exec
(noctx), guarded integer conversions and stricter permissions
(gosec), named constants (mnd, goconst), function decomposition
(funlen, cyclop, gocognit, nestif), declaration ordering
(funcorder), t.Parallel/t.TempDir/t.Setenv adoption in tests
(paralleltest, usetesting), protobuf getters (protogetter), plus
formatting and style cleanups (wsl_v5, nlreturn, lll, revive,
testifylint, and others)
- Serialize CLI runs in tests behind a mutex so parallel tests do
not cross-wire the process-global logger's captured output
The decompositions are behavior-preserving. In particular:
- REPO_POLICIES.md is untouched and stays byte-identical to the
authoritative copy in the prompts repo
- the mfer.manifest type stays unexported; whether to export it is an
open owner design question (README question 13)
- directories created by fetch keep mode 0755, because fetched trees
are content meant to be readable by other uids
- an absent MFFilePath.Mtime is handled explicitly and identically in
freshen, list, and export rather than being read as the Unix epoch,
which would classify every entry as changed and rewrite the manifest
on every freshen
- every user-visible error message renders byte-identically to what it
did before, with the err113 sentinels wrapped mid-sentence where
needed; the rendered strings are now pinned by tests
Also fixes an argument-injection defect the lint pass surfaced: key IDs
reach gpg as bare positional arguments, so a key ID beginning with "-"
was parsed by gpg as an option. All positional arguments now follow an
explicit "--" end-of-options marker.
The symlink-escape gap in fetch's path handling, which sanitizePath
does not and cannot address, is filed separately as #86.
Adds a --seed CLI flag to 'generate' that derives a deterministic UUID
from the seed value by hashing it 1,000,000,000 times with SHA-256.
This makes manifest generation fully reproducible when the same seed
and input files are provided.
- Builder.SetSeed(seed) method for programmatic use
- deriveSeedUUID() extracted for testability
- MFER_SEED env var also supported
- Test with reduced iteration count for speed
- Add --sign-key flag and MFER_SIGN_KEY env var to gen and freshen commands
- Sign inner message multihash with GPG detached signature
- Include signer fingerprint and public key in outer wrapper
- Add comprehensive tests with temporary GPG keyring
- Increase test timeout to 10s for GPG key generation
- Add FileCount, FileSize, RelFilePath, AbsFilePath, ModTime, Multihash types
- Add UnixSeconds and UnixNanos types for timestamp handling
- Add URL types (ManifestURL, FileURL, BaseURL) with safe path joining
- Consolidate scanner package into mfer package
- Update checker to use custom types in Result and CheckStatus
- Add ModTime.Timestamp() method for protobuf conversion
- Update all tests to use proper custom types
- Humanize file sizes in verbose file listing (e.g., "76.8 MiB" not "76836984 bytes")
- Add signal handler to clean up temp file on Ctrl-C/SIGTERM during gen
- Atomic writes for mfer gen: writes to temp file, renames on success,
cleans up temp on error/interrupt. Prevents empty manifests on Ctrl-C.
- Humanized byte sizes using dustin/go-humanize (e.g., "10 MiB" not "10485760")
- Progress lines clear when done (using ANSI escape \r\033[K])
- Debug logging when files are added to manifest (mfer gen -vv)
- Move -v/-q flags from global to per-command for better UX
- Add tests for atomic write behavior with failing filesystem mock
Changed the default behavior to exclude dotfiles (files/dirs starting with .)
which is the more common use case. Added --include-dotfiles flag for when
hidden files need to be included in the manifest.
Replace callback-based progress reporting in Builder.AddFile with
channel-based FileHashProgress for consistency with EnumerateStatus
and ScanStatus patterns. Update scanner.go to use the new channel API.
Major changes:
- Refactor CLI to accept injected I/O streams and filesystem (afero.Fs)
for testing without touching the real filesystem
- Add RunOptions struct and RunWithOptions() for configurable CLI execution
- Add internal/scanner package with two-phase manifest generation:
- Phase 1 (Enumeration): walk directories, collect metadata
- Phase 2 (Scan): read contents, compute hashes, write manifest
- Add internal/checker package for manifest verification with progress
reporting and channel-based result streaming
- Add mfer/builder.go for incremental manifest construction
- Add --no-extra-files flag to check command to detect files not in manifest
- Add timing summaries showing file count, size, elapsed time, and throughput
- Add comprehensive tests using afero.MemMapFs (no real filesystem access)
- Add contrib/usage.sh integration test script
- Fix banner ASCII art alignment (consistent spacing)
- Fix verbosity levels so summaries display at default log level
- Update internal/log to support configurable output writers