DSL Reference
TestNet standardizes all security tools and automated pipelines using vNext DSL (Domain Specific Language). Built around YAML, vNext eliminates legacy boilerplate edge definitions and separates definitions into two concise types: kind: Tool (atomic tool specification) and kind: Workflow (multi-step DAG pipeline).
1. Core Architectural Principles
- Type Isolation & Unified Registry: Every DSL file must explicitly declare
kind: Toolorkind: Workflowat the root; - No Explicit Edges: DAG topology is determined naturally via
dependsOndeclarations and data-flow parameter mapping (inputs.*.from); - Dynamic Expression Engine: Supports real-time Aviator expression evaluation in step parameters or conditional branches (
when) (e.g.,size(outputs) > 0).
2. Tool Specification (ToolSpec)
kind: Tool defines how a security utility or Docker container executes on remote Go nodes and how its raw output is parsed into structured data.
Complete ToolSpec Example
kind: Tool
metadata:
id: subfinder
name: Subfinder
version: 1.0.0
description: Passive subdomain discovery engine
category: recon
tags:
- subdomain
- dns
spec:
inputs:
target:
required: true
accepts: [DOMAIN]
resolve:
DOMAIN: '{{asset.domain}}'
batch:
enabled: true
mode: FILE
argName: -dL
size: 50
params:
threads:
type: INTEGER
defaultValue: 10
min: 1
max: 100
recursive:
type: BOOLEAN
defaultValue: false
runtime:
type: DOCKER
timeoutSeconds: 300
docker:
image:
default: projectdiscovery/subfinder:latest
network: host
args:
- -silent
- -t
- '{{params.threads}}'
- -d
- '{{input.target}}'
- -o
- /tmp/output.json
- -json
outputs:
subdomain:
assetType: SUBDOMAIN
parser:
type: JSONL
map:
subdomain: $.host
source: $.source
identity:
field: subdomainCore Structure Reference
| Level | Field | Description |
|---|---|---|
| Top | kind: Tool | Fixed type identifier |
| Top | metadata | Metadata: id, name, version (semver) |
| Top | spec | Tool specification (see below) |
| Spec Field | Description |
|---|---|
spec.inputs | Input channels: defines accepted asset types and data resolution rules, supports batch mode |
spec.params | Runtime parameters: supports STRING/INTEGER/NUMBER/BOOLEAN/ARRAY/OBJECT types with defaults and validation |
spec.runtime | Execution engine: defines type (DOCKER/HTTP/DNS/TCP) and engine-specific config |
spec.outputs | Output channels: defines asset type mapping and parser (LINE/JSON/JSONL/REGEX/FILE/CSV/XML) |
Engine Types (runtime.type)
| Type | Description | Config Fields |
|---|---|---|
DOCKER | Docker container execution | docker.image, docker.args, docker.network |
HTTP | HTTP probe | http.url, http.method, http.headers |
DNS | DNS query probe | dns.domain, dns.recordType |
TCP | TCP port probe | tcp.host, tcp.port, tcp.data |
NOTE
The vNext DSL does not provide a SHELL runtime. The schema keeps HTTP_PROBE (httpProbe.url) only as a legacy alias of the HTTP probe type.
Placeholders & Variable Resolution
All placeholder expressions within Tool Spec use double curly braces {{...}} under strict namespaces:
| Namespace | Format | Allowed In | Description |
|---|---|---|---|
| Input Channels | {{input.<channel>}} (or alias {{inputs.<channel>}}) | runtime.docker.args, runtime.http.url, runtime.tcp.host, runtime.env, etc. | References data from channels declared in spec.inputs (resolved from assets or upstream nodes) |
| Parameters | {{params.<param>}} | Any runtime configuration fields | References parameter values declared in spec.params (defaults or caller overrides) |
| Asset Properties | {{asset.<field>}} | spec.inputs.<channel>.resolve and runtime.* | Maps asset properties in input resolve templates; also provides direct fallback when executing on single assets (e.g. {{asset.domain}}, {{asset.ip}}) |
| Secret References | {{secret.<key>}} | Any runtime configuration fields | References platform-managed secrets (e.g. API keys) so credentials never appear in plain text inside the DSL |
Strict Placeholder Enforcement
- Compile-time Static Validation: When saving or validating a Tool DSL, the system statically scans all runtime placeholders. Any reference to undeclared inputs/params or unknown namespaces is rejected immediately with a compilation error.
- Runtime Contract Enforcement: When constructing task execution specifications, any unresolvable placeholder (e.g. missing target value or unset required parameter) immediately raises an exception, preventing silent drops that cause corrupted CLI flags.
3. Workflow Specification (WorkflowSpec)
kind: Workflow chains multiple independent tools into an enterprise-grade Directed Acyclic Graph (DAG).
Complete WorkflowSpec Example
kind: Workflow
metadata:
id: domain-recon-pipeline
name: Domain Recon Pipeline
version: 1.0.0
description: "Domain reconnaissance pipeline: discover subdomains and probe web services"
tags:
- recon
- subdomain
- web
spec:
trigger:
type: MANUAL
enabled: true
input:
assetTypes: [DOMAIN]
nodes:
subfinder:
tool: subfinder
inputs:
target:
from:
- trigger.asset
params:
threads: 20
recursive: true
timeoutSeconds: 600
skipOnNoInput: true
httpx_probe:
tool: httpx
inputs:
target:
from:
- subfinder.outputs.subdomain
dependsOn:
nodes: [subfinder]
policy: ALL_SUCCESS
params:
followRedirects: true
threads: 50
timeoutSeconds: 900
skipOnNoInput: true
outputs:
subdomain:
from: [subfinder.outputs.subdomain]
web:
from: [httpx_probe.outputs.web]
policy:
errorStrategy: CONTINUE
maxConcurrency: 5
timeoutSeconds: 1800
maxRetries: 2Core Structure
| Field | Description |
|---|---|
metadata | Metadata: id, name, version, description, tags |
spec.trigger | Trigger config: type supports MANUAL/CRON/AUTO; AUTO means asset-event-linked auto-trigger (executes when new assets are discovered) |
spec.nodes | DAG nodes: each node declares its tool, inputs.*.from bindings, and dependsOn dependencies |
spec.outputs | Workflow output declarations: aggregates node output channels |
spec.policy | Execution policy: errorStrategy, maxConcurrency, timeoutSeconds, maxRetries |
Node Dependency (dependsOn)
| Field | Description |
|---|---|
dependsOn.nodes | List of upstream node IDs |
dependsOn.policy | Strategy: ALL_SUCCESS (default, all must succeed), ALL_DONE (run when all finish), ANY_SUCCESS (run when any succeeds), ANY_DONE (run when any finishes), EXPRESSION (custom Aviator expression via dependsOn.expression) |
Input Binding (inputs.*.from)
| Source | Syntax | Description |
|---|---|---|
| Trigger input | trigger.asset | References the asset passed to the workflow trigger |
| Node output | {nodeId}.outputs.{channel} | References an output channel of an upstream node |
Conditional Execution (when)
Nodes support Aviator expressions for conditional execution:
nodes:
nuclei_scan:
tool: nuclei
dependsOn:
nodes: [httpx_probe]
policy: ALL_SUCCESS
when: 'size(httpx_probe.outputs.web) > 0'A node may also declare skipOnNoInput: true to be skipped gracefully (instead of failing) when its input resolves to zero assets.
TIP
To learn how to maintain versioned DSL files inside your local testnet-registry store and publish custom tools, refer to the testnet-registry README.
Related Documentation
- Workflow Overview — workflow lifecycle and preset workflows
- Triggers — cron scheduling and asset event triggers
- Built-in Tools — the 24 built-in tools available for orchestration