ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Osmedeus Library SDK 使用指南:以 Go 库方式编排安全扫描工作流与函数求值

Osmedeus Library SDK 使用指南:以 Go 库方式编排安全扫描工作流与函数求值 Osmedeus Library SDK 使用指南以 Go 库方式编排安全扫描工作流与函数求值【免费下载链接】osmedeusA Modern Orchestration Engine for Security项目地址: https://gitcode.com/GitHub_Trending/os/osmedeusOsmedeus 是面向安全领域的现代化编排引擎Modern Orchestration Engine for Security除提供 CLI 与 API 服务外还在 lib/README.md 中对外暴露了完整的 Go 语言 SDK包路径github.com/j3ssie/osmedeus/v5/lib让开发者可以把 Osmedeus 当作普通 Go 依赖嵌入自己的程序以 YAML 字符串定义模块工作流并针对目标执行或直接对 JavaScript 表达式调用内置工具函数。读完本文你将掌握工作流执行 APIRun/RunWithContext等、函数求值 APIEval/EvalCondition等、配置选项RunOptions/EvalOptions、结果类型与类型化错误体系并能把侦察、扫描等模块工作流嵌入到自己的自动化管线中。SDK 的定位与设计原则lib包的文档注释见 lib/doc.go明确说明了该 SDK 的设计取向这些原则直接影响使用方式静默优先库模式默认Silenttrue不向终端输出步骤内容只有错误会被报告默认不碰数据库库模式默认DisableDatabasetrue跳过数据库操作适合轻量级嵌入只支持模块module仅执行kind: module的工作流不执行 flow编排多个模块的流程保证 API 简洁零配置可用传入nil选项时自动使用DefaultRunOptions()与DefaultConfig()开箱即用全面支持 context所有执行函数都接受context.Context天然支持超时与取消线程安全底层复用了内部线程安全的包如函数注册表使用sync.RWMutex保护运行时见 internal/functions/registry.go。因此lib包非常适合构建自定义扫描器、CI/CD 安全检查任务、批量资产巡检脚本等场景而无需启动完整的 Osmedeus 服务端。安装与最小可用示例SDK 使用标准的 Go module 依赖方式安装go get github.com/j3ssie/osmedeus/v5/lib引入包后即可像调用普通函数一样执行一个内联的模块工作流。注意工作流以 YAML 字符串传入kind必须为modulepackage main import ( fmt log github.com/j3ssie/osmedeus/v5/lib ) func main() { // Define a simple workflow workflowYAML : name: simple-scan kind: module steps: - name: echo-target type: bash command: echo Scanning {{target}} // Run the workflow result, err : lib.Run(example.com, workflowYAML, nil) if err ! nil { log.Fatal(err) } fmt.Printf(Status: %s\n, result.Status) fmt.Printf(Duration: %v\n, result.Duration) }工作流中的{{target}}是模板变量由 SDK 在执行前以目标地址渲染模板渲染引擎见 internal/template/engine.go。{{Output}}、{{workspace}}等内置变量同样可用示例见后文侦察工作流。工作流执行 APISDK 提供四个执行入口覆盖从默认参数到完全自定义的梯度函数签名说明Run(target, workflowYAML, opts) (*RunResult, error)主入口执行模块工作流RunWithContext(ctx, target, workflowYAML, opts) (*RunResult, error)支持 context 取消与超时RunModule(target, workflowYAML) (*RunResult, error)便捷包装使用默认选项RunModuleWithParams(target, workflowYAML, params) (*RunResult, error)便捷包装仅自定义参数Run 与 RunWithContextRun本质上是RunWithContext(context.Background(), ...)的薄包装见 lib/osmedeus.go因此两者共享同一套执行管线。RunWithContext是推荐的生产级入口因为它让调用方完全掌控生命周期ctx, cancel : context.WithTimeout(context.Background(), 5*time.Minute) defer cancel() result, err : lib.RunWithContext(ctx, example.com, workflowYAML, nil)RunWithContext内部会依次完成以下工作对应 lib/osmedeus.go入参校验target为空返回ErrEmptyTargetworkflowYAML为空返回ErrEmptyWorkflow解析 YAML调用parser.ParseContent解析失败包装为ParseError结构校验调用parser.Validate失败包装为ValidationError类型检查非module工作流返回ErrNotModuleflow 在库模式下不支持构建配置opts.Config为空时回退到config.DefaultConfig()默认 base 目录为~/osmedeus-base见 internal/config/config.go合并参数自动注入target与tactic默认default两个内建参数再叠加opts.Params中用户提供的键值创建执行器并执行新建executor.NewExecutor()按选项设置DryRun、Verbose、Silent、DisableWorkflowState、SkipWorkspace随后调用exec.ExecuteModule(ctx, workflow, params, cfg)组装结果输出目录为filepath.Join(cfg.WorkspacesPath, target)内部core.WorkflowResult被转换为对外暴露的RunResult。ExecuteModule是底层真正的执行器见 internal/executor/executor.go它会为每次运行生成 UUID创建可取消的 context在服务端模式下可注册到 run control plane 以支持 API 取消并根据工作流配置创建对应的 runnerhost / docker / ssh见 internal/runner/runner.go完成 setup、执行、cleanup 的完整生命周期。RunModule 与 RunModuleWithParams两个便捷包装适合快速验证result, err : lib.RunModule(example.com, workflowYAML) result, err : lib.RunModuleWithParams(example.com, workflowYAML, map[string]string{ threads: 20, timeout: 30, })RunModule等价于Run(target, yaml, nil)RunModuleWithParams内部使用DefaultRunOptions()后仅替换Params字段见 lib/osmedeus.go。函数求值 APISDK 的第二大能力是表达式求值基于内置 JavaScript 运行时internal/functions下的 goja_runtime.go 与 goja_pool.go执行表达式并暴露全部 Osmedeus 工具函数。四种求值入口如下函数签名说明Eval(expression, opts) (interface{}, error)求值 JavaScript 表达式可带上下文EvalCondition(condition, opts) (bool, error)求值布尔条件返回 true/falseEvalFunction(expression) (interface{}, error)Eval的无选项便捷包装EvalFunctionWithContext(expression, ctx) (interface{}, error)带 context 变量的便捷包装Eval 与 EvalCondition// Simple expression result, err : lib.Eval(1 1, nil) // With context variables result, err : lib.Eval(trim(input), lib.EvalOptions{ Context: map[string]interface{}{input: hello }, }) // Boolean condition ok, err : lib.EvalCondition(len(items) 0, lib.EvalOptions{ Context: map[string]interface{}{items: []string{a, b}}, })从实现看lib/osmedeus.goEval的执行路径为合并EvalOptions.Context与TargetTarget会以ctx[target]注入且优先级更高→ 用模板引擎渲染表达式中的{{变量}}→ 交给functions.NewRegistry().Execute执行EvalCondition则调用registry.EvaluateCondition。注意表达式为空时两者都会返回ErrEmptyExpression。便捷包装result, err : lib.EvalFunction(uuid()) result, err : lib.EvalFunctionWithContext(split(text, ,), map[string]interface{}{ text: a,b,c, })可用内置函数总览Eval系列函数拥有全部 Osmedeus 工具函数的访问权限。以下函数表来自 lib/README.md在真实运行中它们与工作流步骤中的function类型共享同一函数注册表见 internal/functions/registry.go文件操作函数说明fileExists(path)检查文件是否存在fileLength(path)获取文件行数dirLength(path)获取目录条目数readFile(path)读取文件内容readLines(path, n)读取前 n 行removeFile(path)删除文件createFolder(path)创建目录appendFile(path, data)追加内容到文件glob(pattern)按模式查找文件字符串操作函数说明trim(s)去除首尾空白split(s, sep)按分隔符拆分字符串join(arr, sep)拼接数组replace(s, old, new)替换子串contains(s, substr)判断是否包含子串startsWith(s, prefix)判断前缀endsWith(s, suffix)判断后缀toLowerCase(s)转小写toUpperCase(s)转大写match(s, pattern)正则匹配regexExtract(s, pattern)提取正则分组类型转换函数说明parseInt(s)解析整数parseFloat(s)解析浮点数toString(v)转字符串toBoolean(v)转布尔工具函数函数说明len(v)获取长度isEmpty(v)判断是否为空isNotEmpty(v)判断是否非空uuid()生成 UUIDrandomString(n)生成随机字符串base64Encode(s)Base64 编码base64Decode(s)Base64 解码日志函数说明log_info(msg)输出 info 日志log_warn(msg)输出警告log_error(msg)输出错误log_debug(msg)输出调试日志Registry还提供Register(name, fn)注册自定义函数见 internal/functions/registry.go允许调用方按需扩展运行时能力。工作流解析与校验 API在真正执行前先解析、校验工作流是降低失败成本的好习惯SDK 为此提供了两个只读入口函数签名说明ParseWorkflow(workflowYAML) (*core.Workflow, error)解析 YAML 字符串不执行ValidateWorkflow(workflowYAML) error解析并校验合法时返回 nilworkflow, err : lib.ParseWorkflow(workflowYAML) if err ! nil { log.Fatal(err) } fmt.Printf(Workflow: %s (%s)\n, workflow.Name, workflow.Kind) if err : lib.ValidateWorkflow(workflowYAML); err ! nil { fmt.Printf(Invalid workflow: %v\n, err) }解析返回的*core.Workflow结构见 internal/core/workflow.go包含Name、Kind、Steps、Params、Triggers、Extends、Override等字段可用于执行前的检查与审计。校验逻辑见 internal/parser/parser.go覆盖kind必须是module或flow、name必填、module 至少包含一个 step除非使用extends继承、step 的name/type必填且type必须属于合法枚举bash、function、parallel、foreach、remote-bash、http、llm、agent、agent-acp、agent-sdk等以及参数、触发器、override 等复杂规则的校验。测试用例可参考 lib/lib_test.go 中的TestParseWorkflow_*与TestValidateWorkflow_*。配置选项详解RunOptionsRunOptions控制工作流执行的行为完整字段见 lib/options.goopts : lib.RunOptions{ // Parameters passed to the workflow Params: map[string]string{ threads: 20, custom: value, }, // Scan aggressiveness: aggressive, default, or gently Tactic: default, // Show commands without executing DryRun: false, // Enable detailed output (shows step stdout) Verbose: false, // Suppress step output (default: true for library mode) Silent: true, // Custom configuration (nil uses DefaultConfig) Config: nil, // Override base folder path BaseFolder: , // Override workspaces output directory WorkspacesPath: , // Disable writing workflow state files DisableWorkflowState: false, // Skip creating workspace/output directory (empty-target mode) SkipWorkspace: false, // Skip database operations (default: true for library mode) DisableDatabase: true, }关键字段说明Tactic扫描激进程度直接决定并发与线程规模。DefaultConfig()中对应线程数为aggressive: 40、default: 10、gently: 5见 internal/config/config.goSDK 会将其注入工作流参数tacticDryRun只打印将执行的命令而不真正执行适合审计工作流定义Silent / Verbose控制步骤输出的可见性DefaultRunOptions()中Silent默认为true见 lib/options.goConfig / BaseFolder / WorkspacesPath三者共同决定文件系统布局。Config提供完整配置对象默认~/osmedeus-baseBaseFolder与WorkspacesPath则分别覆盖 base 目录与 workspace 输出目录SDK 会在执行前调用cfg.ResolvePaths()展开模板变量与环境变量DisableWorkflowState禁止向输出目录写入工作流状态文件适合临时性/内存态执行SkipWorkspace跳过 workspace/输出目录的创建适合无真实目标的场景DisableDatabase跳过全部数据库操作库模式默认开启。RunOptions还提供了一组不可变风格的链式方法WithParams、WithTactic、WithDryRun、WithVerbose、WithSilent、WithConfig、WithBaseFolder、WithWorkspacesPath每个方法返回副本而非修改原对象见 lib/options.go便于在多个调用间安全复用基础选项。EvalOptionsEvalOptions仅有两个字段见 lib/options.goopts : lib.EvalOptions{ // Variables accessible in the expression Context: map[string]interface{}{ input: value, count: 42, }, // Convenience: sets ctx[target] Target: example.com, }Context中的变量在表达式中按名字直接访问Target是便捷字段等价于在Context中设置target键且优先级更高。同样提供WithContext与WithTarget链式方法。结果类型与辅助方法RunResultRunResult汇总一次工作流执行的完整结果结构定义见 lib/result.gotype RunResult struct { WorkflowName string RunID string Target string Status string // completed, failed, cancelled, skipped StartTime time.Time EndTime time.Time Duration time.Duration Steps []*StepResult Exports map[string]interface{} Artifacts []string Error error OutputPath string Message string }辅助方法result.IsSuccess() // true if completed result.IsFailed() // true if failed result.IsCancelled() // true if cancelled result.IsSkipped() // true if skipped result.GetExport(name) // get exported variable result.GetExportString(x) // get as string result.GetExportBool(x) // get as bool result.SuccessfulSteps() // count of successful steps result.FailedSteps() // count of failed steps result.SkippedSteps() // count of skipped stepsRunResult由内部core.WorkflowResult转换而来见 lib/result.goDuration由EndTime.Sub(StartTime)计算OutputPath为工作区目录路径。注意测试中验证了GetExportString仅当导出值是字符串类型时才返回oktrue见 lib/lib_test.go。StepResultStepResult描述工作流中单个步骤的执行结果type StepResult struct { Name string Type string Status string // success, failed, skipped Output string Duration time.Duration Error error Exports map[string]interface{} } // Helper methods step.IsSuccess() step.IsFailed() step.IsSkipped() step.GetExport(name)错误处理与类型化错误SDK 为常见失败场景提供了哨兵错误与类型化错误定义见 lib/errors.go推荐统一拦截result, err : lib.Run(target, yaml, nil) if err ! nil { switch { case errors.Is(err, lib.ErrEmptyTarget): fmt.Println(Target cannot be empty) case errors.Is(err, lib.ErrEmptyWorkflow): fmt.Println(Workflow YAML cannot be empty) case errors.Is(err, lib.ErrNotModule): fmt.Println(Only module workflows are supported) case lib.IsParseError(err): fmt.Println(YAML parsing failed:, err) case lib.IsValidationError(err): fmt.Println(Workflow validation failed:, err) case lib.IsExecutionError(err): fmt.Println(Execution failed:, err) default: fmt.Println(Error:, err) } }错误类型速查表错误说明ErrEmptyTarget目标不能为空ErrEmptyWorkflow工作流内容不能为空ErrEmptyExpression表达式不能为空ErrNotModule工作流必须为kind: module库模式不支持 flowParseErrorYAML 解析失败ValidationError工作流校验失败ExecutionError步骤执行失败实现细节上ParseError、ValidationError、ExecutionError都实现了Unwrap()支持errors.As链式匹配三个Is*判别函数基于errors.As实现见 lib/errors.go。错误消息格式经过测试固化例如执行错误格式为execution error at step step (bash): failed见 lib/lib_test.go。实战示例示例一运行一个侦察工作流把子域名枚举与结果检查串成模块并利用导出变量在步骤间传递数据package main import ( context fmt log time github.com/j3ssie/osmedeus/v5/lib ) func main() { workflow : name: recon kind: module params: - name: threads default: 10 steps: - name: subdomain-enum type: bash command: subfinder -d {{target}} -t {{threads}} -o {{Output}}/subdomains.txt exports: subdomains_file: {{Output}}/subdomains.txt - name: check-results type: function function: | log_info(Found fileLength({{subdomains_file}}) subdomains) // Run with timeout ctx, cancel : context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() result, err : lib.RunWithContext(ctx, example.com, workflow, lib.RunOptions{ Params: map[string]string{threads: 20}, Tactic: aggressive, }) if err ! nil { log.Fatal(err) } fmt.Printf(Status: %s\n, result.Status) fmt.Printf(Duration: %v\n, result.Duration) fmt.Printf(Output: %s\n, result.OutputPath) // Check exports if file, ok : result.GetExportString(subdomains_file); ok { fmt.Printf(Subdomains file: %s\n, file) } }该示例同时体现了多个核心能力params声明工作流参数、{{target}}/{{threads}}/{{Output}}模板变量、exports步骤导出、function步骤内调用fileLength/log_info、RunWithContext超时控制以及GetExportString消费导出变量。示例二执行前先校验工作流package main import ( fmt log github.com/j3ssie/osmedeus/v5/lib ) func main() { workflow : name: my-workflow kind: module steps: - name: step1 type: bash command: echo hello // Validate first if err : lib.ValidateWorkflow(workflow); err ! nil { log.Fatalf(Invalid workflow: %v, err) } // Parse to inspect w, _ : lib.ParseWorkflow(workflow) fmt.Printf(Workflow: %s\n, w.Name) fmt.Printf(Steps: %d\n, len(w.Steps)) // Then execute result, err : lib.Run(target.com, workflow, nil) if err ! nil { log.Fatal(err) } fmt.Printf(Result: %s\n, result.Status) }示例三用函数做文件处理在程序里直接复用 Osmedeus 的表达式能力处理文件与字符串无需编写额外工具链package main import ( fmt log github.com/j3ssie/osmedeus/v5/lib ) func main() { // Check if file exists exists, _ : lib.Eval(fileExists(/tmp/results.txt), nil) fmt.Printf(File exists: %v\n, exists) // Read and process file if exists.(bool) { lineCount, _ : lib.Eval(fileLength(/tmp/results.txt), nil) fmt.Printf(Line count: %v\n, lineCount) } // String processing result, _ : lib.Eval(split(trim(input), ,), lib.EvalOptions{ Context: map[string]interface{}{ input: a, b, c , }, }) fmt.Printf(Split result: %v\n, result) // Conditional logic hasResults, err : lib.EvalCondition(fileExists(path) fileLength(path) 0, lib.EvalOptions{ Context: map[string]interface{}{ path: /tmp/results.txt, }, }) if err ! nil { log.Fatal(err) } fmt.Printf(Has results: %v\n, hasResults) }lib.Eval的表达能力使其成为轻量级数据处理的便捷手段——包括文件读取、行数统计、字符串清洗、正则匹配与组合条件判断且与工作流中的function步骤共享同一套函数注册表。示例四自定义配置SDK 允许加载自定义的 Osmedeus base 配置目录结构、工作区路径、API 密钥等并回退到默认配置package main import ( log github.com/j3ssie/osmedeus/v5/internal/config github.com/j3ssie/osmedeus/v5/lib ) func main() { // Load custom config cfg, err : config.Load(/path/to/osmedeus-base) if err ! nil { // Fall back to default cfg config.DefaultConfig() } workflow : name: custom-scan kind: module steps: - name: scan type: bash command: echo Using custom config result, err : lib.Run(target.com, workflow, lib.RunOptions{ Config: cfg, WorkspacesPath: /custom/output/path, Verbose: true, Silent: false, }) if err ! nil { log.Fatal(err) } log.Printf(Completed: %s, result.Status) }config.Load读取指定 base 目录的配置文件对应~/osmedeus-base的标准布局参考 public/examples/osmedeus-base.example/osm-settings.yaml 的示例结构加载失败时回退到config.DefaultConfig()可保证程序始终可运行。WorkspacesPath覆盖输出目录后本次运行的结果将写入/custom/output/path/target。从 SDK 到源码一条完整的执行调用链为了让读者对 SDK 的内部行为有更精确的预期这里把从lib.Run到步骤执行的调用链梳理如下路径均为当前仓库内的实现入口lib.Run→lib.RunWithContextlib/osmedeus.go解析与校验parser.ParseContentinternal/parser/parser.go基于goccy/go-yaml解析并提供带行列号的格式化错误→parser.Validate校验 kind/name/steps 等规则配置构建config.DefaultConfig()internal/config/config.go默认~/osmedeus-baseSQLite 数据库、ScanTactic 线程数等或config.Load自定义配置随后cfg.ResolvePaths()展开路径模板执行器executor.NewExecutor()ExecuteModuleinternal/executor/executor.go——创建 run UUID、注册 run control plane支持外部取消、依据工作流runner字段创建 host/docker/ssh runner、交由 step dispatcher 逐步骤执行函数求值functions.NewRegistry()管理基于 goja 的运行时internal/functions/registry.goEval/EvalCondition与工作流中的function步骤共用同一注册表结果转换fromWorkflowResult把core.WorkflowResult转换为lib.RunResultlib/result.go。这条链路也解释了为什么库模式如此轻量DisableDatabasetrue跳过数据库写入Silenttrue抑制终端输出SkipWorkspace/DisableWorkflowState可进一步避免文件系统副作用——这让 SDK 非常适合在批量任务、CI 流水线与内存态处理中使用。结语Osmedeus 的libSDK 把整个编排引擎的两种核心能力——模块工作流执行与 JavaScript 函数求值——以简洁的 Go API 暴露出来四个执行入口、四个求值入口、两个解析校验函数加上完善的配置与类型化错误体系足以支撑从快速原型到生产级自动化管线的各种需求。结合 lib/lib_test.go 中的 40 个测试用例覆盖表达式求值、条件判断、工作流解析/校验、超时取消、错误类型与辅助方法开发者可以放心地把 Osmedeus 作为自己安全工具链中的一个可编程组件。【免费下载链接】osmedeusA Modern Orchestration Engine for Security项目地址: https://gitcode.com/GitHub_Trending/os/osmedeus创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进