13 KiB
Task 6 — Frontend identity and administrator UX report
RED
- Added API tests for the
/meprincipal call andmine/allsession-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.confirmwas 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 e2ereached 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/meAPI call; scoped listing defaults tomine.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, andfrontend/src/shell/AppShell.session-mgmt.test.tsx: contract and UX coverage.
Self-review
- Regular users remain fail-closed on
mine; no administrator control renders withoutprincipal.isAdmin. - The all-sessions view includes owner labels (including
Unknownfor 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
displayNamemust never establish ownership. The predicate now skips confirmation only whensession.authorexactly equalsprincipal.subject; all display-name matches and missing authors are conservative cross-owner actions. - Added RED/GREEN regressions where two principals share display name
Alicebut have distinct subjects: both delete (with another session present, so select-all cannot mask the guard) and archive require confirmation. - Added
aria-pressedto 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, andgit diff --checkall 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.shscripts/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:
case=source_contract status=FAIL
The runtime gate was also first invoked before its file existed:
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:
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:
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:
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:
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 byss -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
mktemproot 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.
- The contract checker originally selected only the first matching
/dwh/location. A real copied fixture appended this competing location without authentication:
location ~ ^/dwh/ {
proxy_pass http://127.0.0.1:3001;
}
The first run reached the new check and failed as required:
case=negative_postgrest_regex_bypass status=FAIL
- 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:
case=cleanup_term_ignored_bounded status=FAIL
- The TCP detector has a positive-control regression. A scratch copy of the integration script
replaced its
ss -ltnpHdetector withreturn 1; its known loopback listener was then not detected and the run failed with:
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_declarationsconsumes normalized, comment-stripped effective lines andcheck_templatesrequires 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_pidusesss -ltnpHand 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_pidnow 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 tocaseandstatuslines.
GREEN verification
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.