# 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.