@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/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.factsUsed !== void 0 && !isPlainObject(d.factsUsed)) {
29
- return { ok: false, error: "factsUsed must be an object when present" };
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 client = ctx.services?.[serviceKey];
93
- if (!client || typeof client.evaluate !== "function") {
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 rawResult;
210
+ let execution;
120
211
  try {
121
- rawResult = await client.evaluate(binding.decisionPath, input);
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(rawResult);
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 buildSuccessOutcome(binding, engineVersion, decision, inputHash, ctx, mapDecision) {
155
- const mapped = mapDecision ? mapDecision(decision, ctx) : { result: decision.result, reason: decision.reason };
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
- export { createOpaPolicyEvaluator, defaultHashInput, parseOpaDecision, stableStringify };
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
- "name": "@fabricorg/policy-opa",
3
- "version": "0.1.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
- "peerDependencies": {
49
- "@fabricorg/platform": "^0.3.2"
50
- },
51
- "dependencies": {},
52
- "devDependencies": {
53
- "@types/node": "^22.10.0",
54
- "tsup": "^8.5.0",
55
- "typescript": "^5.7.3",
56
- "vitest": "^4.1.5",
57
- "@fabricorg/platform": "0.3.2"
58
- },
59
- "engines": {
60
- "node": ">=20"
61
- },
62
- "publishConfig": {
63
- "access": "public"
64
- },
65
- "scripts": {
66
- "clean": "rm -rf dist tsconfig.tsbuildinfo",
67
- "build": "tsup",
68
- "type-check": "tsc --noEmit",
69
- "test": "vitest run --passWithNoTests"
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
+ }