/**
 * NISTAIRMFAuditBot -- Automated NIST AI RMF 1.0 compliance auditing.
 *
 * Covers: GOVERN / MAP / MEASURE / MANAGE function coverage, AI risk
 * control evidence, bias metric correlation, system performance monitoring,
 * stakeholder engagement log, and AI RMF Profile document generation.
 * Integrates the 2024 GenAI Profile (NIST AI 600-1). Does NOT call external APIs.
 *
 * Narrative writing is delegated to an injectable NarrativeWriter.
 *
 * P2A-09
 *
 * @connexum/ai-governance
 */
import * as fs from 'fs';
import * as path from 'path';
import { computeAuditScore, } from './scheduler.js';
export class StubNarrativeWriter {
    write(controlId, context) {
        return `[NIST AI RMF] Function ${controlId}: ${context.slice(0, 120)}`;
    }
}
export class NISTAIRMFAuditBot {
    logDir;
    governanceDir;
    narrativeWriter;
    constructor(config) {
        this.logDir = config.logDir;
        this.governanceDir = config.governanceDir;
        this.narrativeWriter = config.narrativeWriter ?? new StubNarrativeWriter();
    }
    runAudit() {
        const checks = [
            // GOVERN function
            this.checkGOVERN1Accountability(),
            this.checkGOVERN2Policies(),
            this.checkGOVERN3Workforce(),
            this.checkGOVERN4Documentation(),
            this.checkGOVERN6Stakeholders(),
            // MAP function
            this.checkMAP1Context(),
            this.checkMAP2AIRisks(),
            this.checkMAP3DataImpacts(),
            this.checkMAP5Impacts(),
            // MEASURE function
            this.checkMEASURE1TestingPlan(),
            this.checkMEASURE2BiasMetrics(),
            this.checkMEASURE3Monitoring(),
            this.checkMEASURE4Feedback(),
            // MANAGE function
            this.checkMANAGE1Prioritization(),
            this.checkMANAGE2Response(),
            this.checkMANAGE3ThirdParty(),
            this.checkMANAGE4Monitoring(),
            // GenAI Profile (NIST AI 600-1)
            this.checkGenAIHallucinationControls(),
            this.checkGenAIDataGovernance(),
        ];
        const { score, passed, failed, warnings } = computeAuditScore(checks);
        return {
            auditId: '',
            packId: 'nist-ai-rmf',
            timestamp: new Date().toISOString(),
            checks,
            score,
            passed,
            failed,
            warnings,
        };
    }
    // --- GOVERN function ---
    checkGOVERN1Accountability() {
        const govFile = path.join(this.governanceDir, 'governance.json');
        const rolesFile = path.join(this.governanceDir, 'roles.json');
        const exists = fs.existsSync(govFile) || fs.existsSync(rolesFile);
        return {
            id: 'nist-ai-rmf-govern1-accountability',
            title: 'GOVERN 1: Organizational accountability for AI risk',
            status: exists ? 'pass' : 'fail',
            detail: exists
                ? 'Governance configuration and/or roles file found per GOVERN 1'
                : 'No governance.json or roles.json -- organizational accountability for AI risk not evidenced',
            evidence: exists
                ? [govFile, rolesFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkGOVERN2Policies() {
        const policyFile = path.join(this.governanceDir, 'security-policy.json');
        const capFile = path.join(this.governanceDir, 'capability-bundles.json');
        const exists = fs.existsSync(policyFile) || fs.existsSync(capFile);
        return {
            id: 'nist-ai-rmf-govern2-policies',
            title: 'GOVERN 2: AI risk policies and procedures',
            status: exists ? 'pass' : 'fail',
            detail: exists
                ? 'Security policies or capability bundles found per GOVERN 2'
                : 'No security-policy.json or capability-bundles.json -- AI risk policies not documented',
            evidence: exists
                ? [policyFile, capFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkGOVERN3Workforce() {
        const trainingFile = path.join(this.governanceDir, 'workforce-training.json');
        const govFile = path.join(this.governanceDir, 'governance.json');
        const exists = fs.existsSync(trainingFile) || fs.existsSync(govFile);
        return {
            id: 'nist-ai-rmf-govern3-workforce',
            title: 'GOVERN 3: AI workforce roles and responsibilities',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Governance or training configuration found per GOVERN 3'
                : 'No workforce-training.json -- AI roles and training not documented',
            evidence: exists
                ? [trainingFile, govFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkGOVERN4Documentation() {
        const hasMultipleDocs = fs.existsSync(this.governanceDir) &&
            fs.readdirSync(this.governanceDir).filter((f) => f.endsWith('.json') || f.endsWith('.md')).length >= 3;
        return {
            id: 'nist-ai-rmf-govern4-documentation',
            title: 'GOVERN 4: Organizational accountability documentation',
            status: hasMultipleDocs ? 'pass' : 'warning',
            detail: hasMultipleDocs
                ? 'Multiple governance documentation files found per GOVERN 4'
                : 'Insufficient governance documentation files -- GOVERN 4 requires comprehensive docs',
            evidence: hasMultipleDocs ? this.governanceDir : undefined,
        };
    }
    checkGOVERN6Stakeholders() {
        const stakeholderFile = path.join(this.governanceDir, 'stakeholder-engagement.json');
        const exists = fs.existsSync(stakeholderFile);
        return {
            id: 'nist-ai-rmf-govern6-stakeholders',
            title: 'GOVERN 6: Stakeholder engagement and feedback',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Stakeholder engagement log found per GOVERN 6'
                : 'No stakeholder-engagement.json -- external stakeholder feedback not documented',
            evidence: exists ? stakeholderFile : undefined,
        };
    }
    // --- MAP function ---
    checkMAP1Context() {
        const contextFile = path.join(this.governanceDir, 'ai-system-context.json');
        const govFile = path.join(this.governanceDir, 'governance.json');
        const exists = fs.existsSync(contextFile) || fs.existsSync(govFile);
        return {
            id: 'nist-ai-rmf-map1-context',
            title: 'MAP 1: AI system context established',
            status: exists ? 'pass' : 'fail',
            detail: exists
                ? 'AI system context documentation found per MAP 1'
                : 'No ai-system-context.json -- AI system context and intended use not documented',
            evidence: exists
                ? [contextFile, govFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkMAP2AIRisks() {
        const riskFile = path.join(this.governanceDir, 'risk-assessment.json');
        const anomalyFile = path.join(this.governanceDir, 'anomaly-detection.json');
        const exists = fs.existsSync(riskFile) || fs.existsSync(anomalyFile);
        return {
            id: 'nist-ai-rmf-map2-risks',
            title: 'MAP 2: AI risk categories mapped',
            status: exists ? 'pass' : 'fail',
            detail: exists
                ? 'Risk assessment or anomaly detection found per MAP 2'
                : 'No risk-assessment.json or anomaly-detection.json -- AI risk mapping not evidenced',
            evidence: exists
                ? [riskFile, anomalyFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkMAP3DataImpacts() {
        const classifierFile = path.join(this.governanceDir, 'data-classifier.json');
        const exists = fs.existsSync(classifierFile);
        return {
            id: 'nist-ai-rmf-map3-data',
            title: 'MAP 3: Data impacts documented',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Data classifier configuration found per MAP 3'
                : 'No data-classifier.json -- data impact on AI system not assessed',
            evidence: exists ? classifierFile : undefined,
        };
    }
    checkMAP5Impacts() {
        const impactFile = path.join(this.governanceDir, 'ai-impact-assessment.json');
        const riskFile = path.join(this.governanceDir, 'risk-assessment.json');
        const exists = fs.existsSync(impactFile) || fs.existsSync(riskFile);
        return {
            id: 'nist-ai-rmf-map5-impacts',
            title: 'MAP 5: Impacts identified and prioritized',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Impact assessment or risk assessment found per MAP 5'
                : 'No ai-impact-assessment.json -- societal and organizational impacts not assessed',
            evidence: exists
                ? [impactFile, riskFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    // --- MEASURE function ---
    checkMEASURE1TestingPlan() {
        const testFile = path.join(this.governanceDir, 'ai-testing-plan.json');
        const hasLogs = fs.existsSync(this.logDir) &&
            fs.readdirSync(this.logDir).some((f) => f.endsWith('.jsonl'));
        const exists = fs.existsSync(testFile) || hasLogs;
        return {
            id: 'nist-ai-rmf-measure1-testing',
            title: 'MEASURE 1: AI risk measurement approach',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Testing plan or audit logs found per MEASURE 1'
                : 'No ai-testing-plan.json -- AI risk measurement approach not documented',
            evidence: exists
                ? (fs.existsSync(testFile) ? testFile : this.logDir)
                : undefined,
        };
    }
    checkMEASURE2BiasMetrics() {
        const biasFile = path.join(this.governanceDir, 'bias-monitor.json');
        const exists = fs.existsSync(biasFile);
        return {
            id: 'nist-ai-rmf-measure2-bias',
            title: 'MEASURE 2: Bias and fairness metrics tracked',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Bias monitoring configuration found per MEASURE 2'
                : 'No bias-monitor.json -- AI bias/fairness metrics not tracked',
            evidence: exists ? biasFile : undefined,
        };
    }
    checkMEASURE3Monitoring() {
        const monitorFile = path.join(this.governanceDir, 'monitoring.json');
        const anomalyFile = path.join(this.governanceDir, 'anomaly-detection.json');
        const exists = fs.existsSync(monitorFile) || fs.existsSync(anomalyFile);
        return {
            id: 'nist-ai-rmf-measure3-monitoring',
            title: 'MEASURE 3: AI system performance monitored',
            status: exists ? 'pass' : 'fail',
            detail: exists
                ? 'Monitoring or anomaly detection configuration found per MEASURE 3'
                : 'No monitoring.json or anomaly-detection.json -- AI performance monitoring not configured',
            evidence: exists
                ? [monitorFile, anomalyFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkMEASURE4Feedback() {
        const feedbackFile = path.join(this.governanceDir, 'feedback-loop.json');
        const hasLogs = fs.existsSync(this.logDir) &&
            fs.readdirSync(this.logDir).some((f) => f.endsWith('.jsonl'));
        const exists = fs.existsSync(feedbackFile) || hasLogs;
        return {
            id: 'nist-ai-rmf-measure4-feedback',
            title: 'MEASURE 4: Feedback mechanisms for AI evaluation',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Feedback loop or audit trail found per MEASURE 4'
                : 'No feedback-loop.json -- feedback mechanisms for AI evaluation not documented',
            evidence: exists
                ? (fs.existsSync(feedbackFile) ? feedbackFile : this.logDir)
                : undefined,
        };
    }
    // --- MANAGE function ---
    checkMANAGE1Prioritization() {
        const riskFile = path.join(this.governanceDir, 'risk-assessment.json');
        const cbFile = path.join(this.governanceDir, 'circuit-breaker.json');
        const exists = fs.existsSync(riskFile) || fs.existsSync(cbFile);
        return {
            id: 'nist-ai-rmf-manage1-prioritization',
            title: 'MANAGE 1: AI risks prioritized and treated',
            status: exists ? 'pass' : 'fail',
            detail: exists
                ? 'Risk assessment or circuit breaker found per MANAGE 1'
                : 'No risk-assessment.json or circuit-breaker.json -- AI risk prioritization not configured',
            evidence: exists
                ? [riskFile, cbFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkMANAGE2Response() {
        const irFile = path.join(this.governanceDir, 'incident-response.json');
        const approvalFile = path.join(this.governanceDir, 'approval-queue.json');
        const exists = fs.existsSync(irFile) || fs.existsSync(approvalFile);
        return {
            id: 'nist-ai-rmf-manage2-response',
            title: 'MANAGE 2: AI incident response',
            status: exists ? 'pass' : 'fail',
            detail: exists
                ? 'Incident response or approval queue found per MANAGE 2'
                : 'No incident-response.json or approval-queue.json -- AI incident response not configured',
            evidence: exists
                ? [irFile, approvalFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkMANAGE3ThirdParty() {
        const vendorFile = path.join(this.governanceDir, 'vendor-registry.json');
        const exists = fs.existsSync(vendorFile);
        return {
            id: 'nist-ai-rmf-manage3-third-party',
            title: 'MANAGE 3: Third-party AI risk managed',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Vendor registry found per MANAGE 3'
                : 'No vendor-registry.json -- third-party AI risk not tracked',
            evidence: exists ? vendorFile : undefined,
        };
    }
    checkMANAGE4Monitoring() {
        const hasLogs = fs.existsSync(this.logDir) &&
            fs.readdirSync(this.logDir).some((f) => f.endsWith('.jsonl'));
        return {
            id: 'nist-ai-rmf-manage4-monitoring',
            title: 'MANAGE 4: AI risk response monitoring',
            status: hasLogs ? 'pass' : 'fail',
            detail: hasLogs
                ? 'Audit logs provide ongoing risk monitoring per MANAGE 4'
                : 'No JSONL audit logs -- post-deployment AI risk monitoring not evidenced',
            evidence: hasLogs ? this.logDir : undefined,
        };
    }
    // --- GenAI Profile (NIST AI 600-1) ---
    checkGenAIHallucinationControls() {
        const guardrailFile = path.join(this.governanceDir, 'content-guardrails.json');
        const ppFile = path.join(this.governanceDir, 'prohibited-practices.json');
        const exists = fs.existsSync(guardrailFile) || fs.existsSync(ppFile);
        return {
            id: 'nist-ai-600-1-hallucination',
            title: 'NIST AI 600-1: GenAI hallucination/confabulation controls',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Content guardrails or prohibited practices configuration found per NIST AI 600-1'
                : 'No content-guardrails.json or prohibited-practices.json -- GenAI hallucination controls not evidenced',
            evidence: exists
                ? [guardrailFile, ppFile].filter((f) => fs.existsSync(f)).join(', ')
                : undefined,
        };
    }
    checkGenAIDataGovernance() {
        const classifierFile = path.join(this.governanceDir, 'data-classifier.json');
        const exists = fs.existsSync(classifierFile);
        return {
            id: 'nist-ai-600-1-data-governance',
            title: 'NIST AI 600-1: GenAI training data governance',
            status: exists ? 'pass' : 'warning',
            detail: exists
                ? 'Data classifier found per NIST AI 600-1 data governance requirements'
                : 'No data-classifier.json -- GenAI training data governance not evidenced',
            evidence: exists ? classifierFile : undefined,
        };
    }
    // ---------------------------------------------------------------------------
    // Gap analysis
    // ---------------------------------------------------------------------------
    analyzeGaps(result) {
        return result.checks
            .filter((c) => c.status === 'fail' || c.status === 'warning')
            .map((c) => ({
            function: (c.id.includes('govern') ? 'GOVERN'
                : c.id.includes('map') ? 'MAP'
                    : c.id.includes('measure') ? 'MEASURE'
                        : 'MANAGE'),
            subcategory: c.id,
            title: c.title,
            detail: c.detail,
        }));
    }
    // ---------------------------------------------------------------------------
    // AI RMF Profile document generator
    // ---------------------------------------------------------------------------
    generateRMFProfile(result) {
        const gaps = this.analyzeGaps(result);
        const byFunction = {
            GOVERN: gaps.filter((g) => g.function === 'GOVERN').length,
            MAP: gaps.filter((g) => g.function === 'MAP').length,
            MEASURE: gaps.filter((g) => g.function === 'MEASURE').length,
            MANAGE: gaps.filter((g) => g.function === 'MANAGE').length,
        };
        return {
            document: 'AI RMF Profile',
            framework: 'NIST AI RMF 1.0 + NIST AI 600-1',
            generatedAt: new Date().toISOString(),
            overallScore: result.score,
            functionCoverage: {
                GOVERN: result.checks.filter((c) => c.id.includes('govern')).length,
                MAP: result.checks.filter((c) => c.id.includes('map')).length,
                MEASURE: result.checks.filter((c) => c.id.includes('measure')).length,
                MANAGE: result.checks.filter((c) => c.id.includes('manage')).length,
            },
            gapsByFunction: byFunction,
            narrative: this.narrativeWriter.write('RMF-PROFILE', `Score ${result.score}/100. Total gaps: ${gaps.length}. GOVERN: ${byFunction.GOVERN}, MAP: ${byFunction.MAP}, MEASURE: ${byFunction.MEASURE}, MANAGE: ${byFunction.MANAGE}.`),
        };
    }
    // ---------------------------------------------------------------------------
    // Report generation
    // ---------------------------------------------------------------------------
    generateReport(result, outputDir) {
        if (!fs.existsSync(outputDir))
            fs.mkdirSync(outputDir, { recursive: true });
        const rmfProfile = this.generateRMFProfile(result);
        const narrative = this.narrativeWriter.write('NIST-AI-RMF-1.0', `Score: ${result.score}/100. ${result.passed} controls passed, ${result.failed} failed.`);
        const report = {
            framework: 'NIST AI RMF 1.0 + NIST AI 600-1 (GenAI Profile)',
            generatedAt: new Date().toISOString(),
            auditId: result.auditId,
            score: result.score,
            passed: result.passed,
            failed: result.failed,
            warnings: result.warnings,
            narrative,
            rmfProfile,
            checks: result.checks,
        };
        const filename = `nist-ai-rmf-report-${Date.now()}.json`;
        const filePath = path.join(outputDir, filename);
        fs.writeFileSync(filePath, JSON.stringify(report, null, 2));
        return filePath;
    }
}
//# sourceMappingURL=nist-ai-rmf.js.map