130 lines
6.0 KiB
Markdown
130 lines
6.0 KiB
Markdown
# Task 3 report — secret-safe dwh-auth administrative CLI
|
||
|
||
## Scope
|
||
|
||
- Added `tools/dwh-auth/internal/command/command.go`, its command tests, and
|
||
`tools/dwh-auth/cmd/dwh-auth/main.go`.
|
||
- The CLI accepts only the frozen Task 3 grammar: key create/import/list/status/revoke,
|
||
registry check, and the reserved serve invocation.
|
||
- Existing Task 1–2 APIs are consumed without modifying their files.
|
||
- No server, Nginx, systemd, Compose, portable `tht`, real registry, real secret, or legacy
|
||
stack was accessed or changed.
|
||
|
||
## TDD evidence
|
||
|
||
Tests were written before `Run` existed. In the official `golang:1.26.5` container, mounted
|
||
against only the dedicated worktree, the focused RED run was:
|
||
|
||
```text
|
||
go test ./internal/command -count=1
|
||
internal/command/command_test.go:214:10: undefined: Run
|
||
FAIL
|
||
```
|
||
|
||
After implementation and formatting:
|
||
|
||
```text
|
||
go test ./internal/command -count=1
|
||
ok github.com/aritmolab/thothii/tools/dwh-auth/internal/command
|
||
|
||
go test -race ./internal/command -count=1
|
||
ok github.com/aritmolab/thothii/tools/dwh-auth/internal/command
|
||
|
||
go test ./... -count=1
|
||
ok internal/command, internal/credential, internal/record, internal/registry, internal/securefile
|
||
|
||
go test -race ./... -count=1
|
||
ok internal/command, internal/credential, internal/record, internal/registry, internal/securefile
|
||
|
||
go vet ./...
|
||
```
|
||
|
||
## Contract coverage
|
||
|
||
- Create generates the Task 1 canonical credential, writes it once through the protected
|
||
exclusive `0600` output primitive, syncs/closes it before registry publication, and emits
|
||
only `created key_id=... installation_id=... output=...`.
|
||
- Existing output is never overwritten. Publication failure attempts compensating removal;
|
||
cleanup uncertainty returns exit 4 and reports only the output path.
|
||
- Legacy import requires `--legacy-raw`, the reserved `legacy-shared` installation ID, and an
|
||
absolute exact-`0600` source. It verifies the opaque value, never changes its source, and
|
||
stores only its digest.
|
||
- List/status expose `PublicRecord` data only; JSON is written as pristine JSON with no digest.
|
||
Revoke requires a non-empty reason and reports only its public key ID.
|
||
- Relative paths, malformed/unknown flags, duplicate options, invalid IDs/metadata/expiry,
|
||
and missing required values return exit 2. Missing status/revoke keys return exit 3.
|
||
Registry/filesystem/integrity failures return exit 4.
|
||
- Diagnostics are fixed redacted strings. Tests use a sentinel secret and assert it is absent
|
||
from stdout/stderr, list/status/check JSON, import output, and unsafe/integrity failures.
|
||
|
||
## Secret-redaction evidence
|
||
|
||
The command never prints credential contents or digests. It does not use environment fallback,
|
||
interactive stdin, or `flag` diagnostics that echo argument values. The sentinel appears only
|
||
in synthetic temporary test input and an integrity-fixture file; all command output assertions
|
||
confirm it is absent. The registry’s existing `PublicRecord` contract omits `secret_sha256`.
|
||
|
||
## Concerns
|
||
|
||
- `serve` is grammar-reserved and returns a redacted exit-4 unavailable response; Task 4 owns
|
||
the Unix-socket service implementation and will wire this dispatch.
|
||
- The earlier concern about UTF-8 metadata hardening is superseded by `055dcab`: metadata now
|
||
rejects invalid UTF-8 and Unicode controls before generation/output. The nil-safe cleanup note
|
||
remains non-blocking and outside this review wave.
|
||
|
||
## Review-fix wave
|
||
|
||
Review findings were addressed in separate commit `055dcab`. Regression tests were added first. The focused RED run in the official Go 1.26.5 container failed on intentionally absent seams:
|
||
|
||
```text
|
||
undefined: nowUTC
|
||
undefined: addRecord
|
||
undefined: closeStore
|
||
FAIL github.com/aritmolab/thothii/tools/dwh-auth/internal/command
|
||
```
|
||
|
||
The fix rejects embedded canonical v1 credentials in description/revocation reason without echoing metadata, validates UTF-8/Unicode controls and expiry against one captured UTC creation time before generation/output, reserves exactly `serve --registry-root ABS --socket ABS`, and makes publication cleanup depend on a definitive registry lookup. Output is retained after publication or close ambiguity, with path-only recovery guidance.
|
||
|
||
Review-fix verification in Go 1.26.5:
|
||
|
||
```text
|
||
go test ./internal/command -count=1 PASS
|
||
go test -race ./internal/command -count=1 PASS
|
||
go test ./... -count=1 PASS
|
||
go test -race ./... -count=1 PASS
|
||
go vet ./... PASS
|
||
git diff --check PASS
|
||
```
|
||
|
||
New tests cover synthetic canonical credentials embedded with prefix/suffix, invalid UTF-8, C1 Unicode controls, past/equal/future expiry, exact serve ordering, deterministic pre-/post-publication and close-failure seams, and sentinel absence from stdout/stderr/list/status JSON.
|
||
|
||
## Cleanup snapshot review-fix wave
|
||
|
||
The second re-review added two regression tests before implementation. The RED run in the
|
||
official Go 1.26.5 container showed the old `Find` proof incorrectly treated both cases as
|
||
cleanup-safe:
|
||
|
||
```text
|
||
FAIL TestCreateRetainsOutputWhenSnapshotFindsUnrelatedIntegrityFailure
|
||
corrupt snapshot result = (4, "", "integrity failure\n")
|
||
FAIL TestCreateRetainsOutputWhenFailedPublicationRecordIsExpired
|
||
expired publication result = (4, "", "integrity failure\n")
|
||
```
|
||
|
||
Commit `b1079bd fix: retain DWH key output on ambiguous publication` replaces the `Find` proof
|
||
with a complete `Store.List()` snapshot. It removes generated output only when the snapshot
|
||
succeeds, the generated key ID is absent, and `Store.Close()` succeeds. Any unrelated integrity
|
||
error, active/revoked/expired record, or close error retains the output and emits only path-based
|
||
recovery guidance. The clean pre-publication failure path still removes the output.
|
||
|
||
Final cleanup-wave verification in Go 1.26.5:
|
||
|
||
```text
|
||
go test ./internal/command -count=1 PASS
|
||
go test -race ./internal/command -count=1 PASS
|
||
go test ./... -count=1 PASS
|
||
go test -race ./... -count=1 PASS
|
||
go vet ./... PASS
|
||
git diff --check PASS
|
||
```
|