Skip to content

Latest commit

 

History

History
623 lines (469 loc) · 29.5 KB

AGENTS.md

File metadata and controls

623 lines (469 loc) · 29.5 KB

DaemonEye Development Guide

"We watch from the shadows — our eyes never close."

@GOTCHAS.md

Mission

DaemonEye is a silent observability and hunt layer for sensitive, restricted, and air-gapped environments. It turns endpoints into stealth honeypots: passive by default, surgically traceable on demand, and cryptographically auditable. Telemetry never leaves customer control unless explicitly exported by an operator.

This repository contains the open-source Community tier — the agent-side foundation that all higher tiers build upon:

  • procmond — privileged process collector, audit ledger, binary hashing
  • daemoneye-agent — detection orchestrator, alert delivery, event bus
  • daemoneye-cli — operator query interface and rule management
  • daemoneye-lib — shared library (config, models, storage, detection, crypto)
  • collector-core — SDK for building new collectors in any language

DaemonEye also ships in higher commercial tiers (sold separately, not in this repo). The Community tier is designed to participate in that larger architecture — protobuf IPC contracts, capability negotiation, and store-and-forward patterns are built in from the start so this repo is the real foundation, not a stripped-down afterthought. See evilbitlabs.io for commercial details.

Core use-case: ShadowHunt

The cornerstone scenario DaemonEye is built around:

  1. Passive baseline — procmond collects lightweight process metadata, parent/child relationships, and connection tuples into the local store (redb)
  2. Heuristic trigger — a detection rule (e.g., Apache → bash spawn) fires in the agent
  3. Silent trace — a TraceCommand targets the root PID and descendants for focused tracing without host-visible artifacts
  4. Focused capture — fork/exec, cmdline snapshots, file metadata, socket events — all cryptographically signed
  5. Cross-host stitching — if a traced process connects to a remote host running DaemonEye, the trace fans out via shared trace_id
  6. Analyst review — lineage graphs, replayable timeline, forensic SQL queries, signed export packages
  7. Manual action — analysts decide containment or continued surveillance; DaemonEye avoids automated enforcement

Every architectural decision in this repo — privilege separation, protobuf IPC, hash-chained audit ledger, SQL-based detection DSL, collector-core SDK — exists to serve this workflow.

Principles

Principle Description
Customer sovereignty All telemetry owned by the customer; no automatic egress to external services
Silent observation Default mode is passive; rules and traces generate no host-visible artifacts
Auditable forensics All events Ed25519-signed, recorded in write-only audit ledger
Air-gap friendly Fully functional offline; signed bundles for rule and update distribution
Privacy defaults Command args masked by default; RBAC for trace initiation

Source of Truth: Technical requirements for the Community tier live in spec/ and .kiro/specs/daemoneye-core-monitoring/. Higher-tier designs are maintained privately and are not part of this repo.


Quick Reference

Task Runner (justfile)

just fmt          # Format all code
just fmt-check    # Check formatting (CI-friendly)
just lint         # Runs fmt-check + clippy + lint-just
just build        # Build all binaries with features
just check        # Quick check without build
just test         # Run all tests

just run-procmond [args]        # Run procmond
just run-daemoneye-cli [args]   # Run daemoneye-cli
just run-daemoneye-agent [args] # Run daemoneye-agent

Core Commands

cargo build --workspace && cargo test --workspace
cargo clippy --workspace -- -D warnings
NO_COLOR=1 TERM=dumb cargo test --workspace  # Stable output
cargo bench                                   # Criterion benchmarks
cargo llvm-cov --all-features --workspace --lcov --output-path lcov.info

# GitHub CI monitoring
gh run list --branch <branch> --limit 5       # Check CI status
gh run view <run-id> --log-failed             # View failed job logs
gh run view <run-id> --json status,jobs       # JSON status check

Commit style: .github/commit-instructions.md


AI Assistant Rules

Behavior Guidelines

  1. No Merging: Never merge without a passing CI check and code review approval on a PR. This must be performed by a human maintainer, not an AI assistant.
  2. No Direct Commits to main: Never commit to main without explicit permission. Work on a feature branch and open a PR for review so all changes go through the proper CI and review process. (Committing to a feature branch during agentic work is expected; merging to main is the gated step — see rule 01.)
  3. Security-First: All changes must maintain least privilege and undergo security review.
  4. Zero-Warnings Policy: cargo clippy -- -D warnings with no exceptions.
  5. Operator-Centric: Prioritize workflows efficient in contested/airgapped environments.
  6. Documentation: Mermaid for diagrams, relative links, maintain link hygiene.
  7. Testing Required: All code changes must include appropriate tests.
  8. Linter Restrictions: Never remove clippy restrictions or deny attributes.
  9. File Size Limit: Keep source files under 500-600 lines when possible.
  10. AI Disclosure: Always disclose AI usage in PR descriptions, following the AI Usage Policy AI Usage Policy. Be transparent, but brief — no need to list every prompt, just the tools used (e.g., "Used Claude Code (Claude Opus 4.7 (1M Context)) for initial draft of detection engine refactor. All code reviewed and tested.").
  11. Compounding Learnings: After a solved, verified problem, automatically invoke the ce-compound skill with mode:non-interactive at the completion checkpoint only when the work produced durable project reasoning that is not readily recoverable from the final code, tests, types, comments, or existing documentation, and losing it would plausibly cause recurrence, material risk, or substantial rediscovery. Apply this counterfactual: if the learning document disappeared, would a future engineer reading the final implementation still be likely to repeat the mistake or redo substantial investigation? If not, do not invoke it. Completion, effort, and diff size alone are not enough. Capture at the checkpoint so a qualifying learning can ship in the PR that produced it, and only where the repository treats captured learnings as tracked, committed knowledge.
  12. Chat Register: Write every report, summary, or handoff to the user through the ce-noslop skill. This applies when you are the top-level agent writing to the user, not when you are a subagent reporting to its caller. Do not apply it to code, config, verbatim quotes, or text the user asked to post as written.

Rule Precedence

  1. Project Rules (AGENTS.md)
  2. Steering Documents (specs/, .kiro/steering/)
  3. Technical Specifications (.kiro/specs/)
  4. Embedded defaults

Architecture Overview

DaemonEye implements a three-component security architecture with strict privilege separation. This repo contains the host-side components. Commercial tiers extend this foundation with fleet management and centralized aggregation; those components live in separate private codebases and are not described here.

Components (this repo)

Component Privileges Network Database Function
procmond Elevated (drops after init) None Write-only (audit) Privileged process collector
daemoneye-agent Minimal Outbound-only Read/write (events) Detection orchestrator
daemoneye-cli Minimal None Read-only Operator CLI
daemoneye-lib N/A N/A N/A Shared library
collector-core N/A N/A N/A Collector SDK

Deployment architecture

flowchart LR
    subgraph "Host (this repo)"
        P[procmond] -->|IPC protobuf| A[daemoneye-agent]
        A -->|reads/writes| DB1[(Event Store)]
        P -->|writes| DB2[(Audit Ledger)]
        C[daemoneye-cli] -->|reads| DB1 & DB2
    end
    A -->|outbound alerts| EXT[(Alert Sinks)]
    A -.->|optional upstream| UP[External tiers]
Loading

The dashed line to "External tiers" indicates that daemoneye-agent's outbound IPC contract is designed to support upstream aggregation in commercial deployments. The upstream components are not part of this repo.

Security Boundaries

  • Privilege Separation: Only procmond runs elevated when necessary
  • IPC: Protobuf over Unix sockets/named pipes with CRC32 validation
  • No Inbound Network: Outbound-only for alert delivery
  • SQL Injection Prevention: AST validation with sqlparser, prepared statements only [Implemented: rule load-time validation, and RuleExecutor runs rules over DataFusion — see detection/execution/]

Technology Stack

Core

Category Technology
Language Rust 2024 Edition (MSRV: 1.95+)
Async Tokio
Database redb (pure Rust embedded)
CLI clap v4 with derive
Process Enum sysinfo
Logging tracing ecosystem
Config YAML/TOML via figment
IPC interprocess + protobuf
Event Bus daemoneye-eventbus + tokio
Testing cargo-nextest, insta, criterion

Dependencies

Category Crate Version
Runtime tokio 1.0+
Serialization serde 1.0+
CLI clap 4.0+
Database redb 4.2+
Process sysinfo 0.37+
Logging tracing 0.1+
Errors thiserror 2.0+
Errors anyhow 1.0+
Crypto blake3 1.8+
Crypto rs-merkle 1.5+
Testing insta 1.0+
Benchmarks criterion 0.7+

OS Support

OS Version Arch Status
Linux Ubuntu 20.04+ LTS, RHEL/CentOS 8+, Debian 11+ x86_64, ARM64 Primary
macOS 14.0+ (Sonoma) x86_64, ARM64 Primary
Windows 10+, Server 2019+ x86_64, ARM64 Primary
Linux Alpine 3.16+, Amazon Linux 2+ x86_64, ARM64 Secondary
FreeBSD 13.0+ x86_64, ARM64 Secondary

Coding Standards

Rust Requirements

  • Edition: Rust 2024 (MSRV: 1.95+)
  • Linting: cargo clippy -- -D warnings (zero warnings)
  • Clippy/rustdoc lint traps: see GOTCHAS.md §5
  • Safety: unsafe_code = "forbid" at workspace level
  • Formatting: rustfmt with 119 char line length
  • Errors: thiserror for structured errors, anyhow for context
  • Async: Async-first with Tokio
  • Logging: Structured with tracing
  • Strictness: warnings = "deny" at workspace; allow requires justification

Pre-commit Requirements

  1. cargo clippy -- -D warnings (zero warnings)
  2. cargo fmt --all --check (formatting)
  3. cargo test --workspace (all tests pass)
  4. just lint-just (justfile syntax)
  5. No new unsafe without approval
  6. Benchmarks within acceptable ranges

Gotchas: see GOTCHAS.md (pre-commit hook behavior is in §1.3).


Security Model

Core Requirements

  • Least privilege: Components run with minimal permissions
  • Automatic privilege drop after initialization
  • SQL injection prevention: AST validation at rule load time [Implemented]; SQL-based rule execution [Implemented: RuleExecutor over DataFusion, see detection/execution/]. Pipeline is two-phase: sqlparser lowers the custom dialect (spec §4.10) at rule-compile time into (a) protobuf collection tasks and (b) derived standard SQL; the runtime executor only sees the derived SQL, never the original dialect.
  • Credentials: Environment variables or OS keychain, never hardcoded
  • No inbound network: Outbound-only for alerts
  • Audit trail: BLAKE3 hash-chained audit ledger [Implemented]; Merkle tree inclusion proofs [In Progress — generate_inclusion_proof() returns empty vec, see crypto.rs]

Planned Hardening (Community)

  • SLSA Level 3 provenance, Cosign signatures [Planned]
  • Merkle tree with inclusion proofs [In Progress — chain hashing implemented; inclusion proof generation stubbed in crypto.rs]
  • Sandboxed detection engine (read-only DB) [Planned]
  • Query whitelist (SELECT only with approved functions) [Implemented: the load-time allowlist refuses any other function call, and the executor registers only those seven functions (hex, instr, length, like, match, regexp, unhex), replacing DataFusion's defaults. Function-like syntax that parses to its own AST node (SUBSTR, TRIM, POSITION, ...) is refused at load by variant, so nothing loads that the executor cannot run]

Fleet-level transport security (mTLS between host agents and upstream aggregators) is handled in the commercial tiers, not in this repo.

Integer Overflow Protection

[profile.release]
overflow-checks = true
lto = "thin"
codegen-units = 1

Use checked_*, saturating_*, or explicit wrapping_* for security-sensitive calculations.

Safe Concurrency

  • Tokio primitives: Semaphore, mpsc, oneshot, watch, Notify
  • Lock scope: Never await while holding locks
  • Async locks: tokio::sync::Mutex/RwLock for async; std::sync for sync-only
  • Bounded concurrency: Use Semaphore with defined capacity
  • Linting: Enable clippy::await_holding_lock = "deny"

Cryptographic Standards

Purpose Approved
Hashing BLAKE3, SHA2 (never SHA-1)
Hash roles SHA-256 = executable identity (TI interop); ssdeep = binary change detection; BLAKE3 = audit ledger/forensic
Signatures ed25519-dalek
AEAD chacha20poly1305, aes-gcm
KDF HKDF-SHA256, Argon2id
TLS rustls (TLS 1.2+ min, 1.3 preferred)
Entropy getrandom
Secrets secrecy, zeroize crates

Input Validation

  • Treat all external inputs as untrusted
  • Validate early, reject with actionable errors
  • Use typed parsers over regex
  • Length limits on all variable-length inputs (Unix socket-path limit: GOTCHAS.md §4.1)
  • SQL: AST validation with sqlparser [Implemented at rule load time; at execution the session registers only the allowlisted functions, see detection/execution/session.rs]

Newtype Safety

Use newtypes for domain constraints (ports vs PIDs vs timestamps). Implement TryFrom with validation.

Dependency Security

  • Commit Cargo.lock, use resolver = "3"
  • Pin security-critical deps, avoid wildcards
  • default-features = false, enable only needed
  • Git deps: pin to commit SHA
  • Tools: cargo audit, cargo deny, cargo vet

Performance Budgets

Metric Target
CPU Usage < 5% sustained
Memory < 100 MB resident
Process Enum < 5s for 10,000+ processes
DB Writes > 1,000 records/sec
Alert Latency < 100ms per rule
Query Response Sub-second for 100k+ events/min

These are targets for a reference host, not hard bounds. Resident memory in particular scales with the deployment: a large, busy server may sit higher and a constrained embedded or SCADA endpoint lower. Size the tunables that govern it to the host rather than treating the number as a pass/fail gate.

Resource Management

  • Bounded channels with backpressure
  • Memory budget enforcement
  • Cancellation tokens for graceful shutdown
  • Circuit breakers for external dependencies
  • Graceful degradation when constrained

Code Organization

Workspace Structure

DaemonEye/
├── Cargo.toml              # Workspace root
├── procmond/               # Privileged collector
├── daemoneye-agent/        # Detection orchestrator
├── daemoneye-cli/          # Operator CLI
├── daemoneye-lib/          # Shared library
│   ├── proto/              # Protobuf definitions
│   └── src/
│       ├── alerting.rs     # Alert delivery
│       ├── config.rs       # Configuration
│       ├── crypto.rs       # Cryptographic functions
│       ├── detection.rs    # SQL detection engine
│       ├── models.rs       # Data structures
│       └── storage.rs      # Database (redb)
├── collector-core/         # Collector framework
├── tests/                  # Integration tests
├── docs/solutions/         # Documented solutions to past problems (bugs, best practices, workflow patterns), by category with YAML frontmatter (module, tags, problem_type) — relevant when implementing or debugging in documented areas
├── CONCEPTS.md             # Shared domain vocabulary (entities, named processes, status concepts) — relevant when orienting to the codebase or discussing domain concepts
└── .kiro/                  # Steering docs & specs

Service Layer Pattern

#[async_trait]
pub trait ProcessCollectionService: Send + Sync {
    async fn collect_processes(&self) -> Result<CollectionResult, CollectionError>;
}

#[async_trait]
pub trait AlertSink: Send + Sync {
    async fn send(&self, alert: &Alert) -> Result<DeliveryResult, AlertingError>;
    fn name(&self) -> &str;
    async fn health_check(&self) -> Result<(), AlertingError>;
}

Testing Strategy

Three-Tier Architecture

Tier Scope Tools
Unit Individual components tokio-test, trait mocking
Integration Cross-component insta, predicates, real redb
E2E (Optional) Full system workflows Test data seeding

Quality Tools

  • Runner: cargo-nextest (parallel, failure isolation)
  • Coverage: llvm-cov (target: >85%)
  • Property: proptest for edge cases
  • Fuzz: Security-critical components
  • Snapshot: insta for CLI output

Test Environment

NO_COLOR=1 TERM=dumb cargo test --workspace           # Stable output
RUST_BACKTRACE=1 cargo test -p daemoneye-lib --nocapture  # Debug
cargo bench --baseline previous                        # Regression

CI Matrix

  • Platforms: Linux, macOS, Windows
  • Rust: stable, beta, MSRV (1.95+)
  • Architectures: x86_64, ARM64

Database Design

redb Tables

Table Access Component
processes R/W agent
scans R/W agent
detection_rules R/W agent
alerts R/W agent
alert_deliveries R/W agent
audit_ledger W (procmond), R (others) procmond

Core Data Types

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ProcessInfo {
    pub pid: u32,
    pub ppid: Option<u32>,
    pub name: String,
    pub executable_path: Option<String>,
    pub command_line: Option<String>,
    pub start_time: Option<DateTime<Utc>>,
    pub cpu_usage: Option<f64>,
    pub memory_usage: Option<u64>,
    pub status: ProcessStatus,
    pub executable_hash: Option<String>, // SHA-256
    pub collection_time: DateTime<Utc>,
}

#[derive(Debug, Error)]
pub enum CollectionError {
    #[error("Permission denied accessing process {pid}")]
    PermissionDenied { pid: u32 },
    #[error("Process {pid} no longer exists")]
    ProcessNotFound { pid: u32 },
    #[error("Database operation failed: {0}")]
    DatabaseError(String),
    #[error("IPC communication failed: {0}")]
    IpcError(String),
}

CLI & Configuration

CLI Design (clap v4)

#[derive(Parser)]
#[command(name = "procmond", about = "Process monitoring daemon")]
pub struct Cli {
    #[command(subcommand)]
    pub command: Commands,
    #[arg(short, long)]
    pub config: Option<PathBuf>,
    #[arg(short, long, default_value = "info")]
    pub log_level: String,
}
  • Use --json for machine-readable output
  • Respect NO_COLOR and TERM=dumb
  • Provide actionable error messages

Configuration Precedence

  1. Command-line flags
  2. Environment variables (component-namespaced: DAEMONEYE_AGENT_*, DAEMONEYE_CLI_*, PROCMOND_*)
  3. User config (~/.config/daemoneye/config.toml)
  4. System config (/etc/daemoneye/config.toml)
  5. Embedded defaults

Alert System

  • Trait-based plugin system (AlertSink trait)
  • Concurrent delivery to multiple sinks
  • Retry with exponential backoff
  • Circuit breaking for failing sinks
  • Delivery audit trail

CI/CD & Reviews

Continuous Integration

  • GitHub Actions: Linux, macOS, Windows matrix
  • Rust: stable, beta, MSRV (1.95+)
  • Checks: fmt, clippy strict, tests, benchmarks
  • Security: Dependency scanning, SLSA provenance

Security Scanners

Code Review

  • Primary tool: coderabbit.ai
  • Security focus, performance assessment
  • Single maintainer: UncleSp1d3r

Commit Standards

  • Format: Conventional Commits
  • Types: feat, fix, docs, style, refactor, perf, test, build, ci, chore
  • Breaking: ! in header or BREAKING CHANGE: in footer

Contribution Checklists

Adding a Detection Rule

Files: daemoneye-lib/src/detection.rs, daemoneye-lib/src/models.rs, daemoneye-agent/src/rules/, tests/integration/

  • Define rule structure with SQL and metadata
  • Implement AST validation (sqlparser)
  • Unit tests with mock data
  • Integration test via agent
  • Validate alert delivery via CLI
  • cargo clippy -- -D warnings passes
  • Performance test if complex
  • Rustdoc documentation

Adding a CLI Option

Files: daemoneye-cli/src/main.rs, daemoneye-lib/src/config.rs, tests/integration/

  • Update clap derive structures
  • Configuration handling in lib
  • Help text and defaults
  • Insta snapshot tests
  • Test short/long forms
  • Validate with NO_COLOR=1 TERM=dumb
  • Update shell completions
  • Rustdoc documentation

Optimizing Database Write Path

Files: daemoneye-lib/src/storage.rs, procmond/src/collector.rs, benches/

  • Establish criterion baseline
  • Implement optimization
  • Batch processing if applicable
  • Validate >1000 records/sec
  • Test with 10k+ processes
  • Memory profiling
  • ACID guarantees maintained
  • Document characteristics

Open-Core Hygiene (any PR touching docs, specs, or AGENTS.md)

DaemonEye is the Community tier of an open-core product. Content for commercial tiers lives in separate private codebases and Confluence — not here.

  • No paid-tier feature enumerations (Business/Enterprise specifics, Security Center internals, fleet-management details, STIX/TAXII, federation)
  • No internal-only URLs (private Confluence hyperlinks, Jira ticket IDs, internal Slack references, pricing specifics)
  • No references to deleted files (sweep for pricing.md, feature-tiers.md, business-tier.md, enterprise-tier.md, product_strategy.md, spec/product.md, spec/procmond/)
  • Boundary-acknowledgement footnotes preferred over erasure ("commercial tiers extend this foundation, sold separately, not in this repo")
  • Never delete a repo doc without first verifying the Confluence copy fully matches — see docs/solutions/workflow-issues/open-core-hygiene-confluence-migration-2026-04-18.md for the eight-phase workflow

Code Generation Guidelines

When generating code:

  1. Use Rust 2024 Edition
  2. Comprehensive error handling with thiserror
  3. Async/await with Tokio
  4. Tests with insta for snapshots
  5. Service layer pattern with traits
  6. Logging with tracing
  7. Workspace inheritance for deps
  8. Performance considerations
  9. Security best practices
  10. Rustdoc for public APIs

Source-of-Truth Map

Section Source
Architecture .kiro/steering/structure.md
Technology .kiro/steering/tech.md
Product .kiro/steering/product.md
Core Requirements .kiro/specs/daemoneye-core-monitoring/requirements.md
Development .kiro/steering/development.md
SQL-to-IPC Pipeline spec/daemon_eye_spec_sql_to_ipc_detection_architecture.md
Detection Execution (binding) ADR-0006: Apache DataFusion over redb TableProviders (spec §9/§11). Detection-engine requirements are R17–R24 in the core spec (merged 2026-06-09; the former upcoming-specs/sql-to-ipc-detection-engine/ is deleted)
Architecture Decision Records docs/adr/ for ADRs recorded in this repo; ADR-0001 through ADR-0007 live in the Confluence ES space and are cited by number only
v1.0 Scope Priority Tiers table in .kiro/specs/daemoneye-core-monitoring/requirements.md — R1–R10 are the v1.0 bar

Cross-References


Glossary

Term Definition
AST Abstract Syntax Tree (SQL validation)
BLAKE3 Cryptographic hash for audit trails
CEF Common Event Format
eBPF Extended Berkeley Packet Filter
ETW Event Tracing for Windows
IPC Inter-Process Communication
redb Pure Rust embedded database
SLSA Supply-chain Levels for Software Artifacts

Remember: DaemonEye is security-focused. Prioritize security, performance, and reliability. When in doubt, choose the more secure and observable approach.

Agent Rules

@.tessl/RULES.md follow the instructions