monora-ai 2.1.0 → 2.1.4
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 +339 -158
- package/dist/aims_governance.d.ts +238 -0
- package/dist/aims_governance.d.ts.map +1 -0
- package/dist/aims_governance.js +922 -0
- package/dist/alerts.d.ts +16 -0
- package/dist/alerts.d.ts.map +1 -1
- package/dist/alerts.js +16 -0
- package/dist/api.d.ts +6 -0
- package/dist/api.d.ts.map +1 -1
- package/dist/api.js +6 -0
- package/dist/assessment.d.ts +85 -0
- package/dist/assessment.d.ts.map +1 -1
- package/dist/assessment.js +525 -13
- package/dist/attribution.d.ts +44 -3
- package/dist/attribution.d.ts.map +1 -1
- package/dist/attribution.js +197 -10
- package/dist/autodetect.d.ts +68 -0
- package/dist/autodetect.d.ts.map +1 -1
- package/dist/autodetect.js +639 -0
- package/dist/bias.d.ts +130 -0
- package/dist/bias.d.ts.map +1 -0
- package/dist/bias.js +223 -0
- package/dist/cli/diagnostics.d.ts +5 -1
- package/dist/cli/diagnostics.d.ts.map +1 -1
- package/dist/cli/diagnostics.js +23 -6
- package/dist/cli/doctor.d.ts +25 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +381 -0
- package/dist/cli/fix.d.ts +16 -0
- package/dist/cli/fix.d.ts.map +1 -0
- package/dist/cli/fix.js +284 -0
- package/dist/cli/init.d.ts +57 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +205 -0
- package/dist/cli.js +1564 -177
- package/dist/complianceConsolidation.d.ts +17 -0
- package/dist/complianceConsolidation.d.ts.map +1 -0
- package/dist/complianceConsolidation.js +68 -0
- package/dist/complianceTargets.d.ts +111 -0
- package/dist/complianceTargets.d.ts.map +1 -0
- package/dist/complianceTargets.js +521 -0
- package/dist/config.d.ts +261 -16
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +381 -32
- package/dist/config_migrations.d.ts.map +1 -1
- package/dist/config_migrations.js +38 -1
- package/dist/config_schema.d.ts +2490 -1035
- package/dist/config_schema.d.ts.map +1 -1
- package/dist/config_schema.js +233 -64
- package/dist/context.d.ts +34 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +118 -7
- package/dist/control_backbone.d.ts +128 -0
- package/dist/control_backbone.d.ts.map +1 -0
- package/dist/control_backbone.js +826 -0
- package/dist/data-governance.d.ts +187 -0
- package/dist/data-governance.d.ts.map +1 -0
- package/dist/data-governance.js +424 -0
- package/dist/dataResidency.d.ts +44 -0
- package/dist/dataResidency.d.ts.map +1 -0
- package/dist/dataResidency.js +203 -0
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/dispatcher.js +17 -5
- package/dist/evidence_store.d.ts +103 -0
- package/dist/evidence_store.d.ts.map +1 -0
- package/dist/evidence_store.js +459 -0
- package/dist/executiveSummary.d.ts +15 -0
- package/dist/executiveSummary.d.ts.map +1 -1
- package/dist/executiveSummary.js +135 -22
- package/dist/identity.d.ts +143 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +231 -0
- package/dist/impact-assessment.d.ts +350 -0
- package/dist/impact-assessment.d.ts.map +1 -0
- package/dist/impact-assessment.js +580 -0
- package/dist/index.d.ts +21 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +254 -5
- package/dist/instrumentation.d.ts +1 -1
- package/dist/instrumentation.d.ts.map +1 -1
- package/dist/instrumentation.js +123 -22
- package/dist/integrations/anthropic.d.ts +3 -0
- package/dist/integrations/anthropic.d.ts.map +1 -1
- package/dist/integrations/anthropic.js +282 -80
- package/dist/integrations/governance.d.ts +33 -0
- package/dist/integrations/governance.d.ts.map +1 -0
- package/dist/integrations/governance.js +208 -0
- package/dist/integrations/langchain.d.ts +4 -0
- package/dist/integrations/langchain.d.ts.map +1 -1
- package/dist/integrations/langchain.js +362 -142
- package/dist/integrations/openai.d.ts +9 -0
- package/dist/integrations/openai.d.ts.map +1 -1
- package/dist/integrations/openai.js +673 -73
- package/dist/iso42001_consolidation.d.ts +16 -0
- package/dist/iso42001_consolidation.d.ts.map +1 -0
- package/dist/iso42001_consolidation.js +413 -0
- package/dist/iso42001_workflows.d.ts +263 -0
- package/dist/iso42001_workflows.d.ts.map +1 -0
- package/dist/iso42001_workflows.js +781 -0
- package/dist/lifecycle.d.ts +299 -0
- package/dist/lifecycle.d.ts.map +1 -0
- package/dist/lifecycle.js +624 -0
- package/dist/lineage.d.ts +2 -2
- package/dist/lineage.d.ts.map +1 -1
- package/dist/lineage.js +9 -16
- package/dist/middleware/express.d.ts.map +1 -1
- package/dist/middleware/express.js +18 -3
- package/dist/middleware/nextjs.js +2 -2
- package/dist/model.d.ts +143 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/model.js +371 -0
- package/dist/onboarding.d.ts +42 -0
- package/dist/onboarding.d.ts.map +1 -0
- package/dist/onboarding.js +1075 -0
- package/dist/oversight.d.ts +264 -0
- package/dist/oversight.d.ts.map +1 -0
- package/dist/oversight.js +497 -0
- package/dist/presets.js +7 -7
- package/dist/quotas.d.ts +171 -0
- package/dist/quotas.d.ts.map +1 -0
- package/dist/quotas.js +259 -0
- package/dist/register.d.ts +13 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +99 -0
- package/dist/registry.d.ts +1 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +7 -0
- package/dist/registryData.json +43 -6
- package/dist/report.d.ts +2 -1
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +189 -2
- package/dist/reporting.d.ts +125 -0
- package/dist/reporting.d.ts.map +1 -1
- package/dist/reporting.js +192 -2
- package/dist/resources.d.ts +285 -0
- package/dist/resources.d.ts.map +1 -0
- package/dist/resources.js +643 -0
- package/dist/risk.d.ts +120 -0
- package/dist/risk.d.ts.map +1 -0
- package/dist/risk.js +220 -0
- package/dist/runtime.d.ts +74 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +416 -18
- package/dist/schemaInference.d.ts +92 -0
- package/dist/schemaInference.d.ts.map +1 -0
- package/dist/schemaInference.js +466 -0
- package/dist/schema_validation.js +2 -2
- package/dist/schemas/config.schema.json +118 -4
- package/dist/security_report.js +4 -4
- package/dist/signing.d.ts +1 -1
- package/dist/signing.d.ts.map +1 -1
- package/dist/signing.js +4 -0
- package/dist/sinks/file.d.ts +19 -1
- package/dist/sinks/file.d.ts.map +1 -1
- package/dist/sinks/file.js +82 -13
- package/dist/sinks/https.d.ts +10 -0
- package/dist/sinks/https.d.ts.map +1 -1
- package/dist/sinks/https.js +76 -16
- package/dist/sinks/stdout.d.ts +1 -0
- package/dist/sinks/stdout.d.ts.map +1 -1
- package/dist/sinks/stdout.js +12 -1
- package/dist/spec.d.ts +159 -0
- package/dist/spec.d.ts.map +1 -0
- package/dist/spec.js +391 -0
- package/dist/stakeholders.d.ts +199 -0
- package/dist/stakeholders.d.ts.map +1 -0
- package/dist/stakeholders.js +398 -0
- package/dist/standards.d.ts.map +1 -1
- package/dist/standards.js +160 -2
- package/dist/standards_ingest.d.ts.map +1 -1
- package/dist/standards_ingest.js +1 -4
- package/dist/telemetry.d.ts +16 -2
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +77 -14
- package/dist/templates/controls/gdpr_control_catalog.json +261 -0
- package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
- package/dist/templates/controls/soc2_control_catalog.json +163 -0
- package/dist/templates/standards/iso42001_claims.json +72 -0
- package/dist/traced_emitter.d.ts.map +1 -1
- package/dist/traced_emitter.js +19 -9
- package/dist/trust_package.d.ts +20 -1
- package/dist/trust_package.d.ts.map +1 -1
- package/dist/trust_package.js +90 -2
- package/dist/verify.d.ts.map +1 -1
- package/dist/verify.js +9 -2
- package/dist/wal.d.ts.map +1 -1
- package/dist/wal.js +2 -1
- package/package.json +14 -1
- package/scripts/postinstall.js +105 -210
- package/templates/controls/gdpr_control_catalog.json +261 -0
- package/templates/controls/iso42001_control_catalog.json +1443 -0
- package/templates/controls/soc2_control_catalog.json +163 -0
- package/templates/standards/iso42001_claims.json +72 -0
package/dist/assessment.js
CHANGED
|
@@ -56,14 +56,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
56
56
|
exports.runComplianceCheck = runComplianceCheck;
|
|
57
57
|
exports.reportUsageProfile = reportUsageProfile;
|
|
58
58
|
exports.onComplianceCheck = onComplianceCheck;
|
|
59
|
+
exports.generateRemediationPlan = generateRemediationPlan;
|
|
59
60
|
exports.generateAssessmentReport = generateAssessmentReport;
|
|
60
61
|
const fs = __importStar(require("fs"));
|
|
61
62
|
const path = __importStar(require("path"));
|
|
62
63
|
const attribution_1 = require("./attribution");
|
|
64
|
+
const complianceConsolidation_1 = require("./complianceConsolidation");
|
|
63
65
|
const config_1 = require("./config");
|
|
64
66
|
const verify_1 = require("./verify");
|
|
65
67
|
// Get version
|
|
66
|
-
let SDK_VERSION = '1.
|
|
68
|
+
let SDK_VERSION = '2.1.4';
|
|
67
69
|
try {
|
|
68
70
|
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
69
71
|
if (fs.existsSync(pkgPath)) {
|
|
@@ -479,6 +481,21 @@ function buildFrameworkChecks(config, frameworks) {
|
|
|
479
481
|
recommendations.push(recommendation);
|
|
480
482
|
}
|
|
481
483
|
};
|
|
484
|
+
const addCoverageChecks = (framework, checkPrefix, category) => {
|
|
485
|
+
let totalControls = 0;
|
|
486
|
+
let coveredControls = 0;
|
|
487
|
+
try {
|
|
488
|
+
const coverage = (0, complianceConsolidation_1.identifyFrameworkRemainingGaps)({ standard: framework });
|
|
489
|
+
const summary = (coverage.summary || {});
|
|
490
|
+
totalControls = Number(summary.total_controls || 0);
|
|
491
|
+
coveredControls = Number(summary.covered_controls || 0);
|
|
492
|
+
}
|
|
493
|
+
catch (error) {
|
|
494
|
+
warnings.push(`${framework}: control coverage check failed: ${error?.message || error}`);
|
|
495
|
+
}
|
|
496
|
+
addCheck(`${checkPrefix}_control_coverage_generated`, `${framework}: control coverage report can be generated`, totalControls > 0, category, `Ensure bundled ${framework} control catalog templates are available and readable`);
|
|
497
|
+
addCheck(`${checkPrefix}_reportable_controls_present`, `${framework}: at least one control is reportable with current evidence`, coveredControls > 0, category, `Collect and approve evidence for at least one ${framework} control to produce reportable coverage`);
|
|
498
|
+
};
|
|
482
499
|
if (frameworks.includes('SOC2')) {
|
|
483
500
|
addCheck('soc2_framework_declared', 'SOC 2: framework declared in audit metadata', complianceFrameworks.includes('SOC2'), 'governance', 'Add SOC2 to audit metadata compliance_frameworks');
|
|
484
501
|
addCheck('soc2_audit_metadata', 'SOC 2: audit metadata documents use case and owner', useCaseDocumented, 'governance', 'Set audit metadata with use_case_name and business_owner for SOC 2');
|
|
@@ -487,6 +504,7 @@ function buildFrameworkChecks(config, frameworks) {
|
|
|
487
504
|
addCheck('soc2_wal_enabled', 'SOC 2: write-ahead log enabled for resilience', Boolean(wal.enabled), 'reliability', 'Enable WAL to strengthen SOC 2 availability evidence');
|
|
488
505
|
addCheck('soc2_policy_enforcement', 'SOC 2: policy enforcement is enabled', Boolean(policies.enforce), 'governance', 'Enable policy enforcement for SOC 2 governance controls');
|
|
489
506
|
addCheck('soc2_incident_alerts', 'SOC 2: violation alert webhook configured', Boolean(alerts.violation_webhook), 'security', 'Configure alerts.violation_webhook for SOC 2 incident response');
|
|
507
|
+
addCoverageChecks('SOC2', 'soc2', 'auditability');
|
|
490
508
|
}
|
|
491
509
|
if (frameworks.includes('GDPR')) {
|
|
492
510
|
addCheck('gdpr_framework_declared', 'GDPR: framework declared in audit metadata', complianceFrameworks.includes('GDPR'), 'privacy', 'Add GDPR to audit metadata compliance_frameworks');
|
|
@@ -495,6 +513,7 @@ function buildFrameworkChecks(config, frameworks) {
|
|
|
495
513
|
addCheck('gdpr_data_categories_declared', 'GDPR: data categories are documented', dataCategoriesDeclared, 'privacy', 'Document data_categories in audit metadata for GDPR');
|
|
496
514
|
addCheck('gdpr_data_classification_set', 'GDPR: default data classification is set', dataClassificationSet, 'privacy', 'Set defaults.data_classification to document GDPR data handling scope');
|
|
497
515
|
addCheck('gdpr_review_documented', 'GDPR: compliance review metadata is documented', reviewDocumented, 'privacy', 'Record review_date or reviewer in audit metadata for GDPR');
|
|
516
|
+
addCoverageChecks('GDPR', 'gdpr', 'privacy');
|
|
498
517
|
}
|
|
499
518
|
if (frameworks.includes('ISO27001')) {
|
|
500
519
|
addCheck('iso27001_framework_declared', 'ISO 27001: framework declared in audit metadata', complianceFrameworks.includes('ISO27001'), 'security', 'Add ISO27001 to audit metadata compliance_frameworks');
|
|
@@ -509,6 +528,272 @@ function buildFrameworkChecks(config, frameworks) {
|
|
|
509
528
|
addCheck('iso42001_policy_enforcement', 'ISO 42001: policy enforcement is enabled', Boolean(policies.enforce), 'governance', 'Enable policy enforcement for ISO 42001 governance controls');
|
|
510
529
|
addCheck('iso42001_data_handling_enabled', 'ISO 42001: data handling/redaction is enabled', dataHandlingEnabled, 'privacy', 'Enable data_handling to support ISO 42001 risk controls');
|
|
511
530
|
addCheck('iso42001_review_documented', 'ISO 42001: compliance review metadata is documented', reviewDocumented, 'governance', 'Record review_date or reviewer in audit metadata for ISO 42001');
|
|
531
|
+
addCoverageChecks('ISO42001', 'iso42001', 'governance');
|
|
532
|
+
// A.5.x - Impact Assessment checks
|
|
533
|
+
const impactConfig = (config.impact_assessment || {});
|
|
534
|
+
const impactEnabled = Boolean(impactConfig.enabled);
|
|
535
|
+
addCheck('iso42001_impact_assessment_enabled', 'ISO 42001 A.5: Impact assessment module is enabled', impactEnabled, 'governance', 'Enable impact_assessment in config for ISO 42001 A.5.x compliance');
|
|
536
|
+
// Check for registered impact assessments
|
|
537
|
+
let hasImpactAssessments = false;
|
|
538
|
+
let hasApprovedAssessment = false;
|
|
539
|
+
try {
|
|
540
|
+
const { getRegistry: getImpactRegistry } = require('./impact-assessment');
|
|
541
|
+
const impactRegistry = getImpactRegistry();
|
|
542
|
+
const assessments = impactRegistry.listAssessments();
|
|
543
|
+
hasImpactAssessments = assessments.length > 0;
|
|
544
|
+
hasApprovedAssessment = assessments.some((a) => a.status === 'approved');
|
|
545
|
+
}
|
|
546
|
+
catch {
|
|
547
|
+
// Module not available
|
|
548
|
+
}
|
|
549
|
+
addCheck('iso42001_impact_assessment_registered', 'ISO 42001 A.5.2: At least one impact assessment is registered', hasImpactAssessments, 'governance', 'Create and register an AI impact assessment using createImpactAssessment()');
|
|
550
|
+
addCheck('iso42001_impact_assessment_approved', 'ISO 42001 A.5.3: At least one impact assessment is approved', hasApprovedAssessment, 'governance', 'Complete impact assessment approval workflow using finalizeAssessment()');
|
|
551
|
+
// A.6.x - Lifecycle checks
|
|
552
|
+
const lifecycleConfig = (config.lifecycle || {});
|
|
553
|
+
const lifecycleEnabled = Boolean(lifecycleConfig.enabled);
|
|
554
|
+
addCheck('iso42001_lifecycle_enabled', 'ISO 42001 A.6: Lifecycle management module is enabled', lifecycleEnabled, 'governance', 'Enable lifecycle in config for ISO 42001 A.6.x compliance');
|
|
555
|
+
// Check for registered system records
|
|
556
|
+
let hasSystemRecords = false;
|
|
557
|
+
let hasRequirements = false;
|
|
558
|
+
let hasVerification = false;
|
|
559
|
+
try {
|
|
560
|
+
const { getRegistry: getLifecycleRegistry } = require('./lifecycle');
|
|
561
|
+
const lifecycleRegistry = getLifecycleRegistry();
|
|
562
|
+
const systemRecords = lifecycleRegistry.listRecords();
|
|
563
|
+
hasSystemRecords = systemRecords.length > 0;
|
|
564
|
+
hasRequirements = systemRecords.some((r) => r.requirements && r.requirements.length > 0);
|
|
565
|
+
hasVerification = systemRecords.some((r) => r.verificationResults && r.verificationResults.length > 0);
|
|
566
|
+
}
|
|
567
|
+
catch {
|
|
568
|
+
// Module not available
|
|
569
|
+
}
|
|
570
|
+
addCheck('iso42001_system_record_registered', 'ISO 42001 A.6.1: At least one AI system record is registered', hasSystemRecords, 'governance', 'Create AI system record using createSystemRecord()');
|
|
571
|
+
addCheck('iso42001_requirements_defined', 'ISO 42001 A.6.2.2: System has defined requirements', hasRequirements, 'governance', 'Define system requirements using addRequirement()');
|
|
572
|
+
addCheck('iso42001_verification_recorded', 'ISO 42001 A.6.2.4: Verification results are recorded', hasVerification, 'governance', 'Record verification results using recordVerification()');
|
|
573
|
+
// A.7.x - Data Governance checks
|
|
574
|
+
const dataGovConfig = (config.data_governance || {});
|
|
575
|
+
const dataGovEnabled = Boolean(dataGovConfig.enabled);
|
|
576
|
+
addCheck('iso42001_data_governance_enabled', 'ISO 42001 A.7: Data governance module is enabled', dataGovEnabled, 'privacy', 'Enable data_governance in config for ISO 42001 A.7.x compliance');
|
|
577
|
+
// Check for registered datasets
|
|
578
|
+
let hasDatasets = false;
|
|
579
|
+
let hasQualityMetrics = false;
|
|
580
|
+
let hasBiasAssessment = false;
|
|
581
|
+
try {
|
|
582
|
+
const { getRegistry: getDataGovRegistry } = require('./data-governance');
|
|
583
|
+
const dataRegistry = getDataGovRegistry();
|
|
584
|
+
const datasets = dataRegistry.listRecords();
|
|
585
|
+
hasDatasets = datasets.length > 0;
|
|
586
|
+
hasQualityMetrics = datasets.some((d) => d.qualityMetrics !== undefined);
|
|
587
|
+
hasBiasAssessment = datasets.some((d) => d.biasAssessments && d.biasAssessments.length > 0);
|
|
588
|
+
}
|
|
589
|
+
catch {
|
|
590
|
+
// Module not available
|
|
591
|
+
}
|
|
592
|
+
addCheck('iso42001_dataset_registered', 'ISO 42001 A.7.2: At least one dataset is registered', hasDatasets, 'privacy', 'Register datasets using createDatasetRecord()');
|
|
593
|
+
addCheck('iso42001_data_quality_recorded', 'ISO 42001 A.7.4: Data quality metrics are recorded', hasQualityMetrics, 'privacy', 'Record data quality metrics using recordQualityMetrics()');
|
|
594
|
+
addCheck('iso42001_data_bias_assessed', 'ISO 42001 A.7.6: Dataset bias assessments are recorded', hasBiasAssessment, 'privacy', 'Record bias assessments using recordDatasetBiasAssessment()');
|
|
595
|
+
// A.8.x/A.10.x - Stakeholder checks
|
|
596
|
+
const stakeholdersConfig = (config.stakeholders || {});
|
|
597
|
+
const stakeholdersEnabled = Boolean(stakeholdersConfig.enabled);
|
|
598
|
+
addCheck('iso42001_stakeholders_enabled', 'ISO 42001 A.8/A.10: Stakeholder management module is enabled', stakeholdersEnabled, 'governance', 'Enable stakeholders in config for ISO 42001 A.8/A.10 compliance');
|
|
599
|
+
// Check for registered stakeholders/suppliers
|
|
600
|
+
let hasStakeholders = false;
|
|
601
|
+
let hasSuppliers = false;
|
|
602
|
+
let hasApprovedSuppliers = false;
|
|
603
|
+
try {
|
|
604
|
+
const { getRegistry: getStakeholderRegistry } = require('./stakeholders');
|
|
605
|
+
const stakeholderRegistry = getStakeholderRegistry();
|
|
606
|
+
const stakeholdersList = stakeholderRegistry.listStakeholders();
|
|
607
|
+
const suppliersList = stakeholderRegistry.listSuppliers();
|
|
608
|
+
hasStakeholders = stakeholdersList.length > 0;
|
|
609
|
+
hasSuppliers = suppliersList.length > 0;
|
|
610
|
+
hasApprovedSuppliers = suppliersList.some((s) => s.status === 'approved');
|
|
611
|
+
}
|
|
612
|
+
catch {
|
|
613
|
+
// Module not available
|
|
614
|
+
}
|
|
615
|
+
addCheck('iso42001_stakeholders_registered', 'ISO 42001 A.8.2: Stakeholders are registered', hasStakeholders, 'governance', 'Register stakeholders using registerStakeholder()');
|
|
616
|
+
addCheck('iso42001_suppliers_registered', 'ISO 42001 A.10.3: Suppliers are registered', hasSuppliers, 'governance', 'Register suppliers using registerSupplier()');
|
|
617
|
+
addCheck('iso42001_suppliers_approved', 'ISO 42001 A.10.3: Suppliers are assessed and approved', hasApprovedSuppliers, 'governance', 'Approve suppliers after assessment using updateSupplierStatus()');
|
|
618
|
+
// A.4.x/A.2.4 - Resource Inventory checks
|
|
619
|
+
const resourcesConfig = (config.resources || {});
|
|
620
|
+
const resourcesEnabled = Boolean(resourcesConfig.enabled);
|
|
621
|
+
addCheck('iso42001_resources_enabled', 'ISO 42001 A.4: Resource inventory module is enabled', resourcesEnabled, 'governance', 'Enable resources in config for ISO 42001 A.4.x compliance');
|
|
622
|
+
// Check for resource inventories and policy reviews
|
|
623
|
+
let hasInventories = false;
|
|
624
|
+
let hasTooling = false;
|
|
625
|
+
let hasPolicyReviews = false;
|
|
626
|
+
try {
|
|
627
|
+
const { getRegistry: getResourceRegistry } = require('./resources');
|
|
628
|
+
const resourceRegistry = getResourceRegistry();
|
|
629
|
+
const inventories = resourceRegistry.listInventories();
|
|
630
|
+
const policyReviews = resourceRegistry.listPolicyReviews();
|
|
631
|
+
hasInventories = inventories.length > 0;
|
|
632
|
+
hasTooling = inventories.some((i) => i.toolingResources && i.toolingResources.length > 0);
|
|
633
|
+
hasPolicyReviews = policyReviews.length > 0;
|
|
634
|
+
}
|
|
635
|
+
catch {
|
|
636
|
+
// Module not available
|
|
637
|
+
}
|
|
638
|
+
addCheck('iso42001_resource_inventory_exists', 'ISO 42001 A.4.2: Resource inventory exists', hasInventories, 'governance', 'Create resource inventory using createResourceInventory()');
|
|
639
|
+
addCheck('iso42001_tooling_resources_tracked', 'ISO 42001 A.4.4: Tooling resources are tracked', hasTooling, 'governance', 'Track tooling resources using addToolingResource()');
|
|
640
|
+
addCheck('iso42001_policy_reviews_scheduled', 'ISO 42001 A.2.4: Policy reviews are scheduled', hasPolicyReviews, 'governance', 'Schedule policy reviews using schedulePolicyReview()');
|
|
641
|
+
// ============================================================
|
|
642
|
+
// NEW ISO 42001 CHECKS - Phase 2 Gap Closure (39 checks)
|
|
643
|
+
// ============================================================
|
|
644
|
+
// Query ISO 42001 workflow records for checks
|
|
645
|
+
let workflowTypes = new Set();
|
|
646
|
+
try {
|
|
647
|
+
const { listWorkflowRecords } = require('./iso42001-workflows');
|
|
648
|
+
const workflowRecords = listWorkflowRecords();
|
|
649
|
+
workflowTypes = new Set(workflowRecords.map((r) => r.workflowType));
|
|
650
|
+
}
|
|
651
|
+
catch {
|
|
652
|
+
// Module not available
|
|
653
|
+
}
|
|
654
|
+
// ----------------------------------------------------------
|
|
655
|
+
// A.2 Policy & Governance (4 new checks)
|
|
656
|
+
// ----------------------------------------------------------
|
|
657
|
+
addCheck('iso42001_policy_alignment_recorded', 'ISO 42001 A.2.3: Policy alignment workflow is recorded', workflowTypes.has('policy_alignment'), 'governance', 'Record policy alignment using recordPolicyAlignment()');
|
|
658
|
+
const iso42001Config = (config.iso42001 || {});
|
|
659
|
+
const aimsContext = iso42001Config.aims_context || '';
|
|
660
|
+
addCheck('iso42001_aims_context_established', 'ISO 42001 A.2.2: AIMS context is established', Boolean(aimsContext), 'governance', 'Set iso42001.aims_context in config to document AIMS context');
|
|
661
|
+
const aimsScope = iso42001Config.aims_scope || '';
|
|
662
|
+
addCheck('iso42001_aims_scope_defined', 'ISO 42001 A.2: AIMS scope is defined', Boolean(aimsScope), 'governance', 'Set iso42001.aims_scope in config to define scope');
|
|
663
|
+
// Check for interested parties via stakeholders module
|
|
664
|
+
addCheck('iso42001_interested_parties_identified', 'ISO 42001 A.2: Interested parties are identified', hasStakeholders, 'governance', 'Register stakeholders using registerStakeholder()');
|
|
665
|
+
// ----------------------------------------------------------
|
|
666
|
+
// A.4 Resources (4 new checks)
|
|
667
|
+
// ----------------------------------------------------------
|
|
668
|
+
let hasHumanResources = false;
|
|
669
|
+
let hasComputeResources = false;
|
|
670
|
+
let hasDataResources = false;
|
|
671
|
+
try {
|
|
672
|
+
const { getRegistry: getResRegistry } = require('./resources');
|
|
673
|
+
const resReg = getResRegistry();
|
|
674
|
+
const allInventories = resReg.listInventories();
|
|
675
|
+
hasHumanResources = allInventories.some((i) => i.humanResources && i.humanResources.length > 0);
|
|
676
|
+
hasComputeResources = allInventories.some((i) => i.computeResources && i.computeResources.length > 0);
|
|
677
|
+
hasDataResources = allInventories.some((i) => i.metadata && i.metadata.data_resources);
|
|
678
|
+
}
|
|
679
|
+
catch {
|
|
680
|
+
// Module not available
|
|
681
|
+
}
|
|
682
|
+
addCheck('iso42001_human_resources_tracked', 'ISO 42001 A.4: Human resources are tracked', hasHumanResources, 'governance', 'Track human resources using addHumanResource()');
|
|
683
|
+
addCheck('iso42001_compute_resources_tracked', 'ISO 42001 A.4: Compute resources are tracked', hasComputeResources, 'governance', 'Track compute resources using addComputeResource()');
|
|
684
|
+
addCheck('iso42001_data_resources_tracked', 'ISO 42001 A.4: Data resources are documented', hasDataResources, 'governance', 'Document data resources in resource inventory metadata');
|
|
685
|
+
const hasCompetencyRecords = workflowTypes.has('resource_competency');
|
|
686
|
+
addCheck('iso42001_competency_training_documented', 'ISO 42001 A.4: Competency and training is documented', hasCompetencyRecords, 'governance', 'Record competency requirements using recordResourceCompetency()');
|
|
687
|
+
// ----------------------------------------------------------
|
|
688
|
+
// A.5 Impact Assessment (5 new checks)
|
|
689
|
+
// ----------------------------------------------------------
|
|
690
|
+
let hasCurrentAssessment = false;
|
|
691
|
+
let hasSocietalImpacts = false;
|
|
692
|
+
let hasIndividualImpacts = false;
|
|
693
|
+
let hasMitigations = false;
|
|
694
|
+
let hasRevalidation = false;
|
|
695
|
+
try {
|
|
696
|
+
const { getRegistry: getImpRegistry } = require('./impact-assessment');
|
|
697
|
+
const impReg = getImpRegistry();
|
|
698
|
+
const allAssessments = impReg.listAssessments();
|
|
699
|
+
const now = new Date().toISOString();
|
|
700
|
+
hasCurrentAssessment = allAssessments.some((a) => !a.validUntil || a.validUntil > now);
|
|
701
|
+
hasSocietalImpacts = allAssessments.some((a) => a.impacts && a.impacts.some((i) => i.impactType === 'societal'));
|
|
702
|
+
hasIndividualImpacts = allAssessments.some((a) => a.impacts && a.impacts.some((i) => i.impactType === 'individual'));
|
|
703
|
+
hasMitigations = allAssessments.some((a) => a.impacts && a.impacts.some((i) => i.mitigations && i.mitigations.length > 0));
|
|
704
|
+
hasRevalidation = allAssessments.some((a) => a.revalidationFrequency);
|
|
705
|
+
}
|
|
706
|
+
catch {
|
|
707
|
+
// Module not available
|
|
708
|
+
}
|
|
709
|
+
addCheck('iso42001_impact_assessment_current', 'ISO 42001 A.5.2: Impact assessment is current (not expired)', hasCurrentAssessment, 'governance', 'Ensure impact assessment validUntil is in the future');
|
|
710
|
+
addCheck('iso42001_societal_impacts_assessed', 'ISO 42001 A.5.5: Societal impacts are assessed', hasSocietalImpacts, 'governance', "Add societal impact records using addImpactRecord({impactType: 'societal'})");
|
|
711
|
+
addCheck('iso42001_individual_impacts_assessed', 'ISO 42001 A.5.4: Individual impacts are assessed', hasIndividualImpacts, 'governance', "Add individual impact records using addImpactRecord({impactType: 'individual'})");
|
|
712
|
+
addCheck('iso42001_impact_mitigations_documented', 'ISO 42001 A.5: Impact mitigations are documented', hasMitigations, 'governance', 'Document mitigations using addMitigation() on impact records');
|
|
713
|
+
addCheck('iso42001_impact_revalidation_scheduled', 'ISO 42001 A.5: Impact revalidation frequency is set', hasRevalidation, 'governance', 'Set revalidationFrequency on impact assessments');
|
|
714
|
+
// ----------------------------------------------------------
|
|
715
|
+
// A.6 Lifecycle (8 new checks)
|
|
716
|
+
// ----------------------------------------------------------
|
|
717
|
+
addCheck('iso42001_development_objectives_defined', 'ISO 42001 A.6.1.2: Development objectives are defined', workflowTypes.has('responsible_development_objectives'), 'governance', 'Record objectives using recordResponsibleDevelopmentObjectives()');
|
|
718
|
+
addCheck('iso42001_development_process_defined', 'ISO 42001 A.6.1.3: Development process is defined', workflowTypes.has('responsible_development_process'), 'governance', 'Record process using recordResponsibleDevelopmentProcess()');
|
|
719
|
+
// Check for design documents via lifecycle
|
|
720
|
+
let hasDesignDocs = false;
|
|
721
|
+
let hasValidation = false;
|
|
722
|
+
let hasDeploymentApproval = false;
|
|
723
|
+
let hasMonitoring = false;
|
|
724
|
+
try {
|
|
725
|
+
const { getRegistry: getLcRegistry } = require('./lifecycle');
|
|
726
|
+
const lcReg = getLcRegistry();
|
|
727
|
+
const lcRecords = lcReg.listRecords();
|
|
728
|
+
hasDesignDocs = lcRecords.some((r) => r.metadata && r.metadata.design_documents);
|
|
729
|
+
hasValidation = lcRecords.some((r) => r.validationResults && r.validationResults.length > 0);
|
|
730
|
+
hasDeploymentApproval = lcRecords.some((r) => (r.stage === 'staging' || r.stage === 'production') &&
|
|
731
|
+
r.metadata &&
|
|
732
|
+
r.metadata.deployment_approved);
|
|
733
|
+
hasMonitoring = lcRecords.some((r) => r.metadata && r.metadata.monitoring_configured);
|
|
734
|
+
}
|
|
735
|
+
catch {
|
|
736
|
+
// Module not available
|
|
737
|
+
}
|
|
738
|
+
addCheck('iso42001_design_documents_current', 'ISO 42001 A.6.2.1: Design documents are maintained', hasDesignDocs || workflowTypes.has('requirements_specification'), 'governance', 'Record requirements using recordRequirementsSpecification() or add design_documents to lifecycle metadata');
|
|
739
|
+
addCheck('iso42001_verification_validation_complete', 'ISO 42001 A.6.2.4: Verification and validation is complete', hasValidation || workflowTypes.has('verification_validation'), 'governance', 'Record V&V using recordVerificationValidation() or recordValidation()');
|
|
740
|
+
addCheck('iso42001_deployment_approval_documented', 'ISO 42001 A.6.2.5: Deployment approval is documented', hasDeploymentApproval || workflowTypes.has('deployment_plan'), 'governance', 'Record deployment approval using recordDeploymentPlan() or set deployment_approved in metadata');
|
|
741
|
+
addCheck('iso42001_operations_monitoring_active', 'ISO 42001 A.6.2.6: Operations monitoring is configured', hasMonitoring || workflowTypes.has('operations_monitoring'), 'governance', 'Record monitoring using recordOperationsMonitoring() or set monitoring_configured in metadata');
|
|
742
|
+
addCheck('iso42001_stakeholder_docs_communicated', 'ISO 42001 A.6.2.7: Stakeholder documentation is communicated', workflowTypes.has('stakeholder_documentation'), 'governance', 'Record documentation using recordStakeholderDocumentation()');
|
|
743
|
+
// Check hash chain for event logging integrity
|
|
744
|
+
const immutabilityConfig = (config.immutability || {});
|
|
745
|
+
const hashChainEnabled = Boolean(immutabilityConfig.enabled);
|
|
746
|
+
addCheck('iso42001_event_logging_integrity', 'ISO 42001 A.6.2.8: Event logging integrity controls are enabled', hashChainEnabled || workflowTypes.has('lifecycle_event_logging'), 'integrity', 'Enable immutability.enabled=true or recordLifecycleEventLogging()');
|
|
747
|
+
// ----------------------------------------------------------
|
|
748
|
+
// A.7 Data (5 new checks)
|
|
749
|
+
// ----------------------------------------------------------
|
|
750
|
+
addCheck('iso42001_data_sources_documented', 'ISO 42001 A.7.2: Data sources are documented', workflowTypes.has('data_acquisition'), 'privacy', 'Record data sources using recordDataAcquisition()');
|
|
751
|
+
// Check for consent basis in data governance
|
|
752
|
+
let hasConsentBasis = false;
|
|
753
|
+
let hasQualityDimensions = false;
|
|
754
|
+
let hasProvenance = false;
|
|
755
|
+
let hasPreparation = false;
|
|
756
|
+
try {
|
|
757
|
+
const { getRegistry: getDataReg } = require('./data-governance');
|
|
758
|
+
const dataReg = getDataReg();
|
|
759
|
+
const allDatasets = dataReg.listRecords();
|
|
760
|
+
hasConsentBasis = allDatasets.some((d) => d.metadata && (d.metadata.consent_basis || d.metadata.legal_basis));
|
|
761
|
+
hasQualityDimensions = allDatasets.some((d) => d.qualityMetrics);
|
|
762
|
+
hasProvenance = allDatasets.some((d) => d.provenance);
|
|
763
|
+
hasPreparation = allDatasets.some((d) => d.preparationSteps && d.preparationSteps.length > 0);
|
|
764
|
+
}
|
|
765
|
+
catch {
|
|
766
|
+
// Module not available
|
|
767
|
+
}
|
|
768
|
+
addCheck('iso42001_data_consent_basis_valid', 'ISO 42001 A.7.3: Data consent/legal basis is documented', hasConsentBasis || workflowTypes.has('data_acquisition'), 'privacy', 'Set consent_basis or legal_basis in dataset metadata');
|
|
769
|
+
addCheck('iso42001_data_quality_dimensions', 'ISO 42001 A.7.4: Data quality dimensions are defined', hasQualityDimensions || workflowTypes.has('data_quality'), 'privacy', 'Record quality metrics using recordQualityMetrics() or recordDataQuality()');
|
|
770
|
+
addCheck('iso42001_data_provenance_traceable', 'ISO 42001 A.7.5: Data provenance is traceable', hasProvenance || workflowTypes.has('data_provenance'), 'privacy', 'Record provenance using recordProvenance() or recordDataProvenance()');
|
|
771
|
+
addCheck('iso42001_data_preparation_documented', 'ISO 42001 A.7.6: Data preparation is documented', hasPreparation || workflowTypes.has('data_preparation'), 'privacy', 'Record preparation using recordPreparationStep() or recordDataPreparation()');
|
|
772
|
+
// ----------------------------------------------------------
|
|
773
|
+
// A.8 Transparency (4 new checks)
|
|
774
|
+
// ----------------------------------------------------------
|
|
775
|
+
addCheck('iso42001_transparency_channels', 'ISO 42001 A.8.2: Transparency disclosure channels are established', workflowTypes.has('transparency_disclosure'), 'transparency', 'Record transparency using recordTransparencyDisclosure()');
|
|
776
|
+
addCheck('iso42001_adverse_impact_process', 'ISO 42001 A.8.3: Adverse impact reporting process is defined', workflowTypes.has('adverse_impact_reporting'), 'transparency', 'Record process using recordAdverseImpactReporting()');
|
|
777
|
+
addCheck('iso42001_incident_escalation_defined', 'ISO 42001 A.8.4: Incident escalation plan is defined', workflowTypes.has('incident_communication'), 'transparency', 'Record plan using recordIncidentCommunication()');
|
|
778
|
+
addCheck('iso42001_regulatory_reporting_compliant', 'ISO 42001 A.8.5: Regulatory reporting obligations are tracked', workflowTypes.has('reporting_obligations'), 'transparency', 'Record obligations using recordReportingObligations()');
|
|
779
|
+
// ----------------------------------------------------------
|
|
780
|
+
// A.9 Responsible Use (3 new checks)
|
|
781
|
+
// ----------------------------------------------------------
|
|
782
|
+
addCheck('iso42001_use_process_documented', 'ISO 42001 A.9.2: Responsible use process is documented', workflowTypes.has('responsible_use_process'), 'governance', 'Record process using recordResponsibleUseProcess()');
|
|
783
|
+
addCheck('iso42001_use_objectives_measurable', 'ISO 42001 A.9.3: Responsible use objectives are measurable', workflowTypes.has('responsible_use_objectives'), 'governance', 'Record objectives using recordResponsibleUseObjectives()');
|
|
784
|
+
addCheck('iso42001_intended_use_defined', 'ISO 42001 A.9.4: Intended use statement is defined', workflowTypes.has('intended_use_statement'), 'governance', 'Record statement using recordIntendedUseStatement()');
|
|
785
|
+
// ----------------------------------------------------------
|
|
786
|
+
// A.10 Third-Party (3 new checks)
|
|
787
|
+
// ----------------------------------------------------------
|
|
788
|
+
addCheck('iso42001_responsibility_allocation', 'ISO 42001 A.10.1: Third-party responsibility allocation is clear', workflowTypes.has('third_party_responsibility'), 'governance', 'Record allocation using recordThirdPartyResponsibility()');
|
|
789
|
+
addCheck('iso42001_supplier_assessment_documented', 'ISO 42001 A.10.2: Supplier assessments are documented', workflowTypes.has('supplier_assurance'), 'governance', 'Record assessments using recordSupplierAssurance()');
|
|
790
|
+
addCheck('iso42001_customer_requirements_mapped', 'ISO 42001 A.10.3: Customer requirements are mapped', workflowTypes.has('customer_alignment'), 'governance', 'Record requirements using recordCustomerAlignment()');
|
|
791
|
+
// ----------------------------------------------------------
|
|
792
|
+
// Clause 9-10 Management (3 new checks)
|
|
793
|
+
// ----------------------------------------------------------
|
|
794
|
+
addCheck('iso42001_audit_findings_addressed', 'ISO 42001 Clause 9: Internal audit findings are addressed', workflowTypes.has('internal_audit'), 'governance', 'Record audits using recordInternalAudit()');
|
|
795
|
+
addCheck('iso42001_management_review_complete', 'ISO 42001 Clause 9: Management review is complete', workflowTypes.has('management_review'), 'governance', 'Record reviews using recordManagementReview()');
|
|
796
|
+
addCheck('iso42001_capa_effectiveness_verified', 'ISO 42001 Clause 10: Corrective action effectiveness is verified', workflowTypes.has('corrective_action'), 'governance', 'Record CAPA using recordCorrectiveAction()');
|
|
512
797
|
}
|
|
513
798
|
return { checks, warnings, recommendations };
|
|
514
799
|
}
|
|
@@ -520,10 +805,17 @@ function loadEvents(eventsPath) {
|
|
|
520
805
|
}
|
|
521
806
|
try {
|
|
522
807
|
const content = fs.readFileSync(eventsPath, 'utf8');
|
|
523
|
-
const events =
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
808
|
+
const events = [];
|
|
809
|
+
const lines = content.split('\n').filter((line) => line.trim());
|
|
810
|
+
lines.forEach((line, index) => {
|
|
811
|
+
try {
|
|
812
|
+
events.push(JSON.parse(line));
|
|
813
|
+
}
|
|
814
|
+
catch (err) {
|
|
815
|
+
const snippet = line.length > 120 ? `${line.slice(0, 120)}...` : line;
|
|
816
|
+
errors.push(`Failed to parse events line ${index + 1}: ${err} (${snippet})`);
|
|
817
|
+
}
|
|
818
|
+
});
|
|
527
819
|
return { events, errors };
|
|
528
820
|
}
|
|
529
821
|
catch (e) {
|
|
@@ -677,23 +969,243 @@ function onComplianceCheck(callback) {
|
|
|
677
969
|
};
|
|
678
970
|
}
|
|
679
971
|
/**
|
|
680
|
-
*
|
|
972
|
+
* Category priority weights for remediation ordering.
|
|
973
|
+
*/
|
|
974
|
+
const CATEGORY_PRIORITY = {
|
|
975
|
+
security: 100,
|
|
976
|
+
integrity: 90,
|
|
977
|
+
privacy: 85,
|
|
978
|
+
governance: 70,
|
|
979
|
+
auditability: 60,
|
|
980
|
+
reliability: 50,
|
|
981
|
+
completeness: 40,
|
|
982
|
+
};
|
|
983
|
+
/**
|
|
984
|
+
* Effort estimates based on check name patterns.
|
|
985
|
+
*/
|
|
986
|
+
const EFFORT_ESTIMATES = {
|
|
987
|
+
// Configuration changes - minimal effort
|
|
988
|
+
immutability_enabled: 'minimal',
|
|
989
|
+
verify_on_emit: 'minimal',
|
|
990
|
+
policies_enforce: 'minimal',
|
|
991
|
+
wal_enabled: 'minimal',
|
|
992
|
+
signing_enabled: 'low',
|
|
993
|
+
data_handling_enabled: 'minimal',
|
|
994
|
+
reporting_enabled: 'minimal',
|
|
995
|
+
// Metadata documentation - low effort
|
|
996
|
+
framework_declared: 'low',
|
|
997
|
+
audit_metadata: 'low',
|
|
998
|
+
use_case_documented: 'low',
|
|
999
|
+
review_documented: 'low',
|
|
1000
|
+
data_categories_declared: 'low',
|
|
1001
|
+
data_classification_set: 'low',
|
|
1002
|
+
// Infrastructure changes - medium/high effort
|
|
1003
|
+
logging_configured: 'medium',
|
|
1004
|
+
incident_alerts: 'medium',
|
|
1005
|
+
redaction_rules_configured: 'medium',
|
|
1006
|
+
};
|
|
1007
|
+
/**
|
|
1008
|
+
* Get effort estimate for a check.
|
|
1009
|
+
*/
|
|
1010
|
+
function getEffortEstimate(checkName) {
|
|
1011
|
+
for (const [pattern, effort] of Object.entries(EFFORT_ESTIMATES)) {
|
|
1012
|
+
if (checkName.includes(pattern)) {
|
|
1013
|
+
return effort;
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
return 'medium';
|
|
1017
|
+
}
|
|
1018
|
+
/**
|
|
1019
|
+
* Determine priority based on category and framework context.
|
|
1020
|
+
*/
|
|
1021
|
+
function determinePriority(category, frameworks, checkName) {
|
|
1022
|
+
const basePriority = CATEGORY_PRIORITY[category] || 50;
|
|
1023
|
+
// Boost priority for certain patterns
|
|
1024
|
+
let priorityScore = basePriority;
|
|
1025
|
+
// Security and integrity issues are always high priority
|
|
1026
|
+
if (category === 'security' || category === 'integrity') {
|
|
1027
|
+
priorityScore += 20;
|
|
1028
|
+
}
|
|
1029
|
+
// Framework-specific boosts
|
|
1030
|
+
if (frameworks.includes('SOC2') && (category === 'auditability' || category === 'integrity')) {
|
|
1031
|
+
priorityScore += 15;
|
|
1032
|
+
}
|
|
1033
|
+
if (frameworks.includes('GDPR') && category === 'privacy') {
|
|
1034
|
+
priorityScore += 20;
|
|
1035
|
+
}
|
|
1036
|
+
if (frameworks.includes('ISO27001') && category === 'security') {
|
|
1037
|
+
priorityScore += 15;
|
|
1038
|
+
}
|
|
1039
|
+
if (frameworks.includes('ISO42001') && category === 'governance') {
|
|
1040
|
+
priorityScore += 15;
|
|
1041
|
+
}
|
|
1042
|
+
// Chain integrity failures are critical
|
|
1043
|
+
if (checkName.includes('chain') && checkName.includes('valid')) {
|
|
1044
|
+
return 'critical';
|
|
1045
|
+
}
|
|
1046
|
+
// Signing for security frameworks
|
|
1047
|
+
if (checkName.includes('signing') && frameworks.includes('ISO27001')) {
|
|
1048
|
+
priorityScore += 10;
|
|
1049
|
+
}
|
|
1050
|
+
if (priorityScore >= 100)
|
|
1051
|
+
return 'critical';
|
|
1052
|
+
if (priorityScore >= 80)
|
|
1053
|
+
return 'high';
|
|
1054
|
+
if (priorityScore >= 50)
|
|
1055
|
+
return 'medium';
|
|
1056
|
+
return 'low';
|
|
1057
|
+
}
|
|
1058
|
+
/**
|
|
1059
|
+
* Extract framework prefix from check name.
|
|
1060
|
+
*/
|
|
1061
|
+
function extractFrameworkFromCheck(checkName) {
|
|
1062
|
+
const frameworks = [];
|
|
1063
|
+
if (checkName.startsWith('soc2_'))
|
|
1064
|
+
frameworks.push('SOC2');
|
|
1065
|
+
if (checkName.startsWith('gdpr_'))
|
|
1066
|
+
frameworks.push('GDPR');
|
|
1067
|
+
if (checkName.startsWith('iso27001_'))
|
|
1068
|
+
frameworks.push('ISO27001');
|
|
1069
|
+
if (checkName.startsWith('iso42001_'))
|
|
1070
|
+
frameworks.push('ISO42001');
|
|
1071
|
+
return frameworks;
|
|
1072
|
+
}
|
|
1073
|
+
/**
|
|
1074
|
+
* Generate a remediation plan from compliance check results.
|
|
681
1075
|
*
|
|
682
|
-
* This
|
|
683
|
-
*
|
|
1076
|
+
* This function analyzes failed compliance checks and generates an
|
|
1077
|
+
* actionable remediation plan with prioritized fixes.
|
|
684
1078
|
*
|
|
685
|
-
* @param
|
|
686
|
-
* @returns
|
|
1079
|
+
* @param result - Compliance check result from runComplianceCheck().
|
|
1080
|
+
* @returns RemediationPlan with prioritized fixes.
|
|
687
1081
|
*
|
|
688
1082
|
* @example
|
|
689
1083
|
* ```typescript
|
|
690
|
-
* const
|
|
691
|
-
* eventsPath: './monora_events.jsonl',
|
|
1084
|
+
* const checkResult = await runComplianceCheck({
|
|
692
1085
|
* configPath: './monora.yml',
|
|
693
|
-
*
|
|
1086
|
+
* frameworks: ['SOC2', 'GDPR'],
|
|
694
1087
|
* });
|
|
1088
|
+
*
|
|
1089
|
+
* const plan = generateRemediationPlan(checkResult);
|
|
1090
|
+
*
|
|
1091
|
+
* console.log(`Total issues: ${plan.summary.totalIssues}`);
|
|
1092
|
+
* console.log(`Critical: ${plan.summary.criticalCount}`);
|
|
1093
|
+
*
|
|
1094
|
+
* for (const issue of plan.orderedFixes) {
|
|
1095
|
+
* console.log(`[${issue.priority}] ${issue.title}: ${issue.fix}`);
|
|
1096
|
+
* }
|
|
695
1097
|
* ```
|
|
696
1098
|
*/
|
|
1099
|
+
function generateRemediationPlan(result) {
|
|
1100
|
+
const items = [];
|
|
1101
|
+
const frameworks = result.frameworksAssessed || [];
|
|
1102
|
+
// Process failed checks
|
|
1103
|
+
for (const check of result.checks) {
|
|
1104
|
+
if (check.passed)
|
|
1105
|
+
continue;
|
|
1106
|
+
const checkFrameworks = extractFrameworkFromCheck(check.name);
|
|
1107
|
+
const affectedFrameworks = checkFrameworks.length > 0 ? checkFrameworks : frameworks;
|
|
1108
|
+
// Find matching recommendation
|
|
1109
|
+
const recommendation = result.recommendations.find((rec) => rec.toLowerCase().includes(check.name.replace(/_/g, ' ').toLowerCase()) ||
|
|
1110
|
+
rec.toLowerCase().includes(check.description.toLowerCase().slice(0, 30)));
|
|
1111
|
+
const item = {
|
|
1112
|
+
id: check.name,
|
|
1113
|
+
title: check.description,
|
|
1114
|
+
description: `Compliance check "${check.name}" failed for category: ${check.category}`,
|
|
1115
|
+
category: check.category,
|
|
1116
|
+
priority: determinePriority(check.category, affectedFrameworks, check.name),
|
|
1117
|
+
effort: getEffortEstimate(check.name),
|
|
1118
|
+
fix: recommendation || `Enable or configure ${check.name.replace(/_/g, ' ')} in your monora.yml`,
|
|
1119
|
+
frameworks: affectedFrameworks,
|
|
1120
|
+
};
|
|
1121
|
+
items.push(item);
|
|
1122
|
+
}
|
|
1123
|
+
// Add items from errors (critical issues)
|
|
1124
|
+
for (const error of result.errors) {
|
|
1125
|
+
const item = {
|
|
1126
|
+
id: `error_${items.length}`,
|
|
1127
|
+
title: 'Critical Error',
|
|
1128
|
+
description: error,
|
|
1129
|
+
category: 'integrity',
|
|
1130
|
+
priority: 'critical',
|
|
1131
|
+
effort: 'high',
|
|
1132
|
+
fix: error.includes('chain')
|
|
1133
|
+
? 'Investigate hash chain integrity. Events may have been tampered with or corrupted.'
|
|
1134
|
+
: 'Address the error before proceeding with compliance certification.',
|
|
1135
|
+
frameworks,
|
|
1136
|
+
};
|
|
1137
|
+
items.push(item);
|
|
1138
|
+
}
|
|
1139
|
+
// Group by priority
|
|
1140
|
+
const issuesByPriority = {
|
|
1141
|
+
critical: items.filter((i) => i.priority === 'critical'),
|
|
1142
|
+
high: items.filter((i) => i.priority === 'high'),
|
|
1143
|
+
medium: items.filter((i) => i.priority === 'medium'),
|
|
1144
|
+
low: items.filter((i) => i.priority === 'low'),
|
|
1145
|
+
};
|
|
1146
|
+
// Group by category
|
|
1147
|
+
const issuesByCategory = {};
|
|
1148
|
+
for (const item of items) {
|
|
1149
|
+
if (!issuesByCategory[item.category]) {
|
|
1150
|
+
issuesByCategory[item.category] = [];
|
|
1151
|
+
}
|
|
1152
|
+
issuesByCategory[item.category].push(item);
|
|
1153
|
+
}
|
|
1154
|
+
// Order fixes: critical first, then by category priority, then by effort (easiest first within priority)
|
|
1155
|
+
const effortOrder = {
|
|
1156
|
+
minimal: 0,
|
|
1157
|
+
low: 1,
|
|
1158
|
+
medium: 2,
|
|
1159
|
+
high: 3,
|
|
1160
|
+
};
|
|
1161
|
+
const orderedFixes = [...items].sort((a, b) => {
|
|
1162
|
+
// First by priority
|
|
1163
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
1164
|
+
const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
1165
|
+
if (priorityDiff !== 0)
|
|
1166
|
+
return priorityDiff;
|
|
1167
|
+
// Then by category importance
|
|
1168
|
+
const categoryDiff = (CATEGORY_PRIORITY[b.category] || 50) - (CATEGORY_PRIORITY[a.category] || 50);
|
|
1169
|
+
if (categoryDiff !== 0)
|
|
1170
|
+
return categoryDiff;
|
|
1171
|
+
// Finally by effort (easier first)
|
|
1172
|
+
return effortOrder[a.effort] - effortOrder[b.effort];
|
|
1173
|
+
});
|
|
1174
|
+
// Calculate estimated total effort
|
|
1175
|
+
const effortCounts = { minimal: 0, low: 0, medium: 0, high: 0 };
|
|
1176
|
+
for (const item of items) {
|
|
1177
|
+
effortCounts[item.effort]++;
|
|
1178
|
+
}
|
|
1179
|
+
let estimatedEffort = 'None';
|
|
1180
|
+
if (items.length > 0) {
|
|
1181
|
+
if (effortCounts.high > 2 || items.length > 10) {
|
|
1182
|
+
estimatedEffort = 'Significant (multiple sessions)';
|
|
1183
|
+
}
|
|
1184
|
+
else if (effortCounts.high > 0 || effortCounts.medium > 3) {
|
|
1185
|
+
estimatedEffort = 'Moderate (few hours)';
|
|
1186
|
+
}
|
|
1187
|
+
else if (effortCounts.medium > 0 || effortCounts.low > 3) {
|
|
1188
|
+
estimatedEffort = 'Low (under an hour)';
|
|
1189
|
+
}
|
|
1190
|
+
else {
|
|
1191
|
+
estimatedEffort = 'Minimal (quick config changes)';
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
return {
|
|
1195
|
+
summary: {
|
|
1196
|
+
totalIssues: items.length,
|
|
1197
|
+
criticalCount: issuesByPriority.critical.length,
|
|
1198
|
+
highCount: issuesByPriority.high.length,
|
|
1199
|
+
mediumCount: issuesByPriority.medium.length,
|
|
1200
|
+
lowCount: issuesByPriority.low.length,
|
|
1201
|
+
estimatedEffort,
|
|
1202
|
+
},
|
|
1203
|
+
issuesByPriority,
|
|
1204
|
+
issuesByCategory,
|
|
1205
|
+
orderedFixes,
|
|
1206
|
+
generatedAt: new Date().toISOString(),
|
|
1207
|
+
};
|
|
1208
|
+
}
|
|
697
1209
|
async function generateAssessmentReport(options = {}) {
|
|
698
1210
|
// Run compliance check
|
|
699
1211
|
const checkResult = await runComplianceCheck({
|