Metric · Security

What is control pass rate, and how do you measure it in Metabase?

Control pass rate is the share of monitored compliance controls currently passing their automated tests, reported per framework — SOC 2, ISO 27001, HIPAA, whichever you're certifying against. It's the day-to-day readiness number between audits. Measure it in Metabase from control tests synced from Vanta or Drata.

TL;DRpassing controls ÷ monitored controls, latest test per control, counted once per framework the control maps to. Exclude not-applicable controls from the denominator, and treat the long-failing list as the real deliverable.

What control pass rate measures

It measures how far you are from a clean audit, continuously instead of annually. Compliance platforms retest controls on a schedule, so the current state — latest test per control — is a live readiness figure, and the gap between frameworks tells you where the next certification effort goes. The companion view matters just as much: which controls have been failing longest, and who owns them. A pass rate without an owner column is a status report; with one, it's a work queue.

What data does it need?

  • A control_tests table: control_id, status (pass/fail/not_applicable), tested_at.
  • A control_framework_map table, since one control routinely maps to several frameworks.
  • A controls table with name and owner, so failures land on someone's desk.
  • Daily snapshots of per-control status if you want a trend — the tests table only proves the present.

SQL patterns

Pass rate by framework (latest test per control)PostgreSQL
WITH latest AS (
  -- one row per control: its most recent test result
  SELECT DISTINCT ON (control_id)
    control_id,
    status,
    tested_at
  FROM control_tests
  ORDER BY control_id, tested_at DESC
)
SELECT
  m.framework,
  COUNT(*) AS monitored_controls,
  COUNT(*) FILTER (WHERE l.status = 'pass') AS passing,
  ROUND(
    100.0 * COUNT(*) FILTER (WHERE l.status = 'pass')
    / NULLIF(COUNT(*), 0), 1
  ) AS pass_rate_pct
FROM latest l
JOIN control_framework_map m ON m.control_id = l.control_id
WHERE l.status <> 'not_applicable'
GROUP BY m.framework
ORDER BY pass_rate_pct;
Controls failing for more than 14 days, with ownerPostgreSQL
WITH latest AS (
  SELECT DISTINCT ON (control_id)
    control_id,
    status
  FROM control_tests
  ORDER BY control_id, tested_at DESC
),
last_pass AS (
  SELECT control_id, MAX(tested_at) AS last_passed_at
  FROM control_tests
  WHERE status = 'pass'
  GROUP BY control_id
)
SELECT
  c.name AS control,
  c.owner,
  lp.last_passed_at::date AS last_passed,
  CURRENT_DATE
    - COALESCE(lp.last_passed_at, c.monitoring_started_at)::date
    AS days_failing
FROM latest l
JOIN controls c ON c.id = l.control_id
LEFT JOIN last_pass lp ON lp.control_id = l.control_id
WHERE l.status = 'fail'
  AND COALESCE(lp.last_passed_at, c.monitoring_started_at)
      < CURRENT_DATE - INTERVAL '14 days'
ORDER BY days_failing DESC;

Pitfalls

Averaging across frameworks.→ A control can map to SOC 2, ISO 27001, and HIPAA at once, and each framework has its own denominator. Count per framework through the mapping table — a blended average answers no question an auditor asks.
No daily snapshots, so no trend.→ The tests table shows today's state; whether posture is improving or a control flapped all quarter is invisible without history. Snapshot per-control status daily from the start.
Counting not-applicable controls in the denominator.→ N/A controls are scoping decisions, not failures — leaving them in deflates the rate and buries real failures in noise. Filter them out, and review the N/A list separately so scoping doesn't become a dumping ground.
Treating a passing automated test as audit evidence.→ A test proves a configuration at a moment; an audit wants the control operating over the whole period. Sustained passing in the snapshot history is the evidence — the point-in-time green check is just the start.

Where this metric applies

Metrics

Dashboards

FAQ

Why use only the latest test per control?
Because compliance platforms retest continuously, and averaging over all test runs turns the metric into a history lesson. A control that failed for a month and was fixed yesterday is passing — that's what the auditor will see. Use DISTINCT ON (control_id) ... ORDER BY tested_at DESC (or a row_number() window) to collapse to the current state, and keep the history for the failing-duration view instead.
Why report pass rate per framework rather than one number?
Because a single control commonly maps to several frameworks — one broken access-review control can be a SOC 2 finding and an ISO 27001 finding at once, and each framework has a different denominator. Join through the control-to-framework mapping that Vanta and Drata both expose, and count the control once per framework it maps to. One blended average answers no question an auditor will ever ask.
Is a passing automated test the same as audit evidence?
No. An automated test confirms a configuration at a point in time; an audit wants evidence the control operated over the whole period — which is exactly why daily snapshots matter. A control flapping between pass and fail all quarter can show 100% on audit day. Snapshot per-control status daily, trend it on a compliance posture dashboard, and treat sustained passing as the goal, not the point-in-time check.
How do you calculate control pass rate?
Divide passing controls by monitored controls, using the latest test result per control: COUNT(passing) / COUNT(monitored), grouped by framework. Exclude controls marked not-applicable from the denominator — they're scoping decisions, not failures — and count each control once per framework it maps to, since mappings overlap.
How do you track control pass rate in Metabase?
Sync control tests and framework mappings from Vanta or Drata into control_tests and control_framework_map tables. Build the per-framework pass rate from the latest test per control, keep the controls-failing-14-plus-days list with owners as the standing work queue, and snapshot daily so the trend exists before the audit does — alongside MFA adoption and the rest of your security analytics.