@probelabs/visor 0.1.129 → 0.1.130

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/README.md +23 -0
  2. package/dist/cli-main.d.ts.map +1 -1
  3. package/dist/config.d.ts +4 -0
  4. package/dist/config.d.ts.map +1 -1
  5. package/dist/docs/author-permissions.md +20 -0
  6. package/dist/docs/enterprise-policy.md +1325 -0
  7. package/dist/docs/index.md +10 -0
  8. package/dist/docs/scheduler-storage.md +433 -0
  9. package/dist/docs/scheduler.md +12 -2
  10. package/dist/enterprise/license/validator.d.ts +39 -0
  11. package/dist/enterprise/license/validator.d.ts.map +1 -0
  12. package/dist/enterprise/loader.d.ts +25 -0
  13. package/dist/enterprise/loader.d.ts.map +1 -0
  14. package/dist/enterprise/policy/opa-compiler.d.ts +37 -0
  15. package/dist/enterprise/policy/opa-compiler.d.ts.map +1 -0
  16. package/dist/enterprise/policy/opa-http-evaluator.d.ts +36 -0
  17. package/dist/enterprise/policy/opa-http-evaluator.d.ts.map +1 -0
  18. package/dist/enterprise/policy/opa-policy-engine.d.ts +48 -0
  19. package/dist/enterprise/policy/opa-policy-engine.d.ts.map +1 -0
  20. package/dist/enterprise/policy/opa-wasm-evaluator.d.ts +34 -0
  21. package/dist/enterprise/policy/opa-wasm-evaluator.d.ts.map +1 -0
  22. package/dist/enterprise/policy/policy-input-builder.d.ts +120 -0
  23. package/dist/enterprise/policy/policy-input-builder.d.ts.map +1 -0
  24. package/dist/enterprise/scheduler/knex-store.d.ts +41 -0
  25. package/dist/enterprise/scheduler/knex-store.d.ts.map +1 -0
  26. package/dist/examples/README.md +23 -0
  27. package/dist/examples/enterprise-policy/README.md +344 -0
  28. package/dist/examples/enterprise-policy/policies/capability_resolve.rego +29 -0
  29. package/dist/examples/enterprise-policy/policies/capability_resolve_test.rego +230 -0
  30. package/dist/examples/enterprise-policy/policies/check_execute.rego +71 -0
  31. package/dist/examples/enterprise-policy/policies/check_execute_test.rego +321 -0
  32. package/dist/examples/enterprise-policy/policies/deploy_production.rego +33 -0
  33. package/dist/examples/enterprise-policy/policies/deploy_production_test.rego +29 -0
  34. package/dist/examples/enterprise-policy/policies/slack_channel_gate.rego +17 -0
  35. package/dist/examples/enterprise-policy/policies/slack_tool_restrict.rego +16 -0
  36. package/dist/examples/enterprise-policy/policies/tool_invoke.rego +24 -0
  37. package/dist/examples/enterprise-policy/policies/tool_invoke_test.rego +227 -0
  38. package/dist/examples/enterprise-policy/visor.yaml +64 -0
  39. package/dist/failure-condition-evaluator.d.ts +18 -0
  40. package/dist/failure-condition-evaluator.d.ts.map +1 -1
  41. package/dist/frontends/slack-frontend.d.ts +1 -0
  42. package/dist/frontends/slack-frontend.d.ts.map +1 -1
  43. package/dist/generated/config-schema.d.ts +139 -0
  44. package/dist/generated/config-schema.d.ts.map +1 -1
  45. package/dist/index.js +12121 -7169
  46. package/dist/liquid-extensions.d.ts.map +1 -1
  47. package/dist/output/traces/{run-2026-02-08T18-16-04-160Z.ndjson → run-2026-02-11T16-20-59-999Z.ndjson} +84 -84
  48. package/dist/{traces/run-2026-02-08T18-16-51-253Z.ndjson → output/traces/run-2026-02-11T16-21-47-711Z.ndjson} +1032 -1032
  49. package/dist/policy/default-engine.d.ts +17 -0
  50. package/dist/policy/default-engine.d.ts.map +1 -0
  51. package/dist/policy/index.d.ts +4 -0
  52. package/dist/policy/index.d.ts.map +1 -0
  53. package/dist/policy/policy-check-command.d.ts +65 -0
  54. package/dist/policy/policy-check-command.d.ts.map +1 -0
  55. package/dist/policy/types.d.ts +81 -0
  56. package/dist/policy/types.d.ts.map +1 -0
  57. package/dist/providers/ai-check-provider.d.ts.map +1 -1
  58. package/dist/providers/check-provider.interface.d.ts +2 -0
  59. package/dist/providers/check-provider.interface.d.ts.map +1 -1
  60. package/dist/providers/claude-code-check-provider.d.ts.map +1 -1
  61. package/dist/providers/mcp-check-provider.d.ts.map +1 -1
  62. package/dist/providers/mcp-custom-sse-server.d.ts.map +1 -1
  63. package/dist/providers/workflow-check-provider.d.ts.map +1 -1
  64. package/dist/scheduler/index.d.ts +2 -0
  65. package/dist/scheduler/index.d.ts.map +1 -1
  66. package/dist/scheduler/schedule-store.d.ts +33 -59
  67. package/dist/scheduler/schedule-store.d.ts.map +1 -1
  68. package/dist/scheduler/schedule-tool.d.ts.map +1 -1
  69. package/dist/scheduler/scheduler.d.ts +24 -3
  70. package/dist/scheduler/scheduler.d.ts.map +1 -1
  71. package/dist/scheduler/store/index.d.ts +7 -0
  72. package/dist/scheduler/store/index.d.ts.map +1 -0
  73. package/dist/scheduler/store/json-migrator.d.ts +10 -0
  74. package/dist/scheduler/store/json-migrator.d.ts.map +1 -0
  75. package/dist/scheduler/store/sqlite-store.d.ts +32 -0
  76. package/dist/scheduler/store/sqlite-store.d.ts.map +1 -0
  77. package/dist/scheduler/store/types.d.ts +127 -0
  78. package/dist/scheduler/store/types.d.ts.map +1 -0
  79. package/dist/sdk/check-provider-registry-M3Y6JMTW.mjs +28 -0
  80. package/dist/sdk/check-provider-registry-PANIXYRB.mjs +28 -0
  81. package/dist/sdk/{chunk-D5KI4YQ4.mjs → chunk-DIND4ZCV.mjs} +2 -2
  82. package/dist/sdk/{chunk-DGZPPGJJ.mjs → chunk-EUUAQBTW.mjs} +1463 -568
  83. package/dist/sdk/chunk-EUUAQBTW.mjs.map +1 -0
  84. package/dist/sdk/{chunk-XDLQ3UNF.mjs → chunk-GEW6LS32.mjs} +2 -2
  85. package/dist/sdk/{chunk-N7HO6KKC.mjs → chunk-HOKQOO3G.mjs} +11 -6
  86. package/dist/sdk/chunk-HOKQOO3G.mjs.map +1 -0
  87. package/dist/sdk/{chunk-XR7XXGL7.mjs → chunk-JL7JXCET.mjs} +2 -2
  88. package/dist/sdk/{chunk-6W75IMDC.mjs → chunk-LG4AUKHB.mjs} +2 -2
  89. package/dist/sdk/{chunk-BDGUM6BA.mjs → chunk-S6CD7GFM.mjs} +1463 -568
  90. package/dist/sdk/chunk-S6CD7GFM.mjs.map +1 -0
  91. package/dist/sdk/{chunk-PO7X5XI7.mjs → chunk-SZXICFQ3.mjs} +2 -2
  92. package/dist/sdk/{chunk-HEX3RL32.mjs → chunk-UCMJJ3IM.mjs} +5 -2
  93. package/dist/sdk/{chunk-HEX3RL32.mjs.map → chunk-UCMJJ3IM.mjs.map} +1 -1
  94. package/dist/sdk/{chunk-7YSOINAQ.mjs → chunk-UCNT3PDT.mjs} +342 -5
  95. package/dist/sdk/chunk-UCNT3PDT.mjs.map +1 -0
  96. package/dist/sdk/{chunk-R5Z7YWPB.mjs → chunk-V2IV3ILA.mjs} +7 -5
  97. package/dist/sdk/chunk-V2IV3ILA.mjs.map +1 -0
  98. package/dist/sdk/{chunk-SGS2VMEL.mjs → chunk-VMLORODQ.mjs} +107 -20
  99. package/dist/sdk/chunk-VMLORODQ.mjs.map +1 -0
  100. package/dist/sdk/{chunk-2KB35MB7.mjs → chunk-VPC3QSPW.mjs} +2 -2
  101. package/dist/sdk/{chunk-J5RGJQ53.mjs → chunk-YJRBN3XS.mjs} +2 -2
  102. package/dist/sdk/{command-executor-DVVXERLR.mjs → command-executor-TOYBBE7S.mjs} +4 -4
  103. package/dist/sdk/{config-7VTT64SQ.mjs → config-OGOS4ZU4.mjs} +4 -4
  104. package/dist/sdk/failure-condition-evaluator-HC3M5377.mjs +17 -0
  105. package/dist/sdk/{github-frontend-3N2NLO66.mjs → github-frontend-E2KJSC3Y.mjs} +7 -7
  106. package/dist/sdk/{host-ONVMEHAA.mjs → host-EE6EJ2FM.mjs} +4 -4
  107. package/dist/sdk/lazy-otel-5NH4ZJJM.mjs +24 -0
  108. package/dist/sdk/{liquid-extensions-5IZLTFSZ.mjs → liquid-extensions-E4EUOCES.mjs} +5 -5
  109. package/dist/sdk/memory-store-AAPL2MTE.mjs +12 -0
  110. package/dist/sdk/{metrics-GXQ2EDXA.mjs → metrics-I6A7IHG4.mjs} +3 -3
  111. package/dist/sdk/{prompt-state-YHGXB2OA.mjs → prompt-state-VAKKC773.mjs} +4 -4
  112. package/dist/sdk/{renderer-schema-CMXOLNIG.mjs → renderer-schema-HXEW6BRJ.mjs} +3 -3
  113. package/dist/sdk/{routing-S3Y7T2X3.mjs → routing-OZQWAGAI.mjs} +9 -8
  114. package/dist/sdk/schedule-tool-handler-B7TMSG6A.mjs +38 -0
  115. package/dist/sdk/schedule-tool-handler-IEB2VS7O.mjs +38 -0
  116. package/dist/sdk/sdk.d.mts +134 -4
  117. package/dist/sdk/sdk.d.ts +134 -4
  118. package/dist/sdk/sdk.js +2509 -1085
  119. package/dist/sdk/sdk.js.map +1 -1
  120. package/dist/sdk/sdk.mjs +14 -14
  121. package/dist/sdk/{slack-frontend-R3M2CACB.mjs → slack-frontend-LAY45IBR.mjs} +119 -29
  122. package/dist/sdk/slack-frontend-LAY45IBR.mjs.map +1 -0
  123. package/dist/sdk/{trace-helpers-YHNPC7MR.mjs → trace-helpers-PP3YHTAM.mjs} +3 -3
  124. package/dist/sdk/{tui-frontend-S546M7A7.mjs → tui-frontend-T56PZB67.mjs} +25 -16
  125. package/dist/sdk/tui-frontend-T56PZB67.mjs.map +1 -0
  126. package/dist/sdk/workflow-check-provider-2ET3SFZH.mjs +28 -0
  127. package/dist/sdk/workflow-check-provider-2ET3SFZH.mjs.map +1 -0
  128. package/dist/sdk/workflow-check-provider-HB4XTD4Z.mjs +28 -0
  129. package/dist/sdk/workflow-check-provider-HB4XTD4Z.mjs.map +1 -0
  130. package/dist/sdk/workflow-registry-AAD37XKZ.mjs +12 -0
  131. package/dist/sdk/workflow-registry-AAD37XKZ.mjs.map +1 -0
  132. package/dist/slack/client.d.ts +12 -0
  133. package/dist/slack/client.d.ts.map +1 -1
  134. package/dist/slack/slack-output-adapter.d.ts.map +1 -1
  135. package/dist/slack/socket-runner.d.ts.map +1 -1
  136. package/dist/state-machine/dispatch/execution-invoker.d.ts.map +1 -1
  137. package/dist/state-machine/dispatch/policy-gate.d.ts +28 -0
  138. package/dist/state-machine/dispatch/policy-gate.d.ts.map +1 -0
  139. package/dist/state-machine/states/level-dispatch.d.ts.map +1 -1
  140. package/dist/state-machine/states/routing.d.ts.map +1 -1
  141. package/dist/state-machine/states/wave-planning.d.ts.map +1 -1
  142. package/dist/state-machine-execution-engine.d.ts.map +1 -1
  143. package/dist/test-runner/core/flow-stage.d.ts.map +1 -1
  144. package/dist/test-runner/validator.d.ts.map +1 -1
  145. package/dist/traces/{run-2026-02-08T18-16-04-160Z.ndjson → run-2026-02-11T16-20-59-999Z.ndjson} +84 -84
  146. package/dist/{output/traces/run-2026-02-08T18-16-51-253Z.ndjson → traces/run-2026-02-11T16-21-47-711Z.ndjson} +1032 -1032
  147. package/dist/tui/chat-runner.d.ts.map +1 -1
  148. package/dist/tui/chat-state.d.ts +1 -0
  149. package/dist/tui/chat-state.d.ts.map +1 -1
  150. package/dist/tui/chat-tui.d.ts +3 -2
  151. package/dist/tui/chat-tui.d.ts.map +1 -1
  152. package/dist/tui/components/chat-box.d.ts +9 -0
  153. package/dist/tui/components/chat-box.d.ts.map +1 -1
  154. package/dist/tui/components/input-bar.d.ts +18 -1
  155. package/dist/tui/components/input-bar.d.ts.map +1 -1
  156. package/dist/tui/components/status-bar.d.ts +5 -2
  157. package/dist/tui/components/status-bar.d.ts.map +1 -1
  158. package/dist/tui/components/trace-viewer.d.ts +1 -0
  159. package/dist/tui/components/trace-viewer.d.ts.map +1 -1
  160. package/dist/tui/tui-frontend.d.ts.map +1 -1
  161. package/dist/types/config.d.ts +107 -3
  162. package/dist/types/config.d.ts.map +1 -1
  163. package/dist/types/engine.d.ts +5 -0
  164. package/dist/types/engine.d.ts.map +1 -1
  165. package/dist/types/execution.d.ts +1 -1
  166. package/dist/types/execution.d.ts.map +1 -1
  167. package/package.json +14 -4
  168. package/dist/sdk/check-provider-registry-ACRGIYOB.mjs +0 -28
  169. package/dist/sdk/check-provider-registry-VYHKFHK2.mjs +0 -28
  170. package/dist/sdk/chunk-7YSOINAQ.mjs.map +0 -1
  171. package/dist/sdk/chunk-BDGUM6BA.mjs.map +0 -1
  172. package/dist/sdk/chunk-DGZPPGJJ.mjs.map +0 -1
  173. package/dist/sdk/chunk-N7HO6KKC.mjs.map +0 -1
  174. package/dist/sdk/chunk-R5Z7YWPB.mjs.map +0 -1
  175. package/dist/sdk/chunk-SGS2VMEL.mjs.map +0 -1
  176. package/dist/sdk/failure-condition-evaluator-4WMDF4Q3.mjs +0 -17
  177. package/dist/sdk/memory-store-3N4AZCYB.mjs +0 -12
  178. package/dist/sdk/slack-frontend-R3M2CACB.mjs.map +0 -1
  179. package/dist/sdk/tui-frontend-S546M7A7.mjs.map +0 -1
  180. package/dist/sdk/workflow-check-provider-4F3432ZP.mjs +0 -28
  181. package/dist/sdk/workflow-check-provider-A44PBPG2.mjs +0 -28
  182. package/dist/sdk/workflow-registry-ZAYYXLEP.mjs +0 -12
  183. /package/dist/sdk/{check-provider-registry-ACRGIYOB.mjs.map → check-provider-registry-M3Y6JMTW.mjs.map} +0 -0
  184. /package/dist/sdk/{check-provider-registry-VYHKFHK2.mjs.map → check-provider-registry-PANIXYRB.mjs.map} +0 -0
  185. /package/dist/sdk/{chunk-D5KI4YQ4.mjs.map → chunk-DIND4ZCV.mjs.map} +0 -0
  186. /package/dist/sdk/{chunk-XDLQ3UNF.mjs.map → chunk-GEW6LS32.mjs.map} +0 -0
  187. /package/dist/sdk/{chunk-XR7XXGL7.mjs.map → chunk-JL7JXCET.mjs.map} +0 -0
  188. /package/dist/sdk/{chunk-6W75IMDC.mjs.map → chunk-LG4AUKHB.mjs.map} +0 -0
  189. /package/dist/sdk/{chunk-PO7X5XI7.mjs.map → chunk-SZXICFQ3.mjs.map} +0 -0
  190. /package/dist/sdk/{chunk-2KB35MB7.mjs.map → chunk-VPC3QSPW.mjs.map} +0 -0
  191. /package/dist/sdk/{chunk-J5RGJQ53.mjs.map → chunk-YJRBN3XS.mjs.map} +0 -0
  192. /package/dist/sdk/{command-executor-DVVXERLR.mjs.map → command-executor-TOYBBE7S.mjs.map} +0 -0
  193. /package/dist/sdk/{config-7VTT64SQ.mjs.map → config-OGOS4ZU4.mjs.map} +0 -0
  194. /package/dist/sdk/{failure-condition-evaluator-4WMDF4Q3.mjs.map → failure-condition-evaluator-HC3M5377.mjs.map} +0 -0
  195. /package/dist/sdk/{github-frontend-3N2NLO66.mjs.map → github-frontend-E2KJSC3Y.mjs.map} +0 -0
  196. /package/dist/sdk/{host-ONVMEHAA.mjs.map → host-EE6EJ2FM.mjs.map} +0 -0
  197. /package/dist/sdk/{liquid-extensions-5IZLTFSZ.mjs.map → lazy-otel-5NH4ZJJM.mjs.map} +0 -0
  198. /package/dist/sdk/{memory-store-3N4AZCYB.mjs.map → liquid-extensions-E4EUOCES.mjs.map} +0 -0
  199. /package/dist/sdk/{metrics-GXQ2EDXA.mjs.map → memory-store-AAPL2MTE.mjs.map} +0 -0
  200. /package/dist/sdk/{prompt-state-YHGXB2OA.mjs.map → metrics-I6A7IHG4.mjs.map} +0 -0
  201. /package/dist/sdk/{routing-S3Y7T2X3.mjs.map → prompt-state-VAKKC773.mjs.map} +0 -0
  202. /package/dist/sdk/{renderer-schema-CMXOLNIG.mjs.map → renderer-schema-HXEW6BRJ.mjs.map} +0 -0
  203. /package/dist/sdk/{trace-helpers-YHNPC7MR.mjs.map → routing-OZQWAGAI.mjs.map} +0 -0
  204. /package/dist/sdk/{workflow-check-provider-4F3432ZP.mjs.map → schedule-tool-handler-B7TMSG6A.mjs.map} +0 -0
  205. /package/dist/sdk/{workflow-check-provider-A44PBPG2.mjs.map → schedule-tool-handler-IEB2VS7O.mjs.map} +0 -0
  206. /package/dist/sdk/{workflow-registry-ZAYYXLEP.mjs.map → trace-helpers-PP3YHTAM.mjs.map} +0 -0
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Copyright (c) ProbeLabs. All rights reserved.
3
+ * Licensed under the Elastic License 2.0; you may not use this file except
4
+ * in compliance with the Elastic License 2.0.
5
+ */
6
+ /**
7
+ * OPA WASM Evaluator - loads and evaluates OPA policies locally.
8
+ *
9
+ * Supports three input formats:
10
+ * 1. Pre-compiled `.wasm` bundle — loaded directly (fastest startup)
11
+ * 2. `.rego` files or directory — auto-compiled to WASM via `opa build` CLI
12
+ * 3. Directory with `policy.wasm` inside — loaded directly
13
+ *
14
+ * Compilation and caching of .rego files is delegated to {@link OpaCompiler}.
15
+ *
16
+ * Requires:
17
+ * - `@open-policy-agent/opa-wasm` npm package (optional dep)
18
+ * - `opa` CLI on PATH (only when auto-compiling .rego files)
19
+ */
20
+ export declare class OpaWasmEvaluator {
21
+ private policy;
22
+ private dataDocument;
23
+ private compiler;
24
+ initialize(rulesPath: string | string[]): Promise<void>;
25
+ /**
26
+ * Load external data from a JSON file to use as the OPA data document.
27
+ * The loaded data will be passed to `policy.setData()` during evaluation,
28
+ * making it available in Rego via `data.<key>`.
29
+ */
30
+ loadData(dataPath: string): void;
31
+ evaluate(input: object): Promise<any>;
32
+ shutdown(): Promise<void>;
33
+ }
34
+ //# sourceMappingURL=opa-wasm-evaluator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"opa-wasm-evaluator.d.ts","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/enterprise/policy/opa-wasm-evaluator.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH;;;;;;;;;;;;;GAaG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAa;IAC3B,OAAO,CAAC,YAAY,CAAc;IAClC,OAAO,CAAC,QAAQ,CAAkC;IAE5C,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B7D;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI;IA2B1B,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC;IAcrC,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;CAehC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Copyright (c) ProbeLabs. All rights reserved.
3
+ * Licensed under the Elastic License 2.0; you may not use this file except
4
+ * in compliance with the Elastic License 2.0.
5
+ */
6
+ import type { PolicyConfig, StepPolicyOverride } from '../../policy/types';
7
+ /**
8
+ * OPA input document shape (internal to enterprise code).
9
+ * This mirrors what OPA .rego rules expect — OSS code never sees this type.
10
+ */
11
+ export interface OpaInput {
12
+ scope: string;
13
+ check?: {
14
+ id: string;
15
+ type: string;
16
+ group?: string;
17
+ tags?: string[];
18
+ criticality?: string;
19
+ sandbox?: string;
20
+ policy?: StepPolicyOverride;
21
+ };
22
+ tool?: {
23
+ serverName: string;
24
+ methodName: string;
25
+ transport?: string;
26
+ };
27
+ capability?: {
28
+ allowEdit?: boolean;
29
+ allowBash?: boolean;
30
+ allowedTools?: string[];
31
+ enableDelegate?: boolean;
32
+ sandbox?: string;
33
+ };
34
+ actor: {
35
+ authorAssociation?: string;
36
+ login?: string;
37
+ roles: string[];
38
+ isLocalMode: boolean;
39
+ slack?: {
40
+ userId?: string;
41
+ email?: string;
42
+ channelId?: string;
43
+ channelType?: 'channel' | 'dm' | 'group';
44
+ };
45
+ };
46
+ repository?: {
47
+ owner?: string;
48
+ name?: string;
49
+ branch?: string;
50
+ baseBranch?: string;
51
+ event?: string;
52
+ action?: string;
53
+ };
54
+ pullRequest?: {
55
+ number?: number;
56
+ labels?: string[];
57
+ draft?: boolean;
58
+ changedFiles?: number;
59
+ };
60
+ }
61
+ export interface ActorContext {
62
+ authorAssociation?: string;
63
+ login?: string;
64
+ isLocalMode: boolean;
65
+ slack?: {
66
+ userId?: string;
67
+ email?: string;
68
+ channelId?: string;
69
+ channelType?: 'channel' | 'dm' | 'group';
70
+ };
71
+ }
72
+ export interface RepositoryContext {
73
+ owner?: string;
74
+ name?: string;
75
+ branch?: string;
76
+ baseBranch?: string;
77
+ event?: string;
78
+ action?: string;
79
+ }
80
+ export interface PullRequestContext {
81
+ number?: number;
82
+ labels?: string[];
83
+ draft?: boolean;
84
+ changedFiles?: number;
85
+ }
86
+ export interface CheckContext {
87
+ id: string;
88
+ type: string;
89
+ group?: string;
90
+ tags?: string[];
91
+ criticality?: string;
92
+ sandbox?: string;
93
+ policy?: StepPolicyOverride;
94
+ }
95
+ /**
96
+ * Builds OPA-compatible input documents from engine context.
97
+ *
98
+ * Resolves actor roles from the `policy.roles` config section by matching
99
+ * the actor's authorAssociation and login against role definitions.
100
+ */
101
+ export declare class PolicyInputBuilder {
102
+ private roles;
103
+ private actor;
104
+ private repository?;
105
+ private pullRequest?;
106
+ constructor(policyConfig: PolicyConfig, actor: ActorContext, repository?: RepositoryContext, pullRequest?: PullRequestContext);
107
+ /** Resolve which roles apply to the current actor. */
108
+ resolveRoles(): string[];
109
+ private buildActor;
110
+ forCheckExecution(check: CheckContext): OpaInput;
111
+ forToolInvocation(serverName: string, methodName: string, transport?: string): OpaInput;
112
+ forCapabilityResolve(checkId: string, capabilities: {
113
+ allowEdit?: boolean;
114
+ allowBash?: boolean;
115
+ allowedTools?: string[];
116
+ enableDelegate?: boolean;
117
+ sandbox?: string;
118
+ }): OpaInput;
119
+ }
120
+ //# sourceMappingURL=policy-input-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy-input-builder.d.ts","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/enterprise/policy/policy-input-builder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Copyright (c) ProbeLabs. All rights reserved.
3
+ * Licensed under the Elastic License 2.0; you may not use this file except
4
+ * in compliance with the Elastic License 2.0.
5
+ */
6
+ import type { Schedule, ScheduleLimits } from '../../scheduler/schedule-store';
7
+ import type { ScheduleStoreBackend, ScheduleStoreStats, StorageConfig, HAConfig } from '../../scheduler/store/types';
8
+ /**
9
+ * Enterprise Knex-backed store for PostgreSQL, MySQL, and MSSQL
10
+ */
11
+ export declare class KnexStoreBackend implements ScheduleStoreBackend {
12
+ private knex;
13
+ private driver;
14
+ private connection;
15
+ constructor(driver: 'postgresql' | 'mysql' | 'mssql', storageConfig: StorageConfig, _haConfig?: HAConfig);
16
+ initialize(): Promise<void>;
17
+ private buildStandardConnection;
18
+ private buildMssqlConnection;
19
+ private resolveSslConfig;
20
+ private validateSslPath;
21
+ shutdown(): Promise<void>;
22
+ private migrateSchema;
23
+ private getKnex;
24
+ create(schedule: Omit<Schedule, 'id' | 'createdAt' | 'runCount' | 'failureCount' | 'status'>): Promise<Schedule>;
25
+ importSchedule(schedule: Schedule): Promise<void>;
26
+ get(id: string): Promise<Schedule | undefined>;
27
+ update(id: string, patch: Partial<Schedule>): Promise<Schedule | undefined>;
28
+ delete(id: string): Promise<boolean>;
29
+ getByCreator(creatorId: string): Promise<Schedule[]>;
30
+ getActiveSchedules(): Promise<Schedule[]>;
31
+ getDueSchedules(now?: number): Promise<Schedule[]>;
32
+ findByWorkflow(creatorId: string, workflowName: string): Promise<Schedule[]>;
33
+ getAll(): Promise<Schedule[]>;
34
+ getStats(): Promise<ScheduleStoreStats>;
35
+ validateLimits(creatorId: string, isRecurring: boolean, limits: ScheduleLimits): Promise<void>;
36
+ tryAcquireLock(lockId: string, nodeId: string, ttlSeconds: number): Promise<string | null>;
37
+ releaseLock(lockId: string, lockToken: string): Promise<void>;
38
+ renewLock(lockId: string, lockToken: string, ttlSeconds: number): Promise<boolean>;
39
+ flush(): Promise<void>;
40
+ }
41
+ //# sourceMappingURL=knex-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"knex-store.d.ts","sourceRoot":"","sources":["file:///home/runner/work/visor/visor/src/enterprise/scheduler/knex-store.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAYH,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAC/E,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,aAAa,EACb,QAAQ,EAET,MAAM,6BAA6B,CAAC;AA+FrC;;GAEG;AACH,qBAAa,gBAAiB,YAAW,oBAAoB;IAC3D,OAAO,CAAC,IAAI,CAAqB;IACjC,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,UAAU,CAAyB;gBAGzC,MAAM,EAAE,YAAY,GAAG,OAAO,GAAG,OAAO,EACxC,aAAa,EAAE,aAAa,EAC5B,SAAS,CAAC,EAAE,QAAQ;IAMhB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAkDjC,OAAO,CAAC,uBAAuB;IAW/B,OAAO,CAAC,oBAAoB;IAkB5B,OAAO,CAAC,gBAAgB;IA4BxB,OAAO,CAAC,eAAe;IAWjB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YAOjB,aAAa;IA4C3B,OAAO,CAAC,OAAO;IAST,MAAM,CACV,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,GAAG,WAAW,GAAG,UAAU,GAAG,cAAc,GAAG,QAAQ,CAAC,GACpF,OAAO,CAAC,QAAQ,CAAC;IAkBd,cAAc,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAOjD,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAM9C,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC;IAgB3E,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAYpC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAMpD,kBAAkB,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAMzC,eAAe,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAsBlD,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAW5E,MAAM,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;IAM7B,QAAQ,IAAI,OAAO,CAAC,kBAAkB,CAAC;IA4BvC,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,OAAO,EACpB,MAAM,EAAE,cAAc,GACrB,OAAO,CAAC,IAAI,CAAC;IAqCV,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAmC1F,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK7D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAalF,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAG7B"}
@@ -134,6 +134,9 @@ Example configurations demonstrating various Visor features and use cases.
134
134
  - **`sandbox-multi-env.yaml`** - Multiple sandbox environments per check
135
135
  - **`sandbox-read-only.yaml`** - Read-only sandbox with network isolation
136
136
 
137
+ ### Enterprise Policy Examples (EE)
138
+ - **`enterprise-policy/`** - OPA policy engine with role-based access control **(Enterprise Edition -- requires license, contact hello@probelabs.com)**
139
+
137
140
  ### Integration Examples
138
141
  - **`jira-simple-example.yaml`** - Simple JIRA integration
139
142
  - **`jira-single-issue-workflow.yaml`** - Single JIRA issue workflow
@@ -464,6 +467,26 @@ visor --config examples/workflows/quick-pr-check.yaml --input "pr_type=feature"
464
467
  visor --config examples/workflows/workflow-composition-example.yaml
465
468
  ```
466
469
 
470
+ ## Enterprise Policy Engine (EE)
471
+
472
+ > **Enterprise Edition feature.** Requires a Visor EE license.
473
+ > Contact **hello@probelabs.com** for licensing.
474
+
475
+ Role-based access control for checks, MCP tools, and AI capabilities using OPA (Open Policy Agent) policies:
476
+
477
+ ```bash
478
+ # Install EE build
479
+ npm install @probelabs/visor@ee
480
+
481
+ # Set license
482
+ export VISOR_LICENSE="<your-jwt-token>"
483
+
484
+ # Run with policy enforcement
485
+ visor --config examples/enterprise-policy/visor.yaml
486
+ ```
487
+
488
+ See [`examples/enterprise-policy/README.md`](enterprise-policy/README.md) for full documentation, configuration reference, and Rego policy examples.
489
+
467
490
  ## 📚 Further Reading
468
491
 
469
492
  - [Main README](../README.md) - Complete Visor documentation
@@ -0,0 +1,344 @@
1
+ # OPA Policy Engine (Enterprise Edition)
2
+
3
+ > **This is an Enterprise Edition feature.** A valid Visor EE license is required.
4
+ > To get a license or learn more, contact **hello@probelabs.com**.
5
+
6
+ The OPA (Open Policy Agent) policy engine gives you fine-grained, role-based access control over Visor checks, MCP tools, and AI capabilities. Policies are written in [Rego](https://www.openpolicyagent.org/docs/latest/policy-language/) and evaluated locally via WASM or against a remote OPA server.
7
+
8
+ For the full documentation, see [docs/enterprise-policy.md](../../docs/enterprise-policy.md).
9
+
10
+ ## What it controls
11
+
12
+ | Scope | What it does |
13
+ |-------|-------------|
14
+ | **Check execution** | Gate which checks can run based on the actor's role |
15
+ | **MCP tool access** | Allow or block specific MCP methods per role |
16
+ | **AI capabilities** | Restrict `allowBash`, `allowEdit`, and tool lists per role |
17
+
18
+ ## Prerequisites
19
+
20
+ | Dependency | Purpose |
21
+ |-----------|---------|
22
+ | `@probelabs/visor@ee` | Visor Enterprise Edition build |
23
+ | Valid EE license (JWT) | Activates the policy engine |
24
+ | `opa` CLI | Compiles `.rego` files to WASM at startup (local mode) |
25
+ | `@open-policy-agent/opa-wasm` | Evaluates WASM policies in-process (installed automatically with EE build) |
26
+
27
+ ### Installing the OPA CLI
28
+
29
+ The OPA CLI is needed to compile `.rego` files into WebAssembly at startup.
30
+
31
+ **macOS:**
32
+ ```bash
33
+ brew install opa
34
+ ```
35
+
36
+ **Linux:**
37
+ ```bash
38
+ curl -L -o /usr/local/bin/opa \
39
+ https://openpolicyagent.org/downloads/latest/opa_linux_amd64_static
40
+ chmod +x /usr/local/bin/opa
41
+ ```
42
+
43
+ **Verify:**
44
+ ```bash
45
+ opa version
46
+ ```
47
+
48
+ > You can skip the OPA CLI if you pre-compile your `.rego` files into a `.wasm` bundle (see [Pre-compiling](#pre-compiling-wasm-bundles) below).
49
+
50
+ ## Quick start
51
+
52
+ ### 1. Install the EE build
53
+
54
+ ```bash
55
+ npm install @probelabs/visor@ee
56
+ ```
57
+
58
+ ### 2. Set your license
59
+
60
+ ```bash
61
+ # Option A: environment variable
62
+ export VISOR_LICENSE="<your-jwt-token>"
63
+
64
+ # Option B: file in project root
65
+ echo "<your-jwt-token>" > .visor-license
66
+ ```
67
+
68
+ ### 3. Add the `policy:` block to your `.visor.yaml`
69
+
70
+ ```yaml
71
+ version: "1.0"
72
+
73
+ policy:
74
+ engine: local # 'local' (WASM) or 'remote' (HTTP OPA server)
75
+ rules: ./policies/ # Path to .rego files (local mode)
76
+ fallback: deny # 'allow' or 'deny' when evaluation fails
77
+ timeout: 5000 # Evaluation timeout in ms
78
+
79
+ roles:
80
+ admin:
81
+ author_association: [OWNER]
82
+ users: [cto-username]
83
+ developer:
84
+ author_association: [MEMBER, COLLABORATOR]
85
+ external:
86
+ author_association: [FIRST_TIME_CONTRIBUTOR, FIRST_TIMER, NONE]
87
+ ```
88
+
89
+ ### 4. Write Rego policies
90
+
91
+ See the `policies/` directory in this example for ready-to-use policies:
92
+
93
+ - **`check_execute.rego`** -- Controls which checks each role can run
94
+ - **`tool_invoke.rego`** -- Blocks destructive MCP methods for non-admins
95
+ - **`capability_resolve.rego`** -- Restricts AI capabilities (bash, file editing) by role
96
+
97
+ ### 5. Run
98
+
99
+ ```bash
100
+ visor --config .visor.yaml
101
+ ```
102
+
103
+ Checks that the actor's role is not authorized for will be skipped with reason `policy_denied`.
104
+
105
+ ## Files in this example
106
+
107
+ ```
108
+ enterprise-policy/
109
+ visor.yaml # Example .visor.yaml with policy configuration
110
+ policies/
111
+ check_execute.rego # Check execution gating
112
+ tool_invoke.rego # MCP tool access control
113
+ capability_resolve.rego # AI capability restrictions
114
+ ```
115
+
116
+ ## Configuration reference
117
+
118
+ ### Top-level `policy:` block
119
+
120
+ | Field | Type | Description |
121
+ |-------|------|-------------|
122
+ | `engine` | `local` \| `remote` \| `disabled` | Evaluation backend |
123
+ | `rules` | `string` \| `string[]` | Path to `.rego` files or `.wasm` bundle (local mode) |
124
+ | `url` | `string` | OPA server URL (remote mode) |
125
+ | `fallback` | `allow` \| `deny` \| `warn` | Default decision on evaluation failure |
126
+ | `timeout` | `number` | Evaluation timeout in ms (default: 5000) |
127
+ | `roles` | `map` | Role definitions (see below) |
128
+
129
+ ### Role definitions
130
+
131
+ Roles map GitHub author associations, team slugs, or explicit usernames to named roles that your Rego policies reference.
132
+
133
+ ```yaml
134
+ roles:
135
+ admin:
136
+ author_association: [OWNER]
137
+ users: [alice, bob]
138
+ developer:
139
+ author_association: [MEMBER, COLLABORATOR]
140
+ external:
141
+ author_association: [FIRST_TIME_CONTRIBUTOR, NONE]
142
+ ```
143
+
144
+ ### Per-step `policy:` override
145
+
146
+ Individual steps can declare role requirements directly in YAML, without writing Rego:
147
+
148
+ ```yaml
149
+ steps:
150
+ deploy-production:
151
+ type: command
152
+ exec: ./deploy.sh production
153
+ policy:
154
+ require: admin # Only admin role can trigger this
155
+ deny: [external] # Explicitly deny external contributors
156
+ rule: visor/deploy/prod # Optional: custom OPA rule path
157
+ ```
158
+
159
+ ## Rego policy structure
160
+
161
+ Policies live under `package visor.<scope>` and must export an `allowed` boolean:
162
+
163
+ ```rego
164
+ package visor.check.execute
165
+
166
+ default allowed = false
167
+
168
+ allowed {
169
+ input.actor.roles[_] == "admin"
170
+ }
171
+
172
+ reason = "access denied" { not allowed }
173
+ ```
174
+
175
+ ### Available scopes
176
+
177
+ | Package | Evaluated when |
178
+ |---------|---------------|
179
+ | `visor.check.execute` | Before each check runs |
180
+ | `visor.tool.invoke` | Before each MCP tool call |
181
+ | `visor.capability.resolve` | When assembling AI config |
182
+
183
+ ### Input document
184
+
185
+ Your Rego policies receive an `input` document with these fields:
186
+
187
+ ```json
188
+ {
189
+ "scope": "check.execute",
190
+ "check": {
191
+ "id": "deploy-production",
192
+ "type": "command",
193
+ "tags": ["deploy"],
194
+ "criticality": "external",
195
+ "policy": { "require": "admin" }
196
+ },
197
+ "actor": {
198
+ "login": "alice",
199
+ "authorAssociation": "MEMBER",
200
+ "roles": ["developer"],
201
+ "isLocalMode": false
202
+ },
203
+ "repository": {
204
+ "owner": "probelabs",
205
+ "name": "visor",
206
+ "branch": "feat/new-feature"
207
+ }
208
+ }
209
+ ```
210
+
211
+ ## Writing Rego for Visor
212
+
213
+ ### Checking roles
214
+
215
+ Use `input.actor.roles[_]` to check if the actor has a specific role:
216
+
217
+ ```rego
218
+ allowed {
219
+ input.actor.roles[_] == "admin"
220
+ }
221
+ ```
222
+
223
+ ### Handling per-step YAML requirements
224
+
225
+ When a step declares `policy.require`, your Rego must handle both string and array values:
226
+
227
+ ```rego
228
+ # String require (e.g., require: admin)
229
+ allowed {
230
+ required := input.check.policy.require
231
+ is_string(required)
232
+ input.actor.roles[_] == required
233
+ }
234
+
235
+ # Array require (e.g., require: [developer, admin])
236
+ allowed {
237
+ required := input.check.policy.require
238
+ is_array(required)
239
+ required[_] == input.actor.roles[_]
240
+ }
241
+ ```
242
+
243
+ ### Local mode bypass
244
+
245
+ When running locally (CLI), you may want to allow all checks:
246
+
247
+ ```rego
248
+ allowed {
249
+ input.actor.isLocalMode == true
250
+ }
251
+ ```
252
+
253
+ ### WASM-safe patterns
254
+
255
+ OPA compiles Rego to WebAssembly for fast in-process evaluation. Some patterns are not WASM-safe:
256
+
257
+ ```rego
258
+ # BAD: not safe for WASM compilation
259
+ allowed = false {
260
+ not input.actor.roles[_] == "admin"
261
+ }
262
+
263
+ # GOOD: use a helper rule
264
+ is_admin { input.actor.roles[_] == "admin" }
265
+ allowed = false {
266
+ not is_admin
267
+ }
268
+ ```
269
+
270
+ ### Testing your policies
271
+
272
+ Use the OPA CLI to test policies before deploying:
273
+
274
+ ```bash
275
+ # Evaluate with test input
276
+ echo '{"actor":{"roles":["developer"],"isLocalMode":false},"check":{"id":"deploy-staging"}}' | \
277
+ opa eval -d policies/ -i /dev/stdin 'data.visor.check.execute.allowed'
278
+
279
+ # Check for syntax errors
280
+ opa check policies/
281
+
282
+ # Run OPA unit tests (if you have _test.rego files)
283
+ opa test policies/ -v
284
+ ```
285
+
286
+ ## Pre-compiling WASM bundles
287
+
288
+ For faster startup (skip compilation at runtime), pre-compile your policies:
289
+
290
+ ```bash
291
+ # Compile all .rego files into a WASM bundle
292
+ opa build -t wasm -e visor -d policies/ -o bundle.tar.gz
293
+
294
+ # Extract the WASM file
295
+ tar -xzf bundle.tar.gz /policy.wasm
296
+
297
+ # Reference the .wasm file in config
298
+ # policy:
299
+ # rules: ./policy.wasm
300
+ ```
301
+
302
+ > When compiling with `opa build`, always use `-e visor` as the entrypoint.
303
+
304
+ ## Remote OPA server
305
+
306
+ To evaluate against a running OPA server instead of local WASM:
307
+
308
+ ```yaml
309
+ policy:
310
+ engine: remote
311
+ url: http://opa:8181
312
+ fallback: deny
313
+ timeout: 3000
314
+ ```
315
+
316
+ Visor sends POST requests to `${url}/v1/data/visor/<scope>` with `{ "input": ... }`.
317
+
318
+ ### Running an OPA server
319
+
320
+ ```bash
321
+ # Local server with your policies
322
+ opa run --server --addr :8181 ./policies/
323
+
324
+ # Docker
325
+ docker run -p 8181:8181 \
326
+ -v $(pwd)/policies:/policies \
327
+ openpolicyagent/opa:latest \
328
+ run --server --addr :8181 /policies/
329
+ ```
330
+
331
+ ## Without a license
332
+
333
+ If no valid license is found, the policy engine is silently disabled and all checks run as normal (the OSS default). No error is raised.
334
+
335
+ ## Further reading
336
+
337
+ - [Full enterprise policy documentation](../../docs/enterprise-policy.md) -- comprehensive guide with troubleshooting
338
+ - [Author permissions (OSS)](../../docs/author-permissions.md) -- simpler, inline permission checks
339
+ - [OPA documentation](https://www.openpolicyagent.org/docs/latest/) -- official OPA docs
340
+ - [Rego playground](https://play.openpolicyagent.org/) -- interactive Rego editor and tester
341
+
342
+ ---
343
+
344
+ **Questions? Need a license?** Contact **hello@probelabs.com**
@@ -0,0 +1,29 @@
1
+ # AI capability restriction policy (Visor Enterprise Edition)
2
+ # Controls which AI capabilities (bash, file editing) are available per role.
3
+ # Contact hello@probelabs.com for licensing.
4
+
5
+ package visor.capability.resolve
6
+
7
+ # Helper: actor has developer role
8
+ is_developer { input.actor.roles[_] == "developer" }
9
+
10
+ # Helper: actor has admin role
11
+ is_admin { input.actor.roles[_] == "admin" }
12
+
13
+ # Disable file editing for non-developers
14
+ capabilities["allowEdit"] = false {
15
+ not is_developer
16
+ not is_admin
17
+ }
18
+
19
+ # Disable bash for external contributors
20
+ capabilities["allowBash"] = false {
21
+ input.actor.roles[_] == "external"
22
+ }
23
+
24
+ reason = "edit capability restricted for non-developer/admin roles" {
25
+ capabilities["allowEdit"] == false
26
+ }
27
+ reason = "bash capability restricted for external contributors" {
28
+ capabilities["allowBash"] == false
29
+ }