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
| Entity | Role |
|---|---|
| Project | Product / business grouping; an Application's project_id ties its repos and targets together for posture rollup. |
| Application | A deployable unit - owns its targets and code repositories. |
| Target | A concrete scannable surface (a URL, a repo). |
| Assessment | One analysis run. Its kind (DAST, SAST, SCA, import…) drives the fingerprint strategy. |
| Finding | The raw atom emitted by a scanner - append-only evidence for one run. |
| Vulnerability | The 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
sourceslist), 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
- Vulnerabilities hub - the user-facing view.
- Assessments - runs and their fingerprint kinds.
- System Architecture · Scan Pipeline.