Files
ThothII/.superpowers/sdd/task-6-report.md
T

299 lines
13 KiB
Markdown

# Task 6 — Frontend identity and administrator UX report
## RED
- Added API tests for the `/me` principal call and `mine`/`all` session-list scopes.
- Added component tests for regular-user scope, admin scope switching, owner labels,
administrator banner, foreign-owner delete confirmation, and foreign-owner archive
confirmation.
- Initial focused run: 7 expected failures (missing `getMe`, missing scope query,
missing owner label/admin controls, and missing foreign-action confirmation).
- The archive-confirmation regression was also run separately before its implementation
and failed because `window.confirm` was not called.
## GREEN
- `npx vitest run src/api/sessions.test.ts src/shell/NavSessions.test.tsx src/shell/AppShell.session-mgmt.test.tsx`
— passed (47 tests before the archive follow-up; the focused archive regression then passed).
- `npm test` — passed: 44 files / 305 tests.
- `npx tsc -b` — passed.
- `npm run build` — passed.
- `git diff --check` — passed.
- `npm run e2e` reached Playwright but could not run: the environment has no Chromium
executable at Playwright's configured cache path. No application test failure was reported.
## Files changed
- `frontend/src/api/types.ts`: typed principal and session scope contracts.
- `frontend/src/api/sessions.ts`: typed `/me` API call; scoped listing defaults to `mine`.
- `frontend/src/shell/AppShell.tsx`: identity query, admin-only session scope selector and
banner, owner-aware destructive action confirmations.
- `frontend/src/shell/NavSessions.tsx`: owner labels in the all-sessions view.
- `frontend/src/api/sessions.test.ts`, `frontend/src/shell/NavSessions.test.tsx`, and
`frontend/src/shell/AppShell.session-mgmt.test.tsx`: contract and UX coverage.
## Self-review
- Regular users remain fail-closed on `mine`; no administrator control renders without
`principal.isAdmin`.
- The all-sessions view includes owner labels (including `Unknown` for legacy records).
- Delete confirmation preserves the pre-existing select-all behavior and adds confirmation
for foreign/unknown owners. Foreign archive now also requires an explicit browser
confirmation; existing Stop & save already has its confirmation dialog.
- A read-only review found no critical, important, or minor issues. The archive guard was
added after that review in response to the requirement to cover every destructive rail
action, and has its own RED/GREEN regression plus the final full verification above.
## Concerns
- E2E remains environment-blocked until the Playwright Chromium browser is installed.
- Existing Vitest runs emit pre-existing MSW unmatched-request and dialog-ref warnings; all
assertions pass and this task does not modify those shared test/UI primitives.
## Review remediation
- A post-commit review correctly identified that matching `displayName` must never establish
ownership. The predicate now skips confirmation only when `session.author` exactly equals
`principal.subject`; all display-name matches and missing authors are conservative
cross-owner actions.
- Added RED/GREEN regressions where two principals share display name `Alice` but have distinct
subjects: both delete (with another session present, so select-all cannot mask the guard) and
archive require confirmation.
- Added `aria-pressed` to the My sessions / All sessions controls and asserts their selected state
before and after switching.
- Remediation verification: focused regressions passed; full frontend Vitest (44 files / 305
tests), `npx tsc -b`, `npm run build`, and `git diff --check` all passed.
---
# DWH authentication Task 6 — Nginx and CI gate report
## Scope
Added only the two DWH-auth Nginx gates and the `dwh-auth-linux` deployment workflow job:
- `scripts/test-dwh-auth-nginx-contract.sh`
- `scripts/test-dwh-auth-nginx-integration.sh`
- `.github/workflows/deployment.yml`
This report deliberately remains unstaged. The pre-existing frontend Task 6 report above is
preserved rather than overwritten.
## TDD RED
The structural gate was written before any Task 5 template change. Those templates already met
the approved contract, so the behavioral RED was obtained by copying them into one exact temporary
root and removing only the effective `/dwh/` `auth_request` directive. The new checker failed as
required, with no credential material in output:
```text
case=source_contract status=FAIL
```
The runtime gate was also first invoked before its file existed:
```text
bash: scripts/test-dwh-auth-nginx-integration.sh: No such file or directory
```
The CI-job RED check found no `dwh-auth-linux` job in `deployment.yml`. No production template was
modified: the tests prove the existing Task 5 template contract instead of weakening it.
## GREEN
Shell syntax and workflow YAML were checked with:
```text
bash -n scripts/test-dwh-auth-nginx-contract.sh scripts/test-dwh-auth-nginx-integration.sh
python3 -c import-yaml-and-safe-load
```
The structural gate passed its source contract plus these 13 real copied-and-mutated Nginx fixtures:
```text
missing_auth_request
missing_proxy_method
missing_proxy_body
missing_proxy_header_isolation
missing_content_length_clear
missing_verifier_key_forward
missing_upstream_key_clear
missing_failure_mapping
public_verifier
tcp_authenticator
postgrest_bypass
failure_mapped_to_success
full_secret_rate_key
```
Each test mutates an effective, not comment-only, directive and requires the checker to reject it.
The source test and all 13 fixture tests emitted `case=... status=PASS`, followed by
`case=summary status=PASS`.
The isolated Nginx 1.24 smoke passed these sanitized cases:
```text
nginx_1_24
build_dwh_auth
registry_setup
verifier_start
synthetic_upstreams
composite_nginx_config
nginx_start
auth_socket_unix_only
verifier_not_public
valid_v1
valid_legacy
invalid_key
revoked_key
expired_key
duplicate_v1
duplicate_legacy
stopped_verifier
header_and_path_isolation
summary
```
It builds with the pinned official Go 1.26.5 image when the host Go binary is absent, creates only
synthetic v1, legacy, revoked, and expired credentials in a `0700` `/tmp` root, runs both Nginx and
the verifier on explicit temporary Unix sockets, and uses a loopback-only marker backend. Its output
is strictly `case` and `status`; keys, values, and digests remain only in the exact temporary root
and are removed by the trap.
`nginx -t` passed against the complete generated configuration. The marker proves that successful
`/dwh/?keep=exact&second=two` reaches the upstream unchanged, while neither the client API key nor
client or verifier `X-DWH-Key-ID` reaches it. A Unix forwarding probe proves that the verifier sees
only `X-API-Key`, with Cookie, Authorization, and spoofed audit ID absent. Duplicate v1 and ordinary
legacy headers return 401 through Nginx; a stopped verifier returns 503.
The final local equivalent of the four CI commands passed:
```text
Docker Go 1.26.5: go test -race ./... -count=1 and go vet ./...
bash scripts/test-dwh-auth-build-contract.sh
bash scripts/test-dwh-auth-nginx-contract.sh
bash scripts/test-dwh-auth-nginx-integration.sh
```
The Go race suite passed for command, credential, record, registry, securefile, and service;
`go vet` was silent; the build contract passed; both Nginx gates reached their summaries.
## CI contract
The new job uses `actions/checkout` with `persist-credentials: false`, pins Go 1.26.5 with cache
keyed on `tools/dwh-auth/go.mod`, installs `nginx-light`, and runs exactly the four required commands.
Existing jobs were not altered.
## Self-review
- The template tests parse normalized effective directives, so commented-out declarations cannot
satisfy the gate.
- The authentication socket is configured as `http://unix:...:/verify`, is observed by `ss -xl`,
and Nginx itself listens only on a temporary Unix socket; neither test starts a public listener.
- All spawned processes are registered by PID; cleanup signals only those PIDs and deletes only the
exact `mktemp` root after a guarded path check.
- The verifier, marker, registry, Nginx prefix, PID, logs, config, and sockets all reside beneath
that root. No `/etc`, systemd, active Nginx config, stack, legacy route, or real registry/key is
read or changed.
- Task 5 templates were not modified because the structural and runtime tests passed unchanged.
## Concern
The sandbox `apply_patch` helper repeatedly failed with `bwrap: loopback: Failed RTM_NEWADDR:
Operation not permitted`. A narrowly scoped fallback editor was used only for the workflow and the
Nginx-version assertion. Its first workflow insertion interpreted the action-reference at signs;
the two malformed values were immediately corrected and all final YAML, exact-string, syntax, and
four-command checks were rerun. No remaining product concern is known; the integration gate requires
Nginx 1.24 and Python 3, both supplied by the specified Ubuntu CI runner.
---
# DWH authentication Task 6 — review remediation wave
## Review findings and RED evidence
The three review findings were reproduced against the Task 6 commit before their corresponding
hardening was accepted.
1. The contract checker originally selected only the first matching `/dwh/` location. A real copied
fixture appended this competing location without authentication:
```nginx
location ~ ^/dwh/ {
proxy_pass http://127.0.0.1:3001;
}
```
The first run reached the new check and failed as required:
```text
case=negative_postgrest_regex_bypass status=FAIL
```
2. The previous process stop sent TERM and immediately used an unbounded `wait`. A synthetic Python
child ignored TERM; the RED run used one exact short-lived watchdog only to prevent a test hang and
produced:
```text
case=cleanup_term_ignored_bounded status=FAIL
```
3. The TCP detector has a positive-control regression. A scratch copy of the integration script
replaced its `ss -ltnpH` detector with `return 1`; its known loopback listener was then not
detected and the run failed with:
```text
case=tcp_listener_detector_positive status=FAIL
```
All RED fixtures and the scratch script used an exact temporary path and were removed. No template,
service, workflow, key, or active Nginx configuration was changed.
## GREEN changes
- `location_declarations` consumes normalized, comment-stripped effective lines and `check_templates`
requires exactly one each of the only approved locations: verifier, unavailable named location, and
`/dwh/`. It therefore rejects both any extra intercepting location and a duplicate. The real regex
bypass and a new real duplicate `/dwh/` bypass fixture both pass by being rejected.
- `tcp_listener_for_pid` uses `ss -ltnpH` and a PID-bound match. The integration gate starts a
loopback-only synthetic listener, proves the detector sees that exact PID, stops and deregisters it,
then proves the verifier PID has no TCP listener while its Unix socket remains present.
- `stop_registered_pid` now sends TERM, polls for exit or zombie for a bounded deadline, sends KILL
if required, polls a second bounded deadline, and only reaps a direct child after terminal state is
proved. Explicit stops deregister their PID. The cleanup loop invokes that bounded operation only
for recorded PIDs and removes only its guarded temporary root.
- The synthetic child that ignores TERM is killed by the bounded path, must no longer answer to
`kill -0`, must not remain registered, and must finish within three seconds. Final gate output is
restricted to `case` and `status` lines.
## GREEN verification
```text
bash -n scripts/test-dwh-auth-nginx-contract.sh scripts/test-dwh-auth-nginx-integration.sh
Docker Go 1.26.5: go test -race ./... -count=1 and go vet ./...
bash scripts/test-dwh-auth-build-contract.sh
bash scripts/test-dwh-auth-nginx-contract.sh
gate contract: source plus 15 negative fixtures PASS, then summary PASS
bash scripts/test-dwh-auth-nginx-integration.sh
gate integration: 20 named cases PASS, then summary PASS
git diff --check
```
The integration cases include `cleanup_term_ignored_bounded`,
`tcp_listener_detector_positive`, `auth_socket_unix_only`, all existing credential decisions,
composite Nginx syntax, and stopped-verifier 503 behavior. Go race tests passed for command,
credential, record, registry, securefile, and service; vet and both diff checks were silent.
## Self-review and concern
The new location parser rejects comment-only and non-exact declarations because it operates on the
same normalized effective representation used by the rest of the contract. The TCP positive control
binds only `127.0.0.1` on a kernel-selected temporary port and is stopped through the same exact-PID
path under test. The bounded cleanup avoids arbitrary process lookup or broad signaling.
The environment still intermittently rejects `apply_patch` with the sandbox loopback error noted in
the original report; only narrowly scoped fallback edits to the two authorized scripts were used and
all final gates were rerun. No remaining review concern is known.