csaf-core 0.2.0

CSAF storage, validation, sidecar generation, import/export
Documentation

ndaal CSAF-CRUD

Secure, single-binary Rust CRUD application for managing CSAF 2.0 and 2.1 security advisories. Provides both a server-side rendered web UI (Hyper + Bootstrap 5 + HTMX) and a RESTful HATEOAS JSON API under /api/v1/.

Features

  • CSAF 2.0 / 2.1 — Full serde types, strict validation, dual CVSS v3.1 + v4.0 scoring.
  • Classification support — TLP 2.0 colour-coded selector (CLEAR/GREEN/AMBER/AMBER+STRICT/RED), German Verschlusssache (VS-NfD / VS-Vertr. / Geh. / Str. Geh.), and NATO (NR / NC / NS / CTS). Written into the exported CSAF either to document.distribution.text, to document.notes[], or to both — configurable per-deployment.
  • Dual embedded databaseredb for CSAF documents, rusqlite (bundled) for user management and audit logging.
  • Zero external dependencies — Single binary deployment.
  • Protocols — HTTP/1.1, HTTP/2, and HTTP/3 (QUIC) over TLS 1.3 via rustls, ring crypto, and quinn.
  • Self-signed certificates — Auto-generated via rcgen with 45-day validity (Let's Encrypt short-lived cert model).
  • Sidecar hashes — SHA-256 and SHA3-512 generated for every export, optional via settings.
  • HATEOAS API — HAL-like _links in every response, RFC 9457 Problem Details error format.
  • Menu structure — CSAF (CRUD), Administration (Import/Export), Settings, Info (About/License/System/Privacy/ Security).
  • Audit logging — Every create/update/delete/import/export recorded with ISO 8601 timestamps.
  • Argon2id password hashing per RFC 9106.

Quick start

# Build
cargo build --release

# Start the server (TLS on 8180 for TCP, 8181 for QUIC)
cargo run --bin csaf-crud

# Use the CLI
cargo run --bin csaf-cli -- import --directory test/csaf
cargo run --bin csaf-cli -- validate \
  test/csaf/2026/003/ndaal-sa-2026-003.json
cargo run --bin csaf-cli -- stats

Workspace layout

crates/
├── csaf-models/   # CSAF 2.0/2.1 serde types, SQLite pool,
│                  # User, AuditLog, Settings models
├── csaf-core/     # redb storage, validation, sidecar generation,
│                  # import/export, configuration
├── csaf-crud/      # Hyper server, HATEOAS API, HTML routes,
│                  # router, static files, TLS 1.3 setup
└── csaf-cli/      # clap-based CLI: import, export, validate,
                   # stats

Testing

# All tests (unit + integration + crate integration)
cargo test --workspace

# Just integration tests
cargo test --workspace --test csaf_crud_cycle
cargo test --workspace --test test_crate_integrations

# Load test (oha, HTTP/2 keep-alive, --insecure for dev cert)
OHA_REQUESTS=1000 OHA_CONCURRENCY=20 test/loadtest/run.sh

Load-test results — port 8180, HTTP/2 over TLS 1.3

1000 requests per endpoint × 20 concurrent connections, oha --http2 --insecure against the locally-built release binary on Apple Silicon (MacBook). All seven endpoints hit 100 % success:

Endpoint req/s p95 latency
/api/v1 12,037 0.74 ms
/api/v1/settings 11,844 0.77 ms
/api/v1/system/health 9,070 0.96 ms
/api/v1/csaf?page=1&per_page=5 8,781 1.64 ms
/ (HTML dashboard) 7,918 2.19 ms
/api/v1/audit-log?page=1&per_page=5 7,572 2.24 ms
/static/img/logo.png 3,076 1.50 ms

Port 8181 (HTTP/3 over QUIC) is not exercised by this load test — oha, h2load, and Homebrew curl on this platform do not include an HTTP/3 / QUIC client. A dedicated QUIC-capable tool (e.g. h2load built with nghttp3 + ngtcp2, or neqo-client) is needed to benchmark 8181.

Test coverage includes:

  • Unit tests per crate (178 tests; +22 for classification)
  • Integration tests — 10 end-to-end CRUD cycle tests
  • Crate integration tests — 57 tests reusing patterns from redb, rusqlite, sha2/sha3, argon2, serde_json, chrono, regex, uuid, matchit, rustls/rcgen, and sysinfo
  • Fuzzing — 16 cargo-fuzz targets including three new classification-focused targets (fuzz_classification_extract, fuzz_classification_writeback, fuzz_tlp_color_class). Parser changes are gated on 300 s per-target in CI.

Total: 245 tests passing.

Quality toolchain

cargo fmt --all
cargo clippy --workspace --all-targets --all-features -- \
  -D warnings
cargo test --workspace
cargo audit
cargo deny check
cargo machete --with-metadata
cargo llvm-cov --lcov --output-path target/coverage/lcov.info \
  --workspace --all-features
rust-doctor
cargo kani --workspace --output-format=terse   # nightly

Linters applied: cargo clippy (pedantic + nursery), yamllint, ryl, markdownlint, rumdl, hadolint, htmlhint, oxlint, ruff, bandit.

rust-doctor — workspace health score

┌────────────────────────────────────────────────────────┐
│ rust-doctor                                            │
│                                                        │
│ 100 / 100  Great                                       │
│                                                        │
│ ████████████████████████████████████████               │
│                                                        │
│ Security:       100                                    │
│ Reliability:    100                                    │
│ Maintainability: 100                                   │
│ Performance:    100                                    │
│ Dependencies:   100                                    │
│                                                        │
│ ✓ 0 error(s)  ✓ 0 warning(s)  ℹ 1 info(s)  38 files   │
└────────────────────────────────────────────────────────┘

Run rust-doctor locally (or rust-doctor --json for machine output) to reproduce. The session-level cache lives in each crate's .rust-doctor-cache.json; any regression greater than 5 points vs the previous run blocks the merge. Configuration is in rust-doctor.toml; every ignore rule carries a justification comment referencing the equivalent [workspace.lints.clippy] entry in Cargo.toml.

Security

  • TLS 1.3 only (no TLS 1.2 fallback)
  • rustls with ring crypto provider (no OpenSSL)
  • Argon2id for password hashing (RFC 9106)
  • Parameterized SQL queries throughout
  • No unsafe code (#![deny(unsafe_code)])
  • SHA-256 and SHA3-512 integrity sidecars

Source code

Canonical repository (used by crates.io and cargo install):

Please open issues and merge requests there. No GitHub mirror is maintained; treat any third-party GitHub copy as untrusted.

License

Apache-2.0. See SPDX headers in each source file.

Author

Pierre Gronau · ndaal Gesellschaft für Sicherheit in der Informationstechnik mbH & Co KG · Cologne