Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,21 @@ APP_HOST=0.0.0.0
APP_PORT=5000
DATABASE_URL=stackdog.db
RUST_BACKTRACE=full

# Log Sniff Configuration
#STACKDOG_LOG_SOURCES=/var/log/syslog,/var/log/auth.log
#STACKDOG_SNIFF_INTERVAL=30
#STACKDOG_SNIFF_OUTPUT_DIR=./stackdog-logs/

# AI Provider Configuration
# Supports OpenAI, Ollama (http://localhost:11434/v1), or any OpenAI-compatible API
#STACKDOG_AI_PROVIDER=openai
#STACKDOG_AI_API_URL=http://localhost:11434/v1
#STACKDOG_AI_API_KEY=
#STACKDOG_AI_MODEL=llama3

# Notification Channels
# Slack: create an incoming webhook at https://api.slack.com/messaging/webhooks
#STACKDOG_SLACK_WEBHOOK_URL=https://hooks.slack.com/services/T.../B.../xxxxx
# Generic webhook endpoint for alert notifications
#STACKDOG_WEBHOOK_URL=https://example.com/webhook
113 changes: 113 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Stackdog Security — Copilot Instructions

## What This Project Is

Stackdog is a Rust-based security platform for Docker containers and Linux servers. It collects events via eBPF syscall monitoring, runs them through a rule/signature engine and optional ML anomaly detection, manages firewall responses (nftables/iptables + container quarantine), and exposes a REST + WebSocket API consumed by a React/TypeScript dashboard.

## Workspace Structure

This is a Cargo workspace with two crates:
- `.` — Main crate (`stackdog`): HTTP server, all security logic
- `ebpf/` — Separate crate (`stackdog-ebpf`): eBPF programs compiled for the kernel (uses `aya-ebpf`)

## Build, Test, and Lint Commands

```bash
# Build
cargo build
cargo build --release

# Tests
cargo test --lib # Unit tests only (in-source)
cargo test --all # All tests including integration
cargo test --lib -- events:: # Run tests for a specific module
cargo test --lib -- rules::scorer # Run a single test by name prefix

# Code quality
cargo fmt --all
cargo clippy --all
cargo audit # Dependency vulnerability scan

# Benchmarks
cargo bench

# Frontend (in web/)
npm test
npm run lint
npm run build
```

## Environment Setup

Requires a `.env` file (copy `.env.sample`). Key variables:
```
APP_HOST=0.0.0.0
APP_PORT=5000
DATABASE_URL=stackdog.db
RUST_BACKTRACE=full
```

System dependencies (Linux): `libsqlite3-dev libssl-dev clang llvm pkg-config`

## Architecture

```
Collectors (Linux only) Rule Engine Response
eBPF syscall events → Signatures → nftables/iptables
Docker daemon events → Threat scoring → Container quarantine
Network events → ML anomaly det. → Alerting

REST + WebSocket API
React/TypeScript UI
```

**Key src/ modules:**

| Module | Purpose |
|---|---|
| `events/` | Core event types: `SyscallEvent`, `SecurityEvent`, `NetworkEvent`, `ContainerEvent` |
| `rules/` | Rule engine, signature database, threat scorer |
| `alerting/` | `AlertManager`, notification channels (Slack/email/webhook) |
| `collectors/` | eBPF loader, Docker daemon events, network collector (Linux only) |
| `firewall/` | nftables management, iptables fallback, `QuarantineManager` (Linux only) |
| `ml/` | Candle-based anomaly detection (optional `ml` feature) |
| `correlator/` | Event correlation engine |
| `baselines/` | Baseline learning for anomaly detection |
| `database/` | SQLite connection pool (`r2d2` + raw `rusqlite`), repositories |
| `api/` | actix-web REST endpoints + WebSocket |
| `response/` | Automated response action pipeline |

## Key Conventions

### Platform-Gating
Linux-only modules (`collectors`, `firewall`) and deps (aya, netlink) are gated:
```rust
#[cfg(target_os = "linux")]
pub mod firewall;
```
The `ebpf` and `ml` features are opt-in and must be enabled explicitly:
```bash
cargo build --features ebpf
cargo build --features ml
```

### Error Handling
- Use `anyhow::{Result, Context}` for application/binary code
- Use `thiserror` for library error types
- Never use `.unwrap()` in production code; use `?` with `.context("...")`

### Database
The project uses raw `rusqlite` with `r2d2` connection pooling. `DbPool` is `r2d2::Pool<SqliteConnectionManager>`. Tables are created with `CREATE TABLE IF NOT EXISTS` in `database::connection::init_database`. Repositories are in `src/database/repositories/` and receive a `&DbPool`.

### API Routes
Each API sub-module exports a `configure_routes(cfg: &mut web::ServiceConfig)` function. All routes are composed in `api::configure_all_routes`, which is the single call site in `main.rs`.

### Test Location
- **Unit tests**: `#[cfg(test)] mod tests { ... }` inside source files
- **Integration tests**: `tests/` directory at workspace root

### eBPF Programs
The `ebpf/` crate is compiled separately for the Linux kernel. User-space loading is handled by `src/collectors/ebpf/` using the `aya` library. Kernel-side programs use `aya-ebpf`.

### Async Runtime
The main binary uses `#[actix_rt::main]`. Library code uses `tokio`. Avoid mixing runtimes.
4 changes: 2 additions & 2 deletions .github/workflows/codacy-analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ jobs:
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout code
uses: actions/checkout@v2
uses: actions/checkout@v4

# Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis
- name: Run Codacy Analysis CLI
Expand All @@ -41,6 +41,6 @@ jobs:

# Upload the SARIF file generated in the previous step
- name: Upload SARIF results file
uses: github/codeql-action/upload-sarif@v1
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: results.sarif
36 changes: 20 additions & 16 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ on:
jobs:
cicd-linux-docker:
name: Cargo and npm build
runs-on: ubuntu-latest
#runs-on: ubuntu-latest
runs-on: [self-hosted, linux]
steps:
- name: Checkout sources
uses: actions/checkout@v2
uses: actions/checkout@v4

- name: Install stable toolchain
uses: actions-rs/toolchain@v1
Expand All @@ -26,7 +27,7 @@ jobs:
components: rustfmt, clippy

- name: Cache cargo registry
uses: actions/cache@v2.1.6
uses: actions/cache@v4
with:
path: ~/.cargo/registry
key: docker-registry-${{ hashFiles('**/Cargo.lock') }}
Expand All @@ -35,7 +36,7 @@ jobs:
docker-

- name: Cache cargo index
uses: actions/cache@v2.1.6
uses: actions/cache@v4
with:
path: ~/.cargo/git
key: docker-index-${{ hashFiles('**/Cargo.lock') }}
Expand All @@ -48,7 +49,7 @@ jobs:
head -c16 /dev/urandom > src/secret.key

- name: Cache cargo build
uses: actions/cache@v2.1.6
uses: actions/cache@v4
with:
path: target
key: docker-build-${{ hashFiles('**/Cargo.lock') }}
Expand Down Expand Up @@ -101,15 +102,15 @@ jobs:
# npm test

- name: Archive production artifacts
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v4
with:
name: dist-without-markdown
path: |
web/dist
!web/dist/**/*.md

# - name: Archive code coverage results
# uses: actions/upload-artifact@v2
# uses: actions/upload-artifact@v4
# with:
# name: code-coverage-report
# path: output/test/code-coverage.html
Expand All @@ -128,18 +129,19 @@ jobs:
cd ..

- name: Upload app archive for Docker job
uses: actions/upload-artifact@v2.2.2
uses: actions/upload-artifact@v4
with:
name: artifact-linux-docker
path: app.tar.gz

cicd-docker:
name: CICD Docker
runs-on: ubuntu-latest
#runs-on: ubuntu-latest
runs-on: [self-hosted, linux]
needs: cicd-linux-docker
steps:
- name: Download app archive
uses: actions/download-artifact@v2
uses: actions/download-artifact@v4
with:
name: artifact-linux-docker

Expand All @@ -149,12 +151,14 @@ jobs:
- name: Display structure of downloaded files
run: ls -R

- name: Docker build and publish
uses: docker/build-push-action@v1
- name: Login to Docker Hub
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: trydirect/stackdog
add_git_labels: true
tag_with_ref: true
#no-cache: true

- name: Docker build and publish
uses: docker/build-push-action@v6
with:
push: true
tags: trydirect/stackdog:latest
77 changes: 77 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
name: Release

on:
push:
tags:
- "v*"

permissions:
contents: write

env:
CARGO_TERM_COLOR: always

jobs:
build:
name: Build ${{ matrix.target }}
runs-on: ubuntu-latest
strategy:
matrix:
include:
- target: x86_64-unknown-linux-gnu
artifact: stackdog-linux-x86_64
- target: aarch64-unknown-linux-gnu
artifact: stackdog-linux-aarch64

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
targets: ${{ matrix.target }}

- name: Install cross
run: cargo install cross --git https://github.com/cross-rs/cross

- name: Build release binary
run: cross build --release --target ${{ matrix.target }}

- name: Package
run: |
mkdir -p dist
cp target/${{ matrix.target }}/release/stackdog dist/stackdog
cd dist
tar czf ${{ matrix.artifact }}.tar.gz stackdog
sha256sum ${{ matrix.artifact }}.tar.gz > ${{ matrix.artifact }}.tar.gz.sha256

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: |
dist/${{ matrix.artifact }}.tar.gz
dist/${{ matrix.artifact }}.tar.gz.sha256

release:
name: Create GitHub Release
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Download all artifacts
uses: actions/download-artifact@v4
with:
path: artifacts
merge-multiple: true

- name: Create release
uses: softprops/action-gh-release@v2
with:
generate_release_notes: true
files: |
artifacts/*.tar.gz
artifacts/*.sha256
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,4 @@ Cargo.lock
=======
*.db
>>>>>>> testing
docs/tasks/
Loading