docs: record DWH auth implementation evidence
This commit is contained in:
@@ -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
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user