feat: add LLM step executor with vision and tool support, event workflow system, and inheritance

- Add LLM executor supporting OpenAI vision, tool calling, embeddings, and structured outputs
- Introduce event emitter/receiver workflows with deduplication and filtering (generate_event functions)
- Add workflow extends/override system enabling inheritance chains and step merge modes
- Update function naming to snake_case across all testdata (fileExists→file_exists, etc.)
- Add comprehensive test fixtures for linter, events, CDN, step dependencies, and extends workflows
This commit is contained in:
j3ssie
2026-01-20 18:23:57 +08:00
parent 9ed02e7eee
commit 1403d20a4d
219 changed files with 25734 additions and 1696 deletions
+2 -2
View File
@@ -38,7 +38,7 @@ modules:
- name: port-scan
depends_on:
- subdomain-enum
condition: "fileLength('{{all_subdomains}}') > 0"
condition: "file_length('{{all_subdomains}}') > 0"
steps:
- name: setup-ports
type: bash
@@ -68,7 +68,7 @@ modules:
- name: screenshot
depends_on:
- port-scan
condition: "fileLength('{{all_ports}}') > 0"
condition: "file_length('{{all_ports}}') > 0"
steps:
- name: setup-screenshots
type: bash
+14 -14
View File
@@ -31,8 +31,8 @@ steps:
- name: validate-dependencies
type: function
function: |
fileExists("{{Binaries}}/metabigor") &&
fileExists("{{Binaries}}/httpx")
file_exists("{{Binaries}}/metabigor") &&
file_exists("{{Binaries}}/httpx")
exports:
deps_valid: "output"
on_error:
@@ -63,14 +63,14 @@ steps:
- name: clean-portscan-results
type: function
pre_condition: 'fileExists("{{output_dir}}/raw-open-ports.txt")'
pre_condition: 'file_exists("{{output_dir}}/raw-open-ports.txt")'
function: CleanRustScan("{{output_dir}}/raw-open-ports.txt", "{{output_dir}}/open-ports.txt")
exports:
clean_ports_file: "{{output_dir}}/open-ports.txt"
- name: count-open-ports
type: function
function: fileLength("{{output_dir}}/open-ports.txt")
function: file_length("{{output_dir}}/open-ports.txt")
exports:
open_port_count: "output"
@@ -102,12 +102,12 @@ steps:
- name: sort-http-results
type: function
pre_condition: 'fileExists("{{httpFile}}")'
pre_condition: 'file_exists("{{httpFile}}")'
function: SortU("{{httpFile}}")
- name: count-http-hosts
type: function
function: fileLength("{{httpFile}}")
function: file_length("{{httpFile}}")
exports:
http_host_count: "output"
@@ -116,7 +116,7 @@ steps:
# ============================================================
- name: http-fingerprinting
type: parallel-steps
pre_condition: 'parseInt("{{http_host_count}}") > 0'
pre_condition: 'parse_int("{{http_host_count}}") > 0'
parallel_steps:
- name: httpx-json-fingerprint
type: bash
@@ -139,14 +139,14 @@ steps:
# ============================================================
- name: clean-http-json
type: function
pre_condition: 'fileExists("{{output_dir}}/{{Workspace}}-http-overview.txt")'
pre_condition: 'file_exists("{{output_dir}}/{{Workspace}}-http-overview.txt")'
function: CleanJSONHttpx("{{output_dir}}/{{Workspace}}-http-overview.txt", "{{output_dir}}/{{Workspace}}-raw-overview.txt")
exports:
raw_overview: "{{output_dir}}/{{Workspace}}-raw-overview.txt"
- name: beautify-results
type: bash
pre_condition: 'fileExists("{{output_dir}}/{{Workspace}}-raw-overview.txt")'
pre_condition: 'file_exists("{{output_dir}}/{{Workspace}}-raw-overview.txt")'
command: "cat {{output_dir}}/{{Workspace}}-raw-overview.txt | csvtk pretty --no-header-row -I -s ' | ' -W 75 > {{output_dir}}/beautify-{{Workspace}}-http.txt"
on_error:
- action: log
@@ -156,7 +156,7 @@ steps:
- name: fallback-beautify
type: bash
pre_condition: '!fileExists("{{output_dir}}/beautify-{{Workspace}}-http.txt")'
pre_condition: '!file_exists("{{output_dir}}/beautify-{{Workspace}}-http.txt")'
command: "cp {{output_dir}}/{{Workspace}}-raw-overview.txt {{output_dir}}/beautify-{{Workspace}}-http.txt 2>/dev/null || touch {{output_dir}}/beautify-{{Workspace}}-http.txt"
# ============================================================
@@ -164,7 +164,7 @@ steps:
# ============================================================
- name: detailed-host-analysis
type: foreach
pre_condition: 'parseInt("{{http_host_count}}") > 0 && parseInt("{{http_host_count}}") < 100'
pre_condition: 'parse_int("{{http_host_count}}") > 0 && parse_int("{{http_host_count}}") < 100'
input: "{{httpFile}}"
variable: host
threads: 5
@@ -199,7 +199,7 @@ steps:
- name: generate-markdown-report
type: function
pre_condition: 'fileExists("{{Data}}/markdown/simple-template.md")'
pre_condition: 'file_exists("{{Data}}/markdown/simple-template.md")'
function: GenMarkdownReport("{{Data}}/markdown/simple-template.md", "{{Output}}/summary.html")
on_error:
- action: log
@@ -222,10 +222,10 @@ steps:
# ============================================================
- name: final-sort
type: function
pre_condition: 'fileExists("{{httpFile}}")'
pre_condition: 'file_exists("{{httpFile}}")'
function: SortU("{{httpFile}}")
- name: notify-completion
type: function
pre_condition: 'parseInt("{{open_port_count}}") > 0'
pre_condition: 'parse_int("{{open_port_count}}") > 0'
function: printf("CIDR scan complete: {{open_port_count}} open ports, {{http_host_count}} HTTP hosts")
+3 -3
View File
@@ -33,7 +33,7 @@ steps:
script: |
var target = "{{Target}}";
var wordlist = "{{wordlist_small}}";
var threadCount = parseInt("{{threads}}");
var threadCount = parse_int("{{threads}}");
// Use larger wordlist for known targets
if (target.includes(".com") || target.includes(".org")) {
@@ -90,7 +90,7 @@ steps:
- name: log-statistics
type: function
script: |
var count = fileLength("{{all_endpoints}}");
var count = file_length("{{all_endpoints}}");
log_info("Total unique endpoints discovered: " + count);
if (count == 0) {
@@ -105,7 +105,7 @@ steps:
# Step 6: foreach - Probe each endpoint for parameters
- name: parameter-discovery
type: foreach
pre_condition: "fileLength('{{all_endpoints}}') > 0"
pre_condition: "file_length('{{all_endpoints}}') > 0"
input: "{{all_endpoints}}"
variable: endpoint
threads: "{{threads}}"
+6 -6
View File
@@ -52,7 +52,7 @@ steps:
- name: determine-strategy
type: function
script: |
var fileCount = fileLength("{{file_list}}");
var fileCount = file_length("{{file_list}}");
log_info("Files to process: " + fileCount);
if (fileCount == 0) {
@@ -158,11 +158,11 @@ steps:
log_info("Deduplicating aggregated data");
var txtFile = "{{aggregated_dir}}/all-txt.txt";
if (fileExists(txtFile)) {
var lineCount = fileLength(txtFile);
if (file_exists(txtFile)) {
var lineCount = file_length(txtFile);
log_info("Text entries before dedup: " + lineCount);
sortUnix(txtFile);
var newCount = fileLength(txtFile);
sort_unix(txtFile);
var newCount = file_length(txtFile);
log_info("Text entries after dedup: " + newCount);
}
@@ -215,7 +215,7 @@ steps:
script: |
var stats = {
processing_mode: "{{processing_mode}}",
files_processed: fileLength("{{file_list}}"),
files_processed: file_length("{{file_list}}"),
dedup_enabled: "{{enable_dedup}}" === "true",
output_format: "{{output_format}}",
completion_time: timestamp()
+7 -7
View File
@@ -59,7 +59,7 @@ modules:
- name: vuln-scan
depends_on:
- recon
condition: "fileLength('{{all_subdomains}}') > 0"
condition: "file_length('{{all_subdomains}}') > 0"
steps:
- name: init-vulns
type: bash
@@ -121,18 +121,18 @@ modules:
scan_depth: "{{scan_depth}}",
timestamp: timestamp(),
statistics: {
subdomains: fileLength("{{all_subdomains}}"),
http_hosts: fileLength("{{http_hosts}}"),
subdomains: file_length("{{all_subdomains}}"),
http_hosts: file_length("{{http_hosts}}"),
critical_findings: 0,
medium_findings: 0
}
};
if (fileExists("{{critical_vulns}}")) {
summary.statistics.critical_findings = fileLength("{{critical_vulns}}");
if (file_exists("{{critical_vulns}}")) {
summary.statistics.critical_findings = file_length("{{critical_vulns}}");
}
if (fileExists("{{medium_vulns}}")) {
summary.statistics.medium_findings = fileLength("{{medium_vulns}}");
if (file_exists("{{medium_vulns}}")) {
summary.statistics.medium_findings = file_length("{{medium_vulns}}");
}
log_info("Assessment Summary:");
+1 -1
View File
@@ -22,7 +22,7 @@ steps:
- name: httpx-fingerprint
type: bash
pre_condition: "fileExists('{{httpFile}}')"
pre_condition: "file_exists('{{httpFile}}')"
command: >
cat {{httpFile}} | {{Binaries}}/httpx -H '{{defaultUA}}' -timeout {{httpTimeout}}
-t {{httpThreads}} -no-fallback -no-color -silent -json -title -favicon
+2 -2
View File
@@ -70,7 +70,7 @@ steps:
- name: analyze-results
type: function
script: |
var portCount = fileLength("{{open_ports}}");
var portCount = file_length("{{open_ports}}");
log_info("Total open ports found: " + portCount);
if (portCount == 0) {
return "no_ports";
@@ -108,7 +108,7 @@ steps:
# Step 7: bash - Batch service detection for many ports
- name: batch-service-detection
type: bash
pre_condition: "fileLength('{{open_ports}}') > 100"
pre_condition: "file_length('{{open_ports}}') > 100"
command: "{{Binaries}}/nmap -sV --version-intensity 5 -iL {{open_ports}} -oN {{services_dir}}/batch-scan.txt"
timeout: 7200
exports:
+9 -9
View File
@@ -33,13 +33,13 @@ steps:
var urls = [];
// Check if target is a file or single URL
if (fileExists(target)) {
if (file_exists(target)) {
log_info("Target is a file, reading URLs");
var content = readFile(target);
var content = read_file(target);
urls = content.trim().split("\n").filter(function(u) { return u.length > 0; });
} else {
// Ensure URL has protocol
if (!target.startsWith("http")) {
if (!target.starts_with("http")) {
target = "https://" + target;
}
urls = [target];
@@ -56,7 +56,7 @@ steps:
# Step 3: bash with pre_condition - Quick probe to filter live URLs
- name: probe-live-urls
type: bash
pre_condition: "fileExists('{{url_list}}')"
pre_condition: "file_exists('{{url_list}}')"
command: "{{Binaries}}/httpx -l {{url_list}} -silent -mc 200,201,301,302,307,401,403 -o {{Output}}/live-urls.txt"
timeout: 600
on_error: continue
@@ -66,9 +66,9 @@ steps:
# Step 4: function - Check live URL count before proceeding
- name: validate-live-urls
type: function
pre_condition: "fileExists('{{live_urls}}')"
pre_condition: "file_exists('{{live_urls}}')"
script: |
var count = fileLength("{{live_urls}}");
var count = file_length("{{live_urls}}");
log_info("Live URLs found: " + count);
if (count == 0) {
@@ -83,7 +83,7 @@ steps:
# Step 5: foreach - Capture screenshots of each URL
- name: capture-screenshots
type: foreach
pre_condition: "fileExists('{{live_urls}}') && fileLength('{{live_urls}}') > 0"
pre_condition: "file_exists('{{live_urls}}') && file_length('{{live_urls}}') > 0"
input: "{{live_urls}}"
variable: url
threads: "{{threads}}"
@@ -128,8 +128,8 @@ steps:
type: function
script: |
var stats = {
total_urls: parseInt("{{url_count}}"),
live_urls: fileLength("{{live_urls}}"),
total_urls: parse_int("{{url_count}}"),
live_urls: file_length("{{live_urls}}"),
screenshots: 0,
thumbnails: 0
};
+3 -3
View File
@@ -27,7 +27,7 @@ steps:
type: function
script: |
log_info("Starting subdomain enumeration for: {{Target}}");
if (isEmpty("{{Target}}")) {
if (is_empty("{{Target}}")) {
log_error("Target is empty");
return false;
}
@@ -61,7 +61,7 @@ steps:
- name: check-results
type: function
script: |
var count = fileLength("{{all_subdomains}}");
var count = file_length("{{all_subdomains}}");
log_info("Found " + count + " unique subdomains");
if (count == 0) {
log_warn("No subdomains found, trying bruteforce");
@@ -73,7 +73,7 @@ steps:
# Step 6: bash with pre_condition - Active bruteforce if passive found few results
- name: active-bruteforce
type: bash
pre_condition: "fileLength('{{all_subdomains}}') < 50"
pre_condition: "file_length('{{all_subdomains}}') < 50"
command: "{{Binaries}}/puredns bruteforce {{wordlist}} {{Target}} -r {{resolvers}} -w {{subdomain_dir}}/bruteforce.txt"
timeout: 1800
on_error: continue
@@ -39,7 +39,7 @@ steps:
log_info(" Severity: {{severity}}");
log_info(" Threads: {{threads}}");
if (!fileExists("{{templates_path}}")) {
if (!file_exists("{{templates_path}}")) {
log_warn("Templates path not found, using default");
}
return true;
@@ -71,7 +71,7 @@ steps:
# Step 5: foreach - Check each finding for exploitability
- name: verify-findings
type: foreach
pre_condition: "fileExists('{{nuclei_results}}')"
pre_condition: "file_exists('{{nuclei_results}}')"
input: "{{nuclei_results}}"
variable: finding
threads: 5
@@ -111,8 +111,8 @@ steps:
var high = 0;
var medium = 0;
if (fileExists("{{nuclei_results}}")) {
var content = readFile("{{nuclei_results}}");
if (file_exists("{{nuclei_results}}")) {
var content = read_file("{{nuclei_results}}");
critical = (content.match(/critical/gi) || []).length;
high = (content.match(/high/gi) || []).length;
medium = (content.match(/medium/gi) || []).length;
+3 -3
View File
@@ -46,7 +46,7 @@ modules:
- name: scanning
depends_on:
- discovery
condition: "fileLength('{{all_endpoints}}') > 0"
condition: "file_length('{{all_endpoints}}') > 0"
steps:
- name: init-scanning
type: bash
@@ -95,8 +95,8 @@ modules:
var findings = [];
var nucleiFile = "{{nuclei_results}}";
if (fileExists(nucleiFile)) {
var content = readFile(nucleiFile);
if (file_exists(nucleiFile)) {
var content = read_file(nucleiFile);
var lines = content.split("\n").filter(function(l) { return l.trim().length > 0; });
findings = lines.map(function(l) {
try { return JSON.parse(l); } catch(e) { return {raw: l}; }
+21 -21
View File
@@ -45,8 +45,8 @@ steps:
- name: validate-dependencies
type: function
function: |
fileExists("{{Binaries}}/jaeles") &&
fileExists("{{Binaries}}/nuclei")
file_exists("{{Binaries}}/jaeles") &&
file_exists("{{Binaries}}/nuclei")
exports:
deps_valid: "output"
on_error:
@@ -71,7 +71,7 @@ steps:
# ============================================================
- name: check-input-exists
type: function
function: fileExists("{{httpFile}}")
function: file_exists("{{httpFile}}")
exports:
input_exists: "output"
on_error:
@@ -81,7 +81,7 @@ steps:
- name: count-input-lines
type: function
function: fileLength("{{httpFile}}")
function: file_length("{{httpFile}}")
exports:
input_count: "output"
@@ -89,8 +89,8 @@ steps:
- name: check-input-limit
type: function
function: |
var count = parseInt("{{input_count}}");
var limit = parseInt("{{limit}}");
var count = parse_int("{{input_count}}");
var limit = parse_int("{{limit}}");
if (count > limit) {
return "exceeds_limit";
}
@@ -128,7 +128,7 @@ steps:
- name: count-split-files
type: function
function: fileLength("{{output_dir}}/raw/split-files.txt")
function: file_length("{{output_dir}}/raw/split-files.txt")
exports:
split_count: "output"
@@ -137,7 +137,7 @@ steps:
# ============================================================
- name: jaeles-active-scan
type: foreach
pre_condition: 'parseInt("{{split_count}}") > 0'
pre_condition: 'parse_int("{{split_count}}") > 0'
input: "{{output_dir}}/raw/split-files.txt"
variable: splitfile
threads: 1
@@ -151,7 +151,7 @@ steps:
- name: jaeles-sensitive-scan
type: foreach
pre_condition: 'parseInt("{{split_count}}") > 0'
pre_condition: 'parse_int("{{split_count}}") > 0'
input: "{{output_dir}}/raw/split-files.txt"
variable: splitfile
threads: 1
@@ -186,14 +186,14 @@ steps:
# ============================================================
- name: copy-active-summary
type: bash
pre_condition: 'fileExists("{{output_dir}}/active/jaeles-summary.txt")'
pre_condition: 'file_exists("{{output_dir}}/active/jaeles-summary.txt")'
command: "cp {{output_dir}}/active/jaeles-summary.txt {{output_dir}}/active/activescan-{{Workspace}}-{{TS}}.txt"
exports:
active_summary: "{{output_dir}}/active/activescan-{{Workspace}}-{{TS}}.txt"
- name: notify-active-results
type: function
pre_condition: 'fileExists("{{output_dir}}/active/activescan-{{Workspace}}-{{TS}}.txt")'
pre_condition: 'file_exists("{{output_dir}}/active/activescan-{{Workspace}}-{{TS}}.txt")'
parallel_functions:
- TeleMessByFile("#report", "{{output_dir}}/active/activescan-{{Workspace}}-{{TS}}.txt")
- Cat("{{output_dir}}/active/activescan-{{Workspace}}-{{TS}}.txt")
@@ -205,14 +205,14 @@ steps:
- name: copy-sensitive-summary
type: bash
pre_condition: 'fileExists("{{output_dir}}/sensitive/jaeles-summary.txt")'
pre_condition: 'file_exists("{{output_dir}}/sensitive/jaeles-summary.txt")'
command: "cp {{output_dir}}/sensitive/jaeles-summary.txt {{output_dir}}/sensitive/sensitivescan-{{Workspace}}-{{TS}}.txt"
exports:
sensitive_summary: "{{output_dir}}/sensitive/sensitivescan-{{Workspace}}-{{TS}}.txt"
- name: notify-sensitive-results
type: function
pre_condition: 'fileExists("{{output_dir}}/sensitive/sensitivescan-{{Workspace}}-{{TS}}.txt")'
pre_condition: 'file_exists("{{output_dir}}/sensitive/sensitivescan-{{Workspace}}-{{TS}}.txt")'
parallel_functions:
- TeleMessByFile("#sensitive", "{{output_dir}}/sensitive/sensitivescan-{{Workspace}}-{{TS}}.txt")
- Cat("{{output_dir}}/sensitive/sensitivescan-{{Workspace}}-{{TS}}.txt")
@@ -227,7 +227,7 @@ steps:
# ============================================================
- name: nuclei-scan
type: bash
pre_condition: '"{{enableNuclei}}" == "true" && fileExists("{{httpFile}}")'
pre_condition: '"{{enableNuclei}}" == "true" && file_exists("{{httpFile}}")'
command: |
timeout -k 1m {{nucleiTimeout}} {{Binaries}}/nuclei \
-H '{{defaultUA}}' \
@@ -249,8 +249,8 @@ steps:
- name: count-nuclei-results
type: function
pre_condition: 'fileExists("{{output_dir}}/nuclei/{{Workspace}}-nuclei-json.txt")'
function: fileLength("{{output_dir}}/nuclei/{{Workspace}}-nuclei-json.txt")
pre_condition: 'file_exists("{{output_dir}}/nuclei/{{Workspace}}-nuclei-json.txt")'
function: file_length("{{output_dir}}/nuclei/{{Workspace}}-nuclei-json.txt")
exports:
nuclei_count: "output"
@@ -259,7 +259,7 @@ steps:
# ============================================================
- name: generate-nuclei-report
type: function
pre_condition: 'parseInt("{{nuclei_count}}") > 0'
pre_condition: 'parse_int("{{nuclei_count}}") > 0'
function: GenNucleiReport("{{output_dir}}/nuclei/{{Workspace}}-nuclei-json.txt", "{{output_dir}}/nuclei/{{Workspace}}-nuclei.html")
on_error:
- action: log
@@ -268,7 +268,7 @@ steps:
- name: parse-nuclei-json
type: bash
pre_condition: 'parseInt("{{nuclei_count}}") > 0'
pre_condition: 'parse_int("{{nuclei_count}}") > 0'
command: |
cat {{output_dir}}/nuclei/{{Workspace}}-nuclei-json.txt | \
jq -r '[.info.severity,.\"template-id\",.\"matched-at\",.\"matched-name\"] | join(\" - \")' \
@@ -278,12 +278,12 @@ steps:
- name: sort-nuclei-results
type: function
pre_condition: 'fileExists("{{output_dir}}/nuclei/{{Workspace}}-nuclei-scan.txt")'
pre_condition: 'file_exists("{{output_dir}}/nuclei/{{Workspace}}-nuclei-scan.txt")'
function: SortU("{{output_dir}}/nuclei/{{Workspace}}-nuclei-scan.txt")
- name: notify-nuclei-results
type: function
pre_condition: 'parseInt("{{nuclei_count}}") > 0'
pre_condition: 'parse_int("{{nuclei_count}}") > 0'
parallel_functions:
- TeleMessByFile("#sensitive", "{{output_dir}}/nuclei/{{Workspace}}-nuclei-scan.txt")
- Cat("{{output_dir}}/nuclei/{{Workspace}}-nuclei-scan.txt")
@@ -297,7 +297,7 @@ steps:
# ============================================================
- name: generate-final-report
type: function
pre_condition: 'fileExists("{{Data}}/markdown/general-template.md")'
pre_condition: 'file_exists("{{Data}}/markdown/general-template.md")'
function: GenMarkdownReport("{{Data}}/markdown/general-template.md", "{{Output}}/summary.html")
on_error:
- action: log
+11 -11
View File
@@ -37,9 +37,9 @@ steps:
- name: validate-dependencies
type: function
function: |
fileExists("{{Binaries}}/subfinder") &&
fileExists("{{Binaries}}/assetfinder") &&
fileExists("{{Binaries}}/httpx")
file_exists("{{Binaries}}/subfinder") &&
file_exists("{{Binaries}}/assetfinder") &&
file_exists("{{Binaries}}/httpx")
exports:
deps_valid: "output"
on_error:
@@ -90,7 +90,7 @@ steps:
- name: count-subdomains
type: function
function: |
var count = fileLength("{{subdomains_file}}");
var count = file_length("{{subdomains_file}}");
return count > 0 ? "true" : "false";
exports:
subdomain_count: "{{Result}}"
@@ -125,14 +125,14 @@ steps:
- name: fallback-probing
type: bash
pre_condition: "!fileExists('{{Output}}/web-recon/probing/live-{{Workspace}}.txt')"
pre_condition: "!file_exists('{{Output}}/web-recon/probing/live-{{Workspace}}.txt')"
command: "cat {{subdomains_file}} | xargs -I {} curl -s -o /dev/null -w '%{http_code} {}\\n' http://{} 2>/dev/null | grep '^200' | awk '{print $2}' > {{Output}}/web-recon/probing/live-{{Workspace}}.txt"
exports:
live_hosts_file: "{{Output}}/web-recon/probing/live-{{Workspace}}.txt"
- name: count-live-hosts
type: function
function: fileLength("{{live_hosts_file}}")
function: file_length("{{live_hosts_file}}")
exports:
live_host_count: "output"
@@ -145,7 +145,7 @@ steps:
# Screenshot capture using Docker
- name: capture-screenshots
type: remote-bash
pre_condition: '"{{enableScreenshots}}" == "true" && parseInt("{{live_host_count}}") > 0'
pre_condition: '"{{enableScreenshots}}" == "true" && parse_int("{{live_host_count}}") > 0'
step_runner: docker
step_runner_config:
image: projectdiscovery/katana:latest
@@ -166,7 +166,7 @@ steps:
# Nuclei vulnerability scanning using Docker
- name: nuclei-scan
type: remote-bash
pre_condition: '"{{enableNuclei}}" == "true" && parseInt("{{live_host_count}}") > 0'
pre_condition: '"{{enableNuclei}}" == "true" && parse_int("{{live_host_count}}") > 0'
step_runner: docker
step_runner_config:
image: projectdiscovery/nuclei:latest
@@ -195,7 +195,7 @@ steps:
# ============================================================
- name: detailed-host-analysis
type: foreach
pre_condition: 'parseInt("{{live_host_count}}") > 0 && parseInt("{{live_host_count}}") < 50'
pre_condition: 'parse_int("{{live_host_count}}") > 0 && parse_int("{{live_host_count}}") < 50'
input: "{{live_hosts_file}}"
variable: host
threads: 5
@@ -213,7 +213,7 @@ steps:
# ============================================================
- name: process-nuclei-results
type: function
pre_condition: 'fileExists("{{Output}}/web-recon/nuclei/results-{{Workspace}}.json")'
pre_condition: 'file_exists("{{Output}}/web-recon/nuclei/results-{{Workspace}}.json")'
parallel_functions:
- db_vuln_critical("{{Output}}/web-recon/nuclei/results-{{Workspace}}.json")
- db_vuln_high("{{Output}}/web-recon/nuclei/results-{{Workspace}}.json")
@@ -259,5 +259,5 @@ steps:
- name: notify-completion
type: function
pre_condition: 'parseInt("{{subdomain_count}}") > 0'
pre_condition: 'parse_int("{{subdomain_count}}") > 0'
function: printf("Scan complete: {{subdomain_count}} subdomains, {{live_host_count}} live hosts")