diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..60e0be93 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,106 @@ +# AGENTS.md + +## Project Overview + +fact (File ACTivity) is a BPF-based file integrity monitoring tool for PCI DSS compliance. It attaches to kernel LSM hooks, receives file system events via ring buffers, enriches them, and outputs via gRPC, OTLP, or JSON. Supports hot-reload via SIGHUP and exposes Prometheus metrics. + +Requires: BTF symbols, LSM hooks, BPF trampolines. Tested on RHEL 9.6+/10+, RHCOS 4.16+, Fedora CoreOS 43. + +## Workspace Structure + +Cargo workspace with three crates (`default-members = ["fact"]`, so bare `cargo build` only builds the main crate): + +- **fact** (edition 2024): Main binary — BPF loading (aya), event processing, config, output, metrics +- **fact-api** (edition 2021): gRPC API generated from protos in `third_party/stackrox/proto` (git submodule) +- **fact-ebpf** (edition 2021): BPF C programs (`src/bpf/main.c`, `checks.c`) + Rust bindings via bindgen + +### Build system dependencies + +`libbpf-dev`, `protobuf-compiler`, `clang` (for BPF compilation), `make`, `git` (build.rs runs `make version` to embed git tag). + +Proto submodule: `git submodule update --init` after fresh clone. + +## Commands + +### Build & check +```sh +cargo build # builds only `fact` (default member) +cargo build --release +cargo check +``` + +### Lint +```sh +make lint # cargo clippy --all-targets --all-features -- -D warnings + tests/ +cargo clippy --all-targets --all-features -- -D warnings # Rust only +``` + +### Format +```sh +make format # cargo fmt + clang-format (BPF C/H) + ruff format tests/ +make format-check # check only, no modifications +``` + +### Test + +**Rust unit tests** (no sudo needed): +```sh +cargo test +``` + +**BPF unit tests** (requires sudo, avoid in automated workflows): +```sh +cargo test --config 'target."cfg(all())".runner="sudo -E"' --features=bpf-test +``` + +**Integration tests** (require Docker, a built image, and proto codegen): +```sh +make image # build container image first +python3 -m venv .venv # create venv (first time) +source .venv/bin/activate # activate venv +pip install -r tests/requirements.txt # install deps (first time) +cd tests/ +make grpc-gen # generate Python proto stubs +pytest --image="" # run all tests +pytest test_file_open.py --image="" # single file +pytest --output=otlp --image="" # test OTLP output +``` + +Integration tests use the Docker Python SDK — they launch `fact` in a privileged container with `--network=host`, bind-mount `/` as `/host`, and communicate via gRPC/OTLP mock servers + health check endpoint. Python linting: `ruff check . && pyright .` (from `tests/`). + +### Run locally (requires sudo) +```sh +cargo run --release --config 'target."cfg(all())".runner="sudo -E"' -- -p /etc -p /var/log +``` + +## Key Architecture Notes + +### Event flow +1. Kernel LSM hooks → BPF programs (`fact-ebpf/src/bpf/main.c`) → ring buffer +2. `Bpf` worker (`fact/src/bpf/mod.rs`) reads ring buffer → channel +3. `HostScanner` (`fact/src/host_scanner.rs`) does periodic inode scanning +4. Rate limiting (`fact/src/rate_limiter.rs`) → output (gRPC/OTLP/JSON) + +### Event type definitions +`fact-ebpf/src/bpf/types.h` is the single source of truth for event structs and enums. `build.rs` runs bindgen on it to generate `$OUT_DIR/bindings.rs`, which `lib.rs` pulls in via `include!`. Edit only `types.h` — Rust bindings are generated automatically. + +### BPF build integration +`fact-ebpf/build.rs` compiles `main.c` and `checks.c` with clang targeting BPF, then runs bindgen on `types.h`. BPF objects are embedded in the binary. No manual clang invocation needed. + +### Config +- Schema: `fact/src/config/mod.rs` +- Hot-reload: `fact/src/config/reloader/mod.rs` (polls every 10s + SIGHUP trigger) +- Config tests: `fact/src/config/tests.rs` and `fact/src/config/reloader/tests.rs` +- Config loaded from YAML files, env vars, or CLI args + +### Feature flags +- `bpf-test`: gates tests that load actual BPF programs (requires sudo) +- `otel`: enables OpenTelemetry/OTLP output (`fact/Cargo.toml`) + +## Gotchas + +- `config.toml` at workspace root sets `rustflags = ["-C", "force-frame-pointers=yes"]` — this affects all builds +- `fact/build.rs` shells out to `make -sC .. version` to embed the git version string — builds fail without `make` and a valid git repo +- `CLANG_FMT` defaults to `clang-format`; CI uses `clang-format-18`. Override via env if your system name differs +- `CLAUDE.md` exists alongside this file with identical content — `AGENTS.md` is canonical +- Prometheus metrics use prefix `stackrox_fact` diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 47a71271..00000000 --- a/CLAUDE.md +++ /dev/null @@ -1,184 +0,0 @@ -# CLAUDE.md - -This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. - -## Project Overview - -fact (File ACTivity) is a file integrity monitoring tool designed for PCI DSS compliance. It's implemented as a BPF agent that: -- Attaches BPF programs to LSM (Linux Security Module) hooks in the kernel -- Receives file system events from the kernel via ring buffers -- Enriches events with process and file metadata -- Outputs events via gRPC or JSON for further processing -- Supports hot-reload of configuration via SIGHUP -- Exposes Prometheus metrics - -The project requires modern kernel features (BTF symbols, LSM hooks, BPF trampolines) and is tested on RHEL 9.6+/10+, RHCOS 4.16+, and Fedora CoreOS 43. - -## Workspace Structure - -This is a Cargo workspace with three main crates: - -- **fact**: Main binary that loads BPF programs, processes events, and handles output - - `src/bpf/`: Rust code for loading and managing BPF programs (uses aya library) - - `checks.rs`: Kernel capability detection (e.g., `bpf_d_path` support) - - `src/event/`: Event processing and enrichment logic - - `src/config/`: Configuration parsing and hot-reload via `Reloader` - - `src/output/`: gRPC and JSON output handlers - - `src/metrics/`: Prometheus metrics subsystem - - `exporter.rs`: HTTP metrics exposition (prefix `stackrox_fact`) - - `kernel_metrics.rs`: Per-hook LSM event counters - - `host_scanner.rs`: HostScanner-specific metrics (scans, inodes, files) - - `src/host_scanner.rs`: Periodic host filesystem scanning and userspace inode tracking - - `src/endpoints.rs`: HTTP server for Prometheus metrics endpoint - - `src/rate_limiter.rs`: Event rate limiting via `governor` crate - - `src/pre_flight.rs`: Pre-flight checks (verifies LSM BPF capability) - - `src/host_info.rs`: Host mount handling, distro detection, kernel/arch info - -- **fact-api**: gRPC API definitions generated from protobuf files in `third_party/stackrox/proto` - -- **fact-ebpf**: BPF program implementation - - `src/bpf/*.{c,h}`: C code for BPF programs (`main.c`, `checks.c`) and headers (event definitions, maps, types, vmlinux) - - `src/lib.rs`: Rust bindings and types for BPF maps/events - - Build script compiles C code to BPF bytecode and generates Rust bindings via bindgen - -## Key Architecture Patterns - -### Event Flow -1. Kernel LSM hooks trigger BPF programs (in `fact-ebpf/src/bpf/main.c`); `checks.c` runs kernel capability probes at startup -2. BPF programs write events to ring buffer -3. `Bpf` worker (in `fact/src/bpf/mod.rs`) reads from ring buffer, sends to channel -4. `HostScanner` (in `fact/src/host_scanner.rs`) periodically scans monitored paths and handles userspace inode tracking -5. Events pass through rate limiting (`fact/src/rate_limiter.rs`) -6. Output handlers (in `fact/src/output/`) send to gRPC or stdout as JSON - -### Build Integration -- Cargo build scripts (`build.rs` files) automatically compile BPF C code -- BPF object files are embedded in the Rust binary -- No manual BPF compilation needed for normal development - -### Configuration -- Config loaded from YAML files or environment variables/CLI args -- `Reloader` monitors for SIGHUP and reloads config without restart -- Paths to monitor can be specified via `--paths` or `FACT_PATHS` - -## Common Commands - -### Building -```sh -# Standard build -cargo build - -# Release build (optimized) -cargo build --release - -# Check without building -cargo check -``` - -### Running -```sh -# Run with sudo (required for BPF) -cargo run --release --config 'target."cfg(all())".runner="sudo -E"' - -# With path monitoring -cargo run --release --config 'target."cfg(all())".runner="sudo -E"' -- -p /etc -p /var/log - -# Skip pre-flight checks (if LSM hook detection fails) -cargo run --release --config 'target."cfg(all())".runner="sudo -E"' -- --skip-pre-flight -``` - -### Testing - -**For agents/automated testing, prefer using pytest integration tests** (no sudo required): - -```sh -# Set up Python virtual environment (first time only) -python3 -m venv .venv -source .venv/bin/activate -pip install -r tests/requirements.txt - -# Build container image first -make image - -# Run integration tests with pytest (recommended for agents) -cd tests/ -pytest --image="" # e.g., pytest --image="quay.io/stackrox-io/fact:latest" - -# Run specific test file -pytest test_file_open.py --image="" -``` - -**Rust unit tests** (for development): - -```sh -# Run Rust unit tests (excludes BPF tests, no sudo needed) -cargo test - -# Run BPF-specific unit tests (requires sudo, avoid in automated workflows) -cargo test --config 'target."cfg(all())".runner="sudo -E"' --features=bpf-test -``` - -**Other test targets**: - -```sh -# Run integration tests via Make (uses ansible, requires VMs) -make integration-tests - -# Run performance tests -make performance-tests -``` - -### Formatting -```sh -# Format Rust and C code -make format - -# Check formatting without modifying files -make format-check -``` - -### Container Image -```sh -# Build container image -make image - -# Build mock server for testing -make mock-server -``` - -### IDE Support for BPF C Code -Generate `compile_commands.json` for clangd on x86_64: -```sh -bear -- clang -target bpf -O2 -g -c -Wall -Werror -D__TARGET_ARCH_x86_64 fact-ebpf/src/bpf/main.c -o /dev/null -``` -For arm64, use `-D__TARGET_ARCH_aarch64` instead. - -## Development Workflow - -### Making Changes to BPF Code -1. Edit C files in `fact-ebpf/src/bpf/` -2. Follow existing patterns in `main.c` for LSM hook attachments -3. Format with `make -C fact-ebpf format` -4. Test with `cargo test --features=bpf-test` (requires sudo) - -### Making Changes to Event Processing -1. Event definitions are in `fact-ebpf/src/bpf/events.h` (C) and `fact-ebpf/src/lib.rs` (Rust bindings) -2. Processing logic is in `fact/src/event/mod.rs` and `fact/src/event/process.rs` -3. Changes to event structure require updates to both C and Rust definitions - -### Configuration Changes -1. Configuration schema is in `fact/src/config/mod.rs` -2. Hot-reload logic is in `fact/src/config/reloader.rs` -3. Add unit tests in `fact/src/config/tests.rs` - -## Important Notes - -- **Preferred testing for agents**: Use pytest integration tests in `tests/` directory (no sudo required) -- **Python environment**: All Python dependencies must be installed in a virtual environment at `.venv` -- All BPF operations require root/sudo privileges (avoid in automated testing when possible) -- The `bpf-test` feature gates tests that load actual BPF programs and requires sudo -- Build scripts handle BPF compilation automatically - no need to run clang manually -- Pytest integration tests require a built container image (use `make image` first) -- The project uses `sudo -E` to preserve environment variables when running with elevated privileges -- SIGHUP triggers configuration reload without restarting the process -- Proto files live in a git submodule (`third_party/stackrox`); run `git submodule update --init` after a fresh clone to build `fact-api` diff --git a/CLAUDE.md b/CLAUDE.md new file mode 120000 index 00000000..47dc3e3d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +AGENTS.md \ No newline at end of file