mirror of
https://github.com/Sea-Haven-Industries/shoc-backend.git
synced 2026-09-30 08:23:12 +00:00
79 lines
4.2 KiB
Markdown
79 lines
4.2 KiB
Markdown
# ADR 0002 — Sentry observability: release identity and redaction-safe telemetry fields
|
|
|
|
- Status: Accepted
|
|
- Date: 2026-09-03
|
|
- Scope: `Api.SeaHavenIndustries` (observability layer only; no behavior changes)
|
|
|
|
## Context
|
|
|
|
The backend reports to Sentry (SH-298). Events arrived without a stable release
|
|
identity, without service/commit attribution, and background jobs each hand-rolled
|
|
their own transaction setup. HTTP request metadata risked leaking PII through
|
|
route values, query strings, or identity claims.
|
|
|
|
## Decision
|
|
|
|
1. **Release identity.** `SentryObservability.ResolveRelease(Assembly)` accepts an
|
|
informational version shaped `shoc-backend@<40 hex commit sha>`, tolerates the
|
|
.NET SDK's matching `+<same sha>` suffix for compatibility, canonicalizes the
|
|
result to lowercase, and otherwise resolves to `local-development`.
|
|
`scripts/package-elastic-beanstalk.sh` resolves
|
|
the commit from `APP_COMMIT_SHA` → `GITHUB_SHA` → `git rev-parse HEAD`, fails
|
|
when `CI=true` cannot produce a valid 40-hex sha, and publishes with
|
|
`-p:SourceRevisionId`, `-p:InformationalVersion=shoc-backend@<sha>`,
|
|
`-p:IncludeSourceRevisionInInformationalVersion=false`,
|
|
`-p:DebugType=portable`, `-p:DebugSymbols=true`.
|
|
2. **Default tags.** `service=shoc-backend` and `app.commit=<sha | local-development>`
|
|
on `SentryOptions.DefaultTags`. All events use the same commit-addressed
|
|
`shoc-backend@<sha>` release.
|
|
3. **HTTP requests.** `SentryRequestMetadataMiddleware` runs **after**
|
|
routing/authentication and **before** authorization. It sets on the current
|
|
scope only the fields below. Non-controller endpoints omit `code.function`.
|
|
4. **Background jobs.** All six worker transaction blocks (five files) use
|
|
`SentryObservability.BeginBackgroundTransaction`, which pushes a scope, starts
|
|
the transaction, sets the scope transaction, and returns a handle with
|
|
`FinishOk` / `FinishCancelled` / `FinishError(Exception)` that cannot
|
|
double-finish. Existing status/error behavior is preserved.
|
|
5. **Last-mile privacy.** Request-body extraction is disabled. Global before-send
|
|
processors clear request data, query strings, cookies, headers, environment
|
|
values, and miscellaneous request values from both error events and
|
|
transactions, retain only an opaque user ID, and attach native trace and
|
|
transaction IDs as searchable transaction tags. Root and child span data use
|
|
an allowlist for function, operation, actor, route template, method/status,
|
|
protocol, database operation, and service host; raw URLs, query values,
|
|
network addresses, and arbitrary extras are removed.
|
|
|
|
## Field / redaction contract
|
|
|
|
Allowed request fields (template values only — never resolved route values):
|
|
|
|
| Field | Source | Rule |
|
|
| --- | --- | --- |
|
|
| `actor.type` | auth state | `authenticated` / `anonymous` / `system` |
|
|
| `operation.type` | static | `http.server` / `background_job` |
|
|
| `code.function` | `ControllerActionDescriptor` | `ControllerName.ActionName` only |
|
|
| `http.method` | request | HTTP verb |
|
|
| `http.route` | `RouteEndpoint.RoutePattern.RawText` | route template; omitted when unresolved |
|
|
| `trace_id` / `transaction_id` | active Sentry span/transaction | native Sentry ids |
|
|
| scope `User.Id` | `ClaimTypes.NameIdentifier` only | set only when authenticated |
|
|
|
|
Never intentionally sent: query strings, headers, bodies, cookies, usernames,
|
|
emails, IP addresses, route values, credentials, or token values. The application
|
|
retains stack traces, exception types/messages, safe tags, operation status, and
|
|
route templates because those are required to identify the failing function and
|
|
operation.
|
|
|
|
## Consequences
|
|
|
|
- Release health maps 1:1 to a commit sha; local builds are clearly labeled.
|
|
- One redaction contract to audit, enforced by
|
|
`SentryObservabilityTests`/`SentryPipelineContractTests`.
|
|
- ASP.NET Core request transactions and the SDK's registered outgoing HTTP
|
|
instrumentation cover inbound API calls and the platform's typed procurement
|
|
client; explicit root transactions cover every hosted worker loop.
|
|
|
|
## Alternatives considered
|
|
|
|
- Per-worker transaction setup (rejected: duplication drifted across five files).
|
|
- Sentry's default request payload with PII scrubbing (rejected: default-deny is
|
|
safer than default-capture-then-scrub).
|