Skip to content

Comments

chore: production hardening and low-hanging fruit#37

Draft
xernobyl wants to merge 8 commits intofeat/webhook-cache-retry-metrics-repo-namingfrom
chore/low-hanging-fruit
Draft

chore: production hardening and low-hanging fruit#37
xernobyl wants to merge 8 commits intofeat/webhook-cache-retry-metrics-repo-namingfrom
chore/low-hanging-fruit

Conversation

@xernobyl
Copy link
Contributor

@xernobyl xernobyl commented Feb 18, 2026

Description

This PR adds production-hardening and low-hanging fruit: constant-time API key comparison, request body limit with metric, error sanitization for 403, DB connection pool configuration, docs for new env vars, and webhook secret exposure hardening.

Changes

Security & hardening

  • Constant-time API key comparison (internal/api/middleware/auth.go): Use crypto/subtle.ConstantTimeCompare for API key check to avoid timing side-channels.
  • Request body limit (internal/api/middleware/max_body.go): MaxBody(maxBytes, recorder) middleware caps body size via http.MaxBytesReader; returns 413 when exceeded. Buffers response only for POST/PUT/PATCH. Config: MAX_REQUEST_BODY_BYTES (default 10 MiB). Metric: hub_request_body_too_large_total.
  • Error sanitization (internal/api/handlers/webhooks_handler.go): 403 Forbidden for webhook limit exceeded returns fixed message "Maximum number of webhooks reached"; actual error logged server-side only.
  • Webhook secret redaction on reads (internal/models/webhooks.go, internal/api/handlers/webhooks_handler.go): GET /v1/webhooks and GET /v1/webhooks/{id} now return public webhook DTOs that omit signing_key.

Database

  • Connection pool config (pkg/database/postgres.go, internal/config): PoolConfig and NewPostgresPool(ctx, url, opts). Env: DATABASE_MAX_CONNS, DATABASE_MIN_CONNS, DATABASE_MAX_CONN_LIFETIME_SECONDS (defaults 25, 0, 3600). All call sites (main, tests) pass pool config from config.

Docs

  • Environment variables: Request limits (MAX_REQUEST_BODY_BYTES) and database pool (DATABASE_MAX_CONNS, DATABASE_MIN_CONNS, DATABASE_MAX_CONN_LIFETIME_SECONDS) documented in docs/reference/environment-variables.mdx.

Tests

  • Webhook integration assertions (tests/integration_test.go): TestWebhooksCRUD now asserts signing_key is absent from webhook GET and LIST responses.

Testing

  • Unit: go test ./internal/... ./pkg/... -count=1
  • Integration: make tests (with Postgres, .env loaded) ✅
  • Lint/format: make fmt

Checklist

  • Code follows project style (make fmt, make lint).
  • New behavior covered by unit/integration tests where applicable.
  • Docs updated (env vars).
  • Related issues linked (if any).

@xernobyl xernobyl marked this pull request as draft February 18, 2026 17:15
@xernobyl xernobyl changed the base branch from main to feat/webhook-cache-retry-metrics-repo-naming February 18, 2026 17:16
@xernobyl xernobyl changed the title chore: production hardening and low-hanging fruit (auth, body limit, pool, cache, retry) chore: production hardening and low-hanging fruit Feb 20, 2026
@xernobyl xernobyl force-pushed the chore/low-hanging-fruit branch from c1856b3 to 98f94f6 Compare February 20, 2026 11:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant