@blamejs/core 0.7.107 → 0.8.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 (100) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/NOTICE +17 -1
  3. package/README.md +4 -3
  4. package/index.js +15 -0
  5. package/lib/asyncapi-bindings.js +160 -0
  6. package/lib/asyncapi-traits.js +143 -0
  7. package/lib/asyncapi.js +531 -0
  8. package/lib/audit-sign.js +1 -1
  9. package/lib/audit.js +68 -2
  10. package/lib/auth/acr-vocabulary.js +265 -0
  11. package/lib/auth/auth-time-tracker.js +111 -0
  12. package/lib/auth/elevation-grant.js +306 -0
  13. package/lib/auth/jwt.js +13 -0
  14. package/lib/auth/lockout.js +16 -3
  15. package/lib/auth/oauth.js +15 -1
  16. package/lib/auth/password.js +22 -2
  17. package/lib/auth/sd-jwt-vc-issuer.js +2 -2
  18. package/lib/auth/sd-jwt-vc.js +7 -2
  19. package/lib/auth/step-up-policy.js +335 -0
  20. package/lib/auth/step-up.js +445 -0
  21. package/lib/break-glass.js +53 -14
  22. package/lib/cache-redis.js +1 -1
  23. package/lib/cache.js +6 -1
  24. package/lib/cli.js +3 -3
  25. package/lib/cluster.js +24 -1
  26. package/lib/compliance-ai-act-logging.js +190 -0
  27. package/lib/compliance-ai-act-prohibited.js +205 -0
  28. package/lib/compliance-ai-act-risk.js +189 -0
  29. package/lib/compliance-ai-act-transparency.js +200 -0
  30. package/lib/compliance-ai-act.js +558 -0
  31. package/lib/compliance.js +12 -2
  32. package/lib/config-drift.js +2 -2
  33. package/lib/crypto-field.js +21 -1
  34. package/lib/crypto.js +114 -1
  35. package/lib/db.js +35 -4
  36. package/lib/dev.js +30 -3
  37. package/lib/dual-control.js +19 -1
  38. package/lib/external-db.js +10 -0
  39. package/lib/file-upload.js +30 -3
  40. package/lib/flag-cache.js +136 -0
  41. package/lib/flag-evaluation-context.js +135 -0
  42. package/lib/flag-providers.js +279 -0
  43. package/lib/flag-targeting.js +210 -0
  44. package/lib/flag.js +284 -0
  45. package/lib/guard-all.js +33 -16
  46. package/lib/guard-csv.js +16 -2
  47. package/lib/guard-html.js +35 -0
  48. package/lib/guard-svg.js +20 -0
  49. package/lib/http-client.js +57 -11
  50. package/lib/inbox.js +391 -0
  51. package/lib/log-stream-syslog.js +8 -0
  52. package/lib/log-stream.js +1 -1
  53. package/lib/mail-arc-sign.js +372 -0
  54. package/lib/mail-auth.js +2 -0
  55. package/lib/mail.js +40 -0
  56. package/lib/middleware/ai-act-disclosure.js +166 -0
  57. package/lib/middleware/asyncapi-serve.js +136 -0
  58. package/lib/middleware/attach-user.js +25 -2
  59. package/lib/middleware/bearer-auth.js +71 -6
  60. package/lib/middleware/body-parser.js +13 -0
  61. package/lib/middleware/cors.js +10 -0
  62. package/lib/middleware/csrf-protect.js +34 -3
  63. package/lib/middleware/dpop.js +3 -3
  64. package/lib/middleware/flag-context.js +76 -0
  65. package/lib/middleware/host-allowlist.js +1 -1
  66. package/lib/middleware/index.js +15 -0
  67. package/lib/middleware/openapi-serve.js +143 -0
  68. package/lib/middleware/require-aal.js +2 -2
  69. package/lib/middleware/require-step-up.js +186 -0
  70. package/lib/middleware/trace-propagate.js +1 -1
  71. package/lib/mtls-ca.js +23 -29
  72. package/lib/mtls-engine-default.js +21 -1
  73. package/lib/network-tls.js +21 -6
  74. package/lib/object-store/sigv4-bucket-ops.js +41 -0
  75. package/lib/observability-otlp-exporter.js +35 -2
  76. package/lib/openapi-paths-builder.js +248 -0
  77. package/lib/openapi-schema-walk.js +192 -0
  78. package/lib/openapi-security.js +169 -0
  79. package/lib/openapi-yaml.js +154 -0
  80. package/lib/openapi.js +443 -0
  81. package/lib/outbox.js +3 -3
  82. package/lib/permissions.js +10 -1
  83. package/lib/pqc-agent.js +22 -1
  84. package/lib/pqc-software.js +195 -0
  85. package/lib/pubsub.js +8 -4
  86. package/lib/redact.js +26 -1
  87. package/lib/retention.js +26 -0
  88. package/lib/router.js +1 -0
  89. package/lib/scheduler.js +57 -1
  90. package/lib/session.js +3 -3
  91. package/lib/ssrf-guard.js +19 -4
  92. package/lib/static.js +12 -0
  93. package/lib/totp.js +16 -0
  94. package/lib/vault/index.js +3 -0
  95. package/lib/vault-aad.js +259 -0
  96. package/lib/vendor/MANIFEST.json +29 -0
  97. package/lib/vendor/noble-post-quantum.cjs +18 -0
  98. package/lib/ws-client.js +978 -0
  99. package/package.json +1 -1
  100. package/sbom.cyclonedx.json +6 -6
@@ -0,0 +1,558 @@
1
+ "use strict";
2
+ /**
3
+ * b.compliance.aiAct — EU AI Act (Regulation (EU) 2024/1689) compliance
4
+ * primitive.
5
+ *
6
+ * Public surface (b.compliance.aiAct.*):
7
+ *
8
+ * .classify(systemDescription)
9
+ * → { tier, prohibitedHits[], annexIIIHits[], obligations[] }
10
+ *
11
+ * .prohibited.{listPractices,listIds,getPractice,classify}
12
+ * .risk.{listAnnexIII,getAnnexIII,classifyAnnexIII,isHighRisk,obligationsFor}
13
+ * .transparency.{banner,htmlBanner,watermark,jsonLdDisclosure,metaTags}
14
+ * .logging.{buildEvent,emit,logEvent,retentionFloorMs,loggerFor}
15
+ * .gpai.{classify, listObligations} (Article 51-55)
16
+ * .deadlines (Article 113)
17
+ * .articleObligations(article)
18
+ *
19
+ * Per the no-MVP rule: every spec'd surface above is implemented; the
20
+ * five Annex III §1-8 use-cases plus the eight Article 5 prohibited
21
+ * practices plus the four Article 50 transparency obligations all ship
22
+ * here. GPAI obligations (Article 51-55) ship as a sibling helper.
23
+ *
24
+ * Operators integrate via the framework's compliance-posture flow:
25
+ *
26
+ * var assessment = b.compliance.aiAct.classify({
27
+ * purpose: "credit-scoring",
28
+ * deployContext: "consumer-finance",
29
+ * deployerType: "private-company",
30
+ * });
31
+ * // assessment.tier === "high-risk"
32
+ * // assessment.annexIIIHits === ["essential-services"]
33
+ * // assessment.obligations === [...Art-9..15 obligations]
34
+ *
35
+ * The framework does NOT perform legal interpretation — operators
36
+ * remain responsible for engaging counsel before deployment.
37
+ */
38
+
39
+ var validateOpts = require("./validate-opts");
40
+ var lazyRequire = require("./lazy-require");
41
+ var { ComplianceError } = require("./framework-error");
42
+
43
+ var prohibited = require("./compliance-ai-act-prohibited");
44
+ var risk = require("./compliance-ai-act-risk");
45
+ var transparency = require("./compliance-ai-act-transparency");
46
+ var logging = require("./compliance-ai-act-logging");
47
+ var audit = lazyRequire(function () { return require("./audit"); });
48
+
49
+ // ---- Article 113 deadline calendar ----
50
+ //
51
+ // Per Art. 113, different parts of the regulation phase in:
52
+ //
53
+ // 2024-08-01 — Regulation enters into force
54
+ // 2026-02-02 — Chapters I (general) + II (prohibited practices)
55
+ // become applicable
56
+ // 2026-08-02 — Chapter V (general-purpose AI) + Chapter X-XI obligations
57
+ // applicable; transparency obligations applicable
58
+ // 2027-08-02 — Chapter III (high-risk AI systems) become applicable
59
+ // for products covered by Art. 6(1) Annex I third-party
60
+ // conformity assessment
61
+ // 2027-08-02 — Member states designate competent authorities
62
+
63
+ var DEADLINES = Object.freeze({
64
+ enteredForce: "2024-08-01",
65
+ prohibitedPractices: "2026-02-02",
66
+ generalPurposeAI: "2026-08-02",
67
+ transparencyObligations: "2026-08-02",
68
+ highRiskAnnexIII: "2027-08-02",
69
+ highRiskAnnexIProducts: "2027-08-02",
70
+ });
71
+
72
+ // ---- Article 51-55 — General-Purpose AI Models ----
73
+
74
+ var GPAI_OBLIGATIONS = Object.freeze([
75
+ Object.freeze({
76
+ article: "Art. 53(1)(a)",
77
+ title: "Technical documentation",
78
+ description: "Provider keeps up-to-date technical documentation including training and testing process, evaluation results, info per Annex XI.",
79
+ }),
80
+ Object.freeze({
81
+ article: "Art. 53(1)(b)",
82
+ title: "Information for downstream providers",
83
+ description: "Provider draws up information / documentation to enable downstream providers to comply with their obligations and to understand the model's capabilities / limitations.",
84
+ }),
85
+ Object.freeze({
86
+ article: "Art. 53(1)(c)",
87
+ title: "Copyright policy",
88
+ description: "Provider puts in place a policy to comply with EU copyright law, in particular to identify and respect machine-readable rights reservations under Art. 4(3) Directive 2019/790.",
89
+ }),
90
+ Object.freeze({
91
+ article: "Art. 53(1)(d)",
92
+ title: "Training-content public summary",
93
+ description: "Provider draws up and makes publicly available a sufficiently detailed summary of the content used for training the GPAI model, per a template provided by the AI Office.",
94
+ }),
95
+ Object.freeze({
96
+ article: "Art. 55",
97
+ title: "Systemic-risk obligations (FLOP threshold)",
98
+ description: "GPAI models with systemic risk (cumulative training compute > 10^25 FLOP per Art. 51(2)) MUST: perform model evaluation including adversarial testing, assess and mitigate possible Union-level systemic risks, track and report serious incidents to the AI Office, ensure adequate cybersecurity.",
99
+ }),
100
+ ]);
101
+
102
+ function gpaiClassify(opts) {
103
+ if (!opts || typeof opts !== "object") return { isGpai: false, isSystemicRisk: false };
104
+ var isGpai = opts.kind === "gpai" ||
105
+ (typeof opts.modalities === "object" && opts.generalPurpose === true);
106
+ var isSystemicRisk = false;
107
+ // Art. 51(2) — presumption of systemic risk if cumulative training
108
+ // compute > 10^25 FLOP.
109
+ if (typeof opts.trainingFlops === "number" && opts.trainingFlops >= 1e25) {
110
+ isSystemicRisk = true;
111
+ }
112
+ if (opts.designatedSystemicRisk === true) {
113
+ isSystemicRisk = true;
114
+ }
115
+ return {
116
+ isGpai: isGpai,
117
+ isSystemicRisk: isSystemicRisk,
118
+ obligations: isGpai ? listGpaiObligations(isSystemicRisk) : [],
119
+ };
120
+ }
121
+
122
+ function listGpaiObligations(includeSystemic) {
123
+ var out = [];
124
+ for (var i = 0; i < GPAI_OBLIGATIONS.length; i += 1) {
125
+ var entry = GPAI_OBLIGATIONS[i];
126
+ if (entry.article === "Art. 55") {
127
+ if (includeSystemic) out.push(entry);
128
+ } else {
129
+ out.push(entry);
130
+ }
131
+ }
132
+ return out;
133
+ }
134
+
135
+ // ---- Article catalog (cross-reference helper) ----
136
+ var ARTICLE_OBLIGATIONS = Object.freeze({
137
+ "Art. 9": Object.freeze({
138
+ title: "Risk-management system",
139
+ summary: "Iterative process throughout the AI system lifecycle: identification + analysis of foreseeable risks, mitigation measures, residual-risk acceptance, post-market evaluation.",
140
+ }),
141
+ "Art. 10": Object.freeze({
142
+ title: "Data and data governance",
143
+ summary: "Training, validation, and testing datasets relevant, sufficiently representative, free of errors / complete; data-governance practices including bias examination + mitigation.",
144
+ }),
145
+ "Art. 11": Object.freeze({
146
+ title: "Technical documentation",
147
+ summary: "Drawn up before placement on market; includes Annex IV elements (general description, design specifications, monitoring + functioning, risk-management procedure, etc.).",
148
+ }),
149
+ "Art. 12": Object.freeze({
150
+ title: "Record-keeping (logging)",
151
+ summary: "Automatic recording of events over the system's lifetime; for biometric ID systems, minimum logged fields per Art. 12(3).",
152
+ }),
153
+ "Art. 13": Object.freeze({
154
+ title: "Transparency and information to deployers",
155
+ summary: "Designed so deployers can interpret + use output appropriately; instructions for use including capabilities + limitations + known foreseeable misuse.",
156
+ }),
157
+ "Art. 14": Object.freeze({
158
+ title: "Human oversight",
159
+ summary: "Effective human oversight by natural persons during use, including ability to intervene, decide not to use the system, or override the output.",
160
+ }),
161
+ "Art. 15": Object.freeze({
162
+ title: "Accuracy, robustness and cybersecurity",
163
+ summary: "Appropriate accuracy / robustness / cybersecurity throughout the lifecycle; declaration of accuracy levels and metrics in instructions for use.",
164
+ }),
165
+ "Art. 27": Object.freeze({
166
+ title: "Fundamental rights impact assessment",
167
+ summary: "Required for deployers using high-risk AI in essential-services / law-enforcement / migration contexts; documents who is using, purpose, individuals affected, risks of harm, governance measures.",
168
+ }),
169
+ "Art. 50": Object.freeze({
170
+ title: "Transparency obligations",
171
+ summary: "Disclosure to natural persons that they are interacting with AI, that content is AI-generated, that emotion recognition / biometric categorisation is in use, that media is a deep fake.",
172
+ }),
173
+ "Art. 53": Object.freeze({
174
+ title: "GPAI provider obligations",
175
+ summary: "Technical documentation, downstream-info, copyright policy, training-content public summary.",
176
+ }),
177
+ "Art. 55": Object.freeze({
178
+ title: "GPAI systemic-risk obligations",
179
+ summary: "Adversarial evaluation, systemic-risk assessment + mitigation, serious-incident reporting, cybersecurity.",
180
+ }),
181
+ });
182
+
183
+ function articleObligations(article) {
184
+ if (typeof article !== "string") return null;
185
+ if (Object.prototype.hasOwnProperty.call(ARTICLE_OBLIGATIONS, article)) {
186
+ return ARTICLE_OBLIGATIONS[article];
187
+ }
188
+ return null;
189
+ }
190
+
191
+ function listArticles() {
192
+ return Object.keys(ARTICLE_OBLIGATIONS).slice();
193
+ }
194
+
195
+ // ---- top-level classifier ----
196
+
197
+ function classify(systemDescription) {
198
+ if (!systemDescription || typeof systemDescription !== "object") {
199
+ throw new ComplianceError("compliance-ai-act/bad-input",
200
+ "compliance.aiAct.classify: systemDescription must be an object — got " +
201
+ typeof systemDescription);
202
+ }
203
+
204
+ var prohibitedHits = prohibited.classify(systemDescription);
205
+ if (prohibitedHits.length > 0) {
206
+ return {
207
+ tier: "prohibited",
208
+ prohibitedHits: prohibitedHits,
209
+ annexIIIHits: [],
210
+ obligations: [],
211
+ action: "do-not-deploy",
212
+ legalReference: prohibitedHits.map(function (id) {
213
+ var p = prohibited.getPractice(id);
214
+ return p ? p.article : null;
215
+ }).filter(Boolean),
216
+ };
217
+ }
218
+
219
+ var annexIIIHits = [];
220
+ if (typeof systemDescription.purpose === "string") {
221
+ annexIIIHits = risk.classifyAnnexIII(systemDescription.purpose);
222
+ }
223
+ if (systemDescription.annexIIIRow && Array.isArray(systemDescription.annexIIIRow)) {
224
+ for (var i = 0; i < systemDescription.annexIIIRow.length; i += 1) {
225
+ if (annexIIIHits.indexOf(systemDescription.annexIIIRow[i]) === -1) {
226
+ annexIIIHits.push(systemDescription.annexIIIRow[i]);
227
+ }
228
+ }
229
+ }
230
+
231
+ var isHighRisk = annexIIIHits.length > 0 ||
232
+ (systemDescription.safetyComponentForRegulatedProduct === true &&
233
+ systemDescription.requiresThirdPartyConformity === true);
234
+
235
+ if (isHighRisk) {
236
+ var obligations = [];
237
+ var seen = Object.create(null);
238
+ for (var j = 0; j < annexIIIHits.length; j += 1) {
239
+ var rowObs = risk.obligationsFor(annexIIIHits[j]);
240
+ for (var k = 0; k < rowObs.length; k += 1) {
241
+ if (!seen[rowObs[k]]) { seen[rowObs[k]] = true; obligations.push(rowObs[k]); }
242
+ }
243
+ }
244
+ return {
245
+ tier: "high-risk",
246
+ prohibitedHits: [],
247
+ annexIIIHits: annexIIIHits,
248
+ obligations: obligations,
249
+ action: "deploy-with-art-9-15-controls",
250
+ legalReference: ["Art. 6(2)", "Annex III"],
251
+ };
252
+ }
253
+
254
+ // GPAI?
255
+ var gpai = gpaiClassify(systemDescription);
256
+ if (gpai.isGpai) {
257
+ return {
258
+ tier: "general-purpose",
259
+ prohibitedHits: [],
260
+ annexIIIHits: [],
261
+ obligations: gpai.obligations.map(function (o) { return o.article; }),
262
+ isSystemicRisk: gpai.isSystemicRisk,
263
+ action: gpai.isSystemicRisk ? "deploy-with-art-53-55-controls" :
264
+ "deploy-with-art-53-controls",
265
+ legalReference: gpai.isSystemicRisk ? ["Art. 51", "Art. 53", "Art. 55"]
266
+ : ["Art. 53"],
267
+ };
268
+ }
269
+
270
+ // Limited-risk transparency-only systems
271
+ if (systemDescription.directlyInteractsWithUsers === true ||
272
+ systemDescription.generatesSyntheticContent === true ||
273
+ systemDescription.usesEmotionRecognition === true ||
274
+ systemDescription.usesBiometricCategorisation === true ||
275
+ systemDescription.generatesDeepFake === true) {
276
+ return {
277
+ tier: "limited-risk",
278
+ prohibitedHits: [],
279
+ annexIIIHits: [],
280
+ obligations: ["Art. 50"],
281
+ action: "deploy-with-art-50-disclosures",
282
+ legalReference: ["Art. 50"],
283
+ };
284
+ }
285
+
286
+ return {
287
+ tier: "minimal-risk",
288
+ prohibitedHits: [],
289
+ annexIIIHits: [],
290
+ obligations: [],
291
+ action: "deploy-no-specific-obligations",
292
+ legalReference: [],
293
+ };
294
+ }
295
+
296
+ // Operator-side hook: emit an audit event whenever a classification is
297
+ // run on the production path. Useful for compliance reviewers tracing
298
+ // which system was classified at which decision point.
299
+ function emitClassificationAudit(systemDescription, result) {
300
+ try {
301
+ audit().safeEmit({
302
+ action: "compliance.aiact.classified",
303
+ outcome: result.tier === "prohibited" ? "denied" : "success",
304
+ actor: { systemId: systemDescription.systemId || null,
305
+ deployer: systemDescription.deployerName || null },
306
+ metadata: {
307
+ tier: result.tier,
308
+ prohibitedHits: result.prohibitedHits,
309
+ annexIIIHits: result.annexIIIHits,
310
+ obligationCount: result.obligations.length,
311
+ },
312
+ });
313
+ } catch (_e) { /* drop-silent */ }
314
+ }
315
+
316
+ // Operator helper that builds the Annex IV technical-documentation
317
+ // scaffold. Returns a sectioned document the operator fills in over
318
+ // the deployment lifecycle. Validated against minimum-required keys at
319
+ // generation time so an operator can't accidentally omit a section.
320
+ function annexIVScaffold(opts) {
321
+ opts = opts || {};
322
+ validateOpts(opts, [
323
+ "systemId", "deployerName", "providerName", "intendedPurpose",
324
+ "annexIIIRow", "deploymentScope", "version",
325
+ ], "compliance.aiAct.annexIVScaffold");
326
+ validateOpts.requireNonEmptyString(opts.systemId,
327
+ "annexIVScaffold: systemId", ComplianceError, "compliance-ai-act/bad-input");
328
+
329
+ return {
330
+ "@context": "https://blamejs.com/schemas/ai-act-annex-iv/v1",
331
+ aiActArticle: "Annex IV",
332
+ sections: {
333
+ "1-general-description": {
334
+ title: "General description of the AI system",
335
+ required: ["systemId", "intendedPurpose", "annexIIIRow", "version", "providerName", "deployerName"],
336
+ provided: {
337
+ systemId: opts.systemId,
338
+ intendedPurpose: opts.intendedPurpose || null,
339
+ annexIIIRow: opts.annexIIIRow || null,
340
+ version: opts.version || null,
341
+ providerName: opts.providerName || null,
342
+ deployerName: opts.deployerName || null,
343
+ deploymentScope: opts.deploymentScope || null,
344
+ },
345
+ },
346
+ "2-detailed-description": {
347
+ title: "Detailed description of the elements and process for development",
348
+ required: ["modelArchitecture", "trainingDataDescription", "preProcessing"],
349
+ provided: null,
350
+ },
351
+ "3-monitoring-functioning": {
352
+ title: "Detailed information about monitoring + functioning + control",
353
+ required: ["accuracyMetrics", "robustnessMetrics", "monitoringMechanism"],
354
+ provided: null,
355
+ },
356
+ "4-risk-management": {
357
+ title: "Description of the risk-management system per Art. 9",
358
+ required: ["riskRegister", "mitigationMeasures", "residualRiskAcceptance"],
359
+ provided: null,
360
+ },
361
+ "5-changes": {
362
+ title: "Description of any changes made to the system through its lifecycle",
363
+ required: ["changeLog"],
364
+ provided: null,
365
+ },
366
+ "6-list-of-harmonised-standards": {
367
+ title: "List of harmonised standards applied",
368
+ required: ["standardsList"],
369
+ provided: null,
370
+ },
371
+ "7-eu-declaration-of-conformity": {
372
+ title: "EU declaration of conformity per Art. 47 + Annex V",
373
+ required: ["declarationDocument"],
374
+ provided: null,
375
+ },
376
+ "8-post-market-monitoring": {
377
+ title: "Description of the post-market monitoring system per Art. 72",
378
+ required: ["monitoringPlan"],
379
+ provided: null,
380
+ },
381
+ },
382
+ };
383
+ }
384
+
385
+ // Operator-actionable checklist derived from a classify() result. Each
386
+ // entry carries a status ("required" | "conditional" | "deferred") +
387
+ // the article reference + a short next-step description.
388
+ function deployerChecklist(assessment) {
389
+ if (!assessment || typeof assessment !== "object") {
390
+ throw new ComplianceError("compliance-ai-act/bad-checklist-input",
391
+ "deployerChecklist: assessment must be a classify() result object");
392
+ }
393
+ var items = [];
394
+ if (assessment.tier === "prohibited") {
395
+ items.push({
396
+ status: "required",
397
+ action: "do-not-deploy",
398
+ article: "Art. 5",
399
+ description: "System falls under Art. 5 prohibited practices — do not deploy in EU market.",
400
+ });
401
+ return items;
402
+ }
403
+ if (assessment.tier === "high-risk") {
404
+ items.push({
405
+ status: "required",
406
+ action: "engage-conformity-assessment",
407
+ article: "Art. 16-26",
408
+ description: "Engage notified body for third-party conformity assessment per Annex VII (or self-assess for systems where self-assessment is permitted under Art. 43).",
409
+ });
410
+ items.push({
411
+ status: "required",
412
+ action: "draw-up-technical-documentation",
413
+ article: "Art. 11 + Annex IV",
414
+ description: "Prepare Annex IV technical documentation. Use b.compliance.aiAct.annexIVScaffold().",
415
+ });
416
+ items.push({
417
+ status: "required",
418
+ action: "establish-risk-management-system",
419
+ article: "Art. 9",
420
+ description: "Iterative risk-management system over the system lifecycle.",
421
+ });
422
+ items.push({
423
+ status: "required",
424
+ action: "data-governance",
425
+ article: "Art. 10",
426
+ description: "Training / validation / testing dataset governance including bias examination.",
427
+ });
428
+ items.push({
429
+ status: "required",
430
+ action: "automatic-logging",
431
+ article: "Art. 12",
432
+ description: "Implement automatic logging via b.compliance.aiAct.logging.loggerFor().",
433
+ });
434
+ items.push({
435
+ status: "required",
436
+ action: "human-oversight",
437
+ article: "Art. 14",
438
+ description: "Effective human oversight by natural persons during use; ability to intervene / override.",
439
+ });
440
+ items.push({
441
+ status: "required",
442
+ action: "accuracy-robustness-cyber",
443
+ article: "Art. 15",
444
+ description: "Declare accuracy / robustness / cybersecurity levels in instructions for use.",
445
+ });
446
+ if (assessment.obligations.indexOf("fundamental-rights-impact-assessment-art-27") !== -1) {
447
+ items.push({
448
+ status: "required",
449
+ action: "fundamental-rights-impact-assessment",
450
+ article: "Art. 27",
451
+ description: "Conduct FRIA before first deployment; documents purpose, individuals affected, foreseeable harms, mitigation.",
452
+ });
453
+ }
454
+ items.push({
455
+ status: "required",
456
+ action: "register-eu-database",
457
+ article: "Art. 71",
458
+ description: "Register the high-risk AI system in the EU database before placing on market or putting into service.",
459
+ });
460
+ items.push({
461
+ status: "required",
462
+ action: "post-market-monitoring",
463
+ article: "Art. 72",
464
+ description: "Establish a post-market monitoring system commensurate with the AI risks.",
465
+ });
466
+ return items;
467
+ }
468
+ if (assessment.tier === "limited-risk") {
469
+ items.push({
470
+ status: "required",
471
+ action: "transparency-disclosure",
472
+ article: "Art. 50",
473
+ description: "Mount b.middleware.aiActDisclosure({ kind: ... }) on routes that interact with users / generate synthetic content / use emotion or biometric categorisation.",
474
+ });
475
+ return items;
476
+ }
477
+ if (assessment.tier === "general-purpose") {
478
+ items.push({
479
+ status: "required",
480
+ action: "gpai-technical-documentation",
481
+ article: "Art. 53(1)(a) + Annex XI",
482
+ description: "Maintain up-to-date technical documentation incl. training process, evaluation results, capabilities / limitations.",
483
+ });
484
+ items.push({
485
+ status: "required",
486
+ action: "downstream-info",
487
+ article: "Art. 53(1)(b)",
488
+ description: "Provide info to downstream providers to enable their compliance.",
489
+ });
490
+ items.push({
491
+ status: "required",
492
+ action: "copyright-policy",
493
+ article: "Art. 53(1)(c)",
494
+ description: "Adopt a policy compliant with EU copyright law including respecting Art. 4(3) Directive 2019/790 rights reservations.",
495
+ });
496
+ items.push({
497
+ status: "required",
498
+ action: "training-content-summary",
499
+ article: "Art. 53(1)(d)",
500
+ description: "Publish a sufficiently detailed summary of training content per the AI Office template.",
501
+ });
502
+ if (assessment.isSystemicRisk === true) {
503
+ items.push({
504
+ status: "required",
505
+ action: "adversarial-evaluation",
506
+ article: "Art. 55",
507
+ description: "Perform model evaluation including adversarial testing to identify systemic risk.",
508
+ });
509
+ items.push({
510
+ status: "required",
511
+ action: "systemic-risk-mitigation",
512
+ article: "Art. 55",
513
+ description: "Assess and mitigate possible Union-level systemic risks.",
514
+ });
515
+ items.push({
516
+ status: "required",
517
+ action: "incident-reporting",
518
+ article: "Art. 55",
519
+ description: "Track and report serious incidents + corrective measures to the AI Office.",
520
+ });
521
+ items.push({
522
+ status: "required",
523
+ action: "cybersecurity",
524
+ article: "Art. 55",
525
+ description: "Ensure adequate cybersecurity protection of the model and physical infrastructure.",
526
+ });
527
+ }
528
+ return items;
529
+ }
530
+ // minimal-risk
531
+ items.push({
532
+ status: "deferred",
533
+ action: "voluntary-codes",
534
+ article: "Art. 95",
535
+ description: "Consider adoption of voluntary codes of conduct for minimal-risk AI per Art. 95.",
536
+ });
537
+ return items;
538
+ }
539
+
540
+ module.exports = {
541
+ classify: classify,
542
+ deployerChecklist: deployerChecklist,
543
+ prohibited: prohibited,
544
+ risk: risk,
545
+ transparency: transparency,
546
+ logging: logging,
547
+ gpai: {
548
+ classify: gpaiClassify,
549
+ listObligations: listGpaiObligations,
550
+ OBLIGATIONS: GPAI_OBLIGATIONS,
551
+ },
552
+ articleObligations: articleObligations,
553
+ listArticles: listArticles,
554
+ ARTICLE_OBLIGATIONS: ARTICLE_OBLIGATIONS,
555
+ DEADLINES: DEADLINES,
556
+ emitClassificationAudit: emitClassificationAudit,
557
+ annexIVScaffold: annexIVScaffold,
558
+ };
package/lib/compliance.js CHANGED
@@ -30,6 +30,7 @@
30
30
 
31
31
  var lazyRequire = require("./lazy-require");
32
32
  var sanctions = require("./compliance-sanctions");
33
+ var aiAct = require("./compliance-ai-act");
33
34
  var { ComplianceError } = require("./framework-error");
34
35
 
35
36
  var audit = lazyRequire(function () { return require("./audit"); });
@@ -66,11 +67,11 @@ var KNOWN_POSTURES = Object.freeze([
66
67
 
67
68
  var STATE = { posture: null, setAt: null };
68
69
 
69
- function _emitAudit(action, metadata) {
70
+ function _emitAudit(action, metadata, outcome) {
70
71
  try {
71
72
  audit().safeEmit({
72
73
  action: action,
73
- outcome: "success",
74
+ outcome: outcome || "success",
74
75
  metadata: metadata,
75
76
  });
76
77
  } catch (_e) { /* audit best-effort */ }
@@ -83,11 +84,19 @@ function set(posture) {
83
84
  JSON.stringify(posture));
84
85
  }
85
86
  if (KNOWN_POSTURES.indexOf(posture) === -1) {
87
+ _emitAudit("compliance.posture.set_rejected",
88
+ { reason: "unknown-posture", posture: posture }, "denied");
86
89
  throw new ComplianceError("compliance/unknown-posture",
87
90
  "compliance.set: unknown posture '" + posture + "'; expected one of " +
88
91
  KNOWN_POSTURES.join(", "));
89
92
  }
90
93
  if (STATE.posture && STATE.posture !== posture) {
94
+ // Audit the rejection so an attacker (or operator misconfig) trying
95
+ // to downgrade an already-set posture produces a chain row
96
+ // operators can alert on.
97
+ _emitAudit("compliance.posture.set_rejected",
98
+ { reason: "already-set", current: STATE.posture, attempted: posture },
99
+ "denied");
91
100
  throw new ComplianceError("compliance/already-set",
92
101
  "compliance.set: posture is already '" + STATE.posture + "' (set at " +
93
102
  new Date(STATE.setAt).toISOString() + "). Runtime switches are " +
@@ -307,6 +316,7 @@ module.exports = {
307
316
  posturesByJurisdiction: posturesByJurisdiction,
308
317
  list: list,
309
318
  sanctions: sanctions,
319
+ aiAct: aiAct,
310
320
  KNOWN_POSTURES: KNOWN_POSTURES,
311
321
  REGIME_MAP: REGIME_MAP,
312
322
  ComplianceError: ComplianceError,
@@ -193,7 +193,7 @@ function create(opts) {
193
193
  if (existing && existing.unreadable) {
194
194
  _emit("config.baseline.unreadable",
195
195
  { sidecar: sidecarPath, reason: "sidecar present but malformed or wrong version" },
196
- "warning");
196
+ "failure");
197
197
  _writeSidecar(snapshot, newDigest);
198
198
  return { signed: true, drifted: false, tamper: false, previousAt: null, reason: "sidecar-unreadable-rewritten" };
199
199
  }
@@ -260,7 +260,7 @@ function create(opts) {
260
260
  keysRemoved: diff.removed,
261
261
  severity: severity,
262
262
  },
263
- severity === "high" ? "failure" : "warning");
263
+ severity === "high" ? "failure" : "success");
264
264
  _writeSidecar(snapshot, newDigest);
265
265
  return {
266
266
  signed: true,
@@ -116,7 +116,27 @@ function unsealRow(table, row) {
116
116
  for (var i = 0; i < s.sealedFields.length; i++) {
117
117
  var field = s.sealedFields[i];
118
118
  if (out[field]) {
119
- var unsealed = vault.unseal(out[field]);
119
+ var unsealed;
120
+ try {
121
+ unsealed = vault.unseal(out[field]);
122
+ } catch (e) {
123
+ // A DB-write attacker who can write `vault:<crafted>`
124
+ // payloads to sealed columns can force ML-KEM
125
+ // decapsulation on attacker-controlled bytes via this read
126
+ // path. Surface the failure as a chain row so operators
127
+ // alert on burst patterns; null the field so downstream
128
+ // code sees "no value" instead of crashing the request.
129
+ try {
130
+ var auditMod = require("./audit"); // allow:inline-require — circular-load defense
131
+ auditMod.safeEmit({
132
+ action: "system.crypto.unseal_failed",
133
+ outcome: "failure",
134
+ metadata: { table: table, field: field, rowId: row && row._id || null,
135
+ reason: (e && e.message) || String(e) },
136
+ });
137
+ } catch (_e) { /* drop-silent */ }
138
+ unsealed = null;
139
+ }
120
140
  // If the value wasn't actually sealed, vault.unseal returns the input
121
141
  // unchanged — keep the original.
122
142
  out[field] = unsealed !== undefined && unsealed !== null ? unsealed : out[field];