Repository navigation
Render Domain routes and serve static files from the release (S-003-2..7, S-003-13..15) - #177
Merged
Merged
Conversation
…..7, S-003-13..15) A Domain's validated spec.routes now render in cloudfall_nginx_site: one location per route, longest path first so the declared order doesn't change the bytes. A proxy route keeps the full request path; a static route aliases <installRoot>/current/<directory>, with try_files to its spaFallback, so a deploy or rollback switches what it serves without an Nginx reload. A Domain with only proxy.upstream renders byte-identical to origin/main, checked against golden files captured before the change. The engine inventory resolves each static route's served directory and the directories from the application root to releases/ that bootstrap creates 0750; the role grants the Nginx worker traverse-only access there with a POSIX ACL (user:www-data:--x) and never adds it to the application's group, so shared/env/<component>.env stays unreadable to it. The domains playbook's early check refuses only a Domain with neither proxy.upstream nor routes. Spec 003 is built: every criterion has a Verification line. Fixes #162 Fixes #90 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without a / route, Nginx served its default root for any unmatched path:
on Debian /usr/share/nginx/html, whose welcome page answers 200, so a Domain
health check on / could pass against nothing the Domain declares. The routes
render a closing location / { return 404; } in that case; a Domain with only
proxy.upstream renders unchanged.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
Author
|
@romamo Decided without waiting: a Domain whose routes have no Why: spec S-003 doesn't say; without it nginx served Debian's welcome page with 200, so a Domain health check on Reply with a comment starting with |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Renders a Domain's validated
spec.routes(validation landed in #168) incloudfall_nginx_site, the last build issue of spec S-003.domain-site.conf.j2: onelocationper route, longest path first then by path, so the declared order doesn't change the bytes. A proxy route proxies with the full request path (proxy_passwith no URI part); a static route isalias <installRoot>/current/<directory>/;plustry_files $uri <path><spaFallback>;when it declares a fallback. Routes render where the single proxy location did (80 without active TLS, 443 with it); the port 80 redirect and the ACME location are untouched. A Domain with onlyproxy.upstreamgoes through the same macro with/and renders byte-identical to origin/mainservedDirectory(<installRoot>/current/<directory>) andtraverseDirectories(application root down to the install root, plusreleases/)routesin its argument spec (each route exactly one ofupstream/static), asserts "upstream or routes", and, for a Domain with static routes, installsacland grantsuser:www-data:--xon the traverse directories (idempotent throughgetfacl). The worker joins no group, soshared/env/<component>.env(root:<app>0640) stays unreadable to it. Because the vhost reads throughcurrent, a deploy or rollback switches what is served with no Nginx reloaddomains.yml: the early check now refuses only a Domain with neitherproxy.upstreamnorroutes(task renamed accordingly)builtwith one Verification line per criterion;engine/README.mdand a changelog fragmentPlan
engine/ansible/roles/cloudfall_nginx_site/{templates/domain-site.conf.j2,tasks/main.yml,tasks/static_access.yml,meta/argument_specs.yml,defaults/main.yml},engine/ansible/playbooks/domains.yml,engine/src/cloudfall_engine/ansible_inventory.py,engine/tests/golden/nginx-site/*.conf(snapshot of origin/main's render),engine/tests/test_nginx_site_routes.py,engine/tests/test_domains_playbook.py,sdk/tests/test_domains_apply.py(the early check's renamed task),engine/README.md,docs/specs/003-domain-routes.md,changelog.d/162-domain-routes-render.mdproxy.upstreampath byte-identical; acceptroutesin the role's argument spec and asserts and in the domains playbook's early check; grant the nginx workeru:www-data:xalong each static route's install root; spec statusbuiltwith its Verification linesspecs.py checkandspecs.py coverage --spec 003Test plan
uv run ruff check .,uv run mypy,ansible-lint engine/ansible(withANSIBLE_CONFIG=engine/ansible/ansible.cfg, as CI): cleanuv run pyteston the touched and neighbouring files (engine/tests/test_nginx_site_*.py,test_domains_*.py,test_ansible_inventory.py,test_examples_render_unchanged.py,sdk/tests/test_domain_routes.py,sdk/tests/test_domains_apply.py): 122 passed. The full suite is left to CIengine/tests/test_nginx_site_routes.pyrenders the vhost with Ansible's owntemplatemodule on localhost from the engine inventory, compares the upstream-only render withengine/tests/golden/nginx-site/(captured from origin/main's template before the change), works out request answers with a small model of Nginx's prefix match,alias,rootandtry_filesover a release tree intmp_path, runsrollback.yml's symlink switch for real, and runs the ACL tasks with stand-ingetfacl/setfaclupstreamandstaticis refusedspecs.py checkandspecs.py coverage --spec 003: passnginx -ton 1.22.1 and 1.26.3, real GET answers, a real POSIX ACL andwww-datareading the files. They are left for a live proving run and said so in the spec's VerificationFixes #162
Fixes #90
🤖 Generated with Claude Code