Production Infrastructure BlueprintBlueprint Rev. 2026-08-09

Rules #

Rules specific to this repository. The community rulesets cover the generic classes of bug. These five encode invariants this codebase actually depends on, three of which were defects here before they were rules. A convention that lives only in a reviewer's memory is not enforced.

R-01

Broad exception handler

A catch-all @ExceptionHandler in a class that does not extend ResponseEntityExceptionHandler swallows Spring MVC's own exceptions, so an unmapped path returns 500 instead of 404 and ordinary client mistakes burn the error budget. Extend ResponseEntityExceptionHandler, which maps those to their real status codes and leaves the catch-all for genuinely unexpected failures.

Rule
blueprint-broad-exception-handler ERROR
Applies to
/services/*/src/main/**
yaml
pattern: @ExceptionHandler($EX.class)
$RET $METHOD(...) { ... }
metavariable-regex: $EX =~ ^(Exception|Throwable|RuntimeException)$
pattern-not-inside: class $CLASS extends ResponseEntityExceptionHandler { ... }
R-02

No secrets from environment

Secrets are delivered as mounted files and read through Spring's configtree:, never from the environment. Environment variables are inherited by every child process, readable through /proc, and captured verbatim in crash dumps and container inspect output. See docs/security.md.

Rule
blueprint-no-secrets-from-environment ERROR
Applies to
/services/*/src/main/**
yaml
pattern: System.getenv(...)
R-03

Readiness must not include kafka

Kafka must not gate readiness. The transactional outbox absorbs a broker outage, so pulling the service out of the load balancer when the broker is down converts a degraded async path into a full outage. See docs/adr/0007-readiness-excludes-kafka.md.

Rule
blueprint-readiness-must-not-include-kafka ERROR
Applies to
**/application*.yml
yaml
pattern-regex: readiness:\s*\n\s*include:[^\n]*kafka
R-04

Migration must be expand only

Migrations must keep the previous release working: they add, and never drop, rename, retype, or add NOT NULL without a default in the same release as the code that stops needing it. Split the change into expand and contract steps across releases. A contract step that is safe now is marked with a nosemgrep comment and the reason on the line before it. See docs/runbooks/zero-downtime-migration.md.

Rule
blueprint-migration-must-be-expand-only ERROR
Applies to
/services/*/src/main/resources/db/migration/*.sql
yaml
pattern-regex: (?i)\bDROP\s+(TABLE|COLUMN)\b
pattern-regex: (?i)\bRENAME\s+(COLUMN\b|TO\b)
pattern-regex: (?i)\bALTER\s+COLUMN\s+\S+\s+(SET\s+DATA\s+)?TYPE\b
pattern-regex: (?i)\bALTER\s+COLUMN\s+\S+\s+SET\s+NOT\s+NULL\b
pattern-regex: (?i)\bADD\s+(COLUMN\s+)?\S+\s+[^,;]*\bNOT\s+NULL\b(?![^,;]*\bDEFAULT\b)
R-05

No plaintext password env

Pass credentials to containers as a file reference (*_PASSWORD_FILE) pointing at a mounted secret, not as a plaintext environment variable.

Rule
blueprint-no-plaintext-password-env ERROR
Applies to
/deploy/**/*.yml · /deploy/**/*.yaml
yaml
pattern-regex: ^\s+[A-Z_]*PASSWORD:\s*\S

The security workflow runs these alongside the community p/java, p/secrets and p/dockerfile rulesets, with --error, so a match fails the build. Each rule was proven to fire against deliberately bad input before it was trusted to pass good input.

esc
↑ ↓ to move↵ to open/ or ⌘K to search