@stigmer/server 3.40.0 → 3.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +133 -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 +9 -4
- package/dist/domain/channelapp/controller.d.ts.map +1 -1
- package/dist/domain/channelapp/controller.js +19 -9
- 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 +154 -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 +35 -12
- 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 +41 -1
- 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
|
@@ -115,6 +115,7 @@ import {
|
|
|
115
115
|
teamQualifierMessage,
|
|
116
116
|
teamRoleNotGrantableMessage,
|
|
117
117
|
} from "./constants.js";
|
|
118
|
+
import type { PolicyChangeCause } from "./change.js";
|
|
118
119
|
import type { IamPolicyGrantPath } from "./grant-path.js";
|
|
119
120
|
import type { IamPolicyStore } from "./store.js";
|
|
120
121
|
import {
|
|
@@ -231,22 +232,27 @@ function requireTeamGrant(
|
|
|
231
232
|
}
|
|
232
233
|
}
|
|
233
234
|
|
|
234
|
-
/** Grant the spec as the chain's caller; the row (fresh or held) is the result. */
|
|
235
|
+
/** Grant the spec as the chain's caller, through the chain's door; the row (fresh or held) is the result. */
|
|
235
236
|
export function newGrantStep(
|
|
236
237
|
grantPath: IamPolicyGrantPath,
|
|
238
|
+
cause: PolicyChangeCause,
|
|
237
239
|
): PipelineStep<typeof IamPolicySpecSchema> {
|
|
238
240
|
return {
|
|
239
241
|
name: "Grant",
|
|
240
242
|
async execute(
|
|
241
243
|
ctx: RequestContext<typeof IamPolicySpecSchema>,
|
|
242
244
|
): Promise<void> {
|
|
243
|
-
const { policy } = await grantPath.grant(
|
|
245
|
+
const { policy } = await grantPath.grant(
|
|
246
|
+
ctx.input,
|
|
247
|
+
ctx.callerIdentity,
|
|
248
|
+
cause,
|
|
249
|
+
);
|
|
244
250
|
ctx.set(POLICY_RESULT_KEY, policy);
|
|
245
251
|
},
|
|
246
252
|
};
|
|
247
253
|
}
|
|
248
254
|
|
|
249
|
-
/** Revoke the spec's row; absent, the default instance is the result (Java's idempotent delete). */
|
|
255
|
+
/** Revoke the spec's row as the chain's caller; absent, the default instance is the result (Java's idempotent delete). */
|
|
250
256
|
export function newRevokeStep(
|
|
251
257
|
grantPath: IamPolicyGrantPath,
|
|
252
258
|
): PipelineStep<typeof IamPolicySpecSchema> {
|
|
@@ -255,7 +261,10 @@ export function newRevokeStep(
|
|
|
255
261
|
async execute(
|
|
256
262
|
ctx: RequestContext<typeof IamPolicySpecSchema>,
|
|
257
263
|
): Promise<void> {
|
|
258
|
-
const revoked = await grantPath.revokeBySpec(
|
|
264
|
+
const revoked = await grantPath.revokeBySpec(
|
|
265
|
+
ctx.input,
|
|
266
|
+
ctx.callerIdentity,
|
|
267
|
+
);
|
|
259
268
|
ctx.set(POLICY_RESULT_KEY, revoked ?? create(IamPolicySchema));
|
|
260
269
|
},
|
|
261
270
|
};
|
|
@@ -273,6 +282,7 @@ export function newRevokeOrgAccessStep(
|
|
|
273
282
|
return grantPath.revokeOrgAccess(
|
|
274
283
|
ctx.input.identityAccountId,
|
|
275
284
|
ctx.input.organizationId,
|
|
285
|
+
ctx.callerIdentity,
|
|
276
286
|
);
|
|
277
287
|
},
|
|
278
288
|
};
|
|
@@ -286,7 +296,7 @@ export function newCleanupResourceStep(
|
|
|
286
296
|
name: "CleanupResource",
|
|
287
297
|
execute(ctx: RequestContext<typeof ApiResourceRefSchema>): Promise<void> {
|
|
288
298
|
const ref: ApiResourceRef = ctx.input;
|
|
289
|
-
return grantPath.cleanupResource(ref);
|
|
299
|
+
return grantPath.cleanupResource(ref, ctx.callerIdentity);
|
|
290
300
|
},
|
|
291
301
|
};
|
|
292
302
|
}
|
|
@@ -18,7 +18,10 @@
|
|
|
18
18
|
*
|
|
19
19
|
* The corners A12 taught are cases from the start, not later additions:
|
|
20
20
|
* every relation on a pair; distinct principals, not rows; the scope-tuple
|
|
21
|
-
* exclusions verbatim; unknown-id delete a no-op; a held id refused.
|
|
21
|
+
* exclusions verbatim; unknown-id delete a no-op; a held id refused. A
|
|
22
|
+
* change record changes nothing about the row; what a store that keeps a
|
|
23
|
+
* history writes with it is that store's own test, since the port lets an
|
|
24
|
+
* implementation keep none.
|
|
22
25
|
*
|
|
23
26
|
* What the kit deliberately does not carry: open source's derived-id
|
|
24
27
|
* refusal and its primary-key read, the cloud's column layout and SQLSTATE
|
|
@@ -51,6 +54,7 @@ import type {
|
|
|
51
54
|
PortContractDeclaration,
|
|
52
55
|
PortContractFixture,
|
|
53
56
|
} from "../../store/port-contract.js";
|
|
57
|
+
import type { PolicyChangeRecord } from "./change.js";
|
|
54
58
|
import {
|
|
55
59
|
IAM_POLICY_API_VERSION,
|
|
56
60
|
IAM_POLICY_KIND,
|
|
@@ -378,6 +382,38 @@ const CASES: ReadonlyArray<PortContractDeclaration<IamPolicyStore>> = [
|
|
|
378
382
|
);
|
|
379
383
|
},
|
|
380
384
|
],
|
|
385
|
+
[
|
|
386
|
+
"a change record changes nothing about the row: save and deleteById behave as without one",
|
|
387
|
+
async ({ store }) => {
|
|
388
|
+
const record: PolicyChangeRecord = {
|
|
389
|
+
actor: { id: BOB, callerClass: "user" },
|
|
390
|
+
cause: "grant",
|
|
391
|
+
organizationId: "acme",
|
|
392
|
+
};
|
|
393
|
+
const policy = policyRow(orgRole(ALICE, "admin", "acme"));
|
|
394
|
+
await store.save(policy, record);
|
|
395
|
+
const found = await store.findById(idOf(policy));
|
|
396
|
+
assert.ok(
|
|
397
|
+
found !== undefined && equals(IamPolicySchema, found, policy),
|
|
398
|
+
"a policy saved with a record must read back exactly as saved",
|
|
399
|
+
);
|
|
400
|
+
await assert.rejects(
|
|
401
|
+
store.save(policyRow(orgRole(ALICE, "admin", "acme"), BOB), record),
|
|
402
|
+
DuplicatePolicyError,
|
|
403
|
+
"a held id with a record must still raise DuplicatePolicyError",
|
|
404
|
+
);
|
|
405
|
+
await store.deleteById(idOf(policy), { ...record, cause: "revoke" });
|
|
406
|
+
assert.equal(
|
|
407
|
+
await store.findById(idOf(policy)),
|
|
408
|
+
undefined,
|
|
409
|
+
"a policy deleted with a record must be gone",
|
|
410
|
+
);
|
|
411
|
+
await assert.doesNotReject(
|
|
412
|
+
store.deleteById(idOf(policy), { ...record, cause: "revoke" }),
|
|
413
|
+
"deleting an id that is not held, with a record, must resolve",
|
|
414
|
+
);
|
|
415
|
+
},
|
|
416
|
+
],
|
|
381
417
|
[
|
|
382
418
|
"deleteById of an unknown id resolves",
|
|
383
419
|
async ({ store }) => {
|
|
@@ -38,10 +38,24 @@
|
|
|
38
38
|
* editions' filters read alike);
|
|
39
39
|
* - a typed not-found reads as `undefined`; any other storage failure
|
|
40
40
|
* propagates as the infrastructure fault it is (the ratified
|
|
41
|
-
* store-fault mapping — an outage must never read as "no grant")
|
|
41
|
+
* store-fault mapping — an outage must never read as "no grant");
|
|
42
|
+
* - a change record (change.ts) never changes what happens to the row:
|
|
43
|
+
* `save` and `deleteById` behave identically with and without one.
|
|
44
|
+
*
|
|
45
|
+
* The change record. The grant path hands one to `save` and `deleteById`
|
|
46
|
+
* for every access row it writes or deletes. An implementation that keeps
|
|
47
|
+
* a permission history writes exactly one entry for it in the SAME atomic
|
|
48
|
+
* unit as the row change, and none when the row did not change: a held id
|
|
49
|
+
* raises DuplicatePolicyError before anything is written, and deleting an
|
|
50
|
+
* id that is not held records nothing. History equals the row changes
|
|
51
|
+
* exactly, with nothing to filter or heal. An implementation may keep no
|
|
52
|
+
* history and ignore the record; open source's adapter does. A driver
|
|
53
|
+
* written against the one-argument methods still satisfies this interface.
|
|
42
54
|
*/
|
|
43
55
|
import type { IamPolicy } from "@stigmer/protos/ai/stigmer/iam/iampolicy/v1/api_pb";
|
|
44
56
|
|
|
57
|
+
import type { PolicyChangeRecord } from "./change.js";
|
|
58
|
+
|
|
45
59
|
/**
|
|
46
60
|
* Raised by `save` when the id is already held, so the grant path runs its
|
|
47
61
|
* race arm (re-read the winner by triple; answer it as the duplicate).
|
|
@@ -56,10 +70,10 @@ export class DuplicatePolicyError extends Error {
|
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
export interface IamPolicyStore {
|
|
59
|
-
/** Insert; a held id raises DuplicatePolicyError. */
|
|
60
|
-
save(policy: IamPolicy): Promise<void>;
|
|
61
|
-
/** Removes the row; no error when it does not exist. */
|
|
62
|
-
deleteById(id: string): Promise<void>;
|
|
73
|
+
/** Insert; a held id raises DuplicatePolicyError. `record`: the change to keep, when the row grants access. */
|
|
74
|
+
save(policy: IamPolicy, record?: PolicyChangeRecord): Promise<void>;
|
|
75
|
+
/** Removes the row; no error when it does not exist. `record`: as for `save`, kept only when a row was removed. */
|
|
76
|
+
deleteById(id: string, record?: PolicyChangeRecord): Promise<void>;
|
|
63
77
|
findById(id: string): Promise<IamPolicy | undefined>;
|
|
64
78
|
/** Every row naming the principal — the cleanup's principal-side arm. */
|
|
65
79
|
findByPrincipal(
|
|
@@ -30,6 +30,35 @@
|
|
|
30
30
|
* - a caller whose credential names no subject (an opaque token) is
|
|
31
31
|
* `undefined` with NO second read — the store is never asked about "";
|
|
32
32
|
* - an idp-shaped caller with no account is `undefined`.
|
|
33
|
+
*
|
|
34
|
+
* And the question the API-key verifier asks of a stamp that resolved to
|
|
35
|
+
* nobody, `isPreSignInOperatorStamp` (stigmer/stigmer#1169): does it name
|
|
36
|
+
* the operator of the server's life before sign-in was turned on? Written
|
|
37
|
+
* failing before the export exists.
|
|
38
|
+
*
|
|
39
|
+
* - the `"system"` placeholder does, with no read (it is only ever the
|
|
40
|
+
* unconfigured laptop's operator);
|
|
41
|
+
* - an email with a `local|<email>` account in the store does;
|
|
42
|
+
* - an email with no such account does not (an issuer subject that
|
|
43
|
+
* happens to look like an email);
|
|
44
|
+
* - an account-id stamp and the empty stamp do not, with no read, so the
|
|
45
|
+
* common key costs the verifier nothing;
|
|
46
|
+
* - a store fault propagates as the same error.
|
|
47
|
+
*
|
|
48
|
+
* And provisionMyAccount's admission, `mayProvisionDirectAccount`: did the
|
|
49
|
+
* platform's own sign-in vouch for this caller? Over a store whose direct
|
|
50
|
+
* read answers no federated and no platform-client row, as the port says:
|
|
51
|
+
*
|
|
52
|
+
* - the trusted-local operator (no issuer, no token) is admitted;
|
|
53
|
+
* - an idp-shaped `user` caller (no account, identity = subject) is;
|
|
54
|
+
* - a caller that is already its subject's direct account is;
|
|
55
|
+
* - a caller whose account is a federated one is not, whether or not a
|
|
56
|
+
* platform person holds the direct account of the subject its token
|
|
57
|
+
* names: that subject is the provider's to choose;
|
|
58
|
+
* - a platform client's user is not, nor a system lane's token (its
|
|
59
|
+
* identity is its lane account, whose id no direct row carries as a
|
|
60
|
+
* subject), nor any caller that is not of class `user`, nor a
|
|
61
|
+
* credential naming no subject.
|
|
33
62
|
*/
|
|
34
63
|
import { create } from "@bufbuild/protobuf";
|
|
35
64
|
import { ConnectError } from "@connectrpc/connect";
|
|
@@ -40,8 +69,13 @@ import { IdentityAccountProvisioningMode } from "@stigmer/protos/ai/stigmer/iam/
|
|
|
40
69
|
|
|
41
70
|
import type { CallerIdentity } from "../../../extensions/identity.js";
|
|
42
71
|
import { accountIdFor, localIdpIdFor } from "../constants.js";
|
|
43
|
-
import {
|
|
44
|
-
|
|
72
|
+
import {
|
|
73
|
+
accountForCaller,
|
|
74
|
+
identityIdForSubject,
|
|
75
|
+
isPreSignInOperatorStamp,
|
|
76
|
+
mayProvisionDirectAccount,
|
|
77
|
+
} from "../resolve.js";
|
|
78
|
+
import type { AccountsByCaller, AccountsBySubject } from "../resolve.js";
|
|
45
79
|
import { fakeIdentityAccountStore } from "./support.js";
|
|
46
80
|
|
|
47
81
|
function seeded(sub: string, id: string = accountIdFor(sub)) {
|
|
@@ -223,3 +257,213 @@ describe("accountForCaller — the account a caller stands for", () => {
|
|
|
223
257
|
expect(account).toBeUndefined();
|
|
224
258
|
});
|
|
225
259
|
});
|
|
260
|
+
|
|
261
|
+
describe("isPreSignInOperatorStamp — a stamp from before sign-in was turned on (stigmer/stigmer#1169)", () => {
|
|
262
|
+
it('the "system" placeholder is the unconfigured laptop\'s operator, with no read', async () => {
|
|
263
|
+
const accounts = fakeIdentityAccountStore();
|
|
264
|
+
const bySubject = vi.spyOn(accounts, "findDirectByIdpId");
|
|
265
|
+
|
|
266
|
+
expect(await isPreSignInOperatorStamp(accounts, "system")).toBe(true);
|
|
267
|
+
expect(bySubject).not.toHaveBeenCalled();
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
it("an email with a local|<email> account is the configured operator's", async () => {
|
|
271
|
+
const accounts = seeded(localIdpIdFor("operator@example.com"));
|
|
272
|
+
const bySubject = vi.spyOn(accounts, "findDirectByIdpId");
|
|
273
|
+
|
|
274
|
+
expect(
|
|
275
|
+
await isPreSignInOperatorStamp(accounts, "operator@example.com"),
|
|
276
|
+
).toBe(true);
|
|
277
|
+
expect(bySubject).toHaveBeenCalledTimes(1);
|
|
278
|
+
expect(bySubject).toHaveBeenCalledWith(
|
|
279
|
+
localIdpIdFor("operator@example.com"),
|
|
280
|
+
);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it("an email with no local|<email> account is not — an issuer subject may look like one", async () => {
|
|
284
|
+
const accounts = seeded(localIdpIdFor("operator@example.com"));
|
|
285
|
+
|
|
286
|
+
expect(
|
|
287
|
+
await isPreSignInOperatorStamp(accounts, "someone@example.com"),
|
|
288
|
+
).toBe(false);
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
it("an account-id stamp and the empty stamp are not, and the store is never asked", async () => {
|
|
292
|
+
const accounts = seeded(localIdpIdFor("operator@example.com"));
|
|
293
|
+
const bySubject = vi.spyOn(accounts, "findDirectByIdpId");
|
|
294
|
+
|
|
295
|
+
expect(
|
|
296
|
+
await isPreSignInOperatorStamp(
|
|
297
|
+
accounts,
|
|
298
|
+
accountIdFor(localIdpIdFor("operator@example.com")),
|
|
299
|
+
),
|
|
300
|
+
).toBe(false);
|
|
301
|
+
expect(await isPreSignInOperatorStamp(accounts, "")).toBe(false);
|
|
302
|
+
expect(bySubject).not.toHaveBeenCalled();
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
it("a store fault propagates as the same error", async () => {
|
|
306
|
+
const fault = new Error("store is on fire");
|
|
307
|
+
const broken: AccountsBySubject = {
|
|
308
|
+
findDirectByIdpId: () => Promise.reject(fault),
|
|
309
|
+
};
|
|
310
|
+
await expect(
|
|
311
|
+
isPreSignInOperatorStamp(broken, "operator@example.com"),
|
|
312
|
+
).rejects.toBe(fault);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe("mayProvisionDirectAccount — provisionMyAccount's admission", () => {
|
|
317
|
+
const PERSON = "auth0|platform-person";
|
|
318
|
+
|
|
319
|
+
function row(
|
|
320
|
+
id: string,
|
|
321
|
+
idpId: string,
|
|
322
|
+
mode: IdentityAccountProvisioningMode,
|
|
323
|
+
) {
|
|
324
|
+
return create(IdentityAccountSchema, {
|
|
325
|
+
metadata: { id },
|
|
326
|
+
spec: { idpId, provisioningMode: mode },
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** The port's semantics: the direct read answers no federated and no platform-client row. */
|
|
331
|
+
function accountsOf(...rows: ReturnType<typeof row>[]): AccountsByCaller {
|
|
332
|
+
return {
|
|
333
|
+
findById: (id) =>
|
|
334
|
+
Promise.resolve(rows.find((r) => r.metadata?.id === id)),
|
|
335
|
+
findDirectByIdpId: (idpId) =>
|
|
336
|
+
Promise.resolve(
|
|
337
|
+
rows.find(
|
|
338
|
+
(r) =>
|
|
339
|
+
r.spec?.idpId === idpId &&
|
|
340
|
+
r.spec.provisioningMode !==
|
|
341
|
+
IdentityAccountProvisioningMode.federated &&
|
|
342
|
+
r.spec.provisioningMode !==
|
|
343
|
+
IdentityAccountProvisioningMode.platform_client,
|
|
344
|
+
),
|
|
345
|
+
),
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const direct = row(
|
|
350
|
+
accountIdFor(PERSON),
|
|
351
|
+
PERSON,
|
|
352
|
+
IdentityAccountProvisioningMode.direct,
|
|
353
|
+
);
|
|
354
|
+
const federated = row(
|
|
355
|
+
"ida_federated",
|
|
356
|
+
PERSON,
|
|
357
|
+
IdentityAccountProvisioningMode.federated,
|
|
358
|
+
);
|
|
359
|
+
const endUser = row(
|
|
360
|
+
accountIdFor("stgm_pc|acme|user-7"),
|
|
361
|
+
"stgm_pc|acme|user-7",
|
|
362
|
+
IdentityAccountProvisioningMode.platform_client,
|
|
363
|
+
);
|
|
364
|
+
const lane = row(
|
|
365
|
+
"ida_guestlane",
|
|
366
|
+
"stgm_guest|acme",
|
|
367
|
+
IdentityAccountProvisioningMode.identity_account_provisioning_mode_unspecified,
|
|
368
|
+
);
|
|
369
|
+
const token = (sub: string) => ({
|
|
370
|
+
issuer: "https://issuer.test",
|
|
371
|
+
rawToken: tokenFor(sub),
|
|
372
|
+
});
|
|
373
|
+
|
|
374
|
+
it.each([
|
|
375
|
+
[
|
|
376
|
+
"the trusted-local operator",
|
|
377
|
+
accountsOf(),
|
|
378
|
+
caller({ identityId: "operator@example.com" }),
|
|
379
|
+
localIdpIdFor("operator@example.com"),
|
|
380
|
+
],
|
|
381
|
+
[
|
|
382
|
+
"an idp-shaped person before their first provisioning",
|
|
383
|
+
accountsOf(),
|
|
384
|
+
caller({ identityId: PERSON, ...token(PERSON) }),
|
|
385
|
+
PERSON,
|
|
386
|
+
],
|
|
387
|
+
[
|
|
388
|
+
"a person who is already their subject's direct account",
|
|
389
|
+
accountsOf(direct),
|
|
390
|
+
caller({ identityId: direct.metadata!.id, ...token(PERSON) }),
|
|
391
|
+
PERSON,
|
|
392
|
+
],
|
|
393
|
+
])("admits %s", async (_name, accounts, who, subject) => {
|
|
394
|
+
expect(await mayProvisionDirectAccount(accounts, who, subject)).toBe(true);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
it.each([
|
|
398
|
+
[
|
|
399
|
+
"a federated account whose provider minted a platform person's subject",
|
|
400
|
+
accountsOf(direct, federated),
|
|
401
|
+
caller({ identityId: federated.metadata!.id, ...token(PERSON) }),
|
|
402
|
+
PERSON,
|
|
403
|
+
],
|
|
404
|
+
[
|
|
405
|
+
"a federated account whose subject no platform person holds",
|
|
406
|
+
accountsOf(federated),
|
|
407
|
+
caller({ identityId: federated.metadata!.id, ...token(PERSON) }),
|
|
408
|
+
PERSON,
|
|
409
|
+
],
|
|
410
|
+
[
|
|
411
|
+
"a platform client's user",
|
|
412
|
+
accountsOf(endUser),
|
|
413
|
+
caller({
|
|
414
|
+
identityId: endUser.metadata!.id,
|
|
415
|
+
...token("stgm_pc|acme|user-7"),
|
|
416
|
+
}),
|
|
417
|
+
"stgm_pc|acme|user-7",
|
|
418
|
+
],
|
|
419
|
+
[
|
|
420
|
+
"a system lane's token, whose subject is its lane account's id",
|
|
421
|
+
accountsOf(lane),
|
|
422
|
+
caller({
|
|
423
|
+
identityId: lane.metadata!.id,
|
|
424
|
+
callerClass: "user",
|
|
425
|
+
...token(lane.metadata!.id),
|
|
426
|
+
}),
|
|
427
|
+
lane.metadata!.id,
|
|
428
|
+
],
|
|
429
|
+
[
|
|
430
|
+
"a caller of another class, idp-shaped",
|
|
431
|
+
accountsOf(),
|
|
432
|
+
caller({
|
|
433
|
+
identityId: "stgm_channel|acme",
|
|
434
|
+
callerClass: "channel",
|
|
435
|
+
...token("stgm_channel|acme"),
|
|
436
|
+
}),
|
|
437
|
+
"stgm_channel|acme",
|
|
438
|
+
],
|
|
439
|
+
[
|
|
440
|
+
"an identity that is neither its subject nor an account",
|
|
441
|
+
accountsOf(),
|
|
442
|
+
caller({ identityId: "someone-else", ...token(PERSON) }),
|
|
443
|
+
PERSON,
|
|
444
|
+
],
|
|
445
|
+
[
|
|
446
|
+
"a credential naming no subject",
|
|
447
|
+
accountsOf(),
|
|
448
|
+
caller({ identityId: "", ...token("") }),
|
|
449
|
+
"",
|
|
450
|
+
],
|
|
451
|
+
])("refuses %s", async (_name, accounts, who, subject) => {
|
|
452
|
+
expect(await mayProvisionDirectAccount(accounts, who, subject)).toBe(false);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it("a store fault propagates as the same error", async () => {
|
|
456
|
+
const fault = new Error("store is on fire");
|
|
457
|
+
const broken: AccountsByCaller = {
|
|
458
|
+
findById: () => Promise.reject(fault),
|
|
459
|
+
findDirectByIdpId: () => Promise.reject(fault),
|
|
460
|
+
};
|
|
461
|
+
await expect(
|
|
462
|
+
mayProvisionDirectAccount(
|
|
463
|
+
broken,
|
|
464
|
+
caller({ identityId: PERSON, ...token(PERSON) }),
|
|
465
|
+
PERSON,
|
|
466
|
+
),
|
|
467
|
+
).rejects.toBe(fault);
|
|
468
|
+
});
|
|
469
|
+
});
|
|
@@ -53,7 +53,7 @@ const CONTRACT_CASE_NAMES = [
|
|
|
53
53
|
"findByIds answers the present ones in request order and skips the unknown",
|
|
54
54
|
"a disconnected store is an infrastructure fault, never 'not found'",
|
|
55
55
|
"two concurrent saves of one subject end in fulfilments and DuplicateAccountErrors only, and the winner is readable by subject",
|
|
56
|
-
"
|
|
56
|
+
"no subject lookup answers a federated account: its subject is its identity provider's",
|
|
57
57
|
"findDirectByIdpId and findDirectByEmail never answer a platform-client account, while findByIdpId (any mode) does",
|
|
58
58
|
"findByIds answers one row per distinct id, in first-occurrence order; an empty request answers an empty list",
|
|
59
59
|
"update of an unknown id is a no-op: no row appears",
|
|
@@ -49,6 +49,16 @@ export function accountIdFor(idpId: string): string {
|
|
|
49
49
|
return derivedId(ACCOUNT_ID_PREFIX, idpId);
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
/**
|
|
53
|
+
* Whether `id` has an account id's shape, `ida_<...>`: a derived id and a
|
|
54
|
+
* minted one share it (see the header). A shape test, not an existence
|
|
55
|
+
* check. Its one use is to skip a read that could only miss, since no
|
|
56
|
+
* account carries an account id as its subject (resolve.ts).
|
|
57
|
+
*/
|
|
58
|
+
export function isAccountIdShaped(id: string): boolean {
|
|
59
|
+
return id.startsWith(`${ACCOUNT_ID_PREFIX}_`);
|
|
60
|
+
}
|
|
61
|
+
|
|
52
62
|
/**
|
|
53
63
|
* The subject namespace of the trusted-local posture. An OIDC subject is
|
|
54
64
|
* `<connection>|<id>` by Auth0 convention; `local|` claims the same shape
|
|
@@ -142,6 +152,16 @@ export const ACCOUNT_NOT_FOUND_FOR_CALLER_MESSAGE =
|
|
|
142
152
|
export const NO_IDP_ID_MESSAGE =
|
|
143
153
|
"Cannot provision account: no IDP ID in authentication context";
|
|
144
154
|
|
|
155
|
+
/**
|
|
156
|
+
* provisionMyAccount for a caller the platform's own sign-in did not vouch
|
|
157
|
+
* for (PERMISSION_DENIED): a person of an organization's identity provider,
|
|
158
|
+
* a platform client's user, a system lane's token, or any caller that is
|
|
159
|
+
* not a person. Names no account: the refusal answers before the store is
|
|
160
|
+
* asked about the credential's subject.
|
|
161
|
+
*/
|
|
162
|
+
export const NOT_A_DIRECT_SIGN_IN_MESSAGE =
|
|
163
|
+
"Cannot provision account: this RPC provisions a person signing in through this platform's own sign-in, and another lane vouched for this credential";
|
|
164
|
+
|
|
145
165
|
/** provisionMyAccount when the issuer's userinfo cannot be read (UNAVAILABLE); the cause follows. */
|
|
146
166
|
export const USERINFO_UNAVAILABLE_PREFIX =
|
|
147
167
|
"Failed to fetch user profile from identity provider: ";
|
|
@@ -31,7 +31,9 @@
|
|
|
31
31
|
* unprovisioned), getByEmail and getByIdpId (lookup FIRST, then
|
|
32
32
|
* authorizeDirect on the FOUND id — the cloud's order; the annotation's
|
|
33
33
|
* `field_path = "value"` would otherwise hand the Authorizer an email as a
|
|
34
|
-
* resource id), getActorInfo, and provisionMyAccount (
|
|
34
|
+
* resource id), getActorInfo, and provisionMyAccount (PERMISSION_DENIED
|
|
35
|
+
* first for a caller the platform's own sign-in did not vouch for,
|
|
36
|
+
* resolve.ts `mayProvisionDirectAccount`; then the provisioner,
|
|
35
37
|
* then — on the call that CREATED the row — the core AccountCreatedHook
|
|
36
38
|
* (open source's membership rules, 20260913.01 slice 4), then the composed
|
|
37
39
|
* post-persist gates; UNAUTHENTICATED with the cloud's copy for a
|
|
@@ -101,6 +103,7 @@ import {
|
|
|
101
103
|
ACCOUNT_NOT_FOUND_FOR_CALLER_MESSAGE,
|
|
102
104
|
CREATE_IS_INTERNAL_MESSAGE,
|
|
103
105
|
NO_IDP_ID_MESSAGE,
|
|
106
|
+
NOT_A_DIRECT_SIGN_IN_MESSAGE,
|
|
104
107
|
USERINFO_UNAVAILABLE_PREFIX,
|
|
105
108
|
federationUnimplementedMessage,
|
|
106
109
|
idpIdOf,
|
|
@@ -113,7 +116,7 @@ import type {
|
|
|
113
116
|
DirectAccountProvisioner,
|
|
114
117
|
} from "./provisioning.js";
|
|
115
118
|
import { UserInfoFetchError } from "./provisioning.js";
|
|
116
|
-
import { accountForCaller } from "./resolve.js";
|
|
119
|
+
import { accountForCaller, mayProvisionDirectAccount } from "./resolve.js";
|
|
117
120
|
import {
|
|
118
121
|
accountNotFoundError,
|
|
119
122
|
newAssignBackendFieldsStep,
|
|
@@ -509,7 +512,7 @@ async function getByEmail(
|
|
|
509
512
|
);
|
|
510
513
|
}
|
|
511
514
|
|
|
512
|
-
/** getByIdpId — any provisioning mode; lookup first, authorize on the FOUND id. */
|
|
515
|
+
/** getByIdpId — any provisioning mode but federated (a federated subject is its provider's: getByExternalSub); lookup first, authorize on the FOUND id. */
|
|
513
516
|
async function getByIdpId(
|
|
514
517
|
deps: IdentityAccountControllerDeps,
|
|
515
518
|
idpId: IdpId,
|
|
@@ -548,8 +551,10 @@ async function lookupThenAuthorize(
|
|
|
548
551
|
// ---------------------------------------------------------------------------
|
|
549
552
|
|
|
550
553
|
/**
|
|
551
|
-
* provisionMyAccount — the subject from the caller's credential,
|
|
552
|
-
*
|
|
554
|
+
* provisionMyAccount — the subject from the caller's credential, admitted
|
|
555
|
+
* only for a caller the platform's own sign-in vouched for
|
|
556
|
+
* (`mayProvisionDirectAccount`), the provisioner's flow, then two
|
|
557
|
+
* post-persist consumers with the caller
|
|
553
558
|
* RE-STAMPED as the account: the position-1 identity was idp-shaped
|
|
554
559
|
* because no row existed when the verifier ran, and anything that
|
|
555
560
|
* attributes ownership must name the account, never a principal no later
|
|
@@ -582,6 +587,16 @@ async function provisionMyAccount(
|
|
|
582
587
|
if (idpId === "") {
|
|
583
588
|
throw new ConnectError(NO_IDP_ID_MESSAGE, Code.Unauthenticated);
|
|
584
589
|
}
|
|
590
|
+
// Before any read of the subject: a credential another lane vouched for
|
|
591
|
+
// names a subject that lane chose, and the direct account under it is a
|
|
592
|
+
// platform person's to hold, never that lane's to provision or read.
|
|
593
|
+
const admitted = await read(
|
|
594
|
+
() => mayProvisionDirectAccount(deps.accounts, caller, idpId),
|
|
595
|
+
"failed to resolve the caller's account",
|
|
596
|
+
);
|
|
597
|
+
if (!admitted) {
|
|
598
|
+
throw new ConnectError(NOT_A_DIRECT_SIGN_IN_MESSAGE, Code.PermissionDenied);
|
|
599
|
+
}
|
|
585
600
|
let account: IdentityAccount;
|
|
586
601
|
let created: boolean;
|
|
587
602
|
try {
|
|
@@ -54,11 +54,45 @@
|
|
|
54
54
|
* what "nobody" means (the fire caller's deterministic refusal, the
|
|
55
55
|
* verifier's liveness sentence), so this function answers `undefined`
|
|
56
56
|
* and never throws for it. The empty stamp is `undefined` with no read.
|
|
57
|
+
*
|
|
58
|
+
* The fourth reading asks of a stamp that named nobody whether it is the
|
|
59
|
+
* operator's from before sign-in was turned on:
|
|
60
|
+
* `isPreSignInOperatorStamp` (stigmer/stigmer#1169). Under the
|
|
61
|
+
* trusted-local posture every write is stamped with the operator's email,
|
|
62
|
+
* or with the "system" placeholder when no email is configured, and the
|
|
63
|
+
* operator's account carries the subject `local|<that stamp>`. After
|
|
64
|
+
* sign-in the operator signs in as a different account, one derived from
|
|
65
|
+
* the issuer's subject, which by construction never collides with a
|
|
66
|
+
* `local|` one (constants.ts). So such a stamp names a principal no
|
|
67
|
+
* signed-in person is. The API-key verifier asks this so it can refuse
|
|
68
|
+
* such a key by name instead of admitting a bare email. The answer is yes
|
|
69
|
+
* for "system" with no read, and for any other stamp when the store holds
|
|
70
|
+
* `local|<stamp>`, which is one direct-subject read. An account-id stamp
|
|
71
|
+
* and the empty stamp answer no with no read: the common key costs its
|
|
72
|
+
* verifier nothing.
|
|
73
|
+
*
|
|
74
|
+
* The fifth reading asks of a caller whether the platform's own sign-in
|
|
75
|
+
* vouched for it: `mayProvisionDirectAccount`, provisionMyAccount's
|
|
76
|
+
* admission. That RPC provisions the DIRECT account of the credential's
|
|
77
|
+
* subject, and a subject names a direct account only when the lane that
|
|
78
|
+
* admitted the caller is one of the platform's own. Every such lane
|
|
79
|
+
* resolves its caller through `identityIdForSubject` and stamps the `user`
|
|
80
|
+
* class, so its caller is either idp-shaped (no account, and the identity
|
|
81
|
+
* is the subject itself) or the direct account of that subject. Anything
|
|
82
|
+
* else was vouched for by another lane: an organization's identity
|
|
83
|
+
* provider stamps its own federated account, a platform client's user
|
|
84
|
+
* token its own account, a system lane its lane account or raw lane
|
|
85
|
+
* subject. Their `sub` is theirs to choose, so provisioning by it would
|
|
86
|
+
* hand them a platform person's row, or create one under the subject with
|
|
87
|
+
* a profile fetched from their own issuer. The trusted-local operator, who
|
|
88
|
+
* carries no issuer and no token, is the posture's own and is admitted.
|
|
89
|
+
* Two primary-key reads; faults propagate as they are.
|
|
57
90
|
*/
|
|
58
91
|
import type { IdentityAccount } from "@stigmer/protos/ai/stigmer/iam/identityaccount/v1/api_pb";
|
|
59
92
|
|
|
60
93
|
import type { CallerIdentity } from "../../extensions/identity.js";
|
|
61
|
-
import {
|
|
94
|
+
import { SYSTEM_OPERATOR_IDENTITY_ID } from "../../pipeline/interceptors/auth.js";
|
|
95
|
+
import { idpIdOf, isAccountIdShaped, localIdpIdFor } from "./constants.js";
|
|
62
96
|
import type { IdentityAccountStore } from "./store.js";
|
|
63
97
|
|
|
64
98
|
/** The one read a verifier needs from the domain: the direct account for a subject. */
|
|
@@ -124,3 +158,48 @@ export async function accountForStamp(
|
|
|
124
158
|
(await accounts.findDirectByIdpId(stamp))
|
|
125
159
|
);
|
|
126
160
|
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Whether a creator stamp is the operator's from before sign-in was turned
|
|
164
|
+
* on: the "system" placeholder, or an email whose `local|<email>` account
|
|
165
|
+
* the store holds. Faults propagate as they are.
|
|
166
|
+
*/
|
|
167
|
+
export async function isPreSignInOperatorStamp(
|
|
168
|
+
accounts: AccountsBySubject,
|
|
169
|
+
stamp: string,
|
|
170
|
+
): Promise<boolean> {
|
|
171
|
+
if (stamp === SYSTEM_OPERATOR_IDENTITY_ID) {
|
|
172
|
+
return true;
|
|
173
|
+
}
|
|
174
|
+
if (stamp === "" || isAccountIdShaped(stamp)) {
|
|
175
|
+
return false;
|
|
176
|
+
}
|
|
177
|
+
return (await accounts.findDirectByIdpId(localIdpIdFor(stamp))) !== undefined;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Whether provisionMyAccount may provision the direct account of
|
|
182
|
+
* `subject` (the caller's `idpIdOf`) for `caller`: the trusted-local
|
|
183
|
+
* operator; or a `user`-class caller that is idp-shaped (no account under
|
|
184
|
+
* its identity, which is the subject itself) or is already that subject's
|
|
185
|
+
* direct account. Faults propagate as they are.
|
|
186
|
+
*/
|
|
187
|
+
export async function mayProvisionDirectAccount(
|
|
188
|
+
accounts: AccountsByCaller,
|
|
189
|
+
caller: CallerIdentity,
|
|
190
|
+
subject: string,
|
|
191
|
+
): Promise<boolean> {
|
|
192
|
+
if (caller.issuer === "" && caller.rawToken === "") {
|
|
193
|
+
return true;
|
|
194
|
+
}
|
|
195
|
+
if (caller.callerClass !== "user" || subject === "") {
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const standing = await accounts.findById(caller.identityId);
|
|
199
|
+
if (standing === undefined) {
|
|
200
|
+
return caller.identityId === subject;
|
|
201
|
+
}
|
|
202
|
+
const standingId = standing.metadata?.id ?? "";
|
|
203
|
+
const direct = await accounts.findDirectByIdpId(subject);
|
|
204
|
+
return standingId !== "" && direct?.metadata?.id === standingId;
|
|
205
|
+
}
|
|
@@ -103,7 +103,12 @@ export function newResourceIdentityAccountStore(
|
|
|
103
103
|
|
|
104
104
|
findById: readById,
|
|
105
105
|
|
|
106
|
-
findByIdpId:
|
|
106
|
+
async findByIdpId(idpId): Promise<IdentityAccount | undefined> {
|
|
107
|
+
const account = await readBySubject(idpId);
|
|
108
|
+
return account !== undefined && !isFederated(account)
|
|
109
|
+
? account
|
|
110
|
+
: undefined;
|
|
111
|
+
},
|
|
107
112
|
|
|
108
113
|
async findDirectByIdpId(idpId): Promise<IdentityAccount | undefined> {
|
|
109
114
|
const account = await readBySubject(idpId);
|
|
@@ -151,6 +156,14 @@ export function newResourceIdentityAccountStore(
|
|
|
151
156
|
* asserted, so no direct lookup — a verifier's subject resolve, getByEmail —
|
|
152
157
|
* may answer it.
|
|
153
158
|
*/
|
|
159
|
+
/** A row an identity provider vouches for: its subject is the provider's, reached only by the natural key. */
|
|
160
|
+
function isFederated(account: IdentityAccount): boolean {
|
|
161
|
+
return (
|
|
162
|
+
account.spec?.identityProviderRef !== undefined ||
|
|
163
|
+
account.spec?.provisioningMode === IdentityAccountProvisioningMode.federated
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
154
167
|
function isDirect(account: IdentityAccount): boolean {
|
|
155
168
|
const mode = account.spec?.provisioningMode;
|
|
156
169
|
return (
|