@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
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins the trusted-local Authorizer arm by arm: a check on an Organization
|
|
3
|
+
* the store does not hold is `not-found` (the answer the built-in
|
|
4
|
+
* authorizer's arm 4 and the cloud's deny-path probe give, so a server
|
|
5
|
+
* without sign-in refuses a phantom write with the same sentence as one
|
|
6
|
+
* with it, stigmer#1163), on both store drivers; a stored Organization is
|
|
7
|
+
* `allow`; every other check is `allow` without touching the store (the
|
|
8
|
+
* laptop separates no callers); an empty target id is `allow`, never
|
|
9
|
+
* `not-found`, because the Authorize step maps a not-found on an empty id
|
|
10
|
+
* to INTERNAL; and a store fault is `unavailable` with its cause, never a
|
|
11
|
+
* denial, a not-found or a throw.
|
|
12
|
+
*/
|
|
13
|
+
import { create } from "@bufbuild/protobuf";
|
|
14
|
+
import { afterAll, afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
15
|
+
|
|
16
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
17
|
+
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
18
|
+
import { OrganizationSchema } from "@stigmer/protos/ai/stigmer/tenancy/organization/v1/api_pb";
|
|
19
|
+
|
|
20
|
+
import type { AuthzCheck } from "../../extensions/authorizer.js";
|
|
21
|
+
import type { CallerIdentity } from "../../extensions/identity.js";
|
|
22
|
+
import { newTrustedLocalAuthorizer } from "../trusted-local-authorizer.js";
|
|
23
|
+
import type { TrustedLocalAuthorizerStore } from "../trusted-local-authorizer.js";
|
|
24
|
+
import { driverFixtures, dropPostgresFixture } from "./drivers.js";
|
|
25
|
+
import type { OpenedStore } from "./drivers.js";
|
|
26
|
+
|
|
27
|
+
/** The trusted-local identity: the operator's email, no token (pipeline/interceptors/auth.ts). */
|
|
28
|
+
const OPERATOR: CallerIdentity = {
|
|
29
|
+
identityId: "operator@example.com",
|
|
30
|
+
callerClass: "user",
|
|
31
|
+
issuer: "",
|
|
32
|
+
rawToken: "",
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function onOrganization(id: string, permission: IamPermission): AuthzCheck {
|
|
36
|
+
return {
|
|
37
|
+
permission,
|
|
38
|
+
resourceKind: ApiResourceKind.organization,
|
|
39
|
+
resourceId: id,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** A store whose every read is counted and fails: `fault`, or a sentinel no arm may reach. */
|
|
44
|
+
function countingStore(fault?: Error): {
|
|
45
|
+
readonly store: TrustedLocalAuthorizerStore;
|
|
46
|
+
reads(): number;
|
|
47
|
+
} {
|
|
48
|
+
let reads = 0;
|
|
49
|
+
return {
|
|
50
|
+
store: {
|
|
51
|
+
getResource() {
|
|
52
|
+
reads += 1;
|
|
53
|
+
return Promise.reject(fault ?? new Error("the store must not be read"));
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
reads: () => reads,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
afterAll(dropPostgresFixture);
|
|
61
|
+
|
|
62
|
+
describe.each(driverFixtures([ApiResourceKind.organization]))(
|
|
63
|
+
"trusted-local authorizer over $name",
|
|
64
|
+
(fixture) => {
|
|
65
|
+
describe.skipIf(fixture.skip)("authorize", () => {
|
|
66
|
+
let opened: OpenedStore;
|
|
67
|
+
|
|
68
|
+
beforeEach(async () => {
|
|
69
|
+
opened = await fixture.open();
|
|
70
|
+
await opened.store.saveResource(
|
|
71
|
+
ApiResourceKind.organization,
|
|
72
|
+
"acme",
|
|
73
|
+
OrganizationSchema,
|
|
74
|
+
create(OrganizationSchema, {
|
|
75
|
+
apiVersion: "tenancy.stigmer.ai/v1",
|
|
76
|
+
kind: "Organization",
|
|
77
|
+
metadata: { id: "acme", name: "Acme", slug: "acme" },
|
|
78
|
+
}),
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
afterEach(async () => {
|
|
83
|
+
await opened.close();
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("a check on an Organization the store does not hold is not-found, whatever the permission", async () => {
|
|
87
|
+
const authorizer = newTrustedLocalAuthorizer({ store: opened.store });
|
|
88
|
+
for (const permission of [
|
|
89
|
+
IamPermission.can_create_agent,
|
|
90
|
+
IamPermission.can_view,
|
|
91
|
+
IamPermission.can_grant_access,
|
|
92
|
+
]) {
|
|
93
|
+
expect(
|
|
94
|
+
await authorizer.authorize(
|
|
95
|
+
OPERATOR,
|
|
96
|
+
onOrganization("stigmer", permission),
|
|
97
|
+
),
|
|
98
|
+
).toEqual({ kind: "not-found" });
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it("a check on a stored Organization is allowed", async () => {
|
|
103
|
+
const authorizer = newTrustedLocalAuthorizer({ store: opened.store });
|
|
104
|
+
expect(
|
|
105
|
+
await authorizer.authorize(
|
|
106
|
+
OPERATOR,
|
|
107
|
+
onOrganization("acme", IamPermission.can_create_agent),
|
|
108
|
+
),
|
|
109
|
+
).toEqual({ kind: "allow" });
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
},
|
|
113
|
+
);
|
|
114
|
+
|
|
115
|
+
describe("trusted-local authorizer, the arms that never read", () => {
|
|
116
|
+
it.each([
|
|
117
|
+
[
|
|
118
|
+
"an Organization check with an empty id (a platform-scoped write)",
|
|
119
|
+
onOrganization("", IamPermission.can_create_agent),
|
|
120
|
+
],
|
|
121
|
+
[
|
|
122
|
+
"a check on another kind, even one whose row does not exist",
|
|
123
|
+
{
|
|
124
|
+
permission: IamPermission.can_edit,
|
|
125
|
+
resourceKind: ApiResourceKind.agent,
|
|
126
|
+
resourceId: "agt_does_not_exist",
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
[
|
|
130
|
+
"a check on the rowless platform",
|
|
131
|
+
{
|
|
132
|
+
permission: IamPermission.can_manage_plans,
|
|
133
|
+
resourceKind: ApiResourceKind.platform,
|
|
134
|
+
resourceId: "stigmer",
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
] as const)("%s is allowed without a read", async (_name, check) => {
|
|
138
|
+
const counted = countingStore();
|
|
139
|
+
const decision = await newTrustedLocalAuthorizer({
|
|
140
|
+
store: counted.store,
|
|
141
|
+
}).authorize(OPERATOR, check);
|
|
142
|
+
expect(decision).toEqual({ kind: "allow" });
|
|
143
|
+
expect(counted.reads()).toBe(0);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("a store fault on the Organization read is unavailable with its cause, read once", async () => {
|
|
147
|
+
const fault = new Error("database is locked");
|
|
148
|
+
const counted = countingStore(fault);
|
|
149
|
+
const decision = await newTrustedLocalAuthorizer({
|
|
150
|
+
store: counted.store,
|
|
151
|
+
}).authorize(OPERATOR, onOrganization("acme", IamPermission.can_view));
|
|
152
|
+
expect(decision).toEqual({ kind: "unavailable", cause: fault });
|
|
153
|
+
expect(counted.reads()).toBe(1);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pins open source's own authorization over the kinds a unit keeps in a
|
|
3
|
+
* store of its own, on both store drivers: the rows of an identity
|
|
4
|
+
* provider and a team live only behind a registered row reader
|
|
5
|
+
* (extensions/resource-row-reader.ts), never in the generic Store, and
|
|
6
|
+
* every answer below needs them.
|
|
7
|
+
*
|
|
8
|
+
* - The derived source reads a team through its reader, so a grant to
|
|
9
|
+
* the team reaches its member and nobody who left the organization.
|
|
10
|
+
* - The built-in Authorizer at edition `enterprise` answers the
|
|
11
|
+
* provider's and the team's checks from the model; a missing
|
|
12
|
+
* provider, invitation or team, and the rowless platform, are
|
|
13
|
+
* denials with the annotation's copy, never not-found, the cloud's
|
|
14
|
+
* answer for the same kinds (NOT_FOUND_EXEMPT_KINDS).
|
|
15
|
+
* - The built-in policy check (policy-check.ts) answers the unit's
|
|
16
|
+
* three structural questions: whether a resource is an
|
|
17
|
+
* organization's, whether a person views an organization, and
|
|
18
|
+
* whether an account id could still grant access on it; contextual
|
|
19
|
+
* policies and userset principals are refused.
|
|
20
|
+
* - `kindsWithoutRows` names each served kind the built-in posture could
|
|
21
|
+
* not read, which is what refuses such a boot (compose.ts).
|
|
22
|
+
*/
|
|
23
|
+
import { create } from "@bufbuild/protobuf";
|
|
24
|
+
import type { Message } from "@bufbuild/protobuf";
|
|
25
|
+
import { afterAll, afterEach, beforeEach, describe, expect, it } from "vitest";
|
|
26
|
+
|
|
27
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
28
|
+
import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apiresource/enum_pb";
|
|
29
|
+
import { IamPolicySchema } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/api_pb";
|
|
30
|
+
import { IamPermission } from "@stigmer/protos/ai/stigmer/iam/v1/enum_pb";
|
|
31
|
+
import { ServerEdition } from "@stigmer/protos/ai/stigmer/platform/v1/server_info_pb";
|
|
32
|
+
|
|
33
|
+
import { createLogger } from "../../boot/logger.js";
|
|
34
|
+
import {
|
|
35
|
+
IAM_POLICY_API_VERSION,
|
|
36
|
+
IAM_POLICY_KIND,
|
|
37
|
+
policyIdFor,
|
|
38
|
+
} from "../../domain/iampolicy/constants.js";
|
|
39
|
+
import { newResourceIamPolicyStore } from "../../domain/iampolicy/resource-store.js";
|
|
40
|
+
import type { IamPolicyStore } from "../../domain/iampolicy/store.js";
|
|
41
|
+
import { orgRole, triple } from "../../domain/iampolicy/__tests__/support.js";
|
|
42
|
+
import { newResourceIdentityAccountStore } from "../../domain/identityaccount/resource-store.js";
|
|
43
|
+
import type { IdentityAccountStore } from "../../domain/identityaccount/store.js";
|
|
44
|
+
import type { CallerIdentity } from "../../extensions/identity.js";
|
|
45
|
+
import type { ResourceRowReader } from "../../extensions/resource-row-reader.js";
|
|
46
|
+
import { newBuiltInAuthorizer } from "../authorizer.js";
|
|
47
|
+
import { newDerivedTupleSource } from "../derived-tuples.js";
|
|
48
|
+
import { checkRelation } from "../evaluator.js";
|
|
49
|
+
import { builtInModel } from "../model/index.js";
|
|
50
|
+
import { newBuiltInPolicyCheck } from "../policy-check.js";
|
|
51
|
+
import { kindsWithoutRows } from "../posture.js";
|
|
52
|
+
import type { Person } from "../tuples.js";
|
|
53
|
+
import { parseObjectRef } from "../tuples.js";
|
|
54
|
+
import { driverFixtures, dropPostgresFixture } from "./drivers.js";
|
|
55
|
+
import type { OpenedStore } from "./drivers.js";
|
|
56
|
+
import { fixtureRow, storedDeclaration } from "./support.js";
|
|
57
|
+
|
|
58
|
+
const silentLogger = createLogger({
|
|
59
|
+
level: "error",
|
|
60
|
+
pretty: false,
|
|
61
|
+
write: () => {},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
const ROOT = "ida_root"; // owner of acme
|
|
65
|
+
const ADMIN = "ida_admin"; // admin of acme
|
|
66
|
+
const DAVE = "ida_dave"; // member of acme, member of tm_core
|
|
67
|
+
const ERIN = "ida_erin"; // member of tm_core, no role on acme (she left)
|
|
68
|
+
|
|
69
|
+
function personOf(accountId: string): Person {
|
|
70
|
+
return { accountId, aliases: new Set([accountId]) };
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function caller(accountId: string): CallerIdentity {
|
|
74
|
+
return {
|
|
75
|
+
identityId: accountId,
|
|
76
|
+
callerClass: "user",
|
|
77
|
+
issuer: "https://issuer.example",
|
|
78
|
+
rawToken: "opaque",
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/** A reader over rows held in memory, recording every id it is asked for. */
|
|
83
|
+
function memoryReader(rows: ReadonlyArray<[string, Message]>): {
|
|
84
|
+
readonly reader: ResourceRowReader;
|
|
85
|
+
readonly asked: string[];
|
|
86
|
+
} {
|
|
87
|
+
const byId = new Map(rows);
|
|
88
|
+
const asked: string[] = [];
|
|
89
|
+
return {
|
|
90
|
+
asked,
|
|
91
|
+
reader: {
|
|
92
|
+
findById(id) {
|
|
93
|
+
asked.push(id);
|
|
94
|
+
return Promise.resolve(byId.get(id));
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
async function grant(
|
|
101
|
+
policies: IamPolicyStore,
|
|
102
|
+
spec: ReturnType<typeof orgRole>,
|
|
103
|
+
): Promise<void> {
|
|
104
|
+
await policies.save(
|
|
105
|
+
create(IamPolicySchema, {
|
|
106
|
+
apiVersion: IAM_POLICY_API_VERSION,
|
|
107
|
+
kind: IAM_POLICY_KIND,
|
|
108
|
+
metadata: { id: policyIdFor(spec) },
|
|
109
|
+
spec,
|
|
110
|
+
}),
|
|
111
|
+
);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
const SEEDED_KINDS: ReadonlyArray<ApiResourceKind> = [
|
|
115
|
+
ApiResourceKind.iam_policy,
|
|
116
|
+
ApiResourceKind.identity_account,
|
|
117
|
+
ApiResourceKind.organization,
|
|
118
|
+
ApiResourceKind.agent,
|
|
119
|
+
];
|
|
120
|
+
|
|
121
|
+
afterAll(dropPostgresFixture);
|
|
122
|
+
|
|
123
|
+
describe.each(driverFixtures(SEEDED_KINDS))(
|
|
124
|
+
"kinds a unit keeps itself, on $name",
|
|
125
|
+
(fixture) => {
|
|
126
|
+
describe.skipIf(fixture.skip)("through their row readers", () => {
|
|
127
|
+
let opened: OpenedStore;
|
|
128
|
+
let policies: IamPolicyStore;
|
|
129
|
+
let accounts: IdentityAccountStore;
|
|
130
|
+
let teams: ReturnType<typeof memoryReader>;
|
|
131
|
+
let providers: ReturnType<typeof memoryReader>;
|
|
132
|
+
let readers: ReadonlyMap<ApiResourceKind, ResourceRowReader>;
|
|
133
|
+
|
|
134
|
+
beforeEach(async () => {
|
|
135
|
+
opened = await fixture.open();
|
|
136
|
+
policies = newResourceIamPolicyStore(opened.store);
|
|
137
|
+
accounts = newResourceIdentityAccountStore(opened.store);
|
|
138
|
+
const organization = storedDeclaration("organization");
|
|
139
|
+
for (const id of ["acme", "globex"]) {
|
|
140
|
+
await opened.store.saveResource(
|
|
141
|
+
ApiResourceKind.organization,
|
|
142
|
+
id,
|
|
143
|
+
organization.schema,
|
|
144
|
+
fixtureRow(organization, {
|
|
145
|
+
id,
|
|
146
|
+
org: "",
|
|
147
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
148
|
+
createdBy: ROOT,
|
|
149
|
+
}),
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
const agent = storedDeclaration("agent");
|
|
153
|
+
await opened.store.saveResource(
|
|
154
|
+
ApiResourceKind.agent,
|
|
155
|
+
"agt_core",
|
|
156
|
+
agent.schema,
|
|
157
|
+
fixtureRow(agent, {
|
|
158
|
+
id: "agt_core",
|
|
159
|
+
org: "acme",
|
|
160
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
161
|
+
createdBy: "ida_carol",
|
|
162
|
+
}),
|
|
163
|
+
);
|
|
164
|
+
// The unit's rows: in memory behind their readers, never in the
|
|
165
|
+
// generic Store, so every answer that needs them proves the read.
|
|
166
|
+
teams = memoryReader([
|
|
167
|
+
[
|
|
168
|
+
"tm_core",
|
|
169
|
+
fixtureRow(storedDeclaration("team"), {
|
|
170
|
+
id: "tm_core",
|
|
171
|
+
org: "acme",
|
|
172
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
173
|
+
createdBy: ROOT,
|
|
174
|
+
}),
|
|
175
|
+
],
|
|
176
|
+
]);
|
|
177
|
+
providers = memoryReader([
|
|
178
|
+
[
|
|
179
|
+
"idp_acme",
|
|
180
|
+
fixtureRow(storedDeclaration("identity_provider"), {
|
|
181
|
+
id: "idp_acme",
|
|
182
|
+
org: "acme",
|
|
183
|
+
visibility: ApiResourceVisibility.visibility_private,
|
|
184
|
+
createdBy: ADMIN,
|
|
185
|
+
}),
|
|
186
|
+
],
|
|
187
|
+
]);
|
|
188
|
+
readers = new Map([
|
|
189
|
+
[ApiResourceKind.team, teams.reader],
|
|
190
|
+
[ApiResourceKind.identity_provider, providers.reader],
|
|
191
|
+
[ApiResourceKind.invitation, memoryReader([]).reader],
|
|
192
|
+
]);
|
|
193
|
+
await grant(policies, orgRole(ROOT, "owner", "acme"));
|
|
194
|
+
await grant(policies, orgRole(ADMIN, "admin", "acme"));
|
|
195
|
+
await grant(policies, orgRole(DAVE, "member", "acme"));
|
|
196
|
+
for (const member of [DAVE, ERIN]) {
|
|
197
|
+
await grant(
|
|
198
|
+
policies,
|
|
199
|
+
triple({ kind: "identity_account", id: member }, "member", {
|
|
200
|
+
kind: "team",
|
|
201
|
+
id: "tm_core",
|
|
202
|
+
}),
|
|
203
|
+
);
|
|
204
|
+
}
|
|
205
|
+
await grant(
|
|
206
|
+
policies,
|
|
207
|
+
triple(
|
|
208
|
+
{ kind: "team", id: "tm_core", relation: "member" },
|
|
209
|
+
"viewer",
|
|
210
|
+
{
|
|
211
|
+
kind: "agent",
|
|
212
|
+
id: "agt_core",
|
|
213
|
+
},
|
|
214
|
+
),
|
|
215
|
+
);
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
afterEach(async () => {
|
|
219
|
+
await opened.close();
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
async function allowed(
|
|
223
|
+
accountId: string,
|
|
224
|
+
object: string,
|
|
225
|
+
relation: string,
|
|
226
|
+
): Promise<boolean> {
|
|
227
|
+
const person = personOf(accountId);
|
|
228
|
+
const source = newDerivedTupleSource(
|
|
229
|
+
{
|
|
230
|
+
store: opened.store,
|
|
231
|
+
policies,
|
|
232
|
+
accounts,
|
|
233
|
+
rowReaders: readers,
|
|
234
|
+
model: builtInModel,
|
|
235
|
+
},
|
|
236
|
+
person,
|
|
237
|
+
);
|
|
238
|
+
return checkRelation(
|
|
239
|
+
{ model: builtInModel, source },
|
|
240
|
+
parseObjectRef(object),
|
|
241
|
+
relation,
|
|
242
|
+
person,
|
|
243
|
+
);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
it("a grant to a team kept by a unit reaches its member through the team's reader, and not one who left the organization", async () => {
|
|
247
|
+
expect(await allowed(DAVE, "agent:agt_core", "can_view")).toBe(true);
|
|
248
|
+
expect(await allowed(ERIN, "agent:agt_core", "can_view")).toBe(false);
|
|
249
|
+
expect(teams.asked).toContain("tm_core");
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("without the reader the team's organization is unknown, so the grant reaches nobody", async () => {
|
|
253
|
+
readers = new Map();
|
|
254
|
+
expect(await allowed(DAVE, "agent:agt_core", "can_view")).toBe(false);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe("the built-in Authorizer at edition enterprise", () => {
|
|
258
|
+
function authorizer() {
|
|
259
|
+
return newBuiltInAuthorizer({
|
|
260
|
+
store: opened.store,
|
|
261
|
+
policies,
|
|
262
|
+
accounts,
|
|
263
|
+
rowReaders: readers,
|
|
264
|
+
edition: ServerEdition.enterprise,
|
|
265
|
+
logger: silentLogger,
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
it("answers an identity provider from the model over its reader's row: its organization's admin views it, a member does not", async () => {
|
|
270
|
+
const check = {
|
|
271
|
+
permission: IamPermission.can_view,
|
|
272
|
+
resourceKind: ApiResourceKind.identity_provider,
|
|
273
|
+
resourceId: "idp_acme",
|
|
274
|
+
};
|
|
275
|
+
expect(await authorizer().authorize(caller(ADMIN), check)).toEqual({
|
|
276
|
+
kind: "allow",
|
|
277
|
+
});
|
|
278
|
+
expect(await authorizer().authorize(caller(DAVE), check)).toEqual({
|
|
279
|
+
kind: "deny",
|
|
280
|
+
reason: "",
|
|
281
|
+
});
|
|
282
|
+
expect(providers.asked).toContain("idp_acme");
|
|
283
|
+
});
|
|
284
|
+
|
|
285
|
+
it("answers a team: a member of its organization views it, one who left does not", async () => {
|
|
286
|
+
const check = {
|
|
287
|
+
permission: IamPermission.can_view,
|
|
288
|
+
resourceKind: ApiResourceKind.team,
|
|
289
|
+
resourceId: "tm_core",
|
|
290
|
+
};
|
|
291
|
+
expect(await authorizer().authorize(caller(DAVE), check)).toEqual({
|
|
292
|
+
kind: "allow",
|
|
293
|
+
});
|
|
294
|
+
expect(await authorizer().authorize(caller(ERIN), check)).toEqual({
|
|
295
|
+
kind: "deny",
|
|
296
|
+
reason: "",
|
|
297
|
+
});
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it.each([
|
|
301
|
+
[ApiResourceKind.identity_provider, "idp_missing"],
|
|
302
|
+
[ApiResourceKind.invitation, "inv_missing"],
|
|
303
|
+
[ApiResourceKind.team, "tm_missing"],
|
|
304
|
+
[ApiResourceKind.platform, "stigmer"],
|
|
305
|
+
])(
|
|
306
|
+
"a missing %s row is a denial, never not-found, so its ids cannot be enumerated",
|
|
307
|
+
async (resourceKind, resourceId) => {
|
|
308
|
+
expect(
|
|
309
|
+
await authorizer().authorize(caller(ADMIN), {
|
|
310
|
+
permission: IamPermission.can_view,
|
|
311
|
+
resourceKind,
|
|
312
|
+
resourceId,
|
|
313
|
+
}),
|
|
314
|
+
).toEqual({ kind: "deny", reason: "" });
|
|
315
|
+
},
|
|
316
|
+
);
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
describe("the built-in policy check", () => {
|
|
320
|
+
function queries() {
|
|
321
|
+
return newBuiltInPolicyCheck({
|
|
322
|
+
store: opened.store,
|
|
323
|
+
policies,
|
|
324
|
+
accounts,
|
|
325
|
+
rowReaders: readers,
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
it("answers whether a resource is an organization's own, by the resource's derived link", async () => {
|
|
330
|
+
const onAgent = (org: string) =>
|
|
331
|
+
triple({ kind: "organization", id: org }, "organization", {
|
|
332
|
+
kind: "agent",
|
|
333
|
+
id: "agt_core",
|
|
334
|
+
});
|
|
335
|
+
expect(await queries().check(onAgent("acme"), [])).toBe(true);
|
|
336
|
+
expect(await queries().check(onAgent("globex"), [])).toBe(false);
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
it("answers whether a person views an organization", async () => {
|
|
340
|
+
const views = (accountId: string) =>
|
|
341
|
+
triple({ kind: "identity_account", id: accountId }, "viewer", {
|
|
342
|
+
kind: "organization",
|
|
343
|
+
id: "acme",
|
|
344
|
+
});
|
|
345
|
+
expect(await queries().check(views(DAVE), [])).toBe(true);
|
|
346
|
+
expect(await queries().check(views(ERIN), [])).toBe(false);
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
it("answers whether an account id, with no caller behind it, could still grant access", async () => {
|
|
350
|
+
const grants = (accountId: string) =>
|
|
351
|
+
triple(
|
|
352
|
+
{ kind: "identity_account", id: accountId },
|
|
353
|
+
"can_grant_access",
|
|
354
|
+
{ kind: "organization", id: "acme" },
|
|
355
|
+
);
|
|
356
|
+
expect(await queries().check(grants(ADMIN), [])).toBe(true);
|
|
357
|
+
expect(await queries().check(grants(DAVE), [])).toBe(false);
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
it("refuses contextual policies and a userset principal as programming errors", async () => {
|
|
361
|
+
const held = orgRole(DAVE, "viewer", "acme");
|
|
362
|
+
await expect(queries().check(held, [held])).rejects.toThrowError(
|
|
363
|
+
/contextual policies are not supported/,
|
|
364
|
+
);
|
|
365
|
+
await expect(
|
|
366
|
+
queries().check(
|
|
367
|
+
triple(
|
|
368
|
+
{ kind: "organization", id: "acme", relation: "member" },
|
|
369
|
+
"viewer",
|
|
370
|
+
{ kind: "agent", id: "agt_core" },
|
|
371
|
+
),
|
|
372
|
+
[],
|
|
373
|
+
),
|
|
374
|
+
).rejects.toThrowError(/takes a direct principal/);
|
|
375
|
+
});
|
|
376
|
+
});
|
|
377
|
+
});
|
|
378
|
+
},
|
|
379
|
+
);
|
|
380
|
+
|
|
381
|
+
describe("kindsWithoutRows", () => {
|
|
382
|
+
const reader: ResourceRowReader = {
|
|
383
|
+
findById: () => Promise.resolve(undefined),
|
|
384
|
+
};
|
|
385
|
+
const all = new Map([
|
|
386
|
+
[ApiResourceKind.identity_provider, reader],
|
|
387
|
+
[ApiResourceKind.invitation, reader],
|
|
388
|
+
[ApiResourceKind.team, reader],
|
|
389
|
+
]);
|
|
390
|
+
|
|
391
|
+
it("is empty for open source, which keeps every kind it serves itself", () => {
|
|
392
|
+
expect(
|
|
393
|
+
kindsWithoutRows({
|
|
394
|
+
edition: ServerEdition.oss,
|
|
395
|
+
model: builtInModel,
|
|
396
|
+
readers: new Map(),
|
|
397
|
+
}),
|
|
398
|
+
).toEqual([]);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
it("names every Enterprise kind with rows and no reader, and not the rowless platform", () => {
|
|
402
|
+
expect(
|
|
403
|
+
kindsWithoutRows({
|
|
404
|
+
edition: ServerEdition.enterprise,
|
|
405
|
+
model: builtInModel,
|
|
406
|
+
readers: new Map([[ApiResourceKind.invitation, reader]]),
|
|
407
|
+
}),
|
|
408
|
+
).toEqual([ApiResourceKind.identity_provider, ApiResourceKind.team]);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
it("is empty once each kind the edition serves has a reader", () => {
|
|
412
|
+
expect(
|
|
413
|
+
kindsWithoutRows({
|
|
414
|
+
edition: ServerEdition.enterprise,
|
|
415
|
+
model: builtInModel,
|
|
416
|
+
readers: all,
|
|
417
|
+
}),
|
|
418
|
+
).toEqual([]);
|
|
419
|
+
});
|
|
420
|
+
});
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* composition's own services are its own conformance suite's business;
|
|
11
11
|
* this one asks whether the model and the contract say the same thing.
|
|
12
12
|
*
|
|
13
|
-
*
|
|
13
|
+
* Three invariants:
|
|
14
14
|
* - every `rpc.config` annotation that names a static kind asks a
|
|
15
15
|
* permission that kind's type defines. A relation the type does not
|
|
16
16
|
* define answers `deny` in the built-in evaluator and a validation
|
|
@@ -19,7 +19,11 @@
|
|
|
19
19
|
* - the permission of every `resource_kind_path` lane (the IamPolicy
|
|
20
20
|
* lanes, whose kind is the request's) is defined on every kind whose
|
|
21
21
|
* `kind_meta` lists grantable roles, because each such kind is one the
|
|
22
|
-
* grant path admits
|
|
22
|
+
* grant path admits;
|
|
23
|
+
* - only the grant lanes ask `can_grant_access`. The self-check answers it
|
|
24
|
+
* false wherever the edition grants no roles on the kind, so an audience
|
|
25
|
+
* act that asked it would be hidden from its owner there; those ask
|
|
26
|
+
* `can_manage_audience`.
|
|
23
27
|
*
|
|
24
28
|
* Outside the pin, as in the annotation-completeness precedent: `is_public`
|
|
25
29
|
* and `is_skip_authorization` methods (their annotation is never
|
|
@@ -69,6 +73,18 @@ const KNOWN_GAPS: ReadonlyArray<string> = [
|
|
|
69
73
|
"the resource_kind_path lanes ask can_view_access on artifact",
|
|
70
74
|
];
|
|
71
75
|
|
|
76
|
+
/**
|
|
77
|
+
* The RPCs that write grants, the only ones that ask can_grant_access: the
|
|
78
|
+
* IamPolicy lanes and an invitation's create (which carries a role the
|
|
79
|
+
* redeem grants).
|
|
80
|
+
*/
|
|
81
|
+
const GRANT_LANES: ReadonlyArray<string> = [
|
|
82
|
+
"ai.stigmer.iam.iampolicy.v1.IamPolicyCommandController/create",
|
|
83
|
+
"ai.stigmer.iam.iampolicy.v1.IamPolicyCommandController/delete",
|
|
84
|
+
"ai.stigmer.iam.iampolicy.v1.IamPolicyCommandController/revokeOrgAccess",
|
|
85
|
+
"ai.stigmer.iam.invitation.v1.InvitationCommandController/create",
|
|
86
|
+
];
|
|
87
|
+
|
|
72
88
|
/** One annotated method: the question it asks the model. */
|
|
73
89
|
interface WireQuestion {
|
|
74
90
|
readonly method: string;
|
|
@@ -152,6 +168,19 @@ describe("the contract asks the model only what the model defines", () => {
|
|
|
152
168
|
expect(questions.some((q) => q.kindPath !== "")).toBe(true);
|
|
153
169
|
});
|
|
154
170
|
|
|
171
|
+
it("asks can_grant_access only on the grant lanes; every other change of who reaches a resource asks can_manage_audience", () => {
|
|
172
|
+
// The self-check answers can_grant_access false on every kind the
|
|
173
|
+
// edition grants no roles on (domain/iampolicy/controller.ts, its second
|
|
174
|
+
// arm), so a console gate that mirrors an RPC asking it hides the control
|
|
175
|
+
// from the owner wherever that holds (stigmer#1495). A new RPC that
|
|
176
|
+
// changes an audience without writing a grant asks can_manage_audience.
|
|
177
|
+
const grantLanes = annotated()
|
|
178
|
+
.filter((q) => q.permission === IamPermission[IamPermission.can_grant_access])
|
|
179
|
+
.map((q) => q.method)
|
|
180
|
+
.sort();
|
|
181
|
+
expect(grantLanes).toEqual(GRANT_LANES);
|
|
182
|
+
});
|
|
183
|
+
|
|
155
184
|
it("defines every relation the contract asks about, except the known gaps", () => {
|
|
156
185
|
const questions = annotated();
|
|
157
186
|
const gaps: string[] = [];
|