[package]
name = "aperion-shield"
version = "0.9.0"
edition = "2021"
description = "Aperion Shield -- a local MCP guardrail for AI coding agents with optional biometric identity gates (ID.me). Standalone, free, open source."
license = "Apache-2.0"
authors = ["Aperion <support@aperion.ai>"]
readme = "README.md"
keywords = ["mcp", "ai", "guardrails", "security", "agent"]
categories = ["command-line-utilities", "development-tools"]
repository = "https://github.com/AperionAI/shield"

# Standalone crate -- intentionally NOT a member of the enterprise smartflow
# workspace. The free standalone product ships independently with its own
# release cadence, lean dependency tree, and minimal feature surface.
# The Shield rule engine here is a self-contained vendored copy of the
# logic in ../../src/shield/; both sides parse the same YAML schema so
# rules authored for one work in the other.
[workspace]

# Hybrid lib+bin layout. The library exposes the rule engine and its
# adaptive layers for embedders (and integration tests). The binary is
# the MCP guardrail wrapper end-users actually run.
[lib]
name = "aperion_shield"
path = "src/lib.rs"

[[bin]]
name = "aperion-shield"
path = "src/main.rs"

[dependencies]
# Async runtime -- we only need single-thread + stdio support.
tokio = { version = "1", features = ["rt-multi-thread", "macros", "io-util", "io-std", "process", "sync", "time"] }
# JSON-RPC framing for MCP wire protocol.
serde = { version = "1", features = ["derive"] }
serde_json = "1"
serde_yaml = "0.9"
# Rule engine primitives.
regex = "1"
once_cell = "1"
# CLI parsing.
clap = { version = "4", features = ["derive"] }
# Logging to stderr (stdout is reserved for MCP JSON-RPC frames).
log = "0.4"
env_logger = "0.11"
# Error handling.
anyhow = "1"
thiserror = "1"
# UUIDs for ticket ids.
uuid = { version = "1", features = ["v4"] }
# RFC 3339 timestamps.
chrono = { version = "0.4", features = ["serde"] }
# SHA-256 for decision-memory fingerprints (rule_id + normalised argv).
sha2 = "0.10"
# Unified text diff for the `aperion-shield --diff` mode, used to
# emit a per-rule YAML diff inside the behavior-diff report. Lean
# crate (~150KB), well-maintained, only used in --diff -- pulled
# into the binary as a regular dep because it's tiny and used by a
# first-class CLI surface.
similar = "2"
# Cross-platform home-directory resolution for ~/.aperion-shield/ and
# for normalising paths in the sensitive-path matcher.
dirs = "5"

# ── Identity-gated tool calls (ID.me partnership, v0.4+) ──────────────
# All four crates are tiny pure-Rust dependencies; total binary growth
# is < 200 KB. The HTTP client + server stay in-process so Shield never
# has to talk to an external daemon.
async-trait = "0.1"
ed25519-dalek = { version = "2", features = ["rand_core"] }
rand = "0.8"
base64 = "0.22"
hex = "0.4"
url = "2"
# Local OAuth callback server (binds to 127.0.0.1 on an OS-assigned
# port, exposes /verify/<id> and /callback). hyper 1.x with
# hyper-util for the high-level Builder/executor types; the upgrade
# from 0.14 -> 1.x landed in v0.6.0 to close the rustls-webpki
# advisory chain (see SECURITY.md §4.5).
hyper = { version = "1", features = ["server", "http1"] }
hyper-util = { version = "0.1", features = ["tokio", "server", "server-graceful"] }
http-body-util = "0.1"
bytes = "1"
# Outbound HTTPS for ID.me /oauth/token and /userinfo. rustls so we
# don't pick up a system OpenSSL dependency on Linux. v0.6.0 moved
# reqwest 0.11 -> 0.12, which transitively pulls rustls 0.23 +
# rustls-webpki >= 0.103.13 and closes RUSTSEC-2026-0098/-0099/-0104.
reqwest = { version = "0.12", default-features = false, features = ["json", "rustls-tls", "stream"] }
# Stream combinators for the v0.9 Streamable HTTP transports (SSE
# parsing on the upstream relay, SSE response bodies on the downstream
# server). Already in the tree transitively via reqwest/hyper.
futures-util = { version = "0.3", default-features = false }
# Atomic write of the proof cache file.
fs2 = "0.4"

[dev-dependencies]
tempfile = "3"

[profile.release]
opt-level = 3
lto = "thin"
strip = true
codegen-units = 1
