Document the ZAD setup a staging deployment needs #354

Merged
robbertbos merged 1 commit from staging-ingress-docs into main 2026-09-19 12:57:18 +00:00
Owner

Login on the new staging deployment failed because a fresh ZAD deployment gets one subdomain per component. The SPA's /api/* calls then hit the frontend's own nginx, which answers index.html with HTTP 200, so nothing reports an error.

The hostname layout lives in the deployment-layer publish-on-web config. Production got it by hand at go-live (domain-format: subdomain); the deploy job cannot set it, because zad deployment create sends only a name and an image per component. Setting that config on staging with zad service config set publish-on-web --target deployment put both components on waggle-staging.rijksapp.dev, and login and logout work there now.

The docs name that command plus three traps found on the way:

  • Components are project-wide, so zad component update changes production as well.
  • WAGGLE_PUBLIC_HOST is an alias to $PUBLIC_HOST and needs no setting; zad env list does not show aliases.
  • A base domain new to the project (rijksapp.dev) waits for an approval, and the deployment keeps the per-component layout until it is granted.
Login on the new staging deployment failed because a fresh ZAD deployment gets one subdomain per component. The SPA's `/api/*` calls then hit the frontend's own nginx, which answers `index.html` with HTTP 200, so nothing reports an error. The hostname layout lives in the deployment-layer `publish-on-web` config. Production got it by hand at go-live (`domain-format: subdomain`); the deploy job cannot set it, because `zad deployment create` sends only a name and an image per component. Setting that config on staging with `zad service config set publish-on-web --target deployment` put both components on `waggle-staging.rijksapp.dev`, and login and logout work there now. The docs name that command plus three traps found on the way: - Components are project-wide, so `zad component update` changes production as well. - `WAGGLE_PUBLIC_HOST` is an alias to `$PUBLIC_HOST` and needs no setting; `zad env list` does not show aliases. - A base domain new to the project (`rijksapp.dev`) waits for an approval, and the deployment keeps the per-component layout until it is granted.
Document the ingress a staging deployment needs
Some checks failed
CI / release-scripts (pull_request) Successful in 9s
security-scan / SBOM (trivy) (pull_request) Successful in 14s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 16s
security-scan / JS SCA (npm audit) (pull_request) Successful in 21s
security-scan / Python SAST (bandit) (pull_request) Successful in 24s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 43s
test-build / build (frontend) (pull_request) Successful in 1m8s
test-build / build (backend) (pull_request) Successful in 1m14s
test-build / build (pull_request) Successful in 0s
CI / e2e (pull_request) Has been cancelled
CI / pre-commit (pull_request) Has been cancelled
CI / backend-test (pull_request) Has been cancelled
CI / frontend-test (pull_request) Has been cancelled
365a7096d4
A fresh ZAD deployment gets a subdomain per component, and on that layout the
SPA's /api/* calls hit the frontend's own nginx, which answers index.html with
HTTP 200 - the app is handed HTML where it expects JSON and never sees an
error. Production does not hit this because its multi-path ingress was made by
hand at go-live and every deploy preserves it; the components payload carries
only a name and an image.

WAGGLE_PUBLIC_HOST gets the same treatment: pointed at the backend's own host
it still breaks login after the ingress is fixed.
Correct why staging did not get a multi-path ingress
All checks were successful
CI / release-scripts (pull_request) Successful in 12s
security-scan / SBOM (trivy) (pull_request) Successful in 12s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 16s
security-scan / JS SCA (npm audit) (pull_request) Successful in 18s
security-scan / Python SAST (bandit) (pull_request) Successful in 21s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 40s
test-build / build (frontend) (pull_request) Successful in 1m9s
CI / pre-commit (pull_request) Successful in 1m11s
CI / frontend-test (pull_request) Successful in 1m16s
test-build / build (backend) (pull_request) Successful in 1m15s
test-build / build (pull_request) Successful in 0s
CI / backend-test (pull_request) Successful in 2m49s
CI / e2e (pull_request) Successful in 5m33s
46d6448c61
The deploy action does not strip anything: it hands the components JSON to
`zad deployment create` verbatim, and it exposes domain-format and clone-from
besides. We simply never set them. Saying the workflow "cannot" supply an
ingress was wrong, and it pointed the next reader away from the two inputs that
are the actual lever.

Flags clone-from as a trap while there: it copies an existing deployment's
configuration, so cloning production hands staging the production database.
Name the real reason the ingress cannot be automated
All checks were successful
CI / release-scripts (pull_request) Successful in 9s
security-scan / SBOM (trivy) (pull_request) Successful in 13s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 18s
security-scan / Python SAST (bandit) (pull_request) Successful in 26s
security-scan / JS SCA (npm audit) (pull_request) Successful in 37s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 44s
test-build / build (frontend) (pull_request) Successful in 1m18s
test-build / build (backend) (pull_request) Successful in 1m23s
CI / pre-commit (pull_request) Successful in 1m25s
test-build / build (pull_request) Successful in 0s
CI / frontend-test (pull_request) Successful in 1m27s
CI / backend-test (pull_request) Successful in 3m2s
CI / e2e (pull_request) Successful in 4m52s
c3f4165d40
I had this wrong twice. The deploy action does hand the components JSON
through, but zad-cli reads exactly `name` and `image` per entry and drops the
rest silently, and the upsert request body has no path field at all. So the
ingress is not merely something we never asked for - it cannot be asked for
through `deployment create`, and deleting the deployment to recreate it would
change nothing.

The path lives on the component (`zad component update --path`), which is also
the fix for a deployment that already has the wrong shape.
Correct the WAGGLE_PUBLIC_HOST note, and name the base domain
Some checks failed
test-build / build (frontend) (pull_request) Successful in 1m3s
test-build / build (backend) (pull_request) Successful in 1m14s
test-build / build (pull_request) Successful in 0s
CI / pre-commit (pull_request) Successful in 2m53s
CI / frontend-test (pull_request) Has been cancelled
CI / backend-test (pull_request) Has been cancelled
CI / e2e (pull_request) Has been cancelled
CI / release-scripts (pull_request) Successful in 8s
security-scan / SBOM (trivy) (pull_request) Successful in 11s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 16s
security-scan / JS SCA (npm audit) (pull_request) Successful in 18s
security-scan / Python SAST (bandit) (pull_request) Successful in 19s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 39s
c5c65e0961
Measured on the live staging deployment: the same build answers with a
different redirect_uri depending on which host you ask, so the variable is not
set to the wrong value - it is not set at all and follows the Host header. That
only boots because staging is not on WAGGLE_ENVIRONMENT=production, which costs
the cookie its Secure flag and disables the dev-flag vetos.

Adds the base-domain choice while there: staging belongs on rijksapp.dev, and a
domain new to the project needs an approval that leaves the deployment on the
cluster address until granted.
WAGGLE_PUBLIC_HOST is an alias, not an unset variable
All checks were successful
CI / release-scripts (pull_request) Successful in 6s
security-scan / SBOM (trivy) (pull_request) Successful in 10s
security-scan / JS SCA (npm audit) (pull_request) Successful in 17s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 17s
security-scan / Python SAST (bandit) (pull_request) Successful in 19s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 41s
test-build / build (frontend) (pull_request) Successful in 1m2s
test-build / build (backend) (pull_request) Successful in 1m9s
CI / backend-test (pull_request) Successful in 2m39s
CI / pre-commit (pull_request) Successful in 1m9s
CI / frontend-test (pull_request) Successful in 1m9s
test-build / build (pull_request) Successful in 0s
CI / e2e (pull_request) Successful in 4m35s
f1002cf4b6
Measured: `zad alias list -c backend` binds WAGGLE_PUBLIC_HOST and
WAGGLE_ALLOWED_ORIGINS to the platform's $PUBLIC_HOST, so both track the
deployment's own hostname. `zad env list` does not show aliases, and reading
only that is what led me to claim the variable was unset and staging therefore
not on production. Both deployments do run production: the session cookie comes
back with Secure on each.
robbertbos force-pushed staging-ingress-docs from f1002cf4b6
All checks were successful
CI / release-scripts (pull_request) Successful in 6s
security-scan / SBOM (trivy) (pull_request) Successful in 10s
security-scan / JS SCA (npm audit) (pull_request) Successful in 17s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 17s
security-scan / Python SAST (bandit) (pull_request) Successful in 19s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 41s
test-build / build (frontend) (pull_request) Successful in 1m2s
test-build / build (backend) (pull_request) Successful in 1m9s
CI / backend-test (pull_request) Successful in 2m39s
CI / pre-commit (pull_request) Successful in 1m9s
CI / frontend-test (pull_request) Successful in 1m9s
test-build / build (pull_request) Successful in 0s
CI / e2e (pull_request) Successful in 4m35s
to 1b763b4dc1
All checks were successful
CI / pre-commit (pull_request) Successful in 1m17s
CI / release-scripts (pull_request) Successful in 8s
security-scan / SBOM (trivy) (pull_request) Successful in 11s
security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 14s
security-scan / JS SCA (npm audit) (pull_request) Successful in 18s
security-scan / Python SAST (bandit) (pull_request) Successful in 22s
security-scan / Python SCA (pip-audit) (pull_request) Successful in 40s
CI / frontend-test (pull_request) Successful in 1m4s
test-build / build (backend) (pull_request) Successful in 1m20s
test-build / build (pull_request) Successful in 0s
test-build / build (frontend) (pull_request) Successful in 1m5s
CI / backend-test (pull_request) Successful in 5m25s
CI / e2e (pull_request) Successful in 7m36s
2026-09-19 12:55:58 +00:00
Compare
robbertbos changed title from Document the ingress a staging deployment needs to Document the ZAD setup a staging deployment needs 2026-09-19 12:56:18 +00:00
robbertbos deleted branch staging-ingress-docs 2026-09-19 12:57:18 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
robbertbos/waggle!354
No description provided.