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.
Files changed (193) hide show
  1. package/README.md +339 -158
  2. package/dist/aims_governance.d.ts +238 -0
  3. package/dist/aims_governance.d.ts.map +1 -0
  4. package/dist/aims_governance.js +922 -0
  5. package/dist/alerts.d.ts +16 -0
  6. package/dist/alerts.d.ts.map +1 -1
  7. package/dist/alerts.js +16 -0
  8. package/dist/api.d.ts +6 -0
  9. package/dist/api.d.ts.map +1 -1
  10. package/dist/api.js +6 -0
  11. package/dist/assessment.d.ts +85 -0
  12. package/dist/assessment.d.ts.map +1 -1
  13. package/dist/assessment.js +525 -13
  14. package/dist/attribution.d.ts +44 -3
  15. package/dist/attribution.d.ts.map +1 -1
  16. package/dist/attribution.js +197 -10
  17. package/dist/autodetect.d.ts +68 -0
  18. package/dist/autodetect.d.ts.map +1 -1
  19. package/dist/autodetect.js +639 -0
  20. package/dist/bias.d.ts +130 -0
  21. package/dist/bias.d.ts.map +1 -0
  22. package/dist/bias.js +223 -0
  23. package/dist/cli/diagnostics.d.ts +5 -1
  24. package/dist/cli/diagnostics.d.ts.map +1 -1
  25. package/dist/cli/diagnostics.js +23 -6
  26. package/dist/cli/doctor.d.ts +25 -0
  27. package/dist/cli/doctor.d.ts.map +1 -0
  28. package/dist/cli/doctor.js +381 -0
  29. package/dist/cli/fix.d.ts +16 -0
  30. package/dist/cli/fix.d.ts.map +1 -0
  31. package/dist/cli/fix.js +284 -0
  32. package/dist/cli/init.d.ts +57 -0
  33. package/dist/cli/init.d.ts.map +1 -0
  34. package/dist/cli/init.js +205 -0
  35. package/dist/cli.js +1564 -177
  36. package/dist/complianceConsolidation.d.ts +17 -0
  37. package/dist/complianceConsolidation.d.ts.map +1 -0
  38. package/dist/complianceConsolidation.js +68 -0
  39. package/dist/complianceTargets.d.ts +111 -0
  40. package/dist/complianceTargets.d.ts.map +1 -0
  41. package/dist/complianceTargets.js +521 -0
  42. package/dist/config.d.ts +261 -16
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +381 -32
  45. package/dist/config_migrations.d.ts.map +1 -1
  46. package/dist/config_migrations.js +38 -1
  47. package/dist/config_schema.d.ts +2490 -1035
  48. package/dist/config_schema.d.ts.map +1 -1
  49. package/dist/config_schema.js +233 -64
  50. package/dist/context.d.ts +34 -0
  51. package/dist/context.d.ts.map +1 -1
  52. package/dist/context.js +118 -7
  53. package/dist/control_backbone.d.ts +128 -0
  54. package/dist/control_backbone.d.ts.map +1 -0
  55. package/dist/control_backbone.js +826 -0
  56. package/dist/data-governance.d.ts +187 -0
  57. package/dist/data-governance.d.ts.map +1 -0
  58. package/dist/data-governance.js +424 -0
  59. package/dist/dataResidency.d.ts +44 -0
  60. package/dist/dataResidency.d.ts.map +1 -0
  61. package/dist/dataResidency.js +203 -0
  62. package/dist/dispatcher.d.ts.map +1 -1
  63. package/dist/dispatcher.js +17 -5
  64. package/dist/evidence_store.d.ts +103 -0
  65. package/dist/evidence_store.d.ts.map +1 -0
  66. package/dist/evidence_store.js +459 -0
  67. package/dist/executiveSummary.d.ts +15 -0
  68. package/dist/executiveSummary.d.ts.map +1 -1
  69. package/dist/executiveSummary.js +135 -22
  70. package/dist/identity.d.ts +143 -0
  71. package/dist/identity.d.ts.map +1 -0
  72. package/dist/identity.js +231 -0
  73. package/dist/impact-assessment.d.ts +350 -0
  74. package/dist/impact-assessment.d.ts.map +1 -0
  75. package/dist/impact-assessment.js +580 -0
  76. package/dist/index.d.ts +21 -4
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +254 -5
  79. package/dist/instrumentation.d.ts +1 -1
  80. package/dist/instrumentation.d.ts.map +1 -1
  81. package/dist/instrumentation.js +123 -22
  82. package/dist/integrations/anthropic.d.ts +3 -0
  83. package/dist/integrations/anthropic.d.ts.map +1 -1
  84. package/dist/integrations/anthropic.js +282 -80
  85. package/dist/integrations/governance.d.ts +33 -0
  86. package/dist/integrations/governance.d.ts.map +1 -0
  87. package/dist/integrations/governance.js +208 -0
  88. package/dist/integrations/langchain.d.ts +4 -0
  89. package/dist/integrations/langchain.d.ts.map +1 -1
  90. package/dist/integrations/langchain.js +362 -142
  91. package/dist/integrations/openai.d.ts +9 -0
  92. package/dist/integrations/openai.d.ts.map +1 -1
  93. package/dist/integrations/openai.js +673 -73
  94. package/dist/iso42001_consolidation.d.ts +16 -0
  95. package/dist/iso42001_consolidation.d.ts.map +1 -0
  96. package/dist/iso42001_consolidation.js +413 -0
  97. package/dist/iso42001_workflows.d.ts +263 -0
  98. package/dist/iso42001_workflows.d.ts.map +1 -0
  99. package/dist/iso42001_workflows.js +781 -0
  100. package/dist/lifecycle.d.ts +299 -0
  101. package/dist/lifecycle.d.ts.map +1 -0
  102. package/dist/lifecycle.js +624 -0
  103. package/dist/lineage.d.ts +2 -2
  104. package/dist/lineage.d.ts.map +1 -1
  105. package/dist/lineage.js +9 -16
  106. package/dist/middleware/express.d.ts.map +1 -1
  107. package/dist/middleware/express.js +18 -3
  108. package/dist/middleware/nextjs.js +2 -2
  109. package/dist/model.d.ts +143 -0
  110. package/dist/model.d.ts.map +1 -0
  111. package/dist/model.js +371 -0
  112. package/dist/onboarding.d.ts +42 -0
  113. package/dist/onboarding.d.ts.map +1 -0
  114. package/dist/onboarding.js +1075 -0
  115. package/dist/oversight.d.ts +264 -0
  116. package/dist/oversight.d.ts.map +1 -0
  117. package/dist/oversight.js +497 -0
  118. package/dist/presets.js +7 -7
  119. package/dist/quotas.d.ts +171 -0
  120. package/dist/quotas.d.ts.map +1 -0
  121. package/dist/quotas.js +259 -0
  122. package/dist/register.d.ts +13 -0
  123. package/dist/register.d.ts.map +1 -0
  124. package/dist/register.js +99 -0
  125. package/dist/registry.d.ts +1 -0
  126. package/dist/registry.d.ts.map +1 -1
  127. package/dist/registry.js +7 -0
  128. package/dist/registryData.json +43 -6
  129. package/dist/report.d.ts +2 -1
  130. package/dist/report.d.ts.map +1 -1
  131. package/dist/report.js +189 -2
  132. package/dist/reporting.d.ts +125 -0
  133. package/dist/reporting.d.ts.map +1 -1
  134. package/dist/reporting.js +192 -2
  135. package/dist/resources.d.ts +285 -0
  136. package/dist/resources.d.ts.map +1 -0
  137. package/dist/resources.js +643 -0
  138. package/dist/risk.d.ts +120 -0
  139. package/dist/risk.d.ts.map +1 -0
  140. package/dist/risk.js +220 -0
  141. package/dist/runtime.d.ts +74 -0
  142. package/dist/runtime.d.ts.map +1 -1
  143. package/dist/runtime.js +416 -18
  144. package/dist/schemaInference.d.ts +92 -0
  145. package/dist/schemaInference.d.ts.map +1 -0
  146. package/dist/schemaInference.js +466 -0
  147. package/dist/schema_validation.js +2 -2
  148. package/dist/schemas/config.schema.json +118 -4
  149. package/dist/security_report.js +4 -4
  150. package/dist/signing.d.ts +1 -1
  151. package/dist/signing.d.ts.map +1 -1
  152. package/dist/signing.js +4 -0
  153. package/dist/sinks/file.d.ts +19 -1
  154. package/dist/sinks/file.d.ts.map +1 -1
  155. package/dist/sinks/file.js +82 -13
  156. package/dist/sinks/https.d.ts +10 -0
  157. package/dist/sinks/https.d.ts.map +1 -1
  158. package/dist/sinks/https.js +76 -16
  159. package/dist/sinks/stdout.d.ts +1 -0
  160. package/dist/sinks/stdout.d.ts.map +1 -1
  161. package/dist/sinks/stdout.js +12 -1
  162. package/dist/spec.d.ts +159 -0
  163. package/dist/spec.d.ts.map +1 -0
  164. package/dist/spec.js +391 -0
  165. package/dist/stakeholders.d.ts +199 -0
  166. package/dist/stakeholders.d.ts.map +1 -0
  167. package/dist/stakeholders.js +398 -0
  168. package/dist/standards.d.ts.map +1 -1
  169. package/dist/standards.js +160 -2
  170. package/dist/standards_ingest.d.ts.map +1 -1
  171. package/dist/standards_ingest.js +1 -4
  172. package/dist/telemetry.d.ts +16 -2
  173. package/dist/telemetry.d.ts.map +1 -1
  174. package/dist/telemetry.js +77 -14
  175. package/dist/templates/controls/gdpr_control_catalog.json +261 -0
  176. package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
  177. package/dist/templates/controls/soc2_control_catalog.json +163 -0
  178. package/dist/templates/standards/iso42001_claims.json +72 -0
  179. package/dist/traced_emitter.d.ts.map +1 -1
  180. package/dist/traced_emitter.js +19 -9
  181. package/dist/trust_package.d.ts +20 -1
  182. package/dist/trust_package.d.ts.map +1 -1
  183. package/dist/trust_package.js +90 -2
  184. package/dist/verify.d.ts.map +1 -1
  185. package/dist/verify.js +9 -2
  186. package/dist/wal.d.ts.map +1 -1
  187. package/dist/wal.js +2 -1
  188. package/package.json +14 -1
  189. package/scripts/postinstall.js +105 -210
  190. package/templates/controls/gdpr_control_catalog.json +261 -0
  191. package/templates/controls/iso42001_control_catalog.json +1443 -0
  192. package/templates/controls/soc2_control_catalog.json +163 -0
  193. package/templates/standards/iso42001_claims.json +72 -0
@@ -0,0 +1,826 @@
1
+ "use strict";
2
+ /**
3
+ * Control/evidence workflow backbone for framework coverage reporting.
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.clearControlRuntime = clearControlRuntime;
40
+ exports.setControlCatalog = setControlCatalog;
41
+ exports.loadControlCatalog = loadControlCatalog;
42
+ exports.getControlCatalog = getControlCatalog;
43
+ exports.loadDefaultIso42001Catalog = loadDefaultIso42001Catalog;
44
+ exports.loadDefaultSoc2Catalog = loadDefaultSoc2Catalog;
45
+ exports.loadDefaultGdprCatalog = loadDefaultGdprCatalog;
46
+ exports.loadDefaultControlCatalog = loadDefaultControlCatalog;
47
+ exports.resolveControlIdsForEvidenceTypes = resolveControlIdsForEvidenceTypes;
48
+ exports.createWorkflowTask = createWorkflowTask;
49
+ exports.getWorkflowTask = getWorkflowTask;
50
+ exports.listWorkflowTasks = listWorkflowTasks;
51
+ exports.transitionWorkflowTask = transitionWorkflowTask;
52
+ exports.submitWorkflowTask = submitWorkflowTask;
53
+ exports.approveControlEvidence = approveControlEvidence;
54
+ exports.expireWorkflowTask = expireWorkflowTask;
55
+ exports.attachControlEvidence = attachControlEvidence;
56
+ exports.importEvidenceManifest = importEvidenceManifest;
57
+ exports.bootstrapWorkflowsFromCatalog = bootstrapWorkflowsFromCatalog;
58
+ exports.prioritizeMissingWorkflowModules = prioritizeMissingWorkflowModules;
59
+ exports.generateControlCoverageReport = generateControlCoverageReport;
60
+ exports.buildWorkflowStatePayload = buildWorkflowStatePayload;
61
+ exports.exportWorkflowState = exportWorkflowState;
62
+ exports.loadWorkflowState = loadWorkflowState;
63
+ const crypto = __importStar(require("crypto"));
64
+ const fs = __importStar(require("fs"));
65
+ const path = __importStar(require("path"));
66
+ const evidence_store_1 = require("./evidence_store");
67
+ const WORKFLOW_STATUSES = new Set(['draft', 'in_review', 'approved', 'expired']);
68
+ const STATUS_TRANSITIONS = {
69
+ draft: ['in_review', 'approved'],
70
+ in_review: ['draft', 'approved'],
71
+ approved: ['in_review', 'expired'],
72
+ expired: ['in_review'],
73
+ };
74
+ const ISO42001_WORKFLOW_MODULES = [
75
+ {
76
+ module_id: 'aims_governance',
77
+ name: 'AIMS Governance',
78
+ priority: 'P1',
79
+ impact: 'high',
80
+ controls: ['A.2.2', 'A.2.3', 'A.2.4', 'A.3.2', 'A.3.3', 'Clause4', 'Clause5', 'Clause7'],
81
+ },
82
+ {
83
+ module_id: 'risk_impact_workflow',
84
+ name: 'Risk + Impact Workflow',
85
+ priority: 'P1',
86
+ impact: 'high',
87
+ controls: ['A.5.2', 'A.5.3', 'A.5.4', 'A.5.5', 'Clause6'],
88
+ },
89
+ {
90
+ module_id: 'ai_lifecycle_assurance',
91
+ name: 'AI Lifecycle Assurance',
92
+ priority: 'P1',
93
+ impact: 'high',
94
+ controls: ['A.6.1.2', 'A.6.1.3', 'A.6.2.2', 'A.6.2.4', 'A.6.2.5', 'A.6.2.6', 'A.6.2.7', 'A.6.2.8', 'Clause8'],
95
+ },
96
+ {
97
+ module_id: 'audit_review_capa',
98
+ name: 'Audit + Management Review + CAPA',
99
+ priority: 'P2',
100
+ impact: 'high',
101
+ controls: ['Clause9', 'Clause10'],
102
+ },
103
+ {
104
+ module_id: 'data_governance_workflow',
105
+ name: 'Data Governance Workflow',
106
+ priority: 'P2',
107
+ impact: 'medium',
108
+ controls: ['A.7.2', 'A.7.3', 'A.7.4', 'A.7.5', 'A.7.6'],
109
+ },
110
+ {
111
+ module_id: 'transparency_responsible_use',
112
+ name: 'Transparency + Responsible Use',
113
+ priority: 'P2',
114
+ impact: 'medium',
115
+ controls: ['A.8.2', 'A.8.3', 'A.8.4', 'A.8.5', 'A.9.2', 'A.9.3', 'A.9.4'],
116
+ },
117
+ {
118
+ module_id: 'third_party_customer_governance',
119
+ name: 'Third-Party + Customer Governance',
120
+ priority: 'P3',
121
+ impact: 'medium',
122
+ controls: ['A.10.1', 'A.10.2', 'A.10.3'],
123
+ },
124
+ ];
125
+ const SOC2_WORKFLOW_MODULES = [
126
+ {
127
+ module_id: 'soc2_governance_communication',
128
+ name: 'Governance + Communication',
129
+ priority: 'P1',
130
+ impact: 'high',
131
+ controls: ['CC1', 'CC2'],
132
+ },
133
+ {
134
+ module_id: 'soc2_risk_monitoring',
135
+ name: 'Risk + Monitoring',
136
+ priority: 'P1',
137
+ impact: 'high',
138
+ controls: ['CC3', 'CC4', 'CC9'],
139
+ },
140
+ {
141
+ module_id: 'soc2_access_security',
142
+ name: 'Access + Security',
143
+ priority: 'P1',
144
+ impact: 'high',
145
+ controls: ['CC5', 'CC6'],
146
+ },
147
+ {
148
+ module_id: 'soc2_operations_availability',
149
+ name: 'Operations + Availability',
150
+ priority: 'P2',
151
+ impact: 'medium',
152
+ controls: ['CC7', 'CC8'],
153
+ },
154
+ {
155
+ module_id: 'soc2_privacy_integrity',
156
+ name: 'Privacy + Processing Integrity',
157
+ priority: 'P2',
158
+ impact: 'medium',
159
+ controls: ['P_SERIES', 'PI_SERIES'],
160
+ },
161
+ ];
162
+ const GDPR_WORKFLOW_MODULES = [
163
+ {
164
+ module_id: 'gdpr_lawful_basis_consent',
165
+ name: 'Lawful Basis + Consent',
166
+ priority: 'P1',
167
+ impact: 'high',
168
+ controls: ['art5', 'art6', 'art7'],
169
+ },
170
+ {
171
+ module_id: 'gdpr_transparency_rights',
172
+ name: 'Transparency + Data Subject Rights',
173
+ priority: 'P1',
174
+ impact: 'high',
175
+ controls: ['art12', 'art13', 'art14', 'art15', 'art16', 'art17', 'art18', 'art20', 'art21', 'art22'],
176
+ },
177
+ {
178
+ module_id: 'gdpr_privacy_by_design_records',
179
+ name: 'Privacy by Design + Records',
180
+ priority: 'P2',
181
+ impact: 'medium',
182
+ controls: ['art25', 'art30'],
183
+ },
184
+ {
185
+ module_id: 'gdpr_security_breach_handling',
186
+ name: 'Security + Breach Handling',
187
+ priority: 'P2',
188
+ impact: 'high',
189
+ controls: ['art32', 'art33'],
190
+ },
191
+ {
192
+ module_id: 'gdpr_dpia_risk',
193
+ name: 'DPIA + Risk',
194
+ priority: 'P2',
195
+ impact: 'medium',
196
+ controls: ['art35'],
197
+ },
198
+ ];
199
+ const WORKFLOW_MODULES_BY_STANDARD = {
200
+ ISO42001: ISO42001_WORKFLOW_MODULES,
201
+ SOC2: SOC2_WORKFLOW_MODULES,
202
+ GDPR: GDPR_WORKFLOW_MODULES,
203
+ };
204
+ const PRIORITY_ORDER = { P0: 0, P1: 1, P2: 2, P3: 3, P4: 4 };
205
+ const IMPACT_ORDER = { critical: 0, high: 1, medium: 2, low: 3 };
206
+ let runtimeCatalog = null;
207
+ let runtimeWorkflows = new Map();
208
+ let runtimeEvidence = new Map();
209
+ let defaultIso42001Catalog = null;
210
+ let defaultSoc2Catalog = null;
211
+ let defaultGdprCatalog = null;
212
+ function utcNow() {
213
+ return new Date().toISOString();
214
+ }
215
+ function clone(value) {
216
+ return JSON.parse(JSON.stringify(value));
217
+ }
218
+ function normalizeList(value) {
219
+ if (value === null || value === undefined) {
220
+ return [];
221
+ }
222
+ if (Array.isArray(value)) {
223
+ return value
224
+ .map((item) => String(item).trim())
225
+ .filter(Boolean);
226
+ }
227
+ return String(value)
228
+ .replace(/;/g, ',')
229
+ .split(',')
230
+ .map((item) => item.trim())
231
+ .filter(Boolean);
232
+ }
233
+ function buildId(prefix, ...parts) {
234
+ const seed = `${prefix}:${parts.join(':')}:${utcNow()}`;
235
+ const digest = crypto.createHash('sha256').update(seed).digest('hex').slice(0, 12);
236
+ return `${prefix}_${digest}`;
237
+ }
238
+ function normalizeStandard(value) {
239
+ const normalized = String(value || '').trim().toUpperCase().replace(/[-_]/g, '');
240
+ if (!normalized)
241
+ return 'ISO42001';
242
+ if (normalized === 'ISO42001' || normalized === 'ISOIEC42001')
243
+ return 'ISO42001';
244
+ if (normalized === 'SOC2' || normalized === 'SOCII')
245
+ return 'SOC2';
246
+ if (normalized === 'GDPR')
247
+ return 'GDPR';
248
+ return String(value || '').trim().toUpperCase();
249
+ }
250
+ function loadDefaultCatalogFromFile(filename, label) {
251
+ const candidatePaths = [
252
+ path.resolve(__dirname, '..', 'templates', 'controls', filename),
253
+ path.resolve(process.cwd(), 'monora-node', 'templates', 'controls', filename),
254
+ path.resolve(process.cwd(), 'templates', 'controls', filename),
255
+ path.resolve(process.cwd(), 'docs', filename),
256
+ ];
257
+ for (const candidate of candidatePaths) {
258
+ if (!fs.existsSync(candidate)) {
259
+ continue;
260
+ }
261
+ return JSON.parse(fs.readFileSync(candidate, 'utf-8'));
262
+ }
263
+ throw new Error(`Default ${label} control catalog not found`);
264
+ }
265
+ function resolveCatalog(catalog, standard) {
266
+ if (typeof catalog === 'string') {
267
+ try {
268
+ return JSON.parse(fs.readFileSync(catalog, 'utf-8'));
269
+ }
270
+ catch (error) {
271
+ const message = error instanceof Error ? error.message : String(error);
272
+ console.warn(`Failed to load catalog from ${catalog}: ${message}`);
273
+ if (runtimeCatalog) {
274
+ return clone(runtimeCatalog);
275
+ }
276
+ return loadDefaultControlCatalog(standard || 'ISO42001');
277
+ }
278
+ }
279
+ if (catalog) {
280
+ return catalog;
281
+ }
282
+ if (runtimeCatalog) {
283
+ return clone(runtimeCatalog);
284
+ }
285
+ return loadDefaultControlCatalog(standard || 'ISO42001');
286
+ }
287
+ function ensureEvidenceRecord(payload, controlId) {
288
+ const evidence = clone(payload);
289
+ if (!evidence.evidence_id) {
290
+ evidence.evidence_id = buildId('evd', controlId);
291
+ }
292
+ if (!evidence.title) {
293
+ evidence.title = `Evidence for ${controlId}`;
294
+ }
295
+ if (!evidence.source) {
296
+ evidence.source = 'manual';
297
+ }
298
+ if (!evidence.category) {
299
+ evidence.category = 'governance';
300
+ }
301
+ if (!evidence.collection_method) {
302
+ evidence.collection_method = 'manual';
303
+ }
304
+ if (!evidence.collected_at) {
305
+ evidence.collected_at = utcNow();
306
+ }
307
+ const controlIds = new Set(normalizeList(evidence.control_ids));
308
+ controlIds.add(controlId);
309
+ evidence.control_ids = Array.from(controlIds).sort();
310
+ if (!evidence.metadata || typeof evidence.metadata !== 'object') {
311
+ evidence.metadata = {};
312
+ }
313
+ if (!evidence.status) {
314
+ evidence.status = 'collected';
315
+ }
316
+ return evidence;
317
+ }
318
+ function appendHistory(workflow, event, options) {
319
+ workflow.history.push({
320
+ timestamp: utcNow(),
321
+ event,
322
+ actor: options?.actor,
323
+ from_status: options?.fromStatus,
324
+ to_status: options?.toStatus,
325
+ note: options?.note,
326
+ metadata: options?.metadata,
327
+ });
328
+ workflow.updated_at = utcNow();
329
+ }
330
+ function findControl(controlId) {
331
+ const controls = (runtimeCatalog?.controls || []);
332
+ return controls.find((control) => String(control.control_id) === controlId) || {};
333
+ }
334
+ function clearControlRuntime() {
335
+ runtimeCatalog = null;
336
+ runtimeWorkflows = new Map();
337
+ runtimeEvidence = new Map();
338
+ (0, evidence_store_1.clearRuntimeEvidenceStore)();
339
+ }
340
+ function setControlCatalog(catalog) {
341
+ runtimeCatalog = clone(catalog);
342
+ return clone(runtimeCatalog);
343
+ }
344
+ function loadControlCatalog(filePath) {
345
+ const payload = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
346
+ return setControlCatalog(payload);
347
+ }
348
+ function getControlCatalog() {
349
+ return runtimeCatalog ? clone(runtimeCatalog) : null;
350
+ }
351
+ function loadDefaultIso42001Catalog() {
352
+ if (defaultIso42001Catalog) {
353
+ return clone(defaultIso42001Catalog);
354
+ }
355
+ const payload = loadDefaultCatalogFromFile('iso42001_control_catalog.json', 'ISO 42001');
356
+ defaultIso42001Catalog = payload;
357
+ return clone(payload);
358
+ }
359
+ function loadDefaultSoc2Catalog() {
360
+ if (defaultSoc2Catalog) {
361
+ return clone(defaultSoc2Catalog);
362
+ }
363
+ const payload = loadDefaultCatalogFromFile('soc2_control_catalog.json', 'SOC 2');
364
+ defaultSoc2Catalog = payload;
365
+ return clone(payload);
366
+ }
367
+ function loadDefaultGdprCatalog() {
368
+ if (defaultGdprCatalog) {
369
+ return clone(defaultGdprCatalog);
370
+ }
371
+ const payload = loadDefaultCatalogFromFile('gdpr_control_catalog.json', 'GDPR');
372
+ defaultGdprCatalog = payload;
373
+ return clone(payload);
374
+ }
375
+ function loadDefaultControlCatalog(standard) {
376
+ const normalized = normalizeStandard(standard);
377
+ if (normalized === 'SOC2') {
378
+ return loadDefaultSoc2Catalog();
379
+ }
380
+ if (normalized === 'GDPR') {
381
+ return loadDefaultGdprCatalog();
382
+ }
383
+ return loadDefaultIso42001Catalog();
384
+ }
385
+ function resolveControlIdsForEvidenceTypes(evidenceTypes, catalog, standard) {
386
+ const normalizedTypes = new Set(normalizeList(evidenceTypes));
387
+ if (normalizedTypes.size === 0) {
388
+ return [];
389
+ }
390
+ let payload = catalog || runtimeCatalog;
391
+ if (!payload) {
392
+ try {
393
+ payload = loadDefaultControlCatalog(standard || 'ISO42001');
394
+ }
395
+ catch (_err) {
396
+ payload = null;
397
+ }
398
+ }
399
+ const controls = (payload?.controls || []);
400
+ const ids = new Set();
401
+ for (const control of controls) {
402
+ const controlId = String(control.control_id || '').trim();
403
+ if (!controlId) {
404
+ continue;
405
+ }
406
+ const controlTypes = new Set(normalizeList(control.evidence_types));
407
+ for (const evidenceType of normalizedTypes) {
408
+ if (controlTypes.has(evidenceType)) {
409
+ ids.add(controlId);
410
+ }
411
+ }
412
+ }
413
+ return Array.from(ids).sort();
414
+ }
415
+ function createWorkflowTask(options) {
416
+ const control = findControl(options.controlId);
417
+ const controlTitle = String(control.title || options.controlId);
418
+ const owner = options.owner || (typeof control.owner === 'string' ? control.owner.trim() || undefined : undefined);
419
+ const workflow = {
420
+ workflow_id: buildId('wf', options.controlId),
421
+ control_id: options.controlId,
422
+ title: options.title || `${options.controlId} - ${controlTitle}`,
423
+ status: 'draft',
424
+ owner,
425
+ created_at: utcNow(),
426
+ updated_at: utcNow(),
427
+ created_by: options.createdBy,
428
+ due_at: options.dueAt,
429
+ evidence_ids: [],
430
+ notes: options.notes,
431
+ metadata: options.metadata || {},
432
+ history: [],
433
+ };
434
+ appendHistory(workflow, 'created', { actor: options.createdBy, note: options.notes });
435
+ runtimeWorkflows.set(workflow.workflow_id, clone(workflow));
436
+ return clone(workflow);
437
+ }
438
+ function getWorkflowTask(workflowId) {
439
+ const workflow = runtimeWorkflows.get(workflowId);
440
+ return workflow ? clone(workflow) : null;
441
+ }
442
+ function listWorkflowTasks(options) {
443
+ const values = Array.from(runtimeWorkflows.values());
444
+ return values
445
+ .filter((workflow) => !options?.controlId || workflow.control_id === options.controlId)
446
+ .filter((workflow) => !options?.status || workflow.status === options.status)
447
+ .map((workflow) => clone(workflow));
448
+ }
449
+ function transitionWorkflowTask(workflowId, options) {
450
+ const workflow = runtimeWorkflows.get(workflowId);
451
+ if (!workflow) {
452
+ throw new Error(`Workflow not found: ${workflowId}`);
453
+ }
454
+ const fromStatus = workflow.status;
455
+ const allowed = STATUS_TRANSITIONS[workflow.status] || [];
456
+ if (!allowed.includes(options.toStatus)) {
457
+ throw new Error(`Invalid workflow transition ${workflow.status} -> ${options.toStatus}. Allowed: ${allowed.join(', ')}`);
458
+ }
459
+ workflow.status = options.toStatus;
460
+ if (options.toStatus === 'approved') {
461
+ if (workflow.evidence_ids.length === 0) {
462
+ throw new Error('Cannot approve workflow without linked evidence');
463
+ }
464
+ workflow.approved_at = utcNow();
465
+ workflow.approved_by = options.actor;
466
+ }
467
+ appendHistory(workflow, 'status_changed', {
468
+ actor: options.actor,
469
+ fromStatus,
470
+ toStatus: options.toStatus,
471
+ note: options.note,
472
+ });
473
+ runtimeWorkflows.set(workflowId, clone(workflow));
474
+ return clone(workflow);
475
+ }
476
+ function submitWorkflowTask(workflowId, options) {
477
+ return transitionWorkflowTask(workflowId, {
478
+ toStatus: 'in_review',
479
+ actor: options?.actor,
480
+ note: options?.note,
481
+ });
482
+ }
483
+ function approveControlEvidence(workflowId, options) {
484
+ return transitionWorkflowTask(workflowId, {
485
+ toStatus: 'approved',
486
+ actor: options?.actor,
487
+ note: options?.note,
488
+ });
489
+ }
490
+ function expireWorkflowTask(workflowId, options) {
491
+ return transitionWorkflowTask(workflowId, {
492
+ toStatus: 'expired',
493
+ actor: options?.actor,
494
+ note: options?.note,
495
+ });
496
+ }
497
+ function attachControlEvidence(options) {
498
+ const evidence = ensureEvidenceRecord(options.evidence, options.controlId);
499
+ if (options.evidenceType) {
500
+ evidence.metadata = evidence.metadata || {};
501
+ evidence.metadata.evidence_type = options.evidenceType;
502
+ const evidenceTypes = new Set(normalizeList(evidence.metadata.evidence_types));
503
+ evidenceTypes.add(options.evidenceType);
504
+ evidence.metadata.evidence_types = Array.from(evidenceTypes).sort();
505
+ }
506
+ if (options.workflowId) {
507
+ evidence.metadata = evidence.metadata || {};
508
+ evidence.metadata.workflow_id = options.workflowId;
509
+ }
510
+ runtimeEvidence.set(evidence.evidence_id, clone(evidence));
511
+ (0, evidence_store_1.recordRuntimeEvidence)(evidence);
512
+ if (options.workflowId) {
513
+ const workflow = runtimeWorkflows.get(options.workflowId);
514
+ if (!workflow) {
515
+ throw new Error(`Workflow not found: ${options.workflowId}`);
516
+ }
517
+ if (workflow.control_id !== options.controlId) {
518
+ throw new Error(`Workflow control mismatch: ${workflow.control_id} != ${options.controlId}`);
519
+ }
520
+ if (!workflow.evidence_ids.includes(evidence.evidence_id)) {
521
+ workflow.evidence_ids.push(evidence.evidence_id);
522
+ }
523
+ appendHistory(workflow, 'evidence_attached', {
524
+ actor: options.actor,
525
+ note: options.note,
526
+ metadata: { evidence_id: evidence.evidence_id },
527
+ });
528
+ runtimeWorkflows.set(options.workflowId, clone(workflow));
529
+ }
530
+ return clone(evidence);
531
+ }
532
+ function importEvidenceManifest(manifest, options) {
533
+ const evidenceItems = Array.isArray(manifest.evidence_items) ? manifest.evidence_items : [];
534
+ if (options?.clearExisting) {
535
+ runtimeEvidence = new Map();
536
+ (0, evidence_store_1.clearRuntimeEvidenceStore)();
537
+ }
538
+ let count = 0;
539
+ for (const rawItem of evidenceItems) {
540
+ if (!rawItem || typeof rawItem !== 'object') {
541
+ continue;
542
+ }
543
+ const evidenceId = String(rawItem.evidence_id || '').trim();
544
+ if (!evidenceId) {
545
+ continue;
546
+ }
547
+ runtimeEvidence.set(evidenceId, clone(rawItem));
548
+ (0, evidence_store_1.recordRuntimeEvidence)(rawItem);
549
+ count += 1;
550
+ }
551
+ return count;
552
+ }
553
+ function bootstrapWorkflowsFromCatalog(catalog, options) {
554
+ const payload = catalog || runtimeCatalog || loadDefaultIso42001Catalog();
555
+ const controls = Array.isArray(payload.controls) ? payload.controls : [];
556
+ const existingControlIds = new Set(Array.from(runtimeWorkflows.values()).map((w) => w.control_id));
557
+ const created = [];
558
+ for (const control of controls) {
559
+ if (!control || typeof control !== 'object') {
560
+ continue;
561
+ }
562
+ const controlId = String(control.control_id || '').trim();
563
+ if (!controlId || existingControlIds.has(controlId)) {
564
+ continue;
565
+ }
566
+ const ownerValue = String(control.owner || '').trim();
567
+ const owner = ownerValue || options?.ownerFallback || 'Unassigned';
568
+ const workflow = createWorkflowTask({
569
+ controlId,
570
+ title: `${controlId} - ${String(control.title || controlId)}`,
571
+ owner,
572
+ createdBy: options?.createdBy || 'system',
573
+ metadata: { bootstrap: true },
574
+ });
575
+ created.push(workflow);
576
+ existingControlIds.add(controlId);
577
+ }
578
+ return created;
579
+ }
580
+ function extractEvidenceTypes(item) {
581
+ const out = new Set();
582
+ const metadata = item.metadata && typeof item.metadata === 'object' ? item.metadata : {};
583
+ for (const key of ['evidence_type', 'type']) {
584
+ normalizeList(metadata[key]).forEach((value) => out.add(value));
585
+ }
586
+ normalizeList(metadata.evidence_types).forEach((value) => out.add(value));
587
+ normalizeList(item.tags).forEach((value) => out.add(value));
588
+ if (item.category) {
589
+ out.add(String(item.category));
590
+ }
591
+ return out;
592
+ }
593
+ function prioritizeMissingWorkflowModules(uncoveredControls, standard) {
594
+ const missingSet = new Set(normalizeList(uncoveredControls));
595
+ const modules = [];
596
+ const resolvedStandard = normalizeStandard(standard);
597
+ const moduleSource = WORKFLOW_MODULES_BY_STANDARD[resolvedStandard] || ISO42001_WORKFLOW_MODULES;
598
+ for (const moduleDef of moduleSource) {
599
+ const controls = normalizeList(moduleDef.controls);
600
+ const overlap = controls.filter((controlId) => missingSet.has(controlId)).sort();
601
+ if (overlap.length === 0) {
602
+ continue;
603
+ }
604
+ modules.push({
605
+ module_id: moduleDef.module_id,
606
+ name: moduleDef.name,
607
+ priority: moduleDef.priority,
608
+ impact: moduleDef.impact,
609
+ missing_controls: overlap,
610
+ missing_count: overlap.length,
611
+ });
612
+ }
613
+ modules.sort((a, b) => {
614
+ const p = (PRIORITY_ORDER[a.priority] ?? 99) - (PRIORITY_ORDER[b.priority] ?? 99);
615
+ if (p !== 0) {
616
+ return p;
617
+ }
618
+ const i = (IMPACT_ORDER[a.impact] ?? 99) - (IMPACT_ORDER[b.impact] ?? 99);
619
+ if (i !== 0) {
620
+ return i;
621
+ }
622
+ return Number(b.missing_count || 0) - Number(a.missing_count || 0);
623
+ });
624
+ return modules;
625
+ }
626
+ function generateControlCoverageReport(options) {
627
+ const catalog = resolveCatalog(options?.catalog || null, options?.standard);
628
+ const controls = Array.isArray(catalog.controls) ? catalog.controls : [];
629
+ const evidenceItems = options?.evidenceItems || Array.from(runtimeEvidence.values());
630
+ const workflows = options?.workflows || Array.from(runtimeWorkflows.values());
631
+ const targetCoverage = typeof options?.targetCoverage === 'number' ? options.targetCoverage : 0.9;
632
+ const evidenceById = new Map();
633
+ const evidenceByControl = new Map();
634
+ const approvedByControl = new Map();
635
+ for (const rawItem of evidenceItems) {
636
+ if (!rawItem || typeof rawItem !== 'object') {
637
+ continue;
638
+ }
639
+ const item = rawItem;
640
+ const evidenceId = String(item.evidence_id || '').trim();
641
+ if (!evidenceId) {
642
+ continue;
643
+ }
644
+ evidenceById.set(evidenceId, item);
645
+ for (const controlId of normalizeList(item.control_ids)) {
646
+ if (!evidenceByControl.has(controlId)) {
647
+ evidenceByControl.set(controlId, new Set());
648
+ }
649
+ evidenceByControl.get(controlId)?.add(evidenceId);
650
+ if (String(item.status || '').toLowerCase() === 'approved') {
651
+ if (!approvedByControl.has(controlId)) {
652
+ approvedByControl.set(controlId, new Set());
653
+ }
654
+ approvedByControl.get(controlId)?.add(evidenceId);
655
+ }
656
+ }
657
+ }
658
+ const workflowsByControl = new Map();
659
+ for (const rawWorkflow of workflows) {
660
+ if (!rawWorkflow || typeof rawWorkflow !== 'object') {
661
+ continue;
662
+ }
663
+ const workflow = rawWorkflow;
664
+ const controlId = String(workflow.control_id || '').trim();
665
+ const workflowId = String(workflow.workflow_id || '').trim();
666
+ if (!controlId || !workflowId) {
667
+ continue;
668
+ }
669
+ if (!workflowsByControl.has(controlId)) {
670
+ workflowsByControl.set(controlId, new Set());
671
+ }
672
+ workflowsByControl.get(controlId)?.add(workflowId);
673
+ if (workflow.status === 'approved') {
674
+ if (!approvedByControl.has(controlId)) {
675
+ approvedByControl.set(controlId, new Set());
676
+ }
677
+ for (const evidenceId of normalizeList(workflow.evidence_ids)) {
678
+ if (evidenceById.has(evidenceId)) {
679
+ approvedByControl.get(controlId)?.add(evidenceId);
680
+ }
681
+ }
682
+ }
683
+ }
684
+ const rows = [];
685
+ for (const control of controls) {
686
+ if (!control || typeof control !== 'object') {
687
+ continue;
688
+ }
689
+ const controlId = String(control.control_id || '').trim();
690
+ if (!controlId) {
691
+ continue;
692
+ }
693
+ const requiredTypes = Array.from(new Set(normalizeList(control.evidence_types))).sort();
694
+ const linkedEvidenceIds = Array.from(evidenceByControl.get(controlId) || new Set()).sort();
695
+ const approvedEvidenceIds = Array.from(approvedByControl.get(controlId) || new Set()).sort();
696
+ const collectedTypes = new Set();
697
+ for (const evidenceId of linkedEvidenceIds) {
698
+ const evidence = evidenceById.get(evidenceId);
699
+ if (!evidence) {
700
+ continue;
701
+ }
702
+ extractEvidenceTypes(evidence).forEach((value) => collectedTypes.add(value));
703
+ }
704
+ const collectedTypeList = Array.from(collectedTypes).sort();
705
+ const missingEvidenceTypes = requiredTypes.filter((item) => !collectedTypes.has(item));
706
+ const owner = String(control.owner || '').trim() || undefined;
707
+ const frequency = String(control.frequency || '').trim() || undefined;
708
+ const hasRequirements = requiredTypes.length > 0;
709
+ const hasApprovedEvidence = approvedEvidenceIds.length > 0;
710
+ const reportable = Boolean(owner && frequency && hasRequirements && hasApprovedEvidence && missingEvidenceTypes.length === 0);
711
+ const gaps = [];
712
+ if (!owner) {
713
+ gaps.push('missing_owner');
714
+ }
715
+ if (!frequency) {
716
+ gaps.push('missing_frequency');
717
+ }
718
+ if (!hasRequirements) {
719
+ gaps.push('missing_evidence_type_requirements');
720
+ }
721
+ if (linkedEvidenceIds.length === 0) {
722
+ gaps.push('missing_linked_evidence');
723
+ }
724
+ if (!hasApprovedEvidence) {
725
+ gaps.push('missing_approved_evidence');
726
+ }
727
+ if (missingEvidenceTypes.length > 0) {
728
+ gaps.push('missing_required_evidence_types');
729
+ }
730
+ rows.push({
731
+ control_id: controlId,
732
+ title: String(control.title || controlId),
733
+ clause: String(control.clause || '').trim() || undefined,
734
+ owner,
735
+ frequency,
736
+ required_evidence_types: requiredTypes,
737
+ evidence_types_collected: collectedTypeList,
738
+ missing_evidence_types: missingEvidenceTypes,
739
+ linked_evidence_ids: linkedEvidenceIds,
740
+ approved_evidence_ids: approvedEvidenceIds,
741
+ workflow_ids: Array.from(workflowsByControl.get(controlId) || new Set()).sort(),
742
+ status: reportable ? 'covered' : linkedEvidenceIds.length > 0 || approvedEvidenceIds.length > 0 ? 'partial' : 'gap',
743
+ reportable,
744
+ gaps,
745
+ });
746
+ }
747
+ const totalControls = rows.length;
748
+ const coveredControls = rows.filter((row) => row.reportable).length;
749
+ const partialControls = rows.filter((row) => row.status === 'partial').length;
750
+ const gapControls = rows.filter((row) => row.status === 'gap').length;
751
+ const coverageRatio = totalControls > 0 ? coveredControls / totalControls : 0;
752
+ const uncovered = rows.filter((row) => !row.reportable).map((row) => row.control_id);
753
+ const reportStandard = normalizeStandard(String(catalog.standard || options?.standard || 'ISO42001'));
754
+ return {
755
+ report_type: 'control_coverage',
756
+ generated_at: utcNow(),
757
+ catalog_id: catalog.catalog_id,
758
+ standard: catalog.standard,
759
+ version: catalog.version,
760
+ summary: {
761
+ total_controls: totalControls,
762
+ covered_controls: coveredControls,
763
+ partial_controls: partialControls,
764
+ gap_controls: gapControls,
765
+ coverage_ratio: Number(coverageRatio.toFixed(6)),
766
+ coverage_percent: Number((coverageRatio * 100).toFixed(2)),
767
+ target_coverage_ratio: Number(targetCoverage.toFixed(6)),
768
+ target_coverage_percent: Number((targetCoverage * 100).toFixed(2)),
769
+ target_met: coverageRatio >= targetCoverage,
770
+ },
771
+ controls: rows,
772
+ missing_workflow_modules: prioritizeMissingWorkflowModules(uncovered, reportStandard),
773
+ };
774
+ }
775
+ function buildWorkflowStatePayload(options) {
776
+ const catalog = resolveCatalog(options?.catalog || null, options?.standard);
777
+ const workflows = options?.workflows || Array.from(runtimeWorkflows.values());
778
+ const evidenceItems = options?.evidenceItems || Array.from(runtimeEvidence.values());
779
+ return {
780
+ state_type: 'control_workflow_state',
781
+ generated_at: utcNow(),
782
+ catalog_id: catalog.catalog_id,
783
+ standard: catalog.standard,
784
+ version: catalog.version,
785
+ workflows,
786
+ evidence_items: evidenceItems,
787
+ };
788
+ }
789
+ function exportWorkflowState(outputPath, options) {
790
+ const payload = buildWorkflowStatePayload(options);
791
+ fs.mkdirSync(path.dirname(outputPath), { recursive: true });
792
+ fs.writeFileSync(outputPath, JSON.stringify(payload, null, 2), 'utf-8');
793
+ return clone(payload);
794
+ }
795
+ function loadWorkflowState(filePath, options) {
796
+ const payload = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
797
+ const workflows = Array.isArray(payload.workflows) ? payload.workflows : [];
798
+ const evidenceItems = Array.isArray(payload.evidence_items) ? payload.evidence_items : [];
799
+ if (options?.replaceRuntime !== false) {
800
+ runtimeWorkflows = new Map();
801
+ runtimeEvidence = new Map();
802
+ (0, evidence_store_1.clearRuntimeEvidenceStore)();
803
+ for (const workflow of workflows) {
804
+ if (!workflow || typeof workflow !== 'object') {
805
+ continue;
806
+ }
807
+ const workflowId = String(workflow.workflow_id || '').trim();
808
+ if (!workflowId) {
809
+ continue;
810
+ }
811
+ runtimeWorkflows.set(workflowId, clone(workflow));
812
+ }
813
+ for (const evidence of evidenceItems) {
814
+ if (!evidence || typeof evidence !== 'object') {
815
+ continue;
816
+ }
817
+ const evidenceId = String(evidence.evidence_id || '').trim();
818
+ if (!evidenceId) {
819
+ continue;
820
+ }
821
+ runtimeEvidence.set(evidenceId, clone(evidence));
822
+ (0, evidence_store_1.recordRuntimeEvidence)(evidence);
823
+ }
824
+ }
825
+ return payload;
826
+ }