UNPKG

overmind-mcp

Version:

Orchestrateur universel agents IA multi-modeles via MCP. Inclut le protocole 'Custom-Nickname' pour identifier vos agents avec des surnoms originaux (The Chaos Prophet, Shadow Sniper, etc.), l'isolation mémoire (Private Memory Context) et le support pour

124 lines • 6.37 kB
/** * ═══════════════════════════════════════════════════════════════════════════ * Audit Trail — Droit d'accès (art. 26) * ═══════════════════════════════════════════════════════════════════════════ * * Extrait tous les renseignements personnels (RP) liés à un data_subject_id * depuis les tables actives (agent_runs, knowledge_chunks) et, optionnellement, * les archives cold storage (archived_runs, archived_chunks). * * Le résultat est retourné sous forme JSON complet pour respecter l'obligation * de reddition de comptes (art. 26 — communication d'une copie des RP). */ import { z } from 'zod'; import { getPool } from 'overmind-postgres-mcp'; import { logAccess } from '../lib/audit/guard.js'; import { isAuditEnabled } from '../lib/audit/types.js'; export const auditAccessRequestSchema = z.object({ data_subject_id: z .string() .min(1) .describe('Identifiant pseudonymisé du sujet (hash SHA-256, jamais l\'identité brute)'), include_archives: z .boolean() .optional() .default(false) .describe('Inclure les archives cold storage (archived_runs, archived_chunks)'), }); export async function auditAccessRequest(args) { try { const pool = getPool(); const subjectId = args.data_subject_id; // ── Tables actives ────────────────────────────────────────────────────── const agentRunsRes = await pool.query(`SELECT id, runner, agent_name, prompt, result, error, duration_ms, success, session_id, data_subject_id, legal_basis, consent_ref, retention_expires_at, anonymized, created_for, created_at FROM agent_runs WHERE data_subject_id = $1 ORDER BY created_at DESC`, [subjectId]); const knowledgeChunksRes = await pool.query(`SELECT id, source, text, model, data_subject_id, legal_basis, consent_ref, retention_expires_at, anonymized, created_at, updated_at FROM knowledge_chunks WHERE data_subject_id = $1 ORDER BY created_at DESC`, [subjectId]); const result = { data_subject_id: subjectId, generated_at: new Date().toISOString(), audit_enabled: isAuditEnabled(), active: { agent_runs: agentRunsRes.rows, knowledge_chunks: knowledgeChunksRes.rows, }, summary: { agent_runs_count: agentRunsRes.rowCount ?? 0, knowledge_chunks_count: knowledgeChunksRes.rowCount ?? 0, total: (agentRunsRes.rowCount ?? 0) + (knowledgeChunksRes.rowCount ?? 0), }, }; // ── Archives cold storage (optionnel) ─────────────────────────────────── if (args.include_archives) { const archivedRunsRes = await pool.query(`SELECT id, runner, agent_name, prompt, result, error, duration_ms, success, session_id, data_subject_id, legal_basis, consent_ref, retention_expires_at, anonymized, created_for, created_at, archived_at, archive_expires_at FROM archived_runs WHERE data_subject_id = $1 ORDER BY created_at DESC`, [subjectId]); const archivedChunksRes = await pool.query(`SELECT id, source, text, model, data_subject_id, legal_basis, consent_ref, retention_expires_at, anonymized, created_at, updated_at, archived_at, archive_expires_at FROM archived_chunks WHERE data_subject_id = $1 ORDER BY created_at DESC`, [subjectId]); result.archives = { archived_runs: archivedRunsRes.rows, archived_chunks: archivedChunksRes.rows, }; result.summary.archived_runs_count = archivedRunsRes.rowCount ?? 0; result.summary.archived_chunks_count = archivedChunksRes.rowCount ?? 0; result.summary.total += (archivedRunsRes.rowCount ?? 0) + (archivedChunksRes.rowCount ?? 0); } // ── Journalisation de l'accès (art. 26 — reddition de comptes) ────────── await logAccess({ dataSubjectId: subjectId, accessedBy: 'audit_access_request', action: 'read', resourceType: 'data_subject_export', resourceId: subjectId, purpose: args.include_archives ? 'audit_access_request_with_archives' : 'audit_access_request', }).catch(() => { }); // non-bloquant const json = JSON.stringify(result, null, 2); return { content: [ { type: 'text', text: `📋 **Audit Trail — Droit d'accès (Loi 25 art. 26)**\n\n` + `**Sujet :** \`${subjectId}\`\n` + `**Total RP trouvés :** ${result.summary.total}\n` + ` • agent_runs : ${result.summary.agent_runs_count}\n` + ` • knowledge_chunks : ${result.summary.knowledge_chunks_count}` + (result.summary.archived_runs_count !== undefined ? `\n • archived_runs : ${result.summary.archived_runs_count}\n` + ` • archived_chunks : ${result.summary.archived_chunks_count}` : '') + `\n\n\`\`\`json\n${json}\n\`\`\``, }, ], }; } catch (err) { return { content: [ { type: 'text', text: `❌ Erreur audit_access_request: ${err instanceof Error ? err.message : String(err)}`, }, ], isError: true, }; } } //# sourceMappingURL=audit_access_request.js.map