Skip to main content

agentsec_core/
lib.rs

1//! # `agentsec-core` — AgentSec pure-logic library
2//!
3//! Pure-Rust logic crate. No rmcp / clap / GUI dependency — the umbrella
4//! binary `agentsec` is the only transport adapter (see the `agentsec`
5//! crate for CLI / MCP server / hook wiring).
6//!
7//! This crate doc is the single source of truth for the threat model,
8//! module roster, and read-only invariants. Module-level docs reference
9//! the sections below by anchor (e.g. *crate root §Threat surface × vector*).
10//!
11//! ---
12//!
13//! ## §Threat surface × vector
14//!
15//! Defense is framed as a 2-axis matrix. The vertical axis is **where**
16//! the threat is observed, the horizontal axis is **how** the injection
17//! arrives. Modules cover the following cells:
18//!
19//! | Surface              | Vector               | Module        |
20//! |----------------------|----------------------|---------------|
21//! | L1 Agent config dir  | V3 Config tampering  | [`scan`]      |
22//! | L4 Network egress    | V1 Prompt injection  | [`web`]       |
23//! | L5 User-facing input | V1 Prompt injection  | [`paste`]     |
24//!
25//! Surface key:
26//!
27//! - **L1 Agent config** — `~/.claude/`, `~/.cursor/`, `.mcp.json`, skills /
28//!   agents / plugins dirs, dependency manifests, lockfiles, `.env`
29//! - **L2 Dependency manifest** — `package.json`, `Cargo.toml`, lockfiles
30//!   (covered by [`scan`] as a sub-axis of L1)
31//! - **L3 Runtime process** — Agent / MCP subprocess (not implemented)
32//! - **L4 Network egress** — outbound URL fetch from Agent context
33//! - **L5 User-facing input** — pasted text, prompt body, tool args
34//!
35//! Vector key:
36//!
37//! - **V1 Prompt injection** — instruction-override text in fetched URL / RAG
38//!   / pasted content
39//! - **V2 Supply chain** — typosquat / hijacked package (not implemented)
40//! - **V3 Config tampering** — newly-installed / mutated config under L1
41//! - **V4 Runtime tampering** — process injection (not implemented)
42//!
43//! ## §Module roster
44//!
45//! | Module path        | Role                                              |
46//! |--------------------|---------------------------------------------------|
47//! | [`scan`]           | Hash inventory of agent config + lockfiles; diff against the previous snapshot. |
48//! | [`paste`]          | Multi-layer decode + multi-pattern scan + unicode anomaly check; verdict Clean / Suspicious / Blocked. |
49//! | [`web`]            | URL fetch with body cap + 2-layer sanitize (regex then optional LLM) + `<untrusted_content>` envelope. |
50//! | [`output`]         | Render a [`scan::ScanOutcome`] as Markdown.       |
51//! | [`registry`]       | Known-good MCP server registry (builtin + cache + net fetch). |
52//! | [`plain_mode`]     | Temporarily disable `.mcp.json` files via rename + stub. |
53//! | [`diagnostics`]    | Observability: info / status / recent_activity / doctor.   |
54//! | [`emergency_stop`] | Enumerate Agent / MCP processes by name and SIGTERM them. |
55//! | [`config`]         | Edge-resolved `Config` (env → struct); the only env-reading code. |
56//! | [`error`]          | Crate-wide error enum.                            |
57//!
58//! ## §Runtime data root
59//!
60//! All persisted state lives under [`config::Paths::home`], resolved at
61//! the binary's outer rim by [`config::Config::from_env`] as:
62//!
63//! 1. `$AGENTSEC_HOME` if set (used by integration tests to redirect to a
64//!    tempdir), else
65//! 2. `$HOME/.agentsec/`, else
66//! 3. `./.agentsec/` (last-resort fallback when `HOME` is unset).
67//!
68//! Layout:
69//!
70//! ```text
71//! <home>/snapshots/<UTC-ts>.json   — scan snapshots (scan::snapshot)
72//! <home>/scans/last-session-start.txt — last SessionStart hook summary
73//! <home>/paste_log/<UTC-ts>-<id>.json — paste verdicts
74//! <home>/web_log/<UTC-ts>-<id>.json  — sanitize results
75//! ```
76//!
77//! ## §Environment variables
78//!
79//! All env reads are funneled through [`config::Config::from_env`] (the
80//! *only* function in this crate that touches `std::env`). Library
81//! functions take `&Config` (or sub-references) as a parameter; they do
82//! not consult the process environment at the point of use. See
83//! [`config`] for the full mapping and the test-friendly
84//! [`config::Config::from_env_lookup`] override.
85//!
86//! ## §Read-only invariants
87//!
88//! - [`scan`] never mutates any scanned path; it only reads bytes and writes
89//!   to `<home>/snapshots/`.
90//! - [`paste`] never persists the raw input plaintext outside the JSON audit
91//!   row under `<home>/paste_log/`.
92//! - [`web::fetch`] enforces a 2 MiB body cap and 15 s timeout; oversized
93//!   bodies are rejected, not truncated.
94//! - [`web::sanitize::semantic_layer`] **fails open**: a missing API key or
95//!   non-2xx response returns the regex-stripped input unchanged. The 1st
96//!   (regex) layer alone is the floor of protection.
97//! - Symbolic links are not followed during [`scan::inventory::collect`].
98pub mod config;
99pub mod diagnostics;
100pub mod emergency_stop;
101pub mod error;
102pub mod installer;
103pub mod output;
104pub mod paste;
105pub mod plain_mode;
106pub mod registry;
107pub mod scan;
108pub mod web;
109
110pub use config::{Config, LlmConfig, Paths};
111pub use error::Error;