veza/veza-backend-api/internal/config
senke 3c4d0148be feat(webhooks): persist raw hyperswitch payloads to audit log — v1.0.7 item E
Every POST /webhooks/hyperswitch delivery now writes a row to
`hyperswitch_webhook_log` regardless of signature-valid or
processing outcome. Captures both legitimate deliveries and attack
probes — a forensics query now has the actual bytes to read, not
just a "webhook rejected" log line. Disputes (axis-1 P1.6) ride
along: the log captures dispute.* events alongside payment and
refund events, ready for when disputes get a handler.

Table shape (migration 984):
  * payload TEXT — readable in psql, invalid UTF-8 replaced with
    empty (forensics value is in headers + ip + timing for those
    attacks, not the binary body).
  * signature_valid BOOLEAN + partial index for "show me attack
    attempts" being instantaneous.
  * processing_result TEXT — 'ok' / 'error: <msg>' /
    'signature_invalid' / 'skipped'. Matches the P1.5 action
    semantic exactly.
  * source_ip, user_agent, request_id — forensics essentials.
    request_id is captured from Hyperswitch's X-Request-Id header
    when present, else a server-side UUID so every row correlates
    to VEZA's structured logs.
  * event_type — best-effort extract from the JSON payload, NULL
    on malformed input.

Hardening:
  * 64KB body cap via io.LimitReader rejects oversize with 413
    before any INSERT — prevents log-spam DoS.
  * Single INSERT per delivery with final state; no two-phase
    update race on signature-failure path. signature_invalid and
    processing-error rows both land.
  * DB persistence failures are logged but swallowed — the
    endpoint's contract is to ack Hyperswitch, not perfect audit.

Retention sweep:
  * CleanupHyperswitchWebhookLog in internal/jobs, daily tick,
    batched DELETE (10k rows + 100ms pause) so a large backlog
    doesn't lock the table.
  * HYPERSWITCH_WEBHOOK_LOG_RETENTION_DAYS (default 90).
  * Same goroutine-ticker pattern as ScheduleOrphanTracksCleanup.
  * Wired in cmd/api/main.go alongside the existing cleanup jobs.

Tests: 5 in webhook_log_test.go (persistence, request_id auto-gen,
invalid-JSON leaves event_type empty, invalid-signature capture,
extractEventType 5 sub-cases) + 4 in cleanup_hyperswitch_webhook_
log_test.go (deletes-older-than, noop, default-on-zero,
context-cancel). Migration 984 applied cleanly to local Postgres;
all indexes present.

Also (v107-plan.md):
  * Item G acceptance gains an explicit Idempotency-Key threading
    requirement with an empty-key loud-fail test — "literally
    copy-paste D's 4-line test skeleton". Closes the risk that
    item G silently reopens the HTTP-retry duplicate-charge
    exposure D closed.

Out of scope for E (noted in CHANGELOG):
  * Rate limit on the endpoint — pre-existing middleware covers
    it at the router level; adding a per-endpoint limit is
    separate scope.
  * Readable-payload SQL view — deferred, the TEXT column is
    already human-readable; a convenience view is a nice-to-have
    not a ship-blocker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 02:44:58 +02:00
..
config.go feat(webhooks): persist raw hyperswitch payloads to audit log — v1.0.7 item E 2026-04-18 02:44:58 +02:00
config_test.go fix(config): refuse boot in production when HYPERSWITCH_ENABLED=false 2026-04-16 14:55:18 +02:00
cors.go feat: backend, stream server & infra improvements 2026-03-18 11:36:06 +01:00
db_init.go refactor(config): découper config.go par domaine (audit 2.7) 2026-02-15 14:44:33 +01:00
defaults.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
defaults_test.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
docs.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
docs_test.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
env_detection.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
env_detection_test.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
env_helpers.go feat(backend): OAuth FRONTEND_URL from config, docs update 2026-02-17 16:42:23 +01:00
env_loader.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
env_loader_test.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
middlewares_init.go v0.9.4 2026-03-05 23:03:43 +01:00
rabbitmq.go feat: backend — config, handlers, services, logging, migration 2026-03-23 15:46:57 +01:00
rate_limit.go feat: backend, stream server & infra improvements 2026-03-18 11:36:06 +01:00
redis_init.go refactor(config): découper config.go par domaine (audit 2.7) 2026-02-15 14:44:33 +01:00
reloader.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
reloader_test.go v0.9.4 2026-03-05 23:03:43 +01:00
secrets.go [BE-SEC-014] be-sec: Implement secrets management 2025-12-24 12:30:18 +01:00
secrets_test.go STABILISATION: phase 3–5 – API contract, tests & chat-server hardening 2025-12-06 17:21:59 +01:00
services_init.go v0.9.1 2026-03-05 19:22:31 +01:00
testutils.go fix(backend): use explicit DISABLE_RATE_LIMIT_FOR_TESTS flag instead of env-based bypass 2026-02-15 15:56:53 +01:00
testutils_test.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
upload_limits.go feat(backend,web): single source of truth for upload-size limits 2026-04-16 19:37:37 +02:00
upload_limits_test.go feat(backend,web): single source of truth for upload-size limits 2026-04-16 19:37:37 +02:00
validation.go refactor(backend): split config into domain modules (P2) 2026-02-16 11:12:21 +01:00
validation_test.go fix(chat,config): require REDIS_URL in prod + error on in-memory fallback 2026-04-16 14:56:47 +02:00
validator.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
validator_test.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
watcher.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00
watcher_test.go adding initial backend API (Go) 2025-12-03 20:29:37 +01:00