Sweep every first-party crate source (1956 .rs files) to the project comment guidelines: delete redundant restatements, decorative banners, change narration, and end-of-line comments; keep and tighten the crucial ones (invariants, bug rationale, SAFETY blocks, ported-source attribution). No functional code changed. Every edit is proven comment-only against the prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a separate doctest-fence check. Where removing a comment made rustfmt or clippy want to re-lay-out adjacent code, the minimal triggering comment is restored so code tokens stay byte-identical. Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy --workspace --all-targets (0 warnings). Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for these guidelines (flags banners, end-of-line comments, change narration, and commented-out code).
100 lines
2.6 KiB
Rust
100 lines
2.6 KiB
Rust
//! Sandbox event logger.
|
|
//!
|
|
//! Events (profile applied, violations, bypasses) are buffered in memory and
|
|
//! flushed as JSONL to `~/.kigi/sandbox-events.jsonl`.
|
|
|
|
use std::path::PathBuf;
|
|
use std::sync::Mutex;
|
|
|
|
use crate::types::{SandboxEvent, SandboxEventType, SandboxMetrics};
|
|
|
|
pub struct SandboxLogger {
|
|
events: Mutex<Vec<SandboxEvent>>,
|
|
metrics: SandboxMetrics,
|
|
}
|
|
|
|
impl SandboxLogger {
|
|
pub fn new() -> Self {
|
|
Self {
|
|
events: Mutex::new(Vec::new()),
|
|
metrics: SandboxMetrics::default(),
|
|
}
|
|
}
|
|
|
|
pub fn log(&self, event: SandboxEvent) {
|
|
match &event.event_type {
|
|
SandboxEventType::FsViolation => self.metrics.inc_fs_violation(),
|
|
SandboxEventType::NetViolation => self.metrics.inc_net_violation(),
|
|
SandboxEventType::BypassGranted => self.metrics.inc_bypass_granted(),
|
|
SandboxEventType::BypassDenied => self.metrics.inc_bypass_denied(),
|
|
_ => {}
|
|
}
|
|
|
|
tracing::debug!(
|
|
event_type = ?event.event_type,
|
|
profile = %event.profile,
|
|
target = ?event.target,
|
|
operation = ?event.operation,
|
|
"sandbox event"
|
|
);
|
|
|
|
if let Ok(mut events) = self.events.lock() {
|
|
events.push(event);
|
|
}
|
|
}
|
|
|
|
pub fn metrics(&self) -> &SandboxMetrics {
|
|
&self.metrics
|
|
}
|
|
|
|
/// Drains the buffer.
|
|
pub fn take_events(&self) -> Vec<SandboxEvent> {
|
|
self.events
|
|
.lock()
|
|
.map(|mut events| std::mem::take(&mut *events))
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
pub fn flush_to_disk(&self) -> anyhow::Result<()> {
|
|
let events = self.take_events();
|
|
if events.is_empty() {
|
|
return Ok(());
|
|
}
|
|
|
|
let log_path = Self::log_file_path();
|
|
if let Some(parent) = log_path.parent() {
|
|
std::fs::create_dir_all(parent)?;
|
|
}
|
|
|
|
use std::io::Write;
|
|
let mut file = std::fs::OpenOptions::new()
|
|
.create(true)
|
|
.append(true)
|
|
.open(&log_path)?;
|
|
|
|
for event in &events {
|
|
if let Ok(json) = serde_json::to_string(event) {
|
|
writeln!(file, "{}", json)?;
|
|
}
|
|
}
|
|
|
|
tracing::debug!(
|
|
path = %log_path.display(),
|
|
count = events.len(),
|
|
"flushed sandbox events to disk"
|
|
);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn log_file_path() -> PathBuf {
|
|
kigi_config::kigi_home().join("sandbox-events.jsonl")
|
|
}
|
|
}
|
|
|
|
impl Default for SandboxLogger {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|