{"version":3,"sources":["../src/compliance.ts"],"sourcesContent":["import { type AuditLogEntry, Identity, type Secret } from './domain';\nimport type { SecretManager } from './manager';\n\nexport type ComplianceReport = {\n  period: {\n    start: Date;\n    end: Date;\n  };\n  summary: {\n    totalSecrets: number;\n    totalAccesses: number;\n    totalModifications: number;\n    complianceViolations: number;\n  };\n  violations: ComplianceViolation[];\n  recommendations: string[];\n};\n\nexport type ComplianceViolation = {\n  id: string;\n  type: 'rotation_overdue' | 'access_anomaly' | 'policy_violation' | 'unauthorized_access';\n  severity: 'low' | 'medium' | 'high' | 'critical';\n  secretId?: string;\n  description: string;\n  timestamp: Date;\n  actor?: string;\n  details: Record<string, unknown>;\n};\n\ntype AccessPattern = {\n  totalAccesses: number;\n  uniqueActors: Set<string>;\n  accessTimes: Date[];\n  isAnomalous: boolean;\n  anomalyReason?: string;\n  offHoursAccess?: number;\n};\n\ntype SerializableAccessPattern = Omit<AccessPattern, 'uniqueActors' | 'accessTimes'> & {\n  uniqueActors: string[];\n  accessTimes: string[];\n};\n\nexport type AuditQuery = {\n  startDate?: Date;\n  endDate?: Date;\n  secretId?: string;\n  actor?: string;\n  action?: string;\n  tenant?: string;\n  limit?: number;\n  offset?: number;\n};\n\nexport class ComplianceAuditor {\n  constructor(private readonly manager: SecretManager) {}\n\n  async generateComplianceReport(\n    startDate: Date,\n    endDate: Date,\n    tenant?: string\n  ): Promise<ComplianceReport> {\n    const auditEntries = await this.queryAuditLogs({\n      startDate,\n      endDate,\n      ...(tenant && { tenant }),\n    });\n\n    const secrets = await this.manager.listSecrets(\n      new Identity('auditor', ['reader'], tenant ?? 'default')\n    );\n\n    const violations = await this.detectViolations(secrets, auditEntries, startDate, endDate);\n\n    return {\n      period: { start: startDate, end: endDate },\n      summary: {\n        totalSecrets: secrets.length,\n        totalAccesses: auditEntries.filter((entry) => entry.action === 'get').length,\n        totalModifications: auditEntries.filter((entry) =>\n          ['create', 'put', 'delete'].includes(entry.action)\n        ).length,\n        complianceViolations: violations.length,\n      },\n      violations,\n      recommendations: this.generateRecommendations(violations, secrets),\n    };\n  }\n\n  async detectViolations(\n    secrets: Secret[],\n    auditEntries: AuditLogEntry[],\n    _startDate: Date,\n    _endDate: Date\n  ): Promise<ComplianceViolation[]> {\n    const violations: ComplianceViolation[] = [];\n\n    // Check for overdue rotations\n    for (const secret of secrets) {\n      const lastRotation = this.getLastRotationDate(secret, auditEntries);\n      const daysSinceRotation = lastRotation\n        ? (Date.now() - lastRotation.getTime()) / (1000 * 60 * 60 * 24)\n        : Infinity;\n\n      if (daysSinceRotation > secret.policy.rotationDays) {\n        violations.push({\n          id: `rotation-${secret.id}`,\n          type: 'rotation_overdue',\n          severity: daysSinceRotation > secret.policy.rotationDays * 2 ? 'high' : 'medium',\n          secretId: secret.id,\n          description: `Secret has not been rotated for ${Math.round(daysSinceRotation)} days (policy requires ${secret.policy.rotationDays} days)`,\n          timestamp: new Date(),\n          details: {\n            lastRotation,\n            daysOverdue: daysSinceRotation - secret.policy.rotationDays,\n            policyRotationDays: secret.policy.rotationDays,\n          },\n        });\n      }\n    }\n\n    // Check for access anomalies\n    const accessPatterns = this.analyzeAccessPatterns(auditEntries);\n    for (const [secretId, pattern] of Object.entries(accessPatterns)) {\n      if (pattern.isAnomalous) {\n        violations.push({\n          id: `access-anomaly-${secretId}`,\n          type: 'access_anomaly',\n          severity: 'medium',\n          secretId,\n          description: `Unusual access pattern detected for secret`,\n          timestamp: new Date(),\n          details: this.serializeAccessPattern(pattern),\n        });\n      }\n    }\n\n    // Check for policy violations\n    for (const entry of auditEntries) {\n      if (entry.action === 'create' || entry.action === 'put') {\n        const violationsForEntry = await this.checkPolicyCompliance(entry);\n        violations.push(...violationsForEntry);\n      }\n    }\n\n    return violations;\n  }\n\n  private getLastRotationDate(secret: Secret, auditEntries: AuditLogEntry[]): Date | null {\n    const rotationEntries = auditEntries\n      .filter((entry) => entry.secretId === secret.id && entry.action === 'rotate')\n      .sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());\n\n    return rotationEntries[0]?.timestamp ?? null;\n  }\n\n  private analyzeAccessPatterns(auditEntries: AuditLogEntry[]): Record<string, AccessPattern> {\n    const patterns: Record<string, AccessPattern> = {};\n\n    for (const entry of auditEntries) {\n      if (!entry.secretId || entry.action !== 'get') {\n        continue;\n      }\n\n      const pattern =\n        patterns[entry.secretId] ??\n        (patterns[entry.secretId] = {\n          totalAccesses: 0,\n          uniqueActors: new Set(),\n          accessTimes: [],\n          isAnomalous: false,\n        });\n      pattern.totalAccesses++;\n      pattern.uniqueActors.add(entry.subject);\n      pattern.accessTimes.push(entry.timestamp);\n\n      // Simple anomaly detection: high frequency access or access outside business hours\n      if (pattern.totalAccesses > 100) {\n        pattern.isAnomalous = true;\n        pattern.anomalyReason = 'High access frequency';\n      }\n\n      // Check for off-hours access (simplified)\n      const hour = entry.timestamp.getHours();\n      if (hour < 6 || hour > 22) {\n        pattern.offHoursAccess = (pattern.offHoursAccess ?? 0) + 1;\n        if (pattern.offHoursAccess > 10) {\n          pattern.isAnomalous = true;\n          pattern.anomalyReason = 'Frequent off-hours access';\n        }\n      }\n    }\n\n    return patterns;\n  }\n\n  private serializeAccessPattern(pattern: AccessPattern): SerializableAccessPattern {\n    return {\n      totalAccesses: pattern.totalAccesses,\n      uniqueActors: Array.from(pattern.uniqueActors),\n      accessTimes: pattern.accessTimes.map((time) => time.toISOString()),\n      isAnomalous: pattern.isAnomalous,\n      ...(pattern.anomalyReason ? { anomalyReason: pattern.anomalyReason } : {}),\n      ...(pattern.offHoursAccess ? { offHoursAccess: pattern.offHoursAccess } : {}),\n    };\n  }\n\n  private checkPolicyCompliance(_entry: AuditLogEntry): Promise<ComplianceViolation[]> {\n    // This would check if the secret creation/update complied with policies.\n    return Promise.resolve([]);\n  }\n\n  private generateRecommendations(violations: ComplianceViolation[], secrets: Secret[]): string[] {\n    const recommendations: string[] = [];\n\n    const overdueRotations = violations.filter((v) => v.type === 'rotation_overdue').length;\n    if (overdueRotations > 0) {\n      recommendations.push(\n        `Rotate ${overdueRotations} secrets that are past their rotation deadline`\n      );\n    }\n\n    const anomalousAccess = violations.filter((v) => v.type === 'access_anomaly').length;\n    if (anomalousAccess > 0) {\n      recommendations.push('Review access patterns for secrets with anomalous activity');\n    }\n\n    const unrotatedSecrets = secrets.filter((s) => !s.rotationHandler).length;\n    if (unrotatedSecrets > secrets.length * 0.5) {\n      recommendations.push(\n        'Implement rotation handlers for secrets that support automated rotation'\n      );\n    }\n\n    if (secrets.some((s) => !s.description)) {\n      recommendations.push('Add descriptions to all secrets for better governance');\n    }\n\n    return recommendations;\n  }\n\n  queryAuditLogs(query: AuditQuery): Promise<AuditLogEntry[]> {\n    // In a real implementation, this would query the audit log storage\n    // For now, return empty array as audit logs are written to files/console\n    console.info('Audit query:', query);\n    return Promise.resolve([]);\n  }\n\n  exportAuditReport(format: 'json' | 'csv' | 'pdf', report: ComplianceReport): Promise<Buffer> {\n    switch (format) {\n      case 'json':\n        return Promise.resolve(Buffer.from(JSON.stringify(report, null, 2)));\n      case 'csv':\n        return Promise.resolve(this.generateCSVReport(report));\n      case 'pdf':\n        return Promise.resolve(this.generatePDFReport(report));\n      default:\n        return Promise.reject(new Error(`Unsupported format: ${format}`));\n    }\n  }\n\n  private generateCSVReport(report: ComplianceReport): Buffer {\n    const lines = [\n      'Violation ID,Type,Severity,Secret ID,Description,Timestamp',\n      ...report.violations.map(\n        (v) =>\n          `${v.id},${v.type},${v.severity},${v.secretId ?? ''},\"${v.description}\",${v.timestamp.toISOString()}`\n      ),\n    ];\n    return Buffer.from(lines.join('\\n'));\n  }\n\n  private generatePDFReport(report: ComplianceReport): Buffer {\n    // In a real implementation, this would generate a PDF\n    // For now, return JSON as PDF\n    return Buffer.from(JSON.stringify(report, null, 2));\n  }\n}\n"],"mappings":"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","names":[]}