@fabricorg/policy-opa 0.1.0 → 0.3.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 +26 -0
- package/README.md +54 -15
- package/dist/index.cjs +217 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +176 -13
- package/dist/index.d.ts +176 -13
- package/dist/index.js +215 -18
- package/dist/index.js.map +1 -1
- package/package.json +71 -70
package/dist/index.js
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
import { createHash } from 'crypto';
|
|
2
2
|
|
|
3
|
+
// src/bundle-selector.ts
|
|
4
|
+
function selectBundleRevision(execution, binding) {
|
|
5
|
+
if (typeof execution.bundleRevision === "string" && execution.bundleRevision.length > 0) {
|
|
6
|
+
return { bundleRevision: execution.bundleRevision };
|
|
7
|
+
}
|
|
8
|
+
const bundles = readBundles(execution.provenance);
|
|
9
|
+
if (!bundles) return {};
|
|
10
|
+
const names = Object.keys(bundles);
|
|
11
|
+
if (names.length === 0) return {};
|
|
12
|
+
if (binding.bundleName) {
|
|
13
|
+
const revision = bundles[binding.bundleName]?.revision;
|
|
14
|
+
return typeof revision === "string" && revision.length > 0 ? { bundleRevision: revision } : {};
|
|
15
|
+
}
|
|
16
|
+
if (names.length === 1) {
|
|
17
|
+
const only = names[0];
|
|
18
|
+
const revision = only !== void 0 ? bundles[only]?.revision : void 0;
|
|
19
|
+
return typeof revision === "string" && revision.length > 0 ? { bundleRevision: revision } : {};
|
|
20
|
+
}
|
|
21
|
+
return { bundleRevisionStatus: "ambiguous" };
|
|
22
|
+
}
|
|
23
|
+
function readBundles(provenance) {
|
|
24
|
+
if (!provenance || typeof provenance !== "object") return void 0;
|
|
25
|
+
const b = provenance.bundles;
|
|
26
|
+
if (!b || typeof b !== "object" || Array.isArray(b)) return void 0;
|
|
27
|
+
return b;
|
|
28
|
+
}
|
|
29
|
+
|
|
3
30
|
// src/decision-schema.ts
|
|
4
31
|
var POLICY_RESULTS = ["pass", "warn", "block"];
|
|
5
32
|
function parseOpaDecision(raw) {
|
|
@@ -25,8 +52,9 @@ function parseOpaDecision(raw) {
|
|
|
25
52
|
if (err) return { ok: false, error: err };
|
|
26
53
|
}
|
|
27
54
|
}
|
|
28
|
-
if (d.
|
|
29
|
-
|
|
55
|
+
if (d.guidance !== void 0) {
|
|
56
|
+
const err = validateGuidance(d.guidance);
|
|
57
|
+
if (err) return { ok: false, error: err };
|
|
30
58
|
}
|
|
31
59
|
if (d.obligations !== void 0 && !isPlainObject(d.obligations)) {
|
|
32
60
|
return { ok: false, error: "obligations must be an object when present" };
|
|
@@ -52,6 +80,68 @@ function validateConditionResult(value, index) {
|
|
|
52
80
|
}
|
|
53
81
|
return null;
|
|
54
82
|
}
|
|
83
|
+
function validateGuidance(value) {
|
|
84
|
+
if (!isPlainObject(value)) {
|
|
85
|
+
return "guidance must be an object when present";
|
|
86
|
+
}
|
|
87
|
+
const guidance = value;
|
|
88
|
+
if (guidance.summary !== void 0 && typeof guidance.summary !== "string") {
|
|
89
|
+
return "guidance.summary must be a string when present";
|
|
90
|
+
}
|
|
91
|
+
if (!Array.isArray(guidance.factsUsed)) {
|
|
92
|
+
return "guidance.factsUsed must be an array";
|
|
93
|
+
}
|
|
94
|
+
for (let i = 0; i < guidance.factsUsed.length; i += 1) {
|
|
95
|
+
const err = validatePolicyFact(guidance.factsUsed[i], i);
|
|
96
|
+
if (err) return err;
|
|
97
|
+
}
|
|
98
|
+
if (!Array.isArray(guidance.correctiveActions)) {
|
|
99
|
+
return "guidance.correctiveActions must be an array";
|
|
100
|
+
}
|
|
101
|
+
for (let i = 0; i < guidance.correctiveActions.length; i += 1) {
|
|
102
|
+
const err = validateCorrectiveAction(guidance.correctiveActions[i], i);
|
|
103
|
+
if (err) return err;
|
|
104
|
+
}
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
function validatePolicyFact(value, index) {
|
|
108
|
+
if (!isPlainObject(value)) {
|
|
109
|
+
return `guidance.factsUsed[${index}] must be an object`;
|
|
110
|
+
}
|
|
111
|
+
const fact = value;
|
|
112
|
+
if (typeof fact.name !== "string" || fact.name.length === 0) {
|
|
113
|
+
return `guidance.factsUsed[${index}].name must be a non-empty string`;
|
|
114
|
+
}
|
|
115
|
+
if (fact.label !== void 0 && typeof fact.label !== "string") {
|
|
116
|
+
return `guidance.factsUsed[${index}].label must be a string when present`;
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
function validateCorrectiveAction(value, index) {
|
|
121
|
+
if (!isPlainObject(value)) {
|
|
122
|
+
return `guidance.correctiveActions[${index}] must be an object`;
|
|
123
|
+
}
|
|
124
|
+
const action = value;
|
|
125
|
+
if (typeof action.label !== "string" || action.label.length === 0) {
|
|
126
|
+
return `guidance.correctiveActions[${index}].label must be a non-empty string`;
|
|
127
|
+
}
|
|
128
|
+
if (action.description !== void 0 && typeof action.description !== "string") {
|
|
129
|
+
return `guidance.correctiveActions[${index}].description must be a string when present`;
|
|
130
|
+
}
|
|
131
|
+
if (action.actionId !== void 0 && typeof action.actionId !== "string") {
|
|
132
|
+
return `guidance.correctiveActions[${index}].actionId must be a string when present`;
|
|
133
|
+
}
|
|
134
|
+
if (action.parameters !== void 0 && !isPlainObject(action.parameters)) {
|
|
135
|
+
return `guidance.correctiveActions[${index}].parameters must be an object when present`;
|
|
136
|
+
}
|
|
137
|
+
if (action.target !== void 0 && !isPlainObject(action.target)) {
|
|
138
|
+
return `guidance.correctiveActions[${index}].target must be an object when present`;
|
|
139
|
+
}
|
|
140
|
+
if (action.requiresConfirmation !== void 0 && typeof action.requiresConfirmation !== "boolean") {
|
|
141
|
+
return `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
55
145
|
function isPlainObject(value) {
|
|
56
146
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
57
147
|
}
|
|
@@ -89,13 +179,14 @@ function createOpaPolicyEvaluator(options) {
|
|
|
89
179
|
version: binding.version,
|
|
90
180
|
previewSafe,
|
|
91
181
|
evaluate: async (ctx) => {
|
|
92
|
-
const
|
|
93
|
-
|
|
182
|
+
const service = ctx.services?.[serviceKey];
|
|
183
|
+
const transport = resolveTransport(service);
|
|
184
|
+
if (!transport) {
|
|
94
185
|
return makeFailureOutcome(
|
|
95
186
|
binding,
|
|
96
187
|
engineVersion,
|
|
97
188
|
"client_unavailable",
|
|
98
|
-
`No OPA client at ctx.services["${serviceKey}"]`,
|
|
189
|
+
`No OPA client/executor at ctx.services["${serviceKey}"]`,
|
|
99
190
|
onError
|
|
100
191
|
);
|
|
101
192
|
}
|
|
@@ -116,9 +207,9 @@ function createOpaPolicyEvaluator(options) {
|
|
|
116
207
|
inputHash = hashInput(input);
|
|
117
208
|
} catch {
|
|
118
209
|
}
|
|
119
|
-
let
|
|
210
|
+
let execution;
|
|
120
211
|
try {
|
|
121
|
-
|
|
212
|
+
execution = await transport(binding.decisionPath, input);
|
|
122
213
|
} catch (err) {
|
|
123
214
|
return makeFailureOutcome(
|
|
124
215
|
binding,
|
|
@@ -129,7 +220,7 @@ function createOpaPolicyEvaluator(options) {
|
|
|
129
220
|
inputHash
|
|
130
221
|
);
|
|
131
222
|
}
|
|
132
|
-
const parsed = parseOpaDecision(
|
|
223
|
+
const parsed = parseOpaDecision(execution.decision);
|
|
133
224
|
if (!parsed.ok) {
|
|
134
225
|
return makeFailureOutcome(
|
|
135
226
|
binding,
|
|
@@ -137,13 +228,15 @@ function createOpaPolicyEvaluator(options) {
|
|
|
137
228
|
"invalid_response",
|
|
138
229
|
`OPA returned malformed decision: ${parsed.error}`,
|
|
139
230
|
onError,
|
|
140
|
-
inputHash
|
|
231
|
+
inputHash,
|
|
232
|
+
execution
|
|
141
233
|
);
|
|
142
234
|
}
|
|
143
235
|
return buildSuccessOutcome(
|
|
144
236
|
binding,
|
|
145
237
|
engineVersion,
|
|
146
238
|
parsed.decision,
|
|
239
|
+
execution,
|
|
147
240
|
inputHash,
|
|
148
241
|
ctx,
|
|
149
242
|
mapDecision
|
|
@@ -151,13 +244,29 @@ function createOpaPolicyEvaluator(options) {
|
|
|
151
244
|
}
|
|
152
245
|
};
|
|
153
246
|
}
|
|
154
|
-
function
|
|
155
|
-
|
|
247
|
+
function resolveTransport(service) {
|
|
248
|
+
if (!service || typeof service !== "object") return null;
|
|
249
|
+
const exec = service.execute;
|
|
250
|
+
if (typeof exec === "function") {
|
|
251
|
+
return (path, input) => service.execute(path, input);
|
|
252
|
+
}
|
|
253
|
+
const eval_ = service.evaluate;
|
|
254
|
+
if (typeof eval_ === "function") {
|
|
255
|
+
return async (path, input) => ({
|
|
256
|
+
decision: await service.evaluate(path, input)
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
function buildSuccessOutcome(binding, engineVersion, decision, execution, inputHash, ctx, mapDecision) {
|
|
262
|
+
const selection = selectBundleRevision(execution, binding);
|
|
263
|
+
const mapped = mapDecision ? mapDecision(decision, ctx, execution) : { result: decision.result, reason: decision.reason };
|
|
156
264
|
return {
|
|
157
265
|
policyId: binding.policyId,
|
|
158
266
|
policyVersion: binding.version,
|
|
159
|
-
result: mapped.result,
|
|
160
|
-
reason: mapped.reason,
|
|
267
|
+
result: mapped.result ?? decision.result,
|
|
268
|
+
reason: mapped.reason ?? decision.reason,
|
|
269
|
+
guidance: mapped.guidance ?? decision.guidance,
|
|
161
270
|
metadata: {
|
|
162
271
|
...mapped.metadata ?? {},
|
|
163
272
|
opaDecision: decision
|
|
@@ -169,30 +278,48 @@ function buildSuccessOutcome(binding, engineVersion, decision, inputHash, ctx, m
|
|
|
169
278
|
dispatchPath: ["code"],
|
|
170
279
|
engine: {
|
|
171
280
|
name: ENGINE_NAME,
|
|
172
|
-
version: engineVersion,
|
|
281
|
+
version: execution.opaVersion ?? engineVersion,
|
|
173
282
|
metadata: stripUndefined({
|
|
174
283
|
decisionPath: binding.decisionPath,
|
|
175
284
|
regoPackage: binding.regoPackage,
|
|
176
285
|
inputHash,
|
|
286
|
+
decisionId: execution.decisionId,
|
|
287
|
+
bundleName: binding.bundleName,
|
|
288
|
+
bundleRevision: selection.bundleRevision,
|
|
289
|
+
bundleRevisionStatus: selection.bundleRevisionStatus,
|
|
290
|
+
provenance: execution.provenance,
|
|
177
291
|
conditionResults: decision.conditionResults,
|
|
178
|
-
factsUsed: decision.factsUsed,
|
|
179
292
|
obligations: decision.obligations
|
|
180
293
|
})
|
|
181
294
|
}
|
|
182
295
|
}
|
|
183
296
|
};
|
|
184
297
|
}
|
|
185
|
-
function makeFailureOutcome(binding, engineVersion, error, reason, onError, inputHash) {
|
|
298
|
+
function makeFailureOutcome(binding, engineVersion, error, reason, onError, inputHash, execution) {
|
|
186
299
|
if (onError === "throw") {
|
|
187
300
|
const err = new Error(reason);
|
|
188
301
|
err.kind = error;
|
|
189
302
|
throw err;
|
|
190
303
|
}
|
|
304
|
+
const selection = execution ? selectBundleRevision(execution, binding) : {};
|
|
191
305
|
return {
|
|
192
306
|
policyId: binding.policyId,
|
|
193
307
|
policyVersion: binding.version,
|
|
194
308
|
result: "block",
|
|
195
309
|
reason,
|
|
310
|
+
guidance: {
|
|
311
|
+
summary: "OPA policy evaluation could not complete.",
|
|
312
|
+
factsUsed: [
|
|
313
|
+
{ name: "opaFailureKind", value: error, label: "Failure kind" },
|
|
314
|
+
{ name: "decisionPath", value: binding.decisionPath, label: "Decision path" }
|
|
315
|
+
],
|
|
316
|
+
correctiveActions: [
|
|
317
|
+
{
|
|
318
|
+
label: "Check OPA policy engine",
|
|
319
|
+
description: "Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape."
|
|
320
|
+
}
|
|
321
|
+
]
|
|
322
|
+
},
|
|
196
323
|
metadata: {
|
|
197
324
|
opaError: error
|
|
198
325
|
},
|
|
@@ -203,11 +330,16 @@ function makeFailureOutcome(binding, engineVersion, error, reason, onError, inpu
|
|
|
203
330
|
dispatchPath: ["code"],
|
|
204
331
|
engine: {
|
|
205
332
|
name: ENGINE_NAME,
|
|
206
|
-
version: engineVersion,
|
|
333
|
+
version: execution?.opaVersion ?? engineVersion,
|
|
207
334
|
metadata: stripUndefined({
|
|
208
335
|
decisionPath: binding.decisionPath,
|
|
209
336
|
regoPackage: binding.regoPackage,
|
|
210
337
|
inputHash,
|
|
338
|
+
decisionId: execution?.decisionId,
|
|
339
|
+
bundleName: binding.bundleName,
|
|
340
|
+
bundleRevision: selection.bundleRevision,
|
|
341
|
+
bundleRevisionStatus: selection.bundleRevisionStatus,
|
|
342
|
+
provenance: execution?.provenance,
|
|
211
343
|
error,
|
|
212
344
|
errorReason: reason
|
|
213
345
|
})
|
|
@@ -232,6 +364,71 @@ function formatError(err) {
|
|
|
232
364
|
}
|
|
233
365
|
}
|
|
234
366
|
|
|
235
|
-
|
|
367
|
+
// src/executor-client.ts
|
|
368
|
+
function executorFromOpaClient(client) {
|
|
369
|
+
return {
|
|
370
|
+
async execute(path, input) {
|
|
371
|
+
const decision = await client.evaluate(path, input);
|
|
372
|
+
return { decision };
|
|
373
|
+
}
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// src/executor-http.ts
|
|
378
|
+
function executorFromOpaHttp(opts) {
|
|
379
|
+
const baseUrl = stripTrailingSlash(opts.baseUrl);
|
|
380
|
+
const provenance = opts.provenance ?? true;
|
|
381
|
+
const customFetch = opts.fetch;
|
|
382
|
+
const headers = {
|
|
383
|
+
"content-type": "application/json",
|
|
384
|
+
accept: "application/json",
|
|
385
|
+
...opts.headers ?? {}
|
|
386
|
+
};
|
|
387
|
+
return {
|
|
388
|
+
async execute(path, input) {
|
|
389
|
+
const fetchImpl = customFetch ?? globalThis.fetch;
|
|
390
|
+
if (typeof fetchImpl !== "function") {
|
|
391
|
+
throw new Error(
|
|
392
|
+
"executorFromOpaHttp: no fetch implementation available. Pass `fetch` in options or run on a runtime with `globalThis.fetch`."
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
const url = `${baseUrl}/v1/data/${stripLeadingSlash(path)}${provenance ? "?provenance=true" : ""}`;
|
|
396
|
+
const response = await fetchImpl(url, {
|
|
397
|
+
method: "POST",
|
|
398
|
+
headers,
|
|
399
|
+
body: JSON.stringify({ input })
|
|
400
|
+
});
|
|
401
|
+
if (!response.ok) {
|
|
402
|
+
const text = await safeReadText(response);
|
|
403
|
+
throw new Error(`OPA HTTP ${response.status} at ${url}: ${truncate(text, 500)}`);
|
|
404
|
+
}
|
|
405
|
+
const body = await response.json();
|
|
406
|
+
return {
|
|
407
|
+
decision: body.result,
|
|
408
|
+
decisionId: body.decision_id,
|
|
409
|
+
opaVersion: body.provenance?.version,
|
|
410
|
+
provenance: body.provenance
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
}
|
|
415
|
+
function stripTrailingSlash(s) {
|
|
416
|
+
return s.replace(/\/+$/, "");
|
|
417
|
+
}
|
|
418
|
+
function stripLeadingSlash(s) {
|
|
419
|
+
return s.replace(/^\/+/, "");
|
|
420
|
+
}
|
|
421
|
+
async function safeReadText(response) {
|
|
422
|
+
try {
|
|
423
|
+
return await response.text();
|
|
424
|
+
} catch {
|
|
425
|
+
return "<unreadable body>";
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
function truncate(s, max) {
|
|
429
|
+
return s.length <= max ? s : `${s.slice(0, max)}\u2026`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
export { createOpaPolicyEvaluator, defaultHashInput, executorFromOpaClient, executorFromOpaHttp, parseOpaDecision, selectBundleRevision, stableStringify };
|
|
236
433
|
//# sourceMappingURL=index.js.map
|
|
237
434
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/decision-schema.ts","../src/hash.ts","../src/factory.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { PolicyEvaluationResult } from \"@fabricorg/platform/policies\";\nimport type { OpaDecision } from \"./types\";\n\nconst POLICY_RESULTS: readonly PolicyEvaluationResult[] = [\"pass\", \"warn\", \"block\"];\n\nexport type OpaDecisionParseResult =\n\t| { ok: true; decision: OpaDecision }\n\t| { ok: false; error: string };\n\n/**\n * Hand-rolled validator for the Rego \"house style\" decision shape. Avoids a\n * runtime zod dependency to keep the adapter zero-dep.\n *\n * Accepts a raw OPA result and either returns the parsed `OpaDecision` or a\n * single human-readable error string describing the first violation. We don't\n * accumulate every error: when audit evidence has to record \"OPA returned\n * something invalid\", one precise reason is more useful than a list.\n */\nexport function parseOpaDecision(raw: unknown): OpaDecisionParseResult {\n\tif (raw === null || typeof raw !== \"object\") {\n\t\treturn { ok: false, error: \"decision must be an object\" };\n\t}\n\n\tconst d = raw as Record<string, unknown>;\n\n\tif (typeof d.result !== \"string\" || !POLICY_RESULTS.includes(d.result as PolicyEvaluationResult)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `result must be \"pass\" | \"warn\" | \"block\" (got ${JSON.stringify(d.result)})`,\n\t\t};\n\t}\n\n\tif (d.reason !== undefined && typeof d.reason !== \"string\") {\n\t\treturn { ok: false, error: \"reason must be a string when present\" };\n\t}\n\n\tif (d.conditionResults !== undefined) {\n\t\tif (!Array.isArray(d.conditionResults)) {\n\t\t\treturn { ok: false, error: \"conditionResults must be an array when present\" };\n\t\t}\n\t\tfor (let i = 0; i < d.conditionResults.length; i += 1) {\n\t\t\tconst err = validateConditionResult(d.conditionResults[i], i);\n\t\t\tif (err) return { ok: false, error: err };\n\t\t}\n\t}\n\n\tif (d.factsUsed !== undefined && !isPlainObject(d.factsUsed)) {\n\t\treturn { ok: false, error: \"factsUsed must be an object when present\" };\n\t}\n\n\tif (d.obligations !== undefined && !isPlainObject(d.obligations)) {\n\t\treturn { ok: false, error: \"obligations must be an object when present\" };\n\t}\n\n\treturn { ok: true, decision: d as unknown as OpaDecision };\n}\n\nfunction validateConditionResult(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `conditionResults[${index}] must be an object`;\n\t}\n\tconst c = value as Record<string, unknown>;\n\tif (typeof c.conditionId !== \"string\" || c.conditionId.length === 0) {\n\t\treturn `conditionResults[${index}].conditionId must be a non-empty string`;\n\t}\n\tif (typeof c.passed !== \"boolean\") {\n\t\treturn `conditionResults[${index}].passed must be a boolean`;\n\t}\n\tif (typeof c.result !== \"string\" || !POLICY_RESULTS.includes(c.result as PolicyEvaluationResult)) {\n\t\treturn `conditionResults[${index}].result must be \"pass\" | \"warn\" | \"block\"`;\n\t}\n\tif (c.reason !== undefined && typeof c.reason !== \"string\") {\n\t\treturn `conditionResults[${index}].reason must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Stable JSON stringify — sorts object keys recursively so two\n * structurally-equal inputs produce the same string regardless of property\n * insertion order. Required for hash determinism across builds of the same\n * `buildInput` function.\n */\nexport function stableStringify(value: unknown): string {\n\tif (value === undefined) return \"null\";\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value);\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map(stableStringify).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys\n\t\t.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)\n\t\t.join(\",\")}}`;\n}\n\n/**\n * Default input hasher: SHA-256 over a stable stringification.\n * Format: `sha256:<hex>` — namespaced so future migrations to a different\n * algorithm can be detected by a prefix check in evidence dashboards.\n */\nexport function defaultHashInput(input: Record<string, unknown>): string {\n\tconst hex = createHash(\"sha256\").update(stableStringify(input)).digest(\"hex\");\n\treturn `sha256:${hex}`;\n}\n","import type {\n\tPolicyContext,\n\tPolicyEvaluator,\n\tPolicyOutcome,\n} from \"@fabricorg/platform/policies\";\n\nimport { parseOpaDecision } from \"./decision-schema\";\nimport { defaultHashInput } from \"./hash\";\nimport type {\n\tCreateOpaPolicyEvaluatorOptions,\n\tOpaDecision,\n\tOpaPolicyClient,\n\tOpaPolicyFailureKind,\n} from \"./types\";\n\nconst DEFAULT_SERVICE_KEY = \"opa\";\nconst ENGINE_NAME = \"opa\";\n\n/**\n * Build a Fabric `PolicyEvaluator` that delegates decision-making to an OPA\n * (Open Policy Agent) deployment. The evaluator:\n *\n * 1. Reads the host-injected OPA client from `ctx.services[serviceKey]`.\n * 2. Builds a JSON input snapshot via `buildInput(ctx)` — domain code that\n * snapshots facts the engine needs. Fabric platform never lets OPA reach\n * into the database directly; all facts flow through this function.\n * 3. Evaluates the Rego decision at `binding.decisionPath`.\n * 4. Validates the response against the house-style shape (`OpaDecision`).\n * 5. Maps the decision to a `PolicyOutcome` and attaches engine provenance\n * (`engine.name = \"opa\"`, `decisionPath`, `inputHash`) for audit.\n *\n * Failures (missing client, build failure, network failure, malformed response)\n * are governed by `onError`. Default `\"block\"` honors Fabric's default-deny\n * posture and records the failure category under `engine.metadata.error`.\n */\nexport function createOpaPolicyEvaluator<TDb = unknown>(\n\toptions: CreateOpaPolicyEvaluatorOptions<TDb>,\n): PolicyEvaluator<TDb> {\n\tconst {\n\t\tbinding,\n\t\tbuildInput,\n\t\tserviceKey = DEFAULT_SERVICE_KEY,\n\t\tonError = \"block\",\n\t\tpreviewSafe = false,\n\t\tengineVersion,\n\t\tmapDecision,\n\t\thashInput = defaultHashInput,\n\t} = options;\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tversion: binding.version,\n\t\tpreviewSafe,\n\t\tevaluate: async (ctx) => {\n\t\t\tconst client = ctx.services?.[serviceKey] as OpaPolicyClient | undefined;\n\t\t\tif (!client || typeof client.evaluate !== \"function\") {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"client_unavailable\",\n\t\t\t\t\t`No OPA client at ctx.services[\"${serviceKey}\"]`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet input: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tinput = await buildInput(ctx);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"input_build_failed\",\n\t\t\t\t\t`buildInput threw: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet inputHash: string | undefined;\n\t\t\ttry {\n\t\t\t\tinputHash = hashInput(input);\n\t\t\t} catch {\n\t\t\t\t// hashing is best-effort — if a custom hasher throws, omit the\n\t\t\t\t// field rather than fail the policy.\n\t\t\t}\n\n\t\t\tlet rawResult: unknown;\n\t\t\ttry {\n\t\t\t\trawResult = await client.evaluate(binding.decisionPath, input);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"evaluation_failed\",\n\t\t\t\t\t`OPA evaluation failed: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsed = parseOpaDecision(rawResult);\n\t\t\tif (!parsed.ok) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"invalid_response\",\n\t\t\t\t\t`OPA returned malformed decision: ${parsed.error}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn buildSuccessOutcome(\n\t\t\t\tbinding,\n\t\t\t\tengineVersion,\n\t\t\t\tparsed.decision,\n\t\t\t\tinputHash,\n\t\t\t\tctx,\n\t\t\t\tmapDecision,\n\t\t\t);\n\t\t},\n\t};\n}\n\nfunction buildSuccessOutcome<TDb>(\n\tbinding: CreateOpaPolicyEvaluatorOptions<TDb>[\"binding\"],\n\tengineVersion: string | undefined,\n\tdecision: OpaDecision,\n\tinputHash: string | undefined,\n\tctx: PolicyContext<TDb>,\n\tmapDecision: CreateOpaPolicyEvaluatorOptions<TDb>[\"mapDecision\"],\n): PolicyOutcome {\n\tconst mapped = mapDecision\n\t\t? mapDecision(decision, ctx)\n\t\t: { result: decision.result, reason: decision.reason };\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: mapped.result,\n\t\treason: mapped.reason,\n\t\tmetadata: {\n\t\t\t...(mapped.metadata ?? {}),\n\t\t\topaDecision: decision,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tconditionResults: decision.conditionResults,\n\t\t\t\t\tfactsUsed: decision.factsUsed,\n\t\t\t\t\tobligations: decision.obligations,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction makeFailureOutcome(\n\tbinding: CreateOpaPolicyEvaluatorOptions[\"binding\"],\n\tengineVersion: string | undefined,\n\terror: OpaPolicyFailureKind,\n\treason: string,\n\tonError: \"block\" | \"throw\",\n\tinputHash?: string,\n): PolicyOutcome {\n\tif (onError === \"throw\") {\n\t\tconst err = new Error(reason);\n\t\t(err as Error & { kind?: OpaPolicyFailureKind }).kind = error;\n\t\tthrow err;\n\t}\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: \"block\",\n\t\treason,\n\t\tmetadata: {\n\t\t\topaError: error,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\terror,\n\t\t\t\t\terrorReason: reason,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction stripUndefined(obj: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj)) {\n\t\tif (v !== undefined) out[k] = v;\n\t}\n\treturn out;\n}\n\nfunction formatError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\tif (typeof err === \"string\") return err;\n\ttry {\n\t\treturn JSON.stringify(err);\n\t} catch {\n\t\treturn String(err);\n\t}\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/bundle-selector.ts","../src/decision-schema.ts","../src/hash.ts","../src/factory.ts","../src/executor-client.ts","../src/executor-http.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { OpaPolicyBinding, OpaPolicyExecution } from \"./types\";\n\nexport interface BundleSelection {\n\tbundleRevision?: string;\n\t/**\n\t * Set to `\"ambiguous\"` when OPA reports multiple bundles and the binding\n\t * did not pick one with `bundleName`. The adapter records this on the\n\t * evidence so dashboards can flag policies that need explicit selectors.\n\t * `\"missing\"` is set when provenance was expected but absent.\n\t */\n\tbundleRevisionStatus?: \"ambiguous\" | \"missing\";\n}\n\n/**\n * Determine which OPA bundle revision applies to this decision.\n *\n * Rules (in order):\n * 1. If the executor already populated `execution.bundleRevision`, use it.\n * 2. If `binding.bundleName` is set, look it up in `provenance.bundles`.\n * 3. If exactly one bundle is reported, use its revision unambiguously.\n * 4. If multiple bundles are reported and no selector exists, mark\n * `bundleRevisionStatus: \"ambiguous\"`.\n * 5. If no provenance is reported at all, return `{}` — the caller decides\n * whether absence is meaningful (it is not, for executors that don't\n * carry provenance).\n */\nexport function selectBundleRevision(\n\texecution: OpaPolicyExecution,\n\tbinding: OpaPolicyBinding,\n): BundleSelection {\n\tif (typeof execution.bundleRevision === \"string\" && execution.bundleRevision.length > 0) {\n\t\treturn { bundleRevision: execution.bundleRevision };\n\t}\n\n\tconst bundles = readBundles(execution.provenance);\n\tif (!bundles) return {};\n\n\tconst names = Object.keys(bundles);\n\tif (names.length === 0) return {};\n\n\tif (binding.bundleName) {\n\t\tconst revision = bundles[binding.bundleName]?.revision;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\tif (names.length === 1) {\n\t\tconst only = names[0];\n\t\t// names.length === 1 guarantees names[0] is defined, but the\n\t\t// non-null assertion satisfies noUncheckedIndexedAccess if enabled.\n\t\tconst revision = only !== undefined ? bundles[only]?.revision : undefined;\n\t\treturn typeof revision === \"string\" && revision.length > 0\n\t\t\t? { bundleRevision: revision }\n\t\t\t: {};\n\t}\n\n\treturn { bundleRevisionStatus: \"ambiguous\" };\n}\n\nfunction readBundles(\n\tprovenance: Record<string, unknown> | undefined,\n): Record<string, { revision?: unknown }> | undefined {\n\tif (!provenance || typeof provenance !== \"object\") return undefined;\n\tconst b = (provenance as { bundles?: unknown }).bundles;\n\tif (!b || typeof b !== \"object\" || Array.isArray(b)) return undefined;\n\treturn b as Record<string, { revision?: unknown }>;\n}\n","import type { PolicyEvaluationResult } from \"@fabricorg/platform/policies\";\nimport type { OpaDecision } from \"./types\";\n\nconst POLICY_RESULTS: readonly PolicyEvaluationResult[] = [\"pass\", \"warn\", \"block\"];\n\nexport type OpaDecisionParseResult =\n\t| { ok: true; decision: OpaDecision }\n\t| { ok: false; error: string };\n\n/**\n * Hand-rolled validator for the Rego \"house style\" decision shape. Avoids a\n * runtime zod dependency to keep the adapter zero-dep.\n *\n * Accepts a raw OPA result and either returns the parsed `OpaDecision` or a\n * single human-readable error string describing the first violation. We don't\n * accumulate every error: when audit evidence has to record \"OPA returned\n * something invalid\", one precise reason is more useful than a list.\n */\nexport function parseOpaDecision(raw: unknown): OpaDecisionParseResult {\n\tif (raw === null || typeof raw !== \"object\") {\n\t\treturn { ok: false, error: \"decision must be an object\" };\n\t}\n\n\tconst d = raw as Record<string, unknown>;\n\n\tif (typeof d.result !== \"string\" || !POLICY_RESULTS.includes(d.result as PolicyEvaluationResult)) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\terror: `result must be \"pass\" | \"warn\" | \"block\" (got ${JSON.stringify(d.result)})`,\n\t\t};\n\t}\n\n\tif (d.reason !== undefined && typeof d.reason !== \"string\") {\n\t\treturn { ok: false, error: \"reason must be a string when present\" };\n\t}\n\n\tif (d.conditionResults !== undefined) {\n\t\tif (!Array.isArray(d.conditionResults)) {\n\t\t\treturn { ok: false, error: \"conditionResults must be an array when present\" };\n\t\t}\n\t\tfor (let i = 0; i < d.conditionResults.length; i += 1) {\n\t\t\tconst err = validateConditionResult(d.conditionResults[i], i);\n\t\t\tif (err) return { ok: false, error: err };\n\t\t}\n\t}\n\n\tif (d.guidance !== undefined) {\n\t\tconst err = validateGuidance(d.guidance);\n\t\tif (err) return { ok: false, error: err };\n\t}\n\n\tif (d.obligations !== undefined && !isPlainObject(d.obligations)) {\n\t\treturn { ok: false, error: \"obligations must be an object when present\" };\n\t}\n\n\treturn { ok: true, decision: d as unknown as OpaDecision };\n}\n\nfunction validateConditionResult(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `conditionResults[${index}] must be an object`;\n\t}\n\tconst c = value as Record<string, unknown>;\n\tif (typeof c.conditionId !== \"string\" || c.conditionId.length === 0) {\n\t\treturn `conditionResults[${index}].conditionId must be a non-empty string`;\n\t}\n\tif (typeof c.passed !== \"boolean\") {\n\t\treturn `conditionResults[${index}].passed must be a boolean`;\n\t}\n\tif (typeof c.result !== \"string\" || !POLICY_RESULTS.includes(c.result as PolicyEvaluationResult)) {\n\t\treturn `conditionResults[${index}].result must be \"pass\" | \"warn\" | \"block\"`;\n\t}\n\tif (c.reason !== undefined && typeof c.reason !== \"string\") {\n\t\treturn `conditionResults[${index}].reason must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction validateGuidance(value: unknown): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn \"guidance must be an object when present\";\n\t}\n\tconst guidance = value as Record<string, unknown>;\n\tif (guidance.summary !== undefined && typeof guidance.summary !== \"string\") {\n\t\treturn \"guidance.summary must be a string when present\";\n\t}\n\tif (!Array.isArray(guidance.factsUsed)) {\n\t\treturn \"guidance.factsUsed must be an array\";\n\t}\n\tfor (let i = 0; i < guidance.factsUsed.length; i += 1) {\n\t\tconst err = validatePolicyFact(guidance.factsUsed[i], i);\n\t\tif (err) return err;\n\t}\n\tif (!Array.isArray(guidance.correctiveActions)) {\n\t\treturn \"guidance.correctiveActions must be an array\";\n\t}\n\tfor (let i = 0; i < guidance.correctiveActions.length; i += 1) {\n\t\tconst err = validateCorrectiveAction(guidance.correctiveActions[i], i);\n\t\tif (err) return err;\n\t}\n\treturn null;\n}\n\nfunction validatePolicyFact(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `guidance.factsUsed[${index}] must be an object`;\n\t}\n\tconst fact = value as Record<string, unknown>;\n\tif (typeof fact.name !== \"string\" || fact.name.length === 0) {\n\t\treturn `guidance.factsUsed[${index}].name must be a non-empty string`;\n\t}\n\tif (fact.label !== undefined && typeof fact.label !== \"string\") {\n\t\treturn `guidance.factsUsed[${index}].label must be a string when present`;\n\t}\n\treturn null;\n}\n\nfunction validateCorrectiveAction(value: unknown, index: number): string | null {\n\tif (!isPlainObject(value)) {\n\t\treturn `guidance.correctiveActions[${index}] must be an object`;\n\t}\n\tconst action = value as Record<string, unknown>;\n\tif (typeof action.label !== \"string\" || action.label.length === 0) {\n\t\treturn `guidance.correctiveActions[${index}].label must be a non-empty string`;\n\t}\n\tif (action.description !== undefined && typeof action.description !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].description must be a string when present`;\n\t}\n\tif (action.actionId !== undefined && typeof action.actionId !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].actionId must be a string when present`;\n\t}\n\tif (action.parameters !== undefined && !isPlainObject(action.parameters)) {\n\t\treturn `guidance.correctiveActions[${index}].parameters must be an object when present`;\n\t}\n\tif (action.target !== undefined && !isPlainObject(action.target)) {\n\t\treturn `guidance.correctiveActions[${index}].target must be an object when present`;\n\t}\n\tif (action.requiresConfirmation !== undefined && typeof action.requiresConfirmation !== \"boolean\") {\n\t\treturn `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;\n\t}\n\treturn null;\n}\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n\treturn value !== null && typeof value === \"object\" && !Array.isArray(value);\n}\n","import { createHash } from \"node:crypto\";\n\n/**\n * Stable JSON stringify — sorts object keys recursively so two\n * structurally-equal inputs produce the same string regardless of property\n * insertion order. Required for hash determinism across builds of the same\n * `buildInput` function.\n */\nexport function stableStringify(value: unknown): string {\n\tif (value === undefined) return \"null\";\n\tif (value === null || typeof value !== \"object\") return JSON.stringify(value);\n\tif (Array.isArray(value)) {\n\t\treturn `[${value.map(stableStringify).join(\",\")}]`;\n\t}\n\tconst obj = value as Record<string, unknown>;\n\tconst keys = Object.keys(obj).sort();\n\treturn `{${keys\n\t\t.map((k) => `${JSON.stringify(k)}:${stableStringify(obj[k])}`)\n\t\t.join(\",\")}}`;\n}\n\n/**\n * Default input hasher: SHA-256 over a stable stringification.\n * Format: `sha256:<hex>` — namespaced so future migrations to a different\n * algorithm can be detected by a prefix check in evidence dashboards.\n */\nexport function defaultHashInput(input: Record<string, unknown>): string {\n\tconst hex = createHash(\"sha256\").update(stableStringify(input)).digest(\"hex\");\n\treturn `sha256:${hex}`;\n}\n","import type {\n\tPolicyContext,\n\tPolicyEvaluator,\n\tPolicyOutcome,\n} from \"@fabricorg/platform/policies\";\n\nimport { selectBundleRevision } from \"./bundle-selector\";\nimport { parseOpaDecision } from \"./decision-schema\";\nimport { defaultHashInput } from \"./hash\";\nimport type {\n\tCreateOpaPolicyEvaluatorOptions,\n\tOpaDecision,\n\tOpaPolicyBinding,\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n\tOpaPolicyFailureKind,\n} from \"./types\";\n\nconst DEFAULT_SERVICE_KEY = \"opa\";\nconst ENGINE_NAME = \"opa\";\n\n/**\n * Build a Fabric `PolicyEvaluator` that delegates decision-making to an OPA\n * (Open Policy Agent) deployment.\n *\n * The adapter accepts either of two service shapes under\n * `ctx.services[serviceKey]`:\n *\n * - `OpaPolicyExecutor` (preferred) — `execute(path, input)` returning a rich\n * `OpaPolicyExecution` (decision plus `decisionId`, `bundleRevision`,\n * `opaVersion`, `provenance`). Ship one with {@link executorFromOpaHttp} or\n * {@link executorFromOpaClient}.\n * - `OpaPolicyClient` — `evaluate(path, input)` returning the raw decision\n * only. Compatible with the high-level `@open-policy-agent/opa` SDK at the\n * cost of OPA-side provenance.\n *\n * If both methods are present, `execute` is preferred.\n *\n * The evaluator:\n *\n * 1. Resolves the service from `ctx.services[serviceKey]`.\n * 2. Builds a JSON input snapshot via `buildInput(ctx)` — domain code that\n * snapshots facts the engine needs. OPA never reaches into the database\n * directly; all facts flow through this function.\n * 3. Calls OPA at `binding.decisionPath`.\n * 4. Validates the response against the house-style shape (`OpaDecision`).\n * 5. Maps the decision to a `PolicyOutcome` and attaches engine provenance\n * under `dispatchEvidence.engine` — `name`, optional `version`, and\n * metadata covering `decisionPath`, `regoPackage`, `inputHash`, plus (when\n * the executor surfaces them) `decisionId`, `bundleName`, `bundleRevision`,\n * `bundleRevisionStatus`, and the raw `provenance` block.\n *\n * Failures (missing client, build failure, network failure, malformed\n * response) are governed by `onError`. Default `\"block\"` honors Fabric's\n * default-deny posture and records the failure category under\n * `engine.metadata.error`.\n */\nexport function createOpaPolicyEvaluator<TDb = unknown>(\n\toptions: CreateOpaPolicyEvaluatorOptions<TDb>,\n): PolicyEvaluator<TDb> {\n\tconst {\n\t\tbinding,\n\t\tbuildInput,\n\t\tserviceKey = DEFAULT_SERVICE_KEY,\n\t\tonError = \"block\",\n\t\tpreviewSafe = false,\n\t\tengineVersion,\n\t\tmapDecision,\n\t\thashInput = defaultHashInput,\n\t} = options;\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tversion: binding.version,\n\t\tpreviewSafe,\n\t\tevaluate: async (ctx) => {\n\t\t\tconst service = ctx.services?.[serviceKey];\n\t\t\tconst transport = resolveTransport(service);\n\t\t\tif (!transport) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"client_unavailable\",\n\t\t\t\t\t`No OPA client/executor at ctx.services[\"${serviceKey}\"]`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet input: Record<string, unknown>;\n\t\t\ttry {\n\t\t\t\tinput = await buildInput(ctx);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"input_build_failed\",\n\t\t\t\t\t`buildInput threw: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tlet inputHash: string | undefined;\n\t\t\ttry {\n\t\t\t\tinputHash = hashInput(input);\n\t\t\t} catch {\n\t\t\t\t// hashing is best-effort — if a custom hasher throws, omit the\n\t\t\t\t// field rather than fail the policy.\n\t\t\t}\n\n\t\t\tlet execution: OpaPolicyExecution;\n\t\t\ttry {\n\t\t\t\texecution = await transport(binding.decisionPath, input);\n\t\t\t} catch (err) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"evaluation_failed\",\n\t\t\t\t\t`OPA evaluation failed: ${formatError(err)}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst parsed = parseOpaDecision(execution.decision);\n\t\t\tif (!parsed.ok) {\n\t\t\t\treturn makeFailureOutcome(\n\t\t\t\t\tbinding,\n\t\t\t\t\tengineVersion,\n\t\t\t\t\t\"invalid_response\",\n\t\t\t\t\t`OPA returned malformed decision: ${parsed.error}`,\n\t\t\t\t\tonError,\n\t\t\t\t\tinputHash,\n\t\t\t\t\texecution,\n\t\t\t\t);\n\t\t\t}\n\n\t\t\treturn buildSuccessOutcome(\n\t\t\t\tbinding,\n\t\t\t\tengineVersion,\n\t\t\t\tparsed.decision,\n\t\t\t\texecution,\n\t\t\t\tinputHash,\n\t\t\t\tctx,\n\t\t\t\tmapDecision,\n\t\t\t);\n\t\t},\n\t};\n}\n\n/**\n * Discriminates between the rich executor shape and the legacy client shape.\n * Returns a uniform `(path, input) => OpaPolicyExecution` transport, or\n * `null` if the service doesn't implement either contract.\n *\n * `execute` is preferred when both are present so a v0.1 client wrapped by a\n * richer executor still wins.\n */\nfunction resolveTransport(\n\tservice: unknown,\n): ((path: string, input: unknown) => Promise<OpaPolicyExecution>) | null {\n\tif (!service || typeof service !== \"object\") return null;\n\tconst exec = (service as Partial<OpaPolicyExecutor>).execute;\n\tif (typeof exec === \"function\") {\n\t\treturn (path, input) => (service as OpaPolicyExecutor).execute(path, input);\n\t}\n\tconst eval_ = (service as Partial<OpaPolicyClient>).evaluate;\n\tif (typeof eval_ === \"function\") {\n\t\treturn async (path, input) => ({\n\t\t\tdecision: await (service as OpaPolicyClient).evaluate(path, input),\n\t\t});\n\t}\n\treturn null;\n}\n\nfunction buildSuccessOutcome<TDb>(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\tdecision: OpaDecision,\n\texecution: OpaPolicyExecution,\n\tinputHash: string | undefined,\n\tctx: PolicyContext<TDb>,\n\tmapDecision: CreateOpaPolicyEvaluatorOptions<TDb>[\"mapDecision\"],\n): PolicyOutcome {\n\tconst selection = selectBundleRevision(execution, binding);\n\tconst mapped = mapDecision\n\t\t? mapDecision(decision, ctx, execution)\n\t\t: { result: decision.result, reason: decision.reason };\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: mapped.result ?? decision.result,\n\t\treason: mapped.reason ?? decision.reason,\n\t\tguidance: mapped.guidance ?? decision.guidance,\n\t\tmetadata: {\n\t\t\t...(mapped.metadata ?? {}),\n\t\t\topaDecision: decision,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution.provenance,\n\t\t\t\t\tconditionResults: decision.conditionResults,\n\t\t\t\t\tobligations: decision.obligations,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction makeFailureOutcome(\n\tbinding: OpaPolicyBinding,\n\tengineVersion: string | undefined,\n\terror: OpaPolicyFailureKind,\n\treason: string,\n\tonError: \"block\" | \"throw\",\n\tinputHash?: string,\n\texecution?: OpaPolicyExecution,\n): PolicyOutcome {\n\tif (onError === \"throw\") {\n\t\tconst err = new Error(reason);\n\t\t(err as Error & { kind?: OpaPolicyFailureKind }).kind = error;\n\t\tthrow err;\n\t}\n\n\tconst selection = execution ? selectBundleRevision(execution, binding) : {};\n\n\treturn {\n\t\tpolicyId: binding.policyId,\n\t\tpolicyVersion: binding.version,\n\t\tresult: \"block\",\n\t\treason,\n\t\tguidance: {\n\t\t\tsummary: \"OPA policy evaluation could not complete.\",\n\t\t\tfactsUsed: [\n\t\t\t\t{ name: \"opaFailureKind\", value: error, label: \"Failure kind\" },\n\t\t\t\t{ name: \"decisionPath\", value: binding.decisionPath, label: \"Decision path\" },\n\t\t\t],\n\t\t\tcorrectiveActions: [\n\t\t\t\t{\n\t\t\t\t\tlabel: \"Check OPA policy engine\",\n\t\t\t\t\tdescription:\n\t\t\t\t\t\t\"Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape.\",\n\t\t\t\t},\n\t\t\t],\n\t\t},\n\t\tmetadata: {\n\t\t\topaError: error,\n\t\t},\n\t\tdispatchEvidence: {\n\t\t\tpolicyKind: \"code\",\n\t\t\tpolicyId: binding.policyId,\n\t\t\tpolicyVersion: binding.version,\n\t\t\tdispatchPath: [\"code\"],\n\t\t\tengine: {\n\t\t\t\tname: ENGINE_NAME,\n\t\t\t\tversion: execution?.opaVersion ?? engineVersion,\n\t\t\t\tmetadata: stripUndefined({\n\t\t\t\t\tdecisionPath: binding.decisionPath,\n\t\t\t\t\tregoPackage: binding.regoPackage,\n\t\t\t\t\tinputHash,\n\t\t\t\t\tdecisionId: execution?.decisionId,\n\t\t\t\t\tbundleName: binding.bundleName,\n\t\t\t\t\tbundleRevision: selection.bundleRevision,\n\t\t\t\t\tbundleRevisionStatus: selection.bundleRevisionStatus,\n\t\t\t\t\tprovenance: execution?.provenance,\n\t\t\t\t\terror,\n\t\t\t\t\terrorReason: reason,\n\t\t\t\t}),\n\t\t\t},\n\t\t},\n\t};\n}\n\nfunction stripUndefined(obj: Record<string, unknown>): Record<string, unknown> {\n\tconst out: Record<string, unknown> = {};\n\tfor (const [k, v] of Object.entries(obj)) {\n\t\tif (v !== undefined) out[k] = v;\n\t}\n\treturn out;\n}\n\nfunction formatError(err: unknown): string {\n\tif (err instanceof Error) return err.message;\n\tif (typeof err === \"string\") return err;\n\ttry {\n\t\treturn JSON.stringify(err);\n\t} catch {\n\t\treturn String(err);\n\t}\n}\n","import type {\n\tOpaPolicyClient,\n\tOpaPolicyExecution,\n\tOpaPolicyExecutor,\n} from \"./types\";\n\n/**\n * Wrap an `OpaPolicyClient` (the high-level `@open-policy-agent/opa` SDK\n * shape) as an {@link OpaPolicyExecutor}. The resulting executor carries no\n * OPA-side provenance — the high-level SDK discards `decisionId` and\n * `provenance` from the response — but does centralize the\n * `(path, input) => execution` plumbing so hosts can choose at startup whether\n * to wire a client or a full executor.\n *\n * For full provenance (decisionId, bundleRevision, opaVersion), prefer\n * {@link executorFromOpaHttp}.\n */\nexport function executorFromOpaClient(client: OpaPolicyClient): OpaPolicyExecutor {\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst decision = await client.evaluate(path, input);\n\t\t\treturn { decision };\n\t\t},\n\t};\n}\n","import type { OpaPolicyExecution, OpaPolicyExecutor } from \"./types\";\n\nexport interface OpaHttpExecutorOptions {\n\t/**\n\t * Base URL of the OPA server, e.g. `\"http://localhost:8181\"` or\n\t * `\"https://opa.internal.example.com\"`. Trailing slash is permitted; the\n\t * executor normalizes it.\n\t */\n\tbaseUrl: string;\n\t/**\n\t * Override for `globalThis.fetch`. Lets the host inject a fetch instance\n\t * with retries, mTLS, OpenTelemetry instrumentation, etc. Defaults to\n\t * `globalThis.fetch`.\n\t */\n\tfetch?: typeof globalThis.fetch;\n\t/** Extra request headers (e.g. `Authorization`). */\n\theaders?: Record<string, string>;\n\t/**\n\t * Request OPA-side provenance (`decision_id`, `provenance.version`,\n\t * `provenance.bundles[*].revision`) via `?provenance=true`. Defaults to\n\t * `true` — turning it off forfeits OPA's contribution to audit evidence\n\t * and is rarely what you want.\n\t */\n\tprovenance?: boolean;\n}\n\ninterface OpaHttpResponseBody {\n\tresult?: unknown;\n\tdecision_id?: string;\n\tprovenance?: {\n\t\tversion?: string;\n\t\tbuild_commit?: string;\n\t\tbuild_timestamp?: string;\n\t\tbuild_host?: string;\n\t\tbundles?: Record<string, { revision?: string }>;\n\t};\n}\n\n/**\n * Build an {@link OpaPolicyExecutor} that talks to OPA's REST API directly.\n *\n * POSTs to `{baseUrl}/v1/data/{path}?provenance=true` with body\n * `{ \"input\": ... }`. Parses the snake_case response and lifts:\n *\n * - `result` → `execution.decision`\n * - `decision_id` → `execution.decisionId`\n * - `provenance.version` → `execution.opaVersion`\n * - `provenance` (whole block) → `execution.provenance`\n *\n * Bundle revision selection happens in the factory, not the executor, because\n * it depends on `binding.bundleName`.\n *\n * Calling this in environments without `globalThis.fetch` (older Node) throws\n * at call time; pass `fetch: nodeFetch` or `fetch: undici-fetch` etc. via the\n * options to support those runtimes explicitly.\n */\nexport function executorFromOpaHttp(opts: OpaHttpExecutorOptions): OpaPolicyExecutor {\n\tconst baseUrl = stripTrailingSlash(opts.baseUrl);\n\tconst provenance = opts.provenance ?? true;\n\tconst customFetch = opts.fetch;\n\tconst headers = {\n\t\t\"content-type\": \"application/json\",\n\t\taccept: \"application/json\",\n\t\t...(opts.headers ?? {}),\n\t};\n\n\treturn {\n\t\tasync execute(path: string, input: unknown): Promise<OpaPolicyExecution> {\n\t\t\tconst fetchImpl = customFetch ?? globalThis.fetch;\n\t\t\tif (typeof fetchImpl !== \"function\") {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t\"executorFromOpaHttp: no fetch implementation available. Pass `fetch` in options or run on a runtime with `globalThis.fetch`.\",\n\t\t\t\t);\n\t\t\t}\n\n\t\t\tconst url = `${baseUrl}/v1/data/${stripLeadingSlash(path)}${\n\t\t\t\tprovenance ? \"?provenance=true\" : \"\"\n\t\t\t}`;\n\t\t\tconst response = await fetchImpl(url, {\n\t\t\t\tmethod: \"POST\",\n\t\t\t\theaders,\n\t\t\t\tbody: JSON.stringify({ input }),\n\t\t\t});\n\n\t\t\tif (!response.ok) {\n\t\t\t\tconst text = await safeReadText(response);\n\t\t\t\tthrow new Error(`OPA HTTP ${response.status} at ${url}: ${truncate(text, 500)}`);\n\t\t\t}\n\n\t\t\tconst body = (await response.json()) as OpaHttpResponseBody;\n\n\t\t\treturn {\n\t\t\t\tdecision: body.result,\n\t\t\t\tdecisionId: body.decision_id,\n\t\t\t\topaVersion: body.provenance?.version,\n\t\t\t\tprovenance: body.provenance as Record<string, unknown> | undefined,\n\t\t\t};\n\t\t},\n\t};\n}\n\nfunction stripTrailingSlash(s: string): string {\n\treturn s.replace(/\\/+$/, \"\");\n}\n\nfunction stripLeadingSlash(s: string): string {\n\treturn s.replace(/^\\/+/, \"\");\n}\n\nasync function safeReadText(response: Response): Promise<string> {\n\ttry {\n\t\treturn await response.text();\n\t} catch {\n\t\treturn \"<unreadable body>\";\n\t}\n}\n\nfunction truncate(s: string, max: number): string {\n\treturn s.length <= max ? s : `${s.slice(0, max)}…`;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,71 +1,72 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
}
|
|
2
|
+
"name": "@fabricorg/policy-opa",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Open Policy Agent (OPA) adapter for @fabricorg/platform. Wraps a Rego decision behind Fabric's PolicyEvaluator contract — Fabric keeps policyId.vN canonical for audit; engine evidence carries OPA provenance (decision path, input hash, bundle revision). Zero coupling to a specific OPA SDK; structurally typed client.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"fabric",
|
|
7
|
+
"fabricorg",
|
|
8
|
+
"policy",
|
|
9
|
+
"opa",
|
|
10
|
+
"open-policy-agent",
|
|
11
|
+
"rego",
|
|
12
|
+
"authorization",
|
|
13
|
+
"policy-engine"
|
|
14
|
+
],
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"author": "Fabric",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "https://github.com/Fabric-Pro/fabric-platform.git",
|
|
20
|
+
"directory": "packages/policy-opa"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/Fabric-Pro/fabric-platform#readme",
|
|
23
|
+
"bugs": {
|
|
24
|
+
"url": "https://github.com/Fabric-Pro/fabric-platform/issues"
|
|
25
|
+
},
|
|
26
|
+
"type": "module",
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"main": "./dist/index.cjs",
|
|
29
|
+
"types": "./dist/index.d.ts",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": {
|
|
32
|
+
"import": {
|
|
33
|
+
"types": "./dist/index.d.ts",
|
|
34
|
+
"default": "./dist/index.js"
|
|
35
|
+
},
|
|
36
|
+
"require": {
|
|
37
|
+
"types": "./dist/index.d.cts",
|
|
38
|
+
"default": "./dist/index.cjs"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"files": [
|
|
43
|
+
"dist",
|
|
44
|
+
"README.md",
|
|
45
|
+
"CHANGELOG.md",
|
|
46
|
+
"LICENSE"
|
|
47
|
+
],
|
|
48
|
+
"scripts": {
|
|
49
|
+
"clean": "rm -rf dist tsconfig.tsbuildinfo",
|
|
50
|
+
"build": "tsup",
|
|
51
|
+
"type-check": "tsc --noEmit",
|
|
52
|
+
"test": "vitest run --passWithNoTests",
|
|
53
|
+
"prepublishOnly": "pnpm clean && pnpm build && pnpm test"
|
|
54
|
+
},
|
|
55
|
+
"peerDependencies": {
|
|
56
|
+
"@fabricorg/platform": "^0.4.0"
|
|
57
|
+
},
|
|
58
|
+
"dependencies": {},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@fabricorg/platform": "workspace:*",
|
|
61
|
+
"@types/node": "^22.10.0",
|
|
62
|
+
"tsup": "^8.5.0",
|
|
63
|
+
"typescript": "^5.7.3",
|
|
64
|
+
"vitest": "^4.1.5"
|
|
65
|
+
},
|
|
66
|
+
"engines": {
|
|
67
|
+
"node": ">=20"
|
|
68
|
+
},
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"access": "public"
|
|
71
|
+
}
|
|
72
|
+
}
|