Skip to content

Fix: 4 issues (#1204, #1205, #1206, #1207) - #1283

Merged
fejilaup-cloud merged 2 commits into
AtomicIP:mainfrom
knightqueen-sketch:simple/1204-1205-1206-1207
Oct 21, 2026
Merged

fejilaup-cloud merged 2 commits into
AtomicIP:mainfrom
knightqueen-sketch:simple/1204-1205-1206-1207

Conversation

@knightqueen-sketch

Copy link
Copy Markdown
Contributor

Closes #1204
Closes #1205
Closes #1206
Closes #1207

Issues

#1204 Replace the Wildcard CORS Header With an Allowlist

Labels: security, api-server
Priority: High
Estimated Time: 2 hours

Description:
cors_middleware (middleware_pipeline.rs ~L129) sets Access-Control-Allow-Origin: * on every response, including admin and recovery routes. Any site can read those responses from a browser.

Tasks:

  • Configure an allowlist of origins per environment
  • Apply CORS headers only to public read routes
  • Add a test that an unlisted origin receives no allow header

Related existing issues: #‍703

Imported from the AtomicIp_130.md backlog (item 65).

#1205 Add GraphQL Depth and Complexity Limits

Labels: security, api-server
Priority: High
Estimated Time: 3 hours

Description:
The GraphQL schema in graphql.rs has no depth or complexity limit. A deeply nested or wide query can consume unbounded CPU and memory on a public endpoint.

Tasks:

  • Set limit_depth and limit_complexity on the schema builder
  • Document the limits in docs/api-reference.md
  • Add tests that an over-limit query is rejected

Imported from the AtomicIp_130.md backlog (item 66).

#1206 Explicitly Configure GraphQL Introspection

Labels: security, api-server
Priority: Low
Estimated Time: 1 hour

Description:
Nothing in the API server sets introspection explicitly, so the schema is exposed by default in every environment, including production.

Tasks:

  • Disable introspection outside development
  • Make the setting an explicit environment option
  • Add a test that introspection is off in production mode

Imported from the AtomicIp_130.md backlog (item 67).

#1207 Protect the /metrics Endpoint

Labels: security, api-server, monitoring
Priority: Medium
Estimated Time: 1.5 hours

Description:
/metrics is a public route. It exposes request counts, error rates, and internal labels to anyone who can reach the service.

Tasks:

  • Serve metrics on a separate internal port or require a token
  • Update the Prometheus scrape config
  • Add a test that unauthenticated scrapes are refused

Related existing issues: #‍260

Imported from the AtomicIp_130.md backlog (item 68).

Summary

Keep the new configuration env-driven and default-safe: empty CORS allowlist means no CORS headers are emitted, introspection defaults off outside development, and metrics require a token or are only reachable on the internal port. Reuse the existing AuthError/IntoResponse pattern in auth.rs for the metrics token guard if convenient. Ensure the public router no longer mounts /metrics and that the test router in main.rs mirrors production wiring so the integration tests are meaningful. Verify async-graphql 7 exposes limit_depth/limit_complexity/disable_introspection on SchemaBuilder (they are available via the standard extensions in v7).

Changes

  • Replace the wildcard CORS behaviour in cors_middleware. Add an allowed_origins: Vec<String> field to MiddlewareConfig (default empty, populated from an env var such as CORS_ALLOWED_ORIGINS) and a helper that decides whether a request path is a public read route (e.g. GET on /v1/ip/, /v1/swap/, /graphql, /health, /version) versus admin/recovery routes (/v1/admin/, /v1/auth/recovery/). In cors_middleware, read the request Origin header before calling next.run, and only when the path is a public read route AND the origin matches the allowlist, insert Access-Control-Allow-Origin echoing that origin (plus Vary: Origin) along with the Allow-Methods/Allow-Headers/Expose-Headers headers; otherwise emit no CORS headers at all. Handle OPTIONS preflight for allowed origins. Add unit tests in this module asserting an unlisted origin receives no Access-Control-Allow-Origin header and that admin/recovery paths never receive CORS headers. (api-server/src/middleware_pipeline.rs)
  • Add GraphQL depth/complexity limits and explicit introspection control to the schema builders. Introduce a GraphQLSecurityConfig (depth_limit, complexity_limit, introspection_enabled) loaded from env (e.g. GRAPHQL_MAX_DEPTH, GRAPHQL_MAX_COMPLEXITY, GRAPHQL_INTROSPECTION) with introspection defaulting to off unless APP_ENV/ENVIRONMENT is 'development'. Update build_schema, build_schema_with_context and build_schema_with_broadcaster to apply .limit_depth(...), .limit_complexity(...) and .disable_introspection() when configured. Add tests that a query exceeding the depth limit and one exceeding the complexity limit are rejected with errors, and a test that with introspection disabled an introspection query returns an error while with it enabled it succeeds. (api-server/src/graphql.rs)
  • Protect the /metrics endpoint. Add a bearer-token guard (e.g. require_metrics_token middleware reading METRICS_AUTH_TOKEN from env and comparing the Authorization header) and/or support serving metrics on a separate internal listener port (METRICS_PORT). Expose a helper that builds the internal metrics router so main.rs can mount it separately. Add a test that metrics_handler behind the guard returns 401 when no/invalid token is supplied and 200 with the correct token. (api-server/src/metrics.rs)
  • Wire the new security configuration into the server. Load CORS allowed origins, GraphQL limits/introspection settings and metrics auth settings from env at startup; build the GraphQL schema via the new config-aware builder; remove /metrics from the public router and instead spawn a separate internal listener on METRICS_PORT (guarded by METRICS_AUTH_TOKEN) so the public port no longer serves metrics; apply cors_middleware only to the public read routes rather than globally. Update the test router in this file to mirror the production wiring so integration tests can exercise CORS, GraphQL limits/introspection and metrics auth. (api-server/src/main.rs)
  • Add integration tests covering the four hardening changes: an unlisted Origin receives no Access-Control-Allow-Origin header while an allowlisted origin on a public read route does; admin/recovery routes never receive CORS headers; a GraphQL query exceeding the configured depth or complexity limit is rejected; introspection is rejected when the server runs in production mode; and an unauthenticated scrape of the metrics endpoint is refused (401) while an authenticated scrape succeeds. (api-server/tests/integration_tests.rs)
  • Document the GraphQL depth and complexity limits (configurable via GRAPHQL_MAX_DEPTH / GRAPHQL_MAX_COMPLEXITY, with the default values chosen in graphql.rs) and the error returned when a query exceeds them. Also document that introspection is disabled outside development (GRAPHQL_INTROSPECTION env option) and that /metrics is served on an internal port / requires a bearer token. (docs/api-reference.md)
  • Update the Prometheus scrape configuration so the api-server is scraped on the internal metrics port with the bearer token (bearer_token_file / authorization credentials) instead of the public /metrics path. Adjust the scrape job and any metric-name references in these rule files if the target label changes. (monitoring/prometheus/operations-rules.yml)
  • Update the monitoring README to describe that /metrics is now served on the internal metrics port and requires the METRICS_AUTH_TOKEN bearer token, and note the Prometheus scrape configuration change. (monitoring/README.md)
  • Update the api-server Deployment: add a metrics containerPort (METRICS_PORT), change the prometheus.io/port annotation to the internal metrics port, and add METRICS_AUTH_TOKEN (from the existing secret) plus METRICS_PORT, CORS_ALLOWED_ORIGINS, GRAPHQL_MAX_DEPTH, GRAPHQL_MAX_COMPLEXITY and GRAPHQL_INTROSPECTION env entries so the new configuration is available in-cluster. (deploy/k8s/base/deployment.yaml)
  • Add a separate internal metrics port to the api-server Service (targetPort matching the metrics containerPort) so Prometheus can scrape it, and ensure the public http port no longer exposes /metrics. (deploy/k8s/base/service.yaml)

Co-authored-by: Simple Agent <agent@simple.dev>
@drips-wave

drips-wave Bot commented Oct 18, 2026

Copy link
Copy Markdown

@knightqueen-sketch Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@fejilaup-cloud
fejilaup-cloud merged commit 416e7cf into AtomicIP:main Oct 21, 2026
0 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants