You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Stop embedding secret-shaped literals for the production-defaults guard
SonarCloud's hard-coded-secret rule flags any string that structurally
resembles a key/password next to a suspiciously-named field, regardless of
whether it's a real secret — it caught both the plaintext defaults and
their SHA-256 hashes in the previous two attempts.
ProductionSecretsGuard now takes two ProductionSecretsSnapshot values (the
bound Production configuration, and a fresh runtime read of the base
appsettings.json) and compares them structurally, so the 'dev default' is
never written down as a literal in source — Program.cs re-reads
appsettings.json itself to build the baseline. Tests use synthetic
placeholder strings instead of the real dev-default values.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MoQrUqEN5AoByRCVYD6Qrt
Copy file name to clipboardExpand all lines: src/Anything.API/agent.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -25,5 +25,5 @@ Thin HTTP layer. Endpoints extract request data and dispatch to `IMediator.Send(
25
25
-**Auth on the endpoint is not scoping.**`.RequireAuthorization()` + `HouseholdMiddleware` only prove the caller is *a member* of the header's household — the handler's own query must still filter by `IHouseholdContext.HouseholdId`, or every member of any household can read/write the row. Both halves are required for every new household-scoped endpoint.
26
26
-**`HouseholdMiddleware`'s exempt prefixes** (`/api/auth`, `/api/households`, `/api/events`, `/api/shared`, `/swagger`) skip the membership check entirely, so endpoints under them enforce their own access rules in the handler. Adding a prefix to that list needs the same justification. The middleware also costs one DB query per request — don't add further per-request middleware queries.
27
27
-**SSE (`/api/events`) broadcasts every event to every connected client, across households.**`SyncEvent` must stay type + optional id — never put entity data (names, amounts) in it. Its auth token rides the query string (EventSource can't set headers): don't log query strings anywhere, and don't reuse the query-token pattern on other endpoints.
28
-
-**The checked-in `appsettings.json` secrets are dev-only, and Production enforces that**: `ValidateProductionSecrets` in `Program.cs` refuses to start when `Jwt:SecretKey`, `Admin:Password`, or the MinIO secret still hold the checked-in defaults, or when `ImageSettings:ImageProxyKey`/`ImageProxySalt` are unset (unset means unsigned `/insecure` imgproxy URLs — an open resizer). Override them via environment variables; never commit a real secret to any appsettings file, and add any new secret's default to that guard.
28
+
-**The checked-in `appsettings.json` secrets are dev-only, and Production enforces that**: `ValidateProductionSecrets` in `Program.cs` refuses to start when `Jwt:SecretKey`, `Admin:Password`, or the MinIO secret still equal what a fresh runtime read of the base `appsettings.json` holds, or when `ImageSettings:ImageProxyKey`/`ImageProxySalt` are unset (unset means unsigned `/insecure` imgproxy URLs — an open resizer). It deliberately compares against a **runtime file read**, not an embedded literal or hash (`ProductionSecretsGuard`/`ProductionSecretsSnapshot`) — a hard-coded copy of the dev secret, plaintext or hashed, is itself what SonarCloud's secret-detection rule flags. Override real deployments via environment variables; never commit a real secret to any appsettings file, and never add a new secret's literal/hash to the guard — extend the snapshot and the baseline file read instead.
29
29
-**Anonymous endpoints doing per-request crypto or DB work need a rate limiter.** Login/refresh/register carry `.RequireRateLimiting(RateLimitPolicies.Auth)` (per-client-IP fixed window, configured via `RateLimiting:Auth`; the integration-test factory raises the limit). Client IPs are real only because `UseForwardedHeaders` trusts the nginx chain in `Program.cs` — keep that ordering (first in the pipeline) intact.
errors.Add("ImageSettings:SecretKey is unchanged from the checked-in appsettings.json default — set real MinIO credentials via environment variables.");
errors.Add("ImageSettings:ImageProxyKey/ImageProxySalt are unset — without them image URLs are unsigned (/insecure), an open resizer. Set both (hex) and configure imgproxy with the same IMGPROXY_KEY/IMGPROXY_SALT.");
0 commit comments