@weave_protocol/domere 1.0.13 → 1.0.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +278 -31
- package/dist/audit/index.d.ts +2 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/index.js +2 -0
- package/dist/audit/index.js.map +1 -0
- package/dist/audit/replay.d.ts +153 -0
- package/dist/audit/replay.d.ts.map +1 -0
- package/dist/audit/replay.js +328 -0
- package/dist/audit/replay.js.map +1 -0
- package/dist/compliance/checkpoint.d.ts +183 -0
- package/dist/compliance/checkpoint.d.ts.map +1 -0
- package/dist/compliance/checkpoint.js +394 -0
- package/dist/compliance/checkpoint.js.map +1 -0
- package/dist/compliance/index.d.ts +2 -0
- package/dist/compliance/index.d.ts.map +1 -0
- package/dist/compliance/index.js +2 -0
- package/dist/compliance/index.js.map +1 -0
- package/dist/handoff/index.d.ts +2 -0
- package/dist/handoff/index.d.ts.map +1 -0
- package/dist/handoff/index.js +2 -0
- package/dist/handoff/index.js.map +1 -0
- package/dist/handoff/verification.d.ts +115 -0
- package/dist/handoff/verification.d.ts.map +1 -0
- package/dist/handoff/verification.js +285 -0
- package/dist/handoff/verification.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/audit/index.ts +1 -0
- package/src/audit/replay.ts +504 -0
- package/src/compliance/checkpoint.ts +647 -0
- package/src/compliance/index.ts +1 -0
- package/src/handoff/index.ts +1 -0
- package/src/handoff/verification.ts +428 -0
- package/src/index.ts +5 -0
|
@@ -0,0 +1,647 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dōmere - Compliance Checkpoints (SOC2/HIPAA)
|
|
3
|
+
*
|
|
4
|
+
* Automated compliance tracking and reporting for AI systems.
|
|
5
|
+
* Supports SOC2, HIPAA, GDPR, and custom frameworks.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import * as crypto from 'crypto';
|
|
9
|
+
|
|
10
|
+
// =============================================================================
|
|
11
|
+
// Types
|
|
12
|
+
// =============================================================================
|
|
13
|
+
|
|
14
|
+
export type ComplianceFramework = 'SOC2' | 'HIPAA' | 'GDPR' | 'PCI-DSS' | 'ISO27001' | 'CUSTOM';
|
|
15
|
+
|
|
16
|
+
export type SOC2Control =
|
|
17
|
+
| 'CC1.1' | 'CC1.2' | 'CC1.3' | 'CC1.4' | 'CC1.5' // Control Environment
|
|
18
|
+
| 'CC2.1' | 'CC2.2' | 'CC2.3' // Communication
|
|
19
|
+
| 'CC3.1' | 'CC3.2' | 'CC3.3' | 'CC3.4' // Risk Assessment
|
|
20
|
+
| 'CC4.1' | 'CC4.2' // Monitoring
|
|
21
|
+
| 'CC5.1' | 'CC5.2' | 'CC5.3' // Control Activities
|
|
22
|
+
| 'CC6.1' | 'CC6.2' | 'CC6.3' | 'CC6.4' | 'CC6.5' | 'CC6.6' | 'CC6.7' | 'CC6.8' // Logical Access
|
|
23
|
+
| 'CC7.1' | 'CC7.2' | 'CC7.3' | 'CC7.4' | 'CC7.5' // System Operations
|
|
24
|
+
| 'CC8.1' // Change Management
|
|
25
|
+
| 'CC9.1' | 'CC9.2'; // Risk Mitigation
|
|
26
|
+
|
|
27
|
+
export type HIPAAControl =
|
|
28
|
+
| 'ACCESS_CONTROL'
|
|
29
|
+
| 'AUDIT_CONTROLS'
|
|
30
|
+
| 'INTEGRITY'
|
|
31
|
+
| 'PERSON_AUTH'
|
|
32
|
+
| 'TRANSMISSION_SECURITY'
|
|
33
|
+
| 'PRIVACY_RULE'
|
|
34
|
+
| 'BREACH_NOTIFICATION'
|
|
35
|
+
| 'MINIMUM_NECESSARY';
|
|
36
|
+
|
|
37
|
+
export interface ComplianceCheckpointRecord {
|
|
38
|
+
id: string;
|
|
39
|
+
thread_id: string;
|
|
40
|
+
timestamp: Date;
|
|
41
|
+
|
|
42
|
+
// Framework & control
|
|
43
|
+
framework: ComplianceFramework;
|
|
44
|
+
control: string;
|
|
45
|
+
control_description: string;
|
|
46
|
+
|
|
47
|
+
// Event details
|
|
48
|
+
event_type: 'access' | 'modification' | 'disclosure' | 'deletion' | 'transmission' | 'authentication' | 'authorization' | 'audit';
|
|
49
|
+
event_description: string;
|
|
50
|
+
|
|
51
|
+
// Data classification
|
|
52
|
+
data_classification: 'public' | 'internal' | 'confidential' | 'restricted' | 'phi' | 'pii';
|
|
53
|
+
data_categories: string[];
|
|
54
|
+
|
|
55
|
+
// Actors
|
|
56
|
+
agent_id: string;
|
|
57
|
+
user_id?: string;
|
|
58
|
+
data_subject_id?: string;
|
|
59
|
+
|
|
60
|
+
// Legal basis (GDPR/HIPAA)
|
|
61
|
+
legal_basis?: 'consent' | 'contract' | 'legal_obligation' | 'vital_interests' | 'public_task' | 'legitimate_interests' | 'treatment' | 'payment' | 'operations';
|
|
62
|
+
|
|
63
|
+
// Retention
|
|
64
|
+
retention_days?: number;
|
|
65
|
+
retention_policy?: string;
|
|
66
|
+
|
|
67
|
+
// Risk
|
|
68
|
+
risk_level: 'low' | 'medium' | 'high' | 'critical';
|
|
69
|
+
mitigations_applied: string[];
|
|
70
|
+
|
|
71
|
+
// Verification
|
|
72
|
+
checkpoint_hash: string;
|
|
73
|
+
signed: boolean;
|
|
74
|
+
signature?: string;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ComplianceViolationRecord {
|
|
78
|
+
id: string;
|
|
79
|
+
checkpoint_id: string;
|
|
80
|
+
thread_id: string;
|
|
81
|
+
timestamp: Date;
|
|
82
|
+
|
|
83
|
+
framework: ComplianceFramework;
|
|
84
|
+
control: string;
|
|
85
|
+
|
|
86
|
+
violation_type: 'unauthorized_access' | 'data_breach' | 'policy_violation' | 'retention_violation' | 'consent_violation' | 'audit_gap' | 'encryption_failure';
|
|
87
|
+
severity: 'low' | 'medium' | 'high' | 'critical';
|
|
88
|
+
description: string;
|
|
89
|
+
|
|
90
|
+
affected_records: number;
|
|
91
|
+
affected_subjects: string[];
|
|
92
|
+
|
|
93
|
+
remediation_required: boolean;
|
|
94
|
+
remediation_deadline?: Date;
|
|
95
|
+
remediation_status: 'pending' | 'in_progress' | 'completed' | 'waived';
|
|
96
|
+
remediation_notes?: string;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface ComplianceReportOutput {
|
|
100
|
+
id: string;
|
|
101
|
+
generated_at: Date;
|
|
102
|
+
period_start: Date;
|
|
103
|
+
period_end: Date;
|
|
104
|
+
|
|
105
|
+
framework: ComplianceFramework;
|
|
106
|
+
|
|
107
|
+
// Summary
|
|
108
|
+
total_checkpoints: number;
|
|
109
|
+
checkpoints_by_control: Record<string, number>;
|
|
110
|
+
checkpoints_by_event_type: Record<string, number>;
|
|
111
|
+
checkpoints_by_risk_level: Record<string, number>;
|
|
112
|
+
|
|
113
|
+
// Violations
|
|
114
|
+
total_violations: number;
|
|
115
|
+
violations_by_severity: Record<string, number>;
|
|
116
|
+
open_violations: number;
|
|
117
|
+
remediated_violations: number;
|
|
118
|
+
|
|
119
|
+
// Data subjects
|
|
120
|
+
unique_data_subjects: number;
|
|
121
|
+
data_access_count: number;
|
|
122
|
+
|
|
123
|
+
// Compliance score
|
|
124
|
+
compliance_score: number; // 0-100
|
|
125
|
+
control_coverage: Record<string, { covered: boolean; checkpoint_count: number }>;
|
|
126
|
+
|
|
127
|
+
// Attestation
|
|
128
|
+
attestation?: {
|
|
129
|
+
attester: string;
|
|
130
|
+
attested_at: Date;
|
|
131
|
+
statement: string;
|
|
132
|
+
signature: string;
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export interface RetentionPolicy {
|
|
137
|
+
name: string;
|
|
138
|
+
data_categories: string[];
|
|
139
|
+
retention_days: number;
|
|
140
|
+
deletion_method: 'soft' | 'hard' | 'anonymize';
|
|
141
|
+
legal_hold_exempt: boolean;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// =============================================================================
|
|
145
|
+
// SOC2 Control Descriptions
|
|
146
|
+
// =============================================================================
|
|
147
|
+
|
|
148
|
+
export const SOC2_CONTROLS: Record<SOC2Control, string> = {
|
|
149
|
+
'CC1.1': 'Integrity and Ethical Values',
|
|
150
|
+
'CC1.2': 'Board Independence and Oversight',
|
|
151
|
+
'CC1.3': 'Organizational Structure',
|
|
152
|
+
'CC1.4': 'Commitment to Competence',
|
|
153
|
+
'CC1.5': 'Accountability',
|
|
154
|
+
'CC2.1': 'Information Quality',
|
|
155
|
+
'CC2.2': 'Internal Communication',
|
|
156
|
+
'CC2.3': 'External Communication',
|
|
157
|
+
'CC3.1': 'Risk Assessment Objectives',
|
|
158
|
+
'CC3.2': 'Risk Identification',
|
|
159
|
+
'CC3.3': 'Fraud Risk',
|
|
160
|
+
'CC3.4': 'Change Impact Analysis',
|
|
161
|
+
'CC4.1': 'Monitoring Activities',
|
|
162
|
+
'CC4.2': 'Deficiency Evaluation',
|
|
163
|
+
'CC5.1': 'Control Selection',
|
|
164
|
+
'CC5.2': 'Technology Controls',
|
|
165
|
+
'CC5.3': 'Policy Deployment',
|
|
166
|
+
'CC6.1': 'Logical Access Security',
|
|
167
|
+
'CC6.2': 'Access Provisioning',
|
|
168
|
+
'CC6.3': 'Access Removal',
|
|
169
|
+
'CC6.4': 'Access Review',
|
|
170
|
+
'CC6.5': 'Authentication',
|
|
171
|
+
'CC6.6': 'Access Restrictions',
|
|
172
|
+
'CC6.7': 'Data Transmission Protection',
|
|
173
|
+
'CC6.8': 'Malicious Software Prevention',
|
|
174
|
+
'CC7.1': 'Infrastructure Monitoring',
|
|
175
|
+
'CC7.2': 'Security Event Detection',
|
|
176
|
+
'CC7.3': 'Incident Response',
|
|
177
|
+
'CC7.4': 'Business Continuity',
|
|
178
|
+
'CC7.5': 'Data Recovery',
|
|
179
|
+
'CC8.1': 'Change Management',
|
|
180
|
+
'CC9.1': 'Risk Mitigation',
|
|
181
|
+
'CC9.2': 'Vendor Management',
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const HIPAA_CONTROLS: Record<HIPAAControl, string> = {
|
|
185
|
+
'ACCESS_CONTROL': 'Access Control (§164.312(a)(1))',
|
|
186
|
+
'AUDIT_CONTROLS': 'Audit Controls (§164.312(b))',
|
|
187
|
+
'INTEGRITY': 'Integrity Controls (§164.312(c)(1))',
|
|
188
|
+
'PERSON_AUTH': 'Person Authentication (§164.312(d))',
|
|
189
|
+
'TRANSMISSION_SECURITY': 'Transmission Security (§164.312(e)(1))',
|
|
190
|
+
'PRIVACY_RULE': 'Privacy Rule Compliance',
|
|
191
|
+
'BREACH_NOTIFICATION': 'Breach Notification (§164.400-414)',
|
|
192
|
+
'MINIMUM_NECESSARY': 'Minimum Necessary Standard',
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
// =============================================================================
|
|
196
|
+
// Compliance Manager
|
|
197
|
+
// =============================================================================
|
|
198
|
+
|
|
199
|
+
export class ComplianceManager {
|
|
200
|
+
private checkpoints: Map<string, ComplianceCheckpointRecord> = new Map();
|
|
201
|
+
private violations: Map<string, ComplianceViolationRecord> = new Map();
|
|
202
|
+
private retentionPolicies: Map<string, RetentionPolicy> = new Map();
|
|
203
|
+
private signingKey: Buffer;
|
|
204
|
+
|
|
205
|
+
constructor(signingKey: string) {
|
|
206
|
+
this.signingKey = crypto.scryptSync(signingKey, 'domere-compliance', 32);
|
|
207
|
+
this.initDefaultPolicies();
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Record a compliance checkpoint
|
|
212
|
+
*/
|
|
213
|
+
async checkpoint(params: {
|
|
214
|
+
thread_id: string;
|
|
215
|
+
framework: ComplianceFramework;
|
|
216
|
+
control: string;
|
|
217
|
+
event_type: ComplianceCheckpointRecord['event_type'];
|
|
218
|
+
event_description: string;
|
|
219
|
+
data_classification: ComplianceCheckpointRecord['data_classification'];
|
|
220
|
+
data_categories?: string[];
|
|
221
|
+
agent_id: string;
|
|
222
|
+
user_id?: string;
|
|
223
|
+
data_subject_id?: string;
|
|
224
|
+
legal_basis?: ComplianceCheckpointRecord['legal_basis'];
|
|
225
|
+
retention_days?: number;
|
|
226
|
+
risk_level?: ComplianceCheckpointRecord['risk_level'];
|
|
227
|
+
mitigations_applied?: string[];
|
|
228
|
+
sign?: boolean;
|
|
229
|
+
}): Promise<ComplianceCheckpointRecord> {
|
|
230
|
+
const id = `chk_${crypto.randomUUID()}`;
|
|
231
|
+
|
|
232
|
+
// Get control description
|
|
233
|
+
let controlDescription = params.control;
|
|
234
|
+
if (params.framework === 'SOC2' && SOC2_CONTROLS[params.control as SOC2Control]) {
|
|
235
|
+
controlDescription = SOC2_CONTROLS[params.control as SOC2Control];
|
|
236
|
+
} else if (params.framework === 'HIPAA' && HIPAA_CONTROLS[params.control as HIPAAControl]) {
|
|
237
|
+
controlDescription = HIPAA_CONTROLS[params.control as HIPAAControl];
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Auto-assess risk if not provided
|
|
241
|
+
const riskLevel = params.risk_level || this.assessRisk(params);
|
|
242
|
+
|
|
243
|
+
// Get retention from policy
|
|
244
|
+
const retention = params.retention_days || this.getRetentionDays(params.data_categories || []);
|
|
245
|
+
|
|
246
|
+
const checkpoint: ComplianceCheckpointRecord = {
|
|
247
|
+
id,
|
|
248
|
+
thread_id: params.thread_id,
|
|
249
|
+
timestamp: new Date(),
|
|
250
|
+
|
|
251
|
+
framework: params.framework,
|
|
252
|
+
control: params.control,
|
|
253
|
+
control_description: controlDescription,
|
|
254
|
+
|
|
255
|
+
event_type: params.event_type,
|
|
256
|
+
event_description: params.event_description,
|
|
257
|
+
|
|
258
|
+
data_classification: params.data_classification,
|
|
259
|
+
data_categories: params.data_categories || [],
|
|
260
|
+
|
|
261
|
+
agent_id: params.agent_id,
|
|
262
|
+
user_id: params.user_id,
|
|
263
|
+
data_subject_id: params.data_subject_id,
|
|
264
|
+
|
|
265
|
+
legal_basis: params.legal_basis,
|
|
266
|
+
retention_days: retention,
|
|
267
|
+
|
|
268
|
+
risk_level: riskLevel,
|
|
269
|
+
mitigations_applied: params.mitigations_applied || [],
|
|
270
|
+
|
|
271
|
+
checkpoint_hash: '',
|
|
272
|
+
signed: params.sign || false,
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
// Compute hash
|
|
276
|
+
checkpoint.checkpoint_hash = this.computeCheckpointHash(checkpoint);
|
|
277
|
+
|
|
278
|
+
// Sign if requested
|
|
279
|
+
if (params.sign) {
|
|
280
|
+
checkpoint.signature = this.sign(checkpoint.checkpoint_hash);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
// Store
|
|
284
|
+
this.checkpoints.set(id, checkpoint);
|
|
285
|
+
|
|
286
|
+
// Check for violations
|
|
287
|
+
await this.checkViolations(checkpoint);
|
|
288
|
+
|
|
289
|
+
return checkpoint;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/**
|
|
293
|
+
* Record a compliance violation
|
|
294
|
+
*/
|
|
295
|
+
async recordViolation(params: {
|
|
296
|
+
checkpoint_id?: string;
|
|
297
|
+
thread_id: string;
|
|
298
|
+
framework: ComplianceFramework;
|
|
299
|
+
control: string;
|
|
300
|
+
violation_type: ComplianceViolationRecord['violation_type'];
|
|
301
|
+
severity: ComplianceViolationRecord['severity'];
|
|
302
|
+
description: string;
|
|
303
|
+
affected_records?: number;
|
|
304
|
+
affected_subjects?: string[];
|
|
305
|
+
remediation_deadline?: Date;
|
|
306
|
+
}): Promise<ComplianceViolationRecord> {
|
|
307
|
+
const id = `vio_${crypto.randomUUID()}`;
|
|
308
|
+
|
|
309
|
+
const violation: ComplianceViolationRecord = {
|
|
310
|
+
id,
|
|
311
|
+
checkpoint_id: params.checkpoint_id || '',
|
|
312
|
+
thread_id: params.thread_id,
|
|
313
|
+
timestamp: new Date(),
|
|
314
|
+
|
|
315
|
+
framework: params.framework,
|
|
316
|
+
control: params.control,
|
|
317
|
+
|
|
318
|
+
violation_type: params.violation_type,
|
|
319
|
+
severity: params.severity,
|
|
320
|
+
description: params.description,
|
|
321
|
+
|
|
322
|
+
affected_records: params.affected_records || 0,
|
|
323
|
+
affected_subjects: params.affected_subjects || [],
|
|
324
|
+
|
|
325
|
+
remediation_required: params.severity !== 'low',
|
|
326
|
+
remediation_deadline: params.remediation_deadline,
|
|
327
|
+
remediation_status: 'pending',
|
|
328
|
+
};
|
|
329
|
+
|
|
330
|
+
this.violations.set(id, violation);
|
|
331
|
+
|
|
332
|
+
return violation;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Update remediation status
|
|
337
|
+
*/
|
|
338
|
+
async updateRemediation(violationId: string, status: ComplianceViolationRecord['remediation_status'], notes?: string): Promise<ComplianceViolationRecord | null> {
|
|
339
|
+
const violation = this.violations.get(violationId);
|
|
340
|
+
if (!violation) return null;
|
|
341
|
+
|
|
342
|
+
violation.remediation_status = status;
|
|
343
|
+
if (notes) violation.remediation_notes = notes;
|
|
344
|
+
|
|
345
|
+
return violation;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* Generate compliance report
|
|
350
|
+
*/
|
|
351
|
+
async generateReport(params: {
|
|
352
|
+
framework: ComplianceFramework;
|
|
353
|
+
period_start: Date;
|
|
354
|
+
period_end: Date;
|
|
355
|
+
attester?: string;
|
|
356
|
+
}): Promise<ComplianceReportOutput> {
|
|
357
|
+
const id = `rpt_${crypto.randomUUID()}`;
|
|
358
|
+
|
|
359
|
+
// Filter checkpoints
|
|
360
|
+
const relevantCheckpoints = Array.from(this.checkpoints.values()).filter(c =>
|
|
361
|
+
c.framework === params.framework &&
|
|
362
|
+
c.timestamp >= params.period_start &&
|
|
363
|
+
c.timestamp <= params.period_end
|
|
364
|
+
);
|
|
365
|
+
|
|
366
|
+
// Filter violations
|
|
367
|
+
const relevantViolations = Array.from(this.violations.values()).filter(v =>
|
|
368
|
+
v.framework === params.framework &&
|
|
369
|
+
v.timestamp >= params.period_start &&
|
|
370
|
+
v.timestamp <= params.period_end
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
// Compute stats
|
|
374
|
+
const checkpointsByControl: Record<string, number> = {};
|
|
375
|
+
const checkpointsByEventType: Record<string, number> = {};
|
|
376
|
+
const checkpointsByRiskLevel: Record<string, number> = {};
|
|
377
|
+
const dataSubjects = new Set<string>();
|
|
378
|
+
let dataAccessCount = 0;
|
|
379
|
+
|
|
380
|
+
for (const c of relevantCheckpoints) {
|
|
381
|
+
checkpointsByControl[c.control] = (checkpointsByControl[c.control] || 0) + 1;
|
|
382
|
+
checkpointsByEventType[c.event_type] = (checkpointsByEventType[c.event_type] || 0) + 1;
|
|
383
|
+
checkpointsByRiskLevel[c.risk_level] = (checkpointsByRiskLevel[c.risk_level] || 0) + 1;
|
|
384
|
+
|
|
385
|
+
if (c.data_subject_id) dataSubjects.add(c.data_subject_id);
|
|
386
|
+
if (c.event_type === 'access') dataAccessCount++;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
const violationsBySeverity: Record<string, number> = {};
|
|
390
|
+
let openViolations = 0;
|
|
391
|
+
let remediatedViolations = 0;
|
|
392
|
+
|
|
393
|
+
for (const v of relevantViolations) {
|
|
394
|
+
violationsBySeverity[v.severity] = (violationsBySeverity[v.severity] || 0) + 1;
|
|
395
|
+
if (v.remediation_status === 'pending' || v.remediation_status === 'in_progress') {
|
|
396
|
+
openViolations++;
|
|
397
|
+
} else if (v.remediation_status === 'completed') {
|
|
398
|
+
remediatedViolations++;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
// Calculate control coverage
|
|
403
|
+
const controlCoverage: Record<string, { covered: boolean; checkpoint_count: number }> = {};
|
|
404
|
+
const controlList = params.framework === 'SOC2' ? Object.keys(SOC2_CONTROLS) :
|
|
405
|
+
params.framework === 'HIPAA' ? Object.keys(HIPAA_CONTROLS) : [];
|
|
406
|
+
|
|
407
|
+
for (const control of controlList) {
|
|
408
|
+
const count = checkpointsByControl[control] || 0;
|
|
409
|
+
controlCoverage[control] = { covered: count > 0, checkpoint_count: count };
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
// Calculate compliance score
|
|
413
|
+
const coveredControls = Object.values(controlCoverage).filter(c => c.covered).length;
|
|
414
|
+
const totalControls = controlList.length;
|
|
415
|
+
const controlScore = totalControls > 0 ? (coveredControls / totalControls) * 50 : 50;
|
|
416
|
+
|
|
417
|
+
const violationPenalty = Math.min(50, relevantViolations.length * 5);
|
|
418
|
+
const complianceScore = Math.max(0, Math.round(controlScore + 50 - violationPenalty));
|
|
419
|
+
|
|
420
|
+
const report: ComplianceReportOutput = {
|
|
421
|
+
id,
|
|
422
|
+
generated_at: new Date(),
|
|
423
|
+
period_start: params.period_start,
|
|
424
|
+
period_end: params.period_end,
|
|
425
|
+
|
|
426
|
+
framework: params.framework,
|
|
427
|
+
|
|
428
|
+
total_checkpoints: relevantCheckpoints.length,
|
|
429
|
+
checkpoints_by_control: checkpointsByControl,
|
|
430
|
+
checkpoints_by_event_type: checkpointsByEventType,
|
|
431
|
+
checkpoints_by_risk_level: checkpointsByRiskLevel,
|
|
432
|
+
|
|
433
|
+
total_violations: relevantViolations.length,
|
|
434
|
+
violations_by_severity: violationsBySeverity,
|
|
435
|
+
open_violations: openViolations,
|
|
436
|
+
remediated_violations: remediatedViolations,
|
|
437
|
+
|
|
438
|
+
unique_data_subjects: dataSubjects.size,
|
|
439
|
+
data_access_count: dataAccessCount,
|
|
440
|
+
|
|
441
|
+
compliance_score: complianceScore,
|
|
442
|
+
control_coverage: controlCoverage,
|
|
443
|
+
};
|
|
444
|
+
|
|
445
|
+
// Add attestation if requested
|
|
446
|
+
if (params.attester) {
|
|
447
|
+
const statement = `I, ${params.attester}, attest that this compliance report accurately reflects the state of the ${params.framework} controls for the period ${params.period_start.toISOString()} to ${params.period_end.toISOString()}.`;
|
|
448
|
+
report.attestation = {
|
|
449
|
+
attester: params.attester,
|
|
450
|
+
attested_at: new Date(),
|
|
451
|
+
statement,
|
|
452
|
+
signature: this.sign(statement),
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
return report;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/**
|
|
460
|
+
* Get checkpoints for a thread
|
|
461
|
+
*/
|
|
462
|
+
async getCheckpoints(threadId: string): Promise<ComplianceCheckpointRecord[]> {
|
|
463
|
+
return Array.from(this.checkpoints.values())
|
|
464
|
+
.filter(c => c.thread_id === threadId)
|
|
465
|
+
.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Get violations for a thread
|
|
470
|
+
*/
|
|
471
|
+
async getViolations(threadId: string): Promise<ComplianceViolationRecord[]> {
|
|
472
|
+
return Array.from(this.violations.values())
|
|
473
|
+
.filter(v => v.thread_id === threadId)
|
|
474
|
+
.sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime());
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
/**
|
|
478
|
+
* Add retention policy
|
|
479
|
+
*/
|
|
480
|
+
addRetentionPolicy(policy: RetentionPolicy): void {
|
|
481
|
+
this.retentionPolicies.set(policy.name, policy);
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/**
|
|
485
|
+
* HIPAA-specific: Log PHI access
|
|
486
|
+
*/
|
|
487
|
+
async logPHIAccess(params: {
|
|
488
|
+
thread_id: string;
|
|
489
|
+
agent_id: string;
|
|
490
|
+
patient_id: string;
|
|
491
|
+
access_reason: string;
|
|
492
|
+
data_accessed: string[];
|
|
493
|
+
legal_basis: 'treatment' | 'payment' | 'operations';
|
|
494
|
+
}): Promise<ComplianceCheckpointRecord> {
|
|
495
|
+
return this.checkpoint({
|
|
496
|
+
thread_id: params.thread_id,
|
|
497
|
+
framework: 'HIPAA',
|
|
498
|
+
control: 'ACCESS_CONTROL',
|
|
499
|
+
event_type: 'access',
|
|
500
|
+
event_description: `PHI accessed for ${params.access_reason}`,
|
|
501
|
+
data_classification: 'phi',
|
|
502
|
+
data_categories: params.data_accessed,
|
|
503
|
+
agent_id: params.agent_id,
|
|
504
|
+
data_subject_id: params.patient_id,
|
|
505
|
+
legal_basis: params.legal_basis,
|
|
506
|
+
sign: true,
|
|
507
|
+
});
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
/**
|
|
511
|
+
* SOC2-specific: Log access control event
|
|
512
|
+
*/
|
|
513
|
+
async logAccessControl(params: {
|
|
514
|
+
thread_id: string;
|
|
515
|
+
agent_id: string;
|
|
516
|
+
user_id?: string;
|
|
517
|
+
resource: string;
|
|
518
|
+
action: 'grant' | 'revoke' | 'modify' | 'review';
|
|
519
|
+
success: boolean;
|
|
520
|
+
}): Promise<ComplianceCheckpointRecord> {
|
|
521
|
+
return this.checkpoint({
|
|
522
|
+
thread_id: params.thread_id,
|
|
523
|
+
framework: 'SOC2',
|
|
524
|
+
control: params.action === 'grant' ? 'CC6.2' :
|
|
525
|
+
params.action === 'revoke' ? 'CC6.3' :
|
|
526
|
+
params.action === 'review' ? 'CC6.4' : 'CC6.1',
|
|
527
|
+
event_type: 'authorization',
|
|
528
|
+
event_description: `Access ${params.action} for ${params.resource}: ${params.success ? 'success' : 'failed'}`,
|
|
529
|
+
data_classification: 'internal',
|
|
530
|
+
agent_id: params.agent_id,
|
|
531
|
+
user_id: params.user_id,
|
|
532
|
+
risk_level: params.success ? 'low' : 'medium',
|
|
533
|
+
sign: true,
|
|
534
|
+
});
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
// ===========================================================================
|
|
538
|
+
// Private Methods
|
|
539
|
+
// ===========================================================================
|
|
540
|
+
|
|
541
|
+
private initDefaultPolicies(): void {
|
|
542
|
+
this.addRetentionPolicy({
|
|
543
|
+
name: 'phi_retention',
|
|
544
|
+
data_categories: ['phi', 'medical_records', 'patient_data'],
|
|
545
|
+
retention_days: 2190, // 6 years for HIPAA
|
|
546
|
+
deletion_method: 'hard',
|
|
547
|
+
legal_hold_exempt: false,
|
|
548
|
+
});
|
|
549
|
+
|
|
550
|
+
this.addRetentionPolicy({
|
|
551
|
+
name: 'pii_retention',
|
|
552
|
+
data_categories: ['pii', 'personal_data'],
|
|
553
|
+
retention_days: 365,
|
|
554
|
+
deletion_method: 'anonymize',
|
|
555
|
+
legal_hold_exempt: false,
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
this.addRetentionPolicy({
|
|
559
|
+
name: 'audit_log_retention',
|
|
560
|
+
data_categories: ['audit_logs', 'access_logs'],
|
|
561
|
+
retention_days: 365, // SOC2 requirement
|
|
562
|
+
deletion_method: 'soft',
|
|
563
|
+
legal_hold_exempt: true,
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
private assessRisk(params: { data_classification: string; event_type: string }): 'low' | 'medium' | 'high' | 'critical' {
|
|
568
|
+
if (params.data_classification === 'phi' || params.data_classification === 'restricted') {
|
|
569
|
+
if (params.event_type === 'disclosure' || params.event_type === 'transmission') {
|
|
570
|
+
return 'critical';
|
|
571
|
+
}
|
|
572
|
+
return 'high';
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (params.data_classification === 'pii' || params.data_classification === 'confidential') {
|
|
576
|
+
return 'medium';
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return 'low';
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
private getRetentionDays(categories: string[]): number {
|
|
583
|
+
let maxRetention = 90; // Default
|
|
584
|
+
|
|
585
|
+
for (const policy of this.retentionPolicies.values()) {
|
|
586
|
+
if (categories.some(c => policy.data_categories.includes(c))) {
|
|
587
|
+
maxRetention = Math.max(maxRetention, policy.retention_days);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
return maxRetention;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
private async checkViolations(checkpoint: ComplianceCheckpointRecord): Promise<void> {
|
|
595
|
+
// Check for missing legal basis on PHI
|
|
596
|
+
if (checkpoint.data_classification === 'phi' && !checkpoint.legal_basis) {
|
|
597
|
+
await this.recordViolation({
|
|
598
|
+
checkpoint_id: checkpoint.id,
|
|
599
|
+
thread_id: checkpoint.thread_id,
|
|
600
|
+
framework: 'HIPAA',
|
|
601
|
+
control: 'MINIMUM_NECESSARY',
|
|
602
|
+
violation_type: 'policy_violation',
|
|
603
|
+
severity: 'high',
|
|
604
|
+
description: 'PHI accessed without documented legal basis',
|
|
605
|
+
affected_records: 1,
|
|
606
|
+
affected_subjects: checkpoint.data_subject_id ? [checkpoint.data_subject_id] : [],
|
|
607
|
+
});
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
// Check for high-risk access without mitigations
|
|
611
|
+
if (checkpoint.risk_level === 'critical' && checkpoint.mitigations_applied.length === 0) {
|
|
612
|
+
await this.recordViolation({
|
|
613
|
+
checkpoint_id: checkpoint.id,
|
|
614
|
+
thread_id: checkpoint.thread_id,
|
|
615
|
+
framework: checkpoint.framework,
|
|
616
|
+
control: checkpoint.control,
|
|
617
|
+
violation_type: 'policy_violation',
|
|
618
|
+
severity: 'medium',
|
|
619
|
+
description: 'Critical risk event without documented mitigations',
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
private computeCheckpointHash(checkpoint: ComplianceCheckpointRecord): string {
|
|
625
|
+
const data = [
|
|
626
|
+
checkpoint.id,
|
|
627
|
+
checkpoint.thread_id,
|
|
628
|
+
checkpoint.timestamp.toISOString(),
|
|
629
|
+
checkpoint.framework,
|
|
630
|
+
checkpoint.control,
|
|
631
|
+
checkpoint.event_type,
|
|
632
|
+
checkpoint.event_description,
|
|
633
|
+
checkpoint.data_classification,
|
|
634
|
+
checkpoint.agent_id,
|
|
635
|
+
].join('|');
|
|
636
|
+
|
|
637
|
+
return crypto.createHash('sha256').update(data).digest('hex');
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
private sign(data: string): string {
|
|
641
|
+
const hmac = crypto.createHmac('sha256', this.signingKey);
|
|
642
|
+
hmac.update(data);
|
|
643
|
+
return hmac.digest('hex');
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
export default ComplianceManager;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./checkpoint.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./verification.js";
|