* feat: Complete migration from Prefect to Temporal BREAKING CHANGE: Replaces Prefect workflow orchestration with Temporal ## Major Changes - Replace Prefect with Temporal for workflow orchestration - Implement vertical worker architecture (rust, android) - Replace Docker registry with MinIO for unified storage - Refactor activities to be co-located with workflows - Update all API endpoints for Temporal compatibility ## Infrastructure - New: docker-compose.temporal.yaml (Temporal + MinIO + workers) - New: workers/ directory with rust and android vertical workers - New: backend/src/temporal/ (manager, discovery) - New: backend/src/storage/ (S3-cached storage with MinIO) - New: backend/toolbox/common/ (shared storage activities) - Deleted: docker-compose.yaml (old Prefect setup) - Deleted: backend/src/core/prefect_manager.py - Deleted: backend/src/services/prefect_stats_monitor.py - Deleted: Docker registry and insecure-registries requirement ## Workflows - Migrated: security_assessment workflow to Temporal - New: rust_test workflow (example/test workflow) - Deleted: secret_detection_scan (Prefect-based, to be reimplemented) - Activities now co-located with workflows for independent testing ## API Changes - Updated: backend/src/api/workflows.py (Temporal submission) - Updated: backend/src/api/runs.py (Temporal status/results) - Updated: backend/src/main.py (727 lines, TemporalManager integration) - Updated: All 16 MCP tools to use TemporalManager ## Testing - ✅ All services healthy (Temporal, PostgreSQL, MinIO, workers, backend) - ✅ All API endpoints functional - ✅ End-to-end workflow test passed (72 findings from vulnerable_app) - ✅ MinIO storage integration working (target upload/download, results) - ✅ Worker activity discovery working (6 activities registered) - ✅ Tarball extraction working - ✅ SARIF report generation working ## Documentation - ARCHITECTURE.md: Complete Temporal architecture documentation - QUICKSTART_TEMPORAL.md: Getting started guide - MIGRATION_DECISION.md: Why we chose Temporal over Prefect - IMPLEMENTATION_STATUS.md: Migration progress tracking - workers/README.md: Worker development guide ## Dependencies - Added: temporalio>=1.6.0 - Added: boto3>=1.34.0 (MinIO S3 client) - Removed: prefect>=3.4.18 * feat: Add Python fuzzing vertical with Atheris integration This commit implements a complete Python fuzzing workflow using Atheris: ## Python Worker (workers/python/) - Dockerfile with Python 3.11, Atheris, and build tools - Generic worker.py for dynamic workflow discovery - requirements.txt with temporalio, boto3, atheris dependencies - Added to docker-compose.temporal.yaml with dedicated cache volume ## AtherisFuzzer Module (backend/toolbox/modules/fuzzer/) - Reusable module extending BaseModule - Auto-discovers fuzz targets (fuzz_*.py, *_fuzz.py, fuzz_target.py) - Recursive search to find targets in nested directories - Dynamically loads TestOneInput() function - Configurable max_iterations and timeout - Real-time stats callback support for live monitoring - Returns findings as ModuleFinding objects ## Atheris Fuzzing Workflow (backend/toolbox/workflows/atheris_fuzzing/) - Temporal workflow for orchestrating fuzzing - Downloads user code from MinIO - Executes AtherisFuzzer module - Uploads results to MinIO - Cleans up cache after execution - metadata.yaml with vertical: python for routing ## Test Project (test_projects/python_fuzz_waterfall/) - Demonstrates stateful waterfall vulnerability - main.py with check_secret() that leaks progress - fuzz_target.py with Atheris TestOneInput() harness - Complete README with usage instructions ## Backend Fixes - Fixed parameter merging in REST API endpoints (workflows.py) - Changed workflow parameter passing from positional args to kwargs (manager.py) - Default parameters now properly merged with user parameters ## Testing ✅ Worker discovered AtherisFuzzingWorkflow ✅ Workflow executed end-to-end successfully ✅ Fuzz target auto-discovered in nested directories ✅ Atheris ran 100,000 iterations ✅ Results uploaded and cache cleaned * chore: Complete Temporal migration with updated CLI/SDK/docs This commit includes all remaining Temporal migration changes: ## CLI Updates (cli/) - Updated workflow execution commands for Temporal - Enhanced error handling and exceptions - Updated dependencies in uv.lock ## SDK Updates (sdk/) - Client methods updated for Temporal workflows - Updated models for new workflow execution - Updated dependencies in uv.lock ## Documentation Updates (docs/) - Architecture documentation for Temporal - Workflow concept documentation - Resource management documentation (new) - Debugging guide (new) - Updated tutorials and how-to guides - Troubleshooting updates ## README Updates - Main README with Temporal instructions - Backend README - CLI README - SDK README ## Other - Updated IMPLEMENTATION_STATUS.md - Removed old vulnerable_app.tar.gz These changes complete the Temporal migration and ensure the CLI/SDK work correctly with the new backend. * fix: Use positional args instead of kwargs for Temporal workflows The Temporal Python SDK's start_workflow() method doesn't accept a 'kwargs' parameter. Workflows must receive parameters as positional arguments via the 'args' parameter. Changed from: args=workflow_args # Positional arguments This fixes the error: TypeError: Client.start_workflow() got an unexpected keyword argument 'kwargs' Workflows now correctly receive parameters in order: - security_assessment: [target_id, scanner_config, analyzer_config, reporter_config] - atheris_fuzzing: [target_id, target_file, max_iterations, timeout_seconds] - rust_test: [target_id, test_message] * fix: Filter metadata-only parameters from workflow arguments SecurityAssessmentWorkflow was receiving 7 arguments instead of 2-5. The issue was that target_path and volume_mode from default_parameters were being passed to the workflow, when they should only be used by the system for configuration. Now filters out metadata-only parameters (target_path, volume_mode) before passing arguments to workflow execution. * refactor: Remove Prefect leftovers and volume mounting legacy Complete cleanup of Prefect migration artifacts: Backend: - Delete registry.py and workflow_discovery.py (Prefect-specific files) - Remove Docker validation from setup.py (no longer needed) - Remove ResourceLimits and VolumeMount models - Remove target_path and volume_mode from WorkflowSubmission - Remove supported_volume_modes from API and discovery - Clean up metadata.yaml files (remove volume/path fields) - Simplify parameter filtering in manager.py SDK: - Remove volume_mode parameter from client methods - Remove ResourceLimits and VolumeMount models - Remove Prefect error patterns from docker_logs.py - Clean up WorkflowSubmission and WorkflowMetadata models CLI: - Remove Volume Modes display from workflow info All removed features are Prefect-specific or Docker volume mounting artifacts. Temporal workflows use MinIO storage exclusively. * feat: Add comprehensive test suite and benchmark infrastructure - Add 68 unit tests for fuzzer, scanner, and analyzer modules - Implement pytest-based test infrastructure with fixtures - Add 6 performance benchmarks with category-specific thresholds - Configure GitHub Actions for automated testing and benchmarking - Add test and benchmark documentation Test coverage: - AtherisFuzzer: 8 tests - CargoFuzzer: 14 tests - FileScanner: 22 tests - SecurityAnalyzer: 24 tests All tests passing (68/68) All benchmarks passing (6/6) * fix: Resolve all ruff linting violations across codebase Fixed 27 ruff violations in 12 files: - Removed unused imports (Depends, Dict, Any, Optional, etc.) - Fixed undefined workflow_info variable in workflows.py - Removed dead code with undefined variables in atheris_fuzzer.py - Changed f-string to regular string where no placeholders used All files now pass ruff checks for CI/CD compliance. * fix: Configure CI for unit tests only - Renamed docker-compose.temporal.yaml → docker-compose.yml for CI compatibility - Commented out integration-tests job (no integration tests yet) - Updated test-summary to only depend on lint and unit-tests CI will now run successfully with 68 unit tests. Integration tests can be added later. * feat: Add CI/CD integration with ephemeral deployment model Implements comprehensive CI/CD support for FuzzForge with on-demand worker management: **Worker Management (v0.7.0)** - Add WorkerManager for automatic worker lifecycle control - Auto-start workers from stopped state when workflows execute - Auto-stop workers after workflow completion - Health checks and startup timeout handling (90s default) **CI/CD Features** - `--fail-on` flag: Fail builds based on SARIF severity levels (error/warning/note/info) - `--export-sarif` flag: Export findings in SARIF 2.1.0 format - `--auto-start`/`--auto-stop` flags: Control worker lifecycle - Exit code propagation: Returns 1 on blocking findings, 0 on success **Exit Code Fix** - Add `except typer.Exit: raise` handlers at 3 critical locations - Move worker cleanup to finally block for guaranteed execution - Exit codes now propagate correctly even when build fails **CI Scripts & Examples** - ci-start.sh: Start FuzzForge services with health checks - ci-stop.sh: Clean shutdown with volume preservation option - GitHub Actions workflow example (security-scan.yml) - GitLab CI pipeline example (.gitlab-ci.example.yml) - docker-compose.ci.yml: CI-optimized compose file with profiles **OSS-Fuzz Integration** - New ossfuzz_campaign workflow for running OSS-Fuzz projects - OSS-Fuzz worker with Docker-in-Docker support - Configurable campaign duration and project selection **Documentation** - Comprehensive CI/CD integration guide (docs/how-to/cicd-integration.md) - Updated architecture docs with worker lifecycle details - Updated workspace isolation documentation - CLI README with worker management examples **SDK Enhancements** - Add get_workflow_worker_info() endpoint - Worker vertical metadata in workflow responses **Testing** - All workflows tested: security_assessment, atheris_fuzzing, secret_detection, cargo_fuzzing - All monitoring commands tested: stats, crashes, status, finding - Full CI pipeline simulation verified - Exit codes verified for success/failure scenarios Ephemeral CI/CD model: ~3-4GB RAM, ~60-90s startup, runs entirely in CI containers. * fix: Resolve ruff linting violations in CI/CD code - Remove unused variables (run_id, defaults, result) - Remove unused imports - Fix f-string without placeholders All CI/CD integration files now pass ruff checks.
12 KiB
CI/CD Integration Guide
This guide shows you how to integrate FuzzForge into your CI/CD pipeline for automated security testing on every commit, pull request, or scheduled run.
Overview
FuzzForge can run entirely inside CI containers (GitHub Actions, GitLab CI, etc.) with no external infrastructure required. The complete FuzzForge stack—Temporal, PostgreSQL, MinIO, Backend, and workers—starts automatically when needed and cleans up after execution.
Key Benefits
✅ Zero Infrastructure: No servers to maintain ✅ Ephemeral: Fresh environment per run ✅ Resource Efficient: On-demand workers (v0.7.0) save ~6-7GB RAM ✅ Fast Feedback: Fail builds on critical/high findings ✅ Standards Compliant: SARIF export for GitHub Security / GitLab SAST
Prerequisites
Required
- CI Runner: Ubuntu with Docker support
- RAM: At least 4GB available (7GB on GitHub Actions)
- Startup Time: ~60-90 seconds
Optional
- jq: For merging Docker daemon config (auto-installed in examples)
- Python 3.11+: For FuzzForge CLI
Quick Start
1. Add Startup Scripts
FuzzForge provides helper scripts to configure Docker and start services:
# Start FuzzForge (configure Docker, start services, wait for health)
bash scripts/ci-start.sh
# Stop and cleanup after execution
bash scripts/ci-stop.sh
2. Install CLI
pip install ./cli
3. Initialize Project
ff init --api-url http://localhost:8000 --name "CI Security Scan"
4. Run Workflow
# Run and fail on error findings
ff workflow run security_assessment . \
--wait \
--fail-on error \
--export-sarif results.sarif
Deployment Models
FuzzForge supports two CI/CD deployment models:
Option A: Ephemeral (Recommended)
Everything runs inside the CI container for each job.
┌────────────────────────────────────┐
│ GitHub Actions Runner │
│ │
│ ┌──────────────────────────────┐ │
│ │ FuzzForge Stack │ │
│ │ • Temporal │ │
│ │ • PostgreSQL │ │
│ │ • MinIO │ │
│ │ • Backend │ │
│ │ • Workers (on-demand) │ │
│ └──────────────────────────────┘ │
│ │
│ ff workflow run ... │
└────────────────────────────────────┘
Pros:
- No infrastructure to maintain
- Complete isolation per run
- Works on GitHub/GitLab free tier
Cons:
- 60-90s startup time per run
- Limited to runner resources
Best For: Open source projects, infrequent scans, PR checks
Option B: Persistent Backend
Backend runs on a separate server, CLI connects remotely.
┌──────────────┐ ┌──────────────────┐
│ CI Runner │────────▶│ FuzzForge Server │
│ (ff CLI) │ HTTPS │ (self-hosted) │
└──────────────┘ └──────────────────┘
Pros:
- No startup time
- More resources
- Faster execution
Cons:
- Requires infrastructure
- Needs API tokens
Best For: Large teams, frequent scans, long fuzzing campaigns
GitHub Actions Integration
Complete Example
See .github/workflows/examples/security-scan.yml for a full working example.
Basic workflow:
name: Security Scan
on: [pull_request, push]
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Start FuzzForge
run: bash scripts/ci-start.sh
- name: Install CLI
run: pip install ./cli
- name: Security Scan
run: |
ff init --api-url http://localhost:8000
ff workflow run security_assessment . \
--wait \
--fail-on error \
--export-sarif results.sarif
- name: Upload SARIF
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
- name: Cleanup
if: always()
run: bash scripts/ci-stop.sh
GitHub Security Tab Integration
Upload SARIF results to see findings directly in GitHub:
- name: Upload SARIF to GitHub Security
if: always()
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
Findings appear in:
- Security tab → Code scanning alerts
- Pull request annotations
- Commit status checks
GitLab CI Integration
Complete Example
See .gitlab-ci.example.yml for a full working example.
Basic pipeline:
stages:
- security
variables:
FUZZFORGE_API_URL: "http://localhost:8000"
security:scan:
image: docker:24
services:
- docker:24-dind
before_script:
- apk add bash python3 py3-pip
- bash scripts/ci-start.sh
- pip3 install ./cli --break-system-packages
- ff init --api-url $FUZZFORGE_API_URL
script:
- ff workflow run security_assessment . --wait --fail-on error --export-sarif results.sarif
artifacts:
reports:
sast: results.sarif
after_script:
- bash scripts/ci-stop.sh
GitLab SAST Dashboard Integration
The reports: sast: section automatically integrates with GitLab's Security Dashboard.
CLI Flags for CI/CD
--fail-on
Fail the build if findings match specified SARIF severity levels.
Syntax:
--fail-on error,warning,note,info,all,none
SARIF Levels:
error- Critical security issues (fail build)warning- Potential security issues (may fail build)note- Informational findings (typically don't fail)info- Additional context (rarely blocks)all- Any finding (strictest)none- Never fail (report only)
Examples:
# Fail on errors only (recommended for CI)
--fail-on error
# Fail on errors or warnings
--fail-on error,warning
# Fail on any finding (strictest)
--fail-on all
# Never fail, just report (useful for monitoring)
--fail-on none
Common Patterns:
- PR checks:
--fail-on error(block critical issues) - Release gates:
--fail-on error,warning(stricter) - Nightly scans:
--fail-on none(monitoring only) - Security audit:
--fail-on all(maximum strictness)
Exit Codes:
0- No blocking findings1- Found blocking findings or error
--export-sarif
Export SARIF results to a file after workflow completion.
Syntax:
--export-sarif <path>
Example:
ff workflow run security_assessment . \
--wait \
--export-sarif results.sarif
--wait
Wait for workflow execution to complete (required for CI/CD).
Example:
ff workflow run security_assessment . --wait
Without --wait, the command returns immediately and the workflow runs in the background.
Common Workflows
PR Security Gate
Block PRs with critical/high findings:
on: pull_request
jobs:
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: bash scripts/ci-start.sh
- run: pip install ./cli
- run: |
ff init --api-url http://localhost:8000
ff workflow run security_assessment . --wait --fail-on error
- if: always()
run: bash scripts/ci-stop.sh
Secret Detection (Zero Tolerance)
Fail on ANY exposed secrets:
ff workflow run secret_detection . --wait --fail-on all
Nightly Fuzzing (Report Only)
Run long fuzzing campaigns without failing the build:
on:
schedule:
- cron: '0 2 * * *' # 2 AM daily
jobs:
fuzzing:
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- uses: actions/checkout@v4
- run: bash scripts/ci-start.sh
- run: pip install ./cli
- run: |
ff init --api-url http://localhost:8000
ff workflow run atheris_fuzzing . \
max_iterations=100000000 \
timeout_seconds=7200 \
--wait \
--export-sarif fuzzing-results.sarif
continue-on-error: true
- if: always()
run: bash scripts/ci-stop.sh
Release Gate
Block releases with ANY security findings:
on:
push:
tags:
- 'v*'
jobs:
release-security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: bash scripts/ci-start.sh
- run: pip install ./cli
- run: |
ff init --api-url http://localhost:8000
ff workflow run security_assessment . --wait --fail-on all
Performance Optimization
Startup Time
Current: ~60-90 seconds Breakdown:
- Docker daemon restart: 10-15s
- docker-compose up: 30-40s
- Health check wait: 20-30s
Tips to reduce:
- Use
docker-compose.ci.yml(optional, see below) - Cache Docker layers (GitHub Actions)
- Use self-hosted runners (persistent Docker)
Optional: CI-Optimized Compose File
Create docker-compose.ci.yml:
version: '3.8'
services:
postgresql:
# Use in-memory storage (faster, ephemeral)
tmpfs:
- /var/lib/postgresql/data
command: postgres -c fsync=off -c full_page_writes=off
minio:
# Use in-memory storage
tmpfs:
- /data
temporal:
healthcheck:
# More frequent health checks
interval: 5s
retries: 10
Usage:
docker-compose -f docker-compose.yml -f docker-compose.ci.yml up -d
Troubleshooting
"Permission denied" connecting to Docker socket
Solution: Add user to docker group or use sudo.
# GitHub Actions (already has permissions)
# GitLab CI: use docker:dind service
"Connection refused to localhost:8000"
Problem: Services not healthy yet.
Solution: Increase health check timeout in ci-start.sh:
timeout 180 bash -c 'until curl -sf http://localhost:8000/health; do sleep 3; done'
"Out of disk space"
Problem: Docker volumes filling up.
Solution: Cleanup in after_script:
after_script:
- bash scripts/ci-stop.sh
- docker system prune -af --volumes
Worker not starting
Problem: Worker container exists but not running.
Solution: Workers are pre-built but start on-demand (v0.7.0). If a workflow fails immediately, check:
docker logs fuzzforge-worker-<vertical>
Best Practices
- Always use
--waitin CI/CD pipelines - Set appropriate
--fail-onlevels for your use case:- PR checks:
error(block critical issues) - Release gates:
error,warning(stricter) - Nightly scans: Don't use (report only)
- PR checks:
- Export SARIF to integrate with security dashboards
- Set timeouts on CI jobs to prevent hanging
- Use artifacts to preserve findings for review
- Cleanup always with
if: always()orafter_script
Advanced: Persistent Backend Setup
For high-frequency usage, deploy FuzzForge on a dedicated server:
1. Deploy FuzzForge Server
# On your CI server
git clone https://github.com/FuzzingLabs/fuzzforge_ai.git
cd fuzzforge_ai
docker-compose up -d
2. Generate API Token (Future Feature)
# This will be available in a future release
docker exec fuzzforge-backend python -c "
from src.auth import generate_token
print(generate_token(name='github-actions'))
"
3. Configure CI to Use Remote Backend
env:
FUZZFORGE_API_URL: https://fuzzforge.company.com
FUZZFORGE_API_TOKEN: ${{ secrets.FUZZFORGE_TOKEN }}
steps:
- run: pip install fuzzforge-cli
- run: ff workflow run security_assessment . --wait --fail-on error
Note: Authentication is not yet implemented (v0.7.0). Use network isolation or VPN for now.
Examples
- GitHub Actions:
.github/workflows/examples/security-scan.yml - GitLab CI:
.gitlab-ci.example.yml - Startup Script:
scripts/ci-start.sh - Cleanup Script:
scripts/ci-stop.sh
Support
- Documentation: https://docs.fuzzforge.io
- Issues: GitHub Issues
- Discussions: GitHub Discussions