1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
//! `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
}
}