claw-guard 0.1.0

Security and policy engine for ClawDB
Documentation
use chrono::{DateTime, Utc};
use thiserror::Error;
use uuid::Uuid;

#[derive(Debug, Error)]
pub enum GuardError {
    #[error("policy not found: {0}")]
    PolicyNotFound(String),
    #[error("policy parse error: {0}")]
    PolicyParse(String),
    #[error("unsupported condition shape: {0}")]
    InvalidCondition(String),
    #[error("access denied: {0}")]
    AccessDenied(String),
    #[error("invalid token: {0}")]
    TokenInvalid(String),
    #[error("token expired at {expired_at}")]
    TokenExpired { expired_at: DateTime<Utc> },
    #[error("session not found: {0}")]
    SessionNotFound(Uuid),
    #[error("session expired: {session_id} at {expired_at}")]
    SessionExpired { session_id: Uuid, expired_at: DateTime<Utc> },
    #[error("session revoked: {0}")]
    SessionRevoked(Uuid),
    #[error("audit log failed: {0}")]
    AuditLogFailed(String),
    #[error("database error: {0}")]
    Database(#[from] sqlx::Error),
    #[error("migration error: {0}")]
    Migration(#[from] sqlx::migrate::MigrateError),
    #[error("serialization error: {0}")]
    Serialization(#[from] serde_json::Error),
    #[error("toml parse error: {0}")]
    Toml(#[from] toml::de::Error),
    #[error("jwt error: {0}")]
    Jwt(#[from] jsonwebtoken::errors::Error),
    #[error("io error: {0}")]
    Io(#[from] std::io::Error),
    #[error("uuid parse error: {0}")]
    Uuid(#[from] uuid::Error),
    #[error("config error: {0}")]
    Config(String),
    #[error("masking error: {0}")]
    MaskingError(String),
    #[error("transport error: {0}")]
    Transport(String),
}

impl From<GuardError> for tonic::Status {
    fn from(err: GuardError) -> Self {
        match &err {
            GuardError::AccessDenied(_) => tonic::Status::permission_denied(err.to_string()),
            GuardError::TokenInvalid(_) | GuardError::TokenExpired { .. } => tonic::Status::unauthenticated(err.to_string()),
            GuardError::PolicyNotFound(_) | GuardError::SessionNotFound(_) | GuardError::SessionRevoked(_) => tonic::Status::not_found(err.to_string()),
            GuardError::PolicyParse(_) | GuardError::InvalidCondition(_) | GuardError::Config(_) => tonic::Status::invalid_argument(err.to_string()),
            GuardError::Database(_) | GuardError::Io(_) | GuardError::Transport(_) => tonic::Status::unavailable(err.to_string()),
            _ => tonic::Status::internal(err.to_string()),
        }
    }
}

pub type GuardResult<T> = Result<T, GuardError>;