@blamejs/core 0.7.107 → 0.8.0
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/CHANGELOG.md +17 -1
- package/NOTICE +17 -1
- package/README.md +4 -3
- package/index.js +15 -0
- package/lib/asyncapi-bindings.js +160 -0
- package/lib/asyncapi-traits.js +143 -0
- package/lib/asyncapi.js +531 -0
- package/lib/audit.js +6 -0
- package/lib/auth/acr-vocabulary.js +265 -0
- package/lib/auth/auth-time-tracker.js +111 -0
- package/lib/auth/elevation-grant.js +306 -0
- package/lib/auth/step-up-policy.js +335 -0
- package/lib/auth/step-up.js +445 -0
- package/lib/compliance-ai-act-logging.js +186 -0
- package/lib/compliance-ai-act-prohibited.js +205 -0
- package/lib/compliance-ai-act-risk.js +189 -0
- package/lib/compliance-ai-act-transparency.js +200 -0
- package/lib/compliance-ai-act.js +558 -0
- package/lib/compliance.js +2 -0
- package/lib/crypto.js +32 -0
- package/lib/flag-cache.js +136 -0
- package/lib/flag-evaluation-context.js +135 -0
- package/lib/flag-providers.js +279 -0
- package/lib/flag-targeting.js +210 -0
- package/lib/flag.js +284 -0
- package/lib/inbox.js +367 -0
- package/lib/mail-arc-sign.js +372 -0
- package/lib/mail-auth.js +2 -0
- package/lib/middleware/ai-act-disclosure.js +166 -0
- package/lib/middleware/asyncapi-serve.js +136 -0
- package/lib/middleware/flag-context.js +76 -0
- package/lib/middleware/index.js +15 -0
- package/lib/middleware/openapi-serve.js +143 -0
- package/lib/middleware/require-step-up.js +186 -0
- package/lib/openapi-paths-builder.js +248 -0
- package/lib/openapi-schema-walk.js +192 -0
- package/lib/openapi-security.js +169 -0
- package/lib/openapi-yaml.js +154 -0
- package/lib/openapi.js +443 -0
- package/lib/pqc-software.js +195 -0
- package/lib/vault/index.js +3 -0
- package/lib/vault-aad.js +259 -0
- package/lib/vendor/MANIFEST.json +29 -0
- package/lib/vendor/noble-post-quantum.cjs +18 -0
- package/lib/ws-client.js +829 -0
- package/package.json +1 -1
- 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"); });
|
|
@@ -307,6 +308,7 @@ module.exports = {
|
|
|
307
308
|
posturesByJurisdiction: posturesByJurisdiction,
|
|
308
309
|
list: list,
|
|
309
310
|
sanctions: sanctions,
|
|
311
|
+
aiAct: aiAct,
|
|
310
312
|
KNOWN_POSTURES: KNOWN_POSTURES,
|
|
311
313
|
REGIME_MAP: REGIME_MAP,
|
|
312
314
|
ComplianceError: ComplianceError,
|
package/lib/crypto.js
CHANGED
|
@@ -361,6 +361,37 @@ function encryptMlkem768X25519(plaintext, recipient) {
|
|
|
361
361
|
]).toString("base64");
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
+
// Symmetric named-pair to encryptMlkem768X25519. Operators wiring the
|
|
365
|
+
// IETF / Cloudflare / Chrome TLS-1.3 hybrid (codepoint 0x11EC) want
|
|
366
|
+
// the encrypt + decrypt halves under symmetric, discoverable names.
|
|
367
|
+
//
|
|
368
|
+
// The generic b.crypto.decrypt already dispatches by KEM ID and
|
|
369
|
+
// handles ML_KEM_768_X25519 envelopes correctly; this helper REJECTS
|
|
370
|
+
// any other KEM ID at the head, so an operator who calls
|
|
371
|
+
// decryptMlkem768X25519 with a ciphertext sealed under a different
|
|
372
|
+
// algorithm gets a clear error rather than the generic "unsupported
|
|
373
|
+
// KEM ID" path.
|
|
374
|
+
//
|
|
375
|
+
// recipient: { privateKey, x25519PrivateKey } — operator's keys
|
|
376
|
+
// ciphertext: base64 envelope from encryptMlkem768X25519
|
|
377
|
+
function decryptMlkem768X25519(ciphertext, recipient) {
|
|
378
|
+
if (!recipient || typeof recipient !== "object" ||
|
|
379
|
+
!recipient.privateKey || !recipient.x25519PrivateKey) {
|
|
380
|
+
throw new Error("decryptMlkem768X25519 requires { privateKey, x25519PrivateKey } " +
|
|
381
|
+
"(privateKey is the ML-KEM-768 PEM, x25519PrivateKey is the X25519 PEM)");
|
|
382
|
+
}
|
|
383
|
+
var packed = Buffer.from(ciphertext, "base64");
|
|
384
|
+
if (packed[0] !== C.ENVELOPE_MAGIC) {
|
|
385
|
+
throw new Error("decryptMlkem768X25519: invalid envelope (bad magic byte)");
|
|
386
|
+
}
|
|
387
|
+
if (packed[1] !== C.KEM_IDS.ML_KEM_768_X25519) {
|
|
388
|
+
throw new Error("decryptMlkem768X25519: envelope KEM ID is " + packed[1] +
|
|
389
|
+
", expected " + C.KEM_IDS.ML_KEM_768_X25519 +
|
|
390
|
+
" (ML_KEM_768_X25519). Use b.crypto.decrypt for KEM-id dispatch.");
|
|
391
|
+
}
|
|
392
|
+
return decryptEnvelope(packed, recipient);
|
|
393
|
+
}
|
|
394
|
+
|
|
364
395
|
// ---- Cert-peer envelope primitives ----
|
|
365
396
|
//
|
|
366
397
|
// The framework's default `encrypt` / `decrypt` source the recipient
|
|
@@ -515,6 +546,7 @@ module.exports = {
|
|
|
515
546
|
encrypt: encrypt,
|
|
516
547
|
decrypt: decrypt,
|
|
517
548
|
encryptMlkem768X25519: encryptMlkem768X25519,
|
|
549
|
+
decryptMlkem768X25519: decryptMlkem768X25519,
|
|
518
550
|
encryptEnvelopeAsCertPeer: encryptEnvelopeAsCertPeer,
|
|
519
551
|
decryptEnvelopeAsCertPeer: decryptEnvelopeAsCertPeer,
|
|
520
552
|
SUPPORTED_KEM_ALGORITHMS: SUPPORTED_KEM_ALGORITHMS,
|