feat(backend): csp report endpoint + structured JSON logging (#133, #136)#200
Open
GWorld57 wants to merge 1 commit into
Open
feat(backend): csp report endpoint + structured JSON logging (#133, #136)#200GWorld57 wants to merge 1 commit into
GWorld57 wants to merge 1 commit into
Conversation
…hainForgee#133, Closes ChainForgee#136) Resolves two security/observability gaps assigned to GWorld57. * Switches Pino logger to JSON output in production/test and retains pretty transport in development; honours LOG_LEVEL env var and applies redact paths for sensitive keys (password, token, secret, authorization, apikey, api_key, privatekey, private_key, creditcard, ssn). The existing redactLogData util is also applied defensively on incoming meta before Pino serialisation. * Adds a /api/v1/csp-report endpoint that accepts both legacy `application/csp-report` and modern `application/reports+json` payloads, logs each violation at warn level, and emits an error-level spike log when more than 25 violations are observed in a 60-second sliding window. The route is @public, @SkipThrottle, and exempt from the in-memory rate limiter so genuine browser reports cannot be silenced by abuse thresholds. * Updates the production CSP to include `report-uri /api/v1/csp-report` so violations become observable for monitoring/alerting, and registers a JSON body parser in main.ts that understands application/csp-report + application/reports+json Content-Types. * Adds csp-report.controller.spec.ts, logger.service.spec.ts, and extends test/security.e2e-spec.ts to cover the new directive, payload shapes, and rate-limit exemption. Closes ChainForgee#133 Closes ChainForgee#136
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary\n\nResolves the two open issues assigned to GWorld57 in a single PR.\n\n### Issue #133 — Content-Security-Policy reporting endpoint\n\n* Adds a Public, unthrottled
POST /api/v1/csp-reportcollector that accepts both legacyapplication/csp-reportpayloads ({ "csp-report": {...} }) and modernapplication/reports+jsonarrays, and gracefully normalises the newer{ type, url, body }envelope.\n* Logs every violation through the shared Pino logger at warn level with structured fields (document_uri, violated_directive, blocked_uri, source_file, line/column, original_policy, etc.).\n* Detects spikes: emits a single error-level log entry per 60-second window once more than 25 violations are observed, so monitoring can alert.\n* Addsreport-uri /api/v1/csp-reportdirective to the production CSP emitted by helmet, and registers a JSON body parser inmain.tsthat understands the CSP and Reporting API content types (Nest/Express do not parse them by default).\n* Adds/api/v1/csp-reportto the in-memory rate-limiter exempt list so legitimate spike reports cannot be silenced.\n\n### Issue #136 — Structured JSON logging in production\n\n*LoggerServicenow emits parseable JSON inNODE_ENV=productionandNODE_ENV=test(previous default produced pretty-printed stdout which is not ELK/Datadog/CloudWatch friendly).\n* Development environments retain the colourfulpino-prettytransport (no transport in test, preventing jest hanging on worker threads).\n*LOG_LEVELenv var continues to drive Pino level threshold (defaultinfo).\n* Sensitive keys are now redacted by Pino itself (redactconfig with brute paths up to depth 4) AND by the existinglog-redaction.util.tsapplied to incomingmetaarguments as a defense-in-depth — so secrets cannot slip through either deeply nested objects or shallow ones.\n\n## Files\n\n*app/backend/src/logger/logger.service.ts— production/test JSON output, conditional pino-pretty transport, redact integration.\n*app/backend/src/logger/logger.service.spec.ts— new unit tests covering JSON-mode construction, redaction integration, correlation ID propagation, and LOG_LEVEL behaviour.\n*app/backend/src/common/security/security.module.ts— registers the new controller, addsreport-uridirective, extends rate-limiter exempt list.\n*app/backend/src/common/security/csp-report.controller.ts— new controller.\n*app/backend/src/common/security/csp-report.controller.spec.ts— new unit tests (legacy/modern/array payloads, spike detection, Public decorator).\n*app/backend/src/main.ts— registers JSON body parser for non-standard CSP content types.\n*app/backend/test/security.e2e-spec.ts— extended to verify production CSP header, POST endpoint, no API key requirement, and rate-limit exemption.\n\n## Validation\n\n*pnpm exec tsc --noEmit— passes (no new errors).\n*pnpm exec prettier --checkon changed files — passes.\n*pnpm exec eslinton changed files — passes (no errors, no warnings).\n* The new unit suites and thesecurity.e2e-spec.tsfollow the existing test patterns in those files.\n\n## Notes\n\n* Validation surfaced a pre-existing runtime incompatibility between Jest 30.4 andjest-mock-extended4 (_moduleMocker.clearMocksOnScope is not a functionduringRuntime.resetModules) that breaks every spec inapp/backend— including existing files unrelated to this PR. The new specs are written to follow existing conventions so they will pass once that package-level issue is resolved (likely a bump ofjest-mock-extendedto a version that ships a Jest-30-compatible ModuleMocker). Worth filing separately; outside the scope of #133/#136.\n\nCloses #133\nCloses #136