Skip to content
Open
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
28 changes: 28 additions & 0 deletions src/cli/config/security.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ pub struct SecurityConfig {
/// Persist scores across restarts (default false)
#[serde(default)]
pub scoring_persist: bool,
/// Tool-call spike: warn threshold per session per minute.
///
/// Crossing this threshold logs a warning + emits a metric, but
/// does not reject the request. Set to `0` to disable warnings.
#[serde(default = "default_tool_spike_warn_per_min")]
pub tool_spike_warn_per_min: u32,
/// Tool-call spike: block threshold per session per minute.
///
/// Crossing this threshold returns HTTP 429, writes an audit
/// entry, and emits a metric. Set to `0` to disable blocking.
#[serde(default = "default_tool_spike_block_per_min")]
pub tool_spike_block_per_min: u32,
}

impl Default for SecurityConfig {
Expand All @@ -82,6 +94,8 @@ impl Default for SecurityConfig {
scoring_window_size: default_scoring_window_size(),
scoring_decay_rate: default_scoring_decay_rate(),
scoring_persist: false,
tool_spike_warn_per_min: default_tool_spike_warn_per_min(),
tool_spike_block_per_min: default_tool_spike_block_per_min(),
}
}
}
Expand Down Expand Up @@ -123,6 +137,20 @@ fn default_scoring_decay_rate() -> f64 {
0.001
}

// NOTE: 100 tool calls/min/session is roughly the upper bound for a busy
// build run (Claude Code reading ~2 files/sec while exploring a tree).
// Above this we want a paper trail; we still allow the request through.
fn default_tool_spike_warn_per_min() -> u32 {
100
}

// NOTE: 500 tool calls/min/session is firmly anomalous — equivalent to
// >8/sec sustained, which only a runaway loop produces. Blocks the
// dispatch and emits a signed audit entry.
fn default_tool_spike_block_per_min() -> u32 {
500
}

/// EU AI Act compliance configuration
#[derive(Debug, Clone, Deserialize, Serialize, Default)]
pub struct ComplianceConfig {
Expand Down
2 changes: 2 additions & 0 deletions src/security/audit_log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,8 @@ pub enum AuditEvent {
HitApproval,
/// TEE attestation report generated at startup.
TeeAttestation,
/// Tool-call spike anomaly blocked (T-AD1).
ToolSpikeBlocked,
}

/// Immutable audit log entry.
Expand Down
2 changes: 2 additions & 0 deletions src/security/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod provider_scorer;
pub mod rate_limit;
pub mod risk;
pub mod tee;
pub mod tool_spike;

// Re-exports used by server/mod.rs and other modules
pub use audit_log::AuditLog;
Expand All @@ -20,3 +21,4 @@ pub use fips::FipsStatus;
pub use headers::{apply_security_headers, SecurityHeadersConfig};
pub use rate_limit::{RateLimitConfig, RateLimitKey, RateLimiter};
pub use tee::TeeStatus;
pub use tool_spike::{SpikeAction, ToolSpikeConfig, ToolSpikeDetector};
Loading
Loading