Skip to main content

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​

EnvironmentLocation
Localdocker/nginx/_locations.conf in the hub repo
Dev & test instancesdeploy/services/nginx/files/locations.conf in the deployment repo
Staging & Prodapp/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-src when omitted, so leaving one out usually still blocks. frame-ancestors, base-uri and form-action have no fallback and are unrestricted when omitted.

Services that set their own CSP​

Three Node services each set CSP headers covering their own responses:

FileCovers
app/routes/index.jsDocument (HTML) responses — the CSP that governs what scripts the page can run and what it can connect to
auth/app.jsAuth service responses, i.e. the login pages
api/app.jsAPI (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.