deploy.sh referenced apps/portal which was deleted in WS-3 PR-B1; the
script has been broken in main since that merge (npm run build
-w apps/portal would fail). Collapse to a single-app build.
Changes:
- deploy.sh: replace dual-build block (build app + portal, verify both
dist/) with single-app build (build app, verify dist/index.html)
- deploy/nginx/csp-portal.conf: deleted (content was identical to
csp-spa.conf — verified before removal)
- deploy/README.md: replace "Portal (portal.crewli.app)" server-block
section with "Legacy portal redirect" — a 301 server block
template that redirects portal.crewli.app → crewli.app preserving
the request URI. Notes that DNS retirement is a separate ops task
Out of scope: actually retiring the portal.crewli.app DNS record
(operational, tracked separately).
bash -n deploy.sh: clean.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
API middleware:
- SecurityHeaders now sets Content-Security-Policy from config/security.php
- Default API policy: "default-src 'none'; frame-ancestors 'none'"
- Supports report-only mode via CSP_REPORT_ONLY env var
- Policy value configurable via CSP_POLICY env var
Nginx deployment configs (deploy/nginx/):
- security-headers.conf: shared headers for all server blocks
- csp-api.conf: restrictive JSON-only policy for api.crewli.app
- csp-spa.conf: SPA policy for app/admin (self + unsafe-inline styles)
- csp-portal.conf: portal policy matching SPA
Development:
- CSP meta tags added to all three index.html files
- Includes 'unsafe-inline' + 'unsafe-eval' for Vite HMR/loader script
- Each app allows its own ws:// port for HMR websocket
Resolves security finding A13-9.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>