@stigmer/server 3.40.0 → 3.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (528) hide show
  1. package/dist/authorization/authorizer.d.ts +16 -10
  2. package/dist/authorization/authorizer.d.ts.map +1 -1
  3. package/dist/authorization/authorizer.js +17 -9
  4. package/dist/authorization/authorizer.js.map +1 -1
  5. package/dist/authorization/derived-tuples.d.ts +7 -3
  6. package/dist/authorization/derived-tuples.d.ts.map +1 -1
  7. package/dist/authorization/derived-tuples.js +62 -6
  8. package/dist/authorization/derived-tuples.js.map +1 -1
  9. package/dist/authorization/evaluator.d.ts +11 -7
  10. package/dist/authorization/evaluator.d.ts.map +1 -1
  11. package/dist/authorization/evaluator.js +16 -10
  12. package/dist/authorization/evaluator.js.map +1 -1
  13. package/dist/authorization/list-read-scope.d.ts +4 -0
  14. package/dist/authorization/list-read-scope.d.ts.map +1 -1
  15. package/dist/authorization/list-read-scope.js +1 -0
  16. package/dist/authorization/list-read-scope.js.map +1 -1
  17. package/dist/authorization/model/data/authorization-model.json +830 -67
  18. package/dist/authorization/model/execution-viewer.d.ts.map +1 -1
  19. package/dist/authorization/model/execution-viewer.js +26 -24
  20. package/dist/authorization/model/execution-viewer.js.map +1 -1
  21. package/dist/authorization/model/index.d.ts +4 -1
  22. package/dist/authorization/model/index.d.ts.map +1 -1
  23. package/dist/authorization/model/index.js +4 -1
  24. package/dist/authorization/model/index.js.map +1 -1
  25. package/dist/authorization/model/rewrite.d.ts +5 -3
  26. package/dist/authorization/model/rewrite.d.ts.map +1 -1
  27. package/dist/authorization/organization-directory.d.ts +44 -0
  28. package/dist/authorization/organization-directory.d.ts.map +1 -1
  29. package/dist/authorization/organization-directory.js +1 -0
  30. package/dist/authorization/organization-directory.js.map +1 -1
  31. package/dist/authorization/person.d.ts +14 -1
  32. package/dist/authorization/person.d.ts.map +1 -1
  33. package/dist/authorization/person.js +16 -0
  34. package/dist/authorization/person.js.map +1 -1
  35. package/dist/authorization/policy-check.d.ts +52 -0
  36. package/dist/authorization/policy-check.d.ts.map +1 -0
  37. package/dist/authorization/policy-check.js +35 -0
  38. package/dist/authorization/policy-check.js.map +1 -0
  39. package/dist/authorization/posture.d.ts +30 -4
  40. package/dist/authorization/posture.d.ts.map +1 -1
  41. package/dist/authorization/posture.js +58 -0
  42. package/dist/authorization/posture.js.map +1 -1
  43. package/dist/authorization/resource-creators.d.ts +4 -0
  44. package/dist/authorization/resource-creators.d.ts.map +1 -0
  45. package/dist/authorization/resource-creators.js +44 -0
  46. package/dist/authorization/resource-creators.js.map +1 -0
  47. package/dist/authorization/trusted-local-authorizer.d.ts +9 -0
  48. package/dist/authorization/trusted-local-authorizer.d.ts.map +1 -0
  49. package/dist/authorization/trusted-local-authorizer.js +70 -0
  50. package/dist/authorization/trusted-local-authorizer.js.map +1 -0
  51. package/dist/authorization/tuples.d.ts +12 -0
  52. package/dist/authorization/tuples.d.ts.map +1 -1
  53. package/dist/authorization/tuples.js +3 -0
  54. package/dist/authorization/tuples.js.map +1 -1
  55. package/dist/boot/compose.d.ts.map +1 -1
  56. package/dist/boot/compose.js +133 -43
  57. package/dist/boot/compose.js.map +1 -1
  58. package/dist/boot/config.d.ts +22 -7
  59. package/dist/boot/config.d.ts.map +1 -1
  60. package/dist/boot/config.js +2 -1
  61. package/dist/boot/config.js.map +1 -1
  62. package/dist/boot/inprocess.d.ts.map +1 -1
  63. package/dist/boot/inprocess.js +10 -4
  64. package/dist/boot/inprocess.js.map +1 -1
  65. package/dist/boot/list-indexes.d.ts.map +1 -1
  66. package/dist/boot/list-indexes.js +6 -1
  67. package/dist/boot/list-indexes.js.map +1 -1
  68. package/dist/boot/logger.d.ts +3 -1
  69. package/dist/boot/logger.d.ts.map +1 -1
  70. package/dist/boot/logger.js +3 -1
  71. package/dist/boot/logger.js.map +1 -1
  72. package/dist/boot/oauth-redirect-uri.d.ts +33 -12
  73. package/dist/boot/oauth-redirect-uri.d.ts.map +1 -1
  74. package/dist/boot/oauth-redirect-uri.js +43 -14
  75. package/dist/boot/oauth-redirect-uri.js.map +1 -1
  76. package/dist/boot/skill-transfer-origin.d.ts +46 -14
  77. package/dist/boot/skill-transfer-origin.d.ts.map +1 -1
  78. package/dist/boot/skill-transfer-origin.js +53 -13
  79. package/dist/boot/skill-transfer-origin.js.map +1 -1
  80. package/dist/domain/agentchannel/steps.d.ts +8 -6
  81. package/dist/domain/agentchannel/steps.d.ts.map +1 -1
  82. package/dist/domain/agentchannel/steps.js +9 -7
  83. package/dist/domain/agentchannel/steps.js.map +1 -1
  84. package/dist/domain/agentexecution/controller.d.ts +7 -0
  85. package/dist/domain/agentexecution/controller.d.ts.map +1 -1
  86. package/dist/domain/agentexecution/controller.js +1 -1
  87. package/dist/domain/agentexecution/controller.js.map +1 -1
  88. package/dist/domain/agentexecution/create-steps.d.ts +26 -12
  89. package/dist/domain/agentexecution/create-steps.d.ts.map +1 -1
  90. package/dist/domain/agentexecution/create-steps.js +61 -43
  91. package/dist/domain/agentexecution/create-steps.js.map +1 -1
  92. package/dist/domain/agentexecution/submit-approval.d.ts.map +1 -1
  93. package/dist/domain/agentexecution/submit-approval.js +9 -6
  94. package/dist/domain/agentexecution/submit-approval.js.map +1 -1
  95. package/dist/domain/agentexecution/submit-file-decision.d.ts.map +1 -1
  96. package/dist/domain/agentexecution/submit-file-decision.js +5 -4
  97. package/dist/domain/agentexecution/submit-file-decision.js.map +1 -1
  98. package/dist/domain/agentshare/steps.d.ts +5 -3
  99. package/dist/domain/agentshare/steps.d.ts.map +1 -1
  100. package/dist/domain/agentshare/steps.js +6 -4
  101. package/dist/domain/agentshare/steps.js.map +1 -1
  102. package/dist/domain/apikey/verifier.d.ts +7 -0
  103. package/dist/domain/apikey/verifier.d.ts.map +1 -1
  104. package/dist/domain/apikey/verifier.js +34 -1
  105. package/dist/domain/apikey/verifier.js.map +1 -1
  106. package/dist/domain/channelapp/controller.d.ts +9 -4
  107. package/dist/domain/channelapp/controller.d.ts.map +1 -1
  108. package/dist/domain/channelapp/controller.js +19 -9
  109. package/dist/domain/channelapp/controller.js.map +1 -1
  110. package/dist/domain/executioncontext/steps.d.ts +2 -1
  111. package/dist/domain/executioncontext/steps.d.ts.map +1 -1
  112. package/dist/domain/executioncontext/steps.js +2 -1
  113. package/dist/domain/executioncontext/steps.js.map +1 -1
  114. package/dist/domain/iampolicy/access-lists.d.ts.map +1 -1
  115. package/dist/domain/iampolicy/access-lists.js +57 -2
  116. package/dist/domain/iampolicy/access-lists.js.map +1 -1
  117. package/dist/domain/iampolicy/change.d.ts +53 -0
  118. package/dist/domain/iampolicy/change.d.ts.map +1 -0
  119. package/dist/domain/iampolicy/change.js +44 -0
  120. package/dist/domain/iampolicy/change.js.map +1 -0
  121. package/dist/domain/iampolicy/constants.d.ts +6 -0
  122. package/dist/domain/iampolicy/constants.d.ts.map +1 -1
  123. package/dist/domain/iampolicy/constants.js +6 -0
  124. package/dist/domain/iampolicy/constants.js.map +1 -1
  125. package/dist/domain/iampolicy/controller.d.ts.map +1 -1
  126. package/dist/domain/iampolicy/controller.js +9 -5
  127. package/dist/domain/iampolicy/controller.js.map +1 -1
  128. package/dist/domain/iampolicy/grant-path.d.ts +31 -13
  129. package/dist/domain/iampolicy/grant-path.d.ts.map +1 -1
  130. package/dist/domain/iampolicy/grant-path.js +216 -19
  131. package/dist/domain/iampolicy/grant-path.js.map +1 -1
  132. package/dist/domain/iampolicy/membership.d.ts +11 -3
  133. package/dist/domain/iampolicy/membership.d.ts.map +1 -1
  134. package/dist/domain/iampolicy/membership.js +18 -13
  135. package/dist/domain/iampolicy/membership.js.map +1 -1
  136. package/dist/domain/iampolicy/resource-store.d.ts.map +1 -1
  137. package/dist/domain/iampolicy/resource-store.js +4 -0
  138. package/dist/domain/iampolicy/resource-store.js.map +1 -1
  139. package/dist/domain/iampolicy/role-lifecycle.d.ts.map +1 -1
  140. package/dist/domain/iampolicy/role-lifecycle.js +2 -2
  141. package/dist/domain/iampolicy/role-lifecycle.js.map +1 -1
  142. package/dist/domain/iampolicy/roles.d.ts.map +1 -1
  143. package/dist/domain/iampolicy/roles.js +7 -0
  144. package/dist/domain/iampolicy/roles.js.map +1 -1
  145. package/dist/domain/iampolicy/steps.d.ts +4 -3
  146. package/dist/domain/iampolicy/steps.d.ts.map +1 -1
  147. package/dist/domain/iampolicy/steps.js +7 -7
  148. package/dist/domain/iampolicy/steps.js.map +1 -1
  149. package/dist/domain/iampolicy/store-contract.d.ts.map +1 -1
  150. package/dist/domain/iampolicy/store-contract.js +22 -1
  151. package/dist/domain/iampolicy/store-contract.js.map +1 -1
  152. package/dist/domain/iampolicy/store.d.ts +18 -5
  153. package/dist/domain/iampolicy/store.d.ts.map +1 -1
  154. package/dist/domain/iampolicy/store.js.map +1 -1
  155. package/dist/domain/identityaccount/constants.d.ts +15 -0
  156. package/dist/domain/identityaccount/constants.d.ts.map +1 -1
  157. package/dist/domain/identityaccount/constants.js +17 -0
  158. package/dist/domain/identityaccount/constants.js.map +1 -1
  159. package/dist/domain/identityaccount/controller.d.ts.map +1 -1
  160. package/dist/domain/identityaccount/controller.js +17 -6
  161. package/dist/domain/identityaccount/controller.js.map +1 -1
  162. package/dist/domain/identityaccount/resolve.d.ts +47 -0
  163. package/dist/domain/identityaccount/resolve.d.ts.map +1 -1
  164. package/dist/domain/identityaccount/resolve.js +38 -1
  165. package/dist/domain/identityaccount/resolve.js.map +1 -1
  166. package/dist/domain/identityaccount/resource-store.d.ts.map +1 -1
  167. package/dist/domain/identityaccount/resource-store.js +11 -1
  168. package/dist/domain/identityaccount/resource-store.js.map +1 -1
  169. package/dist/domain/identityaccount/steps.d.ts +2 -1
  170. package/dist/domain/identityaccount/steps.d.ts.map +1 -1
  171. package/dist/domain/identityaccount/steps.js +4 -3
  172. package/dist/domain/identityaccount/steps.js.map +1 -1
  173. package/dist/domain/identityaccount/store-contract.js +2 -2
  174. package/dist/domain/identityaccount/store-contract.js.map +1 -1
  175. package/dist/domain/identityaccount/store.d.ts +6 -1
  176. package/dist/domain/identityaccount/store.d.ts.map +1 -1
  177. package/dist/domain/mcpserver/connect-sandbox.d.ts +67 -0
  178. package/dist/domain/mcpserver/connect-sandbox.d.ts.map +1 -0
  179. package/dist/domain/mcpserver/connect-sandbox.js +64 -0
  180. package/dist/domain/mcpserver/connect-sandbox.js.map +1 -0
  181. package/dist/domain/mcpserver/connect.d.ts +42 -10
  182. package/dist/domain/mcpserver/connect.d.ts.map +1 -1
  183. package/dist/domain/mcpserver/connect.js +147 -40
  184. package/dist/domain/mcpserver/connect.js.map +1 -1
  185. package/dist/domain/mcpserver/controller.js +4 -2
  186. package/dist/domain/mcpserver/controller.js.map +1 -1
  187. package/dist/domain/mcpserver/engine.d.ts +26 -7
  188. package/dist/domain/mcpserver/engine.d.ts.map +1 -1
  189. package/dist/domain/mcpserver/engine.js.map +1 -1
  190. package/dist/domain/mcpserver/start-connect.d.ts +5 -0
  191. package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
  192. package/dist/domain/mcpserver/start-connect.js +38 -15
  193. package/dist/domain/mcpserver/start-connect.js.map +1 -1
  194. package/dist/domain/memory/controller.js +2 -1
  195. package/dist/domain/memory/controller.js.map +1 -1
  196. package/dist/domain/memory/list-index.d.ts +2 -0
  197. package/dist/domain/memory/list-index.d.ts.map +1 -0
  198. package/dist/domain/memory/list-index.js +31 -0
  199. package/dist/domain/memory/list-index.js.map +1 -0
  200. package/dist/domain/memory/queries.d.ts +10 -0
  201. package/dist/domain/memory/queries.d.ts.map +1 -0
  202. package/dist/domain/memory/queries.js +54 -0
  203. package/dist/domain/memory/queries.js.map +1 -0
  204. package/dist/domain/memory/steps.d.ts +13 -11
  205. package/dist/domain/memory/steps.d.ts.map +1 -1
  206. package/dist/domain/memory/steps.js +26 -57
  207. package/dist/domain/memory/steps.js.map +1 -1
  208. package/dist/domain/organization/steps.d.ts.map +1 -1
  209. package/dist/domain/organization/steps.js +1 -1
  210. package/dist/domain/organization/steps.js.map +1 -1
  211. package/dist/domain/platformclient/mint.d.ts.map +1 -1
  212. package/dist/domain/platformclient/mint.js +2 -2
  213. package/dist/domain/platformclient/mint.js.map +1 -1
  214. package/dist/domain/platformclient/verifier.d.ts.map +1 -1
  215. package/dist/domain/platformclient/verifier.js +6 -3
  216. package/dist/domain/platformclient/verifier.js.map +1 -1
  217. package/dist/domain/plugin/push.d.ts.map +1 -1
  218. package/dist/domain/plugin/push.js +1 -0
  219. package/dist/domain/plugin/push.js.map +1 -1
  220. package/dist/domain/schedule/steps.d.ts +3 -1
  221. package/dist/domain/schedule/steps.d.ts.map +1 -1
  222. package/dist/domain/schedule/steps.js +3 -1
  223. package/dist/domain/schedule/steps.js.map +1 -1
  224. package/dist/domain/skill/push.d.ts.map +1 -1
  225. package/dist/domain/skill/push.js +1 -0
  226. package/dist/domain/skill/push.js.map +1 -1
  227. package/dist/domain/workflow/registry/data/task-kind-registry.json +27 -1
  228. package/dist/domain/workflowexecution/submit-approval.d.ts +5 -2
  229. package/dist/domain/workflowexecution/submit-approval.d.ts.map +1 -1
  230. package/dist/domain/workflowexecution/submit-approval.js +1 -1
  231. package/dist/domain/workflowexecution/submit-approval.js.map +1 -1
  232. package/dist/domain/workflowexecution/submit-file-decision.d.ts +5 -2
  233. package/dist/domain/workflowexecution/submit-file-decision.d.ts.map +1 -1
  234. package/dist/domain/workflowexecution/submit-file-decision.js +1 -1
  235. package/dist/domain/workflowexecution/submit-file-decision.js.map +1 -1
  236. package/dist/domain/workflowexecution/submit-workflow-task-approval.d.ts.map +1 -1
  237. package/dist/domain/workflowexecution/submit-workflow-task-approval.js +12 -1
  238. package/dist/domain/workflowexecution/submit-workflow-task-approval.js.map +1 -1
  239. package/dist/domain/workflowinstance/controller.d.ts +6 -3
  240. package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
  241. package/dist/domain/workflowinstance/controller.js +12 -7
  242. package/dist/domain/workflowinstance/controller.js.map +1 -1
  243. package/dist/domain/workflowinstance/steps.d.ts +31 -0
  244. package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
  245. package/dist/domain/workflowinstance/steps.js +88 -1
  246. package/dist/domain/workflowinstance/steps.js.map +1 -1
  247. package/dist/extensions/composed-services.d.ts +56 -0
  248. package/dist/extensions/composed-services.d.ts.map +1 -0
  249. package/dist/extensions/composed-services.js +2 -0
  250. package/dist/extensions/composed-services.js.map +1 -0
  251. package/dist/extensions/drivers.d.ts +32 -1
  252. package/dist/extensions/drivers.d.ts.map +1 -1
  253. package/dist/extensions/identity.d.ts +4 -1
  254. package/dist/extensions/identity.d.ts.map +1 -1
  255. package/dist/extensions/identity.js +4 -1
  256. package/dist/extensions/identity.js.map +1 -1
  257. package/dist/extensions/registry.d.ts +37 -0
  258. package/dist/extensions/registry.d.ts.map +1 -1
  259. package/dist/extensions/registry.js +50 -0
  260. package/dist/extensions/registry.js.map +1 -1
  261. package/dist/extensions/resource-authorization.d.ts +78 -0
  262. package/dist/extensions/resource-authorization.d.ts.map +1 -1
  263. package/dist/extensions/resource-row-reader.d.ts +43 -0
  264. package/dist/extensions/resource-row-reader.d.ts.map +1 -0
  265. package/dist/extensions/resource-row-reader.js +2 -0
  266. package/dist/extensions/resource-row-reader.js.map +1 -0
  267. package/dist/extensions/visitor-classifier.d.ts +41 -0
  268. package/dist/extensions/visitor-classifier.d.ts.map +1 -0
  269. package/dist/extensions/visitor-classifier.js +2 -0
  270. package/dist/extensions/visitor-classifier.js.map +1 -0
  271. package/dist/identity/oidc-userinfo.d.ts +6 -1
  272. package/dist/identity/oidc-userinfo.d.ts.map +1 -1
  273. package/dist/identity/oidc-userinfo.js.map +1 -1
  274. package/dist/identity/oidc-verifier.d.ts.map +1 -1
  275. package/dist/identity/oidc-verifier.js +37 -8
  276. package/dist/identity/oidc-verifier.js.map +1 -1
  277. package/dist/index.d.ts +14 -6
  278. package/dist/index.d.ts.map +1 -1
  279. package/dist/index.js +25 -9
  280. package/dist/index.js.map +1 -1
  281. package/dist/pipeline/errors.d.ts +8 -0
  282. package/dist/pipeline/errors.d.ts.map +1 -1
  283. package/dist/pipeline/errors.js +25 -16
  284. package/dist/pipeline/errors.js.map +1 -1
  285. package/dist/pipeline/interceptors/auth.d.ts +17 -9
  286. package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
  287. package/dist/pipeline/interceptors/auth.js +17 -9
  288. package/dist/pipeline/interceptors/auth.js.map +1 -1
  289. package/dist/pipeline/steps/authorization-tuples.d.ts +23 -1
  290. package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
  291. package/dist/pipeline/steps/authorization-tuples.js +42 -0
  292. package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
  293. package/dist/pipeline/steps/authorize.d.ts +6 -5
  294. package/dist/pipeline/steps/authorize.d.ts.map +1 -1
  295. package/dist/pipeline/steps/authorize.js +6 -5
  296. package/dist/pipeline/steps/authorize.js.map +1 -1
  297. package/dist/pipeline/steps/defaults.d.ts +12 -0
  298. package/dist/pipeline/steps/defaults.d.ts.map +1 -1
  299. package/dist/pipeline/steps/defaults.js +42 -7
  300. package/dist/pipeline/steps/defaults.js.map +1 -1
  301. package/dist/pipeline/steps/guard-memory-capture.d.ts +13 -15
  302. package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
  303. package/dist/pipeline/steps/guard-memory-capture.js +2 -3
  304. package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
  305. package/dist/runnerauth/built-in-runner-credential-provider.d.ts +0 -2
  306. package/dist/runnerauth/built-in-runner-credential-provider.d.ts.map +1 -1
  307. package/dist/runnerauth/built-in-runner-credential-provider.js +8 -17
  308. package/dist/runnerauth/built-in-runner-credential-provider.js.map +1 -1
  309. package/dist/runnerauth/runner-credential-provider.d.ts +17 -7
  310. package/dist/runnerauth/runner-credential-provider.d.ts.map +1 -1
  311. package/dist/runnerauth/runner-credential-provider.js.map +1 -1
  312. package/dist/sandbox/docker.d.ts.map +1 -1
  313. package/dist/sandbox/docker.js +3 -0
  314. package/dist/sandbox/docker.js.map +1 -1
  315. package/dist/sandbox/kubernetes.d.ts.map +1 -1
  316. package/dist/sandbox/kubernetes.js +3 -0
  317. package/dist/sandbox/kubernetes.js.map +1 -1
  318. package/dist/sandbox/local-process.d.ts.map +1 -1
  319. package/dist/sandbox/local-process.js +4 -0
  320. package/dist/sandbox/local-process.js.map +1 -1
  321. package/dist/sandbox/provisioner.d.ts +18 -6
  322. package/dist/sandbox/provisioner.d.ts.map +1 -1
  323. package/dist/sandbox/provisioner.js.map +1 -1
  324. package/dist/temporal/manager.d.ts +5 -0
  325. package/dist/temporal/manager.d.ts.map +1 -1
  326. package/dist/temporal/manager.js +9 -0
  327. package/dist/temporal/manager.js.map +1 -1
  328. package/dist/temporal/mcpserver/engine-client.d.ts +2 -2
  329. package/dist/temporal/mcpserver/engine-client.d.ts.map +1 -1
  330. package/dist/temporal/mcpserver/engine-client.js +6 -4
  331. package/dist/temporal/mcpserver/engine-client.js.map +1 -1
  332. package/dist/temporal/mcpserver/names.d.ts +13 -2
  333. package/dist/temporal/mcpserver/names.d.ts.map +1 -1
  334. package/dist/temporal/mcpserver/names.js +15 -2
  335. package/dist/temporal/mcpserver/names.js.map +1 -1
  336. package/dist/temporal/sdk-logger.d.ts +74 -0
  337. package/dist/temporal/sdk-logger.d.ts.map +1 -0
  338. package/dist/temporal/sdk-logger.js +143 -0
  339. package/dist/temporal/sdk-logger.js.map +1 -0
  340. package/package.json +6 -6
  341. package/src/authorization/README.md +18 -6
  342. package/src/authorization/__tests__/authorizer.test.ts +5 -1
  343. package/src/authorization/__tests__/derived-tuples.test.ts +26 -0
  344. package/src/authorization/__tests__/evaluator.test.ts +4 -0
  345. package/src/authorization/__tests__/list-read-scope.test.ts +11 -5
  346. package/src/authorization/__tests__/store-tests.test.ts +3 -1
  347. package/src/authorization/__tests__/trusted-local-authorizer.test.ts +155 -0
  348. package/src/authorization/__tests__/unit-owned-kinds.test.ts +420 -0
  349. package/src/authorization/__tests__/wire-permissions.test.ts +31 -2
  350. package/src/authorization/authorizer.ts +21 -10
  351. package/src/authorization/derived-tuples.ts +92 -18
  352. package/src/authorization/evaluator.ts +30 -15
  353. package/src/authorization/list-read-scope.ts +4 -0
  354. package/src/authorization/model/__tests__/registry.test.ts +23 -0
  355. package/src/authorization/model/data/authorization-model.json +830 -67
  356. package/src/authorization/model/execution-viewer.ts +32 -27
  357. package/src/authorization/model/index.ts +4 -1
  358. package/src/authorization/model/rewrite.ts +5 -3
  359. package/src/authorization/organization-directory.ts +4 -0
  360. package/src/authorization/person.ts +32 -1
  361. package/src/authorization/policy-check.ts +105 -0
  362. package/src/authorization/posture.ts +45 -4
  363. package/src/authorization/resource-creators.ts +48 -0
  364. package/src/authorization/trusted-local-authorizer.ts +91 -0
  365. package/src/authorization/tuples.ts +17 -0
  366. package/src/boot/__tests__/compose.test.ts +120 -4
  367. package/src/boot/__tests__/list-indexes.test.ts +4 -0
  368. package/src/boot/__tests__/oauth-redirect-uri.test.ts +121 -10
  369. package/src/boot/__tests__/skill-transfer-origin.test.ts +96 -25
  370. package/src/boot/compose.ts +154 -61
  371. package/src/boot/config.ts +28 -12
  372. package/src/boot/inprocess.ts +18 -4
  373. package/src/boot/list-indexes.ts +6 -1
  374. package/src/boot/logger.ts +3 -1
  375. package/src/boot/oauth-redirect-uri.ts +62 -17
  376. package/src/boot/skill-transfer-origin.ts +71 -16
  377. package/src/domain/agent/__tests__/agent.test.ts +42 -1
  378. package/src/domain/agentchannel/__tests__/agentchannel.test.ts +9 -0
  379. package/src/domain/agentchannel/__tests__/channel-runtime.test.ts +2 -0
  380. package/src/domain/agentchannel/__tests__/create-authorization.test.ts +7 -6
  381. package/src/domain/agentchannel/steps.ts +9 -7
  382. package/src/domain/agentexecution/__tests__/agentexecution.test.ts +148 -56
  383. package/src/domain/agentexecution/__tests__/create-steps.test.ts +175 -12
  384. package/src/domain/agentexecution/__tests__/file-review-seed.ts +91 -0
  385. package/src/domain/agentexecution/controller.ts +8 -0
  386. package/src/domain/agentexecution/create-steps.ts +74 -44
  387. package/src/domain/agentexecution/submit-approval.ts +9 -6
  388. package/src/domain/agentexecution/submit-file-decision.ts +5 -4
  389. package/src/domain/agentinstance/__tests__/agentinstance.test.ts +2 -0
  390. package/src/domain/agentshare/__tests__/agentshare.test.ts +17 -0
  391. package/src/domain/agentshare/__tests__/create-authorization.test.ts +5 -4
  392. package/src/domain/agentshare/steps.ts +6 -4
  393. package/src/domain/apikey/__tests__/verifier.test.ts +73 -1
  394. package/src/domain/apikey/verifier.ts +45 -1
  395. package/src/domain/artifact/__tests__/artifact.test.ts +13 -24
  396. package/src/domain/channelapp/__tests__/channelapp.test.ts +7 -0
  397. package/src/domain/channelapp/controller.ts +35 -12
  398. package/src/domain/environment/__tests__/environment.test.ts +13 -0
  399. package/src/domain/executioncontext/__tests__/executioncontext.test.ts +2 -0
  400. package/src/domain/executioncontext/steps.ts +2 -1
  401. package/src/domain/iampolicy/__tests__/access-lists.test.ts +79 -0
  402. package/src/domain/iampolicy/__tests__/change.test.ts +63 -0
  403. package/src/domain/iampolicy/__tests__/controller.test.ts +39 -3
  404. package/src/domain/iampolicy/__tests__/grant-path.test.ts +595 -27
  405. package/src/domain/iampolicy/__tests__/iampolicy.test.ts +33 -2
  406. package/src/domain/iampolicy/__tests__/membership.test.ts +47 -5
  407. package/src/domain/iampolicy/__tests__/resource-store.test.ts +1 -0
  408. package/src/domain/iampolicy/__tests__/role-lifecycle.test.ts +41 -8
  409. package/src/domain/iampolicy/__tests__/roles.test.ts +3 -2
  410. package/src/domain/iampolicy/__tests__/steps.test.ts +75 -6
  411. package/src/domain/iampolicy/__tests__/support.ts +68 -4
  412. package/src/domain/iampolicy/access-lists.ts +70 -2
  413. package/src/domain/iampolicy/change.ts +109 -0
  414. package/src/domain/iampolicy/constants.ts +8 -0
  415. package/src/domain/iampolicy/controller.ts +17 -3
  416. package/src/domain/iampolicy/grant-path.ts +349 -31
  417. package/src/domain/iampolicy/membership.ts +32 -12
  418. package/src/domain/iampolicy/resource-store.ts +4 -0
  419. package/src/domain/iampolicy/role-lifecycle.ts +2 -0
  420. package/src/domain/iampolicy/roles.ts +8 -0
  421. package/src/domain/iampolicy/steps.ts +15 -5
  422. package/src/domain/iampolicy/store-contract.ts +37 -1
  423. package/src/domain/iampolicy/store.ts +19 -5
  424. package/src/domain/identityaccount/__tests__/resolve.test.ts +246 -2
  425. package/src/domain/identityaccount/__tests__/resource-store.test.ts +1 -1
  426. package/src/domain/identityaccount/constants.ts +20 -0
  427. package/src/domain/identityaccount/controller.ts +20 -5
  428. package/src/domain/identityaccount/resolve.ts +80 -1
  429. package/src/domain/identityaccount/resource-store.ts +14 -1
  430. package/src/domain/identityaccount/steps.ts +4 -3
  431. package/src/domain/identityaccount/store-contract.ts +4 -4
  432. package/src/domain/identityaccount/store.ts +6 -1
  433. package/src/domain/mcpserver/__tests__/connect-authorization.test.ts +1 -0
  434. package/src/domain/mcpserver/__tests__/connect.test.ts +358 -15
  435. package/src/domain/mcpserver/__tests__/mcpserver.test.ts +2 -0
  436. package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +2 -0
  437. package/src/domain/mcpserver/__tests__/store-faults.test.ts +2 -0
  438. package/src/domain/mcpserver/connect-sandbox.ts +135 -0
  439. package/src/domain/mcpserver/connect.ts +226 -56
  440. package/src/domain/mcpserver/controller.ts +8 -2
  441. package/src/domain/mcpserver/engine.ts +24 -6
  442. package/src/domain/mcpserver/start-connect.ts +49 -10
  443. package/src/domain/memory/__tests__/memory.test.ts +92 -22
  444. package/src/domain/memory/__tests__/queries.test.ts +173 -0
  445. package/src/domain/memory/controller.ts +2 -1
  446. package/src/domain/memory/list-index.ts +32 -0
  447. package/src/domain/memory/queries.ts +72 -0
  448. package/src/domain/memory/steps.ts +26 -63
  449. package/src/domain/oauthapp/__tests__/oauthapp.test.ts +14 -0
  450. package/src/domain/organization/__tests__/support.ts +41 -0
  451. package/src/domain/organization/steps.ts +1 -0
  452. package/src/domain/platformclient/mint.ts +6 -2
  453. package/src/domain/platformclient/verifier.ts +6 -3
  454. package/src/domain/plugin/__tests__/plugin.test.ts +11 -24
  455. package/src/domain/plugin/push.ts +1 -0
  456. package/src/domain/schedule/__tests__/schedule.composed.test.ts +2 -0
  457. package/src/domain/schedule/steps.ts +3 -1
  458. package/src/domain/session/__tests__/session.test.ts +2 -0
  459. package/src/domain/skill/__tests__/skill.test.ts +7 -25
  460. package/src/domain/skill/push.ts +1 -0
  461. package/src/domain/workflow/__tests__/workflow.test.ts +2 -0
  462. package/src/domain/workflow/registry/data/task-kind-registry.json +27 -1
  463. package/src/domain/workflowexecution/__tests__/forward-attribution-composed.test.ts +270 -0
  464. package/src/domain/workflowexecution/__tests__/submit-workflow-task-approval.test.ts +196 -0
  465. package/src/domain/workflowexecution/__tests__/workflowexecution.test.ts +3 -57
  466. package/src/domain/workflowexecution/submit-approval.ts +9 -2
  467. package/src/domain/workflowexecution/submit-file-decision.ts +6 -1
  468. package/src/domain/workflowexecution/submit-workflow-task-approval.ts +23 -5
  469. package/src/domain/workflowinstance/controller.ts +27 -9
  470. package/src/domain/workflowinstance/steps.ts +123 -1
  471. package/src/extensions/__tests__/apikey-before-sign-in-composed.test.ts +172 -0
  472. package/src/extensions/__tests__/built-in-authorization-composed.test.ts +80 -1
  473. package/src/extensions/__tests__/composed-services-composed.test.ts +236 -0
  474. package/src/extensions/__tests__/extension-composition.test.ts +229 -16
  475. package/src/extensions/__tests__/identity-account-composed.test.ts +84 -4
  476. package/src/extensions/__tests__/list-read-scope-composed.test.ts +41 -1
  477. package/src/extensions/__tests__/registry.test.ts +147 -1
  478. package/src/extensions/__tests__/secret-cleanup-composed.test.ts +2 -0
  479. package/src/extensions/__tests__/visitor-classifier-points.test.ts +42 -0
  480. package/src/extensions/composed-services.ts +61 -0
  481. package/src/extensions/drivers.ts +33 -1
  482. package/src/extensions/identity.ts +4 -1
  483. package/src/extensions/registry.ts +105 -0
  484. package/src/extensions/resource-authorization.ts +87 -0
  485. package/src/extensions/resource-row-reader.ts +43 -0
  486. package/src/extensions/visitor-classifier.ts +41 -0
  487. package/src/identity/__tests__/oidc-verifier.test.ts +38 -12
  488. package/src/identity/oidc-userinfo.ts +6 -1
  489. package/src/identity/oidc-verifier.ts +42 -8
  490. package/src/index.ts +61 -6
  491. package/src/pipeline/__tests__/steps.test.ts +31 -4
  492. package/src/pipeline/errors.ts +30 -16
  493. package/src/pipeline/interceptors/auth.ts +17 -9
  494. package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +20 -0
  495. package/src/pipeline/steps/__tests__/guard-memory-capture.test.ts +72 -15
  496. package/src/pipeline/steps/authorization-tuples.ts +54 -0
  497. package/src/pipeline/steps/authorize.ts +6 -5
  498. package/src/pipeline/steps/defaults.ts +52 -7
  499. package/src/pipeline/steps/guard-memory-capture.ts +15 -20
  500. package/src/runnerauth/__tests__/built-in-runner-credential-provider.test.ts +1 -1
  501. package/src/runnerauth/__tests__/runner-subject-composed.test.ts +13 -0
  502. package/src/runnerauth/bound-execution.ts +2 -2
  503. package/src/runnerauth/built-in-runner-credential-provider.ts +8 -21
  504. package/src/runnerauth/runner-credential-provider.ts +17 -7
  505. package/src/sandbox/__tests__/docker.integration.test.ts +4 -0
  506. package/src/sandbox/__tests__/kubernetes.test.ts +18 -1
  507. package/src/sandbox/__tests__/local-process.integration.test.ts +4 -0
  508. package/src/sandbox/__tests__/provisioner.test.ts +1 -0
  509. package/src/sandbox/docker.ts +3 -0
  510. package/src/sandbox/kubernetes.ts +3 -0
  511. package/src/sandbox/local-process.ts +4 -0
  512. package/src/sandbox/provisioner.ts +18 -6
  513. package/src/store/postgres/__tests__/support.ts +11 -2
  514. package/src/temporal/README.md +1 -0
  515. package/src/temporal/__tests__/manager.test.ts +56 -4
  516. package/src/temporal/__tests__/sdk-log-workflows.ts +26 -0
  517. package/src/temporal/__tests__/sdk-logger.e2e.test.ts +150 -0
  518. package/src/temporal/__tests__/sdk-logger.test.ts +238 -0
  519. package/src/temporal/manager.ts +9 -0
  520. package/src/temporal/mcpserver/engine-client.ts +8 -3
  521. package/src/temporal/mcpserver/names.ts +16 -2
  522. package/src/temporal/sdk-logger.ts +173 -0
  523. package/dist/authorization/lane-admission.d.ts +0 -50
  524. package/dist/authorization/lane-admission.d.ts.map +0 -1
  525. package/dist/authorization/lane-admission.js +0 -13
  526. package/dist/authorization/lane-admission.js.map +0 -1
  527. package/src/authorization/__tests__/lane-admission.test.ts +0 -115
  528. package/src/authorization/lane-admission.ts +0 -73
@@ -64,6 +64,7 @@ import type {
64
64
  AuthzDecision,
65
65
  } from "../extensions/authorizer.js";
66
66
  import type { CallerIdentity } from "../extensions/identity.js";
67
+ import type { ResourceRowReader } from "../extensions/resource-row-reader.js";
67
68
  import {
68
69
  kindEnumName,
69
70
  kindServedByEdition,
@@ -81,15 +82,18 @@ import { formatObjectRef } from "./tuples.js";
81
82
  /**
82
83
  * Kinds whose missing row is a denial, never `not-found` (arm 4): the
83
84
  * cloud's `PROBE_EXEMPT_KINDS` (stigmer-cloud
84
- * src/authorizer/fga-authorizer.ts) restricted to the kinds this edition
85
- * serves — `platform`, `identity_provider` and `invitation` are refused by
86
- * arm 2 before any row is asked about. The cloud exempts them because
87
- * their rows live in its own tables, out of its probe's reach; matching
88
- * the set here keeps the wire identical across editions (an unknown
89
- * platform client's id is PERMISSION_DENIED with the annotation's copy in
90
- * both). The cloud pins every kind here inside its own
91
- * `PROBE_EXEMPT_KINDS`, which is why this set is exported; a kind that
92
- * moves into open source joins this set in the same change.
85
+ * src/authorizer/fga-authorizer.ts), the same set. The cloud exempts them
86
+ * because their rows live in its own tables, out of its probe's reach;
87
+ * matching the set here keeps the wire identical across editions (an
88
+ * unknown platform client's id is PERMISSION_DENIED with the annotation's
89
+ * copy in both), so a member cannot learn which provider, invitation or
90
+ * team ids exist in an organization they may not read. In open source,
91
+ * `platform`, `identity_provider`, `invitation` and `team` are refused by
92
+ * arm 2 before any row is asked about, so their entries matter only to an
93
+ * edition that serves them. `platform` also has no row at all
94
+ * (model/bindings.ts, ROWLESS): outside this set every check on it would
95
+ * answer not-found without evaluating. The cloud pins every kind here
96
+ * inside its own `PROBE_EXEMPT_KINDS`, which is why this set is exported.
93
97
  *
94
98
  * `iam_policy` is reachable as a target through the IamPolicy RPCs' own
95
99
  * `resource.kind` (a caller may name it); the grant scope refuses such a
@@ -97,9 +101,13 @@ import { formatObjectRef } from "./tuples.js";
97
101
  * keeps the wire the same on the way there.
98
102
  */
99
103
  export const NOT_FOUND_EXEMPT_KINDS: ReadonlySet<ApiResourceKind> = new Set([
104
+ ApiResourceKind.platform,
100
105
  ApiResourceKind.identity_account,
106
+ ApiResourceKind.identity_provider,
101
107
  ApiResourceKind.iam_policy,
102
108
  ApiResourceKind.platform_client,
109
+ ApiResourceKind.invitation,
110
+ ApiResourceKind.team,
103
111
  ]);
104
112
 
105
113
  /** The Java RequestAuthorizationService's pre-check copy, byte for byte (the cloud renders the same). */
@@ -121,9 +129,11 @@ export interface BuiltInAuthorizerDeps {
121
129
  readonly policies: IamPolicyStore;
122
130
  /** The account port: the caller's account, and identity_account targets. */
123
131
  readonly accounts: AccountsByCaller;
124
- /** The served edition (`extensions.edition`); the built-in posture pins it to `oss` at boot. */
132
+ /** The served edition (`extensions.edition`); above `oss`, boot has checked every served kind's rows are readable. */
125
133
  readonly edition: ServerEdition;
126
134
  readonly logger: Logger;
135
+ /** The readers of the kinds units keep themselves (`drivers.resourceRowReaders`), handed to every tuple source. */
136
+ readonly rowReaders?: ReadonlyMap<ApiResourceKind, ResourceRowReader>;
127
137
  /** The declarations to evaluate; the built-in model unless a test says otherwise. */
128
138
  readonly model?: Model;
129
139
  }
@@ -163,6 +173,7 @@ export function newBuiltInAuthorizer(deps: BuiltInAuthorizerDeps): Authorizer {
163
173
  store: deps.store,
164
174
  policies: deps.policies,
165
175
  accounts: deps.accounts,
176
+ rowReaders: deps.rowReaders,
166
177
  model,
167
178
  },
168
179
  person,
@@ -45,6 +45,10 @@
45
45
  * organization`), so a person who left the organization reads the
46
46
  * team's rows and is admitted by none of them.
47
47
  *
48
+ * A check about an object rather than a person (an organization asked
49
+ * whether a resource is its own, authorization/policy-check.ts) reads the
50
+ * rows that name that object directly, and holds no team.
51
+ *
48
52
  * Open source serves no team (the kind's tier is enterprise), so the
49
53
  * person's rows name none and the second read never happens: one read per
50
54
  * source, an indexed read on the OSS adapter (its list index by
@@ -71,15 +75,19 @@
71
75
  * spec fields the facts do not carry), so listing the two instance kinds
72
76
  * costs one row read per candidate, stated in the scope's cost pins.
73
77
  *
74
- * Rows are read through the generic Store, with one exception: an
75
- * `identity_account` object is read through the account PORT
76
- * (`accounts.findById`), the binding every other reader of accounts —
77
- * the verifiers, whoAmI, the create path — follows. A composition that
78
- * registers its own account store and keeps the built-in authorizer
79
- * therefore still lets a person read their own account (the derivation
80
- * is `owner@self`); a generic read would miss and deny them their own
81
- * row. IamPolicy rows are already the port's (`findByPrincipal`), so no
82
- * second exception is needed for them.
78
+ * A row is read where the composition keeps it. Open source's kinds are
79
+ * read through the generic Store. An `identity_account` object is read
80
+ * through the account PORT (`accounts.findById`), the binding every other
81
+ * reader of accounts — the verifiers, whoAmI, the create path — follows:
82
+ * a composition that registers its own account store and keeps the
83
+ * built-in authorizer therefore still lets a person read their own
84
+ * account (the derivation is `owner@self`), where a generic read would
85
+ * miss and deny them their own row. A kind a unit keeps in a store of its
86
+ * own (an identity provider, an invitation, a team, in the editions that
87
+ * serve them) is read through the reader the unit registered for it
88
+ * (`rowReaders`, extensions/resource-row-reader.ts), so a team a grant
89
+ * names resolves its organization from the row its unit wrote. IamPolicy
90
+ * rows are already the port's (`findByPrincipal`), so they need no reader.
83
91
  */
84
92
  import type { Message } from "@bufbuild/protobuf";
85
93
 
@@ -91,6 +99,7 @@ import { isPersonStamp } from "../domain/iampolicy/membership.js";
91
99
  import type { IamPolicyStore } from "../domain/iampolicy/store.js";
92
100
  import type { IdentityAccountStore } from "../domain/identityaccount/store.js";
93
101
  import type { VisibilityTupleShape } from "../extensions/resource-authorization.js";
102
+ import type { ResourceRowReader } from "../extensions/resource-row-reader.js";
94
103
  import {
95
104
  getKindMeta,
96
105
  kindByEnumName,
@@ -105,13 +114,13 @@ import type { Model } from "./model/index.js";
105
114
  import { builtInModel } from "./model/index.js";
106
115
  import type {
107
116
  ObjectRef,
108
- Person,
117
+ Principal,
109
118
  RowLoader,
110
119
  Subject,
111
120
  Tuple,
112
121
  TupleSource,
113
122
  } from "./tuples.js";
114
- import { ACCOUNT_TYPE, formatObjectRef } from "./tuples.js";
123
+ import { ACCOUNT_TYPE, formatObjectRef, isPerson } from "./tuples.js";
115
124
 
116
125
  /**
117
126
  * Kinds whose `[identity_account]` owner is recorded as an IamPolicy row
@@ -123,6 +132,10 @@ export const ROW_RECORDED_OWNER_KINDS: ReadonlySet<ApiResourceKind> = new Set([
123
132
  ApiResourceKind.organization,
124
133
  ]);
125
134
 
135
+ /** The organization type, and the relation that stands while a person holds a role on it (tenancy/organization.fga). */
136
+ const ORGANIZATION_TYPE = kindEnumName(ApiResourceKind.organization);
137
+ const AFFILIATED_RELATION = "affiliated";
138
+
126
139
  /** The FGA type a team grant names, and the relation that makes a person one of its members (the model's `team#member`). */
127
140
  const TEAM_TYPE = kindEnumName(ApiResourceKind.team);
128
141
  const TEAM_MEMBER_RELATION = "member";
@@ -223,6 +236,8 @@ export interface DerivedTupleSourceDeps {
223
236
  readonly policies: IamPolicyStore;
224
237
  /** The account port — an `identity_account` object is read through it, never the generic Store (the module header). */
225
238
  readonly accounts: Pick<IdentityAccountStore, "findById">;
239
+ /** The readers of the kinds units keep themselves (`drivers.resourceRowReaders`); absent, every other row is the generic Store's. */
240
+ readonly rowReaders?: ReadonlyMap<ApiResourceKind, ResourceRowReader>;
226
241
  /** The declarations to derive with; the built-in model unless a test says otherwise. */
227
242
  readonly model?: Model;
228
243
  }
@@ -231,7 +246,8 @@ export interface DerivedTupleSource extends TupleSource {
231
246
  /** The memoised row reads, exposed for a declaration's `derived` rules and for tests. */
232
247
  readonly loader: RowLoader;
233
248
  /**
234
- * The person's own IamPolicy rows as tuples — the ONE read of them this
249
+ * The person's own IamPolicy rows as tuples, each organization role with
250
+ * the organization's `affiliated` tuple it stands for — the ONE read of them this
235
251
  * source makes, shared with `tuplesOf`. A list-shaped consumer (the
236
252
  * organization directory; the list scope) reads its candidate objects
237
253
  * from here instead of scanning the port a second time. The rows granted
@@ -248,7 +264,7 @@ export interface DerivedTupleSourceSeed {
248
264
 
249
265
  export function newDerivedTupleSource(
250
266
  deps: DerivedTupleSourceDeps,
251
- person: Person,
267
+ principal: Principal,
252
268
  seed?: DerivedTupleSourceSeed,
253
269
  ): DerivedTupleSource {
254
270
  const model = deps.model ?? builtInModel;
@@ -307,9 +323,13 @@ export function newDerivedTupleSource(
307
323
 
308
324
  function rowTuples(): Promise<ReadonlyArray<Tuple>> {
309
325
  if (personRows === undefined) {
310
- personRows = deps.policies
311
- .findByPrincipal(ACCOUNT_TYPE, person.accountId)
312
- .then((found) => found.map(tupleOfRow));
326
+ personRows = isPerson(principal)
327
+ ? deps.policies
328
+ .findByPrincipal(ACCOUNT_TYPE, principal.accountId)
329
+ .then((found) => found.flatMap(tuplesOfPersonRow))
330
+ : deps.policies
331
+ .findByPrincipal(principal.object.type, principal.object.id)
332
+ .then((found) => found.filter(isDirectGrant).map(tupleOfRow));
313
333
  }
314
334
  return personRows;
315
335
  }
@@ -357,7 +377,10 @@ export function newDerivedTupleSource(
357
377
  const fromRows =
358
378
  (await reachableTuples()).get(pairKey(object, relation)) ?? [];
359
379
  const declaration = model.byType(object.type);
360
- if (declaration === undefined) {
380
+ if (declaration === undefined || isAffiliation(object, relation)) {
381
+ // An organization's `affiliated` tuples are the person's rows'
382
+ // (tuplesOfPersonRow); the organization's own row derives none, so
383
+ // it is not read for them.
361
384
  return fromRows;
362
385
  }
363
386
  const fromRow = (await derivedTuplesOf(object)).filter(onPair);
@@ -378,7 +401,7 @@ export function newDerivedTupleSource(
378
401
  * the row does not exist.
379
402
  */
380
403
  async function loadRow(
381
- deps: Pick<DerivedTupleSourceDeps, "store" | "accounts">,
404
+ deps: Pick<DerivedTupleSourceDeps, "store" | "accounts" | "rowReaders">,
382
405
  model: Model,
383
406
  object: ObjectRef,
384
407
  ): Promise<Message | undefined> {
@@ -395,6 +418,10 @@ async function loadRow(
395
418
  if (kind === ApiResourceKind.identity_account) {
396
419
  return deps.accounts.findById(object.id);
397
420
  }
421
+ const reader = deps.rowReaders?.get(kind);
422
+ if (reader !== undefined) {
423
+ return reader.findById(object.id);
424
+ }
398
425
  try {
399
426
  return await deps.store.getResource(kind, object.id, declaration.schema);
400
427
  } catch (error) {
@@ -405,6 +432,15 @@ async function loadRow(
405
432
  }
406
433
  }
407
434
 
435
+ /**
436
+ * Whether a row names its principal directly (`organization:o`), not as a
437
+ * userset (`organization:o#member`): the rows an object principal itself
438
+ * holds. A userset row grants the object's members, never the object.
439
+ */
440
+ function isDirectGrant(row: IamPolicy): boolean {
441
+ return (row.spec?.principal?.relation ?? "") === "";
442
+ }
443
+
408
444
  /** The key a tuple is served under: its object and relation. */
409
445
  function pairKey(object: ObjectRef, relation: string): string {
410
446
  return `${formatObjectRef(object)}#${relation}`;
@@ -426,6 +462,44 @@ function indexByPair(
426
462
  return index;
427
463
  }
428
464
 
465
+ /** Whether the pair is an organization's `affiliated`, which only the person's rows carry. */
466
+ function isAffiliation(object: ObjectRef, relation: string): boolean {
467
+ return object.type === ORGANIZATION_TYPE && relation === AFFILIATED_RELATION;
468
+ }
469
+
470
+ /**
471
+ * A row of the person's as the tuples it stands for: the tuple it records,
472
+ * and, for a role on an organization, the organization's `affiliated`
473
+ * tuple. `affiliated` is stored in the model so its bound costs one read
474
+ * (fga/model/tenancy/organization.fga); it stands exactly while the person
475
+ * holds a row on the organization, and this edition derives it from those
476
+ * rows here, in the same one read, where an edition that stores tuples
477
+ * writes it from the grant path's affiliation announcements. A row that
478
+ * names a userset (a team's members) is not the person's role and stands
479
+ * for no affiliation.
480
+ */
481
+ function tuplesOfPersonRow(row: IamPolicy): ReadonlyArray<Tuple> {
482
+ const recorded = tupleOfRow(row);
483
+ const principal = row.spec?.principal;
484
+ if (
485
+ recorded.object.type !== ORGANIZATION_TYPE ||
486
+ recorded.object.id === "" ||
487
+ principal === undefined ||
488
+ principal.kind !== ACCOUNT_TYPE ||
489
+ principal.relation !== ""
490
+ ) {
491
+ return [recorded];
492
+ }
493
+ return [
494
+ recorded,
495
+ {
496
+ object: recorded.object,
497
+ relation: AFFILIATED_RELATION,
498
+ subject: account(principal.id),
499
+ },
500
+ ];
501
+ }
502
+
429
503
  /** An IamPolicy row as the tuple it records: `resource#relation@principal`. */
430
504
  function tupleOfRow(row: IamPolicy): Tuple {
431
505
  const spec = row.spec;
@@ -1,10 +1,13 @@
1
1
  /**
2
2
  * The evaluator — OpenFGA's check, over the built-in model and a tuple
3
3
  * source, small because the model uses five rewrite forms and nothing
4
- * else (model/rewrite.ts). `checkRelation(object, relation, person)`
5
- * answers "does this person hold this relation on this object" the way
6
- * the cloud's engine answers it over stored tuples, so the two editions
7
- * share one meaning of authorization. There is no context parameter: the
4
+ * else (model/rewrite.ts). `checkRelation(object, relation, principal)`
5
+ * answers "does this person (or this object) hold this relation on this
6
+ * object" the way the cloud's engine answers it over stored tuples, so the
7
+ * two editions share one meaning of authorization. The principal is
8
+ * almost always a person; an object principal (an organization) is how a
9
+ * unit asks the structural questions the cloud asks its engine, such as
10
+ * whether a resource belongs to an organization. There is no context parameter: the
8
11
  * model declares no condition, so a check has no posture to state.
9
12
  *
10
13
  * The walk, in the order a `.fga` line reads:
@@ -12,7 +15,8 @@
12
15
  * its subject's TYPE is in the line's restriction list — the check
13
16
  * OpenFGA makes at write time, made here at read time, so a derived
14
17
  * tuple the model no longer admits denies instead of allowing. An
15
- * object subject matches when it names one of the person's aliases;
18
+ * object subject matches a person when it is an account naming one of
19
+ * their aliases, and an object principal when it is that very object;
16
20
  * a userset subject is resolved on its own object.
17
21
  * - `computed`: the same object, another relation.
18
22
  * - `from`: every object the tupleset relation links to (again within
@@ -46,8 +50,8 @@
46
50
  */
47
51
  import type { Model } from "./model/index.js";
48
52
  import type { Rewrite, SubjectType } from "./model/rewrite.js";
49
- import type { ObjectRef, Person, Subject, TupleSource } from "./tuples.js";
50
- import { ACCOUNT_TYPE, formatObjectRef, pairKey } from "./tuples.js";
53
+ import type { ObjectRef, Principal, Subject, TupleSource } from "./tuples.js";
54
+ import { ACCOUNT_TYPE, formatObjectRef, isPerson, pairKey } from "./tuples.js";
51
55
 
52
56
  /**
53
57
  * OpenFGA's default resolution-depth limit (its `resolveNodeLimit`), so
@@ -88,7 +92,7 @@ export async function checkRelation(
88
92
  deps: EvaluationDeps,
89
93
  object: ObjectRef,
90
94
  relation: string,
91
- person: Person,
95
+ principal: Principal,
92
96
  ): Promise<boolean> {
93
97
  if (deps.model.byType(object.type) === undefined) {
94
98
  throw new AuthorizationEvaluationError(
@@ -96,7 +100,7 @@ export async function checkRelation(
96
100
  `no declaration for kind '${object.type}' (target ${formatObjectRef(object)})`,
97
101
  );
98
102
  }
99
- return new Walk(deps, person).resolve(object, relation, 0);
103
+ return new Walk(deps, principal).resolve(object, relation, 0);
100
104
  }
101
105
 
102
106
  /** One check's state: the memo and the in-progress set, over one source. */
@@ -106,7 +110,7 @@ class Walk {
106
110
 
107
111
  constructor(
108
112
  private readonly deps: EvaluationDeps,
109
- private readonly person: Person,
113
+ private readonly principal: Principal,
110
114
  ) {}
111
115
 
112
116
  resolve(
@@ -203,7 +207,7 @@ class Walk {
203
207
  }
204
208
  }
205
209
 
206
- /** Whether one direct tuple's subject reaches the person, within the line's type restriction. */
210
+ /** Whether one direct tuple's subject reaches the principal, within the line's type restriction. */
207
211
  private async subjectHolds(
208
212
  subject: Subject,
209
213
  restriction: ReadonlyArray<SubjectType>,
@@ -212,12 +216,10 @@ class Walk {
212
216
  switch (subject.form) {
213
217
  case "object":
214
218
  return (
215
- subject.object.type === ACCOUNT_TYPE &&
216
219
  restriction.some(
217
220
  (allowed) =>
218
- allowed.form === "object" && allowed.type === ACCOUNT_TYPE,
219
- ) &&
220
- this.person.aliases.has(subject.object.id)
221
+ allowed.form === "object" && allowed.type === subject.object.type,
222
+ ) && this.isPrincipal(subject.object)
221
223
  );
222
224
  case "userset":
223
225
  return (
@@ -235,6 +237,19 @@ class Walk {
235
237
  }
236
238
  }
237
239
 
240
+ /** Whether an object subject names the principal: one of a person's aliases on an account, or the object principal itself. */
241
+ private isPrincipal(object: ObjectRef): boolean {
242
+ if (isPerson(this.principal)) {
243
+ return (
244
+ object.type === ACCOUNT_TYPE && this.principal.aliases.has(object.id)
245
+ );
246
+ }
247
+ return (
248
+ object.type === this.principal.object.type &&
249
+ object.id === this.principal.object.id
250
+ );
251
+ }
252
+
238
253
  /** The object types the tupleset line admits — `[organization]`, `[session]` — from its `this` nodes. */
239
254
  private objectTypesOf(
240
255
  object: ObjectRef,
@@ -70,6 +70,7 @@ import type { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apireso
70
70
  import type { Logger } from "../boot/logger.js";
71
71
  import type { IamPolicyStore } from "../domain/iampolicy/store.js";
72
72
  import type { CallerIdentity } from "../extensions/identity.js";
73
+ import type { ResourceRowReader } from "../extensions/resource-row-reader.js";
73
74
  import type {
74
75
  ListEntryMeta,
75
76
  ListReadScope,
@@ -101,6 +102,8 @@ export interface BuiltInListReadScopeDeps {
101
102
  /** The account port: the caller's account, and the parent hops that land on one. */
102
103
  readonly accounts: AccountsByCaller;
103
104
  readonly logger: Logger;
105
+ /** The readers of the kinds units keep themselves (`drivers.resourceRowReaders`), handed to every tuple source. */
106
+ readonly rowReaders?: ReadonlyMap<ApiResourceKind, ResourceRowReader>;
104
107
  /** The declarations to evaluate; the built-in model unless a test says otherwise. */
105
108
  readonly model?: Model;
106
109
  }
@@ -126,6 +129,7 @@ export function newBuiltInListReadScope(
126
129
  store: deps.store,
127
130
  policies: deps.policies,
128
131
  accounts: deps.accounts,
132
+ rowReaders: deps.rowReaders,
129
133
  model,
130
134
  },
131
135
  person,
@@ -11,6 +11,11 @@
11
11
  * exactly the four kinds the wider editions serve, so a kind the
12
12
  * contract moves between tiers is a visible diff here;
13
13
  * - a kind is reached by enum and by FGA type name alike;
14
+ * - every role a kind's `grantable_roles` lets a person hold is a
15
+ * relation of the kind's type whose direct list admits
16
+ * `identity_account`, so a grant the step accepts is a tuple the engine
17
+ * can store (`authorization_config.proto` states the rule; this holds
18
+ * the model to it);
14
19
  * - the relations whose direct list admits a team (`team#member`) are
15
20
  * exactly the roles the kind's `team_grantable_roles` names, a subset
16
21
  * of what a person can be granted and never ownership, so the grant
@@ -283,6 +288,10 @@ function inheritedWholeKinds(): ReadonlyArray<{
283
288
  });
284
289
  }
285
290
 
291
+ function isPerson(subject: SubjectType): boolean {
292
+ return subject.form === "object" && subject.type === "identity_account";
293
+ }
294
+
286
295
  function isTeamMembers(subject: SubjectType): boolean {
287
296
  return subject.form === "userset" && subject.type === "team" && subject.relation === "member";
288
297
  }
@@ -371,6 +380,20 @@ describe("the built-in model", () => {
371
380
  }
372
381
  });
373
382
 
383
+ it("stores every role a kind lets a person hold as a relation that admits the person directly — the model and the contract say one thing", () => {
384
+ const gaps: string[] = [];
385
+ for (const declaration of builtInModel.declarations) {
386
+ for (const role of grantableRolesFor(declaration.kind)) {
387
+ const relation = IamRole[role];
388
+ const rewrite = declaration.relations.get(relation);
389
+ if (rewrite === undefined || !directSubjects(rewrite).some(isPerson)) {
390
+ gaps.push(`${declaration.type}#${relation}`);
391
+ }
392
+ }
393
+ }
394
+ expect(gaps.sort()).toEqual([]);
395
+ });
396
+
374
397
  it("lets a team hold only roles a person can hold on the kind, and never ownership", () => {
375
398
  for (const value of ApiResourceKindSchema.values) {
376
399
  const kind = value.number as ApiResourceKind;