4.1 KiB
4.1 KiB
Container Packaging Task 4 Report
Status
Implemented and verified runtime-configured frontend packaging.
Changes
- Added the browser runtime contract
window.__THOTHII_CONFIG__.backendBaseUrl. - Loaded
/config.jsbefore the Vite module entrypoint. - Made runtime configuration take precedence while preserving
VITE_BACKEND_URLand the existinghttp://localhost:8787client default for development and tests. - Added a multi-stage frontend image that builds with Node and serves static assets as
unprivileged UID/GID
101:101with nginx on port 8080. - Added startup-time
BACKEND_BASE_URLsubstitution (default/api). - Added
/api/reverse proxying tocore:8787, SPA fallback, no-cache runtime config, and SSE-safe proxy settings (proxy_buffering off,proxy_cache off, one-hour read timeout).
TDD evidence
- RED:
npx vitest run src/api/runtime-config.test.tsfailed because./runtime-configdid not exist. - GREEN: targeted runtime config suite passed (3 tests after preserving the legacy client default).
Verification
cd frontend && npx vitest run --reporter=dot && npx tsc -b && npm run build— exit 0 (40 test files, 185 tests; TypeScript and Vite production build passed).docker build -f docker/frontend.Dockerfile -t thothii-frontend:test .— success.- Image metadata reports
USER 101:101. - Two-container isolated-network smoke:
/config.jsreturnedwindow.__THOTHII_CONFIG__ = { backendBaseUrl: "/api" };/api/healthproxied to the core image and returned{"status":"ok"}.- an unknown nested route returned the SPA
index.html. - active nginx config contained
proxy_buffering off,proxy_cache off, andproxy_read_timeout 1h. /config.jsreturnedCache-Control: no-store.
sh -n docker/frontend-entrypoint.shandgit diff --check— exit 0.
Secret-leakage inspection
.dockerignoreexcludes.env*(except examples), credentials/key formats, dependency trees, build outputs, backend data, and deployment data.- The runtime web root contained no
.env*,.pem,.key,.p12, or.pfxfiles. - Image history contained build/package instructions only; no secret build arguments or credential values were introduced by this task.
Self-review / concerns
- nginx resolves the
corehostname at startup, matching the planned Compose service name; standalone runs therefore need a reachable network alias namedcore. - Existing frontend test warnings (React refs/act, MSW unmatched incidental requests, Vite chunk-size warnings) remain; they did not fail the requested gates and are unrelated to this task.
.superpowers/sdd/progress.mdwas already modified by the orchestrator and was intentionally excluded from this task's commit.
P1 review fixes
Follow-up commit work addressed both review findings:
- Runtime configuration is now produced with
jq -cn --arg, soBACKEND_BASE_URLis encoded by a real JSON serializer rather than interpolated into JavaScript bysed. - The image includes
frontend-config-smoke, which strips only the fixed assignment wrapper, parses the remaining JSON withjq, requires exactly thebackendBaseUrlkey, and compares the decoded value to the environment input. - The hostile smoke passed with quotes, backslashes, a literal newline, ampersand, pipe, and
"; globalThis.PWNED=true; //in the value. A breakout would leave non-JSON trailing input and fail parsing. - Added
joinBackendPath, shared by API fetch and EventSource creation. It removes duplicate boundary slashes for relative and absolute bases while keeping empty and/bases rooted.
Follow-up verification:
- RED: six join cases failed with
joinBackendPath is not a functionbefore implementation. - Targeted: runtime config, API client, and EventSource suites — 14 tests passed.
- Full frontend gate — exit 0 (40 test files, 191 tests, TypeScript, Vite build).
- Rebuilt
thothii-frontend:testsuccessfully. - Hostile config image smoke —
frontend runtime config smoke: ok. - Rebuilt two-container smoke — default
/apiconfig, proxied/api/health, SPA fallback, and SSE-safe nginx directives all passed.