Jobs
Orchestrating multiple scenarios with shared pools and bindings.
A job coordinates multiple scenario workloads, each drawing from shared pools and running concurrently.
Structure
type: job
name: Detect IAM user brute force
pools:
- id: iam-users
type: pool
csv:
path: ./users.csv
workloads:
- scenario: ./brute-force.yaml
count: 10
bindings:
target_user: pool.iam-users.usernameName
The top-level name is the job's authored, customer-recognizable Test name — a short phrase describing the behavior the job exercises (for example, Detect anomalous S3 object exfiltration). It is display metadata: it never becomes a database identity, and it is not part of a Test case's identity digest or of Detection matching, so naming or renaming a job does not re-create its Test cases.
Author a name for every job — it is the primary way a Test is recognized throughout the product.
Pools
Pools provide reusable datasets — IP ranges, user lists, CSV files. They are declared at the job level and referenced in workload bindings via pool.<id> or pool.<id>.<field>.
Pool types:
| Type | Description |
|---|---|
ip_range | Generates IPs from a CIDR block (max 1,048,576 IPs) |
string_list | A static list of string values |
csv | Rows loaded from a CSV file |
Bindings
Bindings map pool draws and generator outputs to scenario state variables. Each binding expression is evaluated and injected into the scenario's state before execution.
Bindings are re-evaluated on every iteration of a loop: workload (and on every combo of a matrix: workload), so a binding such as target_user: pool.iam-users draws a fresh user per iteration, and request_id: gen.uuid() produces a fresh UUID per iteration.
Job-level state is evaluated once at job start and is available to bindings via ref.* (for example account_id: ref.account_id); it stays stable across iterations.
Important: pool.* expressions are only valid in job state and workload bindings — they are rejected if used directly in scenario state or fields blocks.
Concurrency
Each workload runs in its own goroutine. The job runner forks a per-goroutine clock so concurrent workloads advance logical time independently. If any workload errors, the shared context is cancelled and sibling workloads stop.