diff --git a/docs/content/automation/rules_engine_2/about.md b/docs/content/automation/rules_engine_2/about.md index 17141f717f..2a4bc21eb9 100644 --- a/docs/content/automation/rules_engine_2/about.md +++ b/docs/content/automation/rules_engine_2/about.md @@ -21,6 +21,8 @@ The original [Rules Engine](/automation/rules_engine/about/) applies an ordered * **Traceability.** Every execution is recorded node by node as a [Run](../runs/), and every outbound send is recorded as a [Delivery](../deliveries/) that says exactly what was sent, where it went, and how it ended. * **A simulate mode.** A rule can record precisely what it would send without sending anything, which is how you test one safely before it touches the outside world. +Rules are not limited to Findings. An Asset (Product) rule reacts to Assets being created, updated or tagged, or sweeps them on a schedule, and can set their fields, move them between Organizations, tag and untag them, and place them in the Asset hierarchy. That makes recurring inventory work self-service: instead of a one-off migration to regroup Assets, a rule expresses the grouping and keeps enforcing it as new Assets arrive. + Both engines run side by side. Turning on Rules Engine 2.0 does not disable or convert your existing rules, and there is a [converter](../converting_from_rules_engine/) for when you want to move them across. ## Enabling Rules Engine 2.0 diff --git a/docs/content/automation/rules_engine_2/building_rules.md b/docs/content/automation/rules_engine_2/building_rules.md index cc3a1285f6..3b64238cf3 100644 --- a/docs/content/automation/rules_engine_2/building_rules.md +++ b/docs/content/automation/rules_engine_2/building_rules.md @@ -46,26 +46,41 @@ A node with several incoming edges receives all of their outputs concatenated. Preview runs the real engine, not a simulation of it, and then rolls the whole thing back. Nothing is written, no run is recorded, and egress is forced to simulate whatever the rule's mode says. It is the fastest way to check that your conditions match what you expected. -Preview is the one execution that caps how many Findings it looks at, so that it stays fast. When it truncates, it says so in the trace. A real run has no such cap. +Preview is the one execution that caps how many items it looks at, so that it stays fast. When it truncates, it says so in the trace. A real run has no such cap. + +## What a rule works on + +Every rule works on one kind of item, and its trigger decides which: + +* **On Finding Event** makes a Finding rule: Finding items flow along the edges, and the Findings nodes change them. +* **On Asset Event** makes an Asset rule: Asset (Product) items flow instead, and the Assets nodes change them. +* **On a Schedule** and **Manual Run** carry a **Sweep Over** setting that picks either kind. Rules saved before this setting existed sweep Findings, exactly as they always did. + +The editor enforces this as you build. Nodes that do not apply to the trigger are dimmed in the palette with a tooltip saying why, and a connection to an incompatible node will not complete. The same rule is enforced on save and on every run, so a graph cannot mix kinds however it was produced. + +Two categories work on either kind: **Logic** nodes route and trim whatever flows through them, and the notification **Egress** nodes (Slack, Teams, email, SNS, webhook, in-app alert) send about either. Three nodes stay Finding-only on purpose: **De-duplicate Within Run** (de-duplication is a Finding concept), and the **ticket** and **report** nodes (tickets and reports track Findings). + +The scope editor follows the kind too: a Finding trigger's scope opens the Findings list, and an Asset trigger's scope opens the Assets list, each in the same filter vocabulary its list page uses. Conditions and message templates offer the matching field paths (`finding.*` in a Finding rule, `product.*` in an Asset rule), and the insert menu only offers paths the rule's items actually carry. ## Triggers and scope -Every graph starts with one of three triggers. +Every graph starts with one of four triggers. * **On Finding Event** wakes the rule when Findings are created, updated, closed or reopened. Choose which of those in the node's **Event** setting, or `any` for all four. -* **On a Schedule** sweeps Findings on a recurring schedule. -* **Manual Run** sweeps Findings when you press **Run** on the rule. +* **On Asset Event** wakes the rule when Assets are created or updated, tag changes included. +* **On a Schedule** sweeps everything in scope on a recurring schedule, Findings or Assets per its **Sweep Over** setting. +* **Manual Run** sweeps everything in scope when you press **Run** on the rule, Findings or Assets per its **Sweep Over** setting. ### Scope -All three triggers take a **Scope**, and scope is how you narrow what the rule considers. It is the same filter vocabulary the original Rules Engine uses, roughly sixty filters spanning Findings and the objects around them, so a filter you already know how to write there means the same thing here. +Every trigger takes a **Scope**, and scope is how you narrow what the rule considers. For a Finding rule it is the same filter vocabulary the original Rules Engine uses, roughly sixty filters spanning Findings and the objects around them, so a filter you already know how to write there means the same thing here. For an Asset rule it is the Assets list's own filters instead. Two things about scope are worth understanding: -* **Scope is applied on top of authorization, never instead of it.** The rule runs as its owner, so scope narrows an already-authorized set of Findings. Leaving scope empty does not mean "every Finding in the instance", it means "every Finding the rule owner can see". -* **An invalid scope fails the run rather than widening it.** If a filter key does not exist, or a value is one the filter would silently discard, the run errors out. A rule that does nothing is recoverable. A rule that quietly edits every Finding in the instance is not. +* **Scope is applied on top of authorization, never instead of it.** The rule runs as its owner, so scope narrows an already-authorized set. Leaving scope empty does not mean "everything in the instance", it means "everything the rule owner can see". +* **An invalid scope fails the run rather than widening it.** If a filter key does not exist, or a value is one the filter would silently discard, the run errors out. A rule that does nothing is recoverable. A rule that quietly edits everything in the instance is not. -For an event trigger, scope acts as a second gate: the Findings named in the event are matched against it, and only those that pass enter the graph. +For an event trigger, scope acts as a second gate: the Findings or Assets named in the event are matched against it, and only those that pass enter the graph. ### Scheduling @@ -98,6 +113,8 @@ ctx.rule_name A path that does not resolve produces no value rather than an error. +An Asset rule reads its items the same way, through `product.*`, `product_type.*` and `ctx.*` paths. `ctx.changed_fields` carries the names of the fields an update changed, and the insert menu only offers paths the rule's items actually carry. + ### Conditioning on an exception With [Risk Acceptances 2.0](/triage_findings/findings_workflows/pro__risk_acceptance/) enabled, diff --git a/docs/content/automation/rules_engine_2/configuration.md b/docs/content/automation/rules_engine_2/configuration.md index 10664a58c6..1f28ab56de 100644 --- a/docs/content/automation/rules_engine_2/configuration.md +++ b/docs/content/automation/rules_engine_2/configuration.md @@ -82,7 +82,7 @@ Retention is surfaced in the product rather than left implicit: the API serves b How many days a finished delivery is kept. -This is the fastest-growing table in the feature. A per-Finding egress node writes up to a chunk's worth of rows per run, including in Simulate mode. Raise it if you need a longer outbound audit trail, and lower it if volume is a problem. +This is the fastest-growing table in the feature. A per-item egress node writes up to a chunk's worth of rows per run, including in Simulate mode. Raise it if you need a longer outbound audit trail, and lower it if volume is a problem. ### `DD_RULES_V2_RUN_RETENTION_DAYS` @@ -124,11 +124,11 @@ Turn this on if you genuinely webhook to something on a private address, which a **Default: 1000. Set to 0 to remove the ceiling.** -The most per-Finding sends a single egress node will record in one run. +The most per-item sends a single egress node will record in one run. -A node with **One Message per Finding** turned on produces one delivery row and one queued task per Finding. Because a run has no item cap, a rule with a very broad scope and per-Finding sending on would otherwise mean an unbounded number of both. +A node with **One Message per Item** turned on produces one delivery row and one queued task per item. Because a run has no item cap, a rule with a very broad scope and per-item sending on would otherwise mean an unbounded number of both. The ceiling is per node per run and counts items of either kind: a Finding rule's Findings and an Asset rule's Assets spend the same budget. -Past this ceiling the node records a **visible skip** saying how many Findings it did not send about. It does not fail the run, and it does not silently stop. +Past this ceiling the node records a **visible skip** saying how many items it did not send about. It does not fail the run, and it does not silently stop. ## Related settings diff --git a/docs/content/automation/rules_engine_2/deliveries.md b/docs/content/automation/rules_engine_2/deliveries.md index f2469a28ec..c6daace3ba 100644 --- a/docs/content/automation/rules_engine_2/deliveries.md +++ b/docs/content/automation/rules_engine_2/deliveries.md @@ -111,8 +111,19 @@ Remember that Simulate holds back **only** the outbound sends. Findings nodes st Deliveries are kept for **180 days** by default, after which a retention job prunes them. -This is the fastest-growing table in the feature, because a node sending one message per Finding writes a row per Finding, in Simulate mode as well as Live. The default is a real window rather than "keep everything", so the growth does not quietly become your problem. +This is the fastest-growing table in the feature, because a node sending one message per item writes a row per item, in Simulate mode as well as Live. The default is a real window rather than "keep everything", so the growth does not quietly become your problem. You are told about it rather than left to discover it. A delivery's detail shows the retention window and the date that row will be deleted, and the date is recalculated on read, so changing the window takes effect immediately. Set the window longer if you need a longer outbound audit trail, or to `0` to keep everything. See [Configuration](../configuration/#retention). + +## Deliveries from Asset rules + +A notification sent by an Asset rule lands in the outbox like any other delivery. A per-item send names its Asset the way a per-Finding send names its Finding, and the row links to the Asset. + +Visibility follows the row's subject. A row about one Asset is visible to anyone who can view that Asset. A batch row (a digest) has no single subject and quotes the names of everything its send covered, so it stays behind the global Finding viewing grant, exactly as Finding digests do. + +Two rendering details worth knowing when reading recorded payloads: + +- An Asset digest counts its batch by business criticality ("7 asset(s): 2 very high, 5 unclassified") where a Finding digest counts by severity. +- A webhook body from an Asset rule carries `"entity": "asset"` and an `assets` list with each Asset's identifying fields; its `findings` list is present and empty, so a receiver written against the Finding shape keeps parsing. diff --git a/docs/content/automation/rules_engine_2/node_reference.md b/docs/content/automation/rules_engine_2/node_reference.md index a283d974b4..8f51ee136b 100644 --- a/docs/content/automation/rules_engine_2/node_reference.md +++ b/docs/content/automation/rules_engine_2/node_reference.md @@ -8,13 +8,13 @@ aliases: --- Note: Rules Engine 2.0 is a DefectDojo Pro-only feature. -Rules Engine 2.0 ships 25 nodes in four categories. This page documents all of them. +Rules Engine 2.0 ships 31 nodes in five categories. This page documents all of them. Unless stated otherwise, a node takes one input, produces one output called `out`, and passes every item it received on to that output. That matters when you chain nodes: a Findings node changes the Finding and then hands the item onward, so several of them in a row all apply. ## Triggers -Every graph has exactly one trigger, and only a trigger can start a run. All three produce Finding items and all three take a **Scope** that narrows which Findings they produce. See [Building Rules](../building_rules/) for how scope works. +Every graph has exactly one trigger, and only a trigger can start a run. The trigger also decides what kind of item the rule works on: Findings or Assets (Products). Every trigger takes a **Scope** that narrows what it produces. See [Building Rules](../building_rules/) for how scope and the kind of item work. ### On Finding Event @@ -29,25 +29,40 @@ Runs when Findings are created, updated, closed or reopened. Findings named by the event are matched against scope before they enter the graph, so the event decides *when* and scope decides *which*. +### On Asset Event + +`trigger.asset` + +Runs when Assets (Products) are created or updated. Tag changes count as updates, so a rule can react to an Asset being tagged. + +| Setting | Default | Notes | +|---------|---------|-------| +| **Event** | `created` | Which Asset change wakes this rule: `created`, `updated`, or `any` for both. | +| **Scope** | empty | Which Assets this rule considers, in the Assets list's own filters. Empty means every Asset the rule owner can see. | + +Assets named by the event are matched against scope before they enter the graph. For an update, the names of the changed fields travel with the items as `ctx.changed_fields`, so an If / Filter node can say "only when the organization changed" (`ctx.changed_fields` `contains` `organization`) or "only when tagged" (`contains` `tags`). + ### On a Schedule `trigger.schedule` -Sweeps every Finding in scope on a schedule. The schedule is configured on the rule and is limited to quarter-hour marks. +Sweeps everything in scope on a schedule. The schedule is configured on the rule and is limited to quarter-hour marks. | Setting | Default | Notes | |---------|---------|-------| -| **Scope** | empty | Which Findings this rule considers. | +| **Sweep Over** | `Findings` | What kind of item this rule sweeps: `Findings` or `Assets`. The trigger decides what every node downstream works on. | +| **Scope** | empty | What this rule considers. Follows Sweep Over: a Finding sweep filters in the Findings list's vocabulary, an Asset sweep in the Assets list's. | ### Manual Run `trigger.manual` -Sweeps every Finding in scope when you press **Run** on the rule. +Sweeps everything in scope when you press **Run** on the rule. | Setting | Default | Notes | |---------|---------|-------| -| **Scope** | empty | Which Findings this rule considers. | +| **Sweep Over** | `Findings` | What kind of item this rule sweeps: `Findings` or `Assets`. The trigger decides what every node downstream works on. | +| **Scope** | empty | What this rule considers. Follows Sweep Over: a Finding sweep filters in the Findings list's vocabulary, an Asset sweep in the Assets list's. | ## Logic @@ -224,13 +239,77 @@ Sets the risk, overriding the computed one. |---------|---------| | **Risk** | `Low`, `Medium`, `Needs Action`, `Urgent` | +## Assets + +These nodes change Assets (Products). Like the Findings nodes, every change is attributed back to the rule, run and node that made it, and shows up on the Asset's provenance. They only join graphs whose trigger produces Assets. + +These nodes save each Asset individually, so everything that normally follows an Asset edit still happens: organization membership follows a move, tag changes reconcile memberships, and Assets with tag inheritance enabled propagate added tags to their Findings. + +### Set a Field + +`asset.set_field` + +Sets a field on the Asset. Assets already holding the value are left alone, and Assets the rule owner may not edit are counted on the node trace as skipped rather than touched. + +| Setting | Default | Notes | +|---------|---------|-------| +| **Field** | none | One of: `description`, `business_criticality`, `platform`, `lifecycle`, `origin`, `user_records`, `revenue`, `external_audience`, `internet_accessible`. | +| **Value** | none | The control follows the field: a template for description (with `{{product.name}}` style placeholders), a picker for the choice fields, a number or a toggle for the rest. | + +Two fields are deliberately not offered: `name` (it is unique, so one rendered value written across a sweep cannot work) and the SLA configuration (it drives an asynchronous recalculation with its own write lock, and belongs to a dedicated flow). + +### Set Organization + +`asset.set_organization` + +Moves the Asset to a different Organization (Product Type). Its primary organization membership follows automatically, exactly as it does when the move is made on the Asset form. + +| Setting | Default | Notes | +|---------|---------|-------| +| **Organization** | none | The destination. | + +The permission gate mirrors the Asset form: the rule owner needs edit permission on each Asset, and the add-asset permission on the destination Organization. Without the latter the run fails up front, before anything moves. + +### Add Tags + +`asset.add_tags` + +Adds tags to the Asset. Supports `{{product.name}}` style placeholders, so a sweep can tag by rendered value. On Assets with tag inheritance enabled, added tags propagate to their Findings. + +| Setting | Default | Notes | +|---------|---------|-------| +| **Tags** | none | Comma separated tags. | + +### Remove Tags + +`asset.remove_tags` + +Removes tags from the Asset. A tag the Asset does not carry is simply not removed, and counts the Asset as unchanged. + +| Setting | Default | Notes | +|---------|---------|-------| +| **Tags** | none | Comma separated tags. | + +### Set Parent + +`asset.set_parent` + +Places the Asset under a parent in the Asset hierarchy, or removes its parent. An edge the hierarchy refuses (a cycle, or the Asset being its own parent) is counted as failed on the node trace and skipped, rather than failing the run. + +| Setting | Default | Notes | +|---------|---------|-------| +| **Action** | `Set Parent` | `Set Parent` or `Remove Parent`. | +| **Parent** | none | The Asset to place these under. Shown while the action is Set Parent. | + ## Egress Egress nodes are the nodes that leave DefectDojo. Every one of them records a [Delivery](../deliveries/) before anything is sent, and every one of them honours the rule's **Simulate** or **Live** mode. -Several of them offer the same **One Message per Finding** choice. Off, the node sends one message describing the whole batch, with a severity breakdown and a capped list of Findings. On, it sends one message per Finding. +The notification nodes (Slack, Teams, email, SNS, webhook, in-app alert) work in Finding and Asset rules alike: in an Asset rule the default message line becomes the Asset's name and organization, digests count by business criticality instead of severity, and a webhook body carries an `assets` list plus an `entity` key (its `findings` list stays present and empty, so existing receivers never meet a missing key). The ticket nodes and the report node stay Finding-only: tickets and reports track Findings. + +Several of them offer the same **One Message per Item** choice. Off, the node sends one message describing the whole batch, with a breakdown and a capped list of items. On, it sends one message per item. -A node sending one message per Finding stops after 1,000 sends in a single run by default, and records a visible skip saying how many Findings it did not send about. See [Configuration](../configuration/#per-finding-send-ceiling). +A node sending one message per item stops after 1,000 sends in a single run by default, and records a visible skip saying how many items it did not send about. The ceiling counts items of either kind. See [Configuration](../configuration/#per-finding-send-ceiling). ### When a channel is unavailable diff --git a/docs/content/automation/rules_engine_2/runs.md b/docs/content/automation/rules_engine_2/runs.md index be473449d8..b1e7f29181 100644 --- a/docs/content/automation/rules_engine_2/runs.md +++ b/docs/content/automation/rules_engine_2/runs.md @@ -129,3 +129,11 @@ Provenance survives the rule. Deleting a rule or a run keeps the timeline entrie ## Deleting rules with history A rule that has produced deliveries cannot be deleted out from under them. Delete the deliveries first, or keep the rule and disable it. This is intentional: deliveries hold the record of what was actually sent to external systems, and a cascade delete would take in-flight sends with it. + +## Asset runs + +A run of an Asset rule reads the same way a Finding run does, with the Asset surfaces in place of the Finding ones. The runs list's **Items Changed** and **Items Left Alone** counts link to the Assets list for an Asset run and to the Findings list for a Finding run, each filtered to exactly what that run touched or considered. + +The left-alone list carries the same caveat it does for Findings: for a scheduled or manual sweep it is the rule's scope evaluated now, minus what the run changed. An Asset created since the run appears there, and one the run moved out of scope does not. + +Every change an Asset rule makes is attributed to the rule, run and node that made it, and each Asset's own rules-engine history is available through the API at `/api/vue/rules_engine_v2/assets/{id}/provenance/`, the Asset twin of the Finding provenance timeline. Reading it follows Asset visibility: an Asset the caller cannot see answers 404 rather than an empty timeline.