@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
@@ -3,7 +3,8 @@
3
3
  * built-in authorizer: which tuples a stored row stands for, in exactly
4
4
  * the shapes the cloud's tuple driver writes (stigmer-cloud
5
5
  * iam/tuple-lifecycle.ts: `organization:<org>#viewer` for the org level,
6
- * the owner by the kind's attribution, the parent links by `kind_meta`). Two facts are the
6
+ * the conditional `identity_account:*` for public, the owner by the
7
+ * kind's attribution, the parent links by `kind_meta`). Two facts are the
7
8
  * OSS edition's own and are pinned here by name: the organization's owner
8
9
  * is a ROW (2b's role lifecycle), never derived from its creator stamp,
9
10
  * or a revoked founder would stay owner; and a stamp that names no person
@@ -95,7 +96,7 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
95
96
  ]);
96
97
  });
97
98
 
98
- it("a row that still carries the retired public level derives no viewer tuple at all — no shape reaches every account, and the level's own org floor left with it", () => {
99
+ it("a public blueprint adds the conditional wildcard AND keeps the org floor", () => {
99
100
  expect(
100
101
  derivedFor("skill", {
101
102
  visibility: ApiResourceVisibility.visibility_public,
@@ -103,6 +104,8 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
103
104
  ).toEqual([
104
105
  "skill:skill-1#organization@organization:acme",
105
106
  "skill:skill-1#owner@identity_account:ida_carol",
107
+ "skill:skill-1#viewer@identity_account:* with allow_public",
108
+ "skill:skill-1#viewer@organization:acme#viewer",
106
109
  ]);
107
110
  });
108
111
 
@@ -163,7 +166,7 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
163
166
  ).toEqual(["memory:memory-1#organization@organization:acme"]);
164
167
  });
165
168
 
166
- it("an environment carries its creator tuple and an org-viewer at org level, and nothing beyond its org ceiling", () => {
169
+ it("an environment carries its creator tuple, an org-viewer at org level, and NO public wildcard (the kind's ceiling)", () => {
167
170
  expect(
168
171
  derivedFor("environment", {
169
172
  visibility: ApiResourceVisibility.visibility_org,
@@ -176,7 +179,7 @@ describe("deriveTuples — the cloud driver's shapes, from the row", () => {
176
179
  ]);
177
180
  expect(
178
181
  derivedFor("environment", {
179
- visibility: ApiResourceVisibility.visibility_platform,
182
+ visibility: ApiResourceVisibility.visibility_public,
180
183
  }),
181
184
  ).toEqual([
182
185
  "environment:environment-1#organization@organization:acme",
@@ -506,6 +509,9 @@ describe.each(driverFixtures(SEEDED_KINDS))(
506
509
  object,
507
510
  "can_view",
508
511
  DAVE,
512
+ {
513
+ allow: false,
514
+ },
509
515
  ),
510
516
  ).toBe(true);
511
517
  expect(rowReads).toBe(1);
@@ -701,6 +707,7 @@ describe.each(driverFixtures(SEEDED_KINDS))(
701
707
  parseObjectRef(object),
702
708
  relation,
703
709
  person,
710
+ { allow: true },
704
711
  );
705
712
  }
706
713
 
@@ -1,10 +1,11 @@
1
1
  /**
2
2
  * Pins the evaluator's semantics the store tests cannot express (the
3
3
  * cloud's `.fga.yaml` documents prove the model's answers; this file
4
- * proves the machinery under them): how a person matches a tuple, that a
5
- * direct tuple outside the line's type restriction is ignored (model drift
6
- * fails closed), how far a resolution may walk, and that a declaration
7
- * cycle or an undeclared target is a thrown fault and never a silent deny.
4
+ * proves the machinery under them): how a person matches a tuple, what
5
+ * the `allow_public` context does, that a direct tuple outside the line's
6
+ * type restriction is ignored (model drift fails closed), how far a
7
+ * resolution may walk, and that a declaration cycle or an undeclared
8
+ * target is a thrown fault and never a silent deny.
8
9
  *
9
10
  * The fixture source is the in-memory one the store-test kit uses, so the
10
11
  * two proofs share one tuple vocabulary. Where a case needs a shape the
@@ -29,6 +30,7 @@ import {
29
30
  direct,
30
31
  from,
31
32
  objectOf,
33
+ publicWith,
32
34
  union,
33
35
  usersetOf,
34
36
  } from "../model/rewrite.js";
@@ -54,17 +56,22 @@ function person(accountId: string, ...aliases: string[]): Person {
54
56
  return { accountId, aliases: new Set([accountId, ...aliases]) };
55
57
  }
56
58
 
59
+ const RESOLVE = { allow: true };
60
+ const LIST = { allow: false };
61
+
57
62
  async function allowed(
58
63
  source: TupleSource,
59
64
  object: string,
60
65
  relation: string,
61
66
  who: Person,
67
+ context = RESOLVE,
62
68
  ): Promise<boolean> {
63
69
  return checkRelation(
64
70
  { model: builtInModel, source },
65
71
  parseObjectRef(object),
66
72
  relation,
67
73
  who,
74
+ context,
68
75
  );
69
76
  }
70
77
 
@@ -93,17 +100,67 @@ describe("a person against a direct tuple", () => {
93
100
  });
94
101
  });
95
102
 
96
- describe("a stranger against a row with no grant that names them", () => {
97
- it("reads nothing: no subject form reaches every account, so a stranger holds no relation on a row they were not granted", async () => {
98
- const source = newInMemoryTupleSource([
99
- tuple("agent:open#organization@organization:acme"),
100
- tuple("agent:open#owner@identity_account:ida_carol"),
101
- tuple("agent:open#viewer@organization:acme#viewer"),
102
- ]);
103
- const stranger = person("ida_mallory");
103
+ describe("the public wildcard and its condition", () => {
104
+ const publicViewer = (object: string): Tuple => ({
105
+ object: parseObjectRef(object),
106
+ relation: "viewer",
107
+ subject: {
108
+ form: "wildcard",
109
+ type: "identity_account",
110
+ condition: "allow_public",
111
+ },
112
+ });
113
+ const source = newInMemoryTupleSource([
114
+ tuple("agent:open#organization@organization:acme"),
115
+ publicViewer("agent:open"),
116
+ ]);
117
+ const stranger = person("ida_mallory");
118
+
119
+ it("reads for anyone on a point check (the cloud's `allow: true`) and for nobody in a listing (`allow: false`)", async () => {
104
120
  expect(await allowed(source, "agent:open", "can_view", stranger)).toBe(
105
- false,
121
+ true,
106
122
  );
123
+ expect(
124
+ await allowed(source, "agent:open", "can_view", stranger, LIST),
125
+ ).toBe(false);
126
+ });
127
+
128
+ it("ignores a wildcard tuple that carries no condition where the line demands one — a tuple the cloud could never have written", async () => {
129
+ const bare = newInMemoryTupleSource([
130
+ tuple("agent:open#viewer@identity_account:*"),
131
+ ]);
132
+ expect(await allowed(bare, "agent:open", "can_view", stranger)).toBe(false);
133
+ });
134
+
135
+ it("is a thrown fault under a condition the transcript names but the evaluator does not know — a model that grew a condition", async () => {
136
+ const grown = declareKind({
137
+ kind: ApiResourceKind.agent,
138
+ schema: AgentSchema,
139
+ source: "test/grown.fga",
140
+ relations: [
141
+ ["viewer", direct(publicWith("identity_account", "after_hours"))],
142
+ ],
143
+ });
144
+ const afterHours = newInMemoryTupleSource([
145
+ {
146
+ object: parseObjectRef("agent:open"),
147
+ relation: "viewer",
148
+ subject: {
149
+ form: "wildcard",
150
+ type: "identity_account",
151
+ condition: "after_hours",
152
+ },
153
+ },
154
+ ]);
155
+ await expect(
156
+ checkRelation(
157
+ { model: newModel([grown]), source: afterHours },
158
+ parseObjectRef("agent:open"),
159
+ "viewer",
160
+ stranger,
161
+ RESOLVE,
162
+ ),
163
+ ).rejects.toMatchObject({ reason: "unknown-condition" });
107
164
  });
108
165
  });
109
166
 
@@ -220,6 +277,7 @@ describe("the walk itself", () => {
220
277
  parseObjectRef("agent:n0"),
221
278
  "next",
222
279
  person("ida_nobody"),
280
+ RESOLVE,
223
281
  ),
224
282
  ).rejects.toMatchObject({ reason: "resolution-depth-exceeded" });
225
283
  });
@@ -240,6 +298,7 @@ describe("the walk itself", () => {
240
298
  parseObjectRef("agent:x"),
241
299
  "a",
242
300
  person("ida_nobody"),
301
+ RESOLVE,
243
302
  ),
244
303
  ).rejects.toBeInstanceOf(AuthorizationEvaluationError);
245
304
  });
@@ -273,7 +332,7 @@ describe("declareKind validates a transcript at load", () => {
273
332
  source: "test/bad.fga",
274
333
  relations: [
275
334
  ["viewer", direct(objectOf("identity_account"))],
276
- ["viewer", direct(usersetOf("organization", "viewer"))],
335
+ ["viewer", direct(publicWith("identity_account", "allow_public"))],
277
336
  ],
278
337
  }),
279
338
  ).toThrow("declared twice");
@@ -50,7 +50,7 @@ describe("rowFactsOf against the tuple lifecycle's own resolution", () => {
50
50
  for (const visibility of [
51
51
  ApiResourceVisibility.visibility_private,
52
52
  ApiResourceVisibility.visibility_org,
53
- ApiResourceVisibility.visibility_platform,
53
+ ApiResourceVisibility.visibility_public,
54
54
  ]) {
55
55
  it(`${declaration.type} at ${ApiResourceVisibility[visibility]}: the same parent links and visibility shapes`, () => {
56
56
  const row = fixtureRow(declaration, {
@@ -133,7 +133,7 @@ describe("a list candidate against the loaded row — the facts' two producers",
133
133
  for (const visibility of [
134
134
  ApiResourceVisibility.visibility_private,
135
135
  ApiResourceVisibility.visibility_org,
136
- ApiResourceVisibility.visibility_platform,
136
+ ApiResourceVisibility.visibility_public,
137
137
  ]) {
138
138
  it(`${declaration.type} at ${ApiResourceVisibility[visibility]}: the candidate the helper builds carries the facts the driver derives from`, async () => {
139
139
  const row = fixtureRow(declaration, {
@@ -0,0 +1,185 @@
1
+ # Pinned copy of stigmer-cloud backend/services/stigmer-server/fga/tests/agent-instance-creation.fga.yaml
2
+ # at commit 4c03c38d2 (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 agent-instance creation: two halves, asked together by
6
+ # the create since stigmer#1209 (v3.22.0). The agent half is the agent's
7
+ # can_create_instance (can_execute, so the viewer set: whoever may run the
8
+ # agent may instantiate it). The organization half is
9
+ # can_create_agent_instance: member on the organization the instance is
10
+ # created IN, which is the caller's own, not the agent's: a personal
11
+ # instance of another organization's public agent lives in the caller's
12
+ # organization (the marketplace case), so the agent's permission alone
13
+ # would let a row be planted in any organization named on the request.
14
+ #
15
+ # What these pin: owners, admins and members hold the organization half;
16
+ # a viewer-role account may run an org-visible agent (the agent half) and
17
+ # still lacks the organization half; a guest holds neither; an outsider
18
+ # holds neither; and the marketplace case passes on the caller's own
19
+ # organization while the agent half comes from the public wildcard.
20
+ #
21
+ # Run: fga model test --tests agent-instance-creation.fga.yaml
22
+
23
+ name: agent-instance-creation
24
+ model_file: ../model/fga.mod
25
+
26
+ tuples:
27
+ # Org acme: olivia owns it, oscar administers, dave is a plain member,
28
+ # vera a read-only viewer, greta the share-link guest account.
29
+ - user: identity_account:olivia
30
+ relation: owner
31
+ object: organization:acme
32
+ - user: identity_account:oscar
33
+ relation: admin
34
+ object: organization:acme
35
+ - user: identity_account:dave
36
+ relation: member
37
+ object: organization:acme
38
+ - user: identity_account:vera
39
+ relation: viewer
40
+ object: organization:acme
41
+ - user: identity_account:greta
42
+ relation: guest
43
+ object: organization:acme
44
+
45
+ # Org consumer: mia is a plain member there and holds no role in acme.
46
+ - user: identity_account:mia
47
+ relation: member
48
+ object: organization:consumer
49
+
50
+ # An ORG-visible agent in acme, authored by oscar.
51
+ - user: organization:acme
52
+ relation: organization
53
+ object: agent:team-bot
54
+ - user: identity_account:oscar
55
+ relation: owner
56
+ object: agent:team-bot
57
+ - user: organization:acme#viewer
58
+ relation: viewer
59
+ object: agent:team-bot
60
+
61
+ # A PRIVATE agent in acme, authored by oscar (no visibility tuple).
62
+ - user: organization:acme
63
+ relation: organization
64
+ object: agent:secret-bot
65
+ - user: identity_account:oscar
66
+ relation: owner
67
+ object: agent:secret-bot
68
+
69
+ # A PUBLIC marketplace agent in acme (the conditional wildcard plus the
70
+ # org floor tuple the visibility writer emits).
71
+ - user: organization:acme
72
+ relation: organization
73
+ object: agent:open-bot
74
+ - user: identity_account:oscar
75
+ relation: owner
76
+ object: agent:open-bot
77
+ - user: identity_account:*
78
+ relation: viewer
79
+ object: agent:open-bot
80
+ condition:
81
+ name: allow_public
82
+ context: {}
83
+ - user: organization:acme#viewer
84
+ relation: viewer
85
+ object: agent:open-bot
86
+
87
+ tests:
88
+ - name: owners, admins and members hold the organization half
89
+ check:
90
+ - user: identity_account:olivia
91
+ object: organization:acme
92
+ assertions:
93
+ can_create_agent_instance: true
94
+ - user: identity_account:oscar
95
+ object: organization:acme
96
+ assertions:
97
+ can_create_agent_instance: true
98
+ - user: identity_account:dave
99
+ object: organization:acme
100
+ assertions:
101
+ can_create_agent_instance: true
102
+
103
+ - name: a viewer, a guest and an outsider do not
104
+ check:
105
+ - user: identity_account:vera
106
+ object: organization:acme
107
+ assertions:
108
+ can_create_agent_instance: false
109
+ can_create_session: false
110
+ - user: identity_account:greta
111
+ object: organization:acme
112
+ assertions:
113
+ can_create_agent_instance: false
114
+ can_create_session: true
115
+ - user: identity_account:mia
116
+ object: organization:acme
117
+ assertions:
118
+ can_create_agent_instance: false
119
+
120
+ - name: a member instantiates an org-visible agent, both halves held
121
+ check:
122
+ - user: identity_account:dave
123
+ object: agent:team-bot
124
+ context:
125
+ allow: false
126
+ assertions:
127
+ can_create_instance: true
128
+ can_execute: true
129
+
130
+ - name: a viewer may run the org-visible agent and still cannot instantiate it here
131
+ check:
132
+ - user: identity_account:vera
133
+ object: agent:team-bot
134
+ context:
135
+ allow: false
136
+ assertions:
137
+ can_create_instance: true
138
+ - user: identity_account:vera
139
+ object: organization:acme
140
+ assertions:
141
+ can_create_agent_instance: false
142
+
143
+ - name: a private agent gives the agent half to its author and the admins only
144
+ check:
145
+ - user: identity_account:oscar
146
+ object: agent:secret-bot
147
+ context:
148
+ allow: false
149
+ assertions:
150
+ can_create_instance: true
151
+ - user: identity_account:olivia
152
+ object: agent:secret-bot
153
+ context:
154
+ allow: false
155
+ assertions:
156
+ can_create_instance: true
157
+ - user: identity_account:dave
158
+ object: agent:secret-bot
159
+ context:
160
+ allow: false
161
+ assertions:
162
+ can_create_instance: false
163
+ - user: identity_account:mia
164
+ object: agent:secret-bot
165
+ context:
166
+ allow: false
167
+ assertions:
168
+ can_create_instance: false
169
+
170
+ - name: the marketplace case, the agent half from the wildcard and the organization half at home
171
+ check:
172
+ - user: identity_account:mia
173
+ object: agent:open-bot
174
+ context:
175
+ allow: true
176
+ assertions:
177
+ can_create_instance: true
178
+ - user: identity_account:mia
179
+ object: organization:consumer
180
+ assertions:
181
+ can_create_agent_instance: true
182
+ - user: identity_account:mia
183
+ object: organization:acme
184
+ assertions:
185
+ can_create_agent_instance: false