diff --git a/confluence/00-engineering-standards.md b/confluence/00-engineering-standards.md index 3d36c04..bd73004 100644 --- a/confluence/00-engineering-standards.md +++ b/confluence/00-engineering-standards.md @@ -13,6 +13,7 @@ These pages describe how we build, review, and ship software at Sea Haven Indust | Secrets and Configuration | Where sensitive and non-sensitive values live | | AWS Infrastructure | Infrastructure as code, Lambda defaults, tagging | | CI/CD and Deployments | Pipelines, environments, releases, and rollback | +| Sentry | Error monitoring, logs, tracing, metrics, and privacy rules | ## Core rules @@ -20,11 +21,11 @@ If you read nothing else, follow these: 1. Use kebab-case for every name. 2. Never commit to `main` directly. Every change goes through a pull request. -3. Every PR title ends with its Jira key, for example `feat(api): add receipt search (DEV-123)`. +3. PR title should end with its Jira key, for example `feat(api): add receipt search (DEV-123)`. 4. Never put secrets in code, environment variables, `.env` files in git, tickets, chat, or wiki pages. -5. Every AWS resource is created by infrastructure as code. Nothing is built by hand in the console. +5. AWS resources are created by infrastructure as code. Nothing is built by hand in the console. 6. Nobody deploys from a laptop. The pipeline deploys. ## Questions and changes -Ask your Sea Haven point of contact. To propose a change to these standards, open a Jira ticket in the matching project (see Issue Tracking). +Ask your technical point of contact. To propose a change to these standards, open a Jira ticket in the matching project (see Issue Tracking). diff --git a/confluence/05-secrets-and-configuration.md b/confluence/05-secrets-and-configuration.md index 4fbbb03..1b1dae9 100644 --- a/confluence/05-secrets-and-configuration.md +++ b/confluence/05-secrets-and-configuration.md @@ -61,4 +61,4 @@ def handler(event, context): - Share credentials in Jira, Confluence, Slack, email, or any other plain-text tool. - Hardcode account IDs, ARNs, or resource names that belong in configuration. -If a secret is committed or exposed by mistake, tell your Sea Haven contact immediately so it can be rotated. Deleting the commit is not enough. +If a secret is committed or exposed by mistake, tell your technical point of contact immediately so it can be rotated. Deleting the commit is not enough. diff --git a/confluence/07-ci-cd-and-deployments.md b/confluence/07-ci-cd-and-deployments.md index 773f4a9..26b6c5f 100644 --- a/confluence/07-ci-cd-and-deployments.md +++ b/confluence/07-ci-cd-and-deployments.md @@ -66,4 +66,4 @@ A green workflow run is not proof of a working deploy. Check the live system: he ## Repository settings -Sea Haven manages repository settings, branch protection, secret scanning, and Dependabot alerts. If a setting blocks your work, raise it with your Sea Haven contact rather than working around it. +Sea Haven manages repository settings, branch protection, secret scanning, and Dependabot alerts. If a setting blocks your work, raise it with your technical point of contact rather than working around it. diff --git a/confluence/08-sentry.md b/confluence/08-sentry.md new file mode 100644 index 0000000..decfd14 --- /dev/null +++ b/confluence/08-sentry.md @@ -0,0 +1,74 @@ +# Sentry + +Sentry is our observability platform. Errors, logs, traces, and application metrics from every deployable go to Sentry. + +## Projects + +- One Sentry project per deployable. A frontend and its backend are separate projects. +- Name the project after the deployable, in kebab-case, for example `expense-approval-bot` and `expense-approval-bot-api`. +- Sea Haven creates projects and DSNs. Ask your technical point of contact for access. + +## SDKs + +| Deployable | SDK | +|---|---| +| Python Lambda | `sentry-sdk` with `AwsLambdaIntegration(timeout_warning=True)` | +| Node.js Lambda | `@sentry/aws-serverless`, with every handler wrapped in `Sentry.wrapHandler` | +| React SPA | `@sentry/react`, with `Sentry.ErrorBoundary` around the app | + +Initialize Sentry once in a shared module that every handler imports, not separately in each function. + +## Configuration + +- The DSN comes from configuration for each environment. Never hardcode or commit it. +- When the DSN is empty, the SDK does nothing. Local runs, unit tests, and CI run with no DSN and make no calls to Sentry. +- Set `environment` to the deploy environment (`dev` or `prod`), taken from the pipeline, not from a hand-set variable. +- Set `release` to the commit SHA, added at build time in the pipeline. +- The Sentry auth token used to upload source maps is a secret. It lives in GitHub Environment secrets. + +## What to send + +| Signal | Standard | +|---|---| +| Errors | Unhandled exceptions and failed calls to external services. Tag them with `route`, `upstream`, and a correlation ID where they apply. | +| Logs | `enable_logs=True` (Python) or `enableLogs: true` (JavaScript). Send existing INFO-level and higher logs to Sentry Logs. | +| Tracing | Trace incoming requests and add spans for external calls and database access. Sample 100% in dev; in prod, sample 20% for user-facing apps, or 100% for low-volume jobs. | +| Metrics | Count business outcomes, such as requests created, upstream errors, and cache hits, and record latency distributions. | +| Session replay | Frontends only. Mask all text and inputs and block all media. Sample 10% of sessions in prod, and 100% of sessions that hit an error. | + +Do not report user-input 4xx responses as errors. Do not report business alerts that still return success as errors. + +## Privacy + +This section is mandatory. Sentry must never receive personal data, secrets, or request payloads. + +- Set `send_default_pii=False` (Python) or `sendDefaultPii: false` (JavaScript). +- Turn off stack-frame local variables (`include_local_variables=False`) and request bodies (`max_request_body_size="never"`). +- Scrub in every hook: `before_send`, `before_send_transaction`, `before_send_log`, and `before_send_metric`. +- Always strip `Authorization`, `Cookie`, and `Set-Cookie` headers, tokens, API keys, and query strings on authentication routes. +- Never send SSNs, legal IDs, or other personal identifiers in events, logs, traces, or metric attributes. Never use an email address as a metric attribute. +- Replay network capture records URL, status, and timing only. No request or response bodies. + +Write unit tests that prove the scrubbing hooks drop these fields. + +## Source maps + +- The release workflow uploads source maps to Sentry, tagged with the release SHA. +- Do not deploy source maps to the public hosting bucket. + +## Alerts and dashboards + +- Every project has alerts for new issues and regressions, plus metric alerts for error rate and p95 latency, for each environment. Alerts go to the team's Slack alerts channel. +- Build dashboards in Sentry. Do not build CloudWatch dashboards, CloudWatch custom metrics, or X-Ray tracing for new work. +- Lambda log groups still exist, with 60-day retention, but nothing new is built on top of them. + +## Definition of done + +A new deployable is not production-ready until: + +- [ ] A forced error in dev shows in Sentry with `environment`, `release`, and a readable stack trace +- [ ] Logs for a request appear in Sentry and link to its trace +- [ ] The scrubbing tests pass, and captured dev events contain no headers, tokens, or personal data +- [ ] Local runs and CI make no Sentry calls +- [ ] Alerts fire to Slack for a test issue +- [ ] The README documents the Sentry project, sampling rates, and what is scrubbed diff --git a/confluence/README.md b/confluence/README.md index 8ca1003..26eab14 100644 --- a/confluence/README.md +++ b/confluence/README.md @@ -23,6 +23,7 @@ This README is internal. Do not publish it. | `05-secrets-and-configuration.md` | `secrets-and-config.md` | | `06-aws-infrastructure.md` | `aws-infrastructure.md`, `terraform-project-layout.md` | | `07-ci-cd-and-deployments.md` | `cicd.md`, `github-standards.md` | +| `08-sentry.md` | Jira IP-24 and PLAT-174 (the handbook has no Sentry page) | ## Deliberately excluded