CI / CD
TODO:
Intro
Flows
dev. staging, production QA testing Releases Circle Ci...
Release hub repo to prod
See deployment wiki
Security headers & CSP
CSP and response headers are set in more than one place, and which of them the browser actually sees depends on the environment.
Where the document CSP comes from
| Environment | Location |
|---|---|
| Local | docker/nginx/_locations.conf in the hub repo |
| Dev & test instances | deploy/services/nginx/files/locations.conf in the deployment repo |
| Staging & Prod | app/routes/index.js in the hub repo |
Dev and the Jenkins test instances are deployed by the same Docker Swarm scripts in the deployment repo, so they all share that one nginx config. Staging and production run on ECS with no nginx in front of the app service, so the headers set by the app itself are the only ones the browser receives.
Changes to CSP or response headers must be applied in all relevant environments.
Why a change can work locally but still fail on dev
Locally, nginx sets its own CSP and suppresses the upstream one (proxy_hide_header Content-Security-Policy), so only the nginx policy applies.
On dev, nginx does not suppress the upstream header. It adds its own CSP alongside the one coming from the app service, so the browser receives two policies and enforces both independently — in effect the intersection, so the most restrictive wins.
Because of this, updating app/routes/index.js alone is not enough for dev: if a directive is narrower in the dev nginx config, or absent from it and not covered by that policy's default-src, nginx will still block it on dev. Both must be kept in sync.
[!NOTE] Most fetch directives fall back to
default-srcwhen omitted, so leaving one out usually still blocks.frame-ancestors,base-uriandform-actionhave no fallback and are unrestricted when omitted.
Services that set their own CSP
Three Node services each set CSP headers covering their own responses:
| File | Covers |
|---|---|
app/routes/index.js | Document (HTML) responses — the CSP that governs what scripts the page can run and what it can connect to |
auth/app.js | Auth service responses, i.e. the login pages |
api/app.js | API (JSON) responses — does not govern browser-level page enforcement |
These three policies are not currently identical: auth/app.js and api/app.js omit blob: and 'unsafe-eval' from script-src and set no connect-src at all. When widening the document CSP for a feature, check whether the auth and API policies need the same change rather than assuming they already match.