@bevel-software/platform-core-backend 0.20.0 → 0.21.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/core/catalog-cache-invalidation.d.ts +7 -2
- package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
- package/dist/core/catalog-cache-invalidation.js +8 -9
- package/dist/core/catalog-cache-invalidation.js.map +1 -1
- package/dist/core/core-ports.d.ts +19 -0
- package/dist/core/core-ports.d.ts.map +1 -1
- package/dist/core/core-ports.js.map +1 -1
- package/dist/core/create-core-server.d.ts +2 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +23 -105
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +30 -5
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +136 -81
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +74 -28
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +157 -20
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core/public-config.d.ts +5 -1
- package/dist/core/public-config.d.ts.map +1 -1
- package/dist/core/public-config.js +7 -5
- package/dist/core/public-config.js.map +1 -1
- package/dist/core-config.d.ts +95 -1
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +24 -8
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +18 -1
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +19 -8
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts +2 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +10 -10
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/change-read-gate.d.ts +6 -3
- package/dist/modules/access/change-read-gate.d.ts.map +1 -1
- package/dist/modules/access/change-read-gate.js +9 -6
- package/dist/modules/access/change-read-gate.js.map +1 -1
- package/dist/modules/access/creator-access.d.ts +4 -2
- package/dist/modules/access/creator-access.d.ts.map +1 -1
- package/dist/modules/access/creator-access.js +7 -4
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/agent-instructions/read-preamble.d.ts +2 -1
- package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -1
- package/dist/modules/agent-instructions/read-preamble.js +6 -9
- package/dist/modules/agent-instructions/read-preamble.js.map +1 -1
- package/dist/modules/auth/account-admission.d.ts +40 -0
- package/dist/modules/auth/account-admission.d.ts.map +1 -0
- package/dist/modules/auth/account-admission.js +17 -0
- package/dist/modules/auth/account-admission.js.map +1 -0
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +4 -1
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +19 -1
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +33 -1
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +9 -0
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts +13 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +10 -2
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/advisory-lock.d.ts +17 -0
- package/dist/modules/database/advisory-lock.d.ts.map +1 -1
- package/dist/modules/database/advisory-lock.js +24 -3
- package/dist/modules/database/advisory-lock.js.map +1 -1
- package/dist/modules/database/connection.d.ts +67 -2
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +118 -12
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/migrate.d.ts +1 -1
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +27 -3
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/kb-fs/branch-name.d.ts +0 -1
- package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
- package/dist/modules/kb-fs/branch-name.js +3 -3
- package/dist/modules/kb-fs/branch-name.js.map +1 -1
- package/dist/modules/kb-fs/clone-config.d.ts +9 -8
- package/dist/modules/kb-fs/clone-config.d.ts.map +1 -1
- package/dist/modules/kb-fs/clone-config.js +14 -12
- package/dist/modules/kb-fs/clone-config.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +7 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +4 -4
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +4 -4
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.js +7 -10
- package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts +4 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +5 -3
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +6 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.js +14 -9
- package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
- package/dist/modules/plugins/discovery/native.source.d.ts +4 -1
- package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/native.source.js +4 -2
- package/dist/modules/plugins/discovery/native.source.js.map +1 -1
- package/dist/modules/plugins/index.d.ts +1 -1
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js +1 -1
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts +3 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.js +6 -6
- package/dist/modules/plugins/join-request-jobs.service.js.map +1 -1
- package/dist/modules/plugins/join-requests.service.d.ts +3 -1
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-requests.service.js +9 -8
- package/dist/modules/plugins/join-requests.service.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +65 -10
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js +136 -31
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugin-links.service.d.ts +107 -5
- package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.service.js +151 -21
- package/dist/modules/plugins/plugin-links.service.js.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.d.ts +10 -3
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +33 -26
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts +4 -2
- package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.js +10 -12
- package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +3 -0
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +45 -15
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.service.d.ts +4 -4
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.service.js +7 -10
- package/dist/modules/plugins/plugins.service.js.map +1 -1
- package/dist/modules/plugins/teams.routes.d.ts +4 -1
- package/dist/modules/plugins/teams.routes.d.ts.map +1 -1
- package/dist/modules/plugins/teams.routes.js +11 -9
- package/dist/modules/plugins/teams.routes.js.map +1 -1
- package/dist/modules/secrets-vault/index.d.ts +1 -1
- package/dist/modules/secrets-vault/index.d.ts.map +1 -1
- package/dist/modules/secrets-vault/index.js +1 -1
- package/dist/modules/secrets-vault/index.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts +29 -11
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js +46 -21
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +3 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +4 -6
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +12 -8
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +20 -22
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/setup.routes.d.ts +9 -2
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +20 -14
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/allowed-tools-check.d.ts +4 -3
- package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -1
- package/dist/modules/skills/allowed-tools-check.js +8 -8
- package/dist/modules/skills/allowed-tools-check.js.map +1 -1
- package/dist/modules/skills/pending-skills.service.d.ts +3 -1
- package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
- package/dist/modules/skills/pending-skills.service.js +9 -6
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts +2 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.js +6 -6
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
- package/dist/modules/skills/skills.routes.d.ts +4 -1
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +4 -4
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +4 -2
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +13 -11
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +2 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +6 -5
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +4 -2
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -10
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts +3 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.js +19 -16
- package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-delete.service.d.ts +4 -2
- package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-delete.service.js +14 -12
- package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +3 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +7 -7
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +4 -2
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +15 -12
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +3 -0
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +4 -6
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts +3 -2
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +9 -9
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +11 -5
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +23 -14
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.d.ts +26 -2
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.js +35 -5
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +9 -4
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/session-ontology.service.d.ts +6 -1
- package/dist/modules/workflow/session-ontology.service.d.ts.map +1 -1
- package/dist/modules/workflow/session-ontology.service.js +6 -2
- package/dist/modules/workflow/session-ontology.service.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +8 -3
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +33 -23
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts +3 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.js +3 -3
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
- package/dist/modules/workspace/startup/kb-git.d.ts +4 -3
- package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-git.js +15 -13
- package/dist/modules/workspace/startup/kb-git.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +5 -8
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +35 -38
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +23 -16
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js +12 -5
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +12 -5
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +12 -5
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts +4 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +14 -11
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +17 -3
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +36 -30
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +6 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +10 -6
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/workspace.routes.d.ts +2 -1
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +8 -7
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +18 -12
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +32 -28
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +2 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +20 -18
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +3 -2
- package/dist/modules/workspace/write-denial.d.ts.map +1 -1
- package/dist/modules/workspace/write-denial.js +6 -5
- package/dist/modules/workspace/write-denial.js.map +1 -1
- package/dist/shared/git.contract.d.ts +52 -7
- package/dist/shared/git.contract.d.ts.map +1 -1
- package/dist/shared/git.contract.js +30 -8
- package/dist/shared/git.contract.js.map +1 -1
- package/dist/shared/kb-context.d.ts +76 -0
- package/dist/shared/kb-context.d.ts.map +1 -0
- package/dist/shared/kb-context.js +108 -0
- package/dist/shared/kb-context.js.map +1 -0
- package/dist/shared/kb-layout.d.ts +3 -2
- package/dist/shared/kb-layout.d.ts.map +1 -1
- package/dist/shared/kb-layout.js +4 -3
- package/dist/shared/kb-layout.js.map +1 -1
- package/dist/shared/kb-layout.test.js +35 -27
- package/dist/shared/kb-layout.test.js.map +1 -1
- package/dist/shared/pending-proposals.d.ts +4 -1
- package/dist/shared/pending-proposals.d.ts.map +1 -1
- package/dist/shared/pending-proposals.js +3 -4
- package/dist/shared/pending-proposals.js.map +1 -1
- package/dist/shared/redact-secret.d.ts +5 -5
- package/dist/shared/redact-secret.js +5 -5
- package/dist/tenancy/index.d.ts +13 -0
- package/dist/tenancy/index.d.ts.map +1 -0
- package/dist/tenancy/index.js +13 -0
- package/dist/tenancy/index.js.map +1 -0
- package/dist/tenancy/static-tenant-source.d.ts +98 -0
- package/dist/tenancy/static-tenant-source.d.ts.map +1 -0
- package/dist/tenancy/static-tenant-source.js +220 -0
- package/dist/tenancy/static-tenant-source.js.map +1 -0
- package/dist/tenancy/tenant-host.d.ts +80 -0
- package/dist/tenancy/tenant-host.d.ts.map +1 -0
- package/dist/tenancy/tenant-host.js +217 -0
- package/dist/tenancy/tenant-host.js.map +1 -0
- package/dist/tenancy/tenant-runtime.d.ts +91 -0
- package/dist/tenancy/tenant-runtime.d.ts.map +1 -0
- package/dist/tenancy/tenant-runtime.js +174 -0
- package/dist/tenancy/tenant-runtime.js.map +1 -0
- package/dist/tenancy/tenant-secrets.d.ts +24 -0
- package/dist/tenancy/tenant-secrets.d.ts.map +1 -0
- package/dist/tenancy/tenant-secrets.js +30 -0
- package/dist/tenancy/tenant-secrets.js.map +1 -0
- package/dist/tenancy/tenant-source.contract.d.ts +45 -0
- package/dist/tenancy/tenant-source.contract.d.ts.map +1 -0
- package/dist/tenancy/tenant-source.contract.js +21 -0
- package/dist/tenancy/tenant-source.contract.js.map +1 -0
- package/migrations/0000_core_init.sql +14 -14
- package/migrations/0003_deployment_settings.sql +1 -1
- package/migrations/0005_github_facade.sql +1 -1
- package/migrations/0012_agent_audit.sql +6 -6
- package/package.json +3 -3
- package/src/__tests__/branch-model.test.ts +7 -6
- package/src/__tests__/kb-context.ts +30 -0
- package/src/__tests__/kb-layout-config.test.ts +35 -30
- package/src/core/__tests__/catalog-cache-invalidation.test.ts +2 -1
- package/src/core/__tests__/lifecycle.test.ts +78 -1
- package/src/core/__tests__/public-config.test.ts +5 -1
- package/src/core/catalog-cache-invalidation.ts +16 -11
- package/src/core/core-ports.ts +19 -0
- package/src/core/create-core-server.ts +27 -106
- package/src/core/create-core-services.ts +180 -95
- package/src/core/lifecycle.ts +214 -29
- package/src/core/public-config.ts +8 -5
- package/src/core-config.ts +107 -8
- package/src/index.ts +25 -2
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -1
- package/src/modules/access/__tests__/change-read-gate.test.ts +13 -11
- package/src/modules/access/__tests__/creator-access.test.ts +3 -2
- package/src/modules/access/__tests__/roles.routes.test.ts +2 -1
- package/src/modules/access/access-control.service.ts +20 -6
- package/src/modules/access/access.routes.ts +10 -13
- package/src/modules/access/change-read-gate.ts +10 -4
- package/src/modules/access/creator-access.ts +7 -2
- package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +13 -12
- package/src/modules/agent-instructions/read-preamble.ts +10 -12
- package/src/modules/auth/__tests__/account.routes.test.ts +15 -0
- package/src/modules/auth/__tests__/auth.service.test.ts +60 -0
- package/src/modules/auth/account-admission.ts +44 -0
- package/src/modules/auth/account.routes.ts +4 -1
- package/src/modules/auth/auth.service.ts +33 -1
- package/src/modules/auth/oidc-auth-provider.ts +9 -0
- package/src/modules/connection-probe/connection-probe.service.ts +7 -1
- package/src/modules/database/__tests__/advisory-lock.test.ts +23 -1
- package/src/modules/database/__tests__/connection.test.ts +98 -0
- package/src/modules/database/__tests__/migrations-unqualified.test.ts +32 -0
- package/src/modules/database/advisory-lock.ts +28 -4
- package/src/modules/database/connection.ts +143 -13
- package/src/modules/database/migrate.ts +48 -14
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +2 -1
- package/src/modules/diff/__tests__/diff.service.test.ts +2 -1
- package/src/modules/kb-fs/__tests__/branch-name.test.ts +6 -6
- package/src/modules/kb-fs/__tests__/clone-config.test.ts +24 -20
- package/src/modules/kb-fs/branch-name.ts +3 -3
- package/src/modules/kb-fs/clone-config.ts +15 -12
- package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +2 -1
- package/src/modules/mcp/mcp.service.ts +11 -4
- package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +12 -11
- package/src/modules/plugins/__tests__/bundle-dialect.test.ts +2 -1
- package/src/modules/plugins/__tests__/compile-marketplace.test.ts +6 -4
- package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +2 -1
- package/src/modules/plugins/__tests__/join-requests.service.test.ts +2 -1
- package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +4 -3
- package/src/modules/plugins/__tests__/plugin-index.service.test.ts +6 -4
- package/src/modules/plugins/__tests__/plugin-links.service.test.ts +220 -5
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +3 -1
- package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +7 -6
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +11 -2
- package/src/modules/plugins/__tests__/teams.routes.test.ts +2 -1
- package/src/modules/plugins/compile/marketplace-compiler.service.ts +7 -9
- package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +20 -16
- package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +9 -2
- package/src/modules/plugins/discovery/kb-plugin-source.ts +15 -8
- package/src/modules/plugins/discovery/native.source.ts +4 -1
- package/src/modules/plugins/index.ts +1 -1
- package/src/modules/plugins/join-request-jobs.service.ts +8 -7
- package/src/modules/plugins/join-requests.service.ts +7 -7
- package/src/modules/plugins/plugin-links.service.ts +192 -19
- package/src/modules/plugins/plugin-links.ts +147 -27
- package/src/modules/plugins/plugin-provision.service.ts +54 -27
- package/src/modules/plugins/plugin-rename.service.ts +10 -10
- package/src/modules/plugins/plugins.routes.ts +45 -15
- package/src/modules/plugins/plugins.service.ts +7 -11
- package/src/modules/plugins/teams.routes.ts +16 -8
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +7 -0
- package/src/modules/secrets-vault/__tests__/secrets-variable-loader.test.ts +40 -0
- package/src/modules/secrets-vault/__tests__/tool-owner-gate.route.test.ts +2 -0
- package/src/modules/secrets-vault/index.ts +2 -0
- package/src/modules/secrets-vault/secrets-variable-loader.ts +51 -21
- package/src/modules/secrets-vault/secrets-vault.routes.ts +7 -6
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +24 -11
- package/src/modules/settings/__tests__/git-root-folders.test.ts +2 -1
- package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +2 -1
- package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +7 -4
- package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +2 -0
- package/src/modules/settings/__tests__/setup.routes.sync-status.test.ts +2 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +33 -52
- package/src/modules/settings/deployment-settings.service.ts +21 -20
- package/src/modules/settings/setup.routes.ts +26 -16
- package/src/modules/skills/__tests__/allowed-tools-check.test.ts +11 -10
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +4 -3
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -1
- package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +2 -1
- package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +2 -1
- package/src/modules/skills/__tests__/skills.service.test.ts +3 -2
- package/src/modules/skills/allowed-tools-check.ts +7 -6
- package/src/modules/skills/pending-skills.service.ts +9 -8
- package/src/modules/skills/skill-access-requests.routes.ts +7 -7
- package/src/modules/skills/skills.routes.ts +4 -3
- package/src/modules/skills/skills.service.ts +13 -9
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +3 -2
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -2
- package/src/modules/tool-manuals/__tests__/mcp-json-discovery.test.ts +17 -12
- package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +4 -1
- package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +5 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +4 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +13 -5
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +9 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +3 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +2 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +6 -4
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +13 -11
- package/src/modules/tool-manuals/pending-tools.service.ts +19 -16
- package/src/modules/tool-manuals/tool-delete.service.ts +13 -10
- package/src/modules/tool-manuals/tool-manuals.routes.ts +10 -8
- package/src/modules/tool-manuals/tool-manuals.service.ts +15 -13
- package/src/modules/tool-manuals/tool-manuals.tools.ts +7 -6
- package/src/modules/workflow/__tests__/apply-failure.test.ts +2 -1
- package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +14 -26
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -1
- package/src/modules/workflow/__tests__/session-ontology.service.test.ts +3 -2
- package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +3 -10
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +3 -10
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +28 -27
- package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +3 -2
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +2 -1
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -4
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +2 -1
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +2 -1
- package/src/modules/workflow/agent-tools/workflow.tools.ts +11 -9
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +5 -4
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +12 -11
- package/src/modules/workflow/git/__tests__/git.service.commitChanges.test.ts +9 -8
- package/src/modules/workflow/git/__tests__/git.service.commitFile.strayPath.test.ts +8 -7
- package/src/modules/workflow/git/__tests__/git.service.commitFile.test.ts +6 -5
- package/src/modules/workflow/git/__tests__/git.service.createBranch.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.deleteBranch.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.diffFileAtCommit.test.ts +7 -6
- package/src/modules/workflow/git/__tests__/git.service.diffFileBetweenBranches.test.ts +16 -15
- package/src/modules/workflow/git/__tests__/git.service.fileContentsAtCommit.test.ts +3 -2
- package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.history-guards.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +10 -9
- package/src/modules/workflow/git/__tests__/git.service.listTrackedFiles.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.logForFile.test.ts +6 -5
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +9 -8
- package/src/modules/workflow/git/__tests__/git.service.pendingChanges.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.postMergePull.test.ts +4 -3
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +9 -8
- package/src/modules/workflow/git/__tests__/git.service.readFileAtRef.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +2 -1
- package/src/modules/workflow/git/__tests__/git.service.status.test.ts +4 -3
- package/src/modules/workflow/git/__tests__/git.service.syncFromRemote.test.ts +8 -7
- package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +41 -3
- package/src/modules/workflow/git/git.service.ts +24 -13
- package/src/modules/workflow/git/node-git-runner.ts +37 -4
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +9 -6
- package/src/modules/workflow/session-ontology.service.ts +7 -2
- package/src/modules/workflow/workflow.service.ts +31 -24
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +3 -2
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +10 -9
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +4 -2
- package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +3 -2
- package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +5 -4
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +2 -2
- package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
- package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.service.test.ts +84 -50
- package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +2 -1
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -7
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +4 -3
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +9 -8
- package/src/modules/workspace/__tests__/write-denial.test.ts +5 -4
- package/src/modules/workspace/session-ontology.gate.ts +6 -4
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +6 -2
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +29 -21
- package/src/modules/workspace/startup/kb-git.ts +15 -22
- package/src/modules/workspace/startup/kb-startup-runner.ts +40 -46
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +104 -98
- package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +24 -16
- package/src/modules/workspace/startup/steps/personal-spaces.step.ts +14 -5
- package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +13 -5
- package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +14 -5
- package/src/modules/workspace/startup/steps/seed-tree.ts +11 -9
- package/src/modules/workspace/startup/steps/template-files.step.ts +43 -34
- package/src/modules/workspace/startup/steps/template-source.ts +8 -5
- package/src/modules/workspace/workspace.routes.ts +8 -7
- package/src/modules/workspace/workspace.service.ts +30 -27
- package/src/modules/workspace/workspace.tools.ts +21 -20
- package/src/modules/workspace/write-denial.ts +7 -5
- package/src/shared/__tests__/kb-layout.plugin.test.ts +19 -16
- package/src/shared/git.contract.ts +70 -8
- package/src/shared/kb-context.ts +130 -0
- package/src/shared/kb-layout.test.ts +37 -27
- package/src/shared/kb-layout.ts +4 -3
- package/src/shared/pending-proposals.ts +7 -4
- package/src/shared/redact-secret.ts +5 -5
- package/src/tenancy/__tests__/static-tenant-source.test.ts +177 -0
- package/src/tenancy/__tests__/tenant-host.test.ts +372 -0
- package/src/tenancy/__tests__/tenant-runtime.test.ts +221 -0
- package/src/tenancy/__tests__/tenant-secrets.test.ts +35 -0
- package/src/tenancy/index.ts +35 -0
- package/src/tenancy/static-tenant-source.ts +296 -0
- package/src/tenancy/tenant-host.ts +261 -0
- package/src/tenancy/tenant-runtime.ts +208 -0
- package/src/tenancy/tenant-secrets.ts +41 -0
- package/src/tenancy/tenant-source.contract.ts +59 -0
|
@@ -13,7 +13,8 @@ import {
|
|
|
13
13
|
import type { IAccessControl } from '../access/access-control.interface.js';
|
|
14
14
|
import { WorkflowDomainError } from '../../shared/domain-errors.js';
|
|
15
15
|
import { domainErrorBody } from '../../shared/http-errors.js';
|
|
16
|
-
import {
|
|
16
|
+
import { pluginFolderBelowRoot } from './plugins.service.js';
|
|
17
|
+
import type { KbContext } from '../../shared/kb-context.js';
|
|
17
18
|
import { PluginProvisionError, type PluginProvisionService } from './plugin-provision.service.js';
|
|
18
19
|
import { PluginLinkError, type PluginLinksService } from './plugin-links.service.js';
|
|
19
20
|
import { PluginRenameError, type PluginRenameService } from './plugin-rename.service.js';
|
|
@@ -159,6 +160,8 @@ export function createPluginsRoutes(
|
|
|
159
160
|
joinRequestJobs: PluginJoinRequestJobs,
|
|
160
161
|
provision: PluginProvisionService,
|
|
161
162
|
resolveUser: (req: express.Request) => Promise<AuthUser | null>,
|
|
163
|
+
/** The released branch's clone — every verdict here is read from it. */
|
|
164
|
+
kb: Pick<KbContext, 'defaultWorkspaceId'>,
|
|
162
165
|
/** Optional: a host without the link machinery simply has no link routes. */
|
|
163
166
|
links?: PluginLinksService,
|
|
164
167
|
/** Optional: a host without it has no rename route. */
|
|
@@ -209,11 +212,30 @@ export function createPluginsRoutes(
|
|
|
209
212
|
* POST /api/plugins/:name/links { skillPath } → { root, skills }
|
|
210
213
|
* DELETE /api/plugins/:name/links?skillPath= → { root, revoked }
|
|
211
214
|
* POST /api/plugins/:name/links/repair { skillPath } → { root }
|
|
215
|
+
* POST /api/plugins/:name/links/repair-all → { repaired, skipped }
|
|
212
216
|
*
|
|
213
217
|
* Refusals carry a `kind` the UI branches on — `needs-skill-write` (409) is
|
|
214
218
|
* the one that becomes "request write access".
|
|
219
|
+
*
|
|
220
|
+
* `repair-all` is the plugin PAGE's: it repairs every link of the plugin the
|
|
221
|
+
* caller can, and reports what it could not. A caller who may not write the
|
|
222
|
+
* plugin gets the same 404 every other link route gives them, so probing it
|
|
223
|
+
* confirms nothing about a plugin they cannot see.
|
|
215
224
|
*/
|
|
216
225
|
if (links) {
|
|
226
|
+
/** The one refusal mapping every link route answers with. */
|
|
227
|
+
const linkFailure = (res: express.Response, err: unknown) => {
|
|
228
|
+
if (err instanceof PluginLinkError) {
|
|
229
|
+
res.status(err.status).json({ error: err.message, ...err.payload });
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (err instanceof WorkflowDomainError) {
|
|
233
|
+
res.status(err.status).json(domainErrorBody(err));
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
log.error('link operation failed:', { err });
|
|
237
|
+
res.status(500).json({ error: 'Failed to update the plugin\'s links' });
|
|
238
|
+
};
|
|
217
239
|
const linkOp = async (
|
|
218
240
|
req: express.Request,
|
|
219
241
|
res: express.Response,
|
|
@@ -237,16 +259,7 @@ export function createPluginsRoutes(
|
|
|
237
259
|
try {
|
|
238
260
|
res.json(await op(user, String(req.params.name), skillPath));
|
|
239
261
|
} catch (err) {
|
|
240
|
-
|
|
241
|
-
res.status(err.status).json({ error: err.message, ...err.payload });
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
if (err instanceof WorkflowDomainError) {
|
|
245
|
-
res.status(err.status).json(domainErrorBody(err));
|
|
246
|
-
return;
|
|
247
|
-
}
|
|
248
|
-
log.error('link operation failed:', { err });
|
|
249
|
-
res.status(500).json({ error: 'Failed to update the plugin\'s links' });
|
|
262
|
+
linkFailure(res, err);
|
|
250
263
|
}
|
|
251
264
|
};
|
|
252
265
|
const bodyPath = (req: express.Request) => ((req.body ?? {}) as { skillPath?: unknown }).skillPath;
|
|
@@ -254,6 +267,23 @@ export function createPluginsRoutes(
|
|
|
254
267
|
router.post('/plugins/:name/links/repair', (req, res) =>
|
|
255
268
|
linkOp(req, res, (u, p, s) => links.repair(u, p, s), bodyPath),
|
|
256
269
|
);
|
|
270
|
+
// No `skillPath`: this one is about the plugin, so it cannot ride `linkOp`.
|
|
271
|
+
router.post('/plugins/:name/links/repair-all', async (req, res) => {
|
|
272
|
+
if (!req.userEmail) {
|
|
273
|
+
res.status(401).json({ error: 'Unauthenticated' });
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const user = await resolveUser(req);
|
|
277
|
+
if (!user) {
|
|
278
|
+
res.status(401).json({ error: 'Unauthenticated' });
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
try {
|
|
282
|
+
res.json(await links.repairAll(user, String(req.params.name)));
|
|
283
|
+
} catch (err) {
|
|
284
|
+
linkFailure(res, err);
|
|
285
|
+
}
|
|
286
|
+
});
|
|
257
287
|
router.delete('/plugins/:name/links', (req, res) =>
|
|
258
288
|
linkOp(req, res, (u, p, s) => links.unlink(u, p, s), (r) => r.query.skillPath),
|
|
259
289
|
);
|
|
@@ -296,7 +326,7 @@ export function createPluginsRoutes(
|
|
|
296
326
|
res.json({ plugins: [] });
|
|
297
327
|
return;
|
|
298
328
|
}
|
|
299
|
-
const wsId =
|
|
329
|
+
const wsId = kb.defaultWorkspaceId();
|
|
300
330
|
const probes = probesFor(catalog);
|
|
301
331
|
const [readable, writable, owned] = await Promise.all([
|
|
302
332
|
accessControl.canReadBatch(wsId, email, probes),
|
|
@@ -453,7 +483,7 @@ export function createPluginsRoutes(
|
|
|
453
483
|
}
|
|
454
484
|
// By identity — the manifest name the catalog keys on.
|
|
455
485
|
const plugin = (await pluginIndex.catalog()).find((g) => g.name === req.params.name);
|
|
456
|
-
const wsId =
|
|
486
|
+
const wsId = kb.defaultWorkspaceId();
|
|
457
487
|
const ownerVerdicts = plugin
|
|
458
488
|
? await Promise.all(
|
|
459
489
|
plugin.folders.map((f) => accessControl.canOwner(wsId, email, memberProbe(f))),
|
|
@@ -494,7 +524,7 @@ export function createPluginsRoutes(
|
|
|
494
524
|
const catalog = await pluginIndex.catalog();
|
|
495
525
|
// By identity — the manifest name the catalog keys on.
|
|
496
526
|
const plugin = catalog.find((g) => g.name === req.params.name);
|
|
497
|
-
const wsId =
|
|
527
|
+
const wsId = kb.defaultWorkspaceId();
|
|
498
528
|
// Same ANY-folder shape `GET /plugins` resolves with, so a plugin can
|
|
499
529
|
// never be listed as discoverable there and rejected as unknown here.
|
|
500
530
|
const verdicts = plugin
|
|
@@ -567,7 +597,7 @@ export function createPluginsRoutes(
|
|
|
567
597
|
return null;
|
|
568
598
|
}
|
|
569
599
|
const writable = await accessControl.canWriteBatch(
|
|
570
|
-
|
|
600
|
+
kb.defaultWorkspaceId(),
|
|
571
601
|
email,
|
|
572
602
|
plugin.folders.map(accessMdOf),
|
|
573
603
|
);
|
|
@@ -3,13 +3,10 @@ import { logger } from '../../shared/logging.js';
|
|
|
3
3
|
|
|
4
4
|
const log = logger('plugins');
|
|
5
5
|
import path from 'node:path';
|
|
6
|
-
import {
|
|
7
|
-
DEFAULT_BRANCH,
|
|
8
|
-
} from '@bevel-software/platform-shared';
|
|
9
6
|
import { isPrivateAccessMd } from '../access-model/access-grammar.js';
|
|
10
7
|
import { isAbsence } from '../../shared/fs.contract.js';
|
|
11
8
|
import type { WorkspaceService } from '../workspace/workspace.service.js';
|
|
12
|
-
import {
|
|
9
|
+
import type { KbContext } from '../../shared/kb-context.js';
|
|
13
10
|
import type { IAccessControl } from '../access/access-control.interface.js';
|
|
14
11
|
import type { ISkillService } from '../skills/skills.contract.js';
|
|
15
12
|
import type { IToolManualService } from '../tool-manuals/tool-manuals.contract.js';
|
|
@@ -63,7 +60,7 @@ export class PluginIndexService implements IPluginIndexService {
|
|
|
63
60
|
private readonly accessControl: IAccessControl,
|
|
64
61
|
private readonly skillService: ISkillService,
|
|
65
62
|
private readonly toolManualService: IToolManualService,
|
|
66
|
-
private readonly
|
|
63
|
+
private readonly kb: KbContext,
|
|
67
64
|
/** Where plugins come from — the one discovery every catalog shares. */
|
|
68
65
|
private readonly source: PluginSource,
|
|
69
66
|
now: () => number = Date.now,
|
|
@@ -77,6 +74,10 @@ export class PluginIndexService implements IPluginIndexService {
|
|
|
77
74
|
this.cache = new TtlCache(CACHE_TTL_MS, now);
|
|
78
75
|
}
|
|
79
76
|
|
|
77
|
+
private get kbDirName(): string {
|
|
78
|
+
return this.kb.kbDirName;
|
|
79
|
+
}
|
|
80
|
+
|
|
80
81
|
invalidate(): void {
|
|
81
82
|
this.cache.invalidate();
|
|
82
83
|
}
|
|
@@ -115,7 +116,7 @@ export class PluginIndexService implements IPluginIndexService {
|
|
|
115
116
|
*/
|
|
116
117
|
private async build(): Promise<PluginCatalogEntry[] | null> {
|
|
117
118
|
try {
|
|
118
|
-
const wsId = (await this.workspaceService.getOrCreateForBranch(
|
|
119
|
+
const wsId = (await this.workspaceService.getOrCreateForBranch(this.kb.defaultBranch)).id;
|
|
119
120
|
const kbRoot = path.join(await this.workspaceService.getWorkspacePath(wsId), this.kbDirName);
|
|
120
121
|
|
|
121
122
|
const scanned = await this.scanFolders(kbRoot);
|
|
@@ -301,11 +302,6 @@ function bucketByFolder(items: { path: string }[], folders: Map<string, string[]
|
|
|
301
302
|
return counts;
|
|
302
303
|
}
|
|
303
304
|
|
|
304
|
-
/** The default-branch workspace id every plugin resolution runs against. */
|
|
305
|
-
export function pluginsWorkspaceId(): string {
|
|
306
|
-
return workspaceIdForBranch(DEFAULT_BRANCH);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
305
|
/**
|
|
310
306
|
* A plugin folder's path BELOW the plugins root: `GTM`, or `teams/deep`.
|
|
311
307
|
*
|
|
@@ -2,12 +2,17 @@ import express from 'express';
|
|
|
2
2
|
import { logger } from '../../shared/logging.js';
|
|
3
3
|
|
|
4
4
|
const log = logger('teams');
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
isPersonalPluginDir,
|
|
7
|
+
isPersonalPluginFolder,
|
|
8
|
+
pluginOfPath,
|
|
9
|
+
type KbLayout,
|
|
10
|
+
} from '@bevel-software/platform-shared';
|
|
6
11
|
import type { IAccessControl } from '../access/access-control.interface.js';
|
|
12
|
+
import type { KbContext } from '../../shared/kb-context.js';
|
|
7
13
|
import type { ISkillService } from '../skills/skills.contract.js';
|
|
8
14
|
import type { IToolManualService } from '../tool-manuals/tool-manuals.contract.js';
|
|
9
15
|
import type { IPluginIndexService, PluginCatalogEntry } from './plugins.contract.js';
|
|
10
|
-
import { pluginsWorkspaceId } from './plugins.service.js';
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* What one team can use, by id — the Library's "Your teams" lens.
|
|
@@ -51,6 +56,8 @@ export function createTeamsRoutes(
|
|
|
51
56
|
pluginIndex: IPluginIndexService,
|
|
52
57
|
skillService: Pick<ISkillService, 'listSkills'>,
|
|
53
58
|
toolManuals: Pick<IToolManualService, 'listAllSummaries'>,
|
|
59
|
+
/** The released branch's clone the verdicts are read from, and the layout that names the plugins root. */
|
|
60
|
+
kb: Pick<KbContext, 'defaultWorkspaceId' | 'layout'>,
|
|
54
61
|
): express.Router {
|
|
55
62
|
const router = express.Router();
|
|
56
63
|
|
|
@@ -61,7 +68,7 @@ export function createTeamsRoutes(
|
|
|
61
68
|
return;
|
|
62
69
|
}
|
|
63
70
|
try {
|
|
64
|
-
const wsId =
|
|
71
|
+
const wsId = kb.defaultWorkspaceId();
|
|
65
72
|
const [{ groups }, catalog, allSkills, allTools] = await Promise.all([
|
|
66
73
|
accessControl.kbPrincipals(wsId),
|
|
67
74
|
pluginIndex.catalog(),
|
|
@@ -73,9 +80,10 @@ export function createTeamsRoutes(
|
|
|
73
80
|
// be a team's to read — whatever a hand-written grant in there says.
|
|
74
81
|
// One rule for the plugin and for its contents, so the two cannot
|
|
75
82
|
// disagree.
|
|
76
|
-
const
|
|
77
|
-
const
|
|
78
|
-
const
|
|
83
|
+
const layout = kb.layout;
|
|
84
|
+
const plugins = catalog.filter((g) => !g.folders.every((f) => isPersonalPluginDir(f, layout)));
|
|
85
|
+
const skills = allSkills.filter((s) => !inPersonalPlugin(s.path, layout));
|
|
86
|
+
const tools = allTools.filter((t) => !inPersonalPlugin(t.path, layout));
|
|
79
87
|
const folderProbes = plugins.flatMap((g) => g.folders);
|
|
80
88
|
const discoverProbes = folderProbes.map(accessMdOf);
|
|
81
89
|
const skillProbes = skills.map((s) => skillMdOf(s.path));
|
|
@@ -123,7 +131,7 @@ export function createTeamsRoutes(
|
|
|
123
131
|
const accessMdOf = (folder: string) => `${folder}/access.md`;
|
|
124
132
|
const skillMdOf = (skillPath: string) => `${skillPath}/SKILL.md`;
|
|
125
133
|
/** Under `Plugins/personal-<id>/…` — one person's space, whatever it grants. */
|
|
126
|
-
const inPersonalPlugin = (repoPath: string) => {
|
|
127
|
-
const folder = pluginOfPath(repoPath);
|
|
134
|
+
const inPersonalPlugin = (repoPath: string, layout: KbLayout) => {
|
|
135
|
+
const folder = pluginOfPath(repoPath, layout);
|
|
128
136
|
return folder !== null && isPersonalPluginFolder(folder);
|
|
129
137
|
};
|
|
@@ -2,6 +2,7 @@ import type { Server as HttpServer } from 'node:http';
|
|
|
2
2
|
import express from 'express';
|
|
3
3
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
4
4
|
import { createSecretsVaultRoutes } from '../secrets-vault.routes.js';
|
|
5
|
+
import { testKbContext } from '../../../__tests__/kb-context.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* The aggregated `/connect/pending` surface: everything standing between the
|
|
@@ -85,6 +86,7 @@ async function baseUrlWith(auth: { userId?: string; email?: string }): Promise<s
|
|
|
85
86
|
app.use(
|
|
86
87
|
'/api',
|
|
87
88
|
createSecretsVaultRoutes({
|
|
89
|
+
kb: testKbContext(),
|
|
88
90
|
secretsVault,
|
|
89
91
|
toolManualService,
|
|
90
92
|
accessControl,
|
|
@@ -170,6 +172,7 @@ describe('GET /api/connect/pending — the workspace tier', () => {
|
|
|
170
172
|
app.use(
|
|
171
173
|
'/api',
|
|
172
174
|
createSecretsVaultRoutes({
|
|
175
|
+
kb: testKbContext(),
|
|
173
176
|
secretsVault: {
|
|
174
177
|
statusFor: async (_u: string, keys: string[]) =>
|
|
175
178
|
keys.map((key) => ({
|
|
@@ -258,6 +261,7 @@ describe('GET /api/connect/pending — readability', () => {
|
|
|
258
261
|
app.use(
|
|
259
262
|
'/api',
|
|
260
263
|
createSecretsVaultRoutes({
|
|
264
|
+
kb: testKbContext(),
|
|
261
265
|
secretsVault: {
|
|
262
266
|
statusFor: async (_u: string, keys: string[]) =>
|
|
263
267
|
keys.map((key) => ({
|
|
@@ -384,6 +388,7 @@ describe('GET /api/connect/pending — OAuth scope coverage', () => {
|
|
|
384
388
|
app.use(
|
|
385
389
|
'/api',
|
|
386
390
|
createSecretsVaultRoutes({
|
|
391
|
+
kb: testKbContext(),
|
|
387
392
|
secretsVault: vaultWithGranted(grantedScopes),
|
|
388
393
|
toolManualService: oauthTool,
|
|
389
394
|
accessControl,
|
|
@@ -478,6 +483,7 @@ describe('GET /api/connect/pending — tool sign-ins are not double-listed as st
|
|
|
478
483
|
app.use(
|
|
479
484
|
'/api',
|
|
480
485
|
createSecretsVaultRoutes({
|
|
486
|
+
kb: testKbContext(),
|
|
481
487
|
secretsVault: vault,
|
|
482
488
|
toolManualService: oauthTool,
|
|
483
489
|
accessControl,
|
|
@@ -538,6 +544,7 @@ describe('GET /api/connect/pending — a row of the wrong KIND is not "set up"',
|
|
|
538
544
|
app.use(
|
|
539
545
|
'/api',
|
|
540
546
|
createSecretsVaultRoutes({
|
|
547
|
+
kb: testKbContext(),
|
|
541
548
|
secretsVault: {
|
|
542
549
|
statusFor: async (_u: string, keys: string[]) => keys.map(opts.status),
|
|
543
550
|
list: async () => [],
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { describe, test, expect } from 'vitest';
|
|
2
|
+
import { UtcpClientConfigSerializer } from '@utcp/sdk';
|
|
2
3
|
import {
|
|
3
4
|
BevelSecretsVariableLoader,
|
|
5
|
+
DEFAULT_SECRETS_SCOPE,
|
|
6
|
+
bevelSecretsLoaderConfig,
|
|
4
7
|
registerBevelSecretsVariableLoader,
|
|
8
|
+
unregisterBevelSecretsVariableLoader,
|
|
5
9
|
} from '../secrets-variable-loader.js';
|
|
6
10
|
import type { ISecretsVaultService } from '../secrets-vault.contract.js';
|
|
7
11
|
|
|
@@ -51,4 +55,40 @@ describe('BevelSecretsVariableLoader', () => {
|
|
|
51
55
|
const loader = new BevelSecretsVariableLoader('');
|
|
52
56
|
expect(await loader.get('m_X')).toBeNull();
|
|
53
57
|
});
|
|
58
|
+
|
|
59
|
+
test('two knowledge bases in one process resolve the same user and key from their own vaults', async () => {
|
|
60
|
+
// One process, two vaults, one user id in each (ids are only unique
|
|
61
|
+
// within a knowledge base): a loader reads the vault registered under
|
|
62
|
+
// ITS scope, and a scope nobody registered resolves nothing.
|
|
63
|
+
registerBevelSecretsVariableLoader(fakeVault('user-1', { weather_WEATHER_KEY: 'sk-acme' }), 'acme');
|
|
64
|
+
registerBevelSecretsVariableLoader(fakeVault('user-1', { weather_WEATHER_KEY: 'sk-globex' }), 'globex');
|
|
65
|
+
expect(await new BevelSecretsVariableLoader('user-1', 'acme').get('weather_WEATHER_KEY')).toBe('sk-acme');
|
|
66
|
+
expect(await new BevelSecretsVariableLoader('user-1', 'globex').get('weather_WEATHER_KEY')).toBe('sk-globex');
|
|
67
|
+
expect(await new BevelSecretsVariableLoader('user-1', 'nobody').get('weather_WEATHER_KEY')).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test('the descriptor round-trips the scope through the serializer registry', async () => {
|
|
71
|
+
registerBevelSecretsVariableLoader(fakeVault('user-1', { weather_WEATHER_KEY: 'sk-acme' }), 'acme');
|
|
72
|
+
const config = new UtcpClientConfigSerializer().validateDict({
|
|
73
|
+
variables: {},
|
|
74
|
+
load_variables_from: [bevelSecretsLoaderConfig('user-1', 'acme')],
|
|
75
|
+
});
|
|
76
|
+
const [loader] = config.load_variables_from as BevelSecretsVariableLoader[];
|
|
77
|
+
expect(loader.scope).toBe('acme');
|
|
78
|
+
expect(await loader.get('weather_WEATHER_KEY')).toBe('sk-acme');
|
|
79
|
+
// Without a scope the descriptor names the single knowledge base's.
|
|
80
|
+
const [plain] = new UtcpClientConfigSerializer().validateDict({
|
|
81
|
+
variables: {},
|
|
82
|
+
load_variables_from: [bevelSecretsLoaderConfig('user-1')],
|
|
83
|
+
}).load_variables_from as BevelSecretsVariableLoader[];
|
|
84
|
+
expect(plain.scope).toBe(DEFAULT_SECRETS_SCOPE);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test('unregistering a scope makes its loaders resolve nothing', async () => {
|
|
88
|
+
registerBevelSecretsVariableLoader(fakeVault('user-1', { weather_WEATHER_KEY: 'sk-acme' }), 'evicted');
|
|
89
|
+
const loader = new BevelSecretsVariableLoader('user-1', 'evicted');
|
|
90
|
+
expect(await loader.get('weather_WEATHER_KEY')).toBe('sk-acme');
|
|
91
|
+
unregisterBevelSecretsVariableLoader('evicted');
|
|
92
|
+
expect(await loader.get('weather_WEATHER_KEY')).toBeNull();
|
|
93
|
+
});
|
|
54
94
|
});
|
|
@@ -2,6 +2,7 @@ import type { Server as HttpServer } from 'node:http';
|
|
|
2
2
|
import express from 'express';
|
|
3
3
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
4
4
|
import { createSecretsVaultRoutes } from '../secrets-vault.routes.js';
|
|
5
|
+
import { testKbContext } from '../../../__tests__/kb-context.js';
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* THE OWNER GATE: a tool's shared (admin) secrets — plain values and OAuth
|
|
@@ -91,6 +92,7 @@ async function baseUrlAs(email: string): Promise<string> {
|
|
|
91
92
|
app.use(
|
|
92
93
|
'/api',
|
|
93
94
|
createSecretsVaultRoutes({
|
|
95
|
+
kb: testKbContext(),
|
|
94
96
|
secretsVault,
|
|
95
97
|
toolManualService,
|
|
96
98
|
accessControl,
|
|
@@ -21,6 +21,8 @@ export {
|
|
|
21
21
|
} from './secrets-vault.contract.js';
|
|
22
22
|
export {
|
|
23
23
|
registerBevelSecretsVariableLoader,
|
|
24
|
+
unregisterBevelSecretsVariableLoader,
|
|
24
25
|
bevelSecretsLoaderConfig,
|
|
25
26
|
BEVEL_SECRETS_LOADER_TYPE,
|
|
27
|
+
DEFAULT_SECRETS_SCOPE,
|
|
26
28
|
} from './secrets-variable-loader.js';
|
|
@@ -18,29 +18,43 @@ const log = logger('secrets-vault');
|
|
|
18
18
|
* The `UtcpClient.create` path re-validates the whole config through the
|
|
19
19
|
* serializer registry, so a loader can't be handed in as a bare live object — it
|
|
20
20
|
* must round-trip through a registered serializer. We therefore put a plain
|
|
21
|
-
* descriptor `{ variable_loader_type, user_id }` in `load_variables_from`
|
|
22
|
-
* {@link bevelSecretsLoaderConfig}) and let the registered serializer
|
|
23
|
-
* live loader bound to the
|
|
24
|
-
*
|
|
25
|
-
*
|
|
21
|
+
* descriptor `{ variable_loader_type, user_id, scope }` in `load_variables_from`
|
|
22
|
+
* (via {@link bevelSecretsLoaderConfig}) and let the registered serializer
|
|
23
|
+
* rebuild a live loader bound to the vault registered under that scope.
|
|
24
|
+
*
|
|
25
|
+
* ONE VAULT PER SCOPE, NOT PER PROCESS. The serializer registry is UTCP's and
|
|
26
|
+
* process-wide, but a process can host several knowledge bases, each with a
|
|
27
|
+
* vault of its own, and a user id is only unique within one of them. So the
|
|
28
|
+
* descriptor names the scope its vault was registered under, and a loader
|
|
29
|
+
* reads through that vault alone: two knowledge bases whose users both stored
|
|
30
|
+
* `weather_WEATHER_KEY` never see each other's value. A single-tenant
|
|
31
|
+
* deployment registers under {@link DEFAULT_SECRETS_SCOPE} and names nothing.
|
|
32
|
+
* Swapping the vault backend (e.g. to a client's external secret manager) is
|
|
33
|
+
* just a different `ISecretsVaultService` passed to
|
|
34
|
+
* {@link registerBevelSecretsVariableLoader}.
|
|
26
35
|
*/
|
|
27
36
|
export const BEVEL_SECRETS_LOADER_TYPE = 'bevel_secrets';
|
|
28
37
|
|
|
38
|
+
/** The scope a deployment that hosts one knowledge base registers under. */
|
|
39
|
+
export const DEFAULT_SECRETS_SCOPE = 'default';
|
|
40
|
+
|
|
29
41
|
/**
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
42
|
+
* The vaults the reconstructed loaders read through, by scope. A composition
|
|
43
|
+
* root registers its vault before any client is built; a graph that is torn
|
|
44
|
+
* down unregisters it so a stale descriptor resolves nothing.
|
|
33
45
|
*/
|
|
34
|
-
|
|
46
|
+
const vaults = new Map<string, ISecretsVaultService>();
|
|
35
47
|
|
|
36
48
|
export class BevelSecretsVariableLoader implements VariableLoader {
|
|
37
49
|
readonly variable_loader_type = BEVEL_SECRETS_LOADER_TYPE;
|
|
38
50
|
readonly user_id: string;
|
|
51
|
+
readonly scope: string;
|
|
39
52
|
// VariableLoader is an open shape; allow arbitrary extra props.
|
|
40
53
|
[key: string]: unknown;
|
|
41
54
|
|
|
42
|
-
constructor(userId: string) {
|
|
55
|
+
constructor(userId: string, scope: string = DEFAULT_SECRETS_SCOPE) {
|
|
43
56
|
this.user_id = userId;
|
|
57
|
+
this.scope = scope;
|
|
44
58
|
}
|
|
45
59
|
|
|
46
60
|
/**
|
|
@@ -52,9 +66,10 @@ export class BevelSecretsVariableLoader implements VariableLoader {
|
|
|
52
66
|
* harvest a secret the user configured for a different manual.
|
|
53
67
|
*/
|
|
54
68
|
async get(effectiveKey: string): Promise<string | null> {
|
|
55
|
-
|
|
69
|
+
const vault = vaults.get(this.scope);
|
|
70
|
+
if (!vault || !this.user_id) return null;
|
|
56
71
|
try {
|
|
57
|
-
return await
|
|
72
|
+
return await vault.resolve(this.user_id, effectiveKey);
|
|
58
73
|
} catch (err) {
|
|
59
74
|
// Log the fault so a backend failure is distinguishable from a merely
|
|
60
75
|
// unset secret (resolve returning null) when troubleshooting.
|
|
@@ -66,15 +81,18 @@ export class BevelSecretsVariableLoader implements VariableLoader {
|
|
|
66
81
|
|
|
67
82
|
class BevelSecretsVariableLoaderSerializer extends Serializer<VariableLoader> {
|
|
68
83
|
toDict(obj: VariableLoader): Record<string, unknown> {
|
|
84
|
+
const loader = obj as BevelSecretsVariableLoader;
|
|
69
85
|
return {
|
|
70
86
|
variable_loader_type: BEVEL_SECRETS_LOADER_TYPE,
|
|
71
|
-
user_id:
|
|
87
|
+
user_id: loader.user_id ?? '',
|
|
88
|
+
scope: loader.scope ?? DEFAULT_SECRETS_SCOPE,
|
|
72
89
|
};
|
|
73
90
|
}
|
|
74
91
|
|
|
75
92
|
validateDict(obj: Record<string, unknown>): VariableLoader {
|
|
76
93
|
const userId = typeof obj.user_id === 'string' ? obj.user_id : '';
|
|
77
|
-
|
|
94
|
+
const scope = typeof obj.scope === 'string' && obj.scope ? obj.scope : DEFAULT_SECRETS_SCOPE;
|
|
95
|
+
return new BevelSecretsVariableLoader(userId, scope);
|
|
78
96
|
}
|
|
79
97
|
}
|
|
80
98
|
|
|
@@ -91,14 +109,26 @@ VariableLoaderSerializer.registerVariableLoader(
|
|
|
91
109
|
);
|
|
92
110
|
|
|
93
111
|
/**
|
|
94
|
-
* Bind the
|
|
95
|
-
*
|
|
112
|
+
* Bind the vault the loaders of `scope` read through. Called once per
|
|
113
|
+
* knowledge base at composition time; before it runs, loaders of that scope
|
|
114
|
+
* resolve to null.
|
|
96
115
|
*/
|
|
97
|
-
export function registerBevelSecretsVariableLoader(
|
|
98
|
-
|
|
116
|
+
export function registerBevelSecretsVariableLoader(
|
|
117
|
+
secretsVault: ISecretsVaultService,
|
|
118
|
+
scope: string = DEFAULT_SECRETS_SCOPE,
|
|
119
|
+
): void {
|
|
120
|
+
vaults.set(scope, secretsVault);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/** Forget a scope's vault — the last step of tearing a knowledge base's graph down. */
|
|
124
|
+
export function unregisterBevelSecretsVariableLoader(scope: string = DEFAULT_SECRETS_SCOPE): void {
|
|
125
|
+
vaults.delete(scope);
|
|
99
126
|
}
|
|
100
127
|
|
|
101
|
-
/**
|
|
102
|
-
|
|
103
|
-
|
|
128
|
+
/**
|
|
129
|
+
* The plain descriptor to place in a `UtcpClientConfig.load_variables_from`
|
|
130
|
+
* for a given user of the knowledge base registered under `scope`.
|
|
131
|
+
*/
|
|
132
|
+
export function bevelSecretsLoaderConfig(userId: string, scope: string = DEFAULT_SECRETS_SCOPE): Record<string, unknown> {
|
|
133
|
+
return { variable_loader_type: BEVEL_SECRETS_LOADER_TYPE, user_id: userId, scope };
|
|
104
134
|
}
|
|
@@ -3,7 +3,6 @@ import { logger } from '../../shared/logging.js';
|
|
|
3
3
|
|
|
4
4
|
const log = logger('secrets');
|
|
5
5
|
import { createHmac, randomBytes, timingSafeEqual } from 'node:crypto';
|
|
6
|
-
import { DEFAULT_BRANCH } from '@bevel-software/platform-shared';
|
|
7
6
|
import {
|
|
8
7
|
InvalidSecretError,
|
|
9
8
|
SecretNotFoundError,
|
|
@@ -17,11 +16,13 @@ import type { IToolManualService, ToolManualSummary, ToolVariable } from '../too
|
|
|
17
16
|
import type { IConnectionProbeService } from '../connection-probe/connection-probe.contract.js';
|
|
18
17
|
import { utcpNamespacedKey } from '../../shared/utcp-namespace.js';
|
|
19
18
|
import type { IAccessControl } from '../access/access-control.interface.js';
|
|
20
|
-
import {
|
|
19
|
+
import type { KbContext } from '../../shared/kb-context.js';
|
|
21
20
|
import '../auth/auth.middleware.js'; // Express Request augmentation (req.userId / req.userEmail)
|
|
22
21
|
|
|
23
22
|
export interface SecretsVaultRoutesDeps {
|
|
24
23
|
secretsVault: ISecretsVaultService;
|
|
24
|
+
/** The released branch's clone — where the `.tool` files the access verdicts are read from live. */
|
|
25
|
+
kb: Pick<KbContext, 'defaultWorkspaceId'>;
|
|
25
26
|
/** Source of `.tool` manuals + their declared variable scopes (default-branch catalog). */
|
|
26
27
|
toolManualService: IToolManualService;
|
|
27
28
|
/** Gates who may set a tool's ADMIN (shared) secrets — writers of the `.tool` file. */
|
|
@@ -79,16 +80,16 @@ export function isSafeReturnPath(returnTo: unknown): returnTo is string {
|
|
|
79
80
|
* `req.userId` — secrets are private per user. Mounted behind the JWT middleware.
|
|
80
81
|
*/
|
|
81
82
|
export function createSecretsVaultRoutes(deps: SecretsVaultRoutesDeps): express.Router {
|
|
82
|
-
const { secretsVault, toolManualService, accessControl, connectionProbe } = deps;
|
|
83
|
+
const { secretsVault, toolManualService, accessControl, connectionProbe, kb } = deps;
|
|
83
84
|
const router = express.Router();
|
|
84
85
|
// A FUNCTION, not a constant. Routers are constructed at boot, and on a
|
|
85
86
|
// deployment configured through the setup screen the branch model does not
|
|
86
|
-
// exist yet at that moment —
|
|
87
|
-
//
|
|
87
|
+
// exist yet at that moment — the default branch is still ''. The context
|
|
88
|
+
// learns it when setup applies the model, but only reads INSIDE a function
|
|
88
89
|
// body see it; a construction-time capture would keep handing an empty
|
|
89
90
|
// workspace id to the access resolver until the next restart ("Invalid
|
|
90
91
|
// workspace ID" on every /secrets/tools call).
|
|
91
|
-
const defaultWs = () =>
|
|
92
|
+
const defaultWs = () => kb.defaultWorkspaceId();
|
|
92
93
|
|
|
93
94
|
// The vault key = the exact key UTCP looks the var up under (doubles underscores
|
|
94
95
|
// in the manual namespace), so storage and resolution agree for snake_case ids.
|
|
@@ -149,20 +149,12 @@ describe('DeploymentSettingsService — secrets', () => {
|
|
|
149
149
|
expect(token).not.toHaveProperty('value');
|
|
150
150
|
});
|
|
151
151
|
|
|
152
|
-
it('
|
|
152
|
+
it('keeps a stored token out of the process environment: git reads it per call', async () => {
|
|
153
153
|
const { db } = makeDb();
|
|
154
154
|
const settings = new DeploymentSettingsService(db, ENC_KEY);
|
|
155
155
|
await settings.save({ gitToken: 'ghp_fromsetup' }, null);
|
|
156
|
-
expect(process.env.GITHUB_TOKEN).
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
it('does not overwrite a git token the environment supplied', async () => {
|
|
160
|
-
process.env.GIT_TOKEN = 'ghp_fromenv';
|
|
161
|
-
process.env.GITHUB_TOKEN = 'ghp_fromenv';
|
|
162
|
-
const { db } = makeDb();
|
|
163
|
-
const settings = new DeploymentSettingsService(db, ENC_KEY);
|
|
164
|
-
settings.syncGitTokenEnv();
|
|
165
|
-
expect(process.env.GITHUB_TOKEN).toBe('ghp_fromenv');
|
|
156
|
+
expect(process.env.GITHUB_TOKEN).toBeUndefined();
|
|
157
|
+
expect(settings.resolve('gitToken')).toBe('ghp_fromsetup');
|
|
166
158
|
});
|
|
167
159
|
|
|
168
160
|
it('refuses to store a secret with no encryption key rather than writing plaintext', async () => {
|
|
@@ -528,3 +520,24 @@ describe('DeploymentSettingsService — validation', () => {
|
|
|
528
520
|
).toEqual([]);
|
|
529
521
|
});
|
|
530
522
|
});
|
|
523
|
+
|
|
524
|
+
describe('DeploymentSettingsService — an environment of its own', () => {
|
|
525
|
+
it('resolves the env-first layer from the environment it was given, not the process\'s', async () => {
|
|
526
|
+
process.env.KB_REPO_URL = 'https://host.example/leaks-into-every-tenant.git';
|
|
527
|
+
const { db } = makeDb();
|
|
528
|
+
const own = new DeploymentSettingsService(db, ENC_KEY, undefined, {
|
|
529
|
+
env: { KB_REPO_URL: 'https://github.com/acme/kb.git', GIT_USERNAME: 'oauth2' },
|
|
530
|
+
});
|
|
531
|
+
await own.load();
|
|
532
|
+
expect(own.resolve('kbRepoUrl')).toBe('https://github.com/acme/kb.git');
|
|
533
|
+
expect(own.sourceOf('kbRepoUrl')).toBe('env');
|
|
534
|
+
expect(own.resolve('gitUsername')).toBe('oauth2');
|
|
535
|
+
// What the given environment leaves out is not taken from the process either.
|
|
536
|
+
expect(own.resolve('gitToken')).toBe('');
|
|
537
|
+
expect(own.sourceOf('gitToken')).toBe('unset');
|
|
538
|
+
// A service built without one keeps reading the process, as before.
|
|
539
|
+
const shared = new DeploymentSettingsService(db, ENC_KEY);
|
|
540
|
+
await shared.load();
|
|
541
|
+
expect(shared.resolve('kbRepoUrl')).toBe('https://host.example/leaks-into-every-tenant.git');
|
|
542
|
+
});
|
|
543
|
+
});
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
rootFolderListerFor,
|
|
11
11
|
type GitRunner,
|
|
12
12
|
} from '../git-root-folders.js';
|
|
13
|
-
import type
|
|
13
|
+
import { NO_GIT_CREDENTIALS, type IGitRunner } from '../../../shared/git.contract.js';
|
|
14
14
|
|
|
15
15
|
const LISTING = {
|
|
16
16
|
url: 'https://example.com/acme/kb.git',
|
|
@@ -226,6 +226,7 @@ describe('rootFolderListerFor — the listing runs through the deployment git po
|
|
|
226
226
|
const outcomes = ['', 'KnowledgeBase\0Plugins\0'];
|
|
227
227
|
const port: IGitRunner = {
|
|
228
228
|
defaultTimeoutMs: 1000,
|
|
229
|
+
credentials: NO_GIT_CREDENTIALS,
|
|
229
230
|
run: (async (cwd: string, args: string[], opts: { env?: NodeJS.ProcessEnv; timeoutMs?: number } = {}) => {
|
|
230
231
|
calls.push({ cwd, args, opts });
|
|
231
232
|
return { stdout: outcomes.shift() ?? '', stderr: '' };
|
|
@@ -6,6 +6,7 @@ import { createSetupRoutes } from '../setup.routes.js';
|
|
|
6
6
|
import { DeploymentSettingsService } from '../deployment-settings.service.js';
|
|
7
7
|
import type { Database } from '../../database/connection.js';
|
|
8
8
|
import type { IAdminAccessService } from '../../admin/admin.interface.js';
|
|
9
|
+
import { testKbContext } from '../../../__tests__/kb-context.js';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* A boot that survived an unreachable remote leaves the RUNNER standing on a
|
|
@@ -68,7 +69,7 @@ function listen(runner: { runAll(): Promise<void>; lastFailure(): string | null
|
|
|
68
69
|
});
|
|
69
70
|
app.use(
|
|
70
71
|
'/api',
|
|
71
|
-
createSetupRoutes(settings, { isAdmin: async () => true } as IAdminAccessService, runner),
|
|
72
|
+
createSetupRoutes(settings, { isAdmin: async () => true } as IAdminAccessService, runner, testKbContext()),
|
|
72
73
|
);
|
|
73
74
|
server = app.listen(0);
|
|
74
75
|
const { port } = server.address() as AddressInfo;
|