forge-code-safety
Runtime safety primitives for coding agents — worktree isolation, write scoping, delete prevention, approval gates, and audit logging
Runtime safety primitives for coding agents — worktree isolation, write scoping, delete prevention, approval gates, and audit logging
Package contract
| Field | Value |
|---|---|
| Language | rust |
| Source version | 0.2.0 |
| Manifest | forge-rs/crates/forge-code-safety/Cargo.toml |
| Source files | 8 |
| Evidence | Source reference; registry publication and runtime conformance are separate checks |
Import boundary
use forge_code_safety;Use a source checkout or your verified private registry. Manifest coordinates identify the package; they do not establish that a public registry release exists.
Crate boundary
The following entries are taken from src/lib.rs. Feature conditions in the exact source still apply.
#[cfg(not(target_arch = "wasm32"))]
pub mod approval;
#[cfg(not(target_arch = "wasm32"))]
pub mod audit;
#[cfg(not(target_arch = "wasm32"))]
pub mod delete_policy;
pub mod error;
#[cfg(not(target_arch = "wasm32"))]
pub mod lease;
#[cfg(not(target_arch = "wasm32"))]
pub mod worktree;
#[cfg(not(target_arch = "wasm32"))]
pub mod write_scope;
pub mod prelude;
#[cfg(not(target_arch = "wasm32"))]
pub use crate::approval::{ApprovalGate, ApprovalRequest, ApprovalResponse, AutoDenyGate};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::audit::{AuditEntry, FileAuditLog, FileOperation, OperationResult};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::delete_policy::{DeleteDecision, DeletePolicy, DeletePolicyMode, RiskLevel};
pub use crate::error::{CodeSafetyError, CodeSafetyResult};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::lease::{LeaseRequest, RepoLease, RepoLeaseManager};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::worktree::{WorktreeGuard, WorktreeInfo, WorktreeManager};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::write_scope::WriteScope;Source reference
Download package reference JSON. Each original source file and generated declaration artifact has its own SHA-256 digest. Function bodies and constant values are omitted from downloads. These are source declaration inventories, not compiler-resolved rustdoc, TypeDoc, DocC, or Dokka output. Private modules can contain public declarations that are not reachable through the package boundary; consult the entry point before importing.
approval.rs
Read declaration text · 7 declaration entries
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApprovalRequest {
/// The DID of the agent requesting approval.
pub agent_did: String,
/// The operation type (e.g., "delete", "modify_protected", "force_push").
pub operation: String,
/// The file or directory path the operation targets.
pub path: PathBuf,
/// The assessed risk level of the operation.
pub risk_level: RiskLevel,
/// The agent's justification for why the operation is needed.
pub justification: String
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ApprovalResponse {
/// Unique identifier for this approval decision.
pub decision_id: String,
/// Whether the operation was approved.
pub approved: bool,
/// The entity that made the approval decision.
pub reviewer: String,
/// Why the decision was made.
pub reason: String,
/// When the decision was made.
pub decided_at: DateTime<Utc>,
/// Optional conditions attached to the approval.
pub conditions: Vec<String>
}
#[async_trait]
pub trait ApprovalGate: Send + Sync {
/// Requests approval for a file operation.
///
/// # Arguments
///
/// * `request` - The approval request with details about the operation.
///
/// # Returns
///
/// An [`ApprovalResponse`] indicating whether the operation was approved.
async fn request_approval(&self, request: &ApprovalRequest) -> ApprovalResponse;
}
pub struct AutoDenyGate;
pub struct AutoApproveGate;
pub struct RiskBasedGate {
}
pub fn new(max_auto_approve: RiskLevel) -> Self;audit.rs
Read declaration text · 12 declaration entries
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum FileOperation {
/// Creating a new file.
Create,
/// Reading a file's contents.
Read,
/// Modifying an existing file.
Modify,
/// Deleting a file.
Delete,
/// Renaming or moving a file.
Rename,
/// Changing file permissions.
Chmod,
/// Creating a directory.
CreateDir,
/// Removing a directory.
RemoveDir,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum OperationResult {
/// The operation succeeded.
Success,
/// The operation was denied by policy.
Denied {
/// Why it was denied.
reason: String,
},
/// The operation failed due to an error.
Failed {
/// What went wrong.
reason: String,
},
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuditEntry {
/// Unique identifier for this entry.
pub id: String,
/// When the operation occurred.
pub timestamp: DateTime<Utc>,
/// The DID of the agent that performed the operation.
pub agent_did: String,
/// The type of operation.
pub operation: FileOperation,
/// The file path targeted by the operation.
pub path: PathBuf,
/// The result of the operation.
pub result: OperationResult,
/// Optional additional context or notes.
pub context: Option<String>,
/// BLAKE3 hash of the previous entry for chain integrity.
pub previous_hash: String,
/// BLAKE3 hash of this entry's content.
pub entry_hash: String
}
pub struct FileAuditLog {
}
pub fn new() -> Self;
pub async fn record(
&self,
agent_did: &str,
operation: FileOperation,
path: PathBuf,
result: OperationResult,
context: Option<String>,
);
pub async fn entries(&self) -> Vec<AuditEntry>;
pub async fn len(&self) -> usize;
pub async fn is_empty(&self) -> bool;
pub async fn entries_by_agent(&self, agent_did: &str) -> Vec<AuditEntry>;
pub async fn entries_by_operation(&self, operation: FileOperation) -> Vec<AuditEntry>;
pub async fn verify_chain(&self) -> Result<(), String>;delete_policy.rs
Read declaration text · 12 declaration entries
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DeleteDecision {
/// The delete is denied.
Denied {
/// The path that was denied.
path: PathBuf,
/// Why it was denied.
reason: String,
},
/// The delete requires explicit approval before it can proceed.
RequiresApproval {
/// The path requiring approval.
path: PathBuf,
/// The risk level of the delete.
risk_level: RiskLevel,
},
/// The delete is allowed (matches an approved pattern).
Allowed {
/// The path that was allowed.
path: PathBuf,
/// The pattern that matched.
matched_pattern: String,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RiskLevel {
/// Low risk: generated files, build artifacts, temporary files.
Low,
/// Medium risk: test files, documentation, configuration.
Medium,
/// High risk: source code, production configuration, data.
High,
/// Critical risk: security files, keys, critical infrastructure.
Critical,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeletePolicy {
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub enum DeletePolicyMode {
/// All deletes are denied.
DenyAll,
/// Deletes require explicit approval.
RequireApproval,
/// Deletes matching specific patterns are allowed.
AllowPattern,
}
pub fn deny_all(agent_did: impl Into<String>) -> Self;
pub fn require_approval(agent_did: impl Into<String>) -> Self;
pub fn with_allowed_patterns(agent_did: impl Into<String>, patterns: Vec<String>) -> Self;
pub fn protect_path(mut self, path: impl Into<PathBuf>) -> Self;
pub fn evaluate(&self, path: &Path) -> DeleteDecision;
pub fn enforce(&self, path: &Path) -> CodeSafetyResult<()>;
pub fn agent_did(&self) -> &str;
pub fn mode(&self) -> &DeletePolicyMode;error.rs
Read declaration text · 2 declaration entries
#[derive(Debug, Error)]
pub enum CodeSafetyError {
/// The agent attempted to write to a file outside its assigned write scope.
///
/// Every coding agent is assigned an explicit write scope (a set of paths
/// and glob patterns). Writes to files outside that scope are denied.
#[error("write denied: agent '{agent_did}' attempted to write '{path}' which is outside assigned scope '{scope}'")]
WriteOutsideScope {
/// The path the agent tried to write to.
path: PathBuf,
/// The assigned write scope that was violated.
scope: PathBuf,
/// The DID of the agent that attempted the write.
agent_did: String,
},
/// The agent attempted to delete a file, which is forbidden by default.
///
/// Delete operations require explicit escalation and approval. The default
/// policy is deny-all for deletes.
#[error("delete denied: agent '{agent_did}' attempted to delete '{path}'; delete operations require explicit escalation (set escalation_policy to allow)")]
DeleteDenied {
/// The path the agent tried to delete.
path: PathBuf,
/// The DID of the agent that attempted the delete.
agent_did: String,
},
/// The worktree does not exist or is not accessible.
#[error(
"worktree '{worktree_path}' not found or not accessible for agent '{agent_did}': {reason}"
)]
WorktreeNotFound {
/// The worktree path that was expected.
worktree_path: PathBuf,
/// The DID of the agent that tried to use the worktree.
agent_did: String,
/// Why the worktree was not found.
reason: String,
},
/// The worktree has already been leased to another agent.
#[error("worktree '{worktree_path}' is already leased to agent '{existing_lessee}'; agent '{requesting_agent}' cannot acquire a concurrent lease")]
WorktreeAlreadyLeased {
/// The path of the contested worktree.
worktree_path: PathBuf,
/// The DID of the agent that currently holds the lease.
existing_lessee: String,
/// The DID of the agent that tried to acquire the lease.
requesting_agent: String,
},
/// The agent does not hold a valid lease for the requested repo.
#[error("no active lease: agent '{agent_did}' does not hold a lease for repo '{repo_path}'; acquire a lease with RepoLeaseManager::acquire() first")]
NoActiveLease {
/// The DID of the agent missing a lease.
agent_did: String,
/// The repo path that required a lease.
repo_path: PathBuf,
},
/// The lease has expired.
#[error("lease expired: agent '{agent_did}' lease for worktree '{worktree_path}' expired at {expired_at}; renew or release the lease")]
LeaseExpired {
/// The DID of the agent whose lease expired.
agent_did: String,
/// The worktree path with the expired lease.
worktree_path: PathBuf,
/// When the lease expired (ISO 8601 string).
expired_at: String,
},
/// An approval was required but not granted.
#[error("approval required: operation '{operation}' on '{path}' by agent '{agent_did}' requires approval (risk_level={risk_level})")]
ApprovalRequired {
/// The operation that required approval.
operation: String,
/// The path the operation targets.
path: PathBuf,
/// The DID of the agent requesting the operation.
agent_did: String,
/// The risk level of the operation.
risk_level: String,
},
/// An approval was explicitly denied.
#[error("approval denied: operation '{operation}' on '{path}' by agent '{agent_did}' was denied by reviewer '{reviewer}': {reason}")]
ApprovalDenied {
/// The operation that was denied.
operation: String,
/// The path the operation targets.
path: PathBuf,
/// The DID of the agent whose request was denied.
agent_did: String,
/// The reviewer who denied the request.
reviewer: String,
/// Why the approval was denied.
reason: String,
},
/// A file operation was attempted on the main/default branch directly.
#[error("direct main branch modification denied: agent '{agent_did}' attempted to modify '{path}' on branch '{branch}'; all modifications must be made in worktrees")]
MainBranchModification {
/// The DID of the agent that attempted the modification.
agent_did: String,
/// The path that was targeted.
path: PathBuf,
/// The protected branch name.
branch: String,
},
/// The audit log write failed.
#[error("audit log write failed for operation '{operation}' by agent '{agent_did}': {reason}")]
AuditLogFailed {
/// The operation that was being audited.
operation: String,
/// The DID of the agent.
agent_did: String,
/// Why the audit log write failed.
reason: String,
},
/// I/O error during file operations.
#[error("file I/O error at '{path}': {reason}")]
IoError {
/// The path where the I/O error occurred.
path: PathBuf,
/// What went wrong.
reason: String,
},
/// Git operation failed.
#[error("git operation failed in '{repo_path}': {reason}")]
GitError {
/// The repository where the git operation failed.
repo_path: PathBuf,
/// What went wrong.
reason: String,
},
}
pub type CodeSafetyResult<T> = Result<T, CodeSafetyError>;lease.rs
Read declaration text · 14 declaration entries
#[derive(Debug, Clone)]
pub struct LeaseRequest {
/// The DID of the agent requesting the lease.
pub agent_did: String,
/// The worktree path to lease.
pub worktree_path: PathBuf,
/// The write scope the agent is granted.
pub write_scope: WriteScope,
/// How long the lease should be valid for.
pub duration: Duration
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RepoLease {
/// Unique identifier for this lease.
pub id: String,
/// The DID of the agent holding this lease.
pub agent_did: String,
/// The worktree path this lease covers.
pub worktree_path: PathBuf,
/// The write scope granted by this lease.
pub write_scope: WriteScope,
/// When the lease was acquired.
pub acquired_at: DateTime<Utc>,
/// When the lease expires.
pub expires_at: DateTime<Utc>
}
pub fn is_expired(&self) -> bool;
pub fn remaining(&self) -> Duration;
pub struct RepoLeaseManager {
}
pub fn new() -> Self;
pub async fn acquire(&self, request: LeaseRequest) -> CodeSafetyResult<RepoLease>;
pub async fn release(&self, lease_id: &str) -> CodeSafetyResult<()>;
pub async fn renew(
&self,
lease_id: &str,
additional_duration: Duration,
) -> CodeSafetyResult<RepoLease>;
pub async fn is_active(&self, lease_id: &str) -> bool;
pub async fn get_by_agent(&self, agent_did: &str) -> Option<RepoLease>;
pub async fn get_by_path(&self, worktree_path: &PathBuf) -> Option<RepoLease>;
pub async fn list_active(&self) -> Vec<RepoLease>;
pub async fn cleanup_expired(&self) -> usize;lib.rs
Read declaration text · 15 declaration entries
#[cfg(not(target_arch = "wasm32"))]
pub mod approval;
#[cfg(not(target_arch = "wasm32"))]
pub mod audit;
#[cfg(not(target_arch = "wasm32"))]
pub mod delete_policy;
pub mod error;
#[cfg(not(target_arch = "wasm32"))]
pub mod lease;
#[cfg(not(target_arch = "wasm32"))]
pub mod worktree;
#[cfg(not(target_arch = "wasm32"))]
pub mod write_scope;
pub mod prelude;
#[cfg(not(target_arch = "wasm32"))]
pub use crate::approval::{ApprovalGate, ApprovalRequest, ApprovalResponse, AutoDenyGate};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::audit::{AuditEntry, FileAuditLog, FileOperation, OperationResult};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::delete_policy::{DeleteDecision, DeletePolicy, DeletePolicyMode, RiskLevel};
pub use crate::error::{CodeSafetyError, CodeSafetyResult};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::lease::{LeaseRequest, RepoLease, RepoLeaseManager};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::worktree::{WorktreeGuard, WorktreeInfo, WorktreeManager};
#[cfg(not(target_arch = "wasm32"))]
pub use crate::write_scope::WriteScope;worktree.rs
Read declaration text · 22 declaration entries
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WorktreeInfo {
}
pub fn id(&self) -> &str;
pub fn path(&self) -> &Path;
pub fn branch(&self) -> &str;
pub fn agent_did(&self) -> &str;
pub fn repo_root(&self) -> &Path;
pub fn created_at(&self) -> DateTime<Utc>;
pub struct WorktreeManager {
}
pub fn new(repo_root: &Path) -> Self;
pub fn with_base(repo_root: &Path, worktree_base: &Path) -> Self;
pub async fn create(
&self,
agent_did: &str,
branch_name: &str,
) -> CodeSafetyResult<WorktreeInfo>;
pub async fn remove(&self, worktree: &WorktreeInfo) -> CodeSafetyResult<()>;
pub async fn list(&self) -> Vec<WorktreeInfo>;
pub async fn find_by_agent(&self, agent_did: &str) -> Option<WorktreeInfo>;
pub async fn worktree_for_path(&self, path: &Path) -> Option<WorktreeInfo>;
pub fn repo_root(&self) -> &Path;
#[derive(Debug, Clone)]
pub struct WorktreeGuard {
}
pub fn new(info: WorktreeInfo) -> Self;
pub fn info(&self) -> &WorktreeInfo;
pub fn validate_path(&self, path: &Path) -> CodeSafetyResult<()>;
pub fn validate_branch(&self, branch: &str) -> CodeSafetyResult<()>;
pub fn is_protected_branch(branch: &str) -> bool;write_scope.rs
Read declaration text · 14 declaration entries
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct WriteScope {
}
pub fn builder(agent_did: impl Into<String>) -> WriteScopeBuilder;
pub fn agent_did(&self) -> &str;
pub fn is_allowed(&self, path: &Path) -> CodeSafetyResult<()>;
pub fn allowed_directories(&self) -> &[PathBuf];
pub fn denied_paths(&self) -> &[PathBuf];
pub fn has_any_allowed(&self) -> bool;
pub struct WriteScopeBuilder {
}
pub fn allow_directory(mut self, path: impl Into<PathBuf>) -> Self;
pub fn allow_file(mut self, path: impl Into<PathBuf>) -> Self;
pub fn allow_extension(mut self, pattern: impl Into<String>) -> Self;
pub fn deny_path(mut self, path: impl Into<PathBuf>) -> Self;
pub fn deny_directory(mut self, path: impl Into<PathBuf>) -> Self;
pub fn build(self) -> WriteScope;