# Production monitoring or alerting is configured with repo-visible evidence

- **Pattern:** `ab-002636` (`soc2-readiness.incident-and-recovery.monitoring-and-alerting-configured`)
- **Severity:** high
- **Lifecycle:** active
- **Last modified:** 2026-07-03
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002636
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002636)

## Why it matters

SOC 2 CC7.2 requires the entity to monitor system components for anomalies indicative of malicious acts and errors, and availability monitoring is the same evidence an auditor pulls for A1.1: "show me what watches production and who gets paged" is a standard request in the incident-management section. AI-generated and vibe-coded apps fail this reliably because monitoring is an operations habit, not a code prompt: coding assistants scaffold the app, the deploy config, even a `/api/health` endpoint, but nothing ever watches that endpoint, so the first signal of an outage or an anomaly is a customer complaint. Detection time drives incident impact and, for a Type II report, an unmonitored production service means there is no anomaly-detection evidence to sample at all. One passing leg of this check is an evidence-pointer: dashboard-configured monitors (UptimeRobot, Better Stack, Vercel alerts set in the web UI) are invisible to a repo audit, so a committed ops doc naming the monitoring provider and what it watches counts as the evidence, which is exactly the artifact an auditor will ask for. Note the relationship to this audit's health-check-endpoint check: that check verifies the probe surface exists; this check verifies something is actually watching it.

## Severity rationale

High because an unwatched production service turns every outage and anomaly into a customer-reported incident, stretching detection time from minutes to hours or days, and leaves zero CC7.2 anomaly-detection evidence for the audit window; it is not critical because the gap enables slow response rather than direct exploitation.

## Remediation

Pick the cheapest leg that fits your stack. For a Vercel/Next.js app with a health endpoint, a scheduled GitHub Actions synthetic check is a 10-line commit at `.github/workflows/uptime.yml`:

```yaml
on:
  schedule:
    - cron: '*/15 * * * *'
jobs:
  probe:
    runs-on: ubuntu-latest
    steps:
      - run: curl --fail --max-time 10 https://yourapp.com/api/health
```

A failing run emails the repo owners, which is a real (if minimal) alert path. Alternatives: an Upptime repo config (`.upptimerc.yml` with your production URLs), a Checkly config (`checkly.config.ts` plus `__checks__/`), Prometheus Alertmanager rules, or Terraform monitor/alarm resources (`aws_cloudwatch_metric_alarm`, `google_monitoring_alert_policy`, `pagerduty_service`). If your monitoring genuinely lives in a dashboard (UptimeRobot, Better Stack web UI), commit an ops note at `docs/ops/monitoring.md` naming the provider, the monitored URLs or metrics, and where alerts go: that committed note is the evidence a SOC 2 auditor asks for under CC7.2.

## Detection

- **ID:** `monitoring-and-alerting-configured`
- **Severity:** `high`
- **What to look for:** First determine whether the project is production-bound: deploy config (`vercel.json`, `netlify.toml`, `fly.toml`, `render.yaml`, `railway.json`, `Procfile`, `app.yaml`, a `Dockerfile` paired with a CI deploy step), CI deploy workflows (`.github/workflows/*.yml` running `vercel`, `flyctl deploy`, `gcloud run deploy`, `eb deploy`), IaC directories (`*.tf`, `serverless.yml`, `cdk.json`), or docs naming a production URL. If not production-bound, skip. If production-bound, look for ANY of these five monitoring legs (config surfaces are language-agnostic; the same paths apply to Python and Go repos): (a) uptime monitor as code: `.upptimerc.yml` (Upptime), `checkly.config.ts`/`checkly.config.js` or `__checks__/**/*.check.ts` (Checkly), Terraform monitor resources (`betteruptime_monitor`, `datadog_monitor`, `newrelic_synthetics_*`, `uptimerobot_monitor`, `pingdom_check`, `grafana_synthetic_monitoring_check`); (b) scheduled synthetic checks: a CI workflow with a `schedule:` cron whose steps `curl`/`wget`/`fetch` a production URL (or a scheduled job in `.gitlab-ci.yml`); (c) alerting config: `alertmanager.yml` or Prometheus rule files containing `alert:` definitions, Terraform `pagerduty_*` or `opsgenie_*` resources, Sentry alert rules as code (`sentry_issue_alert`/`sentry_metric_alert` Terraform resources or an exported alert-rules file); (d) platform monitoring in IaC: `aws_cloudwatch_metric_alarm`, `google_monitoring_alert_policy`, `azurerm_monitor_metric_alert`; (e) evidence-pointer leg: a committed ops doc (`docs/ops/**`, `docs/monitoring.md`, `runbooks/**`, `SECURITY.md`, `README.md` ops section) naming the monitoring provider AND what is monitored (URLs, endpoints, or metrics). This audit's `health-check-endpoint` check covers the probe surface itself; this check is about whether anything is watching it.
- **Pass criteria:** Production-bound AND at least one leg (a)-(e) is present with real content: a monitor resource or upptime/checkly config that names at least one non-localhost target URL; a cron workflow whose request hits a non-localhost production URL; an alerting config with at least one concrete alert rule or receiver/route; an IaC alarm/policy resource with a target metric; or an ops doc naming both the provider (e.g. UptimeRobot, Better Stack, Grafana Cloud) and the monitored targets. A pass on leg (e) alone is a pass with a note in the receipt that the evidence is documentation, not config.
- **Fail criteria:** Production-bound and none of the five legs holds. Fail the sneaky variants too: an observability SDK installed or initialized (`@sentry/nextjs`, `dd-trace`, `prom-client` in `package.json`) with no alert rules anywhere (error capture is not alerting); a workflow whose `schedule:` block is commented out, or whose probe curls `localhost` or `127.0.0.1`; an `.upptimerc.yml` or `__checks__/` directory with an empty or placeholder `sites`/checks list; Terraform monitor resources that are commented out or live only under `examples/`; an ops doc that says "we monitor uptime" without naming a provider or any target.
- **Skip (N/A) when:** The project is not production-bound (no deploy config, no CI deploy step, no IaC, no production URL in docs): a library, CLI tool, or not-yet-deployed scaffold has nothing to monitor. Quote: `"No deploy config, CI deploy workflow, IaC, or documented production URL; project is not production-bound, nothing to monitor"`.
- **Before evaluating, quote:** On pass, quote the file path plus the 1-3 lines showing the monitored target, alert rule, or (for the doc leg) the provider and target sentence. On fail, quote the evidence that the project is production-bound (e.g. the `vercel.json` path or the deploy step in `.github/workflows/deploy.yml`) and name the monitoring surfaces searched. Never pass from a dependency name or a directory name alone; the target/rule/provider line itself must be excerpted.
- **Report even on pass:** `"Monitoring evidence: <leg a-e> at <path>, watching <target/metric>; alert path: <receiver/CI-failure-email/doc-stated or 'not visible in repo'>"`.
- **Detail on fail:** `"vercel.json and a production deploy workflow present, but no monitor-as-code, scheduled synthetic check, alerting config, or ops doc naming a monitoring provider found in .github/workflows/, terraform, docs/, or runbooks/. Monitors configured in a web dashboard are invisible here; commit an ops note naming your monitoring provider and targets."` or `".github/workflows/uptime.yml exists but its schedule: block is commented out and the probe curls http://localhost:3000/api/health; no other monitoring evidence committed. Commit an ops note naming your monitoring provider and targets, or fix the workflow to probe the production URL."`
- **Remediation:** Cheapest real fix: a scheduled GitHub Actions probe at `.github/workflows/uptime.yml` (`schedule: cron '*/15 * * * *'` plus `curl --fail https://yourapp.com/api/health`; a failed run emails repo owners). Alternatives: `.upptimerc.yml`, `checkly.config.ts`, Alertmanager rules, or Terraform alarm resources. If monitoring lives in a dashboard, commit `docs/ops/monitoring.md` naming provider, targets, and alert destination. Deeper logging and alerting coverage lives in the `saas-logging` audit.

## External references

- soc2 CC7.2
- iso-27001 A.8.16
- nist SI-4

Taxons: observability, operational-readiness

HTML version: https://auditbuffet.com/patterns/ab-002636
