monora-ai 2.0.0 → 2.1.3
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 +441 -150
- 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 +269 -0
- package/dist/assessment.d.ts.map +1 -0
- package/dist/assessment.js +1232 -0
- package/dist/attestation.js +23 -1
- package/dist/attribution.d.ts +349 -0
- package/dist/attribution.d.ts.map +1 -0
- package/dist/attribution.js +987 -0
- package/dist/autodetect.d.ts +69 -1
- package/dist/autodetect.d.ts.map +1 -1
- package/dist/autodetect.js +644 -1
- package/dist/bias.d.ts +130 -0
- package/dist/bias.d.ts.map +1 -0
- package/dist/bias.js +223 -0
- package/dist/circuit_breaker.js +3 -3
- package/dist/cli/diagnostics.d.ts +5 -1
- package/dist/cli/diagnostics.d.ts.map +1 -1
- package/dist/cli/diagnostics.js +31 -8
- 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 +1611 -126
- 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 +301 -17
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +428 -36
- package/dist/config_migrations.d.ts +41 -0
- package/dist/config_migrations.d.ts.map +1 -1
- package/dist/config_migrations.js +205 -0
- package/dist/config_schema.d.ts +2900 -731
- package/dist/config_schema.d.ts.map +1 -1
- package/dist/config_schema.js +257 -55
- 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 +122 -0
- package/dist/control_backbone.d.ts.map +1 -0
- package/dist/control_backbone.js +698 -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 +32 -0
- package/dist/dispatcher.d.ts.map +1 -1
- package/dist/dispatcher.js +91 -4
- package/dist/events.d.ts.map +1 -1
- package/dist/events.js +38 -0
- 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 +65 -8
- package/dist/executiveSummary.d.ts.map +1 -1
- package/dist/executiveSummary.js +289 -26
- 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 +25 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +300 -4
- package/dist/instrumentation.d.ts +1 -1
- package/dist/instrumentation.d.ts.map +1 -1
- package/dist/instrumentation.js +243 -27
- package/dist/integrations/anthropic.d.ts +3 -0
- package/dist/integrations/anthropic.d.ts.map +1 -1
- package/dist/integrations/anthropic.js +284 -79
- 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 +7 -0
- package/dist/integrations/langchain.d.ts.map +1 -1
- package/dist/integrations/langchain.js +387 -143
- 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 +12 -17
- package/dist/middleware/express.d.ts.map +1 -1
- package/dist/middleware/express.js +33 -3
- package/dist/middleware/nextjs.d.ts.map +1 -1
- package/dist/middleware/nextjs.js +42 -68
- 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 +1022 -0
- package/dist/oversight.d.ts +264 -0
- package/dist/oversight.d.ts.map +1 -0
- package/dist/oversight.js +497 -0
- package/dist/pdf_report.d.ts.map +1 -1
- package/dist/pdf_report.js +42 -21
- package/dist/presets.d.ts +88 -0
- package/dist/presets.d.ts.map +1 -0
- package/dist/presets.js +520 -0
- package/dist/propagation.d.ts.map +1 -1
- package/dist/propagation.js +34 -2
- 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 +196 -5
- 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 -1
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +598 -22
- 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 +169 -6
- package/dist/schemas/event.schema.json +4 -0
- 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 +2 -2
- package/dist/standards_ingest.d.ts.map +1 -1
- package/dist/standards_ingest.js +105 -23
- package/dist/streaming.d.ts.map +1 -1
- package/dist/streaming.js +7 -2
- package/dist/telemetry.d.ts +16 -2
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +79 -14
- package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
- package/dist/traced_emitter.d.ts +3 -0
- package/dist/traced_emitter.d.ts.map +1 -1
- package/dist/traced_emitter.js +142 -25
- package/dist/trust_package.d.ts +21 -1
- package/dist/trust_package.d.ts.map +1 -1
- package/dist/trust_package.js +101 -4
- 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 +119 -97
- package/templates/controls/iso42001_control_catalog.json +1443 -0
|
@@ -0,0 +1,1232 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Compliance assessment and certification support for Monora SDK.
|
|
4
|
+
*
|
|
5
|
+
* This module provides tools for running compliance checks and generating
|
|
6
|
+
* assessment reports for ISO 42001, SOC 2, GDPR, and other frameworks.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { runComplianceCheck, reportUsageProfile } from 'monora-ai';
|
|
11
|
+
*
|
|
12
|
+
* // Run compliance check before audit
|
|
13
|
+
* const result = await runComplianceCheck({
|
|
14
|
+
* eventsPath: './monora_events.jsonl',
|
|
15
|
+
* configPath: './monora.yml',
|
|
16
|
+
* });
|
|
17
|
+
*
|
|
18
|
+
* // Report usage profile
|
|
19
|
+
* const profile = reportUsageProfile();
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
22
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
23
|
+
if (k2 === undefined) k2 = k;
|
|
24
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
25
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
26
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
27
|
+
}
|
|
28
|
+
Object.defineProperty(o, k2, desc);
|
|
29
|
+
}) : (function(o, m, k, k2) {
|
|
30
|
+
if (k2 === undefined) k2 = k;
|
|
31
|
+
o[k2] = m[k];
|
|
32
|
+
}));
|
|
33
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
34
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
35
|
+
}) : function(o, v) {
|
|
36
|
+
o["default"] = v;
|
|
37
|
+
});
|
|
38
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
39
|
+
var ownKeys = function(o) {
|
|
40
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
41
|
+
var ar = [];
|
|
42
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
43
|
+
return ar;
|
|
44
|
+
};
|
|
45
|
+
return ownKeys(o);
|
|
46
|
+
};
|
|
47
|
+
return function (mod) {
|
|
48
|
+
if (mod && mod.__esModule) return mod;
|
|
49
|
+
var result = {};
|
|
50
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
51
|
+
__setModuleDefault(result, mod);
|
|
52
|
+
return result;
|
|
53
|
+
};
|
|
54
|
+
})();
|
|
55
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
56
|
+
exports.runComplianceCheck = runComplianceCheck;
|
|
57
|
+
exports.reportUsageProfile = reportUsageProfile;
|
|
58
|
+
exports.onComplianceCheck = onComplianceCheck;
|
|
59
|
+
exports.generateRemediationPlan = generateRemediationPlan;
|
|
60
|
+
exports.generateAssessmentReport = generateAssessmentReport;
|
|
61
|
+
const fs = __importStar(require("fs"));
|
|
62
|
+
const path = __importStar(require("path"));
|
|
63
|
+
const attribution_1 = require("./attribution");
|
|
64
|
+
const config_1 = require("./config");
|
|
65
|
+
const verify_1 = require("./verify");
|
|
66
|
+
// Get version
|
|
67
|
+
let SDK_VERSION = '2.1.3';
|
|
68
|
+
try {
|
|
69
|
+
const pkgPath = path.join(__dirname, '..', 'package.json');
|
|
70
|
+
if (fs.existsSync(pkgPath)) {
|
|
71
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
72
|
+
SDK_VERSION = pkg.version || SDK_VERSION;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// Use default version
|
|
77
|
+
}
|
|
78
|
+
// Callback registry
|
|
79
|
+
const checkCallbacks = [];
|
|
80
|
+
/**
|
|
81
|
+
* Run compliance checks for AI safety and governance.
|
|
82
|
+
*
|
|
83
|
+
* This function runs a series of checks to assess compliance with
|
|
84
|
+
* various frameworks like SOC 2, GDPR, ISO 27001, and ISO 42001.
|
|
85
|
+
*
|
|
86
|
+
* @param options - Check options.
|
|
87
|
+
* @returns ComplianceCheckResult with pass/fail status and details.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```typescript
|
|
91
|
+
* const result = await runComplianceCheck({
|
|
92
|
+
* eventsPath: './monora_events.jsonl',
|
|
93
|
+
* configPath: './monora.yml',
|
|
94
|
+
* frameworks: ['SOC2', 'ISO42001'],
|
|
95
|
+
* });
|
|
96
|
+
*
|
|
97
|
+
* if (result.passed) {
|
|
98
|
+
* console.log(`Compliance score: ${result.score}`);
|
|
99
|
+
* }
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
async function runComplianceCheck(options = {}) {
|
|
103
|
+
const checks = [];
|
|
104
|
+
const warnings = [];
|
|
105
|
+
const errors = [];
|
|
106
|
+
const recommendations = [];
|
|
107
|
+
// Load config if needed
|
|
108
|
+
let loadedConfig = options.config || {};
|
|
109
|
+
if (options.configPath) {
|
|
110
|
+
try {
|
|
111
|
+
loadedConfig = (0, config_1.loadConfig)({ configPath: options.configPath });
|
|
112
|
+
}
|
|
113
|
+
catch (e) {
|
|
114
|
+
errors.push(`Failed to load config: ${e}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// Determine frameworks to check
|
|
118
|
+
const frameworksToCheck = options.frameworks || ['SOC2', 'GDPR', 'ISO27001', 'ISO42001'];
|
|
119
|
+
const { normalizedFrameworks, unknownFrameworks } = normalizeFrameworks(frameworksToCheck);
|
|
120
|
+
for (const framework of unknownFrameworks) {
|
|
121
|
+
warnings.push(`Unknown compliance framework: ${framework}`);
|
|
122
|
+
}
|
|
123
|
+
// Run configuration checks
|
|
124
|
+
const configChecks = checkConfiguration(loadedConfig);
|
|
125
|
+
checks.push(...configChecks.checks);
|
|
126
|
+
warnings.push(...configChecks.warnings);
|
|
127
|
+
recommendations.push(...configChecks.recommendations);
|
|
128
|
+
let events = null;
|
|
129
|
+
// Run event log checks if path provided
|
|
130
|
+
if (options.eventsPath) {
|
|
131
|
+
const loadResult = loadEvents(options.eventsPath);
|
|
132
|
+
if (loadResult.errors.length > 0) {
|
|
133
|
+
errors.push(...loadResult.errors);
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
events = loadResult.events;
|
|
137
|
+
const eventChecks = await checkEvents(options.eventsPath, events);
|
|
138
|
+
checks.push(...eventChecks.checks);
|
|
139
|
+
warnings.push(...eventChecks.warnings);
|
|
140
|
+
errors.push(...eventChecks.errors);
|
|
141
|
+
recommendations.push(...eventChecks.recommendations);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
const frameworkChecks = buildFrameworkChecks(loadedConfig, normalizedFrameworks);
|
|
145
|
+
checks.push(...frameworkChecks.checks);
|
|
146
|
+
warnings.push(...frameworkChecks.warnings);
|
|
147
|
+
recommendations.push(...frameworkChecks.recommendations);
|
|
148
|
+
// Calculate score (framework-weighted)
|
|
149
|
+
const scoreResult = calculateWeightedScore(checks, normalizedFrameworks);
|
|
150
|
+
const score = scoreResult.score;
|
|
151
|
+
// Determine grade
|
|
152
|
+
let grade;
|
|
153
|
+
if (score >= 90)
|
|
154
|
+
grade = 'A';
|
|
155
|
+
else if (score >= 80)
|
|
156
|
+
grade = 'B';
|
|
157
|
+
else if (score >= 70)
|
|
158
|
+
grade = 'C';
|
|
159
|
+
else if (score >= 60)
|
|
160
|
+
grade = 'D';
|
|
161
|
+
else
|
|
162
|
+
grade = 'F';
|
|
163
|
+
// Determine pass/fail
|
|
164
|
+
const passed = score >= 70 && errors.length === 0;
|
|
165
|
+
const result = {
|
|
166
|
+
passed,
|
|
167
|
+
score,
|
|
168
|
+
grade,
|
|
169
|
+
scoreBreakdown: scoreResult.breakdown,
|
|
170
|
+
checks,
|
|
171
|
+
warnings,
|
|
172
|
+
errors,
|
|
173
|
+
recommendations,
|
|
174
|
+
frameworksAssessed: frameworksToCheck,
|
|
175
|
+
assessedAt: new Date().toISOString(),
|
|
176
|
+
sdkVersion: SDK_VERSION,
|
|
177
|
+
};
|
|
178
|
+
// Notify callbacks
|
|
179
|
+
for (const callback of checkCallbacks) {
|
|
180
|
+
try {
|
|
181
|
+
callback(result);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Ignore callback errors
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Check configuration for compliance requirements.
|
|
191
|
+
*/
|
|
192
|
+
function checkConfiguration(config) {
|
|
193
|
+
const checks = [];
|
|
194
|
+
const warnings = [];
|
|
195
|
+
const recommendations = [];
|
|
196
|
+
// Check immutability settings
|
|
197
|
+
const immutability = config.immutability || {};
|
|
198
|
+
checks.push({
|
|
199
|
+
name: 'immutability_enabled',
|
|
200
|
+
description: 'Hash chain immutability is enabled',
|
|
201
|
+
passed: immutability.enabled ?? false,
|
|
202
|
+
category: 'integrity',
|
|
203
|
+
});
|
|
204
|
+
if (immutability.enabled) {
|
|
205
|
+
checks.push({
|
|
206
|
+
name: 'verify_on_emit',
|
|
207
|
+
description: 'Hash verification on emit is enabled',
|
|
208
|
+
passed: immutability.verify_on_emit ?? false,
|
|
209
|
+
category: 'integrity',
|
|
210
|
+
});
|
|
211
|
+
if (!immutability.verify_on_emit) {
|
|
212
|
+
recommendations.push('Enable verify_on_emit for real-time integrity checks');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
// Check policy enforcement
|
|
216
|
+
const policies = config.policies || {};
|
|
217
|
+
checks.push({
|
|
218
|
+
name: 'policies_enforce',
|
|
219
|
+
description: 'Policy enforcement is enabled',
|
|
220
|
+
passed: policies.enforce ?? false,
|
|
221
|
+
category: 'governance',
|
|
222
|
+
});
|
|
223
|
+
// Check WAL settings
|
|
224
|
+
const wal = config.wal || {};
|
|
225
|
+
checks.push({
|
|
226
|
+
name: 'wal_enabled',
|
|
227
|
+
description: 'Write-ahead log is enabled for crash resilience',
|
|
228
|
+
passed: wal.enabled ?? false,
|
|
229
|
+
category: 'reliability',
|
|
230
|
+
});
|
|
231
|
+
if (!wal.enabled) {
|
|
232
|
+
recommendations.push('Enable WAL for crash resilience in production');
|
|
233
|
+
}
|
|
234
|
+
// Check signing settings
|
|
235
|
+
const signing = config.signing || {};
|
|
236
|
+
checks.push({
|
|
237
|
+
name: 'signing_enabled',
|
|
238
|
+
description: 'Event signing is enabled for non-repudiation',
|
|
239
|
+
passed: signing.enabled ?? false,
|
|
240
|
+
category: 'security',
|
|
241
|
+
});
|
|
242
|
+
if (!signing.enabled) {
|
|
243
|
+
recommendations.push('Consider enabling event signing for enterprise deployments');
|
|
244
|
+
}
|
|
245
|
+
// Check data handling
|
|
246
|
+
const dataHandling = config.data_handling || {};
|
|
247
|
+
checks.push({
|
|
248
|
+
name: 'data_handling_enabled',
|
|
249
|
+
description: 'Data handling/redaction rules are configured',
|
|
250
|
+
passed: dataHandling.enabled ?? false,
|
|
251
|
+
category: 'privacy',
|
|
252
|
+
});
|
|
253
|
+
// Check reporting
|
|
254
|
+
const reporting = config.reporting || {};
|
|
255
|
+
checks.push({
|
|
256
|
+
name: 'reporting_enabled',
|
|
257
|
+
description: 'Compliance reporting is enabled',
|
|
258
|
+
passed: reporting.enabled ?? true,
|
|
259
|
+
category: 'auditability',
|
|
260
|
+
});
|
|
261
|
+
return { checks, warnings, recommendations };
|
|
262
|
+
}
|
|
263
|
+
const KNOWN_FRAMEWORKS = new Set(['SOC2', 'GDPR', 'ISO27001', 'ISO42001']);
|
|
264
|
+
const DEFAULT_CATEGORY_WEIGHT = 1;
|
|
265
|
+
const CATEGORY_WEIGHTS = {
|
|
266
|
+
DEFAULT: {
|
|
267
|
+
integrity: 1,
|
|
268
|
+
governance: 1,
|
|
269
|
+
reliability: 1,
|
|
270
|
+
security: 1,
|
|
271
|
+
privacy: 1,
|
|
272
|
+
auditability: 1,
|
|
273
|
+
completeness: 1,
|
|
274
|
+
},
|
|
275
|
+
SOC2: {
|
|
276
|
+
integrity: 2.5,
|
|
277
|
+
governance: 1.5,
|
|
278
|
+
reliability: 1.5,
|
|
279
|
+
security: 2,
|
|
280
|
+
privacy: 0.75,
|
|
281
|
+
auditability: 2.5,
|
|
282
|
+
completeness: 1,
|
|
283
|
+
},
|
|
284
|
+
GDPR: {
|
|
285
|
+
integrity: 1,
|
|
286
|
+
governance: 1.5,
|
|
287
|
+
reliability: 1,
|
|
288
|
+
security: 1,
|
|
289
|
+
privacy: 3,
|
|
290
|
+
auditability: 1.5,
|
|
291
|
+
completeness: 1,
|
|
292
|
+
},
|
|
293
|
+
ISO27001: {
|
|
294
|
+
integrity: 2,
|
|
295
|
+
governance: 1,
|
|
296
|
+
reliability: 1.5,
|
|
297
|
+
security: 2.5,
|
|
298
|
+
privacy: 1,
|
|
299
|
+
auditability: 1.5,
|
|
300
|
+
completeness: 1,
|
|
301
|
+
},
|
|
302
|
+
ISO42001: {
|
|
303
|
+
integrity: 1.5,
|
|
304
|
+
governance: 2.5,
|
|
305
|
+
reliability: 1,
|
|
306
|
+
security: 1,
|
|
307
|
+
privacy: 1,
|
|
308
|
+
auditability: 2,
|
|
309
|
+
completeness: 1,
|
|
310
|
+
},
|
|
311
|
+
};
|
|
312
|
+
function normalizeFrameworkName(value) {
|
|
313
|
+
return String(value || '').replace(/[^a-zA-Z0-9]/g, '').toUpperCase();
|
|
314
|
+
}
|
|
315
|
+
function normalizeFrameworks(frameworks) {
|
|
316
|
+
const normalizedFrameworks = [];
|
|
317
|
+
const unknownFrameworks = [];
|
|
318
|
+
for (const framework of frameworks) {
|
|
319
|
+
const normalized = normalizeFrameworkName(framework);
|
|
320
|
+
if (!normalized) {
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (KNOWN_FRAMEWORKS.has(normalized)) {
|
|
324
|
+
if (!normalizedFrameworks.includes(normalized)) {
|
|
325
|
+
normalizedFrameworks.push(normalized);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
else {
|
|
329
|
+
unknownFrameworks.push(framework);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return { normalizedFrameworks, unknownFrameworks };
|
|
333
|
+
}
|
|
334
|
+
function normalizeFrameworkList(values) {
|
|
335
|
+
if (!Array.isArray(values)) {
|
|
336
|
+
return [];
|
|
337
|
+
}
|
|
338
|
+
const normalized = [];
|
|
339
|
+
for (const value of values) {
|
|
340
|
+
const norm = normalizeFrameworkName(value);
|
|
341
|
+
if (norm) {
|
|
342
|
+
normalized.push(norm);
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return normalized;
|
|
346
|
+
}
|
|
347
|
+
function combineCategoryWeights(frameworks) {
|
|
348
|
+
if (frameworks.length === 0) {
|
|
349
|
+
return { ...CATEGORY_WEIGHTS.DEFAULT };
|
|
350
|
+
}
|
|
351
|
+
const profiles = frameworks.map((framework) => CATEGORY_WEIGHTS[framework] || CATEGORY_WEIGHTS.DEFAULT);
|
|
352
|
+
const categories = Object.keys(CATEGORY_WEIGHTS.DEFAULT);
|
|
353
|
+
const combined = {};
|
|
354
|
+
for (const category of categories) {
|
|
355
|
+
const total = profiles.reduce((sum, profile) => sum + (profile[category] ?? DEFAULT_CATEGORY_WEIGHT), 0);
|
|
356
|
+
combined[category] = total / profiles.length;
|
|
357
|
+
}
|
|
358
|
+
return combined;
|
|
359
|
+
}
|
|
360
|
+
function calculateWeightedScore(checks, frameworks) {
|
|
361
|
+
const rawPassed = checks.filter((check) => check.passed).length;
|
|
362
|
+
const rawTotal = checks.length;
|
|
363
|
+
if (checks.length === 0) {
|
|
364
|
+
return {
|
|
365
|
+
score: 0,
|
|
366
|
+
breakdown: {
|
|
367
|
+
method: 'weighted_categories',
|
|
368
|
+
frameworks: frameworks.length > 0 ? frameworks : ['default'],
|
|
369
|
+
categoryWeights: { ...CATEGORY_WEIGHTS.DEFAULT },
|
|
370
|
+
categoryTotals: {},
|
|
371
|
+
categoryPassed: {},
|
|
372
|
+
weightedPassed: 0,
|
|
373
|
+
weightedTotal: 0,
|
|
374
|
+
rawPassed,
|
|
375
|
+
rawTotal,
|
|
376
|
+
},
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
const weights = combineCategoryWeights(frameworks);
|
|
380
|
+
const categoryWeights = { ...weights };
|
|
381
|
+
const categoryTotals = {};
|
|
382
|
+
const categoryPassed = {};
|
|
383
|
+
let weightedPassed = 0;
|
|
384
|
+
let weightedTotal = 0;
|
|
385
|
+
for (const check of checks) {
|
|
386
|
+
const category = String(check.category || 'uncategorized');
|
|
387
|
+
if (!(category in categoryWeights)) {
|
|
388
|
+
categoryWeights[category] = DEFAULT_CATEGORY_WEIGHT;
|
|
389
|
+
}
|
|
390
|
+
const weight = categoryWeights[category];
|
|
391
|
+
categoryTotals[category] = (categoryTotals[category] || 0) + 1;
|
|
392
|
+
weightedTotal += weight;
|
|
393
|
+
if (check.passed) {
|
|
394
|
+
categoryPassed[category] = (categoryPassed[category] || 0) + 1;
|
|
395
|
+
weightedPassed += weight;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
const score = weightedTotal > 0 ? Math.round((weightedPassed / weightedTotal) * 100) : 0;
|
|
399
|
+
return {
|
|
400
|
+
score,
|
|
401
|
+
breakdown: {
|
|
402
|
+
method: 'weighted_categories',
|
|
403
|
+
frameworks: frameworks.length > 0 ? frameworks : ['default'],
|
|
404
|
+
categoryWeights,
|
|
405
|
+
categoryTotals,
|
|
406
|
+
categoryPassed,
|
|
407
|
+
weightedPassed: Number(weightedPassed.toFixed(2)),
|
|
408
|
+
weightedTotal: Number(weightedTotal.toFixed(2)),
|
|
409
|
+
rawPassed,
|
|
410
|
+
rawTotal,
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function cleanPayload(payload) {
|
|
415
|
+
const cleaned = {};
|
|
416
|
+
for (const [key, value] of Object.entries(payload || {})) {
|
|
417
|
+
if (value === undefined || value === null) {
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (typeof value === 'string' && value.trim() === '') {
|
|
421
|
+
continue;
|
|
422
|
+
}
|
|
423
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
424
|
+
continue;
|
|
425
|
+
}
|
|
426
|
+
if (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
cleaned[key] = value;
|
|
430
|
+
}
|
|
431
|
+
return cleaned;
|
|
432
|
+
}
|
|
433
|
+
function resolveAuditMetadata(config) {
|
|
434
|
+
const auditFromState = (0, attribution_1.getAuditMetadata)();
|
|
435
|
+
const statePayload = auditFromState
|
|
436
|
+
? {
|
|
437
|
+
use_case_name: auditFromState.useCaseName,
|
|
438
|
+
business_owner: auditFromState.businessOwner,
|
|
439
|
+
data_categories: auditFromState.dataCategories,
|
|
440
|
+
risk_level: auditFromState.riskLevel,
|
|
441
|
+
compliance_frameworks: auditFromState.complianceFrameworks,
|
|
442
|
+
review_date: auditFromState.reviewDate,
|
|
443
|
+
reviewer: auditFromState.reviewer,
|
|
444
|
+
notes: auditFromState.notes,
|
|
445
|
+
}
|
|
446
|
+
: {};
|
|
447
|
+
const auditFromConfig = (config.audit || {});
|
|
448
|
+
return cleanPayload({ ...statePayload, ...auditFromConfig });
|
|
449
|
+
}
|
|
450
|
+
function buildFrameworkChecks(config, frameworks) {
|
|
451
|
+
const checks = [];
|
|
452
|
+
const warnings = [];
|
|
453
|
+
const recommendations = [];
|
|
454
|
+
if (!frameworks || frameworks.length === 0) {
|
|
455
|
+
return { checks, warnings, recommendations };
|
|
456
|
+
}
|
|
457
|
+
const auditMetadata = resolveAuditMetadata(config);
|
|
458
|
+
const complianceFrameworks = normalizeFrameworkList(auditMetadata.compliance_frameworks);
|
|
459
|
+
const useCaseDocumented = Boolean(auditMetadata.use_case_name && auditMetadata.business_owner);
|
|
460
|
+
const reviewDocumented = Boolean(auditMetadata.review_date || auditMetadata.reviewer);
|
|
461
|
+
const dataCategoriesDeclared = Boolean(auditMetadata.data_categories);
|
|
462
|
+
const defaults = config.defaults || {};
|
|
463
|
+
const immutability = config.immutability || {};
|
|
464
|
+
const policies = config.policies || {};
|
|
465
|
+
const wal = config.wal || {};
|
|
466
|
+
const signing = config.signing || {};
|
|
467
|
+
const reporting = config.reporting || {};
|
|
468
|
+
const dataHandling = config.data_handling || {};
|
|
469
|
+
const alerts = config.alerts || {};
|
|
470
|
+
const sinks = config.sinks || [];
|
|
471
|
+
const sinksConfigured = sinks.length > 0;
|
|
472
|
+
const reportingEnabled = reporting.enabled ?? true;
|
|
473
|
+
const loggingConfigured = Boolean(reportingEnabled && sinksConfigured);
|
|
474
|
+
const dataHandlingEnabled = Boolean(dataHandling.enabled);
|
|
475
|
+
const redactionRulesConfigured = Array.isArray(dataHandling.rules) && dataHandling.rules.length > 0;
|
|
476
|
+
const dataClassificationSet = Boolean(defaults.data_classification);
|
|
477
|
+
const addCheck = (name, description, passed, category, recommendation) => {
|
|
478
|
+
checks.push({ name, description, passed, category });
|
|
479
|
+
if (recommendation && !passed) {
|
|
480
|
+
recommendations.push(recommendation);
|
|
481
|
+
}
|
|
482
|
+
};
|
|
483
|
+
if (frameworks.includes('SOC2')) {
|
|
484
|
+
addCheck('soc2_framework_declared', 'SOC 2: framework declared in audit metadata', complianceFrameworks.includes('SOC2'), 'governance', 'Add SOC2 to audit metadata compliance_frameworks');
|
|
485
|
+
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');
|
|
486
|
+
addCheck('soc2_logging_configured', 'SOC 2: reporting and event sinks are configured', loggingConfigured, 'auditability', 'Enable reporting and configure at least one sink for SOC 2 audit trails');
|
|
487
|
+
addCheck('soc2_integrity_controls', 'SOC 2: hash chain immutability is enabled', Boolean(immutability.enabled), 'integrity', 'Enable immutability for SOC 2 integrity controls');
|
|
488
|
+
addCheck('soc2_wal_enabled', 'SOC 2: write-ahead log enabled for resilience', Boolean(wal.enabled), 'reliability', 'Enable WAL to strengthen SOC 2 availability evidence');
|
|
489
|
+
addCheck('soc2_policy_enforcement', 'SOC 2: policy enforcement is enabled', Boolean(policies.enforce), 'governance', 'Enable policy enforcement for SOC 2 governance controls');
|
|
490
|
+
addCheck('soc2_incident_alerts', 'SOC 2: violation alert webhook configured', Boolean(alerts.violation_webhook), 'security', 'Configure alerts.violation_webhook for SOC 2 incident response');
|
|
491
|
+
}
|
|
492
|
+
if (frameworks.includes('GDPR')) {
|
|
493
|
+
addCheck('gdpr_framework_declared', 'GDPR: framework declared in audit metadata', complianceFrameworks.includes('GDPR'), 'privacy', 'Add GDPR to audit metadata compliance_frameworks');
|
|
494
|
+
addCheck('gdpr_data_handling_enabled', 'GDPR: data handling/redaction is enabled', dataHandlingEnabled, 'privacy', 'Enable data_handling to support GDPR data minimization');
|
|
495
|
+
addCheck('gdpr_redaction_rules_configured', 'GDPR: redaction rules are configured', redactionRulesConfigured, 'privacy', 'Configure data_handling.rules to redact sensitive data for GDPR');
|
|
496
|
+
addCheck('gdpr_data_categories_declared', 'GDPR: data categories are documented', dataCategoriesDeclared, 'privacy', 'Document data_categories in audit metadata for GDPR');
|
|
497
|
+
addCheck('gdpr_data_classification_set', 'GDPR: default data classification is set', dataClassificationSet, 'privacy', 'Set defaults.data_classification to document GDPR data handling scope');
|
|
498
|
+
addCheck('gdpr_review_documented', 'GDPR: compliance review metadata is documented', reviewDocumented, 'privacy', 'Record review_date or reviewer in audit metadata for GDPR');
|
|
499
|
+
}
|
|
500
|
+
if (frameworks.includes('ISO27001')) {
|
|
501
|
+
addCheck('iso27001_framework_declared', 'ISO 27001: framework declared in audit metadata', complianceFrameworks.includes('ISO27001'), 'security', 'Add ISO27001 to audit metadata compliance_frameworks');
|
|
502
|
+
addCheck('iso27001_signing_enabled', 'ISO 27001: event signing is enabled', Boolean(signing.enabled), 'security', 'Enable signing to strengthen ISO 27001 non-repudiation');
|
|
503
|
+
addCheck('iso27001_immutability_enabled', 'ISO 27001: hash chain immutability is enabled', Boolean(immutability.enabled), 'integrity', 'Enable immutability for ISO 27001 integrity controls');
|
|
504
|
+
addCheck('iso27001_wal_enabled', 'ISO 27001: write-ahead log enabled for resilience', Boolean(wal.enabled), 'reliability', 'Enable WAL to strengthen ISO 27001 availability evidence');
|
|
505
|
+
addCheck('iso27001_logging_configured', 'ISO 27001: reporting and event sinks are configured', loggingConfigured, 'auditability', 'Enable reporting and configure sinks for ISO 27001 audit trails');
|
|
506
|
+
}
|
|
507
|
+
if (frameworks.includes('ISO42001')) {
|
|
508
|
+
addCheck('iso42001_framework_declared', 'ISO 42001: framework declared in audit metadata', complianceFrameworks.includes('ISO42001'), 'governance', 'Add ISO42001 to audit metadata compliance_frameworks');
|
|
509
|
+
addCheck('iso42001_use_case_documented', 'ISO 42001: use case and owner are documented', useCaseDocumented, 'governance', 'Document use_case_name and business_owner for ISO 42001');
|
|
510
|
+
addCheck('iso42001_policy_enforcement', 'ISO 42001: policy enforcement is enabled', Boolean(policies.enforce), 'governance', 'Enable policy enforcement for ISO 42001 governance controls');
|
|
511
|
+
addCheck('iso42001_data_handling_enabled', 'ISO 42001: data handling/redaction is enabled', dataHandlingEnabled, 'privacy', 'Enable data_handling to support ISO 42001 risk controls');
|
|
512
|
+
addCheck('iso42001_review_documented', 'ISO 42001: compliance review metadata is documented', reviewDocumented, 'governance', 'Record review_date or reviewer in audit metadata for ISO 42001');
|
|
513
|
+
// A.5.x - Impact Assessment checks
|
|
514
|
+
const impactConfig = (config.impact_assessment || {});
|
|
515
|
+
const impactEnabled = Boolean(impactConfig.enabled);
|
|
516
|
+
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');
|
|
517
|
+
// Check for registered impact assessments
|
|
518
|
+
let hasImpactAssessments = false;
|
|
519
|
+
let hasApprovedAssessment = false;
|
|
520
|
+
try {
|
|
521
|
+
const { getRegistry: getImpactRegistry } = require('./impact-assessment');
|
|
522
|
+
const impactRegistry = getImpactRegistry();
|
|
523
|
+
const assessments = impactRegistry.listAssessments();
|
|
524
|
+
hasImpactAssessments = assessments.length > 0;
|
|
525
|
+
hasApprovedAssessment = assessments.some((a) => a.status === 'approved');
|
|
526
|
+
}
|
|
527
|
+
catch {
|
|
528
|
+
// Module not available
|
|
529
|
+
}
|
|
530
|
+
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()');
|
|
531
|
+
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()');
|
|
532
|
+
// A.6.x - Lifecycle checks
|
|
533
|
+
const lifecycleConfig = (config.lifecycle || {});
|
|
534
|
+
const lifecycleEnabled = Boolean(lifecycleConfig.enabled);
|
|
535
|
+
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');
|
|
536
|
+
// Check for registered system records
|
|
537
|
+
let hasSystemRecords = false;
|
|
538
|
+
let hasRequirements = false;
|
|
539
|
+
let hasVerification = false;
|
|
540
|
+
try {
|
|
541
|
+
const { getRegistry: getLifecycleRegistry } = require('./lifecycle');
|
|
542
|
+
const lifecycleRegistry = getLifecycleRegistry();
|
|
543
|
+
const systemRecords = lifecycleRegistry.listRecords();
|
|
544
|
+
hasSystemRecords = systemRecords.length > 0;
|
|
545
|
+
hasRequirements = systemRecords.some((r) => r.requirements && r.requirements.length > 0);
|
|
546
|
+
hasVerification = systemRecords.some((r) => r.verificationResults && r.verificationResults.length > 0);
|
|
547
|
+
}
|
|
548
|
+
catch {
|
|
549
|
+
// Module not available
|
|
550
|
+
}
|
|
551
|
+
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()');
|
|
552
|
+
addCheck('iso42001_requirements_defined', 'ISO 42001 A.6.2.2: System has defined requirements', hasRequirements, 'governance', 'Define system requirements using addRequirement()');
|
|
553
|
+
addCheck('iso42001_verification_recorded', 'ISO 42001 A.6.2.4: Verification results are recorded', hasVerification, 'governance', 'Record verification results using recordVerification()');
|
|
554
|
+
// A.7.x - Data Governance checks
|
|
555
|
+
const dataGovConfig = (config.data_governance || {});
|
|
556
|
+
const dataGovEnabled = Boolean(dataGovConfig.enabled);
|
|
557
|
+
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');
|
|
558
|
+
// Check for registered datasets
|
|
559
|
+
let hasDatasets = false;
|
|
560
|
+
let hasQualityMetrics = false;
|
|
561
|
+
let hasBiasAssessment = false;
|
|
562
|
+
try {
|
|
563
|
+
const { getRegistry: getDataGovRegistry } = require('./data-governance');
|
|
564
|
+
const dataRegistry = getDataGovRegistry();
|
|
565
|
+
const datasets = dataRegistry.listRecords();
|
|
566
|
+
hasDatasets = datasets.length > 0;
|
|
567
|
+
hasQualityMetrics = datasets.some((d) => d.qualityMetrics !== undefined);
|
|
568
|
+
hasBiasAssessment = datasets.some((d) => d.biasAssessments && d.biasAssessments.length > 0);
|
|
569
|
+
}
|
|
570
|
+
catch {
|
|
571
|
+
// Module not available
|
|
572
|
+
}
|
|
573
|
+
addCheck('iso42001_dataset_registered', 'ISO 42001 A.7.2: At least one dataset is registered', hasDatasets, 'privacy', 'Register datasets using createDatasetRecord()');
|
|
574
|
+
addCheck('iso42001_data_quality_recorded', 'ISO 42001 A.7.4: Data quality metrics are recorded', hasQualityMetrics, 'privacy', 'Record data quality metrics using recordQualityMetrics()');
|
|
575
|
+
addCheck('iso42001_data_bias_assessed', 'ISO 42001 A.7.6: Dataset bias assessments are recorded', hasBiasAssessment, 'privacy', 'Record bias assessments using recordDatasetBiasAssessment()');
|
|
576
|
+
// A.8.x/A.10.x - Stakeholder checks
|
|
577
|
+
const stakeholdersConfig = (config.stakeholders || {});
|
|
578
|
+
const stakeholdersEnabled = Boolean(stakeholdersConfig.enabled);
|
|
579
|
+
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');
|
|
580
|
+
// Check for registered stakeholders/suppliers
|
|
581
|
+
let hasStakeholders = false;
|
|
582
|
+
let hasSuppliers = false;
|
|
583
|
+
let hasApprovedSuppliers = false;
|
|
584
|
+
try {
|
|
585
|
+
const { getRegistry: getStakeholderRegistry } = require('./stakeholders');
|
|
586
|
+
const stakeholderRegistry = getStakeholderRegistry();
|
|
587
|
+
const stakeholdersList = stakeholderRegistry.listStakeholders();
|
|
588
|
+
const suppliersList = stakeholderRegistry.listSuppliers();
|
|
589
|
+
hasStakeholders = stakeholdersList.length > 0;
|
|
590
|
+
hasSuppliers = suppliersList.length > 0;
|
|
591
|
+
hasApprovedSuppliers = suppliersList.some((s) => s.status === 'approved');
|
|
592
|
+
}
|
|
593
|
+
catch {
|
|
594
|
+
// Module not available
|
|
595
|
+
}
|
|
596
|
+
addCheck('iso42001_stakeholders_registered', 'ISO 42001 A.8.2: Stakeholders are registered', hasStakeholders, 'governance', 'Register stakeholders using registerStakeholder()');
|
|
597
|
+
addCheck('iso42001_suppliers_registered', 'ISO 42001 A.10.3: Suppliers are registered', hasSuppliers, 'governance', 'Register suppliers using registerSupplier()');
|
|
598
|
+
addCheck('iso42001_suppliers_approved', 'ISO 42001 A.10.3: Suppliers are assessed and approved', hasApprovedSuppliers, 'governance', 'Approve suppliers after assessment using updateSupplierStatus()');
|
|
599
|
+
// A.4.x/A.2.4 - Resource Inventory checks
|
|
600
|
+
const resourcesConfig = (config.resources || {});
|
|
601
|
+
const resourcesEnabled = Boolean(resourcesConfig.enabled);
|
|
602
|
+
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');
|
|
603
|
+
// Check for resource inventories and policy reviews
|
|
604
|
+
let hasInventories = false;
|
|
605
|
+
let hasTooling = false;
|
|
606
|
+
let hasPolicyReviews = false;
|
|
607
|
+
try {
|
|
608
|
+
const { getRegistry: getResourceRegistry } = require('./resources');
|
|
609
|
+
const resourceRegistry = getResourceRegistry();
|
|
610
|
+
const inventories = resourceRegistry.listInventories();
|
|
611
|
+
const policyReviews = resourceRegistry.listPolicyReviews();
|
|
612
|
+
hasInventories = inventories.length > 0;
|
|
613
|
+
hasTooling = inventories.some((i) => i.toolingResources && i.toolingResources.length > 0);
|
|
614
|
+
hasPolicyReviews = policyReviews.length > 0;
|
|
615
|
+
}
|
|
616
|
+
catch {
|
|
617
|
+
// Module not available
|
|
618
|
+
}
|
|
619
|
+
addCheck('iso42001_resource_inventory_exists', 'ISO 42001 A.4.2: Resource inventory exists', hasInventories, 'governance', 'Create resource inventory using createResourceInventory()');
|
|
620
|
+
addCheck('iso42001_tooling_resources_tracked', 'ISO 42001 A.4.4: Tooling resources are tracked', hasTooling, 'governance', 'Track tooling resources using addToolingResource()');
|
|
621
|
+
addCheck('iso42001_policy_reviews_scheduled', 'ISO 42001 A.2.4: Policy reviews are scheduled', hasPolicyReviews, 'governance', 'Schedule policy reviews using schedulePolicyReview()');
|
|
622
|
+
// ============================================================
|
|
623
|
+
// NEW ISO 42001 CHECKS - Phase 2 Gap Closure (39 checks)
|
|
624
|
+
// ============================================================
|
|
625
|
+
// Query ISO 42001 workflow records for checks
|
|
626
|
+
let workflowTypes = new Set();
|
|
627
|
+
try {
|
|
628
|
+
const { listWorkflowRecords } = require('./iso42001-workflows');
|
|
629
|
+
const workflowRecords = listWorkflowRecords();
|
|
630
|
+
workflowTypes = new Set(workflowRecords.map((r) => r.workflowType));
|
|
631
|
+
}
|
|
632
|
+
catch {
|
|
633
|
+
// Module not available
|
|
634
|
+
}
|
|
635
|
+
// ----------------------------------------------------------
|
|
636
|
+
// A.2 Policy & Governance (4 new checks)
|
|
637
|
+
// ----------------------------------------------------------
|
|
638
|
+
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()');
|
|
639
|
+
const iso42001Config = (config.iso42001 || {});
|
|
640
|
+
const aimsContext = iso42001Config.aims_context || '';
|
|
641
|
+
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');
|
|
642
|
+
const aimsScope = iso42001Config.aims_scope || '';
|
|
643
|
+
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');
|
|
644
|
+
// Check for interested parties via stakeholders module
|
|
645
|
+
addCheck('iso42001_interested_parties_identified', 'ISO 42001 A.2: Interested parties are identified', hasStakeholders, 'governance', 'Register stakeholders using registerStakeholder()');
|
|
646
|
+
// ----------------------------------------------------------
|
|
647
|
+
// A.4 Resources (4 new checks)
|
|
648
|
+
// ----------------------------------------------------------
|
|
649
|
+
let hasHumanResources = false;
|
|
650
|
+
let hasComputeResources = false;
|
|
651
|
+
let hasDataResources = false;
|
|
652
|
+
try {
|
|
653
|
+
const { getRegistry: getResRegistry } = require('./resources');
|
|
654
|
+
const resReg = getResRegistry();
|
|
655
|
+
const allInventories = resReg.listInventories();
|
|
656
|
+
hasHumanResources = allInventories.some((i) => i.humanResources && i.humanResources.length > 0);
|
|
657
|
+
hasComputeResources = allInventories.some((i) => i.computeResources && i.computeResources.length > 0);
|
|
658
|
+
hasDataResources = allInventories.some((i) => i.metadata && i.metadata.data_resources);
|
|
659
|
+
}
|
|
660
|
+
catch {
|
|
661
|
+
// Module not available
|
|
662
|
+
}
|
|
663
|
+
addCheck('iso42001_human_resources_tracked', 'ISO 42001 A.4: Human resources are tracked', hasHumanResources, 'governance', 'Track human resources using addHumanResource()');
|
|
664
|
+
addCheck('iso42001_compute_resources_tracked', 'ISO 42001 A.4: Compute resources are tracked', hasComputeResources, 'governance', 'Track compute resources using addComputeResource()');
|
|
665
|
+
addCheck('iso42001_data_resources_tracked', 'ISO 42001 A.4: Data resources are documented', hasDataResources, 'governance', 'Document data resources in resource inventory metadata');
|
|
666
|
+
const hasCompetencyRecords = workflowTypes.has('resource_competency');
|
|
667
|
+
addCheck('iso42001_competency_training_documented', 'ISO 42001 A.4: Competency and training is documented', hasCompetencyRecords, 'governance', 'Record competency requirements using recordResourceCompetency()');
|
|
668
|
+
// ----------------------------------------------------------
|
|
669
|
+
// A.5 Impact Assessment (5 new checks)
|
|
670
|
+
// ----------------------------------------------------------
|
|
671
|
+
let hasCurrentAssessment = false;
|
|
672
|
+
let hasSocietalImpacts = false;
|
|
673
|
+
let hasIndividualImpacts = false;
|
|
674
|
+
let hasMitigations = false;
|
|
675
|
+
let hasRevalidation = false;
|
|
676
|
+
try {
|
|
677
|
+
const { getRegistry: getImpRegistry } = require('./impact-assessment');
|
|
678
|
+
const impReg = getImpRegistry();
|
|
679
|
+
const allAssessments = impReg.listAssessments();
|
|
680
|
+
const now = new Date().toISOString();
|
|
681
|
+
hasCurrentAssessment = allAssessments.some((a) => !a.validUntil || a.validUntil > now);
|
|
682
|
+
hasSocietalImpacts = allAssessments.some((a) => a.impacts && a.impacts.some((i) => i.impactType === 'societal'));
|
|
683
|
+
hasIndividualImpacts = allAssessments.some((a) => a.impacts && a.impacts.some((i) => i.impactType === 'individual'));
|
|
684
|
+
hasMitigations = allAssessments.some((a) => a.impacts && a.impacts.some((i) => i.mitigations && i.mitigations.length > 0));
|
|
685
|
+
hasRevalidation = allAssessments.some((a) => a.revalidationFrequency);
|
|
686
|
+
}
|
|
687
|
+
catch {
|
|
688
|
+
// Module not available
|
|
689
|
+
}
|
|
690
|
+
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');
|
|
691
|
+
addCheck('iso42001_societal_impacts_assessed', 'ISO 42001 A.5.5: Societal impacts are assessed', hasSocietalImpacts, 'governance', "Add societal impact records using addImpactRecord({impactType: 'societal'})");
|
|
692
|
+
addCheck('iso42001_individual_impacts_assessed', 'ISO 42001 A.5.4: Individual impacts are assessed', hasIndividualImpacts, 'governance', "Add individual impact records using addImpactRecord({impactType: 'individual'})");
|
|
693
|
+
addCheck('iso42001_impact_mitigations_documented', 'ISO 42001 A.5: Impact mitigations are documented', hasMitigations, 'governance', 'Document mitigations using addMitigation() on impact records');
|
|
694
|
+
addCheck('iso42001_impact_revalidation_scheduled', 'ISO 42001 A.5: Impact revalidation frequency is set', hasRevalidation, 'governance', 'Set revalidationFrequency on impact assessments');
|
|
695
|
+
// ----------------------------------------------------------
|
|
696
|
+
// A.6 Lifecycle (8 new checks)
|
|
697
|
+
// ----------------------------------------------------------
|
|
698
|
+
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()');
|
|
699
|
+
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()');
|
|
700
|
+
// Check for design documents via lifecycle
|
|
701
|
+
let hasDesignDocs = false;
|
|
702
|
+
let hasValidation = false;
|
|
703
|
+
let hasDeploymentApproval = false;
|
|
704
|
+
let hasMonitoring = false;
|
|
705
|
+
try {
|
|
706
|
+
const { getRegistry: getLcRegistry } = require('./lifecycle');
|
|
707
|
+
const lcReg = getLcRegistry();
|
|
708
|
+
const lcRecords = lcReg.listRecords();
|
|
709
|
+
hasDesignDocs = lcRecords.some((r) => r.metadata && r.metadata.design_documents);
|
|
710
|
+
hasValidation = lcRecords.some((r) => r.validationResults && r.validationResults.length > 0);
|
|
711
|
+
hasDeploymentApproval = lcRecords.some((r) => (r.stage === 'staging' || r.stage === 'production') &&
|
|
712
|
+
r.metadata &&
|
|
713
|
+
r.metadata.deployment_approved);
|
|
714
|
+
hasMonitoring = lcRecords.some((r) => r.metadata && r.metadata.monitoring_configured);
|
|
715
|
+
}
|
|
716
|
+
catch {
|
|
717
|
+
// Module not available
|
|
718
|
+
}
|
|
719
|
+
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');
|
|
720
|
+
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()');
|
|
721
|
+
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');
|
|
722
|
+
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');
|
|
723
|
+
addCheck('iso42001_stakeholder_docs_communicated', 'ISO 42001 A.6.2.7: Stakeholder documentation is communicated', workflowTypes.has('stakeholder_documentation'), 'governance', 'Record documentation using recordStakeholderDocumentation()');
|
|
724
|
+
// Check hash chain for event logging integrity
|
|
725
|
+
const immutabilityConfig = (config.immutability || {});
|
|
726
|
+
const hashChainEnabled = Boolean(immutabilityConfig.enabled);
|
|
727
|
+
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()');
|
|
728
|
+
// ----------------------------------------------------------
|
|
729
|
+
// A.7 Data (5 new checks)
|
|
730
|
+
// ----------------------------------------------------------
|
|
731
|
+
addCheck('iso42001_data_sources_documented', 'ISO 42001 A.7.2: Data sources are documented', workflowTypes.has('data_acquisition'), 'privacy', 'Record data sources using recordDataAcquisition()');
|
|
732
|
+
// Check for consent basis in data governance
|
|
733
|
+
let hasConsentBasis = false;
|
|
734
|
+
let hasQualityDimensions = false;
|
|
735
|
+
let hasProvenance = false;
|
|
736
|
+
let hasPreparation = false;
|
|
737
|
+
try {
|
|
738
|
+
const { getRegistry: getDataReg } = require('./data-governance');
|
|
739
|
+
const dataReg = getDataReg();
|
|
740
|
+
const allDatasets = dataReg.listRecords();
|
|
741
|
+
hasConsentBasis = allDatasets.some((d) => d.metadata && (d.metadata.consent_basis || d.metadata.legal_basis));
|
|
742
|
+
hasQualityDimensions = allDatasets.some((d) => d.qualityMetrics);
|
|
743
|
+
hasProvenance = allDatasets.some((d) => d.provenance);
|
|
744
|
+
hasPreparation = allDatasets.some((d) => d.preparationSteps && d.preparationSteps.length > 0);
|
|
745
|
+
}
|
|
746
|
+
catch {
|
|
747
|
+
// Module not available
|
|
748
|
+
}
|
|
749
|
+
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');
|
|
750
|
+
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()');
|
|
751
|
+
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()');
|
|
752
|
+
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()');
|
|
753
|
+
// ----------------------------------------------------------
|
|
754
|
+
// A.8 Transparency (4 new checks)
|
|
755
|
+
// ----------------------------------------------------------
|
|
756
|
+
addCheck('iso42001_transparency_channels', 'ISO 42001 A.8.2: Transparency disclosure channels are established', workflowTypes.has('transparency_disclosure'), 'transparency', 'Record transparency using recordTransparencyDisclosure()');
|
|
757
|
+
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()');
|
|
758
|
+
addCheck('iso42001_incident_escalation_defined', 'ISO 42001 A.8.4: Incident escalation plan is defined', workflowTypes.has('incident_communication'), 'transparency', 'Record plan using recordIncidentCommunication()');
|
|
759
|
+
addCheck('iso42001_regulatory_reporting_compliant', 'ISO 42001 A.8.5: Regulatory reporting obligations are tracked', workflowTypes.has('reporting_obligations'), 'transparency', 'Record obligations using recordReportingObligations()');
|
|
760
|
+
// ----------------------------------------------------------
|
|
761
|
+
// A.9 Responsible Use (3 new checks)
|
|
762
|
+
// ----------------------------------------------------------
|
|
763
|
+
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()');
|
|
764
|
+
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()');
|
|
765
|
+
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()');
|
|
766
|
+
// ----------------------------------------------------------
|
|
767
|
+
// A.10 Third-Party (3 new checks)
|
|
768
|
+
// ----------------------------------------------------------
|
|
769
|
+
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()');
|
|
770
|
+
addCheck('iso42001_supplier_assessment_documented', 'ISO 42001 A.10.2: Supplier assessments are documented', workflowTypes.has('supplier_assurance'), 'governance', 'Record assessments using recordSupplierAssurance()');
|
|
771
|
+
addCheck('iso42001_customer_requirements_mapped', 'ISO 42001 A.10.3: Customer requirements are mapped', workflowTypes.has('customer_alignment'), 'governance', 'Record requirements using recordCustomerAlignment()');
|
|
772
|
+
// ----------------------------------------------------------
|
|
773
|
+
// Clause 9-10 Management (3 new checks)
|
|
774
|
+
// ----------------------------------------------------------
|
|
775
|
+
addCheck('iso42001_audit_findings_addressed', 'ISO 42001 Clause 9: Internal audit findings are addressed', workflowTypes.has('internal_audit'), 'governance', 'Record audits using recordInternalAudit()');
|
|
776
|
+
addCheck('iso42001_management_review_complete', 'ISO 42001 Clause 9: Management review is complete', workflowTypes.has('management_review'), 'governance', 'Record reviews using recordManagementReview()');
|
|
777
|
+
addCheck('iso42001_capa_effectiveness_verified', 'ISO 42001 Clause 10: Corrective action effectiveness is verified', workflowTypes.has('corrective_action'), 'governance', 'Record CAPA using recordCorrectiveAction()');
|
|
778
|
+
}
|
|
779
|
+
return { checks, warnings, recommendations };
|
|
780
|
+
}
|
|
781
|
+
function loadEvents(eventsPath) {
|
|
782
|
+
const errors = [];
|
|
783
|
+
if (!fs.existsSync(eventsPath)) {
|
|
784
|
+
errors.push(`Events file not found: ${eventsPath}`);
|
|
785
|
+
return { events: [], errors };
|
|
786
|
+
}
|
|
787
|
+
try {
|
|
788
|
+
const content = fs.readFileSync(eventsPath, 'utf8');
|
|
789
|
+
const events = [];
|
|
790
|
+
const lines = content.split('\n').filter((line) => line.trim());
|
|
791
|
+
lines.forEach((line, index) => {
|
|
792
|
+
try {
|
|
793
|
+
events.push(JSON.parse(line));
|
|
794
|
+
}
|
|
795
|
+
catch (err) {
|
|
796
|
+
const snippet = line.length > 120 ? `${line.slice(0, 120)}...` : line;
|
|
797
|
+
errors.push(`Failed to parse events line ${index + 1}: ${err} (${snippet})`);
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
return { events, errors };
|
|
801
|
+
}
|
|
802
|
+
catch (e) {
|
|
803
|
+
errors.push(`Failed to parse events file: ${e}`);
|
|
804
|
+
return { events: [], errors };
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
/**
|
|
808
|
+
* Check event log for compliance requirements.
|
|
809
|
+
*/
|
|
810
|
+
async function checkEvents(eventsPath, events) {
|
|
811
|
+
const checks = [];
|
|
812
|
+
const warnings = [];
|
|
813
|
+
const errors = [];
|
|
814
|
+
const recommendations = [];
|
|
815
|
+
if (!events) {
|
|
816
|
+
const loadResult = loadEvents(eventsPath);
|
|
817
|
+
events = loadResult.events;
|
|
818
|
+
errors.push(...loadResult.errors);
|
|
819
|
+
}
|
|
820
|
+
if (errors.length > 0) {
|
|
821
|
+
return { checks, warnings, errors, recommendations };
|
|
822
|
+
}
|
|
823
|
+
// Check we have events
|
|
824
|
+
checks.push({
|
|
825
|
+
name: 'events_exist',
|
|
826
|
+
description: 'Event log contains events',
|
|
827
|
+
passed: events.length > 0,
|
|
828
|
+
category: 'auditability',
|
|
829
|
+
});
|
|
830
|
+
if (events.length > 0) {
|
|
831
|
+
// Check hash chain integrity
|
|
832
|
+
const [chainValid] = (0, verify_1.verifyChain)(events);
|
|
833
|
+
checks.push({
|
|
834
|
+
name: 'hash_chain_valid',
|
|
835
|
+
description: 'Hash chain integrity is verified',
|
|
836
|
+
passed: chainValid,
|
|
837
|
+
category: 'integrity',
|
|
838
|
+
});
|
|
839
|
+
if (!chainValid) {
|
|
840
|
+
errors.push('Hash chain integrity check failed - possible tampering');
|
|
841
|
+
}
|
|
842
|
+
// Check for signatures
|
|
843
|
+
const signedEvents = events.filter((e) => e.event_signature);
|
|
844
|
+
checks.push({
|
|
845
|
+
name: 'events_signed',
|
|
846
|
+
description: 'Events are signed',
|
|
847
|
+
passed: signedEvents.length === events.length,
|
|
848
|
+
category: 'security',
|
|
849
|
+
});
|
|
850
|
+
// Check for sequence gaps
|
|
851
|
+
const gaps = (0, verify_1.detectSequenceGaps)(events);
|
|
852
|
+
checks.push({
|
|
853
|
+
name: 'no_sequence_gaps',
|
|
854
|
+
description: 'No sequence gaps detected',
|
|
855
|
+
passed: gaps.length === 0,
|
|
856
|
+
category: 'completeness',
|
|
857
|
+
});
|
|
858
|
+
if (gaps.length > 0) {
|
|
859
|
+
warnings.push(`Detected ${gaps.length} sequence gaps in event log`);
|
|
860
|
+
}
|
|
861
|
+
// Check for policy violations
|
|
862
|
+
const violations = events.filter((e) => e.event_type === 'policy_violation');
|
|
863
|
+
checks.push({
|
|
864
|
+
name: 'no_violations',
|
|
865
|
+
description: 'No unresolved policy violations',
|
|
866
|
+
passed: violations.length === 0,
|
|
867
|
+
category: 'governance',
|
|
868
|
+
});
|
|
869
|
+
if (violations.length > 0) {
|
|
870
|
+
warnings.push(`Found ${violations.length} policy violations in event log`);
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
return { checks, warnings, errors, recommendations };
|
|
874
|
+
}
|
|
875
|
+
/**
|
|
876
|
+
* Report current usage profile for certification/assessment.
|
|
877
|
+
*
|
|
878
|
+
* This generates a summary of SDK usage that can be used for
|
|
879
|
+
* certification processes like ISO 42001.
|
|
880
|
+
*
|
|
881
|
+
* @param options - Profile options.
|
|
882
|
+
* @returns UsageProfile object.
|
|
883
|
+
*
|
|
884
|
+
* @example
|
|
885
|
+
* ```typescript
|
|
886
|
+
* const profile = reportUsageProfile();
|
|
887
|
+
* console.log(profile.featuresUsed);
|
|
888
|
+
* ```
|
|
889
|
+
*/
|
|
890
|
+
function reportUsageProfile(options = {}) {
|
|
891
|
+
const { config, environment } = options;
|
|
892
|
+
// Get features from config
|
|
893
|
+
const featuresEnabled = [];
|
|
894
|
+
const configSummary = {};
|
|
895
|
+
if (config) {
|
|
896
|
+
if (config.immutability?.enabled)
|
|
897
|
+
featuresEnabled.push('immutability');
|
|
898
|
+
if (config.policies?.enforce)
|
|
899
|
+
featuresEnabled.push('policy_enforcement');
|
|
900
|
+
if (config.wal?.enabled)
|
|
901
|
+
featuresEnabled.push('wal');
|
|
902
|
+
if (config.signing?.enabled)
|
|
903
|
+
featuresEnabled.push('signing');
|
|
904
|
+
if (config.data_handling?.enabled)
|
|
905
|
+
featuresEnabled.push('data_handling');
|
|
906
|
+
if (config.reporting?.enabled)
|
|
907
|
+
featuresEnabled.push('reporting');
|
|
908
|
+
if (config.telemetry?.enabled)
|
|
909
|
+
featuresEnabled.push('telemetry');
|
|
910
|
+
configSummary.environment = config.defaults?.environment ?? 'unknown';
|
|
911
|
+
configSummary.dataClassification = config.defaults?.data_classification ?? 'unknown';
|
|
912
|
+
configSummary.sinksCount = config.sinks?.length ?? 0;
|
|
913
|
+
}
|
|
914
|
+
// Get audit metadata and registration
|
|
915
|
+
const auditMeta = (0, attribution_1.getAuditMetadata)();
|
|
916
|
+
const reg = (0, attribution_1.getRegistration)();
|
|
917
|
+
return {
|
|
918
|
+
sdkVersion: SDK_VERSION,
|
|
919
|
+
featuresEnabled,
|
|
920
|
+
featuresUsed: (0, attribution_1.getFeaturesUsed)(),
|
|
921
|
+
configSummary,
|
|
922
|
+
auditMetadata: auditMeta ?? undefined,
|
|
923
|
+
registration: reg ?? undefined,
|
|
924
|
+
environment: environment ?? configSummary.environment ?? 'unknown',
|
|
925
|
+
generatedAt: new Date().toISOString(),
|
|
926
|
+
};
|
|
927
|
+
}
|
|
928
|
+
/**
|
|
929
|
+
* Register a callback for compliance check events.
|
|
930
|
+
*
|
|
931
|
+
* @param callback - Function called with check result.
|
|
932
|
+
* @returns Unsubscribe function.
|
|
933
|
+
*
|
|
934
|
+
* @example
|
|
935
|
+
* ```typescript
|
|
936
|
+
* const unsubscribe = onComplianceCheck((result) => {
|
|
937
|
+
* if (!result.passed) {
|
|
938
|
+
* sendAlert('Compliance check failed!');
|
|
939
|
+
* }
|
|
940
|
+
* });
|
|
941
|
+
* ```
|
|
942
|
+
*/
|
|
943
|
+
function onComplianceCheck(callback) {
|
|
944
|
+
checkCallbacks.push(callback);
|
|
945
|
+
return () => {
|
|
946
|
+
const index = checkCallbacks.indexOf(callback);
|
|
947
|
+
if (index !== -1) {
|
|
948
|
+
checkCallbacks.splice(index, 1);
|
|
949
|
+
}
|
|
950
|
+
};
|
|
951
|
+
}
|
|
952
|
+
/**
|
|
953
|
+
* Category priority weights for remediation ordering.
|
|
954
|
+
*/
|
|
955
|
+
const CATEGORY_PRIORITY = {
|
|
956
|
+
security: 100,
|
|
957
|
+
integrity: 90,
|
|
958
|
+
privacy: 85,
|
|
959
|
+
governance: 70,
|
|
960
|
+
auditability: 60,
|
|
961
|
+
reliability: 50,
|
|
962
|
+
completeness: 40,
|
|
963
|
+
};
|
|
964
|
+
/**
|
|
965
|
+
* Effort estimates based on check name patterns.
|
|
966
|
+
*/
|
|
967
|
+
const EFFORT_ESTIMATES = {
|
|
968
|
+
// Configuration changes - minimal effort
|
|
969
|
+
immutability_enabled: 'minimal',
|
|
970
|
+
verify_on_emit: 'minimal',
|
|
971
|
+
policies_enforce: 'minimal',
|
|
972
|
+
wal_enabled: 'minimal',
|
|
973
|
+
signing_enabled: 'low',
|
|
974
|
+
data_handling_enabled: 'minimal',
|
|
975
|
+
reporting_enabled: 'minimal',
|
|
976
|
+
// Metadata documentation - low effort
|
|
977
|
+
framework_declared: 'low',
|
|
978
|
+
audit_metadata: 'low',
|
|
979
|
+
use_case_documented: 'low',
|
|
980
|
+
review_documented: 'low',
|
|
981
|
+
data_categories_declared: 'low',
|
|
982
|
+
data_classification_set: 'low',
|
|
983
|
+
// Infrastructure changes - medium/high effort
|
|
984
|
+
logging_configured: 'medium',
|
|
985
|
+
incident_alerts: 'medium',
|
|
986
|
+
redaction_rules_configured: 'medium',
|
|
987
|
+
};
|
|
988
|
+
/**
|
|
989
|
+
* Get effort estimate for a check.
|
|
990
|
+
*/
|
|
991
|
+
function getEffortEstimate(checkName) {
|
|
992
|
+
for (const [pattern, effort] of Object.entries(EFFORT_ESTIMATES)) {
|
|
993
|
+
if (checkName.includes(pattern)) {
|
|
994
|
+
return effort;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return 'medium';
|
|
998
|
+
}
|
|
999
|
+
/**
|
|
1000
|
+
* Determine priority based on category and framework context.
|
|
1001
|
+
*/
|
|
1002
|
+
function determinePriority(category, frameworks, checkName) {
|
|
1003
|
+
const basePriority = CATEGORY_PRIORITY[category] || 50;
|
|
1004
|
+
// Boost priority for certain patterns
|
|
1005
|
+
let priorityScore = basePriority;
|
|
1006
|
+
// Security and integrity issues are always high priority
|
|
1007
|
+
if (category === 'security' || category === 'integrity') {
|
|
1008
|
+
priorityScore += 20;
|
|
1009
|
+
}
|
|
1010
|
+
// Framework-specific boosts
|
|
1011
|
+
if (frameworks.includes('SOC2') && (category === 'auditability' || category === 'integrity')) {
|
|
1012
|
+
priorityScore += 15;
|
|
1013
|
+
}
|
|
1014
|
+
if (frameworks.includes('GDPR') && category === 'privacy') {
|
|
1015
|
+
priorityScore += 20;
|
|
1016
|
+
}
|
|
1017
|
+
if (frameworks.includes('ISO27001') && category === 'security') {
|
|
1018
|
+
priorityScore += 15;
|
|
1019
|
+
}
|
|
1020
|
+
if (frameworks.includes('ISO42001') && category === 'governance') {
|
|
1021
|
+
priorityScore += 15;
|
|
1022
|
+
}
|
|
1023
|
+
// Chain integrity failures are critical
|
|
1024
|
+
if (checkName.includes('chain') && checkName.includes('valid')) {
|
|
1025
|
+
return 'critical';
|
|
1026
|
+
}
|
|
1027
|
+
// Signing for security frameworks
|
|
1028
|
+
if (checkName.includes('signing') && frameworks.includes('ISO27001')) {
|
|
1029
|
+
priorityScore += 10;
|
|
1030
|
+
}
|
|
1031
|
+
if (priorityScore >= 100)
|
|
1032
|
+
return 'critical';
|
|
1033
|
+
if (priorityScore >= 80)
|
|
1034
|
+
return 'high';
|
|
1035
|
+
if (priorityScore >= 50)
|
|
1036
|
+
return 'medium';
|
|
1037
|
+
return 'low';
|
|
1038
|
+
}
|
|
1039
|
+
/**
|
|
1040
|
+
* Extract framework prefix from check name.
|
|
1041
|
+
*/
|
|
1042
|
+
function extractFrameworkFromCheck(checkName) {
|
|
1043
|
+
const frameworks = [];
|
|
1044
|
+
if (checkName.startsWith('soc2_'))
|
|
1045
|
+
frameworks.push('SOC2');
|
|
1046
|
+
if (checkName.startsWith('gdpr_'))
|
|
1047
|
+
frameworks.push('GDPR');
|
|
1048
|
+
if (checkName.startsWith('iso27001_'))
|
|
1049
|
+
frameworks.push('ISO27001');
|
|
1050
|
+
if (checkName.startsWith('iso42001_'))
|
|
1051
|
+
frameworks.push('ISO42001');
|
|
1052
|
+
return frameworks;
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Generate a remediation plan from compliance check results.
|
|
1056
|
+
*
|
|
1057
|
+
* This function analyzes failed compliance checks and generates an
|
|
1058
|
+
* actionable remediation plan with prioritized fixes.
|
|
1059
|
+
*
|
|
1060
|
+
* @param result - Compliance check result from runComplianceCheck().
|
|
1061
|
+
* @returns RemediationPlan with prioritized fixes.
|
|
1062
|
+
*
|
|
1063
|
+
* @example
|
|
1064
|
+
* ```typescript
|
|
1065
|
+
* const checkResult = await runComplianceCheck({
|
|
1066
|
+
* configPath: './monora.yml',
|
|
1067
|
+
* frameworks: ['SOC2', 'GDPR'],
|
|
1068
|
+
* });
|
|
1069
|
+
*
|
|
1070
|
+
* const plan = generateRemediationPlan(checkResult);
|
|
1071
|
+
*
|
|
1072
|
+
* console.log(`Total issues: ${plan.summary.totalIssues}`);
|
|
1073
|
+
* console.log(`Critical: ${plan.summary.criticalCount}`);
|
|
1074
|
+
*
|
|
1075
|
+
* for (const issue of plan.orderedFixes) {
|
|
1076
|
+
* console.log(`[${issue.priority}] ${issue.title}: ${issue.fix}`);
|
|
1077
|
+
* }
|
|
1078
|
+
* ```
|
|
1079
|
+
*/
|
|
1080
|
+
function generateRemediationPlan(result) {
|
|
1081
|
+
const items = [];
|
|
1082
|
+
const frameworks = result.frameworksAssessed || [];
|
|
1083
|
+
// Process failed checks
|
|
1084
|
+
for (const check of result.checks) {
|
|
1085
|
+
if (check.passed)
|
|
1086
|
+
continue;
|
|
1087
|
+
const checkFrameworks = extractFrameworkFromCheck(check.name);
|
|
1088
|
+
const affectedFrameworks = checkFrameworks.length > 0 ? checkFrameworks : frameworks;
|
|
1089
|
+
// Find matching recommendation
|
|
1090
|
+
const recommendation = result.recommendations.find((rec) => rec.toLowerCase().includes(check.name.replace(/_/g, ' ').toLowerCase()) ||
|
|
1091
|
+
rec.toLowerCase().includes(check.description.toLowerCase().slice(0, 30)));
|
|
1092
|
+
const item = {
|
|
1093
|
+
id: check.name,
|
|
1094
|
+
title: check.description,
|
|
1095
|
+
description: `Compliance check "${check.name}" failed for category: ${check.category}`,
|
|
1096
|
+
category: check.category,
|
|
1097
|
+
priority: determinePriority(check.category, affectedFrameworks, check.name),
|
|
1098
|
+
effort: getEffortEstimate(check.name),
|
|
1099
|
+
fix: recommendation || `Enable or configure ${check.name.replace(/_/g, ' ')} in your monora.yml`,
|
|
1100
|
+
frameworks: affectedFrameworks,
|
|
1101
|
+
};
|
|
1102
|
+
items.push(item);
|
|
1103
|
+
}
|
|
1104
|
+
// Add items from errors (critical issues)
|
|
1105
|
+
for (const error of result.errors) {
|
|
1106
|
+
const item = {
|
|
1107
|
+
id: `error_${items.length}`,
|
|
1108
|
+
title: 'Critical Error',
|
|
1109
|
+
description: error,
|
|
1110
|
+
category: 'integrity',
|
|
1111
|
+
priority: 'critical',
|
|
1112
|
+
effort: 'high',
|
|
1113
|
+
fix: error.includes('chain')
|
|
1114
|
+
? 'Investigate hash chain integrity. Events may have been tampered with or corrupted.'
|
|
1115
|
+
: 'Address the error before proceeding with compliance certification.',
|
|
1116
|
+
frameworks,
|
|
1117
|
+
};
|
|
1118
|
+
items.push(item);
|
|
1119
|
+
}
|
|
1120
|
+
// Group by priority
|
|
1121
|
+
const issuesByPriority = {
|
|
1122
|
+
critical: items.filter((i) => i.priority === 'critical'),
|
|
1123
|
+
high: items.filter((i) => i.priority === 'high'),
|
|
1124
|
+
medium: items.filter((i) => i.priority === 'medium'),
|
|
1125
|
+
low: items.filter((i) => i.priority === 'low'),
|
|
1126
|
+
};
|
|
1127
|
+
// Group by category
|
|
1128
|
+
const issuesByCategory = {};
|
|
1129
|
+
for (const item of items) {
|
|
1130
|
+
if (!issuesByCategory[item.category]) {
|
|
1131
|
+
issuesByCategory[item.category] = [];
|
|
1132
|
+
}
|
|
1133
|
+
issuesByCategory[item.category].push(item);
|
|
1134
|
+
}
|
|
1135
|
+
// Order fixes: critical first, then by category priority, then by effort (easiest first within priority)
|
|
1136
|
+
const effortOrder = {
|
|
1137
|
+
minimal: 0,
|
|
1138
|
+
low: 1,
|
|
1139
|
+
medium: 2,
|
|
1140
|
+
high: 3,
|
|
1141
|
+
};
|
|
1142
|
+
const orderedFixes = [...items].sort((a, b) => {
|
|
1143
|
+
// First by priority
|
|
1144
|
+
const priorityOrder = { critical: 0, high: 1, medium: 2, low: 3 };
|
|
1145
|
+
const priorityDiff = priorityOrder[a.priority] - priorityOrder[b.priority];
|
|
1146
|
+
if (priorityDiff !== 0)
|
|
1147
|
+
return priorityDiff;
|
|
1148
|
+
// Then by category importance
|
|
1149
|
+
const categoryDiff = (CATEGORY_PRIORITY[b.category] || 50) - (CATEGORY_PRIORITY[a.category] || 50);
|
|
1150
|
+
if (categoryDiff !== 0)
|
|
1151
|
+
return categoryDiff;
|
|
1152
|
+
// Finally by effort (easier first)
|
|
1153
|
+
return effortOrder[a.effort] - effortOrder[b.effort];
|
|
1154
|
+
});
|
|
1155
|
+
// Calculate estimated total effort
|
|
1156
|
+
const effortCounts = { minimal: 0, low: 0, medium: 0, high: 0 };
|
|
1157
|
+
for (const item of items) {
|
|
1158
|
+
effortCounts[item.effort]++;
|
|
1159
|
+
}
|
|
1160
|
+
let estimatedEffort = 'None';
|
|
1161
|
+
if (items.length > 0) {
|
|
1162
|
+
if (effortCounts.high > 2 || items.length > 10) {
|
|
1163
|
+
estimatedEffort = 'Significant (multiple sessions)';
|
|
1164
|
+
}
|
|
1165
|
+
else if (effortCounts.high > 0 || effortCounts.medium > 3) {
|
|
1166
|
+
estimatedEffort = 'Moderate (few hours)';
|
|
1167
|
+
}
|
|
1168
|
+
else if (effortCounts.medium > 0 || effortCounts.low > 3) {
|
|
1169
|
+
estimatedEffort = 'Low (under an hour)';
|
|
1170
|
+
}
|
|
1171
|
+
else {
|
|
1172
|
+
estimatedEffort = 'Minimal (quick config changes)';
|
|
1173
|
+
}
|
|
1174
|
+
}
|
|
1175
|
+
return {
|
|
1176
|
+
summary: {
|
|
1177
|
+
totalIssues: items.length,
|
|
1178
|
+
criticalCount: issuesByPriority.critical.length,
|
|
1179
|
+
highCount: issuesByPriority.high.length,
|
|
1180
|
+
mediumCount: issuesByPriority.medium.length,
|
|
1181
|
+
lowCount: issuesByPriority.low.length,
|
|
1182
|
+
estimatedEffort,
|
|
1183
|
+
},
|
|
1184
|
+
issuesByPriority,
|
|
1185
|
+
issuesByCategory,
|
|
1186
|
+
orderedFixes,
|
|
1187
|
+
generatedAt: new Date().toISOString(),
|
|
1188
|
+
};
|
|
1189
|
+
}
|
|
1190
|
+
async function generateAssessmentReport(options = {}) {
|
|
1191
|
+
// Run compliance check
|
|
1192
|
+
const checkResult = await runComplianceCheck({
|
|
1193
|
+
eventsPath: options.eventsPath,
|
|
1194
|
+
configPath: options.configPath,
|
|
1195
|
+
frameworks: options.frameworks,
|
|
1196
|
+
});
|
|
1197
|
+
// Get usage profile
|
|
1198
|
+
let config;
|
|
1199
|
+
if (options.configPath) {
|
|
1200
|
+
try {
|
|
1201
|
+
config = (0, config_1.loadConfig)({ configPath: options.configPath });
|
|
1202
|
+
}
|
|
1203
|
+
catch {
|
|
1204
|
+
// Ignore config load errors
|
|
1205
|
+
}
|
|
1206
|
+
}
|
|
1207
|
+
const profile = reportUsageProfile({ config });
|
|
1208
|
+
// Build report
|
|
1209
|
+
const report = {
|
|
1210
|
+
reportType: 'monora_assessment',
|
|
1211
|
+
reportVersion: '1.0.0',
|
|
1212
|
+
sdkVersion: SDK_VERSION,
|
|
1213
|
+
generatedAt: new Date().toISOString(),
|
|
1214
|
+
complianceCheck: checkResult,
|
|
1215
|
+
usageProfile: profile,
|
|
1216
|
+
summary: {
|
|
1217
|
+
passed: checkResult.passed,
|
|
1218
|
+
score: checkResult.score,
|
|
1219
|
+
grade: checkResult.grade,
|
|
1220
|
+
frameworksAssessed: checkResult.frameworksAssessed,
|
|
1221
|
+
totalChecks: checkResult.checks.length,
|
|
1222
|
+
passedChecks: checkResult.checks.filter((c) => c.passed).length,
|
|
1223
|
+
warningsCount: checkResult.warnings.length,
|
|
1224
|
+
errorsCount: checkResult.errors.length,
|
|
1225
|
+
},
|
|
1226
|
+
};
|
|
1227
|
+
// Write to file if requested
|
|
1228
|
+
if (options.outputPath) {
|
|
1229
|
+
fs.writeFileSync(options.outputPath, JSON.stringify(report, null, 2));
|
|
1230
|
+
}
|
|
1231
|
+
return report;
|
|
1232
|
+
}
|