Skip to main content

Unified Data Model

apPosture is a DefectDojo-style aggregator: every scanner - first-party or imported - emits raw Findings, and findings that describe the same underlying issue collapse into a single, deduplicated Vulnerability with its own lifecycle. This is what lets one screen show "147 findings → 38 real vulnerabilities" across DAST, SAST, SCA, containers, IaC, secrets and Kubernetes.

Core entities

EntityRole
ProjectProduct / business grouping; an Application's project_id ties its repos and targets together for posture rollup.
ApplicationA deployable unit - owns its targets and code repositories.
TargetA concrete scannable surface (a URL, a repo).
AssessmentOne analysis run. Its kind (DAST, SAST, SCA, import…) drives the fingerprint strategy.
FindingThe raw atom emitted by a scanner - append-only evidence for one run.
VulnerabilityThe deduplicated, stateful issue: all findings sharing a fingerprint collapse into exactly one.

Finding: the raw atom

A Finding is intentionally rich so any source can map into it. Key fields:

  • Provenance - source (apposture / imported), tool (the concrete scanner: nuclei, trivy, snyk, …), scan_id / assessment_id.
  • Locator - url, method, parameter, file_path, line, component / component_version (for dependency issues).
  • Classification - severity, confidence, cwe_id, cve_id, wasc_id.
  • Proof - verified, proof, exploit_status (not_tested / confirmed / likely / not_exploitable), exploit_evidence.
  • AI enrichment - ai_confirmed, ai_false_positive, ai_severity, ai_business_impact, ai_fix_suggestion.
  • Reachability - reachable (e.g. SCA call-path reachability).

cve_id is what drives live KEV/EPSS enrichment; tool is what populates a Vulnerability's list of corroborating sources.

Deduplication: findings → vulnerabilities

Each finding produces a source-aware fingerprint. The strategy depends on the assessment kind so that, for example, two DAST hits on the same rule+location merge, while an SCA issue keys on package + advisory. Findings with a matching fingerprint attach to the same Vulnerability (which holds fingerprint unique + fingerprint_version).

Benefits of collapsing at the fingerprint:

  • One issue, many proofs - a single Vulnerability can be corroborated by several tools (its sources list), which raises confidence.
  • Stable lifecycle - triage state, risk acceptance and SLA clocks live on the Vulnerability, so they survive re-scans instead of resetting per run.
  • Honest counts - dashboards and reports count vulnerabilities, not duplicated findings.

Lifecycle & status

A Vulnerability carries status across assessments. Re-running an assessment reconciles the new findings against existing vulnerabilities: still-present → stays open, gone → moves toward fixed, brand-new → opened.

Lifecycle transitions are recorded as VulnerabilityEvents, giving an audit trail of when an issue opened, was triaged, accepted or fixed. Risk acceptance, SLA policy and the Priorities funnel all read from this layer.

How modules plug in

Because everything funnels through the same Finding → Vulnerability spine, a newly added scanner (such as Kubernetes Posture) gains dedup, lifecycle, prioritization, attack-chain correlation, compliance mapping and reporting for free - it only has to emit findings.

Next