@stigmer/server 3.22.1-dev.20260922095755 → 3.22.1

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 (268) hide show
  1. package/dist/authorization/authorizer.d.ts +8 -4
  2. package/dist/authorization/authorizer.d.ts.map +1 -1
  3. package/dist/authorization/authorizer.js +9 -5
  4. package/dist/authorization/authorizer.js.map +1 -1
  5. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  6. package/dist/authorization/derived-tuples.js +25 -10
  7. package/dist/authorization/derived-tuples.js.map +1 -1
  8. package/dist/authorization/evaluator.d.ts +8 -7
  9. package/dist/authorization/evaluator.d.ts.map +1 -1
  10. package/dist/authorization/evaluator.js +20 -4
  11. package/dist/authorization/evaluator.js.map +1 -1
  12. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  13. package/dist/authorization/list-read-scope.js +9 -5
  14. package/dist/authorization/list-read-scope.js.map +1 -1
  15. package/dist/authorization/model/agent.d.ts.map +1 -1
  16. package/dist/authorization/model/agent.js +5 -4
  17. package/dist/authorization/model/agent.js.map +1 -1
  18. package/dist/authorization/model/agent_instance.d.ts.map +1 -1
  19. package/dist/authorization/model/agent_instance.js +2 -2
  20. package/dist/authorization/model/agent_instance.js.map +1 -1
  21. package/dist/authorization/model/mcp_server.d.ts.map +1 -1
  22. package/dist/authorization/model/mcp_server.js +2 -2
  23. package/dist/authorization/model/mcp_server.js.map +1 -1
  24. package/dist/authorization/model/plugin.d.ts.map +1 -1
  25. package/dist/authorization/model/plugin.js +4 -3
  26. package/dist/authorization/model/plugin.js.map +1 -1
  27. package/dist/authorization/model/rewrite.d.ts +10 -8
  28. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  29. package/dist/authorization/model/rewrite.js +3 -0
  30. package/dist/authorization/model/rewrite.js.map +1 -1
  31. package/dist/authorization/model/skill.d.ts.map +1 -1
  32. package/dist/authorization/model/skill.js +2 -2
  33. package/dist/authorization/model/skill.js.map +1 -1
  34. package/dist/authorization/model/workflow.d.ts.map +1 -1
  35. package/dist/authorization/model/workflow.js +2 -2
  36. package/dist/authorization/model/workflow.js.map +1 -1
  37. package/dist/authorization/model/workflow_instance.d.ts.map +1 -1
  38. package/dist/authorization/model/workflow_instance.js +2 -2
  39. package/dist/authorization/model/workflow_instance.js.map +1 -1
  40. package/dist/authorization/organization-directory.d.ts.map +1 -1
  41. package/dist/authorization/organization-directory.js +3 -2
  42. package/dist/authorization/organization-directory.js.map +1 -1
  43. package/dist/authorization/store-test-kit.d.ts +6 -0
  44. package/dist/authorization/store-test-kit.d.ts.map +1 -1
  45. package/dist/authorization/store-test-kit.js +62 -16
  46. package/dist/authorization/store-test-kit.js.map +1 -1
  47. package/dist/authorization/tuples.d.ts +32 -13
  48. package/dist/authorization/tuples.d.ts.map +1 -1
  49. package/dist/authorization/tuples.js +11 -3
  50. package/dist/authorization/tuples.js.map +1 -1
  51. package/dist/domain/agent/controller.d.ts.map +1 -1
  52. package/dist/domain/agent/controller.js +4 -4
  53. package/dist/domain/agent/controller.js.map +1 -1
  54. package/dist/domain/agentchannel/controller.d.ts.map +1 -1
  55. package/dist/domain/agentchannel/controller.js +1 -3
  56. package/dist/domain/agentchannel/controller.js.map +1 -1
  57. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  58. package/dist/domain/agentexecution/controller.js +1 -3
  59. package/dist/domain/agentexecution/controller.js.map +1 -1
  60. package/dist/domain/agentinstance/controller.d.ts.map +1 -1
  61. package/dist/domain/agentinstance/controller.js +4 -3
  62. package/dist/domain/agentinstance/controller.js.map +1 -1
  63. package/dist/domain/agentshare/constants.d.ts +11 -6
  64. package/dist/domain/agentshare/constants.d.ts.map +1 -1
  65. package/dist/domain/agentshare/constants.js +16 -8
  66. package/dist/domain/agentshare/constants.js.map +1 -1
  67. package/dist/domain/agentshare/controller.d.ts.map +1 -1
  68. package/dist/domain/agentshare/controller.js +1 -3
  69. package/dist/domain/agentshare/controller.js.map +1 -1
  70. package/dist/domain/agentshare/steps.d.ts +25 -18
  71. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  72. package/dist/domain/agentshare/steps.js +142 -41
  73. package/dist/domain/agentshare/steps.js.map +1 -1
  74. package/dist/domain/environment/controller.d.ts.map +1 -1
  75. package/dist/domain/environment/controller.js +3 -2
  76. package/dist/domain/environment/controller.js.map +1 -1
  77. package/dist/domain/executioncontext/controller.d.ts.map +1 -1
  78. package/dist/domain/executioncontext/controller.js +1 -2
  79. package/dist/domain/executioncontext/controller.js.map +1 -1
  80. package/dist/domain/mcpserver/controller.d.ts.map +1 -1
  81. package/dist/domain/mcpserver/controller.js +4 -3
  82. package/dist/domain/mcpserver/controller.js.map +1 -1
  83. package/dist/domain/plugin/controller.d.ts.map +1 -1
  84. package/dist/domain/plugin/controller.js +3 -1
  85. package/dist/domain/plugin/controller.js.map +1 -1
  86. package/dist/domain/plugin/push.d.ts +5 -7
  87. package/dist/domain/plugin/push.d.ts.map +1 -1
  88. package/dist/domain/plugin/push.js +14 -8
  89. package/dist/domain/plugin/push.js.map +1 -1
  90. package/dist/domain/schedule/controller.d.ts.map +1 -1
  91. package/dist/domain/schedule/controller.js +1 -3
  92. package/dist/domain/schedule/controller.js.map +1 -1
  93. package/dist/domain/session/controller.d.ts.map +1 -1
  94. package/dist/domain/session/controller.js +2 -3
  95. package/dist/domain/session/controller.js.map +1 -1
  96. package/dist/domain/skill/controller.d.ts.map +1 -1
  97. package/dist/domain/skill/controller.js +2 -0
  98. package/dist/domain/skill/controller.js.map +1 -1
  99. package/dist/domain/workflow/controller.d.ts.map +1 -1
  100. package/dist/domain/workflow/controller.js +6 -14
  101. package/dist/domain/workflow/controller.js.map +1 -1
  102. package/dist/domain/workflow/registry/data/task-kind-registry.json +1 -1
  103. package/dist/domain/workflow/validation/task-config-constraints.d.ts +1 -10
  104. package/dist/domain/workflow/validation/task-config-constraints.d.ts.map +1 -1
  105. package/dist/domain/workflow/validation/task-config-constraints.js +2 -3
  106. package/dist/domain/workflow/validation/task-config-constraints.js.map +1 -1
  107. package/dist/domain/workflowexecution/controller.d.ts.map +1 -1
  108. package/dist/domain/workflowexecution/controller.js +2 -4
  109. package/dist/domain/workflowexecution/controller.js.map +1 -1
  110. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  111. package/dist/domain/workflowinstance/controller.js +4 -3
  112. package/dist/domain/workflowinstance/controller.js.map +1 -1
  113. package/dist/extensions/authorization-queries.d.ts +5 -6
  114. package/dist/extensions/authorization-queries.d.ts.map +1 -1
  115. package/dist/extensions/list-read-scope.d.ts +1 -1
  116. package/dist/extensions/resource-authorization.d.ts +2 -3
  117. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  118. package/dist/index.d.ts +3 -1
  119. package/dist/index.d.ts.map +1 -1
  120. package/dist/index.js +13 -0
  121. package/dist/index.js.map +1 -1
  122. package/dist/pipeline/apiresource-meta.d.ts +3 -12
  123. package/dist/pipeline/apiresource-meta.d.ts.map +1 -1
  124. package/dist/pipeline/apiresource-meta.js +10 -21
  125. package/dist/pipeline/apiresource-meta.js.map +1 -1
  126. package/dist/pipeline/steps/authorization-tuples.d.ts +3 -9
  127. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  128. package/dist/pipeline/steps/authorization-tuples.js +11 -9
  129. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  130. package/dist/pipeline/steps/references.d.ts +20 -178
  131. package/dist/pipeline/steps/references.d.ts.map +1 -1
  132. package/dist/pipeline/steps/references.js +43 -344
  133. package/dist/pipeline/steps/references.js.map +1 -1
  134. package/dist/pipeline/steps/visibility-gates.d.ts +27 -0
  135. package/dist/pipeline/steps/visibility-gates.d.ts.map +1 -0
  136. package/dist/pipeline/steps/visibility-gates.js +139 -0
  137. package/dist/pipeline/steps/visibility-gates.js.map +1 -0
  138. package/dist/query/search/controller.js +1 -0
  139. package/dist/query/search/controller.js.map +1 -1
  140. package/dist/query/search/criteria.d.ts +5 -1
  141. package/dist/query/search/criteria.d.ts.map +1 -1
  142. package/dist/query/search/criteria.js +13 -3
  143. package/dist/query/search/criteria.js.map +1 -1
  144. package/dist/query/search/handler.d.ts +4 -5
  145. package/dist/query/search/handler.d.ts.map +1 -1
  146. package/dist/query/search/handler.js +6 -7
  147. package/dist/query/search/handler.js.map +1 -1
  148. package/dist/query/search/query-store.d.ts.map +1 -1
  149. package/dist/query/search/query-store.js +2 -0
  150. package/dist/query/search/query-store.js.map +1 -1
  151. package/dist/store/interface.d.ts +6 -3
  152. package/dist/store/interface.d.ts.map +1 -1
  153. package/dist/store/interface.js.map +1 -1
  154. package/dist/store/postgres/migrations.d.ts +1 -3
  155. package/dist/store/postgres/migrations.d.ts.map +1 -1
  156. package/dist/store/postgres/migrations.js +1 -35
  157. package/dist/store/postgres/migrations.js.map +1 -1
  158. package/dist/store/postgres/store.d.ts.map +1 -1
  159. package/dist/store/postgres/store.js +9 -4
  160. package/dist/store/postgres/store.js.map +1 -1
  161. package/dist/store/sqlite/migrations.d.ts +1 -3
  162. package/dist/store/sqlite/migrations.d.ts.map +1 -1
  163. package/dist/store/sqlite/migrations.js +1 -36
  164. package/dist/store/sqlite/migrations.js.map +1 -1
  165. package/dist/store/sqlite/store.d.ts.map +1 -1
  166. package/dist/store/sqlite/store.js +8 -4
  167. package/dist/store/sqlite/store.js.map +1 -1
  168. package/package.json +6 -6
  169. package/src/authorization/README.md +26 -24
  170. package/src/authorization/__tests__/authorizer.test.ts +9 -10
  171. package/src/authorization/__tests__/derived-tuples.test.ts +11 -4
  172. package/src/authorization/__tests__/evaluator.test.ts +73 -14
  173. package/src/authorization/__tests__/facts.test.ts +2 -2
  174. package/src/authorization/__tests__/fixtures/fga/agent-instance-creation.fga.yaml +185 -0
  175. package/src/authorization/__tests__/fixtures/fga/blueprint-private-visibility.fga.yaml +98 -6
  176. package/src/authorization/__tests__/fixtures/fga/cross-org-share-creation.fga.yaml +98 -0
  177. package/src/authorization/__tests__/fixtures/fga/default-instance-inheritance.fga.yaml +61 -4
  178. package/src/authorization/__tests__/fixtures/fga/mcp-server-authoring.fga.yaml +143 -0
  179. package/src/authorization/__tests__/fixtures/fga/org-admin-owner-inheritance.fga.yaml +21 -1
  180. package/src/authorization/__tests__/fixtures/fga/platform-visibility.fga.yaml +25 -1
  181. package/src/authorization/__tests__/fixtures/fga/public-visibility-setter.fga.yaml +52 -0
  182. package/src/authorization/__tests__/fixtures/fga/workflow-execution-sharing.fga.yaml +3 -1
  183. package/src/authorization/__tests__/list-read-scope.test.ts +17 -18
  184. package/src/authorization/__tests__/store-tests.test.ts +8 -1
  185. package/src/authorization/__tests__/tuples.test.ts +11 -12
  186. package/src/authorization/authorizer.ts +9 -4
  187. package/src/authorization/derived-tuples.ts +31 -14
  188. package/src/authorization/evaluator.ts +44 -8
  189. package/src/authorization/list-read-scope.ts +11 -5
  190. package/src/authorization/model/agent.ts +5 -2
  191. package/src/authorization/model/agent_instance.ts +2 -0
  192. package/src/authorization/model/mcp_server.ts +2 -0
  193. package/src/authorization/model/plugin.ts +4 -1
  194. package/src/authorization/model/rewrite.ts +13 -8
  195. package/src/authorization/model/skill.ts +2 -0
  196. package/src/authorization/model/workflow.ts +2 -0
  197. package/src/authorization/model/workflow_instance.ts +2 -0
  198. package/src/authorization/organization-directory.ts +3 -1
  199. package/src/authorization/store-test-kit.ts +75 -16
  200. package/src/authorization/tuples.ts +39 -16
  201. package/src/domain/agent/__tests__/agent.test.ts +4 -11
  202. package/src/domain/agent/controller.ts +7 -7
  203. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +48 -223
  204. package/src/domain/agentchannel/controller.ts +1 -6
  205. package/src/domain/agentexecution/controller.ts +1 -6
  206. package/src/domain/agentinstance/controller.ts +12 -6
  207. package/src/domain/agentshare/__tests__/agentshare.test.ts +172 -196
  208. package/src/domain/agentshare/__tests__/create-authorization.test.ts +31 -16
  209. package/src/domain/agentshare/constants.ts +26 -14
  210. package/src/domain/agentshare/controller.ts +1 -6
  211. package/src/domain/agentshare/steps.ts +194 -41
  212. package/src/domain/environment/controller.ts +8 -5
  213. package/src/domain/executioncontext/controller.ts +1 -5
  214. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +28 -115
  215. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +18 -53
  216. package/src/domain/mcpserver/controller.ts +12 -6
  217. package/src/domain/plugin/controller.ts +8 -1
  218. package/src/domain/plugin/push.ts +16 -8
  219. package/src/domain/schedule/controller.ts +1 -6
  220. package/src/domain/session/controller.ts +4 -12
  221. package/src/domain/skill/controller.ts +7 -0
  222. package/src/domain/workflow/controller.ts +10 -28
  223. package/src/domain/workflow/registry/data/task-kind-registry.json +1 -1
  224. package/src/domain/workflow/validation/task-config-constraints.ts +3 -7
  225. package/src/domain/workflowexecution/controller.ts +2 -7
  226. package/src/domain/workflowinstance/controller.ts +12 -6
  227. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +19 -32
  228. package/src/extensions/__tests__/extension-composition.test.ts +4 -4
  229. package/src/extensions/__tests__/list-read-scope-composed.test.ts +6 -9
  230. package/src/extensions/authorization-queries.ts +5 -6
  231. package/src/extensions/list-read-scope.ts +1 -1
  232. package/src/extensions/resource-authorization.ts +5 -3
  233. package/src/index.ts +14 -0
  234. package/src/pipeline/apiresource-meta.ts +10 -21
  235. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +31 -18
  236. package/src/pipeline/steps/__tests__/visibility-gates.test.ts +187 -0
  237. package/src/pipeline/steps/authorization-tuples.ts +11 -9
  238. package/src/pipeline/steps/references.ts +70 -578
  239. package/src/pipeline/steps/visibility-gates.ts +174 -0
  240. package/src/query/search/__tests__/criteria.test.ts +4 -0
  241. package/src/query/search/__tests__/query-store.test.ts +40 -11
  242. package/src/query/search/controller.ts +1 -0
  243. package/src/query/search/criteria.ts +14 -0
  244. package/src/query/search/handler.ts +7 -6
  245. package/src/query/search/query-store.ts +2 -0
  246. package/src/store/__tests__/store-contract.ts +51 -6
  247. package/src/store/interface.ts +6 -3
  248. package/src/store/postgres/__tests__/migrations.test.ts +6 -187
  249. package/src/store/postgres/__tests__/store-contract.test.ts +2 -0
  250. package/src/store/postgres/migrations.ts +1 -48
  251. package/src/store/postgres/store.ts +11 -4
  252. package/src/store/sqlite/__tests__/migrations.test.ts +5 -191
  253. package/src/store/sqlite/migrations.ts +1 -45
  254. package/src/store/sqlite/store.ts +10 -4
  255. package/dist/domain/workflow/agent-call-references.d.ts +0 -54
  256. package/dist/domain/workflow/agent-call-references.d.ts.map +0 -1
  257. package/dist/domain/workflow/agent-call-references.js +0 -97
  258. package/dist/domain/workflow/agent-call-references.js.map +0 -1
  259. package/dist/store/public-visibility-retired.d.ts +0 -67
  260. package/dist/store/public-visibility-retired.d.ts.map +0 -1
  261. package/dist/store/public-visibility-retired.js +0 -55
  262. package/dist/store/public-visibility-retired.js.map +0 -1
  263. package/src/domain/workflow/__tests__/agent-call-references.test.ts +0 -222
  264. package/src/domain/workflow/agent-call-references.ts +0 -157
  265. package/src/pipeline/__tests__/supports-visibility.test.ts +0 -112
  266. package/src/pipeline/steps/__tests__/references.test.ts +0 -703
  267. package/src/store/__tests__/public-visibility-retired.test.ts +0 -127
  268. package/src/store/public-visibility-retired.ts +0 -119
@@ -1,5 +1,5 @@
1
1
  # Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/org-admin-owner-inheritance.fga.yaml
2
- # as changed by stigmer-cloud#765 (the OpenFGA store test the cloud runs against its live model).
2
+ # as changed by stigmer-cloud#757 (the OpenFGA store test the cloud runs against its live model).
3
3
  # The body below is byte-identical to the source; the cloud re-runs the LIVE
4
4
  # file against this evaluator at the re-pin, so a stale copy is caught there.
5
5
  # Store tests for org-admin owner inheritance (T08).
@@ -131,6 +131,8 @@ tests:
131
131
  check:
132
132
  - user: identity_account:ana
133
133
  object: agent:carols-bot
134
+ context:
135
+ allow: false
134
136
  assertions:
135
137
  can_view: true
136
138
  can_edit: true
@@ -167,6 +169,8 @@ tests:
167
169
  can_grant_access: true
168
170
  - user: identity_account:ana
169
171
  object: skill:carols-notes
172
+ context:
173
+ allow: false
170
174
  assertions:
171
175
  can_view: true
172
176
  can_edit: true
@@ -174,6 +178,8 @@ tests:
174
178
  can_grant_access: true
175
179
  - user: identity_account:ana
176
180
  object: workflow:carols-flow
181
+ context:
182
+ allow: false
177
183
  assertions:
178
184
  can_view: true
179
185
  can_edit: true
@@ -191,6 +197,8 @@ tests:
191
197
  check:
192
198
  - user: identity_account:root
193
199
  object: agent:carols-bot
200
+ context:
201
+ allow: false
194
202
  assertions:
195
203
  can_edit: true
196
204
  can_delete: true
@@ -210,6 +218,8 @@ tests:
210
218
  check:
211
219
  - user: identity_account:dave
212
220
  object: agent:carols-bot
221
+ context:
222
+ allow: false
213
223
  assertions:
214
224
  can_view: false
215
225
  can_edit: false
@@ -240,6 +250,8 @@ tests:
240
250
  check:
241
251
  - user: identity_account:zara
242
252
  object: agent:carols-bot
253
+ context:
254
+ allow: false
243
255
  assertions:
244
256
  can_view: false
245
257
  can_edit: false
@@ -254,6 +266,8 @@ tests:
254
266
  check:
255
267
  - user: identity_account:ana
256
268
  object: agent_instance:carols-instance
269
+ context:
270
+ allow: false
257
271
  assertions:
258
272
  can_view: false
259
273
  can_edit: false
@@ -283,6 +297,8 @@ tests:
283
297
  check:
284
298
  - user: identity_account:carol
285
299
  object: agent:carols-bot
300
+ context:
301
+ allow: false
286
302
  assertions:
287
303
  can_view: true
288
304
  can_edit: true
@@ -293,6 +309,8 @@ tests:
293
309
  list_objects:
294
310
  - user: identity_account:ana
295
311
  type: agent
312
+ context:
313
+ allow: false
296
314
  assertions:
297
315
  can_view:
298
316
  - agent:carols-bot
@@ -300,6 +318,8 @@ tests:
300
318
  - agent:carols-bot
301
319
  - user: identity_account:ana
302
320
  type: agent_instance
321
+ context:
322
+ allow: false
303
323
  assertions:
304
324
  can_view: []
305
325
  - user: identity_account:ana
@@ -1,5 +1,5 @@
1
1
  # Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/platform-visibility.fga.yaml
2
- # as changed by stigmer-cloud#765 (the OpenFGA store test the cloud runs against its live model).
2
+ # at commit b87dd1170 (the OpenFGA store test the cloud runs against its live model).
3
3
  # The body below is byte-identical to the source; the cloud re-runs the LIVE
4
4
  # file against this evaluator at the re-pin, so a stale copy is caught there.
5
5
  # Store tests for platform visibility (visibility_platform).
@@ -102,6 +102,8 @@ tests:
102
102
  check:
103
103
  - user: identity_account:alice
104
104
  object: agent:sara
105
+ context:
106
+ allow: false
105
107
  assertions:
106
108
  can_view: true
107
109
  can_execute: true
@@ -110,6 +112,8 @@ tests:
110
112
  can_delete: false
111
113
  - user: identity_account:bob
112
114
  object: agent:sara
115
+ context:
116
+ allow: false
113
117
  assertions:
114
118
  can_view: true
115
119
  can_execute: true
@@ -118,6 +122,8 @@ tests:
118
122
  check:
119
123
  - user: identity_account:mallory
120
124
  object: agent:sara
125
+ context:
126
+ allow: false
121
127
  assertions:
122
128
  can_view: false
123
129
  can_execute: false
@@ -127,6 +133,8 @@ tests:
127
133
  check:
128
134
  - user: identity_account:priya
129
135
  object: agent:sara
136
+ context:
137
+ allow: false
130
138
  assertions:
131
139
  can_view: true
132
140
  can_execute: true
@@ -136,6 +144,8 @@ tests:
136
144
  # narrower: platform_user resolves member-from-managed_org.)
137
145
  - user: identity_account:veda
138
146
  object: agent:sara
147
+ context:
148
+ allow: false
139
149
  assertions:
140
150
  can_view: true
141
151
  can_edit: false
@@ -144,6 +154,8 @@ tests:
144
154
  check:
145
155
  - user: identity_account:alice
146
156
  object: agent:internal-bot
157
+ context:
158
+ allow: false
147
159
  assertions:
148
160
  can_view: false
149
161
  can_execute: false
@@ -151,6 +163,8 @@ tests:
151
163
  # without an explicit visibility tuple.
152
164
  - user: identity_account:priya
153
165
  object: agent:internal-bot
166
+ context:
167
+ allow: false
154
168
  assertions:
155
169
  can_view: false
156
170
  can_execute: false
@@ -159,6 +173,8 @@ tests:
159
173
  check:
160
174
  - user: identity_account:alice
161
175
  object: skill:research
176
+ context:
177
+ allow: false
162
178
  assertions:
163
179
  can_view: true
164
180
  can_use: true
@@ -168,6 +184,8 @@ tests:
168
184
  check:
169
185
  - user: identity_account:alice
170
186
  object: workflow:onboarding
187
+ context:
188
+ allow: false
171
189
  assertions:
172
190
  can_view: true
173
191
  can_execute: true
@@ -176,6 +194,8 @@ tests:
176
194
  check:
177
195
  - user: identity_account:alice
178
196
  object: mcp_server:github
197
+ context:
198
+ allow: false
179
199
  assertions:
180
200
  can_view: true
181
201
  can_use: true
@@ -185,6 +205,8 @@ tests:
185
205
  check:
186
206
  - user: identity_account:swarup
187
207
  object: agent:sara
208
+ context:
209
+ allow: false
188
210
  assertions:
189
211
  can_view: true
190
212
  can_edit: true
@@ -194,6 +216,8 @@ tests:
194
216
  list_objects:
195
217
  - user: identity_account:alice
196
218
  type: agent
219
+ context:
220
+ allow: false
197
221
  assertions:
198
222
  can_view:
199
223
  - agent:sara
@@ -0,0 +1,52 @@
1
+ # Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/public-visibility-setter.fga.yaml
2
+ # at commit b87dd1170 (the OpenFGA store test the cloud runs against its live model).
3
+ # The body below is byte-identical to the source; the cloud re-runs the LIVE
4
+ # file against this evaluator at the re-pin, so a stale copy is caught there.
5
+ # Store tests for the public-visibility permission (marketplace curation).
6
+ #
7
+ # can_set_public_visibility gates who may set a resource's visibility to
8
+ # PUBLIC — the only level that crosses every org boundary. It derives
9
+ # from the platform operator role: operators (human curators and the
10
+ # seeding machine account) hold it; ordinary tenants — even org owners,
11
+ # who can otherwise fully manage their resources — never do. Enforced by
12
+ # PublicVisibilityEscalationPolicy at both write doors (updateVisibility
13
+ # escalation and create-with-public).
14
+ #
15
+ # Run with:
16
+ # fga model test --tests public-visibility-setter.fga.yaml
17
+ name: public-visibility-setter
18
+ model_file: ../model/fga.mod
19
+
20
+ tuples:
21
+ # The bootstrap machine account is the platform operator
22
+ # (BootstrapIdentitySeeder re-asserts this tuple on every boot).
23
+ - user: identity_account:machine
24
+ relation: operator
25
+ object: platform:stigmer
26
+
27
+ # A human operator granted the same platform role.
28
+ - user: identity_account:opal
29
+ relation: operator
30
+ object: platform:stigmer
31
+
32
+ # A tenant org owner — owns everything in their org, nothing on the
33
+ # platform.
34
+ - user: identity_account:mallory
35
+ relation: owner
36
+ object: organization:acme
37
+
38
+ tests:
39
+ - name: operators may set public visibility, tenants may not
40
+ check:
41
+ - user: identity_account:machine
42
+ object: platform:stigmer
43
+ assertions:
44
+ can_set_public_visibility: true
45
+ - user: identity_account:opal
46
+ object: platform:stigmer
47
+ assertions:
48
+ can_set_public_visibility: true
49
+ - user: identity_account:mallory
50
+ object: platform:stigmer
51
+ assertions:
52
+ can_set_public_visibility: false
@@ -1,5 +1,5 @@
1
1
  # Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/workflow-execution-sharing.fga.yaml
2
- # as changed by stigmer-cloud#765 (the OpenFGA store test the cloud runs against its live model).
2
+ # at commit b87dd1170 (the OpenFGA store test the cloud runs against its live model).
3
3
  # The body below is byte-identical to the source; the cloud re-runs the LIVE
4
4
  # file against this evaluator at the re-pin, so a stale copy is caught there.
5
5
  # Store tests for workflow_execution sharing and run observability.
@@ -173,6 +173,8 @@ tests:
173
173
  # never alice's run history.
174
174
  - user: identity_account:vera
175
175
  object: workflow_instance:inst1
176
+ context:
177
+ allow: false
176
178
  assertions:
177
179
  can_view: true
178
180
  - user: identity_account:vera
@@ -1,15 +1,15 @@
1
1
  /**
2
2
  * Pins the built-in list read scope on both store drivers as the twin of
3
3
  * the cloud's driver (stigmer-cloud iam/list-read-scope.ts): every
4
- * candidate a list lane offers is answered by `can_view` through the same
5
- * evaluator the Authorizer uses, over tuples derived from the facts the
6
- * candidate carries — no candidate row is read twice.
4
+ * candidate a list lane offers is answered by `can_view` under the
5
+ * LISTING context (`allow: false`, the public wildcard suppressed) through
6
+ * the same evaluator the Authorizer uses, over tuples derived from the
7
+ * facts the candidate carries — no candidate row is read twice.
7
8
  *
8
9
  * The adversarial cells come first, because until slice 5's sibling
9
10
  * cells this file and the composed proof are the only proof that a
10
- * member's list is a member's list: the outsider sees nothing (a row
11
- * still carrying the retired public level included); the viewer rung sees
12
- * the org-visible blueprints
11
+ * member's list is a member's list: the outsider sees nothing (a legacy
12
+ * PUBLIC row included); the viewer rung sees the org-visible blueprints
13
13
  * and nothing personal; the founder — an admin — sees the organization's
14
14
  * blueprints and NOT its members' sessions, keys, environments or
15
15
  * memories (the model's own line, now list-visible); an execution is its session's and
@@ -280,10 +280,9 @@ describe.each(driverFixtures(SEEDED_KINDS))(
280
280
  await grant(orgRole(VIEWER, "viewer", ORG));
281
281
 
282
282
  // Blueprints: the founder's private and org-visible agents, a
283
- // member's private one, one still carrying the retired public
284
- // level (a row the store migration has not met, which derives no
285
- // viewer grant and so reads as its owner's alone), and one
286
- // stamped by the 3.14 verifiers' raw subject.
283
+ // member's private one, a legacy PUBLIC one (nobody can set public
284
+ // under the built-in posture; a row from before it can carry it),
285
+ // and one stamped by the 3.14 verifiers' raw subject.
287
286
  await save("agent", {
288
287
  id: "agt_private",
289
288
  org: ORG,
@@ -428,7 +427,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
428
427
  });
429
428
 
430
429
  describe("the adversarial cells", () => {
431
- it("an OUTSIDER lists nothing of the organization's — a row still carrying the retired public level included", async () => {
430
+ it("an OUTSIDER lists nothing of the organization's — not even the legacy PUBLIC blueprint, which the listing context suppresses", async () => {
432
431
  for (const kind of SEEDED_KINDS.filter(
433
432
  (k) =>
434
433
  k !== ApiResourceKind.iam_policy &&
@@ -442,13 +441,13 @@ describe.each(driverFixtures(SEEDED_KINDS))(
442
441
  }
443
442
  });
444
443
 
445
- it("a VIEWER lists the org-visible blueprint and nothing private; a MEMBER adds their own private one; the retired level grants neither anything", async () => {
444
+ it("a VIEWER lists the org-visible and the public blueprints and nothing private; a MEMBER adds their own private one", async () => {
446
445
  expect(
447
446
  await listAs(resolved(VIEWER), ApiResourceKind.agent),
448
- ).toEqual(["agt_org"]);
447
+ ).toEqual(["agt_org", "agt_public"]);
449
448
  expect(
450
449
  await listAs(resolved(MEMBER), ApiResourceKind.agent),
451
- ).toEqual(["agt_org", "agt_member_private"]);
450
+ ).toEqual(["agt_org", "agt_member_private", "agt_public"]);
452
451
  });
453
452
 
454
453
  it("the FOUNDER and the ADMIN list every blueprint (`owner: … or admin from organization`), including a member's private one", async () => {
@@ -543,7 +542,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
543
542
  const offered = [
544
543
  entryOf(
545
544
  ApiResourceKind.agent,
546
- rows.get(ApiResourceKind.agent)!.get("agt_member_private")!,
545
+ rows.get(ApiResourceKind.agent)!.get("agt_public")!,
547
546
  ),
548
547
  entryOf(
549
548
  ApiResourceKind.agent,
@@ -563,15 +562,15 @@ describe.each(driverFixtures(SEEDED_KINDS))(
563
562
  ApiResourceKind.agent,
564
563
  offered,
565
564
  );
566
- expect([...kept]).toEqual(["agt_member_private", "agt_org"]);
565
+ expect([...kept]).toEqual(["agt_public", "agt_org"]);
567
566
  // The lane's order is the lane's: the helper filters its own
568
567
  // array by the kept set.
569
568
  expect(
570
569
  await listAs(resolved(MEMBER), ApiResourceKind.agent, [
571
- rows.get(ApiResourceKind.agent)!.get("agt_member_private")!,
570
+ rows.get(ApiResourceKind.agent)!.get("agt_public")!,
572
571
  rows.get(ApiResourceKind.agent)!.get("agt_org")!,
573
572
  ]),
574
- ).toEqual(["agt_member_private", "agt_org"]);
573
+ ).toEqual(["agt_public", "agt_org"]);
575
574
  });
576
575
 
577
576
  it("no candidates: the empty set, with no read of any kind", async () => {
@@ -50,18 +50,22 @@ const FIXTURES = new URL("./fixtures/fga/", import.meta.url);
50
50
  */
51
51
  const DOCUMENTS = [
52
52
  "agent-channel-owner.fga.yaml",
53
+ "agent-instance-creation.fga.yaml",
53
54
  "agent-share-owner.fga.yaml",
54
55
  "artifact-org-and-owner.fga.yaml",
55
56
  "blueprint-private-visibility.fga.yaml",
56
57
  "channel-app-owner.fga.yaml",
57
58
  "channel-participation.fga.yaml",
58
59
  "channel-session-visibility.fga.yaml",
60
+ "cross-org-share-creation.fga.yaml",
59
61
  "default-instance-inheritance.fga.yaml",
62
+ "mcp-server-authoring.fga.yaml",
60
63
  "memory-subject-only.fga.yaml",
61
64
  "org-admin-owner-inheritance.fga.yaml",
62
65
  "org-shared-environment.fga.yaml",
63
66
  "platform-visibility.fga.yaml",
64
67
  "provider-standing-viewer.fga.yaml",
68
+ "public-visibility-setter.fga.yaml",
65
69
  "reserved-label-writer.fga.yaml",
66
70
  "schedule-owner.fga.yaml",
67
71
  "schedule-session-visibility.fga.yaml",
@@ -98,7 +102,7 @@ const SKIPPED_PINNED: ReadonlyArray<string> = [
98
102
  "artifact-org-and-owner :: listing reflects org inheritance plus creator ownership :: identity_account:eve <artifact> :: list-objects",
99
103
  "artifact-org-and-owner :: listing reflects org inheritance plus creator ownership :: identity_account:victor <artifact> :: list-objects",
100
104
  "blueprint-private-visibility :: org admin's listable agents include private ones (T08) :: identity_account:oscar <agent> :: list-objects",
101
- "blueprint-private-visibility :: org member's listable agents exclude private ones :: identity_account:dave <agent> :: list-objects",
105
+ "blueprint-private-visibility :: org member's listable agents exclude private ones (wildcard suppressed) :: identity_account:dave <agent> :: list-objects",
102
106
  "blueprint-private-visibility :: org viewer's listable agents are exactly the viewer-shaped org-visible ones :: identity_account:vera <agent> :: list-objects",
103
107
  "blueprint-private-visibility :: owner's listable agents include everything they authored :: identity_account:carol <agent> :: list-objects",
104
108
  "channel-app-owner :: listing channel apps reflects ownership and grants, not membership :: identity_account:alice <channel_app> :: list-objects",
@@ -128,6 +132,9 @@ const SKIPPED_PINNED: ReadonlyArray<string> = [
128
132
  // undeclared-kind: platform
129
133
  "provider-standing-viewer :: operator may view provider standing, tenants may not :: identity_account:mallory platform:stigmer :: undeclared-kind",
130
134
  "provider-standing-viewer :: operator may view provider standing, tenants may not :: identity_account:opal platform:stigmer :: undeclared-kind",
135
+ "public-visibility-setter :: operators may set public visibility, tenants may not :: identity_account:machine platform:stigmer :: undeclared-kind",
136
+ "public-visibility-setter :: operators may set public visibility, tenants may not :: identity_account:mallory platform:stigmer :: undeclared-kind",
137
+ "public-visibility-setter :: operators may set public visibility, tenants may not :: identity_account:opal platform:stigmer :: undeclared-kind",
131
138
  "reserved-label-writer :: operator may write reserved labels, tenants may not :: identity_account:machine platform:stigmer :: undeclared-kind",
132
139
  "reserved-label-writer :: operator may write reserved labels, tenants may not :: identity_account:mallory platform:stigmer :: undeclared-kind",
133
140
  // undeclared-subject-type: identity_provider#platform_user
@@ -13,7 +13,7 @@ import {
13
13
  } from "../tuples.js";
14
14
 
15
15
  describe("the string notation", () => {
16
- it("parses an object and a userset, and an id may carry a colon (issuer subjects do)", () => {
16
+ it("parses an object, a userset and the wildcard, and an id may carry a colon (issuer subjects do)", () => {
17
17
  expect(parseObjectRef("agent:agt_1")).toEqual({
18
18
  type: "agent",
19
19
  id: "agt_1",
@@ -27,6 +27,11 @@ describe("the string notation", () => {
27
27
  object: { type: "organization", id: "acme" },
28
28
  relation: "viewer",
29
29
  });
30
+ expect(parseSubject("identity_account:*")).toEqual({
31
+ form: "wildcard",
32
+ type: "identity_account",
33
+ condition: undefined,
34
+ });
30
35
  expect(parseSubject("identity_account:ida_x")).toEqual({
31
36
  form: "object",
32
37
  object: { type: "identity_account", id: "ida_x" },
@@ -38,24 +43,18 @@ describe("the string notation", () => {
38
43
  expect(() => parseObjectRef(":id")).toThrow("not an object reference");
39
44
  });
40
45
 
41
- it("refuses the wildcard notation — no line of the model admits one", () => {
42
- expect(() => parseSubject("identity_account:*")).toThrow(
43
- "wildcard subject 'identity_account:*' is not admitted",
44
- );
45
- });
46
-
47
- it("formats a tuple in the proto's notation", () => {
46
+ it("formats a tuple in the proto's notation, the condition spelled after `with`", () => {
48
47
  expect(
49
48
  formatTuple({
50
49
  object: parseObjectRef("agent:a"),
51
50
  relation: "viewer",
52
51
  subject: {
53
- form: "userset",
54
- object: { type: "organization", id: "acme" },
55
- relation: "viewer",
52
+ form: "wildcard",
53
+ type: "identity_account",
54
+ condition: "allow_public",
56
55
  },
57
56
  }),
58
- ).toBe("agent:a#viewer@organization:acme#viewer");
57
+ ).toBe("agent:a#viewer@identity_account:* with allow_public");
59
58
  expect(formatSubject(parseSubject("organization:acme#member"))).toBe(
60
59
  "organization:acme#member",
61
60
  );
@@ -17,7 +17,9 @@
17
17
  * 2. A kind this edition does not serve is `deny` (`kindServedByEdition`,
18
18
  * the predicate 2b's `checkMyPermission` arm 1 uses, so the console
19
19
  * and the server agree by construction). `platform` is the one that
20
- * can arrive, through an operator capability no self-host holds.
20
+ * arrives, through `can_set_public_visibility` — under the built-in
21
+ * posture nobody sets public visibility, the model's own reason for
22
+ * making it a platform operator's act.
21
23
  * 3. The caller as a person (person.ts) and one derived tuple source for
22
24
  * them; the target loaded ONCE through the source's memoised loader,
23
25
  * so the read that decides not-found is the read the derivation
@@ -29,9 +31,11 @@
29
31
  * member cannot learn which account ids exist. Present or exempt, the
30
32
  * row is then evaluated: the cloud asks OpenFGA whether or not the row
31
33
  * exists, and so does this driver.
32
- * 5. `checkRelation`. True is `allow`; false is `deny` with an EMPTY
33
- * reason, so the method annotation's byte-pinned `error_msg` wins on
34
- * the wire, exactly the cloud's genuine-denial path.
34
+ * 5. `checkRelation` with the point-check context (`allow: true`: a
35
+ * public resource reads for any authenticated caller, the cloud's
36
+ * posture). True is `allow`; false is `deny` with an EMPTY reason, so
37
+ * the method annotation's byte-pinned `error_msg` wins on the wire,
38
+ * exactly the cloud's genuine-denial path.
35
39
  *
36
40
  * Faults. Everything past the pre-checks runs under one guard: a store
37
41
  * fault, a person that names nobody (`personFor`), an evaluation fault
@@ -175,6 +179,7 @@ export function newBuiltInAuthorizer(deps: BuiltInAuthorizerDeps): Authorizer {
175
179
  object,
176
180
  relation,
177
181
  person,
182
+ { allow: true },
178
183
  );
179
184
  if (allowed) {
180
185
  return { kind: "allow" };
@@ -12,6 +12,7 @@
12
12
  * - owner SELF: <row>#owner@identity_account:<row id>
13
13
  * - creator: <row>#creator@identity_account:<creator stamp> (kinds flagged requires_creator_tuple)
14
14
  * - org-viewer: <row>#viewer@organization:<org>#viewer (visibility_org; cloud#257's shape)
15
+ * - public-viewer: <row>#viewer@identity_account:* with allow_public
15
16
  * - platform-viewer: none — it fans out over identity providers, a kind this edition does not serve
16
17
  *
17
18
  * Two facts are this edition's own and are stated here, nowhere else:
@@ -90,7 +91,11 @@ import type {
90
91
  Tuple,
91
92
  TupleSource,
92
93
  } from "./tuples.js";
93
- import { ACCOUNT_TYPE, formatObjectRef } from "./tuples.js";
94
+ import {
95
+ ACCOUNT_TYPE,
96
+ ALLOW_PUBLIC_CONDITION,
97
+ formatObjectRef,
98
+ } from "./tuples.js";
94
99
 
95
100
  /**
96
101
  * Kinds whose `[identity_account]` owner is recorded as an IamPolicy row
@@ -179,6 +184,12 @@ function visibilitySubject(
179
184
  object: { type: "organization", id: org },
180
185
  relation: "viewer",
181
186
  };
187
+ case "public-viewer":
188
+ return {
189
+ form: "wildcard",
190
+ type: ACCOUNT_TYPE,
191
+ condition: ALLOW_PUBLIC_CONDITION,
192
+ };
182
193
  case "platform-viewer":
183
194
  return undefined;
184
195
  default: {
@@ -350,18 +361,24 @@ function tupleOfRow(row: IamPolicy): Tuple {
350
361
  type: principal?.kind ?? "",
351
362
  id: principal?.id ?? "",
352
363
  };
353
- // A principal id of `*` (a wildcard row a cloud database may still hold
354
- // from the retired public level) is read as an ordinary object id here:
355
- // no person carries `*` among their aliases, so the row matches nobody
356
- // and reads as the inert grant it is, never as a fault that would turn
357
- // the resource unreadable.
358
- const subject: Subject =
359
- principal !== undefined && principal.relation !== ""
360
- ? {
361
- form: "userset",
362
- object: principalObject,
363
- relation: principal.relation,
364
- }
365
- : { form: "object", object: principalObject };
364
+ let subject: Subject;
365
+ if (principal !== undefined && principal.relation !== "") {
366
+ subject = {
367
+ form: "userset",
368
+ object: principalObject,
369
+ relation: principal.relation,
370
+ };
371
+ } else if (principalObject.id === "*") {
372
+ // A wildcard row carries no condition of its own; the evaluator
373
+ // honours it only where a line admits an unconditioned wildcard,
374
+ // which no line in the model does.
375
+ subject = {
376
+ form: "wildcard",
377
+ type: principalObject.type,
378
+ condition: undefined,
379
+ };
380
+ } else {
381
+ subject = { form: "object", object: principalObject };
382
+ }
366
383
  return { object, relation: spec?.relation ?? "", subject };
367
384
  }