areev 0.2.0

Rust SDK for the Areev knowledge database — gRPC and HTTP transports
Documentation
//! `Compliance` resource — audit trail, data-subject-rights exports,
//! hash-chain verification, breach reporting, retention, and metrics.
//!
//! Mirrors the Python SDK's `client.compliance.*` surface.
//!
//! Data-subject-rights (DSR) reads — [`Compliance::audit`],
//! [`Compliance::export`], [`Compliance::export_user`],
//! [`Compliance::verify_latest`], [`Compliance::verify_run`] — are NEVER
//! gated client-side and are always issued. Their response bodies carry
//! personal data and so are suppressed from the SDK's request logging to
//! keep PII / PHI out of customer logs.

use serde_json::{Map, Value};

use crate::error::Result;
use crate::http::HttpClient;

/// Compliance + DSR operations.
///
/// Access via [`crate::Areev::compliance`].
pub struct Compliance<'a> {
    http: &'a HttpClient,
    memory_id: String,
}

impl<'a> Compliance<'a> {
    /// Internal constructor — use [`crate::Areev::compliance`].
    pub(crate) fn new(http: &'a HttpClient, memory_id: String) -> Self {
        Self { http, memory_id }
    }

    fn p(&self, suffix: &str) -> String {
        format!("/memories/{}/{}", self.memory_id, suffix)
    }

    // ── Data-subject rights (never gated; PII-redacted logging) ──────

    /// Read the per-memory audit trail (EU AI Act Art. 12, SOC 2).
    ///
    /// Data-subject right — always issued, never tier/credit gated. The
    /// response is excluded from request logging.
    pub async fn audit(&self, filters: Option<&Value>) -> Result<Value> {
        self.http._get_sensitive(&self.p("audit"), filters).await
    }

    /// Export the full compliance record for the memory (GDPR Art. 15/20).
    ///
    /// Data-subject right — always issued, never gated. PII-redacted
    /// logging.
    pub async fn export(&self, filters: Option<&Value>) -> Result<Value> {
        self.http
            ._get_sensitive(&self.p("compliance/export"), filters)
            .await
    }

    /// Export all data attributed to `user_id` (GDPR Art. 15 / CCPA).
    ///
    /// Data-subject right — always issued, never gated. PII-redacted
    /// logging.
    pub async fn export_user(&self, user_id: &str, filters: Option<&Value>) -> Result<Value> {
        self.http
            ._get_sensitive(&self.p(&format!("export/{user_id}")), filters)
            .await
    }

    /// Verify the latest audit hash-chain anchor (tamper-evidence).
    ///
    /// Data-subject right — always issued, never gated.
    pub async fn verify_latest(&self) -> Result<Value> {
        self.http
            ._get_sensitive(&self.p("verify/latest"), None)
            .await
    }

    /// Run a full compliance verification pass over the audit chain.
    ///
    /// Data-subject right — always issued, never gated.
    pub async fn verify_run(
        &self,
        regulation: Option<&str>,
        sample_size: Option<u32>,
    ) -> Result<Value> {
        let mut body = Map::new();
        if let Some(r) = regulation {
            body.insert("regulation".into(), Value::String(r.to_string()));
        }
        if let Some(n) = sample_size {
            body.insert("sample_size".into(), Value::from(n));
        }
        self.http
            ._post_sensitive(&self.p("verify/run"), Some(&Value::Object(body)), true)
            .await
    }

    // ── Retention ────────────────────────────────────────────────────

    /// Current retention-policy state and pending purges.
    pub async fn retention_status(&self) -> Result<Value> {
        self.http._get(&self.p("retention/status"), None).await
    }

    /// Enforce retention now — purges grains past their retention window.
    ///
    /// Requires: admin scope. Emits an audit event.
    pub async fn retention_enforce(&self, opts: Option<Value>) -> Result<Value> {
        let body = opts.unwrap_or_else(|| Value::Object(Map::new()));
        self.http
            ._post(&self.p("retention/enforce"), Some(&body))
            .await
    }

    // ── Breach lifecycle ─────────────────────────────────────────────

    /// Report a data breach (GDPR Art. 33 — the 72-hour clock starts).
    ///
    /// Requires: admin scope. Emits an audit event.
    pub async fn report_breach(
        &self,
        affected_individuals: u64,
        severity_score: Option<i64>,
        breach_id: Option<&str>,
        triggering_event_ms: Option<i64>,
    ) -> Result<Value> {
        let mut body = Map::new();
        body.insert(
            "affected_individuals".into(),
            Value::from(affected_individuals),
        );
        if let Some(s) = severity_score {
            body.insert("severity_score".into(), Value::from(s));
        }
        if let Some(b) = breach_id {
            body.insert("breach_id".into(), Value::String(b.to_string()));
        }
        if let Some(t) = triggering_event_ms {
            body.insert("triggering_event_ms".into(), Value::from(t));
        }
        self.http
            ._post(&self.p("compliance/breach"), Some(&Value::Object(body)))
            .await
    }

    /// Mark a reported breach resolved. Requires: admin scope.
    pub async fn resolve_breach(&self, breach_id: &str, opts: Option<Value>) -> Result<Value> {
        let body = opts.unwrap_or_else(|| Value::Object(Map::new()));
        self.http
            ._post(
                &self.p(&format!("compliance/breach/{breach_id}/resolve")),
                Some(&body),
            )
            .await
    }

    /// Outstanding breach-notification deadlines. Requires: admin scope.
    pub async fn breach_deadlines(&self) -> Result<Value> {
        self.http
            ._get(&self.p("compliance/breach-deadlines"), None)
            .await
    }

    // ── Reporting / metrics ──────────────────────────────────────────

    /// List recorded policy violations. Requires: admin scope.
    pub async fn violations(&self, filters: Option<&Value>) -> Result<Value> {
        self.http
            ._get(&self.p("compliance/violations"), filters)
            .await
    }

    /// Data-protection impact summary (DPIA inputs). Requires: admin scope.
    pub async fn impact(&self, filters: Option<&Value>) -> Result<Value> {
        self.http._get(&self.p("compliance/impact"), filters).await
    }

    /// Aggregate compliance metrics for the memory. Requires: admin scope.
    pub async fn metrics(&self, filters: Option<&Value>) -> Result<Value> {
        self.http._get(&self.p("compliance/metrics"), filters).await
    }
}