Skip to content

Commit a7765b9

Browse files
committed
add Vulnerability Triage Engine reference documentation
Signed-off-by: tdruez <tdruez@aboutcode.org>
1 parent 3db2dff commit a7765b9

1 file changed

Lines changed: 340 additions & 0 deletions

File tree

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
.. _reference_vulnerability_triage:
2+
3+
Vulnerability Triage Engine
4+
===========================
5+
6+
DejaCode includes a **Vulnerability Triage Engine** that evaluates configurable
7+
detection rules against your product inventory and recommends a remediation action for
8+
each matched vulnerability. It provides a structured way to prioritize, track, and act
9+
on vulnerability exposure across your products.
10+
11+
When a ruleset fires, DejaCode creates a **triage record** linking the vulnerability to
12+
the product and the ruleset that detected it. The record carries the recommended action,
13+
the detection date, the last evaluation date, and an optional link to a DejaCode request
14+
opened automatically by the engine.
15+
16+
Rulesets are **disabled by default**. Each dataspace creates and configures the rulesets
17+
that are relevant to its security program via the **Admin** interface.
18+
19+
1. Built-in Rules
20+
-----------------
21+
22+
Seven rules are available out of the box. Each rule implements a specific detection
23+
condition evaluated against the vulnerabilities known to affect the product's packages.
24+
25+
.. list-table::
26+
:header-rows: 1
27+
:widths: 28 72
28+
29+
* - Label
30+
- Description
31+
* - | **Risk Score**
32+
| ``risk_score``
33+
- Detects vulnerabilities whose risk score is at or above the configured threshold.
34+
* - | **Weighted Risk**
35+
| ``weighted_risk``
36+
- Detects vulnerabilities affecting at least one package whose weighted risk score
37+
meets the configured threshold. The weighted risk score combines the vulnerability
38+
risk with the package's exposure level in the product.
39+
* - | **Exploited Vulnerability**
40+
| ``exploited_vulnerability``
41+
- Detects vulnerabilities for which a known active exploit is available
42+
(exploitability value equals 2.0).
43+
* - | **Reachable Vulnerability**
44+
| ``reachable_vulnerability``
45+
- Detects vulnerabilities confirmed as reachable in the product context: at least
46+
one VulnerabilityAnalysis record for this vulnerability has ``is_reachable`` set
47+
to true.
48+
* - | **Unresolved Vulnerability**
49+
| ``unresolved_vulnerability``
50+
- Detects vulnerabilities affecting the product where at least one package has no
51+
completed triage analysis (i.e., no analysis in a terminal state: resolved,
52+
resolved_with_pedigree, or not_affected).
53+
* - | **Stale Vulnerability**
54+
| ``stale_vulnerability``
55+
- Detects high-risk vulnerabilities that have remained unaddressed beyond the
56+
configured number of days. Considers only vulnerabilities whose risk score meets
57+
or exceeds the configured minimum.
58+
* - | **Dev-Only Vulnerable Package**
59+
| ``dev_only_vulnerable_package``
60+
- Detects vulnerabilities that exclusively affect packages marked as non-deployed
61+
in the product, indicating a lower exposure risk.
62+
63+
.. seealso::
64+
Refer to :ref:`reference_vulnerability_management` for background on vulnerability
65+
fields such as risk score and exploitability.
66+
67+
1.1 Rule Parameters
68+
^^^^^^^^^^^^^^^^^^^
69+
70+
The following parameters are supported by rules that accept them:
71+
72+
**Risk Score** (``risk_score``)
73+
74+
- ``min_risk_score`` (float, 0.0-10.0): only flag vulnerabilities whose risk score is
75+
greater than or equal to this value. Defaults to ``8.0``.
76+
77+
**Weighted Risk** (``weighted_risk``)
78+
79+
- ``min_weighted_risk_score`` (float, 0.0-10.0): only flag vulnerabilities affecting a
80+
package whose weighted risk score is greater than or equal to this value. Defaults to
81+
``8.0``.
82+
83+
**Stale Vulnerability** (``stale_vulnerability``)
84+
85+
- ``max_days`` (integer, min 1): maximum number of days a high-risk vulnerability may
86+
remain without a completed analysis before it is flagged. Defaults to ``30``.
87+
- ``min_risk_score`` (float, 0.0-10.0): only consider vulnerabilities whose risk score
88+
is greater than or equal to this value. Defaults to ``8.0``.
89+
90+
2. Triage Actions
91+
-----------------
92+
93+
Each ruleset recommends a single remediation action. The action is stored on every
94+
triage record created by that ruleset and displayed in the **Recommendation** column
95+
of the product Vulnerabilities tab.
96+
97+
.. list-table::
98+
:header-rows: 1
99+
100+
* - Action
101+
- Label
102+
* - ``upgrade``
103+
- Upgrade Package
104+
* - ``apply_patch``
105+
- Apply Patch
106+
* - ``forensic_analysis``
107+
- Forensic Analysis
108+
* - ``reachability_analysis``
109+
- Reachability Analysis
110+
* - ``change_config``
111+
- Change Configuration
112+
* - ``replace_package``
113+
- Replace Package
114+
* - ``notify``
115+
- Notify
116+
* - ``create_request``
117+
- Create DejaCode Request
118+
119+
3. Triage Record Lifecycle
120+
--------------------------
121+
122+
A **triage record** is created per (vulnerability, product, ruleset) combination the
123+
first time a ruleset evaluation matches a vulnerability. Its lifecycle follows these
124+
states:
125+
126+
- **Detected**: the record is created the first time the ruleset fires for the
127+
vulnerability. ``detected_date`` is set at this point and never changes on subsequent
128+
evaluations.
129+
- **Active**: the record is updated in place on each subsequent evaluation as long as
130+
the vulnerability still matches any active rule in the ruleset. ``last_checked`` is
131+
updated on every run.
132+
- **Deleted**: when a vulnerability no longer matches any rule in the ruleset, its
133+
triage record is deleted. Any preset-applied analysis for that vulnerability is also
134+
removed. If the conditions recur later, a new record is created with a fresh
135+
``detected_date``.
136+
137+
Only **active** triage records appear in the product Vulnerabilities tab.
138+
139+
4. Configuration
140+
----------------
141+
142+
The triage engine is configured through **Triage Rulesets** in the Admin interface
143+
under :guilabel:`Vulnerabilities > Triage Rulesets`.
144+
145+
.. seealso::
146+
For step-by-step instructions on creating and configuring rulesets through the Admin
147+
UI, refer to :ref:`how_to_7`.
148+
149+
4.1 Triage Ruleset
150+
^^^^^^^^^^^^^^^^^^
151+
152+
Each ruleset combines one or more detection rules with a single recommended action:
153+
154+
.. list-table::
155+
:header-rows: 1
156+
157+
* - Field
158+
- Description
159+
* - **Name**
160+
- A descriptive name for the ruleset (e.g., "Critical Vulnerabilities").
161+
* - **Action**
162+
- The remediation action to recommend when the ruleset fires.
163+
* - **Precedence**
164+
- Integer controlling priority when multiple rulesets match the same vulnerability
165+
for the same product. The ruleset with the highest precedence value wins and its
166+
triage record is displayed. Unique per dataspace, so ties cannot occur.
167+
* - **Enabled**
168+
- When unchecked, the ruleset is excluded from all evaluations and its existing
169+
triage records are deleted immediately. Any preset-applied analysis is left in
170+
place: only the tracking record is removed, not the analysis itself.
171+
* - **Analysis Preset**
172+
- Optional. An AnalysisPreset whose default values are applied automatically to
173+
each matched vulnerability (see section 4.2).
174+
* - **Request Template**
175+
- Optional. A RequestTemplate of content type Product used to open a DejaCode
176+
request automatically for each new triage record (see section 4.3).
177+
178+
4.2 Analysis Preset
179+
^^^^^^^^^^^^^^^^^^^
180+
181+
An **Analysis Preset** defines default vulnerability analysis values that the engine
182+
applies automatically to each (product_package, vulnerability) pair matched by the
183+
ruleset.
184+
185+
.. list-table::
186+
:header-rows: 1
187+
188+
* - Field
189+
- Description
190+
* - **State**
191+
- Default analysis state (e.g., ``in_triage``).
192+
* - **Justification**
193+
- Default justification value.
194+
* - **Responses**
195+
- Default response values (multiple choice).
196+
* - **Detail**
197+
- Default free-text detail.
198+
* - **Is Reachable**
199+
- Default reachability flag (true/false/unknown).
200+
201+
Only non-blank preset fields are applied to each analysis. User-owned analyses (those
202+
not created by a preset) are never overwritten. When a user edits an auto-applied
203+
analysis, it becomes user-owned and the engine will not modify it again.
204+
205+
Analysis Presets are managed in the Admin interface under
206+
:guilabel:`Vulnerabilities > Analysis Presets`.
207+
208+
4.3 Request Template
209+
^^^^^^^^^^^^^^^^^^^^
210+
211+
When a **Request Template** is assigned to a ruleset, the engine automatically opens
212+
one DejaCode request per new triage record using the template's title and content as
213+
defaults.
214+
215+
Key behaviors:
216+
217+
- The template must be of content type **Product**.
218+
- The engine uses the request template's creator as the requester. A request template
219+
with no creator cannot be selected on a ruleset: this is validated when the ruleset
220+
is saved, both in the Admin and through the REST API.
221+
- The request is linked to the triage record. Users can navigate to it directly from
222+
the Recommendation column in the Vulnerabilities tab.
223+
- Requests are created once per triage record. Re-evaluation does not open additional
224+
requests for an existing record.
225+
226+
4.4 Seeding Reference Rulesets
227+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
228+
229+
A set of reference rulesets and analysis presets, covering common scenarios (critical
230+
exploited vulnerabilities, reachable vulnerabilities, stale vulnerabilities, dev-only
231+
packages, and more) can be seeded into a dataspace with the ``create_triage_rulesets``
232+
management command::
233+
234+
./manage.py create_triage_rulesets <dataspace_name>
235+
236+
The command refuses to run if the dataspace already has triage rulesets. Pass
237+
``--reset`` to delete all existing rulesets and presets in the dataspace first and
238+
recreate them from scratch; you will be prompted for confirmation unless ``--noinput``
239+
is also passed. Resetting removes every product's ruleset assignments, which must be
240+
redone manually afterward.
241+
242+
5. Evaluation
243+
-------------
244+
245+
5.1 Automatic Evaluation
246+
^^^^^^^^^^^^^^^^^^^^^^^^^
247+
248+
The engine re-evaluates a product's assigned rulesets automatically and immediately
249+
whenever any of the following changes occur, so results are reflected on the very next
250+
page reload without any manual action:
251+
252+
- A **ruleset** already assigned to one or more products is edited and saved, from the
253+
Admin interface or through the REST API: every assigned product is re-evaluated.
254+
- A **ruleset is assigned to or unassigned from** a product, from the product
255+
Vulnerabilities tab or through the REST API.
256+
- A **package is added to or removed from** a product.
257+
- A **VulnerabilityAnalysis** record for a package in the product is saved or deleted.
258+
259+
.. note::
260+
Bulk operations (importing a CSV of packages, importing a ScanCode.io scan, or
261+
cloning a product) evaluate each affected product once in the background after the
262+
import completes, instead of once per imported row. Results may take a short moment
263+
to appear after a large bulk import.
264+
265+
5.2 Manual Re-evaluation
266+
^^^^^^^^^^^^^^^^^^^^^^^^^
267+
268+
A full re-evaluation of every enabled ruleset against every product in a dataspace can
269+
be triggered from the command line::
270+
271+
./manage.py evaluate_triage <dataspace_name>
272+
273+
This is intended for scheduled runs or recovery after data changes.
274+
275+
6. Vulnerabilities Tab
276+
----------------------
277+
278+
The **Vulnerabilities** tab on each product detail page provides a per-vulnerability
279+
view of the product's affected packages. When at least one enabled ruleset is assigned
280+
to the product, a **Recommendation** column appears. A link to open the
281+
:guilabel:`Manage Triage Rulesets` panel is available from the tab's navigation bar for
282+
users with change permission on the product.
283+
284+
For each vulnerability row, the Recommendation cell shows:
285+
286+
- The recommended **action** (colored badge).
287+
- The **ruleset name** that produced the recommendation.
288+
- The **detection date** (Since).
289+
- A link to the **associated request**, if one was opened automatically.
290+
291+
When multiple rulesets are assigned and their rules overlap on the same vulnerability,
292+
only the record from the highest-precedence ruleset is displayed.
293+
294+
Hovering the info icon next to a vulnerability ID shows a popover with its aliases,
295+
summary, exploitability, and risk score.
296+
297+
Vulnerability analysis values (state, justification, responses, reachability) are
298+
shown in adjacent columns and can be edited inline via the edit icon. When an analysis
299+
was auto-applied by a preset, an "Auto-applied" indicator with the preset name is shown
300+
in place of the usual last-modified-by information.
301+
302+
The table can be filtered by **Triage action**, **Analysis state**, **Justification**,
303+
**Responses**, and **Reachability**.
304+
305+
7. REST API
306+
-----------
307+
308+
A product's active triage recommendations are accessible via the REST API at::
309+
310+
GET /api/v2/products/{uuid}/triage_records/
311+
312+
The response is a list of active recommendations, one entry per vulnerability, from
313+
the highest-precedence matching ruleset, each including:
314+
315+
- ``advisory_id``: the vulnerability identifier.
316+
- ``ruleset``: the name of the ruleset that produced the recommendation.
317+
- ``recommended_action``: the remediation action.
318+
- ``matched_rules``: the rule types that matched.
319+
- ``request``: a string representation of the associated request, or ``null``.
320+
- ``detected_date`` and ``last_checked``.
321+
322+
Triage rulesets and analysis presets support full create, retrieve, update, and delete
323+
operations at::
324+
325+
/api/v2/triage_rulesets/
326+
/api/v2/analysis_presets/
327+
328+
A product's ruleset assignments can be listed and managed at::
329+
330+
GET /api/v2/products/{uuid}/manage_triage_rulesets/
331+
POST /api/v2/products/{uuid}/manage_triage_rulesets/
332+
333+
The ``GET`` response lists every enabled ruleset in the product's dataspace, each
334+
flagged with an ``assigned`` boolean. The ``POST`` endpoint assigns or unassigns one
335+
ruleset at a time and re-evaluates the product immediately::
336+
337+
{"ruleset": "<uuid>", "assigned": true}
338+
339+
Vulnerability analyses, including whether they were auto-applied by a preset, are also
340+
available at ``/api/v2/vulnerability_analyses/``.

0 commit comments

Comments
 (0)