Hacking on Osmedeus
This document describes the technical architecture and development practices for Osmedeus. Itโs intended for developers who want to understand, modify, or extend the codebase.Table of Contents
- Project Structure
- Architecture Overview
- Core Components
- Workflow Engine
- Execution Pipeline
- Runner System
- Template Engine
- Function Registry
- Scheduler System
- Database Layer
- Testing
- Adding New Features
Project Structure
Architecture Overview
Osmedeus follows a layered architecture:Core Components
Workflow Types
Step Types
remote-bash Step Type
Theremote-bash step type allows per-step Docker or SSH execution, independent of the module-level runner:
Execution Context
- Variables are set by the executor (built-in variables)
- Params are user-provided
- Exports are step outputs that propagate to subsequent steps
Workflow Engine
Parser
The parser (internal/parser/parser.go) handles YAML parsing:
Loader
The loader (internal/parser/loader.go) provides caching and lookup:
- Check cache
- Try
workflows/<name>.yaml - Try
workflows/<name>-flow.yaml - Try
workflows/modules/<name>.yaml - Try
workflows/modules/<name>-module.yaml
Execution Pipeline
Flow
Executor
- Initialize execution context with built-in variables
- Create and setup the appropriate runner
- Iterate through steps, dispatching to appropriate handler
- Handle pre-conditions, exports, and decision routing
- Process on_success/on_error actions
Step Dispatcher
Runner System
Interface
Host Runner
Simple local execution usingos/exec:
Docker Runner
Supports both ephemeral (docker run --rm) and persistent (docker exec) modes:
SSH Runner
Usesgolang.org/x/crypto/ssh for remote execution:
Template Engine
Variable Resolution
The template engine (internal/template/engine.go) handles {{variable}} interpolation:
- Check context variables
- Check environment variables (optional)
- Return empty string if not found
Built-in Variable Injection
Foreach Variable Syntax
Foreach uses[[variable]] syntax (double brackets) to avoid conflicts with template variables:
Function Registry
Otto JavaScript Runtime
Functions are implemented in Go and exposed to an Otto JavaScript VM:Adding New Functions
- Add the Go implementation in the appropriate file:
- Register in
registerFunctions():
Output and Control Functions
These functions provide output and execution control within workflows:Function Execution
Scheduler System
Trigger Types
Scheduler
Event Filtering
Events are matched using JavaScript expressions:Database Layer
Multi-Engine Support
Models
Repository Pattern
Schedule Operations
JSONL Import
Testing
Test Structure
Running Tests
Writing Tests
Use testify for assertions:Adding New Features
Adding a New Step Type
- Define the type in
internal/core/types.go:
- Create executor in
internal/executor/mynew_executor.go:
- Register in dispatcher (
internal/executor/dispatcher.go):
Adding a New Runner
- Create runner in
internal/runner/myrunner.go:
- Add type in
internal/core/types.go:
- Register in factory (
internal/runner/runner.go):
Adding a New Installer Mode
- Create installer in
internal/installer/mymode.go:
- Add flag in
pkg/cli/install.go:
- Register in
runInstallBinary()switch statement.
internal/installer/nix.go for a complete example.
Adding a New API Endpoint
- Add handler in
pkg/server/handlers/handlers.go:
- Register route in
pkg/server/server.go:
Adding a New CLI Command
- Create command file in
pkg/cli/mycommand.go:
- Register in
pkg/cli/root.go:
CLI Shortcuts and Tips
Command Aliases
osmedeus func- alias forosmedeus functionosmedeus func e- alias forosmedeus function eval
New Scan Flags
-c, --concurrency- Number of targets to scan concurrently--timeout- Scan timeout (e.g.,2h,3h,1d)--repeat- Repeat scan after completion--repeat-wait-time- Wait time between repeats (e.g.,30m,1h,1d)-mcan be specified multiple times to run modules in sequence
Debugging Tips
- Use
osmedeus --usage-exampleto see comprehensive examples for all commands - Use
--verboseor--debugfor detailed logging - Use
--dry-runto preview scan execution without running commands - Use
--log-file-tmpto create timestamped log files for debugging
Code Style
- Use
go fmtandgolangci-lint - Follow Go naming conventions
- Use structured logging with zap
- Return errors, donโt panic
- Use context for cancellation
- Write tests for new features