docs: record DWH auth implementation evidence

This commit is contained in:
User
2026-08-21 13:34:36 +02:00
parent 0c4ff3750d
commit 7118950416
6 changed files with 807 additions and 322 deletions
+119 -46
View File
@@ -1,56 +1,129 @@
# Task 3 report — workflow repository migration
# Task 3 report — secret-safe dwh-auth administrative CLI
## RED
## Scope
- `harness/tests/test_session_repository_workflow.py` initially failed at collection:
`persist_verified_finalization` did not exist.
- The new gate test initially failed because `write_cte_sql` and `write_final_sql`
were not registered. Its first run also exposed the worktree-local missing
Node dependency (`typebox`); `npm ci` installed the lockfile dependency.
- After the principal/legacy policy was clarified, the resolver tests initially
failed because `resolve_principal` did not exist.
- 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.
## GREEN evidence
## TDD evidence
- Focused Python regression set: `66 passed`:
`test_session_repository_workflow`, `test_session_repository`, session mutation/list/
documents/schema-linking, CTE plan/next, decision phase gate, and phase requirement tests.
- Gate suite: `127 passed`, including
`session-repository-writes.test.js`.
- Changed-source Ruff checks pass. `git diff --check` passes.
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:
## Implemented boundary
```text
go test ./internal/command -count=1
internal/command/command_test.go:214:10: undefined: Run
FAIL
```
- Added `resolve_principal`: PostgreSQL session storage requires trusted
`THT_PRINCIPAL_ISSUER` and `THT_PRINCIPAL_SUBJECT`, optional display name, and
strict admin parsing (`1`/`true`). It fails closed and never substitutes a local
identity. Filesystem storage uses `local_principal()`.
- Filesystem repository creates UUIDv4 sessions only and permits safe historical
timestamp IDs (`YYYY-MM-DD-HHMMSS`) for read/mutate compatibility. PostgreSQL
remains UUIDv4 only.
- Phase helpers fold `SessionSnapshot` ledger/artifacts; decision, phase, CTE,
session mutation/list/document paths, retrieval-pack persistence, SQL promotion
lookup, and task-doc/CTE test helpers gained repository/snapshot paths.
- Finalization now publishes report, evidence, and finalized manifest through
`repository.finalize`: one PostgreSQL transaction; filesystem writes artifacts
before the finalized manifest commit marker. Solved-question indexing stays
best-effort after this durable write.
- Added `tht cte save --session --name --file -` and
`tht sql set-final --session --file -`; Pi tools and SKILL.md now use them.
After implementation and formatting:
## Outstanding in-scope migration work
```text
go test ./internal/command -count=1
ok github.com/aritmolab/thothii/tools/dwh-auth/internal/command
Do not treat this task as complete yet. Remaining direct session path consumers are:
go test -race ./internal/command -count=1
ok github.com/aritmolab/thothii/tools/dwh-auth/internal/command
- `harness/tht/cli/memory_cmd.py`: lines 60, 93, 165, 400, 458.
- `harness/tht/cli/sql_cmd.py`: `_session_sql_file` at line 254 remains a legacy
Path-returning bridge for preview/save/export.
- `harness/tht/cli/session_cmd.py:session_dir` remains only as a compatibility
bridge for the out-of-scope datamart command and the still-unmigrated memory/
SQL consumers; workflow mutations in session_cmd do not call it.
go test ./... -count=1
ok internal/command, internal/credential, internal/record, internal/registry, internal/securefile
The full Python suite has not been conclusively re-run to completion after the
latest changes. An earlier root-directory invocation failed only because a
pre-existing test expects `workflow.yaml` relative to `harness/`. Full gate tests
are green. Full-repo Ruff currently fails on pre-existing test-file lint findings;
changed-source Ruff passes.
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
```