Workflow Definitions
Develop playbooks using configuration-as-code (YAML).
A workflow definition is the configuration data that defines and controls how a workflow executes. It is the source of truth when reasoning about any workflow’s execution.
Overview
A workflow defintion is analagous to an instruction manual or blueprint that tells Tracecat runners how to execute a workflow. Workflow definitions are created when a workflow is committed from the UI, and are immutable once created. You can think of them as a snapshot of the workflow (that you view and edit in the UI) at a specific point in time.
These snapshots becomes deployed workflow instances (workflow runs) at runtime. When a workflow is triggered, Tracecat will find and execute its latest workflow definition version.
One workflow can have many different workflow definitions due to versioning
Workflow Definition Schema
Top level attributes for a workflow definition DSLInput
object.
Attribute | Type | Description |
---|---|---|
title | str | The title of the DSL workflow. |
description | str | A description of the DSL workflow. |
entrypoint | str | The entry point for the DSL workflow. |
actions | list[ActionStatement] | A list of action statements in the workflow. |
config | DSLConfig | Configuration settings for the DSL workflow. |
triggers | list[Trigger] | A list of triggers for the workflow. |
inputs | dict[str, Any] | Static input parameters for the workflow. |
trigger_inputs | dict[str, Any] | Dynamic input parameters for the workflow. |
model_config | ConfigDict | Configuration allowing arbitrary types. |
Action Statement
An ActionStatement
is the configuration for single action in a workflow.
Attribute | Type | Description |
---|---|---|
ref | str | Unique reference for the task (lower_snake_case slug of the action’s title) |
action | str | The action’s UDF key <namespace>.<function_name> |
args | dict[str, Any] | Arguments (key-value pairs) for the action |
depends_on | list[str] | Uptream action dependencies (other action ref s) |
run_if | str | None | If conditional. Evaluating to True runs the task. (optional) |
for_each | str | None | Coming soon: An iterable over which the action should be applied (optional) |
Data Model
Workflows are modeled as a directed acyclic graph (DAG).
Accordingly, the workflow definition expresses the graph dependencies between actions.
Each action statement’s depends_on
attribute is a list of references to other actions that must complete before the action can run.
Using YAML
You can create a workflow definition using a YAML file and Tracecat’s YAML-like Domain-Specific Language (DSL). Some benefits of using YAML include:
- Version Control: You can track changes to the workflow over time — better audit trails!
- Inline comments: Nice to have for documentation and debugging.
- IDE Support: You can use your favorite IDE or text editor work with YAML files.
- AI Autocompletion: When used with an IDE AI copilot like
Github Copilot
orSupermaven
that learns your editing behavior, you can get AI-powered autocompletion for your YAML file.
You can find the full schema for the YAML file at traceat/dsl/common.py.
An example YAML file for a workflow definition:
title: Send Slack notifications for GuardDuty findings
description: Pull GuardDuty findings from the API and send them to Slack
config:
scheduler: dynamic
entrypoint: pull_aws_guardduty_findings
inputs:
url: http://api.example.com/v1
num_days: 1
triggers:
- type: webhook
ref: my_webhook
entrypoint: pull_aws_guardduty_findings
- type: schedule
ref: my_schedule
entrypoint: pull_aws_guardduty_findings
actions:
- ref: pull_aws_guardduty_findings
action: core.http_request
args:
url: ${{ INPUTS.url }}/cdr/alerts
method: GET
params:
start_time: "2023-05-27T00:00:00Z"
end_time: "2024-05-28T12:00:00Z"
vendor: aws_guardduty
- ref: smaccify_guardduty_findings
action: core.http_request
depends_on:
- pull_aws_guardduty_findings
args:
url: ${{ INPUTS.url }}/smac/aws_guardduty
method: POST
headers:
Content-Type: application/json
payload: ${{ ACTIONS.pull_aws_guardduty_findings.result.data }} # List of findings
- ref: send_slack_notifications
action: core.http_request
depends_on:
- smaccify_guardduty_findings
args:
url: ${{ INPUTS.url }}/chatops/messages
headers:
Content-Type: application/json
method: POST
payload:
vendor: slack
channel: C0XXXXXXXXX
contexts: ${{ ACTIONS.smaccify_guardduty_findings.result.data }} # List of SMAC findings
text: GuardDuty findings for past 24h
template:
- type: header
text:
type: plain_text
text: "{title}"
emoji: true
- type: section
text:
type: mrkdwn
text: "{description}"
- type: section
fields:
- type: mrkdwn
text: "*Status:* {status}"
- type: mrkdwn
text: "*Malice:* {malice}"
- type: mrkdwn
text: "*Action:* {action}"
- type: mrkdwn
text: "*Context:* {context}"
- type: actions
elements:
- type: button
text:
type: plain_text
emoji: true
text: "Suppress"
style: primary
value: "click_me_123"
- type: button
text:
type: plain_text
emoji: true
text: "Escalate"
style: danger
value: "click_me_123"
Committing Workflow changes
A new workflow definition is created for a workflow when:
- A YAML file is committed to a workflow through the API/CLI
- A workflow is committed through the GUI
When a workflow is committed without a YAML file, Tracecat will look for the
workflow’s GUI-configured actions in the database Action
table and use those
to create the workflow definition.
Versioning
- Our versioning system is intentionally extremely simple
- You can checkout a specific version of a workflow definition, but to promote it to the exe
- Tracecat will always look for the latest version of the workflow definition to execute
- Workflow versions are monotonically increasing integers
Immutability
We do not allow editing of workflow definitions after they are created, nor do we allow deletion of workflow definitions. This ensures that for any compliance or audit purposes, you can always trace back to the exact configuration that was used to execute a workflow.