Repository navigation
Validate Domain routes (S-003-1, S-003-8..12) - #168
Merged
Merged
Conversation
A Domain can now declare spec.routes: proxy routes (path + upstream) and static routes (path + static component, directory, spaFallback). The schema holds each route's shape and the release-relative directory and fallback; config validate checks the route source, path syntax, reserved and duplicate paths, and that a static component exists and is deployed on the proxy server. The inventory parses routes into value objects and serializes them only when present, so a Domain with only proxy.upstream is unchanged. Rendering routes comes with #162. Fixes #159 Part of #90 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The releasePath schema pattern ends with $, which Python's re.search lets match before one trailing newline, so config validate accepted directory: "web\n" that ReleaseRelativePath then refused with a ValueError when the inventory loaded. Refuse control characters in the schema, as component.schema.json's controlCharacterFree does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
shipmill-romamo Bot
added a commit
that referenced
this pull request
Oct 30, 2026
…11) (#171) * Accept a command health check in the component schema (#170) A component can declare healthCheck type: command (command argv, timeoutSeconds 1-300, attempts 1-20, no other key). The SDK parses it into value objects and the deploy, restart and rollback plans name the check and its command in wouldRun; the plan JSON gains no field (S-009-1, S-009-13). The engine does not run the check yet (#164), so the deploy role's entry points refuse a command check on their first task instead of passing an unrun gate. Fixes #161 Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Refuse a bad --source-schema with PRECONDITION and add migrate --data-schema (S-007-12, S-007-13) (#169) * Refuse a bad --source-schema with PRECONDITION and add migrate --data-schema A schema name must match ^[a-z_][a-z0-9_]*$ and be at most 63 characters, and may be named once; a malformed or repeated name now exits PRECONDITION from the command before any playbook, as spec 007 says, where it was a usage error and a repeat was silently dropped. cloudfall migrate takes --data-schema DATABASE=NAME beside --data, so the data step copies only the named schemas as data copy --source-schema does; one for a database with no --data is refused before any step (S-007-12, S-007-13). Fixes #126 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Describe a resumed migrate step by this run's options A pending step of a persisted plan kept the description it was saved with, so a data step saved with --data-schema crm=public and resumed without it reported "schema public" while it copied every schema (#126, S-007-13). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Validate Domain routes (S-003-1, S-003-8..12) (#168) * Validate Domain routes (S-003-1, S-003-8..12) A Domain can now declare spec.routes: proxy routes (path + upstream) and static routes (path + static component, directory, spaFallback). The schema holds each route's shape and the release-relative directory and fallback; config validate checks the route source, path syntax, reserved and duplicate paths, and that a static component exists and is deployed on the proxy server. The inventory parses routes into value objects and serializes them only when present, so a Domain with only proxy.upstream is unchanged. Rendering routes comes with #162. Fixes #159 Part of #90 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Refuse a trailing newline in a static route's directory or spaFallback The releasePath schema pattern ends with $, which Python's re.search lets match before one trailing newline, so config validate accepted directory: "web\n" that ReleaseRelativePath then refused with a ValueError when the inventory loaded. Refuse control characters in the schema, as component.schema.json's controlCharacterFree does. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> * Refuse a data copy the target can't hold before dumping it A preflight on the target host, after the empty-target check and before pg_dump, reads the source and target catalogs and names every schema the source lacks, extension and policy role the target lacks, and auth. reference, taking every name only as a psql variable. Any finding refuses the copy with nothing dumped: data copy and migrate's data step exit PRECONDITION with data_copy_preflight_refused and the four lists, read whole from a findings file under --data-migrations. pg_dump takes the needed extensions with named schemas, and pg_restore runs in one transaction, so a failed restore leaves no table and no receipt. Spec 007 is built (S-007-6 to S-007-11). Fixes #125 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: shipmill-romamo[bot] <338557544+shipmill-romamo[bot]@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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
A Domain can declare
spec.routes(spec S-003): proxy routes (path+upstream {address, port}) and static routes (path+static {component, directory, spaFallback?}), exactly one ofupstreamorstaticper route. This PR is the schema, the parser andcloudfall config validate; rendering is #162.config/schemas/v1/domain.schema.json:routes(at least one item) with$defsfor the route, the upstream (now shared withproxy.upstream, same shape) and the release-relative path.directoryandspaFallbackare held by the schema: letters, digits and._-/, relative, no..segment, anddirectorynot the release root (.,./,././).pathis only a string in the schema, so its rules refuse with their own codessdk/src/cloudfall/domain.py:DomainRoutePath(/then letters, digits and._~/-;is_reserved,is_directory) andReleaseRelativePath(is_release_root)sdk/src/cloudfall/inventory.py:DomainProxyRoute,DomainStaticRoute,DomainInventory.routes(default empty).as_dict()addsroutesonly when there are some, so a Domain with onlyproxy.upstreamserializes byte-for-byte as before (Q-3)sdk/src/cloudfall/validation.py:_validate_domain_referenceschecks routes in this order:domain_route_source_invalid(bothproxy.upstreamandroutes; neither stays valid),domain_route_path_invalid,domain_route_path_reserved(/.well-known/acme-challengeor under it),domain_route_path_duplicate, then for a static route the trailing/(domain_route_path_invalid),resource_reference_missinganddomain_route_component_not_on_proxy. Every refusal exitsCONFIG_INVALIDThe engine needs no change for CI:
config/exampleshas no routes, anddomains.yml's early check already refuses a Domain withoutproxy.upstreambefore any change, so a routes-only Domain stops there until #162.Plan
config/schemas/v1/domain.schema.json,sdk/src/cloudfall/domain.py,sdk/src/cloudfall/inventory.py,sdk/src/cloudfall/validation.py,sdk/tests/test_domain_routes.py,changelog.d/159-domain-routes-validation.mdsdk/tests/test_domain_routes.py); then theroutesschema, the route value objects,DomainInventory.routes, and the_validate_domain_referencesroute checks; the spec's Behaviour covers the rulestest_s003_<k>_...test runningcloudfall config validate; the existing inventory and validation tests prove a Domain with onlyproxy.upstreamis unchanged (Q-3)Test plan
sdk/tests/test_domain_routes.py(28 tests), failing on main at import, passing here;specs.py coverage --spec 003lists a test for each of S-003-1, 8, 9, 10, 11, 12uv run ruff check .,uv run mypy,uv run cloudfall config validate --project config/examples: passsdk/tests/test_validation.py,test_inventory.py,test_domains_apply.py,test_domains_converge.py,test_domains_observe.py,test_service_evidence.py,test_operations_dashboard.py,test_agent_server.py,engine/tests/test_nginx_site_templates.py,test_domains_one_domain.py,test_ansible_inventory.pyFixes #159
Part of #90
🤖 Generated with Claude Code