diff --git a/AGENTS.md b/AGENTS.md index ae81252e..8fcda392 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,7 @@ # Agent Instructions - Keep the project Rust-first for gateway, DNSBL, and high-throughput control-plane code. +- Preserve Wardnet ownership of Agent Artifact Admission, gateway/SOC control-plane policy, and security evidence. Treat `quarantine-sandbox-runtime`, `EgressWeave`, `contextual-orchestrator`, and `appguardrail` as external canonical owners whose released contracts/evidence Wardnet validates rather than reimplements. - Prefer proven security engines over fake in-house detections. Integrate OWASP CRS/Coraza, Suricata, STIX/TAXII, MISP, or OpenCTI before inventing equivalent engines. - Do not use Figma Code Connect for this project unless explicitly requested later. - Keep MVP work narrow: web management, gateway decisions, event/KPI visibility, and DNSBL publishing before broader SIEM/SOAR scope. diff --git a/CLAUDE.md b/CLAUDE.md index 742e3096..d9be6212 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,13 +40,14 @@ cargo +nightly fuzz run fuzz_score_request -- -max_total_time=60 ## Toolchain -`rust-toolchain.toml` pins the `stable` channel with `llvm-tools-preview` (needed by `cargo llvm-cov`), `rustfmt`, and `clippy`. Both workspace crates use `edition = "2024"`. Fuzzing is the one exception that needs nightly. +`rust-toolchain.toml` pins the `stable` channel with `llvm-tools-preview` (needed by `cargo llvm-cov`), `rustfmt`, and `clippy`. All three root-workspace crates use `edition = "2024"`. Fuzzing is the one exception that needs nightly. ## Workspace Layout -Root Cargo workspace with two members (resolver 3): +Root Cargo workspace with three members (resolver 3): - `crates/waf-ids-core` — pure domain crate, no async/HTTP deps (only `serde` + `percent-encoding`): models, validation, upserts, request scoring, DNSBL zone formatting, event retention, threat-feed freshness, KPI snapshots, commercial readiness, buyer evidence manifests. +- `crates/agent-artifact-admission` — Wardnet-owned pre-execution admission boundary for immutable agent artifact/evidence facts, policy evaluation, and auditable allow/deny receipts. It validates released evidence/contracts from canonical sibling owners; it does not execute hostile workloads or reimplement sandbox, egress, orchestration, or guardrail policy engines. - Root crate `waf-ids-ai-soc` (`src/lib.rs`) — Axum management API, embedded admin console, optional JSON state persistence, upstream proxying, NDJSON event export, support bundle assembly, plus the in-crate HTTP tests. Depends on `waf-ids-core`. - `src/main.rs` — deliberately thin shim over `waf_ids_ai_soc::run_from_env` so all config/serve logic is unit-testable; covered end-to-end by `tests/binary.rs` (SIGTERM graceful shutdown). - `fuzz/` — a **separate** cargo workspace (empty `[workspace]` table in `fuzz/Cargo.toml` — do not remove) so root `cargo test --workspace` never builds fuzz targets. Seed corpora live in `fuzz/corpus//`. @@ -67,6 +68,7 @@ Read in `run_from_env` (`src/lib.rs`): `BIND_ADDR` (default `127.0.0.1:8080`), ` ## Key Conventions - Management writes require `X-Admin-Token` and are **upserts**: routes keyed by `id`, threat indicators by `indicator_type` + `value` + `source`, DNSBL entries by `address`. DNSBL response codes must be in `127.0.0.0/8`. +- Agent Artifact Admission owns Wardnet's artifact/evidence binding, admission policy decision, and Wardnet receipt. `quarantine-sandbox-runtime`, `EgressWeave`, `contextual-orchestrator`, and `appguardrail` remain external canonical owners; consume only released contracts/evidence and never copy their implementation logic into Wardnet. - State persistence uses write-to-temp-sibling + atomic rename; management API mutations roll back in memory if the state file cannot be replaced. - Audit logs must never leak admin tokens (`scripts/smoke.sh` asserts this). - Untrusted-input surfaces (request scorer, state deserializer, admin-token parser, DNSBL zone export) are fuzzed; if you change one, keep its libFuzzer target and proptest mirror in sync (`docs/fuzzing.md` lists the invariants per target). diff --git a/docs/architecture.md b/docs/architecture.md index e1ee578b..7908089f 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -8,6 +8,8 @@ flowchart LR admin --> api["Management API"] api --> app["App Crate"] app --> core["waf-ids-core"] + api --> admission["Agent Artifact Admission"] + admission --> admissionCore["crates/agent-artifact-admission"] core --> state["Runtime State"] state --> file["Optional JSON State File"] client["HTTP Client"] --> gateway["Rust Gateway"] @@ -23,6 +25,10 @@ flowchart LR api --> feeds["Threat Feed Import"] feeds --> freshness["Feed Freshness"] commercial --> bundle["Support Bundle"] + sandbox["quarantine-sandbox-runtime\nexternal released evidence"] -.-> admission + egress["EgressWeave\nexternal released evidence"] -.-> admission + orchestrator["contextual-orchestrator\nexternal released API/evidence"] -.-> admission + guardrail["appguardrail\nexternal released evidence"] -.-> admission ``` ## Components @@ -30,6 +36,7 @@ flowchart LR - `src/main.rs`: process startup and operator configuration from `BIND_ADDR`, `ADMIN_TOKEN`, `WAF_IDS_STATE_PATH`, `DNSBL_ORIGIN`, and `EVENT_LIMIT`. - `src/lib.rs`: Axum app, routing, management APIs, optional JSON persistence, gateway handler, upstream proxying, admin console, support bundle assembly, NDJSON event export, and in-crate HTTP tests. - `crates/waf-ids-core`: reusable domain models plus validation, upsert, scoring, DNSBL zone export, event retention, threat-feed freshness, KPI snapshot, and commercial readiness logic. +- `crates/agent-artifact-admission`: Wardnet-owned Agent Artifact Admission domain/application boundary. It binds immutable artifact identity and evidence, evaluates Wardnet admission policy, and emits auditable Wardnet allow/deny receipts; it does not execute hostile workloads or copy sibling-owner sandbox, egress, orchestration, or guardrail logic. - `/admin`: embedded web console. - `/gateway/{path}`: route selection, request scoring, monitor/block decision, optional upstream proxying. - `/dnsbl/zone`: DNSBL zone text using the configured origin, suitable for publication through an authoritative DNS server. @@ -66,6 +73,19 @@ flowchart LR - Commercial readiness is a runtime evidence model for buyer pilots, not a legal revenue recognition or compliance certification system. - The reusable core remains in-repo as a workspace crate. A git submodule is intentionally deferred until an independently versioned engine, SDK, or adapter needs a separate release lifecycle. +### Agent Artifact Admission ownership boundary + +Wardnet owns Agent Artifact Admission policy semantics, immutable artifact/evidence binding, and the admission receipt consumed by its gateway/SOC control plane. Missing or malformed mandatory evidence fails closed according to Wardnet policy; availability of a foreign owner never converts absent evidence into success. + +The following systems remain external canonical owners. Wardnet may validate their released contracts or cryptographically bound evidence, but it must not copy their implementation logic, query their private persistence directly, or bind production behavior to mutable branch/PR state: + +- `quarantine-sandbox-runtime`: hostile-workload isolation, execution profiles, resource/syscall/filesystem controls, ephemeral workspaces, cleanup/recovery, and dynamic artifact-analysis execution. +- `EgressWeave`: outbound destination, transport, and egress authorization/control semantics. +- `contextual-orchestrator`: production LLM/model/tool orchestration and its released API. Wardnet owns the security question and deterministic policy around any advisory result, not provider/model routing. +- `appguardrail`: application/agent guardrail enforcement and its released security evidence contracts. + +This boundary is intentionally contract-first: no source copy, no cross-service SQL, and no mutable sibling dependency. A sibling capability that lacks an immutable released contract remains unavailable to production Wardnet admission rather than being reimplemented locally. + ## Product Architecture Evidence - FigJam: `docs/figma/enterprise-product-architecture.md` diff --git a/tests/agent_artifact_documentation_contract.rs b/tests/agent_artifact_documentation_contract.rs new file mode 100644 index 00000000..3bcb56ed --- /dev/null +++ b/tests/agent_artifact_documentation_contract.rs @@ -0,0 +1,49 @@ +use std::fs; + +fn read_repo_file(path: &str) -> String { + fs::read_to_string(path).unwrap_or_else(|error| panic!("failed to read {path}: {error}")) +} + +#[test] +fn agent_artifact_admission_stays_in_code_current_operator_and_architecture_docs() { + let architecture = read_repo_file("docs/architecture.md"); + assert!( + architecture.contains("Agent Artifact Admission"), + "architecture must name the Wardnet-owned Agent Artifact Admission bounded context" + ); + assert!( + architecture.contains("crates/agent-artifact-admission"), + "architecture must identify the shipped Agent Artifact Admission crate" + ); + for foreign_owner in [ + "quarantine-sandbox-runtime", + "EgressWeave", + "contextual-orchestrator", + "appguardrail", + ] { + assert!( + architecture.contains(foreign_owner), + "architecture must preserve the external-owner boundary for {foreign_owner}" + ); + } + + let claude = read_repo_file("CLAUDE.md"); + assert!( + claude.contains("crates/agent-artifact-admission"), + "operator/developer guidance must include the shipped Agent Artifact Admission workspace member" + ); + assert!( + !claude.contains("Root Cargo workspace with two members"), + "workspace guidance must not claim two members after Agent Artifact Admission is present" + ); + assert!( + !claude.contains("Both workspace crates use `edition = \"2024\"`"), + "toolchain guidance must not retain the pre-admission two-crate statement" + ); + + let agents = read_repo_file("AGENTS.md"); + assert!( + agents.contains("Agent Artifact Admission"), + "canonical agent guidance must retain Wardnet's Agent Artifact Admission ownership boundary" + ); +}