Skip to content

Compliance Posture

The posture dashboard summarises your organization's container security health in five top-line KPIs. Every value is computed live from the underlying scan, triage, and attestation tables — there is no caching, so the page always reflects the current state.

Findings covered by an active attestation are excluded from every metric below.

KPIs

Scan coverage

coverage = scannedTags / totalTags

scannedTags is the count of image tags with at least one scan; totalTags is the count of tags discovered across all connected registries. The dashboard also shows outdatedCount — tags whose most-recent scan is older than freshnessThresholdDays (default 30). When outdatedCount > 0 the coverage tile turns yellow even if the percentage is high.

A per-registry breakdown is included so you can spot a single registry pulling the average down.

MTTR (mean time to remediate)

mttr = avg(remediatedAt - detectedAt)  for vulns with timeline.remediatedAt set

Reported in days, broken down by severity (mttrBySeverity). The dashboard also surfaces the most-recently-resolved vulns with their individual remediation times.

If no vulnerabilities have been remediated yet, MTTR shows N/A rather than zero.

SLA compliance

Computed only over Critical and High vulnerabilities that have an slaDeadline set:

slaCompliance = (withDeadline - breached) / withDeadline * 100

A vulnerability counts as breached when triage.status == OPEN and the deadline is in the past. If no vulnerabilities have deadlines, the tile shows N/A and an "SLA not configured" note. See SLA Policy for the default deadlines (Critical 1d / High 3d / Medium 7d / Low 14d).

Open exceptions

Counts active exceptions (triage.exception is set) and surfaces those expiring within 3 days, with the date of the next review.

Risk score

A weighted aggregate over open vulns:

sevWeights      = { CRITICAL: 10, HIGH: 5, MEDIUM: 2, LOW: 1 }
vulnScore       = sum(sevWeights[v.severity])  capped at 60
breachPenalty   = min(25, breachedCount * 8)
coverageGap     = round((100 - coveragePercent) / 100 * 15)
riskScore       = min(100, vulnScore + breachPenalty + coverageGap)

The score is a 0–100 number where lower is better. Alongside it the dashboard shows a letter grade derived only from severity counts:

Open CriticalOpen HighGrade
≥ 1D
0> 3C
01–3B
00A

Other panels

  • Worst images — the five images with the highest critical * 100 + high weighted count.
  • Severity countssevCounts for Critical/High/Medium/Low, used by report sections.
  • Fixable count — open findings where a fixedVersion is published — the immediately actionable backlog.

API

curl -H "Authorization: Bearer $HG_API_KEY" \
  "https://harborguard.co/api/reports/posture"

Returns the same posture object the dashboard renders. A companion endpoint, GET /api/reports/sla, returns a per-vulnerability SLA tracker plus a 13-week detected/remediated/open lifecycle series for trend visualisation.

See also

On this page