Runs (Pro)

Note: Triage Engine is a DefectDojo Pro-only feature.

A run is one execution of one rule. Every run is recorded, whether it succeeded or failed, and every node inside it leaves a trace. Act > Triage Engine > Runs lists them.

What a run records

FieldMeaning
RuleThe rule that executed.
TriggerThe event that started it, for example finding.created, schedule or manual.
Triggered byThe person who set it off, when a person did: whoever pressed Run Now, or whoever saved the Finding that triggered it. Empty for a schedule, and for a change nobody was present for such as an import or an API call with no user. This is distinct from the rule’s owner, which is who the run executed as.
StatusRunning, Success or Error.
Started and FinishedWhen it ran. Finished is empty only while it is still running.
ErrorThe error that ended it, if it failed.
StatsPer-node totals, cascaded events, and deferred work.
DepthHow many cascade hops away from the originating event this run is.
Source runThe run whose emitted event triggered this one, for a cascaded run.

The node trace

Inside a run, every node records its own row:

FieldMeaning
OrderWhere the node sat in the execution order.
NodeIts id, its type, and its label if you gave it one.
StatusWhether the node completed or raised.
Items inHow many items entered.
Items outHow many left, broken down per output handle, so an If / Filter node shows its true and false counts separately.
SummaryWhatever counters the node reported, for example how many Findings it changed.
ErrorThe error it raised, if it failed.

The trace is what you read when a rule did not do what you expected. An If / Filter node reporting 400 items in and 0 down the true branch tells you the conditions are wrong, without you having to guess.

Execution model

Nodes execute in topological order: a node runs once everything feeding into it has run. A node with several incoming edges receives all of their outputs concatenated. A node with nothing feeding into it still runs, with an empty input list.

A failed run changes nothing

A run is atomic. If any node raises, every Finding change the run made is rolled back.

The trace is not rolled back with it. The node rows and the Error status are written afterwards, so a failed run tells you exactly which node broke while leaving no half-applied edits behind. This is the single most important guarantee to keep in mind when reading the Runs page: an errored run is a run that did nothing.

Egress follows the same rule. Deliveries are recorded inside the run’s transaction and only dispatched after it commits, so a run that rolls back sends nothing.

One run per rule at a time

A rule can only have one run in progress. A second trigger for the same rule while it is still running does not race with it. It waits and retries.

Different rules run fully concurrently, so a slow rule never holds up its siblings.

If a run is somehow abandoned, for example because the worker executing it was killed, its lock is released after a stall window (30 minutes by default) so the rule is not wedged forever. A run approaching that window stops itself first, unwinding cleanly, so a merely slow run can never end up executing alongside its own replacement.

Cascading

A rule that changes a Finding produces exactly the kind of event another rule can trigger on. Triage Engine allows that, so A -> B -> C chains work, and bounds it in two independent ways:

  • Depth. An event may travel at most 3 cascade hops from the change that originated it.
  • Chain membership. Every event carries the list of rules already traversed in its chain, and a rule never runs twice in the same chain. So a rule cannot re-trigger itself, and two rules cannot ping-pong.

A run’s Depth and Source run fields let you follow a chain back to the change that started it. Triggered by is carried down the whole chain, so a cascade one person set off stays attributable to them at every hop.

Changes made by a running rule are attributed to that rule’s own cascade rather than looking like fresh user activity, so a rule delegating work internally does not inflate the chain.

Scale and limits

A run is not capped. A rule processes everything its scope matches, however large that is. A rule that silently stopped at the first N Findings would be a rule you could not trust.

Instead, a run is processed in chunks, 1,000 Findings at a time by default. Only the chunk is held in memory, so a sweep over a very large scope is bounded in memory rather than in coverage. The one exception is Preview, which does cap, and says so in its trace when it truncates.

Two other numbers shape how work is divided:

  • Findings per event, 500 by default. A bulk change is split across several events, each becoming its own run. The practical effect for a large import is a manageable number of runs rather than one run per Finding.
  • Per-Finding send ceiling, 1,000 by default. An egress node set to send one message per Finding stops at this many in a single run and records a visible skip saying how many it did not send about. This bounds delivery rows and queued tasks, which a chunked run no longer bounds on its own.

All three are deployment settings, documented in Configuration.

How long a run may take

A run stamps a heartbeat after each chunk. Stall detection reads that heartbeat rather than the start time, so a long sweep that is still making progress is never mistaken for a crashed worker.

Two windows apply, both configurable:

  • A run that goes 30 minutes without a heartbeat is treated as abandoned, errored, and its lock released.
  • A run is killed outright after six hours, as a guard against one that will never finish.

Retention

Runs are kept for 180 days by default, along with their per-node rows and their Finding provenance. Deliveries are kept for 180 days separately.

The product tells you this rather than leaving it implicit: a run’s detail shows the retention window and the date that run will be deleted. A run still holding deliveries is kept until those are pruned.

Both windows are configurable, and either can be set to keep records indefinitely. See Configuration.

Running a rule by hand

Run Now runs a rule straight away, whatever its trigger, except a webhook trigger. It is on the editor’s toolbar and in each rule’s menu on the rule list, for the rule’s owner when they hold Rule Edit, and for superusers. What a hand-started run works on depends on the trigger:

  • Manual Run and On a Schedule sweep everything in scope, Findings or Assets per the Sweep Over setting, exactly as a scheduled run does.
  • On Finding Event and On Asset Event replay the rule over the Findings or Assets currently in the trigger’s scope, as if the trigger’s event had just happened to each of them. A replay covers at most 500 of them, lowest id first.
  • On a Missing Scan checks for overdue scans now, and When a Group of Scans Has Landed closes every open cycle as it stands.
  • When a Scan Has Landed and On DAST Scan Completed act only on the scan that woke them, so a hand-started run of either has nothing to work on and records a run that changed nothing.
  • A webhook rule has no Run Now. It acts on what a sender delivered, and a hand-started run has no delivery. Use Preview with the receiver’s sample or a pasted payload instead, or replay a stored delivery from the receiver.

The run happens on a worker, not in your browser. The editor waits for it and shows the counts on each node; from the rule list, open Runs to follow it. The run records you as Triggered by, and it follows the rule’s mode: in Simulate, its Finding and Asset edits are real and only outbound sends are held back.

Run Now works on a disabled rule too, AI steps included, so you can try a rule by hand before you enable it. Enabling a rule is what lets its trigger start it on its own. A run started with Run Now that is still waiting to start does not run if, by then, the rule is disabled and has changed since you pressed it: it was disabled, edited, or taken over by someone else.

Preview, in the editor, is the only dry run. It runs the real engine and then rolls everything back, records no run, and forces egress to simulate. Use Preview while building, and runs to see what actually happened.

Provenance on a Finding

Runs answer “what did this rule do?”. Provenance answers the opposite question: “why did this Finding change?”.

Every change a rule makes is recorded against the Finding with the rule, the run and the node responsible, and appears as a timeline on the Finding itself. The recorded actions are:

ActionMeaning
created, updated, closed, reopenedThe Finding’s lifecycle changed.
duplicate, status_changeIts duplicate or status flags changed.
notifiedA notification went out about it.
deliveredAn outbound delivery covered it.

Field edits record what changed, including the before and after value of each field. Very long values are truncated in the record, so the timeline stays a record of the change rather than a second copy of the Finding.

Notifications and deliveries are recorded here too. That is deliberate: a rule that sent a message but changed no field would otherwise leave no trace on the Finding at all.

Provenance survives the rule. Deleting a rule or a run keeps the timeline entries and simply unlinks them, so history does not disappear when someone tidies up.

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 surfaced in the Pro UI as the Asset twin of the Finding provenance timeline. It is served by an internal, session-authenticated endpoint (/api/vue/rules_engine_v2/assets/{id}/provenance/) that backs the UI; that path is not part of the token-authenticated /api/v2/ API and is not intended for automation. Reading it follows Asset visibility: an Asset the caller cannot see answers 404 rather than an empty timeline.