mirror of
https://github.com/j3ssie/osmedeus.git
synced 2026-09-27 12:04:54 +02:00
feat: add inline module support and improve version output
- Add inline module support to ModuleRef allowing modules to be defined directly in flows without external files - Implement IsInline() and ToWorkflow() methods to convert inline ModuleRef definitions to executable workflows - Update ModuleRef.Clone() to properly duplicate all fields including Steps, Runner, RunnerConfig, and Description - Add field alignment formatting and make path optional for inline modules - Enhance parser validation to allow omitting path for inline modules while requiring at least one step - Update executor's preloadModules() and ExecuteFlow() to handle inline modules during flow execution - Improve version command output with JSON format support via --json flag and enhanced colored terminal output
This commit is contained in:
+15
-3
@@ -219,9 +219,11 @@ func (m *ModuleRef) Clone() *ModuleRef {
|
||||
}
|
||||
|
||||
cloned := &ModuleRef{
|
||||
Name: m.Name,
|
||||
Path: m.Path,
|
||||
Condition: m.Condition,
|
||||
Name: m.Name,
|
||||
Path: m.Path,
|
||||
Condition: m.Condition,
|
||||
Runner: m.Runner,
|
||||
Description: m.Description,
|
||||
}
|
||||
|
||||
if len(m.Params) > 0 {
|
||||
@@ -252,6 +254,16 @@ func (m *ModuleRef) Clone() *ModuleRef {
|
||||
|
||||
cloned.Decision = m.Decision.Clone()
|
||||
|
||||
// Clone inline module fields
|
||||
if len(m.Steps) > 0 {
|
||||
cloned.Steps = make([]Step, len(m.Steps))
|
||||
for i, s := range m.Steps {
|
||||
cloned.Steps[i] = *s.Clone()
|
||||
}
|
||||
}
|
||||
|
||||
cloned.RunnerConfig = m.RunnerConfig.Clone()
|
||||
|
||||
return cloned
|
||||
}
|
||||
|
||||
|
||||
@@ -78,16 +78,42 @@ type RunnerConfig struct {
|
||||
WorkDir string `yaml:"workdir,omitempty"` // Working directory on remote/container
|
||||
}
|
||||
|
||||
// ModuleRef references a module in a flow
|
||||
// ModuleRef references a module in a flow or defines an inline module
|
||||
type ModuleRef struct {
|
||||
Name string `yaml:"name"`
|
||||
Path string `yaml:"path"`
|
||||
Path string `yaml:"path,omitempty"` // Path to external module file (omit for inline)
|
||||
Params map[string]string `yaml:"params"`
|
||||
DependsOn []string `yaml:"depends_on"`
|
||||
Condition string `yaml:"condition"`
|
||||
OnSuccess []Action `yaml:"on_success"`
|
||||
OnError []Action `yaml:"on_error"`
|
||||
Decision *DecisionConfig `yaml:"decision"`
|
||||
|
||||
// Inline module fields (used when Path is empty)
|
||||
Steps []Step `yaml:"steps,omitempty"` // Inline steps (makes this an inline module)
|
||||
Runner RunnerType `yaml:"runner,omitempty"` // Runner type for inline module
|
||||
RunnerConfig *RunnerConfig `yaml:"runner_config,omitempty"` // Runner configuration for inline module
|
||||
Description string `yaml:"description,omitempty"` // Description for inline module
|
||||
}
|
||||
|
||||
// IsInline returns true if this is an inline module (has steps defined directly)
|
||||
func (m *ModuleRef) IsInline() bool {
|
||||
return len(m.Steps) > 0
|
||||
}
|
||||
|
||||
// ToWorkflow converts an inline ModuleRef to a Workflow for execution
|
||||
func (m *ModuleRef) ToWorkflow() *Workflow {
|
||||
if !m.IsInline() {
|
||||
return nil
|
||||
}
|
||||
return &Workflow{
|
||||
Kind: KindModule,
|
||||
Name: m.Name,
|
||||
Description: m.Description,
|
||||
Steps: m.Steps,
|
||||
Runner: m.Runner,
|
||||
RunnerConfig: m.RunnerConfig,
|
||||
}
|
||||
}
|
||||
|
||||
// IsModule returns true if the workflow is a module
|
||||
|
||||
@@ -1338,6 +1338,15 @@ func (e *Executor) preloadModules(ctx context.Context, modules []core.ModuleRef)
|
||||
|
||||
for i := range modules {
|
||||
modRef := &modules[i]
|
||||
|
||||
// Skip inline modules - they don't need loading from disk
|
||||
if modRef.IsInline() {
|
||||
mu.Lock()
|
||||
result[modRef.Name] = modRef.ToWorkflow()
|
||||
mu.Unlock()
|
||||
continue
|
||||
}
|
||||
|
||||
wg.Add(1)
|
||||
go func(ref *core.ModuleRef) {
|
||||
defer wg.Done()
|
||||
@@ -1652,17 +1661,27 @@ func (e *Executor) ExecuteFlow(ctx context.Context, flow *core.Workflow, params
|
||||
}
|
||||
|
||||
// Execute module
|
||||
execCtx.Logger.Info("Executing module",
|
||||
zap.String("module", modRef.Name),
|
||||
zap.String("path", modRef.Path),
|
||||
)
|
||||
if modRef.IsInline() {
|
||||
execCtx.Logger.Info("Executing inline module",
|
||||
zap.String("module", modRef.Name),
|
||||
)
|
||||
} else {
|
||||
execCtx.Logger.Info("Executing module",
|
||||
zap.String("module", modRef.Name),
|
||||
zap.String("path", modRef.Path),
|
||||
)
|
||||
}
|
||||
|
||||
// Use preloaded module if available, else load on-demand
|
||||
// Use preloaded module if available, else load on-demand or use inline
|
||||
var module *core.Workflow
|
||||
var err error
|
||||
if preloadedMod, ok := preloaded[modRef.Name]; ok {
|
||||
module = preloadedMod
|
||||
execCtx.Logger.Debug("Using preloaded module", zap.String("module", modRef.Name))
|
||||
} else if modRef.IsInline() {
|
||||
// Use inline module definition
|
||||
module = modRef.ToWorkflow()
|
||||
execCtx.Logger.Debug("Using inline module", zap.String("module", modRef.Name))
|
||||
} else {
|
||||
// Load the module workflow on-demand (fallback for failed preloads)
|
||||
module, err = e.loader.LoadWorkflowByPath(modRef.Path)
|
||||
|
||||
@@ -125,10 +125,18 @@ func (p *Parser) validateFlow(w *core.Workflow) error {
|
||||
Message: "module reference name is required",
|
||||
}
|
||||
}
|
||||
if mod.Path == "" {
|
||||
// Path is required only for external modules (not inline modules)
|
||||
if mod.Path == "" && !mod.IsInline() {
|
||||
return &ValidationError{
|
||||
Field: fmt.Sprintf("modules[%d].path", i),
|
||||
Message: "module reference path is required",
|
||||
Message: "module reference path is required (or define inline steps)",
|
||||
}
|
||||
}
|
||||
// Inline modules must have at least one step
|
||||
if mod.IsInline() && len(mod.Steps) == 0 {
|
||||
return &ValidationError{
|
||||
Field: fmt.Sprintf("modules[%d].steps", i),
|
||||
Message: "inline module must have at least one step",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-6
@@ -1,6 +1,7 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
@@ -452,12 +453,41 @@ var versionCmd = &cobra.Command{
|
||||
Use: "version",
|
||||
Short: "Print version information",
|
||||
Run: func(cmd *cobra.Command, args []string) {
|
||||
fmt.Printf("%s - %s\n", core.BINARY, core.DESC)
|
||||
fmt.Printf("Version: %s\n", core.VERSION)
|
||||
fmt.Printf("Build: %s\n", buildTime)
|
||||
fmt.Printf("Commit: %s\n", commitHash)
|
||||
fmt.Printf("Author: %s\n", core.AUTHOR)
|
||||
fmt.Printf("Docs: %s\n", core.DOCS)
|
||||
if globalJSON {
|
||||
// JSON output
|
||||
versionInfo := map[string]string{
|
||||
"name": core.BINARY,
|
||||
"description": core.DESC,
|
||||
"version": core.VERSION,
|
||||
"build": buildTime,
|
||||
"commit": commitHash,
|
||||
"author": core.AUTHOR,
|
||||
"docs": core.DOCS,
|
||||
}
|
||||
jsonOut, _ := json.MarshalIndent(versionInfo, "", " ")
|
||||
fmt.Println(string(jsonOut))
|
||||
return
|
||||
}
|
||||
|
||||
// Colored output
|
||||
fmt.Printf("%s - %s\n",
|
||||
terminal.BoldCyan(core.BINARY),
|
||||
terminal.HiBlue(core.DESC))
|
||||
fmt.Printf("%s %s\n",
|
||||
terminal.Bold("Version:"),
|
||||
terminal.Green(core.VERSION))
|
||||
fmt.Printf("%s %s\n",
|
||||
terminal.Bold("Build:"),
|
||||
terminal.Yellow(buildTime))
|
||||
fmt.Printf("%s %s\n",
|
||||
terminal.Bold("Commit:"),
|
||||
terminal.Cyan(commitHash))
|
||||
fmt.Printf("%s %s\n",
|
||||
terminal.Bold("Author:"),
|
||||
terminal.Magenta(core.AUTHOR))
|
||||
fmt.Printf("%s %s\n",
|
||||
terminal.Bold("Docs:"),
|
||||
terminal.Blue(core.DOCS))
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
-327
@@ -1,327 +0,0 @@
|
||||
name: vulnscan
|
||||
kind: module
|
||||
description: Run vulnerability scan on all HTTP hosts using Jaeles and Nuclei scanners
|
||||
|
||||
params:
|
||||
- name: target
|
||||
required: true
|
||||
- name: httpFile
|
||||
default: "{{Output}}/probing/http-{{TargetSpace}}.txt"
|
||||
- name: output_dir
|
||||
default: "{{Output}}/vuln"
|
||||
- name: sign
|
||||
default: "~/.jaeles/base-signatures/cves/.*"
|
||||
- name: sign2
|
||||
default: "~/.jaeles/base-signatures/common/.*"
|
||||
- name: sign3
|
||||
default: "~/.jaeles/base-signatures/sensitive/.*"
|
||||
- name: splitLines
|
||||
default: "500"
|
||||
- name: limit
|
||||
default: "25000"
|
||||
- name: extra
|
||||
default: " "
|
||||
- name: enableNuclei
|
||||
default: "true"
|
||||
- name: threads
|
||||
default: "10"
|
||||
- name: nucleiThreads
|
||||
default: "{{threads * 10}}"
|
||||
- name: jaelesThreads
|
||||
default: "{{threads * 5}}"
|
||||
- name: nucleiTimeout
|
||||
default: "8h"
|
||||
- name: jaelesTimeout
|
||||
default: "3h"
|
||||
- name: nucleiSeverity
|
||||
default: "critical,high,medium,low,info"
|
||||
- name: defaultUA
|
||||
default: "User-Agent: Mozilla/5.0 (compatible; Osmedeus/v4; +https://github.com/j3ssie/osmedeus)"
|
||||
|
||||
steps:
|
||||
# ============================================================
|
||||
# Phase 1: Validate Dependencies
|
||||
# ============================================================
|
||||
- name: validate-dependencies
|
||||
type: function
|
||||
function: |
|
||||
file_exists("{{Binaries}}/jaeles") &&
|
||||
file_exists("{{Binaries}}/nuclei")
|
||||
exports:
|
||||
deps_valid: "output"
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Required binaries (jaeles, nuclei) not found"
|
||||
- action: abort
|
||||
|
||||
# ============================================================
|
||||
# Phase 2: Setup Output Directories
|
||||
# ============================================================
|
||||
- name: setup-directories
|
||||
type: bash
|
||||
commands:
|
||||
- mkdir -p {{output_dir}}
|
||||
- mkdir -p {{output_dir}}/raw
|
||||
- mkdir -p {{output_dir}}/active
|
||||
- mkdir -p {{output_dir}}/sensitive
|
||||
- mkdir -p {{output_dir}}/nuclei
|
||||
|
||||
# ============================================================
|
||||
# Phase 3: Validate Input File
|
||||
# ============================================================
|
||||
- name: check-input-exists
|
||||
type: function
|
||||
function: file_exists("{{httpFile}}")
|
||||
exports:
|
||||
input_exists: "output"
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Input file {{httpFile}} not found"
|
||||
- action: abort
|
||||
|
||||
- name: count-input-lines
|
||||
type: function
|
||||
function: file_length("{{httpFile}}")
|
||||
exports:
|
||||
input_count: "output"
|
||||
|
||||
# Decision: Abort if input file exceeds limit
|
||||
- name: check-input-limit
|
||||
type: function
|
||||
function: |
|
||||
var count = parse_int("{{input_count}}");
|
||||
var limit = parse_int("{{limit}}");
|
||||
if (count > limit) {
|
||||
return "exceeds_limit";
|
||||
}
|
||||
return "valid";
|
||||
exports:
|
||||
input_valid: "{{Result}}"
|
||||
decision:
|
||||
switch: "{{input_valid}}"
|
||||
cases:
|
||||
"exceeds_limit":
|
||||
goto: abort-large-input
|
||||
default:
|
||||
goto: split-input-file
|
||||
|
||||
- name: abort-large-input
|
||||
type: function
|
||||
function: printf("ERROR: Input file has {{input_count}} lines, exceeds limit of {{limit}}")
|
||||
on_error:
|
||||
- action: abort
|
||||
|
||||
# ============================================================
|
||||
# Phase 4: Split Input for Parallel Processing
|
||||
# ============================================================
|
||||
- name: split-input-file
|
||||
type: function
|
||||
function: SplitFile("{{httpFile}}", "{{TargetSpace}}-index", {{splitLines}}, "{{output_dir}}/raw")
|
||||
exports:
|
||||
split_dir: "{{output_dir}}/raw"
|
||||
|
||||
- name: list-split-files
|
||||
type: bash
|
||||
command: "ls {{output_dir}}/raw/{{TargetSpace}}-index* 2>/dev/null | head -100 > {{output_dir}}/raw/split-files.txt || touch {{output_dir}}/raw/split-files.txt"
|
||||
exports:
|
||||
split_files: "{{output_dir}}/raw/split-files.txt"
|
||||
|
||||
- name: count-split-files
|
||||
type: function
|
||||
function: file_length("{{output_dir}}/raw/split-files.txt")
|
||||
exports:
|
||||
split_count: "output"
|
||||
|
||||
# ============================================================
|
||||
# Phase 5: Jaeles Vulnerability Scanning
|
||||
# ============================================================
|
||||
- name: jaeles-active-scan
|
||||
type: foreach
|
||||
pre_condition: 'parse_int("{{split_count}}") > 0'
|
||||
input: "{{output_dir}}/raw/split-files.txt"
|
||||
variable: splitfile
|
||||
threads: 1
|
||||
step:
|
||||
name: run-jaeles-active
|
||||
type: bash
|
||||
command: |
|
||||
echo "Running Jaeles active scan on [[splitfile]]..."
|
||||
timeout -k 1m {{jaelesTimeout}} {{Binaries}}/jaeles scan -c {{jaelesThreads}} -s '{{sign}}' -s '{{sign2}}' -U [[splitfile]] -o {{output_dir}}/active/ {{extra}} 2>/dev/null || true
|
||||
timeout: 14400
|
||||
|
||||
- name: jaeles-sensitive-scan
|
||||
type: foreach
|
||||
pre_condition: 'parse_int("{{split_count}}") > 0'
|
||||
input: "{{output_dir}}/raw/split-files.txt"
|
||||
variable: splitfile
|
||||
threads: 1
|
||||
step:
|
||||
name: run-jaeles-sensitive
|
||||
type: bash
|
||||
command: |
|
||||
echo "Running Jaeles sensitive scan on [[splitfile]]..."
|
||||
timeout -k 1m {{jaelesTimeout}} {{Binaries}}/jaeles scan --fi -c {{jaelesThreads}} -s '{{sign3}}' -L 2 -U [[splitfile]] -o {{output_dir}}/sensitive/ {{extra}} 2>/dev/null || true
|
||||
timeout: 14400
|
||||
|
||||
# ============================================================
|
||||
# Phase 6: Generate Jaeles Reports
|
||||
# ============================================================
|
||||
- name: generate-jaeles-reports
|
||||
type: parallel-steps
|
||||
parallel_steps:
|
||||
- name: generate-active-report
|
||||
type: bash
|
||||
command: "{{Binaries}}/jaeles report -o {{output_dir}}/active/ -R {{output_dir}}/active/{{TargetSpace}}-report.html 2>/dev/null || true"
|
||||
on_error:
|
||||
- action: continue
|
||||
|
||||
- name: generate-sensitive-report
|
||||
type: bash
|
||||
command: "{{Binaries}}/jaeles report -o {{output_dir}}/sensitive/ -R {{output_dir}}/sensitive/{{TargetSpace}}-sensitive.html 2>/dev/null || true"
|
||||
on_error:
|
||||
- action: continue
|
||||
|
||||
# ============================================================
|
||||
# Phase 7: Process Jaeles Results
|
||||
# ============================================================
|
||||
- name: copy-active-summary
|
||||
type: bash
|
||||
pre_condition: 'file_exists("{{output_dir}}/active/jaeles-summary.txt")'
|
||||
command: "cp {{output_dir}}/active/jaeles-summary.txt {{output_dir}}/active/activescan-{{TargetSpace}}-{{TS}}.txt"
|
||||
exports:
|
||||
active_summary: "{{output_dir}}/active/activescan-{{TargetSpace}}-{{TS}}.txt"
|
||||
|
||||
- name: notify-active-results
|
||||
type: function
|
||||
pre_condition: 'file_exists("{{output_dir}}/active/activescan-{{TargetSpace}}-{{TS}}.txt")'
|
||||
parallel_functions:
|
||||
- TeleMessByFile("#report", "{{output_dir}}/active/activescan-{{TargetSpace}}-{{TS}}.txt")
|
||||
- Cat("{{output_dir}}/active/activescan-{{TargetSpace}}-{{TS}}.txt")
|
||||
- TotalVulnerability("{{output_dir}}/active/activescan-{{TargetSpace}}-{{TS}}.txt")
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Failed to notify active scan results"
|
||||
- action: continue
|
||||
|
||||
- name: copy-sensitive-summary
|
||||
type: bash
|
||||
pre_condition: 'file_exists("{{output_dir}}/sensitive/jaeles-summary.txt")'
|
||||
command: "cp {{output_dir}}/sensitive/jaeles-summary.txt {{output_dir}}/sensitive/sensitivescan-{{TargetSpace}}-{{TS}}.txt"
|
||||
exports:
|
||||
sensitive_summary: "{{output_dir}}/sensitive/sensitivescan-{{TargetSpace}}-{{TS}}.txt"
|
||||
|
||||
- name: notify-sensitive-results
|
||||
type: function
|
||||
pre_condition: 'file_exists("{{output_dir}}/sensitive/sensitivescan-{{TargetSpace}}-{{TS}}.txt")'
|
||||
parallel_functions:
|
||||
- TeleMessByFile("#sensitive", "{{output_dir}}/sensitive/sensitivescan-{{TargetSpace}}-{{TS}}.txt")
|
||||
- Cat("{{output_dir}}/sensitive/sensitivescan-{{TargetSpace}}-{{TS}}.txt")
|
||||
- TotalVulnerability("{{output_dir}}/sensitive/sensitivescan-{{TargetSpace}}-{{TS}}.txt")
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Failed to notify sensitive scan results"
|
||||
- action: continue
|
||||
|
||||
# ============================================================
|
||||
# Phase 8: Nuclei Vulnerability Scanning
|
||||
# ============================================================
|
||||
- name: nuclei-scan
|
||||
type: bash
|
||||
pre_condition: '"{{enableNuclei}}" == "true" && file_exists("{{httpFile}}")'
|
||||
command: |
|
||||
timeout -k 1m {{nucleiTimeout}} {{Binaries}}/nuclei \
|
||||
-H '{{defaultUA}}' \
|
||||
-silent \
|
||||
-c {{nucleiThreads}} \
|
||||
-jsonl \
|
||||
-severity '{{nucleiSeverity}}' \
|
||||
-t ~/nuclei-templates/ \
|
||||
-l {{httpFile}} \
|
||||
-irr \
|
||||
-o {{output_dir}}/nuclei/{{TargetSpace}}-nuclei-json.txt
|
||||
timeout: 28800
|
||||
exports:
|
||||
nuclei_json: "{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-json.txt"
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Nuclei scan failed or timed out"
|
||||
- action: continue
|
||||
|
||||
- name: count-nuclei-results
|
||||
type: function
|
||||
pre_condition: 'file_exists("{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-json.txt")'
|
||||
function: file_length("{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-json.txt")
|
||||
exports:
|
||||
nuclei_count: "output"
|
||||
|
||||
# ============================================================
|
||||
# Phase 9: Process Nuclei Results
|
||||
# ============================================================
|
||||
- name: generate-nuclei-report
|
||||
type: function
|
||||
pre_condition: 'parse_int("{{nuclei_count}}") > 0'
|
||||
function: GenNucleiReport("{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-json.txt", "{{output_dir}}/nuclei/{{TargetSpace}}-nuclei.html")
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Failed to generate Nuclei HTML report"
|
||||
- action: continue
|
||||
|
||||
- name: parse-nuclei-json
|
||||
type: bash
|
||||
pre_condition: 'parse_int("{{nuclei_count}}") > 0'
|
||||
command: |
|
||||
cat {{output_dir}}/nuclei/{{TargetSpace}}-nuclei-json.txt | \
|
||||
jq -r '[.info.severity,.\"template-id\",.\"matched-at\",.\"matched-name\"] | join(\" - \")' \
|
||||
> {{output_dir}}/nuclei/{{TargetSpace}}-nuclei-scan.txt 2>/dev/null || true
|
||||
exports:
|
||||
nuclei_parsed: "{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-scan.txt"
|
||||
|
||||
- name: sort-nuclei-results
|
||||
type: function
|
||||
pre_condition: 'file_exists("{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-scan.txt")'
|
||||
function: SortU("{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-scan.txt")
|
||||
|
||||
- name: notify-nuclei-results
|
||||
type: function
|
||||
pre_condition: 'parse_int("{{nuclei_count}}") > 0'
|
||||
parallel_functions:
|
||||
- TeleMessByFile("#sensitive", "{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-scan.txt")
|
||||
- Cat("{{output_dir}}/nuclei/{{TargetSpace}}-nuclei-scan.txt")
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Failed to notify Nuclei results"
|
||||
- action: continue
|
||||
|
||||
# ============================================================
|
||||
# Phase 10: Generate Final Report
|
||||
# ============================================================
|
||||
- name: generate-final-report
|
||||
type: function
|
||||
pre_condition: 'file_exists("{{Data}}/markdown/general-template.md")'
|
||||
function: GenMarkdownReport("{{Data}}/markdown/general-template.md", "{{Output}}/summary.html")
|
||||
on_error:
|
||||
- action: log
|
||||
message: "Final report generation skipped - template not found"
|
||||
- action: continue
|
||||
|
||||
- name: generate-vuln-summary
|
||||
type: bash
|
||||
commands:
|
||||
- |
|
||||
echo "=== Vulnerability Scan Report ===" > {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "Target: {{Target}}" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "Workspace: {{TargetSpace}}" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "Date: $(date)" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "=== Statistics ===" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "Input Hosts: {{input_count}}" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "Nuclei Findings: {{nuclei_count}}" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "=== Reports Generated ===" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "- Active Scan: {{output_dir}}/active/{{TargetSpace}}-report.html" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "- Sensitive Scan: {{output_dir}}/sensitive/{{TargetSpace}}-sensitive.html" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
echo "- Nuclei Scan: {{output_dir}}/nuclei/{{TargetSpace}}-nuclei.html" >> {{output_dir}}/final-report-{{TargetSpace}}.txt
|
||||
|
||||
- name: notify-completion
|
||||
type: function
|
||||
function: printf("Vulnerability scan complete: {{input_count}} hosts scanned, {{nuclei_count}} nuclei findings")
|
||||
@@ -0,0 +1,40 @@
|
||||
name: test-inline-modules
|
||||
kind: flow
|
||||
description: Simple test flow with inline modules (no path references)
|
||||
|
||||
params:
|
||||
- name: target
|
||||
required: true
|
||||
|
||||
modules:
|
||||
- name: greet-module
|
||||
description: Simple greeting module
|
||||
steps:
|
||||
- name: greet
|
||||
type: bash
|
||||
command: echo "Hello, {{target}}!"
|
||||
exports:
|
||||
greeting: "{{StepOutput}}"
|
||||
|
||||
- name: info-module
|
||||
description: Displays system info
|
||||
depends_on:
|
||||
- greet-module
|
||||
steps:
|
||||
- name: show-info
|
||||
type: bash
|
||||
command: echo "Target is {{target}}, greeting was {{greeting}}"
|
||||
- name: date-step
|
||||
type: bash
|
||||
command: date +%Y-%m-%d
|
||||
exports:
|
||||
current_date: "{{StepOutput}}"
|
||||
|
||||
- name: final-module
|
||||
description: Final summary module
|
||||
depends_on:
|
||||
- info-module
|
||||
steps:
|
||||
- name: summary
|
||||
type: bash
|
||||
command: echo "Flow completed on {{current_date}} for {{target}}"
|
||||
Reference in New Issue
Block a user