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
gabrielujelistic-collab pushed a commit to Stellar-drive/stellar-drive-atomic-ip that referenced this pull request Nov 9, 2026
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