@fabricorg/policy-opa 0.2.0 → 0.4.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 CHANGED
@@ -1,5 +1,22 @@
1
1
  # @fabricorg/policy-opa
2
2
 
3
+ ## 0.4.0 — 2026-05-17
4
+
5
+ ### Minor
6
+
7
+ - **Explicit corrective-action kinds.** OPA decision validation now requires every `guidance.correctiveActions[]` item to declare `kind: "invoke_action" | "navigate" | "manual"`, matching `@fabricorg/platform@0.5.0`.
8
+ - **Failure guidance updated.** Adapter-generated OPA infrastructure failure guidance now emits a `manual` corrective action.
9
+ - **Peer-deps:** `@fabricorg/platform ^0.5.0`.
10
+
11
+ ## 0.3.0 — 2026-05-17
12
+
13
+ ### Minor
14
+
15
+ - **Policy guidance support.** `OpaDecision` now accepts `guidance?: PolicyGuidance` and the evaluator maps it directly to `PolicyOutcome.guidance`. This makes OPA-backed policies render through the same audit/remediation UI contract as TypeScript code policies.
16
+ - **Engine metadata cleanup.** User-facing facts move out of `dispatchEvidence.engine.metadata` and into `PolicyOutcome.guidance`. Engine metadata remains focused on OPA provenance (`decisionPath`, `inputHash`, `decisionId`, `bundleRevision`, `conditionResults`, `obligations`, raw `provenance`).
17
+ - **Default-deny failure guidance.** OPA infrastructure failures still return `block` by default, now with generic corrective guidance telling operators to check OPA reachability, bundle serving, and decision shape.
18
+ - **Peer-deps:** `@fabricorg/platform ^0.4.0`.
19
+
3
20
  ## 0.2.0 — 2026-05-16
4
21
 
5
22
  ### Minor
package/README.md CHANGED
@@ -78,14 +78,18 @@ decision := {
78
78
  "result": result,
79
79
  "reason": reason,
80
80
  "conditionResults": condition_results,
81
- "factsUsed": facts_used,
81
+ "guidance": {
82
+ "summary": reason,
83
+ "factsUsed": facts_used,
84
+ "correctiveActions": corrective_actions,
85
+ },
82
86
  }
83
87
 
84
88
  result := "block" if not consent_active
85
89
  result := "block" if not within_window
86
90
  default result := "pass"
87
91
 
88
- # ...rules computing reason, condition_results, facts_used...
92
+ # ...rules computing reason, condition_results, facts_used, corrective_actions...
89
93
  ```
90
94
 
91
95
  The validator accepts the following fields (TypeScript types: `OpaDecision`):
@@ -100,11 +104,17 @@ The validator accepts the following fields (TypeScript types: `OpaDecision`):
100
104
  result: "pass" | "warn" | "block";
101
105
  reason?: string;
102
106
  }>;
103
- factsUsed?: Record<string, unknown>;
107
+ guidance?: PolicyGuidance;
104
108
  obligations?: Record<string, unknown>;
105
109
  }
106
110
  ```
107
111
 
112
+ Every `guidance.correctiveActions[]` item must include `kind`:
113
+
114
+ - `invoke_action`: requires `actionId` and optional `parameters`.
115
+ - `navigate`: optional `route` or structured `target`.
116
+ - `manual`: human instruction with no automated operation.
117
+
108
118
  ### 4. The evaluator factory (this package)
109
119
 
110
120
  ```ts
@@ -179,13 +189,12 @@ For a successful OPA evaluation under the HTTP executor (with provenance enabled
179
189
  "version": "0.65.0",
180
190
  "bundles": { "lending": { "revision": "2026-05-16.3" } }
181
191
  },
182
- "conditionResults": [{ "conditionId": "consent_active", "passed": true, "result": "pass" }],
183
- "factsUsed": { "consent": { "active": true } }
192
+ "conditionResults": [{ "conditionId": "consent_active", "passed": true, "result": "pass" }]
184
193
  }
185
194
  }
186
195
  ```
187
196
 
188
- Fabric's `policyId` / `policyVersion` remain canonical (`"what was evaluated"`). `engine.metadata.{decisionId, bundleName, bundleRevision}` answers `"which artifact produced the answer"`, and `decisionId` is the join key against OPA's own decision-log stream if you ship it to a SIEM. All of this rides on the `PolicyEvaluation` row Fabric persists per outcome.
197
+ Fabric's `policyId` / `policyVersion` remain canonical (`"what was evaluated"`). `engine.metadata.{decisionId, bundleName, bundleRevision}` answers `"which artifact produced the answer"`, and `decisionId` is the join key against OPA's own decision-log stream if you ship it to a SIEM. User-facing facts and remediation steps live on `PolicyOutcome.guidance`, not in engine metadata, so code policies and OPA policies render through the same audit UI contract.
189
198
 
190
199
  If OPA serves multiple bundles and the binding has no `bundleName` selector, `bundleRevision` is omitted and `bundleRevisionStatus: "ambiguous"` is recorded — audit dashboards can flag these for a manual fix.
191
200
 
package/dist/index.cjs CHANGED
@@ -54,8 +54,9 @@ function parseOpaDecision(raw) {
54
54
  if (err) return { ok: false, error: err };
55
55
  }
56
56
  }
57
- if (d.factsUsed !== void 0 && !isPlainObject(d.factsUsed)) {
58
- return { ok: false, error: "factsUsed must be an object when present" };
57
+ if (d.guidance !== void 0) {
58
+ const err = validateGuidance(d.guidance);
59
+ if (err) return { ok: false, error: err };
59
60
  }
60
61
  if (d.obligations !== void 0 && !isPlainObject(d.obligations)) {
61
62
  return { ok: false, error: "obligations must be an object when present" };
@@ -81,6 +82,82 @@ function validateConditionResult(value, index) {
81
82
  }
82
83
  return null;
83
84
  }
85
+ function validateGuidance(value) {
86
+ if (!isPlainObject(value)) {
87
+ return "guidance must be an object when present";
88
+ }
89
+ const guidance = value;
90
+ if (guidance.summary !== void 0 && typeof guidance.summary !== "string") {
91
+ return "guidance.summary must be a string when present";
92
+ }
93
+ if (!Array.isArray(guidance.factsUsed)) {
94
+ return "guidance.factsUsed must be an array";
95
+ }
96
+ for (let i = 0; i < guidance.factsUsed.length; i += 1) {
97
+ const err = validatePolicyFact(guidance.factsUsed[i], i);
98
+ if (err) return err;
99
+ }
100
+ if (!Array.isArray(guidance.correctiveActions)) {
101
+ return "guidance.correctiveActions must be an array";
102
+ }
103
+ for (let i = 0; i < guidance.correctiveActions.length; i += 1) {
104
+ const err = validateCorrectiveAction(guidance.correctiveActions[i], i);
105
+ if (err) return err;
106
+ }
107
+ return null;
108
+ }
109
+ function validatePolicyFact(value, index) {
110
+ if (!isPlainObject(value)) {
111
+ return `guidance.factsUsed[${index}] must be an object`;
112
+ }
113
+ const fact = value;
114
+ if (typeof fact.name !== "string" || fact.name.length === 0) {
115
+ return `guidance.factsUsed[${index}].name must be a non-empty string`;
116
+ }
117
+ if (fact.label !== void 0 && typeof fact.label !== "string") {
118
+ return `guidance.factsUsed[${index}].label must be a string when present`;
119
+ }
120
+ return null;
121
+ }
122
+ function validateCorrectiveAction(value, index) {
123
+ if (!isPlainObject(value)) {
124
+ return `guidance.correctiveActions[${index}] must be an object`;
125
+ }
126
+ const action = value;
127
+ if (typeof action.label !== "string" || action.label.length === 0) {
128
+ return `guidance.correctiveActions[${index}].label must be a non-empty string`;
129
+ }
130
+ if (action.kind !== "invoke_action" && action.kind !== "navigate" && action.kind !== "manual") {
131
+ return `guidance.correctiveActions[${index}].kind must be "invoke_action" | "navigate" | "manual"`;
132
+ }
133
+ if (action.description !== void 0 && typeof action.description !== "string") {
134
+ return `guidance.correctiveActions[${index}].description must be a string when present`;
135
+ }
136
+ if (action.kind === "invoke_action" && (typeof action.actionId !== "string" || action.actionId.length === 0)) {
137
+ return `guidance.correctiveActions[${index}].actionId must be a non-empty string for invoke_action`;
138
+ }
139
+ if (action.parameters !== void 0 && !isPlainObject(action.parameters)) {
140
+ return `guidance.correctiveActions[${index}].parameters must be an object when present`;
141
+ }
142
+ if (action.route !== void 0 && typeof action.route !== "string") {
143
+ return `guidance.correctiveActions[${index}].route must be a string when present`;
144
+ }
145
+ if (action.target !== void 0 && !isPlainObject(action.target)) {
146
+ return `guidance.correctiveActions[${index}].target must be an object when present`;
147
+ }
148
+ if (action.requiresConfirmation !== void 0 && typeof action.requiresConfirmation !== "boolean") {
149
+ return `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;
150
+ }
151
+ if (action.requiresRole !== void 0) {
152
+ if (!Array.isArray(action.requiresRole)) {
153
+ return `guidance.correctiveActions[${index}].requiresRole must be an array when present`;
154
+ }
155
+ if (action.requiresRole.some((role) => typeof role !== "string" || role.length === 0)) {
156
+ return `guidance.correctiveActions[${index}].requiresRole must contain only non-empty strings`;
157
+ }
158
+ }
159
+ return null;
160
+ }
84
161
  function isPlainObject(value) {
85
162
  return value !== null && typeof value === "object" && !Array.isArray(value);
86
163
  }
@@ -205,6 +282,7 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
205
282
  policyVersion: binding.version,
206
283
  result: mapped.result ?? decision.result,
207
284
  reason: mapped.reason ?? decision.reason,
285
+ guidance: mapped.guidance ?? decision.guidance,
208
286
  metadata: {
209
287
  ...mapped.metadata ?? {},
210
288
  opaDecision: decision
@@ -227,7 +305,6 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
227
305
  bundleRevisionStatus: selection.bundleRevisionStatus,
228
306
  provenance: execution.provenance,
229
307
  conditionResults: decision.conditionResults,
230
- factsUsed: decision.factsUsed,
231
308
  obligations: decision.obligations
232
309
  })
233
310
  }
@@ -246,6 +323,20 @@ function makeFailureOutcome(binding, engineVersion, error, reason, onError, inpu
246
323
  policyVersion: binding.version,
247
324
  result: "block",
248
325
  reason,
326
+ guidance: {
327
+ summary: "OPA policy evaluation could not complete.",
328
+ factsUsed: [
329
+ { name: "opaFailureKind", value: error, label: "Failure kind" },
330
+ { name: "decisionPath", value: binding.decisionPath, label: "Decision path" }
331
+ ],
332
+ correctiveActions: [
333
+ {
334
+ kind: "manual",
335
+ label: "Check OPA policy engine",
336
+ description: "Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape."
337
+ }
338
+ ]
339
+ },
249
340
  metadata: {
250
341
  opaError: error
251
342
  },
@@ -1 +1 @@
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":["createHash"],"mappings":"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","file":"index.cjs","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.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 { 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\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\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: 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\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"]}
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":["createHash"],"mappings":";;;;;AA0BO,SAAS,oBAAA,CACf,WACA,OAAA,EACkB;AAClB,EAAA,IAAI,OAAO,SAAA,CAAU,cAAA,KAAmB,YAAY,SAAA,CAAU,cAAA,CAAe,SAAS,CAAA,EAAG;AACxF,IAAA,OAAO,EAAE,cAAA,EAAgB,SAAA,CAAU,cAAA,EAAe;AAAA,EACnD;AAEA,EAAA,MAAM,OAAA,GAAU,WAAA,CAAY,SAAA,CAAU,UAAU,CAAA;AAChD,EAAA,IAAI,CAAC,OAAA,EAAS,OAAO,EAAC;AAEtB,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA;AACjC,EAAA,IAAI,KAAA,CAAM,MAAA,KAAW,CAAA,EAAG,OAAO,EAAC;AAEhC,EAAA,IAAI,QAAQ,UAAA,EAAY;AACvB,IAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,OAAA,CAAQ,UAAU,CAAA,EAAG,QAAA;AAC9C,IAAA,OAAO,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,CAAS,MAAA,GAAS,IACtD,EAAE,cAAA,EAAgB,QAAA,EAAS,GAC3B,EAAC;AAAA,EACL;AAEA,EAAA,IAAI,KAAA,CAAM,WAAW,CAAA,EAAG;AACvB,IAAA,MAAM,IAAA,GAAO,MAAM,CAAC,CAAA;AAGpB,IAAA,MAAM,WAAW,IAAA,KAAS,MAAA,GAAY,OAAA,CAAQ,IAAI,GAAG,QAAA,GAAW,MAAA;AAChE,IAAA,OAAO,OAAO,QAAA,KAAa,QAAA,IAAY,QAAA,CAAS,MAAA,GAAS,IACtD,EAAE,cAAA,EAAgB,QAAA,EAAS,GAC3B,EAAC;AAAA,EACL;AAEA,EAAA,OAAO,EAAE,sBAAsB,WAAA,EAAY;AAC5C;AAEA,SAAS,YACR,UAAA,EACqD;AACrD,EAAA,IAAI,CAAC,UAAA,IAAc,OAAO,UAAA,KAAe,UAAU,OAAO,MAAA;AAC1D,EAAA,MAAM,IAAK,UAAA,CAAqC,OAAA;AAChD,EAAA,IAAI,CAAC,KAAK,OAAO,CAAA,KAAM,YAAY,KAAA,CAAM,OAAA,CAAQ,CAAC,CAAA,EAAG,OAAO,MAAA;AAC5D,EAAA,OAAO,CAAA;AACR;;;AChEA,IAAM,cAAA,GAAoD,CAAC,MAAA,EAAQ,MAAA,EAAQ,OAAO,CAAA;AAe3E,SAAS,iBAAiB,GAAA,EAAsC;AACtE,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,OAAO,GAAA,KAAQ,QAAA,EAAU;AAC5C,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,4BAAA,EAA6B;AAAA,EACzD;AAEA,EAAA,MAAM,CAAA,GAAI,GAAA;AAEV,EAAA,IAAI,OAAO,EAAE,MAAA,KAAW,QAAA,IAAY,CAAC,cAAA,CAAe,QAAA,CAAS,CAAA,CAAE,MAAgC,CAAA,EAAG;AACjG,IAAA,OAAO;AAAA,MACN,EAAA,EAAI,KAAA;AAAA,MACJ,OAAO,CAAA,8CAAA,EAAiD,IAAA,CAAK,SAAA,CAAU,CAAA,CAAE,MAAM,CAAC,CAAA,CAAA;AAAA,KACjF;AAAA,EACD;AAEA,EAAA,IAAI,EAAE,MAAA,KAAW,MAAA,IAAa,OAAO,CAAA,CAAE,WAAW,QAAA,EAAU;AAC3D,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,sCAAA,EAAuC;AAAA,EACnE;AAEA,EAAA,IAAI,CAAA,CAAE,qBAAqB,MAAA,EAAW;AACrC,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,CAAA,CAAE,gBAAgB,CAAA,EAAG;AACvC,MAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,gDAAA,EAAiD;AAAA,IAC7E;AACA,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,EAAE,gBAAA,CAAiB,MAAA,EAAQ,KAAK,CAAA,EAAG;AACtD,MAAA,MAAM,MAAM,uBAAA,CAAwB,CAAA,CAAE,gBAAA,CAAiB,CAAC,GAAG,CAAC,CAAA;AAC5D,MAAA,IAAI,KAAK,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,GAAA,EAAI;AAAA,IACzC;AAAA,EACD;AAEA,EAAA,IAAI,CAAA,CAAE,aAAa,MAAA,EAAW;AAC7B,IAAA,MAAM,GAAA,GAAM,gBAAA,CAAiB,CAAA,CAAE,QAAQ,CAAA;AACvC,IAAA,IAAI,KAAK,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,OAAO,GAAA,EAAI;AAAA,EACzC;AAEA,EAAA,IAAI,EAAE,WAAA,KAAgB,MAAA,IAAa,CAAC,aAAA,CAAc,CAAA,CAAE,WAAW,CAAA,EAAG;AACjE,IAAA,OAAO,EAAE,EAAA,EAAI,KAAA,EAAO,KAAA,EAAO,4CAAA,EAA6C;AAAA,EACzE;AAEA,EAAA,OAAO,EAAE,EAAA,EAAI,IAAA,EAAM,QAAA,EAAU,CAAA,EAA4B;AAC1D;AAEA,SAAS,uBAAA,CAAwB,OAAgB,KAAA,EAA8B;AAC9E,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,oBAAoB,KAAK,CAAA,mBAAA,CAAA;AAAA,EACjC;AACA,EAAA,MAAM,CAAA,GAAI,KAAA;AACV,EAAA,IAAI,OAAO,CAAA,CAAE,WAAA,KAAgB,YAAY,CAAA,CAAE,WAAA,CAAY,WAAW,CAAA,EAAG;AACpE,IAAA,OAAO,oBAAoB,KAAK,CAAA,wCAAA,CAAA;AAAA,EACjC;AACA,EAAA,IAAI,OAAO,CAAA,CAAE,MAAA,KAAW,SAAA,EAAW;AAClC,IAAA,OAAO,oBAAoB,KAAK,CAAA,0BAAA,CAAA;AAAA,EACjC;AACA,EAAA,IAAI,OAAO,EAAE,MAAA,KAAW,QAAA,IAAY,CAAC,cAAA,CAAe,QAAA,CAAS,CAAA,CAAE,MAAgC,CAAA,EAAG;AACjG,IAAA,OAAO,oBAAoB,KAAK,CAAA,0CAAA,CAAA;AAAA,EACjC;AACA,EAAA,IAAI,EAAE,MAAA,KAAW,MAAA,IAAa,OAAO,CAAA,CAAE,WAAW,QAAA,EAAU;AAC3D,IAAA,OAAO,oBAAoB,KAAK,CAAA,sCAAA,CAAA;AAAA,EACjC;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,iBAAiB,KAAA,EAA+B;AACxD,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,yCAAA;AAAA,EACR;AACA,EAAA,MAAM,QAAA,GAAW,KAAA;AACjB,EAAA,IAAI,SAAS,OAAA,KAAY,MAAA,IAAa,OAAO,QAAA,CAAS,YAAY,QAAA,EAAU;AAC3E,IAAA,OAAO,gDAAA;AAAA,EACR;AACA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,SAAS,CAAA,EAAG;AACvC,IAAA,OAAO,qCAAA;AAAA,EACR;AACA,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAS,SAAA,CAAU,MAAA,EAAQ,KAAK,CAAA,EAAG;AACtD,IAAA,MAAM,MAAM,kBAAA,CAAmB,QAAA,CAAS,SAAA,CAAU,CAAC,GAAG,CAAC,CAAA;AACvD,IAAA,IAAI,KAAK,OAAO,GAAA;AAAA,EACjB;AACA,EAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,iBAAiB,CAAA,EAAG;AAC/C,IAAA,OAAO,6CAAA;AAAA,EACR;AACA,EAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,SAAS,iBAAA,CAAkB,MAAA,EAAQ,KAAK,CAAA,EAAG;AAC9D,IAAA,MAAM,MAAM,wBAAA,CAAyB,QAAA,CAAS,iBAAA,CAAkB,CAAC,GAAG,CAAC,CAAA;AACrE,IAAA,IAAI,KAAK,OAAO,GAAA;AAAA,EACjB;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,kBAAA,CAAmB,OAAgB,KAAA,EAA8B;AACzE,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,sBAAsB,KAAK,CAAA,mBAAA,CAAA;AAAA,EACnC;AACA,EAAA,MAAM,IAAA,GAAO,KAAA;AACb,EAAA,IAAI,OAAO,IAAA,CAAK,IAAA,KAAS,YAAY,IAAA,CAAK,IAAA,CAAK,WAAW,CAAA,EAAG;AAC5D,IAAA,OAAO,sBAAsB,KAAK,CAAA,iCAAA,CAAA;AAAA,EACnC;AACA,EAAA,IAAI,KAAK,KAAA,KAAU,MAAA,IAAa,OAAO,IAAA,CAAK,UAAU,QAAA,EAAU;AAC/D,IAAA,OAAO,sBAAsB,KAAK,CAAA,qCAAA,CAAA;AAAA,EACnC;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,wBAAA,CAAyB,OAAgB,KAAA,EAA8B;AAC/E,EAAA,IAAI,CAAC,aAAA,CAAc,KAAK,CAAA,EAAG;AAC1B,IAAA,OAAO,8BAA8B,KAAK,CAAA,mBAAA,CAAA;AAAA,EAC3C;AACA,EAAA,MAAM,MAAA,GAAS,KAAA;AACf,EAAA,IAAI,OAAO,MAAA,CAAO,KAAA,KAAU,YAAY,MAAA,CAAO,KAAA,CAAM,WAAW,CAAA,EAAG;AAClE,IAAA,OAAO,8BAA8B,KAAK,CAAA,kCAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IACC,MAAA,CAAO,SAAS,eAAA,IAChB,MAAA,CAAO,SAAS,UAAA,IAChB,MAAA,CAAO,SAAS,QAAA,EACf;AACD,IAAA,OAAO,8BAA8B,KAAK,CAAA,sDAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,WAAA,KAAgB,MAAA,IAAa,OAAO,MAAA,CAAO,gBAAgB,QAAA,EAAU;AAC/E,IAAA,OAAO,8BAA8B,KAAK,CAAA,2CAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IACC,MAAA,CAAO,IAAA,KAAS,eAAA,KACf,OAAO,MAAA,CAAO,aAAa,QAAA,IAAY,MAAA,CAAO,QAAA,CAAS,MAAA,KAAW,CAAA,CAAA,EAClE;AACD,IAAA,OAAO,8BAA8B,KAAK,CAAA,uDAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,UAAA,KAAe,MAAA,IAAa,CAAC,aAAA,CAAc,MAAA,CAAO,UAAU,CAAA,EAAG;AACzE,IAAA,OAAO,8BAA8B,KAAK,CAAA,2CAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,KAAA,KAAU,MAAA,IAAa,OAAO,MAAA,CAAO,UAAU,QAAA,EAAU;AACnE,IAAA,OAAO,8BAA8B,KAAK,CAAA,qCAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,MAAA,KAAW,MAAA,IAAa,CAAC,aAAA,CAAc,MAAA,CAAO,MAAM,CAAA,EAAG;AACjE,IAAA,OAAO,8BAA8B,KAAK,CAAA,uCAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,OAAO,oBAAA,KAAyB,MAAA,IAAa,OAAO,MAAA,CAAO,yBAAyB,SAAA,EAAW;AAClG,IAAA,OAAO,8BAA8B,KAAK,CAAA,qDAAA,CAAA;AAAA,EAC3C;AACA,EAAA,IAAI,MAAA,CAAO,iBAAiB,MAAA,EAAW;AACtC,IAAA,IAAI,CAAC,KAAA,CAAM,OAAA,CAAQ,MAAA,CAAO,YAAY,CAAA,EAAG;AACxC,MAAA,OAAO,8BAA8B,KAAK,CAAA,4CAAA,CAAA;AAAA,IAC3C;AACA,IAAA,IAAI,MAAA,CAAO,YAAA,CAAa,IAAA,CAAK,CAAC,IAAA,KAAS,OAAO,IAAA,KAAS,QAAA,IAAY,IAAA,CAAK,MAAA,KAAW,CAAC,CAAA,EAAG;AACtF,MAAA,OAAO,8BAA8B,KAAK,CAAA,kDAAA,CAAA;AAAA,IAC3C;AAAA,EACD;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,cAAc,KAAA,EAAkD;AACxE,EAAA,OAAO,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,YAAY,CAAC,KAAA,CAAM,QAAQ,KAAK,CAAA;AAC3E;AC9JO,SAAS,gBAAgB,KAAA,EAAwB;AACvD,EAAA,IAAI,KAAA,KAAU,QAAW,OAAO,MAAA;AAChC,EAAA,IAAI,KAAA,KAAU,QAAQ,OAAO,KAAA,KAAU,UAAU,OAAO,IAAA,CAAK,UAAU,KAAK,CAAA;AAC5E,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACzB,IAAA,OAAO,IAAI,KAAA,CAAM,GAAA,CAAI,eAAe,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,MAAM,GAAA,GAAM,KAAA;AACZ,EAAA,MAAM,IAAA,GAAO,MAAA,CAAO,IAAA,CAAK,GAAG,EAAE,IAAA,EAAK;AACnC,EAAA,OAAO,CAAA,CAAA,EAAI,KACT,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,IAAA,CAAK,UAAU,CAAC,CAAC,IAAI,eAAA,CAAgB,GAAA,CAAI,CAAC,CAAC,CAAC,EAAE,CAAA,CAC5D,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA,CAAA;AACZ;AAOO,SAAS,iBAAiB,KAAA,EAAwC;AACxE,EAAA,MAAM,GAAA,GAAMA,iBAAA,CAAW,QAAQ,CAAA,CAAE,MAAA,CAAO,gBAAgB,KAAK,CAAC,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AAC5E,EAAA,OAAO,UAAU,GAAG,CAAA,CAAA;AACrB;;;ACVA,IAAM,mBAAA,GAAsB,KAAA;AAC5B,IAAM,WAAA,GAAc,KAAA;AAsCb,SAAS,yBACf,OAAA,EACuB;AACvB,EAAA,MAAM;AAAA,IACL,OAAA;AAAA,IACA,UAAA;AAAA,IACA,UAAA,GAAa,mBAAA;AAAA,IACb,OAAA,GAAU,OAAA;AAAA,IACV,WAAA,GAAc,KAAA;AAAA,IACd,aAAA;AAAA,IACA,WAAA;AAAA,IACA,SAAA,GAAY;AAAA,GACb,GAAI,OAAA;AAEJ,EAAA,OAAO;AAAA,IACN,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,SAAS,OAAA,CAAQ,OAAA;AAAA,IACjB,WAAA;AAAA,IACA,QAAA,EAAU,OAAO,GAAA,KAAQ;AACxB,MAAA,MAAM,OAAA,GAAU,GAAA,CAAI,QAAA,GAAW,UAAU,CAAA;AACzC,MAAA,MAAM,SAAA,GAAY,iBAAiB,OAAO,CAAA;AAC1C,MAAA,IAAI,CAAC,SAAA,EAAW;AACf,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,oBAAA;AAAA,UACA,2CAA2C,UAAU,CAAA,EAAA,CAAA;AAAA,UACrD;AAAA,SACD;AAAA,MACD;AAEA,MAAA,IAAI,KAAA;AACJ,MAAA,IAAI;AACH,QAAA,KAAA,GAAQ,MAAM,WAAW,GAAG,CAAA;AAAA,MAC7B,SAAS,GAAA,EAAK;AACb,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,oBAAA;AAAA,UACA,CAAA,kBAAA,EAAqB,WAAA,CAAY,GAAG,CAAC,CAAA,CAAA;AAAA,UACrC;AAAA,SACD;AAAA,MACD;AAEA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACH,QAAA,SAAA,GAAY,UAAU,KAAK,CAAA;AAAA,MAC5B,CAAA,CAAA,MAAQ;AAAA,MAGR;AAEA,MAAA,IAAI,SAAA;AACJ,MAAA,IAAI;AACH,QAAA,SAAA,GAAY,MAAM,SAAA,CAAU,OAAA,CAAQ,YAAA,EAAc,KAAK,CAAA;AAAA,MACxD,SAAS,GAAA,EAAK;AACb,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,mBAAA;AAAA,UACA,CAAA,uBAAA,EAA0B,WAAA,CAAY,GAAG,CAAC,CAAA,CAAA;AAAA,UAC1C,OAAA;AAAA,UACA;AAAA,SACD;AAAA,MACD;AAEA,MAAA,MAAM,MAAA,GAAS,gBAAA,CAAiB,SAAA,CAAU,QAAQ,CAAA;AAClD,MAAA,IAAI,CAAC,OAAO,EAAA,EAAI;AACf,QAAA,OAAO,kBAAA;AAAA,UACN,OAAA;AAAA,UACA,aAAA;AAAA,UACA,kBAAA;AAAA,UACA,CAAA,iCAAA,EAAoC,OAAO,KAAK,CAAA,CAAA;AAAA,UAChD,OAAA;AAAA,UACA,SAAA;AAAA,UACA;AAAA,SACD;AAAA,MACD;AAEA,MAAA,OAAO,mBAAA;AAAA,QACN,OAAA;AAAA,QACA,aAAA;AAAA,QACA,MAAA,CAAO,QAAA;AAAA,QACP,SAAA;AAAA,QACA,SAAA;AAAA,QACA,GAAA;AAAA,QACA;AAAA,OACD;AAAA,IACD;AAAA,GACD;AACD;AAUA,SAAS,iBACR,OAAA,EACyE;AACzE,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,UAAU,OAAO,IAAA;AACpD,EAAA,MAAM,OAAQ,OAAA,CAAuC,OAAA;AACrD,EAAA,IAAI,OAAO,SAAS,UAAA,EAAY;AAC/B,IAAA,OAAO,CAAC,IAAA,EAAM,KAAA,KAAW,OAAA,CAA8B,OAAA,CAAQ,MAAM,KAAK,CAAA;AAAA,EAC3E;AACA,EAAA,MAAM,QAAS,OAAA,CAAqC,QAAA;AACpD,EAAA,IAAI,OAAO,UAAU,UAAA,EAAY;AAChC,IAAA,OAAO,OAAO,MAAM,KAAA,MAAW;AAAA,MAC9B,QAAA,EAAU,MAAO,OAAA,CAA4B,QAAA,CAAS,MAAM,KAAK;AAAA,KAClE,CAAA;AAAA,EACD;AACA,EAAA,OAAO,IAAA;AACR;AAEA,SAAS,oBACR,OAAA,EACA,aAAA,EACA,UACA,SAAA,EACA,SAAA,EACA,KACA,WAAA,EACgB;AAChB,EAAA,MAAM,SAAA,GAAY,oBAAA,CAAqB,SAAA,EAAW,OAAO,CAAA;AACzD,EAAA,MAAM,MAAA,GAAS,WAAA,GACZ,WAAA,CAAY,QAAA,EAAU,GAAA,EAAK,SAAS,CAAA,GACpC,EAAE,MAAA,EAAQ,QAAA,CAAS,MAAA,EAAQ,MAAA,EAAQ,SAAS,MAAA,EAAO;AAEtD,EAAA,OAAO;AAAA,IACN,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,IACvB,MAAA,EAAQ,MAAA,CAAO,MAAA,IAAU,QAAA,CAAS,MAAA;AAAA,IAClC,MAAA,EAAQ,MAAA,CAAO,MAAA,IAAU,QAAA,CAAS,MAAA;AAAA,IAClC,QAAA,EAAU,MAAA,CAAO,QAAA,IAAY,QAAA,CAAS,QAAA;AAAA,IACtC,QAAA,EAAU;AAAA,MACT,GAAI,MAAA,CAAO,QAAA,IAAY,EAAC;AAAA,MACxB,WAAA,EAAa;AAAA,KACd;AAAA,IACA,gBAAA,EAAkB;AAAA,MACjB,UAAA,EAAY,MAAA;AAAA,MACZ,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,MACvB,YAAA,EAAc,CAAC,MAAM,CAAA;AAAA,MACrB,MAAA,EAAQ;AAAA,QACP,IAAA,EAAM,WAAA;AAAA,QACN,OAAA,EAAS,UAAU,UAAA,IAAc,aAAA;AAAA,QACjC,UAAU,cAAA,CAAe;AAAA,UACxB,cAAc,OAAA,CAAQ,YAAA;AAAA,UACtB,aAAa,OAAA,CAAQ,WAAA;AAAA,UACrB,SAAA;AAAA,UACA,YAAY,SAAA,CAAU,UAAA;AAAA,UACtB,YAAY,OAAA,CAAQ,UAAA;AAAA,UACpB,gBAAgB,SAAA,CAAU,cAAA;AAAA,UAC1B,sBAAsB,SAAA,CAAU,oBAAA;AAAA,UAChC,YAAY,SAAA,CAAU,UAAA;AAAA,UACtB,kBAAkB,QAAA,CAAS,gBAAA;AAAA,UAC3B,aAAa,QAAA,CAAS;AAAA,SACtB;AAAA;AACF;AACD,GACD;AACD;AAEA,SAAS,mBACR,OAAA,EACA,aAAA,EACA,OACA,MAAA,EACA,OAAA,EACA,WACA,SAAA,EACgB;AAChB,EAAA,IAAI,YAAY,OAAA,EAAS;AACxB,IAAA,MAAM,GAAA,GAAM,IAAI,KAAA,CAAM,MAAM,CAAA;AAC5B,IAAC,IAAgD,IAAA,GAAO,KAAA;AACxD,IAAA,MAAM,GAAA;AAAA,EACP;AAEA,EAAA,MAAM,YAAY,SAAA,GAAY,oBAAA,CAAqB,SAAA,EAAW,OAAO,IAAI,EAAC;AAE1E,EAAA,OAAO;AAAA,IACN,UAAU,OAAA,CAAQ,QAAA;AAAA,IAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,IACvB,MAAA,EAAQ,OAAA;AAAA,IACR,MAAA;AAAA,IACA,QAAA,EAAU;AAAA,MACT,OAAA,EAAS,2CAAA;AAAA,MACT,SAAA,EAAW;AAAA,QACV,EAAE,IAAA,EAAM,gBAAA,EAAkB,KAAA,EAAO,KAAA,EAAO,OAAO,cAAA,EAAe;AAAA,QAC9D,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAO,OAAA,CAAQ,YAAA,EAAc,OAAO,eAAA;AAAgB,OAC7E;AAAA,MACA,iBAAA,EAAmB;AAAA,QAClB;AAAA,UACC,IAAA,EAAM,QAAA;AAAA,UACN,KAAA,EAAO,yBAAA;AAAA,UACP,WAAA,EACC;AAAA;AACF;AACD,KACD;AAAA,IACA,QAAA,EAAU;AAAA,MACT,QAAA,EAAU;AAAA,KACX;AAAA,IACA,gBAAA,EAAkB;AAAA,MACjB,UAAA,EAAY,MAAA;AAAA,MACZ,UAAU,OAAA,CAAQ,QAAA;AAAA,MAClB,eAAe,OAAA,CAAQ,OAAA;AAAA,MACvB,YAAA,EAAc,CAAC,MAAM,CAAA;AAAA,MACrB,MAAA,EAAQ;AAAA,QACP,IAAA,EAAM,WAAA;AAAA,QACN,OAAA,EAAS,WAAW,UAAA,IAAc,aAAA;AAAA,QAClC,UAAU,cAAA,CAAe;AAAA,UACxB,cAAc,OAAA,CAAQ,YAAA;AAAA,UACtB,aAAa,OAAA,CAAQ,WAAA;AAAA,UACrB,SAAA;AAAA,UACA,YAAY,SAAA,EAAW,UAAA;AAAA,UACvB,YAAY,OAAA,CAAQ,UAAA;AAAA,UACpB,gBAAgB,SAAA,CAAU,cAAA;AAAA,UAC1B,sBAAsB,SAAA,CAAU,oBAAA;AAAA,UAChC,YAAY,SAAA,EAAW,UAAA;AAAA,UACvB,KAAA;AAAA,UACA,WAAA,EAAa;AAAA,SACb;AAAA;AACF;AACD,GACD;AACD;AAEA,SAAS,eAAe,GAAA,EAAuD;AAC9E,EAAA,MAAM,MAA+B,EAAC;AACtC,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,GAAG,CAAA,EAAG;AACzC,IAAA,IAAI,CAAA,KAAM,MAAA,EAAW,GAAA,CAAI,CAAC,CAAA,GAAI,CAAA;AAAA,EAC/B;AACA,EAAA,OAAO,GAAA;AACR;AAEA,SAAS,YAAY,GAAA,EAAsB;AAC1C,EAAA,IAAI,GAAA,YAAe,KAAA,EAAO,OAAO,GAAA,CAAI,OAAA;AACrC,EAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,EAAA,IAAI;AACH,IAAA,OAAO,IAAA,CAAK,UAAU,GAAG,CAAA;AAAA,EAC1B,CAAA,CAAA,MAAQ;AACP,IAAA,OAAO,OAAO,GAAG,CAAA;AAAA,EAClB;AACD;;;AChSO,SAAS,sBAAsB,MAAA,EAA4C;AACjF,EAAA,OAAO;AAAA,IACN,MAAM,OAAA,CAAQ,IAAA,EAAc,KAAA,EAA6C;AACxE,MAAA,MAAM,QAAA,GAAW,MAAM,MAAA,CAAO,QAAA,CAAS,MAAM,KAAK,CAAA;AAClD,MAAA,OAAO,EAAE,QAAA,EAAS;AAAA,IACnB;AAAA,GACD;AACD;;;ACgCO,SAAS,oBAAoB,IAAA,EAAiD;AACpF,EAAA,MAAM,OAAA,GAAU,kBAAA,CAAmB,IAAA,CAAK,OAAO,CAAA;AAC/C,EAAA,MAAM,UAAA,GAAa,KAAK,UAAA,IAAc,IAAA;AACtC,EAAA,MAAM,cAAc,IAAA,CAAK,KAAA;AACzB,EAAA,MAAM,OAAA,GAAU;AAAA,IACf,cAAA,EAAgB,kBAAA;AAAA,IAChB,MAAA,EAAQ,kBAAA;AAAA,IACR,GAAI,IAAA,CAAK,OAAA,IAAW;AAAC,GACtB;AAEA,EAAA,OAAO;AAAA,IACN,MAAM,OAAA,CAAQ,IAAA,EAAc,KAAA,EAA6C;AACxE,MAAA,MAAM,SAAA,GAAY,eAAe,UAAA,CAAW,KAAA;AAC5C,MAAA,IAAI,OAAO,cAAc,UAAA,EAAY;AACpC,QAAA,MAAM,IAAI,KAAA;AAAA,UACT;AAAA,SACD;AAAA,MACD;AAEA,MAAA,MAAM,GAAA,GAAM,CAAA,EAAG,OAAO,CAAA,SAAA,EAAY,iBAAA,CAAkB,IAAI,CAAC,CAAA,EACxD,UAAA,GAAa,kBAAA,GAAqB,EACnC,CAAA,CAAA;AACA,MAAA,MAAM,QAAA,GAAW,MAAM,SAAA,CAAU,GAAA,EAAK;AAAA,QACrC,MAAA,EAAQ,MAAA;AAAA,QACR,OAAA;AAAA,QACA,IAAA,EAAM,IAAA,CAAK,SAAA,CAAU,EAAE,OAAO;AAAA,OAC9B,CAAA;AAED,MAAA,IAAI,CAAC,SAAS,EAAA,EAAI;AACjB,QAAA,MAAM,IAAA,GAAO,MAAM,YAAA,CAAa,QAAQ,CAAA;AACxC,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,SAAA,EAAY,QAAA,CAAS,MAAM,CAAA,IAAA,EAAO,GAAG,CAAA,EAAA,EAAK,QAAA,CAAS,IAAA,EAAM,GAAG,CAAC,CAAA,CAAE,CAAA;AAAA,MAChF;AAEA,MAAA,MAAM,IAAA,GAAQ,MAAM,QAAA,CAAS,IAAA,EAAK;AAElC,MAAA,OAAO;AAAA,QACN,UAAU,IAAA,CAAK,MAAA;AAAA,QACf,YAAY,IAAA,CAAK,WAAA;AAAA,QACjB,UAAA,EAAY,KAAK,UAAA,EAAY,OAAA;AAAA,QAC7B,YAAY,IAAA,CAAK;AAAA,OAClB;AAAA,IACD;AAAA,GACD;AACD;AAEA,SAAS,mBAAmB,CAAA,EAAmB;AAC9C,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC5B;AAEA,SAAS,kBAAkB,CAAA,EAAmB;AAC7C,EAAA,OAAO,CAAA,CAAE,OAAA,CAAQ,MAAA,EAAQ,EAAE,CAAA;AAC5B;AAEA,eAAe,aAAa,QAAA,EAAqC;AAChE,EAAA,IAAI;AACH,IAAA,OAAO,MAAM,SAAS,IAAA,EAAK;AAAA,EAC5B,CAAA,CAAA,MAAQ;AACP,IAAA,OAAO,mBAAA;AAAA,EACR;AACD;AAEA,SAAS,QAAA,CAAS,GAAW,GAAA,EAAqB;AACjD,EAAA,OAAO,CAAA,CAAE,UAAU,GAAA,GAAM,CAAA,GAAI,GAAG,CAAA,CAAE,KAAA,CAAM,CAAA,EAAG,GAAG,CAAC,CAAA,MAAA,CAAA;AAChD","file":"index.cjs","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 (\n\t\taction.kind !== \"invoke_action\" &&\n\t\taction.kind !== \"navigate\" &&\n\t\taction.kind !== \"manual\"\n\t) {\n\t\treturn `guidance.correctiveActions[${index}].kind must be \"invoke_action\" | \"navigate\" | \"manual\"`;\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 (\n\t\taction.kind === \"invoke_action\" &&\n\t\t(typeof action.actionId !== \"string\" || action.actionId.length === 0)\n\t) {\n\t\treturn `guidance.correctiveActions[${index}].actionId must be a non-empty string for invoke_action`;\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.route !== undefined && typeof action.route !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].route must be a string 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\tif (action.requiresRole !== undefined) {\n\t\tif (!Array.isArray(action.requiresRole)) {\n\t\t\treturn `guidance.correctiveActions[${index}].requiresRole must be an array when present`;\n\t\t}\n\t\tif (action.requiresRole.some((role) => typeof role !== \"string\" || role.length === 0)) {\n\t\t\treturn `guidance.correctiveActions[${index}].requiresRole must contain only non-empty strings`;\n\t\t}\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\tkind: \"manual\",\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/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
1
+ import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyGuidance, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
2
2
 
3
3
  /**
4
4
  * Binding between a Fabric platform policy and an OPA decision. Verticals
@@ -87,13 +87,13 @@ interface OpaPolicyExecutor {
87
87
  interface OpaDecision {
88
88
  result: PolicyEvaluationResult;
89
89
  reason?: string;
90
+ guidance?: PolicyGuidance;
90
91
  conditionResults?: Array<{
91
92
  conditionId: string;
92
93
  passed: boolean;
93
94
  result: PolicyEvaluationResult;
94
95
  reason?: string;
95
96
  }>;
96
- factsUsed?: Record<string, unknown>;
97
97
  obligations?: Record<string, unknown>;
98
98
  }
99
99
  /**
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
1
+ import { PolicyId, PolicyContext, PolicyEvaluationResult, PolicyGuidance, PolicyOutcome, PolicyEvaluator } from '@fabricorg/platform/policies';
2
2
 
3
3
  /**
4
4
  * Binding between a Fabric platform policy and an OPA decision. Verticals
@@ -87,13 +87,13 @@ interface OpaPolicyExecutor {
87
87
  interface OpaDecision {
88
88
  result: PolicyEvaluationResult;
89
89
  reason?: string;
90
+ guidance?: PolicyGuidance;
90
91
  conditionResults?: Array<{
91
92
  conditionId: string;
92
93
  passed: boolean;
93
94
  result: PolicyEvaluationResult;
94
95
  reason?: string;
95
96
  }>;
96
- factsUsed?: Record<string, unknown>;
97
97
  obligations?: Record<string, unknown>;
98
98
  }
99
99
  /**
package/dist/index.js CHANGED
@@ -52,8 +52,9 @@ function parseOpaDecision(raw) {
52
52
  if (err) return { ok: false, error: err };
53
53
  }
54
54
  }
55
- if (d.factsUsed !== void 0 && !isPlainObject(d.factsUsed)) {
56
- 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 };
57
58
  }
58
59
  if (d.obligations !== void 0 && !isPlainObject(d.obligations)) {
59
60
  return { ok: false, error: "obligations must be an object when present" };
@@ -79,6 +80,82 @@ function validateConditionResult(value, index) {
79
80
  }
80
81
  return null;
81
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.kind !== "invoke_action" && action.kind !== "navigate" && action.kind !== "manual") {
129
+ return `guidance.correctiveActions[${index}].kind must be "invoke_action" | "navigate" | "manual"`;
130
+ }
131
+ if (action.description !== void 0 && typeof action.description !== "string") {
132
+ return `guidance.correctiveActions[${index}].description must be a string when present`;
133
+ }
134
+ if (action.kind === "invoke_action" && (typeof action.actionId !== "string" || action.actionId.length === 0)) {
135
+ return `guidance.correctiveActions[${index}].actionId must be a non-empty string for invoke_action`;
136
+ }
137
+ if (action.parameters !== void 0 && !isPlainObject(action.parameters)) {
138
+ return `guidance.correctiveActions[${index}].parameters must be an object when present`;
139
+ }
140
+ if (action.route !== void 0 && typeof action.route !== "string") {
141
+ return `guidance.correctiveActions[${index}].route must be a string when present`;
142
+ }
143
+ if (action.target !== void 0 && !isPlainObject(action.target)) {
144
+ return `guidance.correctiveActions[${index}].target must be an object when present`;
145
+ }
146
+ if (action.requiresConfirmation !== void 0 && typeof action.requiresConfirmation !== "boolean") {
147
+ return `guidance.correctiveActions[${index}].requiresConfirmation must be a boolean when present`;
148
+ }
149
+ if (action.requiresRole !== void 0) {
150
+ if (!Array.isArray(action.requiresRole)) {
151
+ return `guidance.correctiveActions[${index}].requiresRole must be an array when present`;
152
+ }
153
+ if (action.requiresRole.some((role) => typeof role !== "string" || role.length === 0)) {
154
+ return `guidance.correctiveActions[${index}].requiresRole must contain only non-empty strings`;
155
+ }
156
+ }
157
+ return null;
158
+ }
82
159
  function isPlainObject(value) {
83
160
  return value !== null && typeof value === "object" && !Array.isArray(value);
84
161
  }
@@ -203,6 +280,7 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
203
280
  policyVersion: binding.version,
204
281
  result: mapped.result ?? decision.result,
205
282
  reason: mapped.reason ?? decision.reason,
283
+ guidance: mapped.guidance ?? decision.guidance,
206
284
  metadata: {
207
285
  ...mapped.metadata ?? {},
208
286
  opaDecision: decision
@@ -225,7 +303,6 @@ function buildSuccessOutcome(binding, engineVersion, decision, execution, inputH
225
303
  bundleRevisionStatus: selection.bundleRevisionStatus,
226
304
  provenance: execution.provenance,
227
305
  conditionResults: decision.conditionResults,
228
- factsUsed: decision.factsUsed,
229
306
  obligations: decision.obligations
230
307
  })
231
308
  }
@@ -244,6 +321,20 @@ function makeFailureOutcome(binding, engineVersion, error, reason, onError, inpu
244
321
  policyVersion: binding.version,
245
322
  result: "block",
246
323
  reason,
324
+ guidance: {
325
+ summary: "OPA policy evaluation could not complete.",
326
+ factsUsed: [
327
+ { name: "opaFailureKind", value: error, label: "Failure kind" },
328
+ { name: "decisionPath", value: binding.decisionPath, label: "Decision path" }
329
+ ],
330
+ correctiveActions: [
331
+ {
332
+ kind: "manual",
333
+ label: "Check OPA policy engine",
334
+ description: "Verify the OPA service is reachable, serving the expected bundle, and returning the Fabric OPA decision shape."
335
+ }
336
+ ]
337
+ },
247
338
  metadata: {
248
339
  opaError: error
249
340
  },
package/dist/index.js.map CHANGED
@@ -1 +1 @@
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.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 { 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\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\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: 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\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"]}
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 (\n\t\taction.kind !== \"invoke_action\" &&\n\t\taction.kind !== \"navigate\" &&\n\t\taction.kind !== \"manual\"\n\t) {\n\t\treturn `guidance.correctiveActions[${index}].kind must be \"invoke_action\" | \"navigate\" | \"manual\"`;\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 (\n\t\taction.kind === \"invoke_action\" &&\n\t\t(typeof action.actionId !== \"string\" || action.actionId.length === 0)\n\t) {\n\t\treturn `guidance.correctiveActions[${index}].actionId must be a non-empty string for invoke_action`;\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.route !== undefined && typeof action.route !== \"string\") {\n\t\treturn `guidance.correctiveActions[${index}].route must be a string 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\tif (action.requiresRole !== undefined) {\n\t\tif (!Array.isArray(action.requiresRole)) {\n\t\t\treturn `guidance.correctiveActions[${index}].requiresRole must be an array when present`;\n\t\t}\n\t\tif (action.requiresRole.some((role) => typeof role !== \"string\" || role.length === 0)) {\n\t\t\treturn `guidance.correctiveActions[${index}].requiresRole must contain only non-empty strings`;\n\t\t}\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\tkind: \"manual\",\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,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabricorg/policy-opa",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
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
5
  "keywords": [
6
6
  "fabric",
@@ -46,7 +46,7 @@
46
46
  "LICENSE"
47
47
  ],
48
48
  "peerDependencies": {
49
- "@fabricorg/platform": "^0.3.2"
49
+ "@fabricorg/platform": "^0.5.0"
50
50
  },
51
51
  "dependencies": {},
52
52
  "devDependencies": {
@@ -54,7 +54,7 @@
54
54
  "tsup": "^8.5.0",
55
55
  "typescript": "^5.7.3",
56
56
  "vitest": "^4.1.5",
57
- "@fabricorg/platform": "0.3.2"
57
+ "@fabricorg/platform": "0.5.0"
58
58
  },
59
59
  "engines": {
60
60
  "node": ">=20"