@@ -7,6 +7,176 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77
88## [ Unreleased]
99
10+ ## [ 0.5.0] — 2026-04-21
11+
12+ ### Added
13+ - Five new pipe-friendly sub-commands that replace the ad-hoc external
14+ tool chain (` sha256sum ` , ` shasum ` , ` xxd ` , ` base64 ` , ` jq ` , ` date ` )
15+ with built-ins that behave identically across macOS, Linux, BSD,
16+ WSL, and Git-Bash on Windows:
17+ - ` truestamp hash ` — SHA-2 / SHA-3 / BLAKE2 / MD5 / SHA-1 digests
18+ for files, stdin, URLs, or a picked file. Default output is
19+ byte-identical to GNU coreutils' ` sha256sum ` (including the
20+ standard ` \ ` -escaping for filenames with newlines/backslashes).
21+ ` --style bsd ` matches ` shasum --tag ` ; ` --style bare ` is
22+ digest-only. Legacy algorithms (MD5, SHA-1) emit a one-line
23+ stderr warning unless ` --json ` or ` --silent ` is set. Supports
24+ ` --prefix 0xNN ` (prepend a single domain-separation byte before
25+ hashing) and ` --jcs ` (apply RFC 8785 canonicalization first), so
26+ the Truestamp claims-hash intermediate is a one-liner:
27+ ` truestamp hash --prefix 0x11 --jcs -a sha256 --style bare < claims.json ` .
28+ - ` truestamp encode ` and ` truestamp decode ` — byte-encoding
29+ conversions among ` hex ` , ` base64 ` , ` base64url ` , and ` binary ` ,
30+ with strict cross-encoding-alphabet rejection. Both support
31+ text-to-text conversion via ` --from ` /` --to ` .
32+ - ` truestamp jcs ` — apply RFC 8785 JSON Canonicalization to the
33+ input. Pipes directly into ` truestamp hash ` for hashing
34+ pipelines; ` truestamp hash --jcs ` is the shortcut.
35+ - ` truestamp convert ` — umbrella for domain-specific conversions:
36+ - ` convert time ` — parse and re-format timestamps across zones
37+ and Unix formats (auto / rfc3339 / unix-{s,ms,us,ns}, IANA
38+ zones, Go time layouts as ` --format ` ).
39+ - ` convert proof ` — switch a proof bundle between JSON and CBOR
40+ wire formats. CBOR output uses RFC 8949 §4.2 core
41+ deterministic encoding and prepends the self-describing tag
42+ 55799 so ` truestamp verify ` auto-detects the format.
43+ - ` convert id ` — extract the embedded millisecond timestamp
44+ from a ULID (item IDs) or UUIDv7 (block and entropy IDs).
45+ Auto-detects the type; supports ` --to-zone ` for display.
46+ - ` convert keyid ` — derive the 4-byte Truestamp ` kid `
47+ fingerprint (` truncate4(SHA256(0x51 || pubkey)) ` ) from an
48+ Ed25519 public key in hex, base64, or base64url.
49+ - ` convert merkle ` — decode a compact base64url Merkle proof
50+ (` ip ` / ` ep ` fields) into a human-readable sibling list with
51+ position + hash per step.
52+ - ` internal/inputsrc ` — shared six-mode input resolver (positional,
53+ ` --file [path] ` , ` --file ` picker, ` --url [url] ` , ` --url ` prompt,
54+ stdin pipe). Used uniformly by ` verify ` , ` create ` , and every new
55+ sub-command. ` pflag ` ` NoOptDefVal ` sentinels are now readable
56+ ` (pick) ` / ` (prompt) ` strings so ` --help ` renders cleanly; ` - `
57+ as a positional is accepted as the Unix-standard stdin alias.
58+ - ` internal/encoding ` — RFC 4648 hex/base64/base64url round-trip with
59+ tolerance for trailing whitespace and rejection of mismatched
60+ alphabets.
61+ - ` internal/hashing ` — 14-algorithm registry built on `crypto/{md5,
62+ sha1,sha256,sha512}` + ` golang.org/x/crypto/{sha3,blake2b,blake2s}`,
63+ streaming ` Compute ` , and ` sha256sum ` / ` shasum --tag ` output
64+ formatters with proper filename escaping.
65+ - ` ProofBundle.MarshalCBOR ` on ` internal/proof ` — deterministic CBOR
66+ encoding (RFC 8949 §4.2) with the 0xd9d9f7 self-describing tag.
67+ Byte-valued fields (` pk ` , ` sig ` , hashes, epoch/inclusion proofs)
68+ are re-encoded as CBOR major-type-2 byte strings per an explicit
69+ per-field policy; round-trips stabilize on the second pass.
70+ - ` [hash] ` and ` [convert] ` config sections in
71+ ` ~/.config/truestamp/config.toml ` , plus matching env-var overrides
72+ (` TRUESTAMP_HASH_ALGORITHM ` , ` TRUESTAMP_HASH_ENCODING ` ,
73+ ` TRUESTAMP_HASH_STYLE ` , ` TRUESTAMP_CONVERT_TIME_ZONE ` ).
74+ - Comprehensive test infrastructure:
75+ - ** 59 fuzz targets** (` FuzzXxx ` ) across 13 packages covering every
76+ parser that touches attacker-controlled bytes. Seed corpus lives
77+ in ` f.Add() ` calls; ` go test ` replays them on every run. Active
78+ mutation via ` task fuzz-deep ` (default 15s per target, 59
79+ targets, ~ 320M inputs per full pass).
80+ - ** 20+ benchmarks** (` BenchmarkXxx ` ) on hot paths: hashing across
81+ all 14 algorithms (SHA-256 ~ 2.9 GB/s, BLAKE2b ~ 1.1 GB/s on M3
82+ Max), encoding round-trip, proof parse / marshal (JSON + CBOR),
83+ Merkle decode + verify, domain-prefixed hashing.
84+ - ** 9 golden-output snapshot tests** — ` testdata/golden/ ` fixtures
85+ for ` --help ` output on root/verify/hash, ` hash --list ` , and JSON
86+ envelopes for ` hash ` , ` encode ` , and ` convert {time,id,keyid} ` .
87+ JSON is canonicalized before diffing so tests don't flake on
88+ Go's map-iteration order. Regenerate with
89+ ` UPDATE_GOLDEN=1 go test ./cmd -run Golden ` .
90+ - Coverage raised from 47.6% to 81.2% across 17 packages. Most
91+ packages are now >90%; the handful below that ceiling have
92+ structural reasons (interactive TTY, platform-specific Windows
93+ branches on a macOS/Linux runner, self-upgrade pipeline that
94+ needs a real release tarball + cosign binary).
95+ - New Taskfile entry points:
96+ - ` task test-coverage-full ` — covers CLI subprocess runs too by
97+ building the binary with ` -cover -coverpkg=./... ` and routing
98+ its ` GOCOVERDIR ` through a task-controlled directory (works
99+ around ` go test -cover ` clobbering ` GOCOVERDIR ` in the test
100+ process's environment).
101+ - ` task test-race ` — full suite under the race detector; currently
102+ zero-finding.
103+ - ` task bench ` / ` task bench-compare ` — benchmarks with ` -benchmem `
104+ and a ` -count=5 ` baseline suitable for ` benchstat ` comparison.
105+ - ` task fuzz ` / ` task fuzz-deep ` / ` task fuzz-list ` .
106+ - ` task lint ` — ` go vet ` + ` gofmt -l ` + ` staticcheck ` + ` gosec `
107+ with documented exclusions for CLI-standard patterns
108+ (user-specified file paths, supported-with-warning legacy
109+ hashes, Unix-standard file permissions, hard-coded subprocess
110+ names).
111+ - ` task vuln-check ` — ` govulncheck ` against ` go.mod ` and stdlib.
112+ - ` task precommit-full ` — strict pre-release gate (fmt + lint +
113+ test-race + fuzz seeds + vuln-check + build-all, ~ 3-5 min).
114+ - ` EXAMPLES.md ` — new, ~ 800 lines. Per-sub-command tour with
115+ copy-pastable examples, ~ 15 pipeline recipes, ` --json ` + ` jq `
116+ scripting patterns, CI conventions, and an offline/air-gapped
117+ usage section. Every example was exercised end-to-end against a
118+ live dev server to catch documentation drift. Linked prominently
119+ from the top of ` README.md ` .
120+
121+ ### Changed
122+ - Go toolchain pinned to ** 1.26.2** in both ` .tool-versions ` and
123+ ` go.mod ` (previously ` latest ` , which resolved to 1.26.1). See
124+ Security below. All other entries in ` .tool-versions ` are now
125+ explicitly version-pinned rather than tracking ` latest ` to avoid
126+ silent drift.
127+ - ` task precommit ` slimmed to a ** fast** hot-cache pass — ` fmt ` +
128+ ` lint ` + ` test ` + ` build ` (single-platform). ~ 2 s hot, ~ 8 s cold.
129+ Fuzz seed replay happens automatically as part of ` task test ` so
130+ no separate fuzz step is needed here. The comprehensive gate
131+ (race, active fuzz, vuln-check, cross-compile) lives in
132+ ` precommit-full ` and is intended for PR/release boundaries.
133+ - ` cmd/verify.go ` and ` cmd/create.go ` now consume the shared
134+ ` internal/inputsrc ` resolver; the old duplicated six-mode input
135+ logic in each command is gone.
136+ - ` hash --style bare ` now unconditionally omits the filename column
137+ (previously only did so when ` --no-filename ` was also passed,
138+ making ` bare ` accidentally byte-identical to ` gnu ` when a filename
139+ was available). The three styles now produce three distinct
140+ shapes:
141+ - ` gnu ` — ` <hex> <filename> ` (sha256sum-compatible)
142+ - ` bsd ` — ` <ALGO> (<filename>) = <hex> ` (shasum --tag)
143+ - ` bare ` — ` <hex> ` (digest only, always)
144+ - ` internal/config.ConfigDir ` and ` internal/upgradecheck.cacheDir `
145+ split into ` *_unix.go ` / ` *_windows.go ` via build tags so each
146+ platform's branch is counted for coverage only on the platform
147+ where it can execute.
148+ - ` ProofBundle.MarshalJSON ` now writes ` ts ` , ` pk ` , ` sig ` , ` s ` , ` b ` ,
149+ ` ip ` , ` cx ` in a stable map — with ` encoding/json ` 's alphabetical
150+ key ordering this yields a canonical JSON form suitable for
151+ round-trip comparisons against JCS.
152+ - ` CONTRIBUTING.md ` significantly expanded with a "When to run which
153+ task" table covering every Taskfile entry point, their durations,
154+ and recommended usage. The ` Tests ` section is now broken out by
155+ category (unit/integration, golden snapshots, fuzz, bench, race,
156+ coverage, lint, vuln-check) with guidance on what kind of test to
157+ add when.
158+ - ` CLAUDE.md ` updated with new package structure entries, the
159+ deterministic-CBOR policy, the shared inputsrc pattern, and a
160+ note on the 59-target fuzz coverage.
161+
162+ ### Security
163+ - ` golang.org/x/crypto ` (already an indirect dependency) promoted to
164+ direct; used for SHA-3 and BLAKE2 implementations in
165+ ` internal/hashing ` . ` task vuln-check ` after the bump is clean.
166+ - Go toolchain bump to 1.26.2 eliminates ** six standard-library
167+ vulnerabilities** flagged by ` govulncheck ` in 1.26.1: five in
168+ ` crypto/x509 ` (various certificate-parsing issues reachable via
169+ ` io.Copy ` through our hash-streaming path, though not exploitable
170+ through the CLI's actual call graph) and one XSS-class bug in
171+ ` html/template ` (reachable from ` fmt.Fprintln ` → ` template.Error ` ,
172+ again not exploitable from the CLI's call graph but eliminated on
173+ principle). ` task vuln-check ` now reports zero findings.
174+
175+ ### Fixed
176+ - One real ` staticcheck ` finding addressed: an unused variable
177+ assignment in ` cmd/coverage_extra_test.go ` that the prior test
178+ suite never caught.
179+
10180## [ 0.4.0] — 2026-04-17
11181
12182### Added
@@ -303,7 +473,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
303473 v0.1.0 is the first release of a standalone Go codebase; the two share
304474 nothing beyond the repository name.
305475
306- [ Unreleased ] : https://github.com/truestamp/truestamp-cli/compare/v0.4.0...HEAD
476+ [ Unreleased ] : https://github.com/truestamp/truestamp-cli/compare/v0.5.0...HEAD
477+ [ 0.5.0 ] : https://github.com/truestamp/truestamp-cli/releases/tag/v0.5.0
307478[ 0.4.0 ] : https://github.com/truestamp/truestamp-cli/releases/tag/v0.4.0
308479[ 0.3.3 ] : https://github.com/truestamp/truestamp-cli/releases/tag/v0.3.3
309480[ 0.3.2 ] : https://github.com/truestamp/truestamp-cli/releases/tag/v0.3.2
0 commit comments