Skip to content

Hosting batch 1: configurable CORS, forwarded host, per-route rate limits, DB timeouts, OpenAPI security (#527 #528 #529 #531 #534) - #571

Merged
antosubash merged 18 commits into
mainfrom
feat/hosting-batch-1
Oct 22, 2026
Merged

antosubash merged 18 commits into
mainfrom
feat/hosting-batch-1

Conversation

@antosubash

Copy link
Copy Markdown
Owner

Summary

Closes #527
Closes #528
Closes #529
Closes #531
Closes #534

The design was approved in session; the spec is docs/superpowers/specs/2026-10-21-hosting-batch-1-design.md.

  • hosting: configurable CORS — credentialed API origin allowlist plus public range-resource policy #527 CORS
    • Host settings: cors_*, restart-required. An empty origin list means no CORS. * combined with credentials is rejected.
    • Hook: register_cors_policies(registry) for per-path policies (exact, then regex, then longest prefix).
    • Placement: a dispatching middleware runs after RequestLogging and before BodyLimit, so preflights never reach auth, rate limiting, setup or maintenance.
    • file_storage: public files allow any origin without credentials and Range requests, exposing Content-Range, Accept-Ranges and ETag. The DB setting public_files_cors (default on) turns this off.
  • hosting: honour X-Forwarded-Host behind a trusted proxy, with a host allowlist #528 Forwarded host
    • Allowlist: forwarded_host_allowlist (exact or *.example.com). It applies only behind SM_TRUSTED_PROXY from a trusted peer.
    • Behaviour: uses the rightmost X-Forwarded-Host, the value the trusted proxy appended; this changed after a security review. Anything else is ignored. When no port is given it comes from X-Forwarded-Proto.
  • hosting/rate-limits: per-route policies for authenticated users, keyed by user id #529 Per-route rate limits
    • Ways to declare a limit: a register_rate_limits(registry) hook for path rules, and a RateLimit("10/minute", key=...) dependency for single routes.
    • Keys: user, ip, user_or_ip or tenant. The tenant key applies to signed-in requests only, so anonymous traffic can't drain a tenant's budget.
    • Counters: separate namespaces for public-tier and rule counters. Dependency buckets are keyed by the effective route, including the router prefix.
    • Behaviour change: rate_limit_authenticated now counts per user instead of per IP. It is off by default.
  • db: expose pool-wait, connect, statement and idle-in-transaction timeouts for web and worker engines #531 DB timeouts
    • Host settings: db_pool_timeout, db_connect_timeout, db_statement_timeout_ms and db_idle_in_tx_timeout_ms (env still wins), passed to each driver in its own form. SQLite ignores them.
    • Worker: shares the timeouts and has its own SM_BG_TASKS_DB_* pool overrides. The outbox keeps its 1+2 pool.
  • openapi: declare cookie/Bearer/PAT security schemes on protected operations #534 OpenAPI security
    • Schemes: the schema declares bearerAuth and sessionCookie. Protected operations list both; public ones list [].
    • New doctor warning SM031: an /api route with no permission or public declaration. A new Authenticated() marker silences it for routes any signed-in user may call; added to the self-service tenants and users routes.
  • Groundwork: request hooks moved to a mixin (module.py 299 → 251 lines), plus shared path-matching registries.

Verification

  • Local CI, after merging main:
    • make lint passes.
    • make test-py: 5189 passed, 25 skipped.
    • make test-js passes.
    • make ci-doctor passes.
  • Review:
    • The background security review found the leftmost forwarded host and the anonymous tenant bucket, both fixed.
    • Codex found shared rate-limit counters and prefix-blind dependency buckets, both fixed.
    • The Claude review was clean after 2 passes, with 5 more fixes.
  • HTTP QA against a live app: 12 of 12 passed (preflights, credentialed and denied origins, cross-origin Range 206, forwarded-host spoofing, 429 with Retry-After, timeout settings, schema security, no SM031).
  • Not run locally:
    • the Redis rate-limit test, since there's no redis-server here (CI has Redis);
    • the Postgres-only pg_sleep statement-timeout tests.
  • Reports:

Report links are Claude Artifacts and start private — share them from claude.ai/code/artifacts if reviewers need access.

Accepted / follow-ups

  • bearerAuth is listed on every protected route because it covers provider access tokens; personal API tokens work only on TokenAllowed() routes (documented).
  • asyncpg timeouts are set through host settings, not URL query parameters.
  • Follow-up: unify the three path matchers (public routes, body limits, the new registries).

Test plan

  • CI is green, including Redis and Postgres jobs

https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4

… RateLimit dependency (#529)

rate_limit_authenticated is now keyed per user instead of per IP.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
… key only for signed-in requests

Security review: behind an appending proxy the leftmost forwarded host is
client-controlled, and anonymous traffic sharing a tenant bucket could drain
the tenant's budget.

Claude-Session: https://claude.ai/code/session_01M9neheZZEe3sVpDi2S3zT4
# Conflicts:
#	CHANGELOG.md
#	CLAUDE.md
#	framework/hosting/tests/test_build_time_settings_marked.py
#	framework/hosting/tests/test_middleware_order.py
# Conflicts:
#	CHANGELOG.md
#	framework/hosting/tests/test_build_time_settings_marked.py
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Deploying simple-module-python with  Cloudflare Pages  Cloudflare Pages

Latest commit: 281130e
Status: ✅  Deploy successful!
Preview URL: https://15c0bfcf.simple-module-python.pages.dev
Branch Preview URL: https://feat-hosting-batch-1.simple-module-python.pages.dev

View logs

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 21, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review ✅ Completed 2026-10-21T16:29:13.447815Z c7b3c7a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

# Conflicts:
#	CHANGELOG.md
#	docs/.vitepress/config.ts
#	framework/hosting/simple_module_hosting/_registrations.py
@antosubash
antosubash merged commit 218463c into main Oct 22, 2026
17 checks passed
@antosubash
antosubash deleted the feat/hosting-batch-1 branch October 22, 2026 07:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment