docs: record DWH auth implementation evidence
This commit is contained in:
@@ -63,3 +63,236 @@
|
||||
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.
|
||||
|
||||
Reference in New Issue
Block a user