@stigmer/server 3.40.1 → 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.
- package/dist/authorization/authorizer.d.ts +16 -10
- package/dist/authorization/authorizer.d.ts.map +1 -1
- package/dist/authorization/authorizer.js +17 -9
- package/dist/authorization/authorizer.js.map +1 -1
- package/dist/authorization/derived-tuples.d.ts +7 -3
- package/dist/authorization/derived-tuples.d.ts.map +1 -1
- package/dist/authorization/derived-tuples.js +62 -6
- package/dist/authorization/derived-tuples.js.map +1 -1
- package/dist/authorization/evaluator.d.ts +11 -7
- package/dist/authorization/evaluator.d.ts.map +1 -1
- package/dist/authorization/evaluator.js +16 -10
- package/dist/authorization/evaluator.js.map +1 -1
- package/dist/authorization/list-read-scope.d.ts +4 -0
- package/dist/authorization/list-read-scope.d.ts.map +1 -1
- package/dist/authorization/list-read-scope.js +1 -0
- package/dist/authorization/list-read-scope.js.map +1 -1
- package/dist/authorization/model/data/authorization-model.json +830 -67
- package/dist/authorization/model/execution-viewer.d.ts.map +1 -1
- package/dist/authorization/model/execution-viewer.js +26 -24
- package/dist/authorization/model/execution-viewer.js.map +1 -1
- package/dist/authorization/model/index.d.ts +4 -1
- package/dist/authorization/model/index.d.ts.map +1 -1
- package/dist/authorization/model/index.js +4 -1
- package/dist/authorization/model/index.js.map +1 -1
- package/dist/authorization/model/rewrite.d.ts +5 -3
- package/dist/authorization/model/rewrite.d.ts.map +1 -1
- package/dist/authorization/organization-directory.d.ts +44 -0
- package/dist/authorization/organization-directory.d.ts.map +1 -1
- package/dist/authorization/organization-directory.js +1 -0
- package/dist/authorization/organization-directory.js.map +1 -1
- package/dist/authorization/person.d.ts +14 -1
- package/dist/authorization/person.d.ts.map +1 -1
- package/dist/authorization/person.js +16 -0
- package/dist/authorization/person.js.map +1 -1
- package/dist/authorization/policy-check.d.ts +52 -0
- package/dist/authorization/policy-check.d.ts.map +1 -0
- package/dist/authorization/policy-check.js +35 -0
- package/dist/authorization/policy-check.js.map +1 -0
- package/dist/authorization/posture.d.ts +30 -4
- package/dist/authorization/posture.d.ts.map +1 -1
- package/dist/authorization/posture.js +58 -0
- package/dist/authorization/posture.js.map +1 -1
- package/dist/authorization/resource-creators.d.ts +4 -0
- package/dist/authorization/resource-creators.d.ts.map +1 -0
- package/dist/authorization/resource-creators.js +44 -0
- package/dist/authorization/resource-creators.js.map +1 -0
- package/dist/authorization/trusted-local-authorizer.d.ts +9 -0
- package/dist/authorization/trusted-local-authorizer.d.ts.map +1 -0
- package/dist/authorization/trusted-local-authorizer.js +70 -0
- package/dist/authorization/trusted-local-authorizer.js.map +1 -0
- package/dist/authorization/tuples.d.ts +12 -0
- package/dist/authorization/tuples.d.ts.map +1 -1
- package/dist/authorization/tuples.js +3 -0
- package/dist/authorization/tuples.js.map +1 -1
- package/dist/boot/compose.d.ts.map +1 -1
- package/dist/boot/compose.js +132 -43
- package/dist/boot/compose.js.map +1 -1
- package/dist/boot/config.d.ts +22 -7
- package/dist/boot/config.d.ts.map +1 -1
- package/dist/boot/config.js +2 -1
- package/dist/boot/config.js.map +1 -1
- package/dist/boot/inprocess.d.ts.map +1 -1
- package/dist/boot/inprocess.js +10 -4
- package/dist/boot/inprocess.js.map +1 -1
- package/dist/boot/list-indexes.d.ts.map +1 -1
- package/dist/boot/list-indexes.js +6 -1
- package/dist/boot/list-indexes.js.map +1 -1
- package/dist/boot/logger.d.ts +3 -1
- package/dist/boot/logger.d.ts.map +1 -1
- package/dist/boot/logger.js +3 -1
- package/dist/boot/logger.js.map +1 -1
- package/dist/boot/oauth-redirect-uri.d.ts +33 -12
- package/dist/boot/oauth-redirect-uri.d.ts.map +1 -1
- package/dist/boot/oauth-redirect-uri.js +43 -14
- package/dist/boot/oauth-redirect-uri.js.map +1 -1
- package/dist/boot/skill-transfer-origin.d.ts +46 -14
- package/dist/boot/skill-transfer-origin.d.ts.map +1 -1
- package/dist/boot/skill-transfer-origin.js +53 -13
- package/dist/boot/skill-transfer-origin.js.map +1 -1
- package/dist/domain/agentchannel/steps.d.ts +8 -6
- package/dist/domain/agentchannel/steps.d.ts.map +1 -1
- package/dist/domain/agentchannel/steps.js +9 -7
- package/dist/domain/agentchannel/steps.js.map +1 -1
- package/dist/domain/agentexecution/controller.d.ts +7 -0
- package/dist/domain/agentexecution/controller.d.ts.map +1 -1
- package/dist/domain/agentexecution/controller.js +1 -1
- package/dist/domain/agentexecution/controller.js.map +1 -1
- package/dist/domain/agentexecution/create-steps.d.ts +26 -12
- package/dist/domain/agentexecution/create-steps.d.ts.map +1 -1
- package/dist/domain/agentexecution/create-steps.js +61 -43
- package/dist/domain/agentexecution/create-steps.js.map +1 -1
- package/dist/domain/agentexecution/submit-approval.d.ts.map +1 -1
- package/dist/domain/agentexecution/submit-approval.js +9 -6
- package/dist/domain/agentexecution/submit-approval.js.map +1 -1
- package/dist/domain/agentexecution/submit-file-decision.d.ts.map +1 -1
- package/dist/domain/agentexecution/submit-file-decision.js +5 -4
- package/dist/domain/agentexecution/submit-file-decision.js.map +1 -1
- package/dist/domain/agentshare/steps.d.ts +5 -3
- package/dist/domain/agentshare/steps.d.ts.map +1 -1
- package/dist/domain/agentshare/steps.js +6 -4
- package/dist/domain/agentshare/steps.js.map +1 -1
- package/dist/domain/apikey/verifier.d.ts +7 -0
- package/dist/domain/apikey/verifier.d.ts.map +1 -1
- package/dist/domain/apikey/verifier.js +34 -1
- package/dist/domain/apikey/verifier.js.map +1 -1
- package/dist/domain/channelapp/controller.d.ts +4 -3
- package/dist/domain/channelapp/controller.d.ts.map +1 -1
- package/dist/domain/channelapp/controller.js.map +1 -1
- package/dist/domain/executioncontext/steps.d.ts +2 -1
- package/dist/domain/executioncontext/steps.d.ts.map +1 -1
- package/dist/domain/executioncontext/steps.js +2 -1
- package/dist/domain/executioncontext/steps.js.map +1 -1
- package/dist/domain/iampolicy/access-lists.d.ts.map +1 -1
- package/dist/domain/iampolicy/access-lists.js +57 -2
- package/dist/domain/iampolicy/access-lists.js.map +1 -1
- package/dist/domain/iampolicy/change.d.ts +53 -0
- package/dist/domain/iampolicy/change.d.ts.map +1 -0
- package/dist/domain/iampolicy/change.js +44 -0
- package/dist/domain/iampolicy/change.js.map +1 -0
- package/dist/domain/iampolicy/constants.d.ts +6 -0
- package/dist/domain/iampolicy/constants.d.ts.map +1 -1
- package/dist/domain/iampolicy/constants.js +6 -0
- package/dist/domain/iampolicy/constants.js.map +1 -1
- package/dist/domain/iampolicy/controller.d.ts.map +1 -1
- package/dist/domain/iampolicy/controller.js +9 -5
- package/dist/domain/iampolicy/controller.js.map +1 -1
- package/dist/domain/iampolicy/grant-path.d.ts +31 -13
- package/dist/domain/iampolicy/grant-path.d.ts.map +1 -1
- package/dist/domain/iampolicy/grant-path.js +216 -19
- package/dist/domain/iampolicy/grant-path.js.map +1 -1
- package/dist/domain/iampolicy/membership.d.ts +11 -3
- package/dist/domain/iampolicy/membership.d.ts.map +1 -1
- package/dist/domain/iampolicy/membership.js +18 -13
- package/dist/domain/iampolicy/membership.js.map +1 -1
- package/dist/domain/iampolicy/resource-store.d.ts.map +1 -1
- package/dist/domain/iampolicy/resource-store.js +4 -0
- package/dist/domain/iampolicy/resource-store.js.map +1 -1
- package/dist/domain/iampolicy/role-lifecycle.d.ts.map +1 -1
- package/dist/domain/iampolicy/role-lifecycle.js +2 -2
- package/dist/domain/iampolicy/role-lifecycle.js.map +1 -1
- package/dist/domain/iampolicy/roles.d.ts.map +1 -1
- package/dist/domain/iampolicy/roles.js +7 -0
- package/dist/domain/iampolicy/roles.js.map +1 -1
- package/dist/domain/iampolicy/steps.d.ts +4 -3
- package/dist/domain/iampolicy/steps.d.ts.map +1 -1
- package/dist/domain/iampolicy/steps.js +7 -7
- package/dist/domain/iampolicy/steps.js.map +1 -1
- package/dist/domain/iampolicy/store-contract.d.ts.map +1 -1
- package/dist/domain/iampolicy/store-contract.js +22 -1
- package/dist/domain/iampolicy/store-contract.js.map +1 -1
- package/dist/domain/iampolicy/store.d.ts +18 -5
- package/dist/domain/iampolicy/store.d.ts.map +1 -1
- package/dist/domain/iampolicy/store.js.map +1 -1
- package/dist/domain/identityaccount/constants.d.ts +15 -0
- package/dist/domain/identityaccount/constants.d.ts.map +1 -1
- package/dist/domain/identityaccount/constants.js +17 -0
- package/dist/domain/identityaccount/constants.js.map +1 -1
- package/dist/domain/identityaccount/controller.d.ts.map +1 -1
- package/dist/domain/identityaccount/controller.js +17 -6
- package/dist/domain/identityaccount/controller.js.map +1 -1
- package/dist/domain/identityaccount/resolve.d.ts +47 -0
- package/dist/domain/identityaccount/resolve.d.ts.map +1 -1
- package/dist/domain/identityaccount/resolve.js +38 -1
- package/dist/domain/identityaccount/resolve.js.map +1 -1
- package/dist/domain/identityaccount/resource-store.d.ts.map +1 -1
- package/dist/domain/identityaccount/resource-store.js +11 -1
- package/dist/domain/identityaccount/resource-store.js.map +1 -1
- package/dist/domain/identityaccount/steps.d.ts +2 -1
- package/dist/domain/identityaccount/steps.d.ts.map +1 -1
- package/dist/domain/identityaccount/steps.js +4 -3
- package/dist/domain/identityaccount/steps.js.map +1 -1
- package/dist/domain/identityaccount/store-contract.js +2 -2
- package/dist/domain/identityaccount/store-contract.js.map +1 -1
- package/dist/domain/identityaccount/store.d.ts +6 -1
- package/dist/domain/identityaccount/store.d.ts.map +1 -1
- package/dist/domain/mcpserver/connect-sandbox.d.ts +67 -0
- package/dist/domain/mcpserver/connect-sandbox.d.ts.map +1 -0
- package/dist/domain/mcpserver/connect-sandbox.js +64 -0
- package/dist/domain/mcpserver/connect-sandbox.js.map +1 -0
- package/dist/domain/mcpserver/connect.d.ts +42 -10
- package/dist/domain/mcpserver/connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/connect.js +147 -40
- package/dist/domain/mcpserver/connect.js.map +1 -1
- package/dist/domain/mcpserver/controller.js +4 -2
- package/dist/domain/mcpserver/controller.js.map +1 -1
- package/dist/domain/mcpserver/engine.d.ts +26 -7
- package/dist/domain/mcpserver/engine.d.ts.map +1 -1
- package/dist/domain/mcpserver/engine.js.map +1 -1
- package/dist/domain/mcpserver/start-connect.d.ts +5 -0
- package/dist/domain/mcpserver/start-connect.d.ts.map +1 -1
- package/dist/domain/mcpserver/start-connect.js +38 -15
- package/dist/domain/mcpserver/start-connect.js.map +1 -1
- package/dist/domain/memory/controller.js +2 -1
- package/dist/domain/memory/controller.js.map +1 -1
- package/dist/domain/memory/list-index.d.ts +2 -0
- package/dist/domain/memory/list-index.d.ts.map +1 -0
- package/dist/domain/memory/list-index.js +31 -0
- package/dist/domain/memory/list-index.js.map +1 -0
- package/dist/domain/memory/queries.d.ts +10 -0
- package/dist/domain/memory/queries.d.ts.map +1 -0
- package/dist/domain/memory/queries.js +54 -0
- package/dist/domain/memory/queries.js.map +1 -0
- package/dist/domain/memory/steps.d.ts +13 -11
- package/dist/domain/memory/steps.d.ts.map +1 -1
- package/dist/domain/memory/steps.js +26 -57
- package/dist/domain/memory/steps.js.map +1 -1
- package/dist/domain/organization/steps.d.ts.map +1 -1
- package/dist/domain/organization/steps.js +1 -1
- package/dist/domain/organization/steps.js.map +1 -1
- package/dist/domain/platformclient/mint.d.ts.map +1 -1
- package/dist/domain/platformclient/mint.js +2 -2
- package/dist/domain/platformclient/mint.js.map +1 -1
- package/dist/domain/platformclient/verifier.d.ts.map +1 -1
- package/dist/domain/platformclient/verifier.js +6 -3
- package/dist/domain/platformclient/verifier.js.map +1 -1
- package/dist/domain/plugin/push.d.ts.map +1 -1
- package/dist/domain/plugin/push.js +1 -0
- package/dist/domain/plugin/push.js.map +1 -1
- package/dist/domain/schedule/steps.d.ts +3 -1
- package/dist/domain/schedule/steps.d.ts.map +1 -1
- package/dist/domain/schedule/steps.js +3 -1
- package/dist/domain/schedule/steps.js.map +1 -1
- package/dist/domain/skill/push.d.ts.map +1 -1
- package/dist/domain/skill/push.js +1 -0
- package/dist/domain/skill/push.js.map +1 -1
- package/dist/domain/workflow/registry/data/task-kind-registry.json +27 -1
- package/dist/domain/workflowexecution/submit-approval.d.ts +5 -2
- package/dist/domain/workflowexecution/submit-approval.d.ts.map +1 -1
- package/dist/domain/workflowexecution/submit-approval.js +1 -1
- package/dist/domain/workflowexecution/submit-approval.js.map +1 -1
- package/dist/domain/workflowexecution/submit-file-decision.d.ts +5 -2
- package/dist/domain/workflowexecution/submit-file-decision.d.ts.map +1 -1
- package/dist/domain/workflowexecution/submit-file-decision.js +1 -1
- package/dist/domain/workflowexecution/submit-file-decision.js.map +1 -1
- package/dist/domain/workflowexecution/submit-workflow-task-approval.d.ts.map +1 -1
- package/dist/domain/workflowexecution/submit-workflow-task-approval.js +12 -1
- package/dist/domain/workflowexecution/submit-workflow-task-approval.js.map +1 -1
- package/dist/domain/workflowinstance/controller.d.ts +6 -3
- package/dist/domain/workflowinstance/controller.d.ts.map +1 -1
- package/dist/domain/workflowinstance/controller.js +12 -7
- package/dist/domain/workflowinstance/controller.js.map +1 -1
- package/dist/domain/workflowinstance/steps.d.ts +31 -0
- package/dist/domain/workflowinstance/steps.d.ts.map +1 -1
- package/dist/domain/workflowinstance/steps.js +88 -1
- package/dist/domain/workflowinstance/steps.js.map +1 -1
- package/dist/extensions/composed-services.d.ts +56 -0
- package/dist/extensions/composed-services.d.ts.map +1 -0
- package/dist/extensions/composed-services.js +2 -0
- package/dist/extensions/composed-services.js.map +1 -0
- package/dist/extensions/drivers.d.ts +32 -1
- package/dist/extensions/drivers.d.ts.map +1 -1
- package/dist/extensions/identity.d.ts +4 -1
- package/dist/extensions/identity.d.ts.map +1 -1
- package/dist/extensions/identity.js +4 -1
- package/dist/extensions/identity.js.map +1 -1
- package/dist/extensions/registry.d.ts +37 -0
- package/dist/extensions/registry.d.ts.map +1 -1
- package/dist/extensions/registry.js +50 -0
- package/dist/extensions/registry.js.map +1 -1
- package/dist/extensions/resource-authorization.d.ts +78 -0
- package/dist/extensions/resource-authorization.d.ts.map +1 -1
- package/dist/extensions/resource-row-reader.d.ts +43 -0
- package/dist/extensions/resource-row-reader.d.ts.map +1 -0
- package/dist/extensions/resource-row-reader.js +2 -0
- package/dist/extensions/resource-row-reader.js.map +1 -0
- package/dist/extensions/visitor-classifier.d.ts +41 -0
- package/dist/extensions/visitor-classifier.d.ts.map +1 -0
- package/dist/extensions/visitor-classifier.js +2 -0
- package/dist/extensions/visitor-classifier.js.map +1 -0
- package/dist/identity/oidc-userinfo.d.ts +6 -1
- package/dist/identity/oidc-userinfo.d.ts.map +1 -1
- package/dist/identity/oidc-userinfo.js.map +1 -1
- package/dist/identity/oidc-verifier.d.ts.map +1 -1
- package/dist/identity/oidc-verifier.js +37 -8
- package/dist/identity/oidc-verifier.js.map +1 -1
- package/dist/index.d.ts +14 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +25 -9
- package/dist/index.js.map +1 -1
- package/dist/pipeline/errors.d.ts +8 -0
- package/dist/pipeline/errors.d.ts.map +1 -1
- package/dist/pipeline/errors.js +25 -16
- package/dist/pipeline/errors.js.map +1 -1
- package/dist/pipeline/interceptors/auth.d.ts +17 -9
- package/dist/pipeline/interceptors/auth.d.ts.map +1 -1
- package/dist/pipeline/interceptors/auth.js +17 -9
- package/dist/pipeline/interceptors/auth.js.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.d.ts +23 -1
- package/dist/pipeline/steps/authorization-tuples.d.ts.map +1 -1
- package/dist/pipeline/steps/authorization-tuples.js +42 -0
- package/dist/pipeline/steps/authorization-tuples.js.map +1 -1
- package/dist/pipeline/steps/authorize.d.ts +6 -5
- package/dist/pipeline/steps/authorize.d.ts.map +1 -1
- package/dist/pipeline/steps/authorize.js +6 -5
- package/dist/pipeline/steps/authorize.js.map +1 -1
- package/dist/pipeline/steps/defaults.d.ts +12 -0
- package/dist/pipeline/steps/defaults.d.ts.map +1 -1
- package/dist/pipeline/steps/defaults.js +42 -7
- package/dist/pipeline/steps/defaults.js.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.d.ts +13 -15
- package/dist/pipeline/steps/guard-memory-capture.d.ts.map +1 -1
- package/dist/pipeline/steps/guard-memory-capture.js +2 -3
- package/dist/pipeline/steps/guard-memory-capture.js.map +1 -1
- package/dist/runnerauth/built-in-runner-credential-provider.d.ts +0 -2
- package/dist/runnerauth/built-in-runner-credential-provider.d.ts.map +1 -1
- package/dist/runnerauth/built-in-runner-credential-provider.js +8 -17
- package/dist/runnerauth/built-in-runner-credential-provider.js.map +1 -1
- package/dist/runnerauth/runner-credential-provider.d.ts +17 -7
- package/dist/runnerauth/runner-credential-provider.d.ts.map +1 -1
- package/dist/runnerauth/runner-credential-provider.js.map +1 -1
- package/dist/sandbox/docker.d.ts.map +1 -1
- package/dist/sandbox/docker.js +3 -0
- package/dist/sandbox/docker.js.map +1 -1
- package/dist/sandbox/kubernetes.d.ts.map +1 -1
- package/dist/sandbox/kubernetes.js +3 -0
- package/dist/sandbox/kubernetes.js.map +1 -1
- package/dist/sandbox/local-process.d.ts.map +1 -1
- package/dist/sandbox/local-process.js +4 -0
- package/dist/sandbox/local-process.js.map +1 -1
- package/dist/sandbox/provisioner.d.ts +18 -6
- package/dist/sandbox/provisioner.d.ts.map +1 -1
- package/dist/sandbox/provisioner.js.map +1 -1
- package/dist/temporal/manager.d.ts +5 -0
- package/dist/temporal/manager.d.ts.map +1 -1
- package/dist/temporal/manager.js +9 -0
- package/dist/temporal/manager.js.map +1 -1
- package/dist/temporal/mcpserver/engine-client.d.ts +2 -2
- package/dist/temporal/mcpserver/engine-client.d.ts.map +1 -1
- package/dist/temporal/mcpserver/engine-client.js +6 -4
- package/dist/temporal/mcpserver/engine-client.js.map +1 -1
- package/dist/temporal/mcpserver/names.d.ts +13 -2
- package/dist/temporal/mcpserver/names.d.ts.map +1 -1
- package/dist/temporal/mcpserver/names.js +15 -2
- package/dist/temporal/mcpserver/names.js.map +1 -1
- package/dist/temporal/sdk-logger.d.ts +74 -0
- package/dist/temporal/sdk-logger.d.ts.map +1 -0
- package/dist/temporal/sdk-logger.js +143 -0
- package/dist/temporal/sdk-logger.js.map +1 -0
- package/package.json +6 -6
- package/src/authorization/README.md +18 -6
- package/src/authorization/__tests__/authorizer.test.ts +5 -1
- package/src/authorization/__tests__/derived-tuples.test.ts +26 -0
- package/src/authorization/__tests__/evaluator.test.ts +4 -0
- package/src/authorization/__tests__/list-read-scope.test.ts +11 -5
- package/src/authorization/__tests__/store-tests.test.ts +3 -1
- package/src/authorization/__tests__/trusted-local-authorizer.test.ts +155 -0
- package/src/authorization/__tests__/unit-owned-kinds.test.ts +420 -0
- package/src/authorization/__tests__/wire-permissions.test.ts +31 -2
- package/src/authorization/authorizer.ts +21 -10
- package/src/authorization/derived-tuples.ts +92 -18
- package/src/authorization/evaluator.ts +30 -15
- package/src/authorization/list-read-scope.ts +4 -0
- package/src/authorization/model/__tests__/registry.test.ts +23 -0
- package/src/authorization/model/data/authorization-model.json +830 -67
- package/src/authorization/model/execution-viewer.ts +32 -27
- package/src/authorization/model/index.ts +4 -1
- package/src/authorization/model/rewrite.ts +5 -3
- package/src/authorization/organization-directory.ts +4 -0
- package/src/authorization/person.ts +32 -1
- package/src/authorization/policy-check.ts +105 -0
- package/src/authorization/posture.ts +45 -4
- package/src/authorization/resource-creators.ts +48 -0
- package/src/authorization/trusted-local-authorizer.ts +91 -0
- package/src/authorization/tuples.ts +17 -0
- package/src/boot/__tests__/compose.test.ts +120 -4
- package/src/boot/__tests__/list-indexes.test.ts +4 -0
- package/src/boot/__tests__/oauth-redirect-uri.test.ts +121 -10
- package/src/boot/__tests__/skill-transfer-origin.test.ts +96 -25
- package/src/boot/compose.ts +153 -61
- package/src/boot/config.ts +28 -12
- package/src/boot/inprocess.ts +18 -4
- package/src/boot/list-indexes.ts +6 -1
- package/src/boot/logger.ts +3 -1
- package/src/boot/oauth-redirect-uri.ts +62 -17
- package/src/boot/skill-transfer-origin.ts +71 -16
- package/src/domain/agent/__tests__/agent.test.ts +42 -1
- package/src/domain/agentchannel/__tests__/agentchannel.test.ts +9 -0
- package/src/domain/agentchannel/__tests__/channel-runtime.test.ts +2 -0
- package/src/domain/agentchannel/__tests__/create-authorization.test.ts +7 -6
- package/src/domain/agentchannel/steps.ts +9 -7
- package/src/domain/agentexecution/__tests__/agentexecution.test.ts +148 -56
- package/src/domain/agentexecution/__tests__/create-steps.test.ts +175 -12
- package/src/domain/agentexecution/__tests__/file-review-seed.ts +91 -0
- package/src/domain/agentexecution/controller.ts +8 -0
- package/src/domain/agentexecution/create-steps.ts +74 -44
- package/src/domain/agentexecution/submit-approval.ts +9 -6
- package/src/domain/agentexecution/submit-file-decision.ts +5 -4
- package/src/domain/agentinstance/__tests__/agentinstance.test.ts +2 -0
- package/src/domain/agentshare/__tests__/agentshare.test.ts +17 -0
- package/src/domain/agentshare/__tests__/create-authorization.test.ts +5 -4
- package/src/domain/agentshare/steps.ts +6 -4
- package/src/domain/apikey/__tests__/verifier.test.ts +73 -1
- package/src/domain/apikey/verifier.ts +45 -1
- package/src/domain/artifact/__tests__/artifact.test.ts +13 -24
- package/src/domain/channelapp/__tests__/channelapp.test.ts +7 -0
- package/src/domain/channelapp/controller.ts +4 -3
- package/src/domain/environment/__tests__/environment.test.ts +13 -0
- package/src/domain/executioncontext/__tests__/executioncontext.test.ts +2 -0
- package/src/domain/executioncontext/steps.ts +2 -1
- package/src/domain/iampolicy/__tests__/access-lists.test.ts +79 -0
- package/src/domain/iampolicy/__tests__/change.test.ts +63 -0
- package/src/domain/iampolicy/__tests__/controller.test.ts +39 -3
- package/src/domain/iampolicy/__tests__/grant-path.test.ts +595 -27
- package/src/domain/iampolicy/__tests__/iampolicy.test.ts +33 -2
- package/src/domain/iampolicy/__tests__/membership.test.ts +47 -5
- package/src/domain/iampolicy/__tests__/resource-store.test.ts +1 -0
- package/src/domain/iampolicy/__tests__/role-lifecycle.test.ts +41 -8
- package/src/domain/iampolicy/__tests__/roles.test.ts +3 -2
- package/src/domain/iampolicy/__tests__/steps.test.ts +75 -6
- package/src/domain/iampolicy/__tests__/support.ts +68 -4
- package/src/domain/iampolicy/access-lists.ts +70 -2
- package/src/domain/iampolicy/change.ts +109 -0
- package/src/domain/iampolicy/constants.ts +8 -0
- package/src/domain/iampolicy/controller.ts +17 -3
- package/src/domain/iampolicy/grant-path.ts +349 -31
- package/src/domain/iampolicy/membership.ts +32 -12
- package/src/domain/iampolicy/resource-store.ts +4 -0
- package/src/domain/iampolicy/role-lifecycle.ts +2 -0
- package/src/domain/iampolicy/roles.ts +8 -0
- package/src/domain/iampolicy/steps.ts +15 -5
- package/src/domain/iampolicy/store-contract.ts +37 -1
- package/src/domain/iampolicy/store.ts +19 -5
- package/src/domain/identityaccount/__tests__/resolve.test.ts +246 -2
- package/src/domain/identityaccount/__tests__/resource-store.test.ts +1 -1
- package/src/domain/identityaccount/constants.ts +20 -0
- package/src/domain/identityaccount/controller.ts +20 -5
- package/src/domain/identityaccount/resolve.ts +80 -1
- package/src/domain/identityaccount/resource-store.ts +14 -1
- package/src/domain/identityaccount/steps.ts +4 -3
- package/src/domain/identityaccount/store-contract.ts +4 -4
- package/src/domain/identityaccount/store.ts +6 -1
- package/src/domain/mcpserver/__tests__/connect-authorization.test.ts +1 -0
- package/src/domain/mcpserver/__tests__/connect.test.ts +358 -15
- package/src/domain/mcpserver/__tests__/mcpserver.test.ts +2 -0
- package/src/domain/mcpserver/__tests__/oauth-handshake.test.ts +2 -0
- package/src/domain/mcpserver/__tests__/store-faults.test.ts +2 -0
- package/src/domain/mcpserver/connect-sandbox.ts +135 -0
- package/src/domain/mcpserver/connect.ts +226 -56
- package/src/domain/mcpserver/controller.ts +8 -2
- package/src/domain/mcpserver/engine.ts +24 -6
- package/src/domain/mcpserver/start-connect.ts +49 -10
- package/src/domain/memory/__tests__/memory.test.ts +92 -22
- package/src/domain/memory/__tests__/queries.test.ts +173 -0
- package/src/domain/memory/controller.ts +2 -1
- package/src/domain/memory/list-index.ts +32 -0
- package/src/domain/memory/queries.ts +72 -0
- package/src/domain/memory/steps.ts +26 -63
- package/src/domain/oauthapp/__tests__/oauthapp.test.ts +14 -0
- package/src/domain/organization/__tests__/support.ts +41 -0
- package/src/domain/organization/steps.ts +1 -0
- package/src/domain/platformclient/mint.ts +6 -2
- package/src/domain/platformclient/verifier.ts +6 -3
- package/src/domain/plugin/__tests__/plugin.test.ts +11 -24
- package/src/domain/plugin/push.ts +1 -0
- package/src/domain/schedule/__tests__/schedule.composed.test.ts +2 -0
- package/src/domain/schedule/steps.ts +3 -1
- package/src/domain/session/__tests__/session.test.ts +2 -0
- package/src/domain/skill/__tests__/skill.test.ts +7 -25
- package/src/domain/skill/push.ts +1 -0
- package/src/domain/workflow/__tests__/workflow.test.ts +2 -0
- package/src/domain/workflow/registry/data/task-kind-registry.json +27 -1
- package/src/domain/workflowexecution/__tests__/forward-attribution-composed.test.ts +270 -0
- package/src/domain/workflowexecution/__tests__/submit-workflow-task-approval.test.ts +196 -0
- package/src/domain/workflowexecution/__tests__/workflowexecution.test.ts +3 -57
- package/src/domain/workflowexecution/submit-approval.ts +9 -2
- package/src/domain/workflowexecution/submit-file-decision.ts +6 -1
- package/src/domain/workflowexecution/submit-workflow-task-approval.ts +23 -5
- package/src/domain/workflowinstance/controller.ts +27 -9
- package/src/domain/workflowinstance/steps.ts +123 -1
- package/src/extensions/__tests__/apikey-before-sign-in-composed.test.ts +172 -0
- package/src/extensions/__tests__/built-in-authorization-composed.test.ts +80 -1
- package/src/extensions/__tests__/composed-services-composed.test.ts +236 -0
- package/src/extensions/__tests__/extension-composition.test.ts +229 -16
- package/src/extensions/__tests__/identity-account-composed.test.ts +84 -4
- package/src/extensions/__tests__/list-read-scope-composed.test.ts +2 -0
- package/src/extensions/__tests__/registry.test.ts +147 -1
- package/src/extensions/__tests__/secret-cleanup-composed.test.ts +2 -0
- package/src/extensions/__tests__/visitor-classifier-points.test.ts +42 -0
- package/src/extensions/composed-services.ts +61 -0
- package/src/extensions/drivers.ts +33 -1
- package/src/extensions/identity.ts +4 -1
- package/src/extensions/registry.ts +105 -0
- package/src/extensions/resource-authorization.ts +87 -0
- package/src/extensions/resource-row-reader.ts +43 -0
- package/src/extensions/visitor-classifier.ts +41 -0
- package/src/identity/__tests__/oidc-verifier.test.ts +38 -12
- package/src/identity/oidc-userinfo.ts +6 -1
- package/src/identity/oidc-verifier.ts +42 -8
- package/src/index.ts +61 -6
- package/src/pipeline/__tests__/steps.test.ts +31 -4
- package/src/pipeline/errors.ts +30 -16
- package/src/pipeline/interceptors/auth.ts +17 -9
- package/src/pipeline/steps/__tests__/authorization-tuples.test.ts +20 -0
- package/src/pipeline/steps/__tests__/guard-memory-capture.test.ts +72 -15
- package/src/pipeline/steps/authorization-tuples.ts +54 -0
- package/src/pipeline/steps/authorize.ts +6 -5
- package/src/pipeline/steps/defaults.ts +52 -7
- package/src/pipeline/steps/guard-memory-capture.ts +15 -20
- package/src/runnerauth/__tests__/built-in-runner-credential-provider.test.ts +1 -1
- package/src/runnerauth/__tests__/runner-subject-composed.test.ts +13 -0
- package/src/runnerauth/bound-execution.ts +2 -2
- package/src/runnerauth/built-in-runner-credential-provider.ts +8 -21
- package/src/runnerauth/runner-credential-provider.ts +17 -7
- package/src/sandbox/__tests__/docker.integration.test.ts +4 -0
- package/src/sandbox/__tests__/kubernetes.test.ts +18 -1
- package/src/sandbox/__tests__/local-process.integration.test.ts +4 -0
- package/src/sandbox/__tests__/provisioner.test.ts +1 -0
- package/src/sandbox/docker.ts +3 -0
- package/src/sandbox/kubernetes.ts +3 -0
- package/src/sandbox/local-process.ts +4 -0
- package/src/sandbox/provisioner.ts +18 -6
- package/src/store/postgres/__tests__/support.ts +11 -2
- package/src/temporal/README.md +1 -0
- package/src/temporal/__tests__/manager.test.ts +56 -4
- package/src/temporal/__tests__/sdk-log-workflows.ts +26 -0
- package/src/temporal/__tests__/sdk-logger.e2e.test.ts +150 -0
- package/src/temporal/__tests__/sdk-logger.test.ts +238 -0
- package/src/temporal/manager.ts +9 -0
- package/src/temporal/mcpserver/engine-client.ts +8 -3
- package/src/temporal/mcpserver/names.ts +16 -2
- package/src/temporal/sdk-logger.ts +173 -0
- package/dist/authorization/lane-admission.d.ts +0 -50
- package/dist/authorization/lane-admission.d.ts.map +0 -1
- package/dist/authorization/lane-admission.js +0 -13
- package/dist/authorization/lane-admission.js.map +0 -1
- package/src/authorization/__tests__/lane-admission.test.ts +0 -115
- package/src/authorization/lane-admission.ts +0 -73
|
@@ -46,6 +46,52 @@
|
|
|
46
46
|
* `cleanupResource` and `revokeOrgAccess` take refs and ids their callers
|
|
47
47
|
* read from rows, so they do not refuse.
|
|
48
48
|
*
|
|
49
|
+
* Leaving an organization. The model bounds every direct grant on an
|
|
50
|
+
* organization-scoped object by the organization (`[identity_account]
|
|
51
|
+
* and affiliated from organization`, fga/model/tenancy/organization.fga),
|
|
52
|
+
* so a person with no role left in an organization reaches nothing in it
|
|
53
|
+
* on the next check. This path keeps the ROWS truthful to that: when a
|
|
54
|
+
* revoke leaves an account with no row on an organization, it revokes the
|
|
55
|
+
* rows the account holds on that organization's resources (a share, a
|
|
56
|
+
* team membership, an owner granted by someone else), each through the
|
|
57
|
+
* revoke order, so a departed person is listed nowhere and a return does
|
|
58
|
+
* not bring the shares back. It keeps AUTHORSHIP: an `owner` or `creator`
|
|
59
|
+
* row whose principal is the resource's recorded creator, exactly the
|
|
60
|
+
* tuple open source derives from the creator stamp instead of storing it
|
|
61
|
+
* (authorization/derived-tuples.ts), so both editions keep the same fact
|
|
62
|
+
* and the model's bound governs it in both. `revokeOrgAccess` always
|
|
63
|
+
* sweeps, so a retry after a crash mid-sweep converges; `revokeBySpec`
|
|
64
|
+
* sweeps when the row it revoked was the account's last on that
|
|
65
|
+
* organization; `cleanupResource` never sweeps (an organization's or an
|
|
66
|
+
* account's delete, where the bound already leaves every row inert and a
|
|
67
|
+
* sweep per member would add failure points to a delete that stops on
|
|
68
|
+
* the first fault). A resource's organization is read from the scope
|
|
69
|
+
* links the rows hold (`resolveHierarchy`); open source writes none and
|
|
70
|
+
* grants nothing below the organization (grant-scope.ts), so there the
|
|
71
|
+
* sweep finds nothing to do.
|
|
72
|
+
*
|
|
73
|
+
* Affiliation. The model's bound reads `organization#affiliated`, a stored
|
|
74
|
+
* relation that stands exactly while the person holds a row on the
|
|
75
|
+
* organization. This path is the one writer of those rows, so it announces
|
|
76
|
+
* every change of them through the lifecycle and never decides the answer
|
|
77
|
+
* itself: `onOrganizationAffiliationChanging` before a row naming an
|
|
78
|
+
* account on an organization is deleted (the driver removes the tuple
|
|
79
|
+
* first, fail-closed), `onOrganizationAffiliationChanged` after such a row
|
|
80
|
+
* is written or deleted (the driver re-derives the tuple from the committed
|
|
81
|
+
* rows). `affiliated` itself is refused as a grant on every lane; it is
|
|
82
|
+
* derived, never granted.
|
|
83
|
+
*
|
|
84
|
+
* Who and why. Every method takes the caller, and the grants take the door
|
|
85
|
+
* they came through (change.ts `PolicyChangeCause`); the revokes know
|
|
86
|
+
* theirs. For every access row it writes or deletes, the path hands the
|
|
87
|
+
* store a change record (the actor, the cause, the row's organization), so
|
|
88
|
+
* an edition that keeps a permission history writes it in the same atomic
|
|
89
|
+
* unit as the row (store.ts). The organization is resolved before any row
|
|
90
|
+
* of the operation is deleted: `cleanupResource` removes a resource's
|
|
91
|
+
* scope link before its owner rows, and the sweep already knows its
|
|
92
|
+
* organization. The grant and revoke log lines carry the same facts, open
|
|
93
|
+
* source's own trail.
|
|
94
|
+
*
|
|
49
95
|
* The row this path builds: the proto's apiVersion const and kind, the
|
|
50
96
|
* derived id, the spec as given, and the caller's audit stamp through the
|
|
51
97
|
* platform's one stamper (setAuditFieldsForCreate) — the cloud's
|
|
@@ -54,6 +100,7 @@
|
|
|
54
100
|
* span organizations and none owns it.
|
|
55
101
|
*/
|
|
56
102
|
import { create } from "@bufbuild/protobuf";
|
|
103
|
+
import { Code, ConnectError } from "@connectrpc/connect";
|
|
57
104
|
|
|
58
105
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
59
106
|
import { ApiResourceMetadataSchema } from "@stigmer/protos/ai/stigmer/commons/apiresource/metadata_pb";
|
|
@@ -67,14 +114,25 @@ import type {
|
|
|
67
114
|
|
|
68
115
|
import type { Logger } from "../../boot/logger.js";
|
|
69
116
|
import type { CallerIdentity } from "../../extensions/identity.js";
|
|
70
|
-
import type {
|
|
117
|
+
import type {
|
|
118
|
+
OrganizationAffiliationEvent,
|
|
119
|
+
ResourceAuthorizationLifecycle,
|
|
120
|
+
} from "../../extensions/resource-authorization.js";
|
|
71
121
|
import { kindEnumName } from "../../pipeline/apiresource-meta.js";
|
|
72
122
|
import { setAuditFieldsForCreate } from "../../pipeline/steps/defaults.js";
|
|
73
123
|
import {
|
|
124
|
+
AFFILIATION_NOT_GRANTABLE_MESSAGE,
|
|
74
125
|
IAM_POLICY_API_VERSION,
|
|
75
126
|
IAM_POLICY_KIND,
|
|
76
127
|
policyIdFor,
|
|
77
128
|
} from "./constants.js";
|
|
129
|
+
import { resolveHierarchy } from "./access-lists.js";
|
|
130
|
+
import { grantsAccess, policyActorOf } from "./change.js";
|
|
131
|
+
import type {
|
|
132
|
+
PolicyActor,
|
|
133
|
+
PolicyChangeCause,
|
|
134
|
+
PolicyChangeRecord,
|
|
135
|
+
} from "./change.js";
|
|
78
136
|
import { DuplicatePolicyError } from "./store.js";
|
|
79
137
|
import type { IamPolicyStore } from "./store.js";
|
|
80
138
|
import { refsOf, requireWellFormedTriple } from "./wire-refusals.js";
|
|
@@ -82,6 +140,45 @@ import { refsOf, requireWellFormedTriple } from "./wire-refusals.js";
|
|
|
82
140
|
/** The relation `cleanupResource` revokes last on the ref's own rows. */
|
|
83
141
|
const OWNER_RELATION = IamRole[IamRole.owner];
|
|
84
142
|
|
|
143
|
+
const ACCOUNT_KIND = kindEnumName(ApiResourceKind.identity_account);
|
|
144
|
+
const ORGANIZATION_KIND = kindEnumName(ApiResourceKind.organization);
|
|
145
|
+
|
|
146
|
+
/** The organization relation derived from a person's roles (fga/model/tenancy/organization.fga). */
|
|
147
|
+
const AFFILIATED_RELATION = "affiliated";
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* The (account, organization) pair a row's affiliation hangs on, or
|
|
151
|
+
* undefined when the row is not a person's row on an organization (a
|
|
152
|
+
* structural link, a userset principal, a row on any other kind).
|
|
153
|
+
*/
|
|
154
|
+
function affiliationOf(
|
|
155
|
+
spec: IamPolicySpec,
|
|
156
|
+
): OrganizationAffiliationEvent | undefined {
|
|
157
|
+
const principal = spec.principal;
|
|
158
|
+
const resource = spec.resource;
|
|
159
|
+
if (
|
|
160
|
+
principal === undefined ||
|
|
161
|
+
resource === undefined ||
|
|
162
|
+
principal.kind !== ACCOUNT_KIND ||
|
|
163
|
+
principal.relation !== "" ||
|
|
164
|
+
resource.kind !== ORGANIZATION_KIND
|
|
165
|
+
) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
return { identityAccountId: principal.id, organizationId: resource.id };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* The relations a resource's creation records for its creator: `owner`
|
|
173
|
+
* on a kind whose owner is its creator, `creator` on a kind that also
|
|
174
|
+
* records one (the proto's `requires_creator_tuple`). The removal sweep
|
|
175
|
+
* keeps these when they name the resource's recorded creator.
|
|
176
|
+
*/
|
|
177
|
+
const AUTHORSHIP_RELATIONS: ReadonlySet<string> = new Set([
|
|
178
|
+
OWNER_RELATION,
|
|
179
|
+
"creator",
|
|
180
|
+
]);
|
|
181
|
+
|
|
85
182
|
export interface GrantResult {
|
|
86
183
|
readonly policy: IamPolicy;
|
|
87
184
|
/** True when the triple was already held: no row was written, the hook still fired. */
|
|
@@ -90,18 +187,26 @@ export interface GrantResult {
|
|
|
90
187
|
|
|
91
188
|
export interface IamPolicyGrantPath {
|
|
92
189
|
/**
|
|
93
|
-
* Grant the triple as `caller
|
|
94
|
-
* absent (the caller's audit stamp),
|
|
95
|
-
* duplicate arm too. A hook throw fails
|
|
190
|
+
* Grant the triple as `caller`, through the door `cause` names: gate,
|
|
191
|
+
* find by triple, write the row when absent (the caller's audit stamp),
|
|
192
|
+
* then `onPolicyGranted` — on the duplicate arm too. A hook throw fails
|
|
193
|
+
* the grant with the row in place.
|
|
96
194
|
*/
|
|
97
|
-
grant(
|
|
195
|
+
grant(
|
|
196
|
+
spec: IamPolicySpec,
|
|
197
|
+
caller: CallerIdentity,
|
|
198
|
+
cause: PolicyChangeCause,
|
|
199
|
+
): Promise<GrantResult>;
|
|
98
200
|
/**
|
|
99
|
-
* Revoke the triple: gate, find by
|
|
100
|
-
* row, or with the spec alone on the
|
|
101
|
-
* A hook throw leaves row and tuple.
|
|
102
|
-
* `undefined` when there was none.
|
|
201
|
+
* Revoke the triple as `caller` (IamPolicy.delete's door): gate, find by
|
|
202
|
+
* triple, `onPolicyRevoked` (with the row, or with the spec alone on the
|
|
203
|
+
* absent arm), then delete the row. A hook throw leaves row and tuple.
|
|
204
|
+
* Answers the revoked row, or `undefined` when there was none.
|
|
103
205
|
*/
|
|
104
|
-
revokeBySpec(
|
|
206
|
+
revokeBySpec(
|
|
207
|
+
spec: IamPolicySpec,
|
|
208
|
+
caller: CallerIdentity,
|
|
209
|
+
): Promise<IamPolicy | undefined>;
|
|
105
210
|
/**
|
|
106
211
|
* Revoke every row naming the ref as its principal, then every row naming
|
|
107
212
|
* it as its resource with the `owner` rows last, each through the revoke
|
|
@@ -109,27 +214,88 @@ export interface IamPolicyGrantPath {
|
|
|
109
214
|
* The order matters where the ref still exists: an organization's delete
|
|
110
215
|
* runs this before its row goes and fails on the first fault, so a
|
|
111
216
|
* cleanup that stops partway has not yet removed the owners who may
|
|
112
|
-
* retry it.
|
|
217
|
+
* retry it. `caller` is whoever deleted the resource.
|
|
218
|
+
*/
|
|
219
|
+
cleanupResource(ref: ApiResourceRef, caller: CallerIdentity): Promise<void>;
|
|
220
|
+
/**
|
|
221
|
+
* Revoke every relation the account holds directly on the organization,
|
|
222
|
+
* then every row it holds on the organization's resources except its
|
|
223
|
+
* authorship (the module header's sweep), as `caller`.
|
|
113
224
|
*/
|
|
114
|
-
cleanupResource(ref: ApiResourceRef): Promise<void>;
|
|
115
|
-
/** Revoke every relation the account holds directly on the organization. */
|
|
116
225
|
revokeOrgAccess(
|
|
117
226
|
identityAccountId: string,
|
|
118
227
|
organizationId: string,
|
|
228
|
+
caller: CallerIdentity,
|
|
119
229
|
): Promise<void>;
|
|
120
230
|
}
|
|
121
231
|
|
|
232
|
+
/**
|
|
233
|
+
* The recorded creator of a stored resource, the one fact the removal
|
|
234
|
+
* sweep needs from outside the policy rows.
|
|
235
|
+
*/
|
|
236
|
+
export interface ResourceCreators {
|
|
237
|
+
/**
|
|
238
|
+
* The row's `status.audit.spec_audit.created_by.id`, or undefined when
|
|
239
|
+
* this server stores no row of that kind and id.
|
|
240
|
+
*/
|
|
241
|
+
creatorOf(kind: string, id: string): Promise<string | undefined>;
|
|
242
|
+
}
|
|
243
|
+
|
|
122
244
|
export interface IamPolicyGrantPathDeps {
|
|
123
245
|
readonly policies: IamPolicyStore;
|
|
246
|
+
readonly creators: ResourceCreators;
|
|
124
247
|
/** The composed driver, if any; a driver without the two policy hooks is the same as none. */
|
|
125
248
|
readonly lifecycle: ResourceAuthorizationLifecycle | undefined;
|
|
126
249
|
readonly logger: Logger;
|
|
127
250
|
}
|
|
128
251
|
|
|
252
|
+
/** Who made a change and through which door; the organization is resolved per row. */
|
|
253
|
+
interface Change {
|
|
254
|
+
readonly actor: PolicyActor;
|
|
255
|
+
readonly cause: PolicyChangeCause;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
/** How a row's organization is found: the scope walk, or a value its operation already knows. */
|
|
259
|
+
type OrganizationOf = (resource: ApiResourceRef) => Promise<string>;
|
|
260
|
+
|
|
129
261
|
export function newIamPolicyGrantPath(
|
|
130
262
|
deps: IamPolicyGrantPathDeps,
|
|
131
263
|
): IamPolicyGrantPath {
|
|
132
|
-
const { policies, lifecycle, logger } = deps;
|
|
264
|
+
const { policies, creators, lifecycle, logger } = deps;
|
|
265
|
+
|
|
266
|
+
/** The organization a resource belongs to, through its scope links; "" when it names none. */
|
|
267
|
+
async function organizationByScope(
|
|
268
|
+
resource: ApiResourceRef,
|
|
269
|
+
): Promise<string> {
|
|
270
|
+
if (resource.kind === ORGANIZATION_KIND) {
|
|
271
|
+
return resource.id;
|
|
272
|
+
}
|
|
273
|
+
const hierarchy = await resolveHierarchy(
|
|
274
|
+
policies,
|
|
275
|
+
resource.kind,
|
|
276
|
+
resource.id,
|
|
277
|
+
true,
|
|
278
|
+
);
|
|
279
|
+
return (
|
|
280
|
+
hierarchy.find((level) => level.kind === ORGANIZATION_KIND)?.id ?? ""
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
/** The record the store keeps beside an access row; none for a structural link. */
|
|
285
|
+
async function recordFor(
|
|
286
|
+
spec: IamPolicySpec,
|
|
287
|
+
change: Change,
|
|
288
|
+
organizationOf: OrganizationOf,
|
|
289
|
+
): Promise<PolicyChangeRecord | undefined> {
|
|
290
|
+
if (spec.resource === undefined || !grantsAccess(spec)) {
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
return {
|
|
294
|
+
actor: change.actor,
|
|
295
|
+
cause: change.cause,
|
|
296
|
+
organizationId: await organizationOf(spec.resource),
|
|
297
|
+
};
|
|
298
|
+
}
|
|
133
299
|
|
|
134
300
|
/** The row holding this exact triple — the pair's rows, filtered by relation. */
|
|
135
301
|
async function findByTriple(
|
|
@@ -150,31 +316,129 @@ export function newIamPolicyGrantPath(
|
|
|
150
316
|
);
|
|
151
317
|
}
|
|
152
318
|
|
|
153
|
-
/** The revoke order for one row: the hook, then the delete. */
|
|
154
|
-
async function revokeRow(
|
|
319
|
+
/** The revoke order for one row: its record resolved, the hook, then the delete. */
|
|
320
|
+
async function revokeRow(
|
|
321
|
+
policy: IamPolicy,
|
|
322
|
+
change: Change,
|
|
323
|
+
organizationOf: OrganizationOf = organizationByScope,
|
|
324
|
+
): Promise<void> {
|
|
155
325
|
const spec = policy.spec;
|
|
156
326
|
if (spec === undefined) {
|
|
157
327
|
throw new Error(
|
|
158
328
|
`policy ${policy.metadata?.id ?? "?"} has no spec — corrupt row`,
|
|
159
329
|
);
|
|
160
330
|
}
|
|
331
|
+
const record = await recordFor(spec, change, organizationOf);
|
|
332
|
+
const affiliation = affiliationOf(spec);
|
|
333
|
+
if (affiliation !== undefined) {
|
|
334
|
+
await lifecycle?.onOrganizationAffiliationChanging?.(affiliation);
|
|
335
|
+
}
|
|
161
336
|
await lifecycle?.onPolicyRevoked?.({ spec, policy });
|
|
162
337
|
const id = policy.metadata?.id ?? "";
|
|
163
|
-
await policies.deleteById(id);
|
|
164
|
-
logger.info("iam policy revoked", fieldsOf(id, spec));
|
|
338
|
+
await policies.deleteById(id, record);
|
|
339
|
+
logger.info("iam policy revoked", fieldsOf(id, spec, change, record));
|
|
340
|
+
if (affiliation !== undefined) {
|
|
341
|
+
await lifecycle?.onOrganizationAffiliationChanged?.(affiliation);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/** Whether the account still holds any row on the organization. */
|
|
346
|
+
async function holdsOrganizationRow(
|
|
347
|
+
accountId: string,
|
|
348
|
+
organizationId: string,
|
|
349
|
+
): Promise<boolean> {
|
|
350
|
+
const held = await policies.findByPrincipal(ACCOUNT_KIND, accountId);
|
|
351
|
+
return held.some(
|
|
352
|
+
(policy) =>
|
|
353
|
+
policy.spec?.resource?.kind === ORGANIZATION_KIND &&
|
|
354
|
+
policy.spec.resource.id === organizationId,
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/** Whether the row records the resource's creator as its author. */
|
|
359
|
+
async function isAuthorship(
|
|
360
|
+
policy: IamPolicy,
|
|
361
|
+
accountId: string,
|
|
362
|
+
): Promise<boolean> {
|
|
363
|
+
const spec = policy.spec;
|
|
364
|
+
if (
|
|
365
|
+
spec?.resource === undefined ||
|
|
366
|
+
!AUTHORSHIP_RELATIONS.has(spec.relation)
|
|
367
|
+
) {
|
|
368
|
+
return false;
|
|
369
|
+
}
|
|
370
|
+
const creator = await creators.creatorOf(
|
|
371
|
+
spec.resource.kind,
|
|
372
|
+
spec.resource.id,
|
|
373
|
+
);
|
|
374
|
+
return creator === accountId;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
/** Revoke what the account holds on the organization's resources, authorship kept. */
|
|
378
|
+
async function sweepOrganization(
|
|
379
|
+
accountId: string,
|
|
380
|
+
organizationId: string,
|
|
381
|
+
actor: PolicyActor,
|
|
382
|
+
): Promise<void> {
|
|
383
|
+
const change: Change = { actor, cause: "left_organization" };
|
|
384
|
+
const inThisOrganization: OrganizationOf = async () => organizationId;
|
|
385
|
+
const held = await policies.findByPrincipal(ACCOUNT_KIND, accountId);
|
|
386
|
+
let revoked = 0;
|
|
387
|
+
for (const policy of held) {
|
|
388
|
+
const resource = policy.spec?.resource;
|
|
389
|
+
if (resource === undefined || resource.kind === ORGANIZATION_KIND) {
|
|
390
|
+
continue;
|
|
391
|
+
}
|
|
392
|
+
const hierarchy = await resolveHierarchy(
|
|
393
|
+
policies,
|
|
394
|
+
resource.kind,
|
|
395
|
+
resource.id,
|
|
396
|
+
true,
|
|
397
|
+
);
|
|
398
|
+
const inOrganization = hierarchy.some(
|
|
399
|
+
(level) =>
|
|
400
|
+
level.kind === ORGANIZATION_KIND && level.id === organizationId,
|
|
401
|
+
);
|
|
402
|
+
if (!inOrganization || (await isAuthorship(policy, accountId))) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
await revokeRow(policy, change, inThisOrganization);
|
|
406
|
+
revoked++;
|
|
407
|
+
}
|
|
408
|
+
if (revoked > 0) {
|
|
409
|
+
logger.info("iam policy organization access swept", {
|
|
410
|
+
identityAccountId: accountId,
|
|
411
|
+
organizationId,
|
|
412
|
+
revoked: String(revoked),
|
|
413
|
+
});
|
|
414
|
+
}
|
|
165
415
|
}
|
|
166
416
|
|
|
167
417
|
return {
|
|
168
|
-
async grant(spec, caller): Promise<GrantResult> {
|
|
418
|
+
async grant(spec, caller, cause): Promise<GrantResult> {
|
|
169
419
|
requireWellFormedTriple(spec);
|
|
420
|
+
const change: Change = { actor: policyActorOf(caller), cause };
|
|
421
|
+
if (
|
|
422
|
+
spec.relation === AFFILIATED_RELATION &&
|
|
423
|
+
spec.resource?.kind === ORGANIZATION_KIND
|
|
424
|
+
) {
|
|
425
|
+
throw new ConnectError(
|
|
426
|
+
AFFILIATION_NOT_GRANTABLE_MESSAGE,
|
|
427
|
+
Code.InvalidArgument,
|
|
428
|
+
);
|
|
429
|
+
}
|
|
170
430
|
let policy = await findByTriple(spec);
|
|
171
431
|
let duplicate = policy !== undefined;
|
|
172
432
|
if (policy === undefined) {
|
|
173
433
|
const fresh = buildRow(spec, caller);
|
|
434
|
+
const record = await recordFor(spec, change, organizationByScope);
|
|
174
435
|
try {
|
|
175
|
-
await policies.save(fresh);
|
|
436
|
+
await policies.save(fresh, record);
|
|
176
437
|
policy = fresh;
|
|
177
|
-
logger.info(
|
|
438
|
+
logger.info(
|
|
439
|
+
"iam policy granted",
|
|
440
|
+
fieldsOf(policyIdFor(spec), spec, change, record),
|
|
441
|
+
);
|
|
178
442
|
} catch (error) {
|
|
179
443
|
if (!(error instanceof DuplicatePolicyError)) {
|
|
180
444
|
throw error;
|
|
@@ -194,31 +458,66 @@ export function newIamPolicyGrantPath(
|
|
|
194
458
|
if (duplicate) {
|
|
195
459
|
logger.debug(
|
|
196
460
|
"iam policy already held",
|
|
197
|
-
fieldsOf(policy.metadata?.id ?? "", spec),
|
|
461
|
+
fieldsOf(policy.metadata?.id ?? "", spec, change, undefined),
|
|
198
462
|
);
|
|
199
463
|
}
|
|
200
464
|
// Deliberately unconditional (cloud#425): a duplicate re-grant is the
|
|
201
465
|
// inline heal for a row whose tuple never landed.
|
|
202
466
|
await lifecycle?.onPolicyGranted?.({ policy, duplicate });
|
|
467
|
+
// The same unconditional heal for the affiliation the row stands for.
|
|
468
|
+
const affiliation = affiliationOf(spec);
|
|
469
|
+
if (affiliation !== undefined) {
|
|
470
|
+
await lifecycle?.onOrganizationAffiliationChanged?.(affiliation);
|
|
471
|
+
}
|
|
203
472
|
return { policy, duplicate };
|
|
204
473
|
},
|
|
205
474
|
|
|
206
|
-
async revokeBySpec(spec): Promise<IamPolicy | undefined> {
|
|
475
|
+
async revokeBySpec(spec, caller): Promise<IamPolicy | undefined> {
|
|
207
476
|
requireWellFormedTriple(spec);
|
|
477
|
+
const actor = policyActorOf(caller);
|
|
208
478
|
const existing = await findByTriple(spec);
|
|
209
479
|
if (existing === undefined) {
|
|
210
480
|
// No row: a composition still deletes the bare tuple (one written
|
|
211
481
|
// before the row mirror existed); converges the store either way.
|
|
212
482
|
await lifecycle?.onPolicyRevoked?.({ spec, policy: undefined });
|
|
213
|
-
|
|
483
|
+
const affiliation = affiliationOf(spec);
|
|
484
|
+
if (affiliation !== undefined) {
|
|
485
|
+
// Nothing was deleted; re-deriving from the rows heals a tuple
|
|
486
|
+
// that outlived them.
|
|
487
|
+
await lifecycle?.onOrganizationAffiliationChanged?.(affiliation);
|
|
488
|
+
}
|
|
489
|
+
} else {
|
|
490
|
+
await revokeRow(existing, { actor, cause: "revoke" });
|
|
491
|
+
}
|
|
492
|
+
const { principal, resource } = refsOf(spec);
|
|
493
|
+
if (
|
|
494
|
+
principal.kind === ACCOUNT_KIND &&
|
|
495
|
+
resource.kind === ORGANIZATION_KIND &&
|
|
496
|
+
!(await holdsOrganizationRow(principal.id, resource.id))
|
|
497
|
+
) {
|
|
498
|
+
await sweepOrganization(principal.id, resource.id, actor);
|
|
214
499
|
}
|
|
215
|
-
await revokeRow(existing);
|
|
216
500
|
return existing;
|
|
217
501
|
},
|
|
218
502
|
|
|
219
|
-
async cleanupResource(ref): Promise<void> {
|
|
503
|
+
async cleanupResource(ref, caller): Promise<void> {
|
|
504
|
+
const change: Change = {
|
|
505
|
+
actor: policyActorOf(caller),
|
|
506
|
+
cause: "resource_deleted",
|
|
507
|
+
};
|
|
220
508
|
const asPrincipal = await policies.findByPrincipal(ref.kind, ref.id);
|
|
221
509
|
const asResource = await policies.findByResource(ref.kind, ref.id);
|
|
510
|
+
// The ref's own scope link is one of its resource-side rows and goes
|
|
511
|
+
// before its owners, so its organization is read once, up front.
|
|
512
|
+
const refOrganization = asResource.some(
|
|
513
|
+
(policy) => policy.spec !== undefined && grantsAccess(policy.spec),
|
|
514
|
+
)
|
|
515
|
+
? await organizationByScope(ref)
|
|
516
|
+
: "";
|
|
517
|
+
const organizationOf: OrganizationOf = async (resource) =>
|
|
518
|
+
resource.kind === ref.kind && resource.id === ref.id
|
|
519
|
+
? refOrganization
|
|
520
|
+
: organizationByScope(resource);
|
|
222
521
|
const isOwner = (policy: IamPolicy): boolean =>
|
|
223
522
|
policy.spec?.relation === OWNER_RELATION;
|
|
224
523
|
for (const policy of distinctById([
|
|
@@ -226,11 +525,17 @@ export function newIamPolicyGrantPath(
|
|
|
226
525
|
...asResource.filter((policy) => !isOwner(policy)),
|
|
227
526
|
...asResource.filter(isOwner),
|
|
228
527
|
])) {
|
|
229
|
-
await revokeRow(policy);
|
|
528
|
+
await revokeRow(policy, change, organizationOf);
|
|
230
529
|
}
|
|
231
530
|
},
|
|
232
531
|
|
|
233
|
-
async revokeOrgAccess(
|
|
532
|
+
async revokeOrgAccess(
|
|
533
|
+
identityAccountId,
|
|
534
|
+
organizationId,
|
|
535
|
+
caller,
|
|
536
|
+
): Promise<void> {
|
|
537
|
+
const actor = policyActorOf(caller);
|
|
538
|
+
const change: Change = { actor, cause: "organization_access_revoked" };
|
|
234
539
|
const direct = await policies.findByPrincipalAndResource(
|
|
235
540
|
kindEnumName(ApiResourceKind.identity_account),
|
|
236
541
|
identityAccountId,
|
|
@@ -238,8 +543,9 @@ export function newIamPolicyGrantPath(
|
|
|
238
543
|
organizationId,
|
|
239
544
|
);
|
|
240
545
|
for (const policy of direct) {
|
|
241
|
-
await revokeRow(policy);
|
|
546
|
+
await revokeRow(policy, change);
|
|
242
547
|
}
|
|
548
|
+
await sweepOrganization(identityAccountId, organizationId, actor);
|
|
243
549
|
},
|
|
244
550
|
};
|
|
245
551
|
}
|
|
@@ -271,8 +577,16 @@ function distinctById(
|
|
|
271
577
|
});
|
|
272
578
|
}
|
|
273
579
|
|
|
274
|
-
/**
|
|
275
|
-
|
|
580
|
+
/**
|
|
581
|
+
* The structured fields every log line carries — ids, kinds, who and why,
|
|
582
|
+
* never a token; the organization when the row is an access row.
|
|
583
|
+
*/
|
|
584
|
+
function fieldsOf(
|
|
585
|
+
id: string,
|
|
586
|
+
spec: IamPolicySpec,
|
|
587
|
+
change: Change,
|
|
588
|
+
record: PolicyChangeRecord | undefined,
|
|
589
|
+
): Record<string, string> {
|
|
276
590
|
return {
|
|
277
591
|
policyId: id,
|
|
278
592
|
relation: spec.relation,
|
|
@@ -280,5 +594,9 @@ function fieldsOf(id: string, spec: IamPolicySpec): Record<string, string> {
|
|
|
280
594
|
principalId: spec.principal?.id ?? "",
|
|
281
595
|
resourceKind: spec.resource?.kind ?? "",
|
|
282
596
|
resourceId: spec.resource?.id ?? "",
|
|
597
|
+
actorId: change.actor.id,
|
|
598
|
+
actorClass: change.actor.callerClass,
|
|
599
|
+
cause: change.cause,
|
|
600
|
+
...(record === undefined ? {} : { organizationId: record.organizationId }),
|
|
283
601
|
};
|
|
284
602
|
}
|
|
@@ -59,8 +59,9 @@
|
|
|
59
59
|
* one of them would be an outsider on every organization with nobody
|
|
60
60
|
* able to grant a way back. At the first boot where the bootstrap-state
|
|
61
61
|
* marker (ROLES_RECONCILED_KEY) is absent, the arms above run for every
|
|
62
|
-
* PERSON account (`isPersonAccount`: not a machine
|
|
63
|
-
* level twin of the `user`-class gate),
|
|
62
|
+
* PERSON account (`isPersonAccount`: not a machine, platform-client or
|
|
63
|
+
* federated account, the row-level twin of the `user`-class gate),
|
|
64
|
+
* acting as that account, in
|
|
64
65
|
* creation order — the order the sign-ins would have run the hook in,
|
|
65
66
|
* so arm 4 hands an unclaimed organization to its first sign-in and
|
|
66
67
|
* not to whoever sorts first by id — and the marker is written after
|
|
@@ -131,6 +132,7 @@ import type { Store } from "../../store/interface.js";
|
|
|
131
132
|
import { rfc3339Seconds } from "../../store/rfc3339.js";
|
|
132
133
|
import { accountAsCaller } from "../identityaccount/actor.js";
|
|
133
134
|
import type { AccountCreatedHook } from "../identityaccount/provisioning.js";
|
|
135
|
+
import type { PolicyChangeCause } from "./change.js";
|
|
134
136
|
import { BLUEPRINT_KINDS, ROLES_RECONCILED_KEY } from "./constants.js";
|
|
135
137
|
import type { IamPolicyGrantPath } from "./grant-path.js";
|
|
136
138
|
import { organizationRole, relationOf } from "./specs.js";
|
|
@@ -200,7 +202,14 @@ export function isPersonStamp(stamp: string): boolean {
|
|
|
200
202
|
* it exactly its client's auto-grant role on the owning organization and
|
|
201
203
|
* never runs these rules, and the reconciliation must not either, or every
|
|
202
204
|
* product user would become a member of every organization (and the
|
|
203
|
-
* operator-email arm would read an email the platform asserted).
|
|
205
|
+
* operator-email arm would read an email the platform asserted). Nor does a
|
|
206
|
+
* federated account, for the same reason at every arm: its subject and its
|
|
207
|
+
* email are the ones an organization's identity provider asserted, so the
|
|
208
|
+
* alias rule would read a subject the provider chose as a founder's stamp
|
|
209
|
+
* (`owner`), the operator-email arm an email it chose (`admin`), and arm 5
|
|
210
|
+
* would make it a member of every organization. A federated person's roles
|
|
211
|
+
* come from their provider's configuration and the organization's
|
|
212
|
+
* administrators, never from these rules.
|
|
204
213
|
*/
|
|
205
214
|
export function isPersonAccount(account: IdentityAccount): boolean {
|
|
206
215
|
const spec = account.spec;
|
|
@@ -208,7 +217,8 @@ export function isPersonAccount(account: IdentityAccount): boolean {
|
|
|
208
217
|
spec !== undefined &&
|
|
209
218
|
!spec.isMachineAccount &&
|
|
210
219
|
spec.provisioningMode !== IdentityAccountProvisioningMode.machine &&
|
|
211
|
-
spec.provisioningMode !== IdentityAccountProvisioningMode.platform_client
|
|
220
|
+
spec.provisioningMode !== IdentityAccountProvisioningMode.platform_client &&
|
|
221
|
+
spec.provisioningMode !== IdentityAccountProvisioningMode.federated
|
|
212
222
|
);
|
|
213
223
|
}
|
|
214
224
|
|
|
@@ -331,14 +341,15 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
|
|
|
331
341
|
|
|
332
342
|
/**
|
|
333
343
|
* The arms for ONE account over a scanned world: a row on every
|
|
334
|
-
* organization the account holds none on, granted as `caller
|
|
335
|
-
* by the hook (one account, the world scanned for
|
|
336
|
-
* reconciliation (the world scanned once for every account).
|
|
344
|
+
* organization the account holds none on, granted as `caller` through
|
|
345
|
+
* `cause`'s door. Shared by the hook (one account, the world scanned for
|
|
346
|
+
* it) and the reconciliation (the world scanned once for every account).
|
|
337
347
|
*/
|
|
338
348
|
async function applyRulesTo(
|
|
339
349
|
account: IdentityAccount,
|
|
340
350
|
caller: CallerIdentity,
|
|
341
351
|
world: ScannedWorld,
|
|
352
|
+
cause: PolicyChangeCause,
|
|
342
353
|
): Promise<void> {
|
|
343
354
|
const accountId = account.metadata?.id ?? "";
|
|
344
355
|
if (accountId === "") {
|
|
@@ -369,6 +380,7 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
|
|
|
369
380
|
await grantPath.grant(
|
|
370
381
|
organizationRole(accountId, role, organization.id),
|
|
371
382
|
caller,
|
|
383
|
+
cause,
|
|
372
384
|
);
|
|
373
385
|
}
|
|
374
386
|
}
|
|
@@ -402,10 +414,12 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
|
|
|
402
414
|
if (organizations.length === 0) {
|
|
403
415
|
return;
|
|
404
416
|
}
|
|
405
|
-
await applyRulesTo(
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
417
|
+
await applyRulesTo(
|
|
418
|
+
account,
|
|
419
|
+
caller,
|
|
420
|
+
{ organizations, blueprints: await scanBlueprints() },
|
|
421
|
+
"first_sign_in",
|
|
422
|
+
);
|
|
409
423
|
},
|
|
410
424
|
|
|
411
425
|
async ensureRolesForExistingAccounts(): Promise<void> {
|
|
@@ -419,7 +433,12 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
|
|
|
419
433
|
// As the account itself (actor.ts, the one construction), so the
|
|
420
434
|
// row's audit actor reads exactly as the person's own first
|
|
421
435
|
// sign-in would have stamped it.
|
|
422
|
-
await applyRulesTo(
|
|
436
|
+
await applyRulesTo(
|
|
437
|
+
account,
|
|
438
|
+
accountAsCaller(account),
|
|
439
|
+
world,
|
|
440
|
+
"role_reconciliation",
|
|
441
|
+
);
|
|
423
442
|
}
|
|
424
443
|
}
|
|
425
444
|
// After the last account, never before: a fault above leaves the
|
|
@@ -452,6 +471,7 @@ export function newMembershipRules(deps: MembershipRulesDeps): MembershipRules {
|
|
|
452
471
|
await grantPath.grant(
|
|
453
472
|
organizationRole(accountId, IamRole.owner, organization.id),
|
|
454
473
|
actor,
|
|
474
|
+
"operator_ownership",
|
|
455
475
|
);
|
|
456
476
|
}
|
|
457
477
|
},
|
|
@@ -32,6 +32,10 @@
|
|
|
32
32
|
* way). Conditional store writes are a platform-wide follow-up, not this
|
|
33
33
|
* adapter's to invent.
|
|
34
34
|
*
|
|
35
|
+
* History. Open source keeps no permission history: the change record the
|
|
36
|
+
* grant path hands `save` and `deleteById` (store.ts) is not read here, and
|
|
37
|
+
* the same facts ride the grant path's log lines.
|
|
38
|
+
*
|
|
35
39
|
* Store faults follow the ratified mapping (domain/apikey/lookup.ts): a
|
|
36
40
|
* typed ResourceNotFoundError reads as `undefined`; anything else
|
|
37
41
|
* propagates — an outage must never read as "no grant".
|
|
@@ -109,6 +109,7 @@ export function newBuiltInRoleLifecycle(
|
|
|
109
109
|
await grantPath.grant(
|
|
110
110
|
organizationRole(accountId, IamRole.owner, event.resourceId),
|
|
111
111
|
{ ...event.caller, identityId: accountId },
|
|
112
|
+
"organization_created",
|
|
112
113
|
);
|
|
113
114
|
},
|
|
114
115
|
|
|
@@ -121,6 +122,7 @@ export function newBuiltInRoleLifecycle(
|
|
|
121
122
|
kind: kindEnumName(event.kind),
|
|
122
123
|
id: event.resourceId,
|
|
123
124
|
}),
|
|
125
|
+
event.caller,
|
|
124
126
|
);
|
|
125
127
|
},
|
|
126
128
|
|
|
@@ -60,6 +60,14 @@ const ROLE_DISPLAY: ReadonlyArray<RoleDisplay> = [
|
|
|
60
60
|
description:
|
|
61
61
|
"Reply to customers and manage conversation takeover on a channel",
|
|
62
62
|
},
|
|
63
|
+
// Grantable per resource on agent, workflow and mcp_server; omitting it
|
|
64
|
+
// would hide every editor from the resource's access listing.
|
|
65
|
+
{
|
|
66
|
+
role: IamRole.editor,
|
|
67
|
+
name: "Editor",
|
|
68
|
+
description:
|
|
69
|
+
"Edit and run the resource; cannot delete it or change who has access",
|
|
70
|
+
},
|
|
63
71
|
];
|
|
64
72
|
|
|
65
73
|
const RELATION_TO_DISPLAY: ReadonlyMap<string, RoleDisplay> = new Map(
|