@bevel-software/platform-core-backend 0.33.0 → 0.35.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/agent-guide/access-control.md +146 -289
- package/agent-guide/conventions.md +23 -25
- package/agent-guide/directory-structure.md +72 -120
- package/agent-guide/drafts-and-change-requests.md +92 -0
- package/agent-guide/for-git-users.md +47 -0
- package/agent-guide/glossary.md +36 -0
- package/agent-guide/how-agents-find-things.md +49 -0
- package/agent-guide/html-views.md +239 -8
- package/agent-guide/new-knowledge-base.md +9 -8
- package/agent-guide/skills.md +67 -42
- package/agent-guide/start-here.md +65 -0
- package/agent-guide/tool-manuals.md +133 -155
- package/agent-guide/tools.md +67 -0
- package/agent-guide/where-a-new-file-goes.md +45 -28
- package/dist/core/catalog-revision.d.ts +12 -1
- package/dist/core/catalog-revision.d.ts.map +1 -1
- package/dist/core/catalog-revision.js +23 -3
- package/dist/core/catalog-revision.js.map +1 -1
- package/dist/core/core-ports.d.ts +41 -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.map +1 -1
- package/dist/core/create-core-server.js +15 -8
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +22 -5
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +44 -16
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +16 -0
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +12 -2
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +39 -9
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +15 -3
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +239 -75
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-mutation.service.d.ts +22 -24
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
- package/dist/modules/access/access-mutation.service.js +48 -51
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-view.d.ts.map +1 -1
- package/dist/modules/access/access-view.js +12 -11
- package/dist/modules/access/access-view.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts +3 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +58 -33
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/groups-admin.routes.d.ts.map +1 -1
- package/dist/modules/access/groups-admin.routes.js +4 -2
- package/dist/modules/access/groups-admin.routes.js.map +1 -1
- package/dist/modules/access/groups-admin.service.d.ts +44 -13
- package/dist/modules/access/groups-admin.service.d.ts.map +1 -1
- package/dist/modules/access/groups-admin.service.js +80 -38
- package/dist/modules/access/groups-admin.service.js.map +1 -1
- package/dist/modules/access/groups-edit.d.ts +1 -1
- package/dist/modules/access/groups-edit.d.ts.map +1 -1
- package/dist/modules/access/groups-edit.js +1 -1
- package/dist/modules/access/groups-edit.js.map +1 -1
- package/dist/modules/access/index.d.ts +1 -1
- package/dist/modules/access/index.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.d.ts +116 -24
- package/dist/modules/access/reference-scan.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.js +305 -44
- package/dist/modules/access/reference-scan.js.map +1 -1
- package/dist/modules/access/roles-admin.service.d.ts +17 -8
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +32 -23
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +35 -10
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +60 -20
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/access-model/access-splice.d.ts +22 -18
- package/dist/modules/access-model/access-splice.d.ts.map +1 -1
- package/dist/modules/access-model/access-splice.js +20 -14
- package/dist/modules/access-model/access-splice.js.map +1 -1
- package/dist/modules/access-model/group-files.d.ts +1 -0
- package/dist/modules/access-model/group-files.d.ts.map +1 -1
- package/dist/modules/access-model/group-files.js +5 -1
- package/dist/modules/access-model/group-files.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.d.ts +47 -7
- package/dist/modules/agent-guide/agent-guide.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.js +103 -13
- package/dist/modules/agent-guide/agent-guide.js.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.d.ts +6 -2
- package/dist/modules/agent-guide/agent-guide.tools.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.js +46 -22
- package/dist/modules/agent-guide/agent-guide.tools.js.map +1 -1
- package/dist/modules/agent-guide/guide-budget.d.ts +48 -0
- package/dist/modules/agent-guide/guide-budget.d.ts.map +1 -0
- package/dist/modules/agent-guide/guide-budget.js +67 -0
- package/dist/modules/agent-guide/guide-budget.js.map +1 -0
- package/dist/modules/agent-guide/index.d.ts +2 -1
- package/dist/modules/agent-guide/index.d.ts.map +1 -1
- package/dist/modules/agent-guide/index.js +2 -1
- package/dist/modules/agent-guide/index.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +3 -1
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +7 -1
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +5 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.js +26 -9
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -1
- package/dist/modules/agent-scope/agent-scope.contract.d.ts +67 -0
- package/dist/modules/agent-scope/agent-scope.contract.d.ts.map +1 -0
- package/dist/modules/agent-scope/agent-scope.contract.js +27 -0
- package/dist/modules/agent-scope/agent-scope.contract.js.map +1 -0
- package/dist/modules/agent-scope/connection-scope.d.ts +111 -0
- package/dist/modules/agent-scope/connection-scope.d.ts.map +1 -0
- package/dist/modules/agent-scope/connection-scope.js +165 -0
- package/dist/modules/agent-scope/connection-scope.js.map +1 -0
- package/dist/modules/agent-scope/index.d.ts +3 -0
- package/dist/modules/agent-scope/index.d.ts.map +1 -0
- package/dist/modules/agent-scope/index.js +3 -0
- package/dist/modules/agent-scope/index.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
- package/dist/modules/audit/agent-audit.service.js +2 -0
- package/dist/modules/audit/agent-audit.service.js.map +1 -1
- package/dist/modules/audit/audit.contract.d.ts +6 -0
- package/dist/modules/audit/audit.contract.d.ts.map +1 -1
- package/dist/modules/audit/audit.contract.js.map +1 -1
- package/dist/modules/auth/account-admission.d.ts +12 -0
- package/dist/modules/auth/account-admission.d.ts.map +1 -1
- package/dist/modules/auth/account-admission.js +15 -0
- package/dist/modules/auth/account-admission.js.map +1 -1
- package/dist/modules/auth/auth.middleware.d.ts +27 -1
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
- package/dist/modules/auth/auth.middleware.js +42 -4
- package/dist/modules/auth/auth.middleware.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts +13 -9
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +35 -29
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +55 -6
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +128 -34
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/index.d.ts +1 -1
- package/dist/modules/auth/index.d.ts.map +1 -1
- package/dist/modules/auth/index.js +1 -1
- package/dist/modules/auth/index.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +2 -9
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +2 -2
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts +0 -12
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +1 -38
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +68 -0
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +33 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts +8 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.js +13 -2
- package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
- package/dist/modules/embed/embed.tools.d.ts.map +1 -1
- package/dist/modules/embed/embed.tools.js +5 -0
- package/dist/modules/embed/embed.tools.js.map +1 -1
- package/dist/modules/kb-fs/index.d.ts +2 -0
- package/dist/modules/kb-fs/index.d.ts.map +1 -1
- package/dist/modules/kb-fs/index.js +1 -0
- package/dist/modules/kb-fs/index.js.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +7 -1
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +26 -6
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +22 -7
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-fs/tmp-ref.d.ts +36 -0
- package/dist/modules/kb-fs/tmp-ref.d.ts.map +1 -0
- package/dist/modules/kb-fs/tmp-ref.js +76 -0
- package/dist/modules/kb-fs/tmp-ref.js.map +1 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +7 -0
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +14 -1
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.routes.d.ts +7 -1
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.routes.js +39 -4
- package/dist/modules/mcp/mcp.routes.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +11 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +74 -48
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +24 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +45 -10
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts +9 -0
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +34 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.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.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +18 -2
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +5 -1
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +32 -5
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +11 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/db-secrets-vault.service.js +159 -24
- package/dist/modules/secrets-vault/db-secrets-vault.service.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-vault.contract.d.ts +53 -11
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.js +27 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts +9 -0
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +100 -42
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/oidc-check.d.ts.map +1 -1
- package/dist/modules/settings/oidc-check.js +5 -17
- package/dist/modules/settings/oidc-check.js.map +1 -1
- package/dist/modules/skills/index.d.ts +3 -3
- package/dist/modules/skills/index.d.ts.map +1 -1
- package/dist/modules/skills/index.js +0 -2
- package/dist/modules/skills/index.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +16 -0
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +6 -1
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +25 -13
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +11 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.interface.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts +1 -0
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +4 -1
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/index.d.ts +1 -1
- package/dist/modules/tool-auth/index.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +9 -0
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.js +1 -0
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +27 -3
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +32 -6
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts +7 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +3 -0
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-helpers/tool-def.js +1 -1
- package/dist/modules/tool-helpers/tool-def.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts +15 -0
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +19 -0
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +10 -0
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
- package/dist/modules/tool-helpers/validate-token.d.ts +3 -1
- package/dist/modules/tool-helpers/validate-token.d.ts.map +1 -1
- package/dist/modules/tool-helpers/validate-token.js +1 -1
- package/dist/modules/tool-helpers/validate-token.js.map +1 -1
- package/dist/modules/tool-manuals/index.d.ts +3 -3
- package/dist/modules/tool-manuals/index.d.ts.map +1 -1
- package/dist/modules/tool-manuals/index.js +0 -2
- package/dist/modules/tool-manuals/index.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts +7 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +69 -38
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +46 -6
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +7 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +41 -4
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +24 -13
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +138 -59
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts +8 -2
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +56 -20
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/manual.routes.d.ts +8 -1
- package/dist/modules/tool-registry/manual.routes.d.ts.map +1 -1
- package/dist/modules/tool-registry/manual.routes.js +27 -7
- package/dist/modules/tool-registry/manual.routes.js.map +1 -1
- package/dist/modules/tool-registry/tool.contract.d.ts +7 -0
- package/dist/modules/tool-registry/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-registry/tool.contract.js.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +36 -27
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +2 -2
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +20 -35
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +2 -1
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +3 -0
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -1
- package/dist/modules/workspace/agent-access.gate.js +1 -1
- package/dist/modules/workspace/agent-access.gate.js.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +28 -4
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js +61 -40
- package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
- package/dist/modules/workspace/index.d.ts +8 -0
- package/dist/modules/workspace/index.d.ts.map +1 -1
- package/dist/modules/workspace/index.js +8 -0
- package/dist/modules/workspace/index.js.map +1 -1
- package/dist/modules/workspace/nul-scan.d.ts +19 -0
- package/dist/modules/workspace/nul-scan.d.ts.map +1 -0
- package/dist/modules/workspace/nul-scan.js +55 -0
- package/dist/modules/workspace/nul-scan.js.map +1 -0
- package/dist/modules/workspace/pattern-matcher.contract.d.ts +110 -27
- package/dist/modules/workspace/pattern-matcher.contract.d.ts.map +1 -1
- package/dist/modules/workspace/pattern-matcher.contract.js +30 -13
- package/dist/modules/workspace/pattern-matcher.contract.js.map +1 -1
- package/dist/modules/workspace/ripgrep-search.d.ts +54 -0
- package/dist/modules/workspace/ripgrep-search.d.ts.map +1 -0
- package/dist/modules/workspace/ripgrep-search.js +657 -0
- package/dist/modules/workspace/ripgrep-search.js.map +1 -0
- package/dist/modules/workspace/ripgrep-version.d.ts +15 -0
- package/dist/modules/workspace/ripgrep-version.d.ts.map +1 -0
- package/dist/modules/workspace/ripgrep-version.js +31 -0
- package/dist/modules/workspace/ripgrep-version.js.map +1 -0
- package/dist/modules/workspace/startup/beside-checkout.d.ts +8 -5
- package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -1
- package/dist/modules/workspace/startup/beside-checkout.js +14 -5
- package/dist/modules/workspace/startup/beside-checkout.js.map +1 -1
- package/dist/modules/workspace/worker-pool.d.ts +3 -4
- package/dist/modules/workspace/worker-pool.d.ts.map +1 -1
- package/dist/modules/workspace/worker-pool.js.map +1 -1
- package/dist/modules/workspace/workspace-tmp.d.ts +146 -0
- package/dist/modules/workspace/workspace-tmp.d.ts.map +1 -0
- package/dist/modules/workspace/workspace-tmp.js +435 -0
- package/dist/modules/workspace/workspace-tmp.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +5 -26
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +47 -6
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +86 -6
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +3 -2
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +531 -137
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/shared/oauth-token-error.d.ts +23 -0
- package/dist/shared/oauth-token-error.d.ts.map +1 -0
- package/dist/shared/oauth-token-error.js +47 -0
- package/dist/shared/oauth-token-error.js.map +1 -0
- package/dist/shared/path-order.d.ts +28 -8
- package/dist/shared/path-order.d.ts.map +1 -1
- package/dist/shared/path-order.js +37 -8
- package/dist/shared/path-order.js.map +1 -1
- package/dist/shared/read-capped.d.ts +19 -0
- package/dist/shared/read-capped.d.ts.map +1 -0
- package/dist/shared/read-capped.js +45 -0
- package/dist/shared/read-capped.js.map +1 -0
- package/migrations/0022_session_version.sql +6 -0
- package/migrations/0023_agent_path.sql +3 -0
- package/migrations/meta/0022_snapshot.json +2360 -0
- package/migrations/meta/0023_snapshot.json +2378 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +4 -3
- package/src/__tests__/hexis-catalog.ts +144 -0
- package/src/__tests__/pg-scratch.test.ts +69 -0
- package/src/__tests__/pg-scratch.ts +31 -0
- package/src/__tests__/real-disk.ts +21 -0
- package/src/__tests__/slow-ripgrep.ts +65 -0
- package/src/__tests__/tokens.ts +19 -0
- package/src/__tests__/tool-manuals.ts +32 -0
- package/src/__tests__/tool-wiring.ts +25 -0
- package/src/core/__tests__/boot-without-ripgrep.test.ts +34 -0
- package/src/core/__tests__/catalog-revision.test.ts +89 -0
- package/src/core/__tests__/damaged-document.tools.test.ts +2 -2
- package/src/core/__tests__/gated-boot.test.ts +8 -1
- package/src/core/__tests__/lifecycle.test.ts +46 -13
- package/src/core/__tests__/oauth-sign-in-real-file.test.ts +179 -0
- package/src/core/catalog-revision.ts +24 -2
- package/src/core/core-ports.ts +42 -0
- package/src/core/create-core-server.ts +14 -1
- package/src/core/create-core-services.ts +62 -15
- package/src/core/lifecycle.ts +26 -2
- package/src/index.ts +1 -1
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +12 -0
- package/src/modules/access/__tests__/access-control.colliding-name-cases.test.ts +113 -0
- package/src/modules/access/__tests__/access-control.frontmatter-head.test.ts +117 -0
- package/src/modules/access/__tests__/access-control.group-named-admin.test.ts +122 -0
- package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +50 -0
- package/src/modules/access/__tests__/access-declarations.test.ts +19 -0
- package/src/modules/access/__tests__/access-groups.test.ts +55 -22
- package/src/modules/access/__tests__/access-mutation.service.test.ts +85 -59
- package/src/modules/access/__tests__/access-restrict-here.test.ts +7 -5
- package/src/modules/access/__tests__/access.routes.admins.test.ts +1 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +2 -0
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +2 -0
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +50 -14
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +2 -1
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +1 -0
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +52 -10
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +18 -13
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +2 -0
- package/src/modules/access/__tests__/grant-sources.test.ts +20 -15
- package/src/modules/access/__tests__/groups-admin.routes.test.ts +61 -0
- package/src/modules/access/__tests__/groups-admin.service.test.ts +211 -18
- package/src/modules/access/__tests__/holder-changes.test.ts +127 -0
- package/src/modules/access/__tests__/reference-scan.test.ts +366 -14
- package/src/modules/access/__tests__/roles-admin.security.test.ts +1 -1
- package/src/modules/access/__tests__/roles-admin.service.test.ts +43 -22
- package/src/modules/access/__tests__/roles-capabilities.test.ts +6 -2
- package/src/modules/access/__tests__/roles.routes.test.ts +1 -1
- package/src/modules/access/access-control.interface.ts +43 -10
- package/src/modules/access/access-control.service.ts +250 -72
- package/src/modules/access/access-mutation.service.ts +48 -53
- package/src/modules/access/access-view.ts +12 -10
- package/src/modules/access/access.routes.ts +66 -37
- package/src/modules/access/groups-admin.routes.ts +4 -2
- package/src/modules/access/groups-admin.service.ts +114 -44
- package/src/modules/access/groups-edit.ts +1 -1
- package/src/modules/access/index.ts +1 -1
- package/src/modules/access/reference-scan.ts +319 -46
- package/src/modules/access/roles-admin.service.ts +43 -26
- package/src/modules/access/synced-groups-writer.ts +1 -1
- package/src/modules/access-model/__tests__/access-grammar.test.ts +38 -1
- package/src/modules/access-model/__tests__/access-splice.test.ts +50 -8
- package/src/modules/access-model/access-grammar.ts +65 -20
- package/src/modules/access-model/access-splice.ts +31 -23
- package/src/modules/access-model/group-files.ts +5 -0
- package/src/modules/agent-guide/__tests__/agent-guide.test.ts +110 -25
- package/src/modules/agent-guide/__tests__/agent-guide.tools.test.ts +38 -11
- package/src/modules/agent-guide/__tests__/guide-budget.test.ts +95 -0
- package/src/modules/agent-guide/__tests__/guide-eval.test.ts +182 -0
- package/src/modules/agent-guide/__tests__/guide-matches-code.test.ts +263 -0
- package/src/modules/agent-guide/__tests__/tool-surface.json +514 -0
- package/src/modules/agent-guide/__tests__/tool-surface.test.ts +75 -0
- package/src/modules/agent-guide/agent-guide.tools.ts +51 -22
- package/src/modules/agent-guide/agent-guide.ts +120 -13
- package/src/modules/agent-guide/guide-budget.ts +73 -0
- package/src/modules/agent-guide/index.ts +12 -0
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +5 -4
- package/src/modules/agent-instructions/compose.ts +7 -1
- package/src/modules/agent-instructions/shared-file-rules.ts +27 -9
- package/src/modules/agent-scope/__tests__/agent-surfaces.connect-as.test.ts +421 -0
- package/src/modules/agent-scope/__tests__/connection-scope.test.ts +46 -0
- package/src/modules/agent-scope/__tests__/in-memory-kb.ts +148 -0
- package/src/modules/agent-scope/agent-scope.contract.ts +83 -0
- package/src/modules/agent-scope/connection-scope.ts +199 -0
- package/src/modules/agent-scope/index.ts +15 -0
- package/src/modules/audit/agent-audit.service.ts +2 -0
- package/src/modules/audit/audit.contract.ts +6 -0
- package/src/modules/auth/__tests__/auth.middleware.test.ts +30 -2
- package/src/modules/auth/__tests__/auth.routes.test.ts +71 -5
- package/src/modules/auth/__tests__/auth.service.test.ts +90 -9
- package/src/modules/auth/__tests__/password-change-sessions.pg.test.ts +269 -0
- package/src/modules/auth/account-admission.ts +19 -0
- package/src/modules/auth/auth.middleware.ts +45 -4
- package/src/modules/auth/auth.routes.ts +46 -29
- package/src/modules/auth/auth.service.ts +135 -34
- package/src/modules/auth/index.ts +2 -0
- package/src/modules/auth/oidc-auth-provider.ts +2 -9
- package/src/modules/code-mode/code-mode.tool.ts +2 -2
- package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +5 -24
- package/src/modules/connection-probe/connection-probe.service.ts +1 -34
- package/src/modules/database/__tests__/session-version-migration.pg.test.ts +133 -0
- package/src/modules/database/core-schema.ts +33 -0
- package/src/modules/declared-variables/__tests__/declared-variables.route.test.ts +44 -1
- package/src/modules/declared-variables/declared-variables.routes.ts +12 -1
- package/src/modules/embed/__tests__/embed.tools.test.ts +12 -0
- package/src/modules/embed/embed.tools.ts +5 -0
- package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +25 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +53 -8
- package/src/modules/kb-fs/index.ts +2 -0
- package/src/modules/kb-fs/locking-filesystem.ts +7 -1
- package/src/modules/kb-fs/repo-path.ts +33 -7
- package/src/modules/kb-fs/tmp-ref.ts +81 -0
- package/src/modules/mcp/__tests__/connect-as.pg.test.ts +137 -0
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +29 -5
- package/src/modules/mcp/__tests__/mcp-routes-harness.ts +8 -0
- package/src/modules/mcp/__tests__/mcp.connect-as.test.ts +195 -0
- package/src/modules/mcp/__tests__/mcp.routes.connect-as.test.ts +192 -0
- package/src/modules/mcp/__tests__/oauth-consent.connect-as.test.ts +146 -0
- package/src/modules/mcp/mcp-auth.middleware.ts +19 -2
- package/src/modules/mcp/mcp.routes.ts +39 -3
- package/src/modules/mcp/mcp.service.ts +112 -52
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +46 -8
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +41 -1
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +38 -2
- package/src/modules/plugins/index.ts +1 -1
- package/src/modules/plugins/plugin-links.ts +19 -2
- package/src/modules/plugins/plugins.routes.ts +35 -4
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +113 -0
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +430 -3
- package/src/modules/secrets-vault/__tests__/oauth-live-declaration.route.test.ts +218 -0
- package/src/modules/secrets-vault/__tests__/oauth-return-to.route.test.ts +39 -6
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +170 -27
- package/src/modules/secrets-vault/index.ts +1 -1
- package/src/modules/secrets-vault/secrets-vault.contract.ts +61 -11
- package/src/modules/secrets-vault/secrets-vault.routes.ts +114 -42
- package/src/modules/settings/oidc-check.ts +5 -18
- package/src/modules/skills/__tests__/skills.service.test.ts +34 -0
- package/src/modules/skills/index.ts +7 -2
- package/src/modules/skills/skills.contract.ts +17 -0
- package/src/modules/skills/skills.service.ts +5 -1
- package/src/modules/skills/skills.tools.ts +45 -14
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +4 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +11 -1
- package/src/modules/tool-auth/external-api-key.service.ts +5 -2
- package/src/modules/tool-auth/index.ts +1 -1
- package/src/modules/tool-auth/internal-token.service.ts +10 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +45 -3
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +19 -11
- package/src/modules/tool-helpers/__tests__/can-write.tools.test.ts +3 -1
- package/src/modules/tool-helpers/__tests__/route-tool-schemas.catalog.test.ts +38 -0
- package/src/modules/tool-helpers/tool-context.ts +10 -0
- package/src/modules/tool-helpers/tool-def.ts +1 -1
- package/src/modules/tool-helpers/tool-handler.ts +34 -0
- package/src/modules/tool-helpers/tool.contract.ts +10 -0
- package/src/modules/tool-helpers/validate-token.ts +4 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +80 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +197 -11
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +42 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +99 -8
- package/src/modules/tool-manuals/index.ts +6 -2
- package/src/modules/tool-manuals/mcp-json-discovery.ts +73 -34
- package/src/modules/tool-manuals/tool-manuals.contract.ts +40 -6
- package/src/modules/tool-manuals/tool-manuals.routes.ts +40 -3
- package/src/modules/tool-manuals/tool-manuals.service.ts +169 -61
- package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -25
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +6 -113
- package/src/modules/tool-registry/manual.routes.ts +26 -5
- package/src/modules/tool-registry/tool.contract.ts +7 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +1 -1
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +1 -1
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +54 -3
- package/src/modules/workflow/agent-tools/workflow.tools.ts +36 -27
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +130 -3
- package/src/modules/workflow/git/git.service.ts +29 -48
- package/src/modules/workflow/workflow.service.ts +5 -0
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -2
- package/src/modules/workspace/__tests__/holds-nul.test.ts +66 -0
- package/src/modules/workspace/__tests__/rest-tool-arguments.test.ts +3 -3
- package/src/modules/workspace/__tests__/ripgrep-search.test.ts +570 -0
- package/src/modules/workspace/__tests__/ripgrep-version.test.ts +29 -0
- package/src/modules/workspace/__tests__/workspace-tmp.tools.test.ts +928 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +17 -37
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +20 -8
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +10 -12
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +22 -10
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +549 -162
- package/src/modules/workspace/agent-access.gate.ts +1 -1
- package/src/modules/workspace/file-readers/__tests__/doc-extract.service.test.ts +10 -0
- package/src/modules/workspace/file-readers/doc-extract.service.ts +71 -38
- package/src/modules/workspace/index.ts +20 -0
- package/src/modules/workspace/nul-scan.ts +50 -0
- package/src/modules/workspace/pattern-matcher.contract.ts +123 -32
- package/src/modules/workspace/ripgrep-search.ts +715 -0
- package/src/modules/workspace/ripgrep-version.ts +35 -0
- package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +11 -0
- package/src/modules/workspace/startup/beside-checkout.ts +13 -5
- package/src/modules/workspace/worker-pool.ts +3 -4
- package/src/modules/workspace/workspace-tmp.ts +457 -0
- package/src/modules/workspace/workspace.routes.ts +6 -27
- package/src/modules/workspace/workspace.service.ts +92 -15
- package/src/modules/workspace/workspace.tools.ts +574 -176
- package/src/shared/__tests__/read-capped.test.ts +68 -0
- package/src/shared/oauth-token-error.ts +46 -0
- package/src/shared/path-order.ts +37 -8
- package/src/shared/read-capped.ts +40 -0
- package/starter-packs/engineering/Plugins/engineering-starter/access.md +1 -1
- package/starter-packs/general/Plugins/general-starter/access.md +1 -1
- package/starter-packs/operations/Plugins/operations-starter/access.md +1 -1
- package/starter-packs/sales/Plugins/sales-starter/access.md +1 -1
- package/starter-packs/support/Plugins/support-starter/access.md +1 -1
- package/agent-guide/finding-things.md +0 -7
- package/agent-guide/introduction.md +0 -27
- package/dist/modules/workspace/bounded-matcher.d.ts +0 -73
- package/dist/modules/workspace/bounded-matcher.d.ts.map +0 -1
- package/dist/modules/workspace/bounded-matcher.js +0 -200
- package/dist/modules/workspace/bounded-matcher.js.map +0 -1
- package/src/modules/workspace/__tests__/bounded-matcher.test.ts +0 -213
- package/src/modules/workspace/bounded-matcher.ts +0 -271
|
@@ -2,11 +2,11 @@ import type { Server as HttpServer } from 'node:http';
|
|
|
2
2
|
import { createHmac } from 'node:crypto';
|
|
3
3
|
import express from 'express';
|
|
4
4
|
import { afterEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
} from '../secrets-vault.routes.js';
|
|
5
|
+
import { createSecretsVaultRoutes, createSecretsVaultPublicRoutes, SecretOAuthError } from '../index.js';
|
|
6
|
+
// The one deliberate white-box reach: the open-redirect predicate is pinned as
|
|
7
|
+
// a unit table as well as end-to-end (see below), and it is on no entry because
|
|
8
|
+
// nothing outside the routes should decide what a safe return path is.
|
|
9
|
+
import { isSafeReturnPath } from '../secrets-vault.routes.js';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* OAUTH `returnTo`: a sign-in started from a page other than /connect must land
|
|
@@ -54,6 +54,11 @@ const MANUALS = [
|
|
|
54
54
|
|
|
55
55
|
const toolManualService = {
|
|
56
56
|
listAccessible: async () => MANUALS,
|
|
57
|
+
// The sign-in start reads the declaration from the file; here it reads as the catalog does.
|
|
58
|
+
liveDeclaration: async (_who: string, slug: string, varName: string) => {
|
|
59
|
+
const manual = MANUALS.find((m) => m.slug === slug);
|
|
60
|
+
return manual ? { manual, variable: manual.variables.find((v) => v.name === varName) } : null;
|
|
61
|
+
},
|
|
57
62
|
} as unknown as Parameters<typeof createSecretsVaultRoutes>[0]['toolManualService'];
|
|
58
63
|
|
|
59
64
|
const accessControl = {
|
|
@@ -254,7 +259,35 @@ describe('GET /api/secrets/oauth/callback — where the browser lands', () => {
|
|
|
254
259
|
const state = signState({ u: 'u1', i: 'secret-1', n: 'nonce', r: RETURN_TO });
|
|
255
260
|
const location = await callback(base, state);
|
|
256
261
|
expect(location.startsWith(`${FRONTEND}${RETURN_TO}#error=`)).toBe(true);
|
|
257
|
-
//
|
|
262
|
+
// A failure that is not the provider's word stays generic: only the
|
|
263
|
+
// vault's own error carries a reason that was scrubbed for the page.
|
|
264
|
+
expect(decodeURIComponent(location.split('#error=')[1])).toBe(
|
|
265
|
+
'Authorization failed. Check the provider configuration and try again.',
|
|
266
|
+
);
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
it("carries the provider's error code and Hexis's sentence to the page when the exchange was refused", async () => {
|
|
270
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
271
|
+
const refusal =
|
|
272
|
+
'Token endpoint returned HTTP 400 (invalid_client). The client id or client secret this sign-in uses is not accepted by the provider. The tool owner should check the declared client id and set the client secret again.';
|
|
273
|
+
completeOAuth.mockImplementation(async () => {
|
|
274
|
+
throw new SecretOAuthError(refusal, 400);
|
|
275
|
+
});
|
|
276
|
+
const base = await baseUrl();
|
|
277
|
+
const state = signState({ u: 'u1', i: 'secret-1', n: 'nonce', r: RETURN_TO });
|
|
278
|
+
const location = await callback(base, state);
|
|
279
|
+
expect(decodeURIComponent(location.split('#error=')[1])).toBe(`Authorization failed. ${refusal}`);
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
it("keeps the generic message for the vault's own TRANSPORT errors, which quote what fetch said", async () => {
|
|
283
|
+
vi.spyOn(console, 'error').mockImplementation(() => {});
|
|
284
|
+
completeOAuth.mockImplementation(async () => {
|
|
285
|
+
// No provider status: not a provider's word, and never scrubbed.
|
|
286
|
+
throw new SecretOAuthError('Token endpoint request failed: fetch failed https://user:pw@provider.example/token');
|
|
287
|
+
});
|
|
288
|
+
const base = await baseUrl();
|
|
289
|
+
const state = signState({ u: 'u1', i: 'secret-1', n: 'nonce', r: RETURN_TO });
|
|
290
|
+
const location = await callback(base, state);
|
|
258
291
|
expect(decodeURIComponent(location.split('#error=')[1])).toBe(
|
|
259
292
|
'Authorization failed. Check the provider configuration and try again.',
|
|
260
293
|
);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash, randomBytes } from 'node:crypto';
|
|
2
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
2
3
|
import { logger } from '../../shared/logging.js';
|
|
3
4
|
|
|
4
5
|
const log = logger('vault');
|
|
@@ -7,6 +8,8 @@ import type { Database } from '../database/index.js';
|
|
|
7
8
|
import { secrets } from '../database/index.js';
|
|
8
9
|
import { TokenCrypto } from '../../shared/token-crypto.js';
|
|
9
10
|
import { assertSafeFetchUrl } from '../../shared/ssrf.js';
|
|
11
|
+
import { readCapped } from '../../shared/read-capped.js';
|
|
12
|
+
import { standardTokenErrorCode } from '../../shared/oauth-token-error.js';
|
|
10
13
|
import {
|
|
11
14
|
type ISecretsVaultService,
|
|
12
15
|
type SecretSummary,
|
|
@@ -16,6 +19,7 @@ import {
|
|
|
16
19
|
type PutSharedStaticSecretInput,
|
|
17
20
|
type CreateOAuthSecretInput,
|
|
18
21
|
type OAuthProviderConfig,
|
|
22
|
+
type DeclaredOAuthProvider,
|
|
19
23
|
type VariableScopeResolver,
|
|
20
24
|
type NamespaceSecretCount,
|
|
21
25
|
isKeyInNamespace,
|
|
@@ -32,6 +36,79 @@ const MAX_VALUE_LEN = 100_000;
|
|
|
32
36
|
const REFRESH_SKEW_MS = 60_000;
|
|
33
37
|
/** Upper bound on a token-endpoint round-trip, so a hung provider can't block callers. */
|
|
34
38
|
const TOKEN_REQUEST_TIMEOUT_MS = 10_000;
|
|
39
|
+
/** How much of a refusing token endpoint's body is read for its error code: an OAuth error object, never a whole error page. */
|
|
40
|
+
const TOKEN_ERROR_BODY_MAX_BYTES = 2048;
|
|
41
|
+
// Hexis's own sentences for a refused token request: what to change, in our
|
|
42
|
+
// words, never the provider's.
|
|
43
|
+
const HINT_CLIENT =
|
|
44
|
+
'The client id or client secret this sign-in uses is not accepted by the provider. The tool owner should check the declared client id and set the client secret again.';
|
|
45
|
+
const HINT_GRANT =
|
|
46
|
+
'The provider refused the grant: for a sign-in, a redirect URL mismatch or an expired or reused authorization code; for a refresh, a refresh token that has expired or been revoked. Sign in again.';
|
|
47
|
+
const HINT_SCOPE =
|
|
48
|
+
"The provider refused the scopes this sign-in asks for. The tool owner should check the declared scopes against the provider's app.";
|
|
49
|
+
const HINT_UNAUTHORIZED =
|
|
50
|
+
"The provider does not allow this client to use this grant. The tool owner should check the provider's app settings.";
|
|
51
|
+
const HINT_REQUEST =
|
|
52
|
+
'The provider found the token request malformed. The tool owner should check the declared endpoints and parameters.';
|
|
53
|
+
const HINT_PROVIDER = 'The provider could not serve the token request. Try again later.';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Hexis's sentence for each error code a refusing token endpoint may answer:
|
|
57
|
+
* the standard ones (`shared/oauth-token-error.ts` is the one list of those,
|
|
58
|
+
* read here and by the OIDC configuration check) in `error`, and the ones
|
|
59
|
+
* HubSpot's token endpoint answers in its `status` field. Only a code from
|
|
60
|
+
* those lists is ever taken, exactly, so no other string a provider puts in a
|
|
61
|
+
* field — a secret, a secret with a suffix, free text — can reach a message.
|
|
62
|
+
* Nothing else of the body is ever taken: no description, no message, no first
|
|
63
|
+
* line. That is why a message built here needs no scrubbing, cutting or
|
|
64
|
+
* decoding, and why every spelling a secret could reach a log in (escaped,
|
|
65
|
+
* encoded, cut) stays inexpressible. A standard code without a sentence here
|
|
66
|
+
* (`access_denied`) is named and left unexplained.
|
|
67
|
+
*/
|
|
68
|
+
const TOKEN_ERROR_HINTS: ReadonlyMap<string, string> = new Map([
|
|
69
|
+
['invalid_request', HINT_REQUEST],
|
|
70
|
+
['invalid_client', HINT_CLIENT],
|
|
71
|
+
['invalid_grant', HINT_GRANT],
|
|
72
|
+
['unauthorized_client', HINT_UNAUTHORIZED],
|
|
73
|
+
['unsupported_grant_type', HINT_UNAUTHORIZED],
|
|
74
|
+
['invalid_scope', HINT_SCOPE],
|
|
75
|
+
['server_error', HINT_PROVIDER],
|
|
76
|
+
['temporarily_unavailable', HINT_PROVIDER],
|
|
77
|
+
['BAD_CLIENT_ID', HINT_CLIENT],
|
|
78
|
+
['BAD_CLIENT_SECRET', HINT_CLIENT],
|
|
79
|
+
['BAD_AUTH_CODE', HINT_GRANT],
|
|
80
|
+
['BAD_REDIRECT_URI', HINT_GRANT],
|
|
81
|
+
]);
|
|
82
|
+
|
|
83
|
+
/** The codes HubSpot's token endpoint answers in `status` instead of a standard `error`. */
|
|
84
|
+
const HUBSPOT_STATUS_CODES: ReadonlySet<string> = new Set(['BAD_CLIENT_ID', 'BAD_CLIENT_SECRET', 'BAD_AUTH_CODE', 'BAD_REDIRECT_URI']);
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The known error code a refusing token endpoint answered, or null: a standard
|
|
88
|
+
* `error` (RFC 6749 §5.2), else HubSpot's own `status`, when it is exactly one
|
|
89
|
+
* of the codes known. Without even the code, a bare "HTTP 400" cannot tell a
|
|
90
|
+
* client the provider does not accept from a refused grant.
|
|
91
|
+
*/
|
|
92
|
+
export function tokenEndpointErrorCode(bodyText: string): string | null {
|
|
93
|
+
const standard = standardTokenErrorCode(bodyText);
|
|
94
|
+
if (standard !== null) return standard;
|
|
95
|
+
let json: unknown;
|
|
96
|
+
try {
|
|
97
|
+
json = JSON.parse(bodyText);
|
|
98
|
+
} catch {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
if (!json || typeof json !== 'object' || Array.isArray(json)) return null;
|
|
102
|
+
const { status } = json as Record<string, unknown>;
|
|
103
|
+
return typeof status === 'string' && HUBSPOT_STATUS_CODES.has(status) ? status : null;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** The refusal in one message: the status, the known code when there is one, and Hexis's sentence for it. */
|
|
107
|
+
export function describeTokenEndpointRefusal(status: number, code: string | null): string {
|
|
108
|
+
const base = `Token endpoint returned HTTP ${status}`;
|
|
109
|
+
const hint = code === null ? undefined : TOKEN_ERROR_HINTS.get(code);
|
|
110
|
+
return hint ? `${base} (${code}). ${hint}` : base;
|
|
111
|
+
}
|
|
35
112
|
|
|
36
113
|
/**
|
|
37
114
|
* How a row is stored, or `null` when there is no row — the column is a plain
|
|
@@ -487,8 +564,9 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
487
564
|
throw new InvalidSecretError('clientSecret is required');
|
|
488
565
|
}
|
|
489
566
|
// Validate the provider config the same way createOAuth does (SSRF-safe https
|
|
490
|
-
// URLs)
|
|
491
|
-
//
|
|
567
|
+
// URLs) and store it beside the secret as a record of what was saved — what
|
|
568
|
+
// `statusFor` and the setup surfaces read. A declared sign-in does not run
|
|
569
|
+
// from it: `beginToolOAuthByKey` is handed the declaration as it reads now.
|
|
492
570
|
const provider = this.requireProvider({ ...input.provider, clientSecret: input.clientSecret });
|
|
493
571
|
const blob: OAuthBlob = { clientSecret: provider.clientSecret };
|
|
494
572
|
const valueEncrypted = this.crypto().encrypt(JSON.stringify(blob));
|
|
@@ -510,11 +588,15 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
510
588
|
redirectUri: string;
|
|
511
589
|
state: string;
|
|
512
590
|
scopes?: string[];
|
|
591
|
+
provider?: DeclaredOAuthProvider;
|
|
513
592
|
}): Promise<{ id: string; url: string }> {
|
|
514
593
|
const userId = this.requireUserId(input.userId);
|
|
515
594
|
const key = this.requireKey(input.key);
|
|
516
|
-
// The shared row holds the owner-set client secret
|
|
517
|
-
//
|
|
595
|
+
// The shared row holds the owner-set client secret. For a client the
|
|
596
|
+
// platform registered itself it also holds the provider configuration, the
|
|
597
|
+
// only description of that client there is; for a declared sign-in the
|
|
598
|
+
// configuration it holds is a record of the save, and `input.provider` (the
|
|
599
|
+
// tool file as it reads now) is what the sign-in follows.
|
|
518
600
|
const [shared] = await this.db
|
|
519
601
|
.select()
|
|
520
602
|
.from(secrets)
|
|
@@ -524,11 +606,43 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
524
606
|
throw new SecretOAuthError("This tool's owner hasn't finished setting this up");
|
|
525
607
|
}
|
|
526
608
|
const sharedBlob = this.readBlob(shared.valueEncrypted);
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
609
|
+
let meta: OAuthProviderConfig;
|
|
610
|
+
let oauthMeta: typeof shared.oauthMeta;
|
|
611
|
+
if (input.provider) {
|
|
612
|
+
// A declared client is confidential: without the owner's secret there is
|
|
613
|
+
// nothing to sign in with, whatever the stored row says of itself.
|
|
614
|
+
if (!sharedBlob.clientSecret) {
|
|
615
|
+
throw new SecretOAuthError("This tool's owner hasn't finished setting this up");
|
|
616
|
+
}
|
|
617
|
+
// The save's own validation (https, no private or local address), BEFORE
|
|
618
|
+
// the caller's row is written or a URL built: a declaration that fails it
|
|
619
|
+
// sends nothing anywhere.
|
|
620
|
+
meta = this.requireProvider({ ...input.provider, publicClient: false });
|
|
621
|
+
oauthMeta = this.publicProviderMeta(meta);
|
|
622
|
+
// A MOVED PROPERTY, decided on the ticket (OAuth-Sign-In-Follows-The-Live-
|
|
623
|
+
// Declaration, 2026-10-27): the secret used to be bound to the token
|
|
624
|
+
// endpoint pinned at its save, so a later file edit could not send it
|
|
625
|
+
// anywhere else; now it goes where the file says at each start, so a
|
|
626
|
+
// writer of the tool file can move it (to an https, public host — the
|
|
627
|
+
// validation above still holds). Nothing refuses that; this line is the
|
|
628
|
+
// trail an operator reads when a secret went somewhere new.
|
|
629
|
+
const recorded = (shared.oauthMeta ?? {}) as { tokenUrl?: unknown };
|
|
630
|
+
if (typeof recorded.tokenUrl === 'string' && recorded.tokenUrl !== meta.tokenUrl) {
|
|
631
|
+
// Origins only: a path or query is the file's to say, not the log's.
|
|
632
|
+
const origin = (u: string) => (URL.canParse(u) ? new URL(u).origin : '(unparseable)');
|
|
633
|
+
log.warn(`sign-in on ${key}: the declared token endpoint differs from the one recorded when the client secret was saved`, {
|
|
634
|
+
savedOrigin: origin(recorded.tokenUrl),
|
|
635
|
+
declaredOrigin: origin(meta.tokenUrl),
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
} else {
|
|
639
|
+
meta = this.readMeta(shared.oauthMeta);
|
|
640
|
+
oauthMeta = shared.oauthMeta;
|
|
641
|
+
// A missing secret is "not set up yet" ONLY for confidential clients — a
|
|
642
|
+
// dynamically-registered PUBLIC client (PKCE-only) never has one.
|
|
643
|
+
if (!sharedBlob.clientSecret && !meta.publicClient) {
|
|
644
|
+
throw new SecretOAuthError("This tool's owner hasn't finished setting this up");
|
|
645
|
+
}
|
|
532
646
|
}
|
|
533
647
|
|
|
534
648
|
// Carry forward any tokens the caller already holds so re-entering the flow
|
|
@@ -543,12 +657,12 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
543
657
|
// encKey must degrade to "start fresh", not crash the recovery flow — and (b)
|
|
544
658
|
// they were minted under the SAME provider config we're about to (re)write, or
|
|
545
659
|
// a refresh_token for a stale client id/secret would silently fail once carried
|
|
546
|
-
// into this row after an owner rotates the shared secret
|
|
660
|
+
// into this row after an owner rotates the shared secret or edits the
|
|
661
|
+
// declaration. Compared as values, not as serialised text: the stored side
|
|
662
|
+
// has been through jsonb, which does not keep key order, and a declared
|
|
663
|
+
// sign-in's side is built here.
|
|
547
664
|
let existingTokens: OAuthTokenSet | undefined;
|
|
548
|
-
if (
|
|
549
|
-
existingUserRow?.kind === 'oauth' &&
|
|
550
|
-
JSON.stringify(existingUserRow.oauthMeta) === JSON.stringify(shared.oauthMeta)
|
|
551
|
-
) {
|
|
665
|
+
if (existingUserRow?.kind === 'oauth' && isDeepStrictEqual(existingUserRow.oauthMeta, oauthMeta)) {
|
|
552
666
|
try {
|
|
553
667
|
existingTokens = this.readBlob(existingUserRow.valueEncrypted).tokens;
|
|
554
668
|
} catch {
|
|
@@ -567,9 +681,13 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
567
681
|
const requestedScopes = input.scopes && input.scopes.length ? input.scopes : meta.scopes;
|
|
568
682
|
const pendingScopes = requestedScopes && requestedScopes.length ? requestedScopes.join(' ') : undefined;
|
|
569
683
|
|
|
570
|
-
// Provision (or reset) the caller's own oauth row for this key from the
|
|
571
|
-
//
|
|
572
|
-
//
|
|
684
|
+
// Provision (or reset) the caller's own oauth row for this key from the provider
|
|
685
|
+
// configuration this start uses + the shared secret, preserving any existing
|
|
686
|
+
// tokens. The row records that configuration because `completeOAuth` and every
|
|
687
|
+
// later refresh of this grant read it from HERE: the exchange goes to the token
|
|
688
|
+
// endpoint, under the client id, that the consent was given for. Keyed
|
|
689
|
+
// `<manual>_<VAR>` so `resolve` (scope 'user') returns the token once sign-in
|
|
690
|
+
// completes.
|
|
573
691
|
const blob: OAuthBlob = {
|
|
574
692
|
clientSecret: sharedBlob.clientSecret,
|
|
575
693
|
tokens: existingTokens,
|
|
@@ -579,16 +697,15 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
579
697
|
const valueEncrypted = this.crypto().encrypt(JSON.stringify(blob));
|
|
580
698
|
const [row] = await this.db
|
|
581
699
|
.insert(secrets)
|
|
582
|
-
.values({ userId, key, kind: 'oauth', label: shared.label, valueEncrypted, oauthMeta
|
|
700
|
+
.values({ userId, key, kind: 'oauth', label: shared.label, valueEncrypted, oauthMeta })
|
|
583
701
|
.onConflictDoUpdate({
|
|
584
702
|
target: [secrets.userId, secrets.key],
|
|
585
|
-
set: { kind: 'oauth', valueEncrypted, oauthMeta
|
|
703
|
+
set: { kind: 'oauth', valueEncrypted, oauthMeta, updatedAt: new Date() },
|
|
586
704
|
})
|
|
587
705
|
.returning();
|
|
588
706
|
|
|
589
|
-
// Build the consent URL exactly as beginOAuth does, from the
|
|
590
|
-
//
|
|
591
|
-
// stay owner-pinned.
|
|
707
|
+
// Build the consent URL exactly as beginOAuth does, from the configuration
|
|
708
|
+
// this start uses, with the requested scopes chosen above.
|
|
592
709
|
const url = new URL(meta.authorizationUrl);
|
|
593
710
|
url.searchParams.set('response_type', 'code');
|
|
594
711
|
url.searchParams.set('client_id', meta.clientId);
|
|
@@ -732,7 +849,18 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
732
849
|
err instanceof SecretOAuthError &&
|
|
733
850
|
(err.providerStatus === 400 || err.providerStatus === 401)
|
|
734
851
|
) {
|
|
735
|
-
|
|
852
|
+
// The only trace of a sign-in that silently turns into "not connected":
|
|
853
|
+
// say which one, the provider's reason, and what the guarded wipe did —
|
|
854
|
+
// a concurrent refresh may have rotated the tokens first, in which case
|
|
855
|
+
// nothing was wiped and the rotated grant is served.
|
|
856
|
+
const result = await this.wipeTokens(row, blob);
|
|
857
|
+
const did = result.wiped
|
|
858
|
+
? 'sign-in wiped'
|
|
859
|
+
: result.outcome === 'refreshed'
|
|
860
|
+
? 'the row had been rotated by a concurrent refresh meanwhile; the rotated sign-in is kept'
|
|
861
|
+
: 'the row had been removed or replaced meanwhile; nothing wiped';
|
|
862
|
+
log.warn(`refresh refused for "${row.key}", ${did}: ${err.message}`);
|
|
863
|
+
return result;
|
|
736
864
|
}
|
|
737
865
|
return { outcome: 'transient' };
|
|
738
866
|
}
|
|
@@ -794,7 +922,10 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
794
922
|
private async wipeTokens(
|
|
795
923
|
row: typeof secrets.$inferSelect,
|
|
796
924
|
blob: OAuthBlob,
|
|
797
|
-
): Promise<
|
|
925
|
+
): Promise<
|
|
926
|
+
| { outcome: 'refreshed'; accessToken: string; wiped: false }
|
|
927
|
+
| { outcome: 'rejected'; accessToken: null; wiped: boolean }
|
|
928
|
+
> {
|
|
798
929
|
const next: OAuthBlob = { clientSecret: blob.clientSecret };
|
|
799
930
|
// Guarded on the ciphertext we read, so a concurrent refresh that
|
|
800
931
|
// already persisted ROTATED tokens can't be wiped by our stale
|
|
@@ -807,13 +938,17 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
807
938
|
.where(and(eq(secrets.id, row.id), eq(secrets.valueEncrypted, row.valueEncrypted)))
|
|
808
939
|
.returning({ id: secrets.id });
|
|
809
940
|
if (Array.isArray(wiped) && wiped.length === 0) {
|
|
941
|
+
// `wiped: false` either way: this write matched nothing, and the caller
|
|
942
|
+
// reports what it did, not what it set out to do.
|
|
810
943
|
const fresh = await this.currentAccessToken(row.id);
|
|
811
|
-
return fresh
|
|
944
|
+
return fresh
|
|
945
|
+
? { outcome: 'refreshed', accessToken: fresh, wiped: false }
|
|
946
|
+
: { outcome: 'rejected', accessToken: null, wiped: false };
|
|
812
947
|
}
|
|
813
948
|
// The sign-in just became not-connected — let credential-validity caches
|
|
814
949
|
// (pooled downstream connections dialed with the dead token) drop it now.
|
|
815
950
|
this.notifyMutation(row.userId);
|
|
816
|
-
return { outcome: 'rejected', accessToken: null };
|
|
951
|
+
return { outcome: 'rejected', accessToken: null, wiped: true };
|
|
817
952
|
}
|
|
818
953
|
|
|
819
954
|
async putSharedOAuthProvider(input: {
|
|
@@ -887,7 +1022,15 @@ export class DbSecretsVaultService implements ISecretsVaultService {
|
|
|
887
1022
|
throw new SecretOAuthError(msg);
|
|
888
1023
|
}
|
|
889
1024
|
if (!res.ok) {
|
|
890
|
-
|
|
1025
|
+
// The provider's error CODE rides in the message: the callback route and
|
|
1026
|
+
// the refresh path log that message, and it is the one line that says
|
|
1027
|
+
// WHY a sign-in failed (a client the provider does not accept, a refused
|
|
1028
|
+
// authorization code). Best effort: the STATUS is the contract (the
|
|
1029
|
+
// refresh path reads 400/401 off it to retire a dead grant), and a body
|
|
1030
|
+
// that fails to read must not turn a definitive refusal into an
|
|
1031
|
+
// unclassified error.
|
|
1032
|
+
const code = tokenEndpointErrorCode(await readCapped(res, TOKEN_ERROR_BODY_MAX_BYTES).catch(() => ''));
|
|
1033
|
+
throw new SecretOAuthError(describeTokenEndpointRefusal(res.status, code), res.status);
|
|
891
1034
|
}
|
|
892
1035
|
const json = (await res.json()) as Record<string, unknown>;
|
|
893
1036
|
const accessToken = typeof json.access_token === 'string' ? json.access_token : '';
|
|
@@ -27,4 +27,4 @@ export {
|
|
|
27
27
|
DEFAULT_SECRETS_SCOPE,
|
|
28
28
|
} from './secrets-variable-loader.js';
|
|
29
29
|
// Reached by other modules; exported here so they stop importing the files.
|
|
30
|
-
export { scopesCovered } from './secrets-vault.contract.js';
|
|
30
|
+
export { scopesCovered, userSecretGap, type UserSecretGap } from './secrets-vault.contract.js';
|
|
@@ -74,6 +74,13 @@ export interface SecretConfigStatus {
|
|
|
74
74
|
grantedScopes?: string;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
+
/**
|
|
78
|
+
* A declared sign-in's public provider configuration, as the tool file reads it:
|
|
79
|
+
* everything but the secret (only the owner's shared row holds it) and the
|
|
80
|
+
* public-client flag (a declared client is confidential by definition).
|
|
81
|
+
*/
|
|
82
|
+
export type DeclaredOAuthProvider = Omit<OAuthProviderConfig, 'clientSecret' | 'publicClient'>;
|
|
83
|
+
|
|
77
84
|
/**
|
|
78
85
|
* How a secret is provisioned — mirrors `ToolVariableScope` in the tool-manuals
|
|
79
86
|
* contract, redeclared here to keep the vault free of a tool-manuals import.
|
|
@@ -186,8 +193,10 @@ export interface ISecretsVaultService {
|
|
|
186
193
|
/**
|
|
187
194
|
* Set the confidential client secret + provider config for a tool's OAuth-backed
|
|
188
195
|
* variable, on the SHARED row (`user_id NULL`) for `key`. The provider meta is
|
|
189
|
-
* stored ALONGSIDE the secret
|
|
190
|
-
*
|
|
196
|
+
* stored ALONGSIDE the secret as a record of the save; a sign-in follows the
|
|
197
|
+
* declaration as the tool file reads when it starts (`beginToolOAuthByKey`'s
|
|
198
|
+
* `provider`), not this copy. Owner-gated by the route (write access on the
|
|
199
|
+
* `.tool`).
|
|
191
200
|
*/
|
|
192
201
|
putSharedOAuthClientSecret(input: {
|
|
193
202
|
key: string;
|
|
@@ -212,16 +221,26 @@ export interface ISecretsVaultService {
|
|
|
212
221
|
*/
|
|
213
222
|
getSharedOAuthProvider(key: string): Promise<OAuthProviderConfig | null>;
|
|
214
223
|
/**
|
|
215
|
-
* Provision (if needed) the caller's per-user oauth row for `key`
|
|
216
|
-
*
|
|
217
|
-
*
|
|
218
|
-
* sign into the callback state) and the consent url.
|
|
224
|
+
* Provision (if needed) the caller's per-user oauth row for `key` and build the
|
|
225
|
+
* consent URL. 409 if the owner hasn't set the client secret. Returns the
|
|
226
|
+
* provisioned row's id (to sign into the callback state) and the consent url.
|
|
219
227
|
*
|
|
220
|
-
*
|
|
221
|
-
*
|
|
222
|
-
*
|
|
223
|
-
*
|
|
224
|
-
*
|
|
228
|
+
* Where the provider configuration comes from depends on who registered the
|
|
229
|
+
* client, and each kind of sign-in has exactly one source:
|
|
230
|
+
* - `provider` given — a DECLARED sign-in: the client id, endpoints, PKCE,
|
|
231
|
+
* resource and authorize params are the declaration as the tool file reads
|
|
232
|
+
* now, handed over by the caller. They are validated as the client-secret
|
|
233
|
+
* save validates them (https, no private or local address) before anything
|
|
234
|
+
* is written or built, and they are what the caller's row records, so the
|
|
235
|
+
* token exchange and later refreshes of this grant use the configuration
|
|
236
|
+
* the consent was given for. The shared row contributes the client secret
|
|
237
|
+
* only, and must hold one.
|
|
238
|
+
* - `provider` absent — a client the platform registered itself (dynamic
|
|
239
|
+
* client registration): nothing in a file describes it, so the shared
|
|
240
|
+
* row's stored configuration is used.
|
|
241
|
+
*
|
|
242
|
+
* `scopes`, when given, are the permissions to REQUEST on the consent screen
|
|
243
|
+
* (the live tool file's); omitted → the provider configuration's own scopes.
|
|
225
244
|
*/
|
|
226
245
|
beginToolOAuthByKey(input: {
|
|
227
246
|
userId: string;
|
|
@@ -229,6 +248,7 @@ export interface ISecretsVaultService {
|
|
|
229
248
|
redirectUri: string;
|
|
230
249
|
state: string;
|
|
231
250
|
scopes?: string[];
|
|
251
|
+
provider?: DeclaredOAuthProvider;
|
|
232
252
|
}): Promise<{ id: string; url: string }>;
|
|
233
253
|
|
|
234
254
|
/**
|
|
@@ -342,6 +362,36 @@ export function scopesCovered(required: string[] | undefined, granted: string |
|
|
|
342
362
|
return missingScopes(required, granted).length === 0;
|
|
343
363
|
}
|
|
344
364
|
|
|
365
|
+
/** Why a caller's own value for a per-user variable is not ready yet; see {@link userSecretGap}. */
|
|
366
|
+
export type UserSecretGap = 'missing' | 'wrong-kind' | 'unauthorized' | 'under-scoped';
|
|
367
|
+
|
|
368
|
+
/**
|
|
369
|
+
* Whether the CALLER's own value for a per-user variable is ready, and if not,
|
|
370
|
+
* why: the one rule the MCP proxy hides a tool by and `list_tool_setup` reports
|
|
371
|
+
* from, so the two cannot disagree. `null` when it is ready.
|
|
372
|
+
*
|
|
373
|
+
* - `missing`: no row at all, so it needs a value or a sign-in.
|
|
374
|
+
* - `wrong-kind`: a row of the OTHER kind than the manual now declares. A
|
|
375
|
+
* `.tool` edited from an OAuth sign-in to a plain key (or back) leaves the
|
|
376
|
+
* old row behind, and serving a token where a key is declared fails
|
|
377
|
+
* opaquely at the provider. The credential has to be set up again.
|
|
378
|
+
* - `unauthorized`: an OAuth row with no token yet: registered, sign-in not
|
|
379
|
+
* completed. Fail closed: anything but a confirmed `true` counts.
|
|
380
|
+
* - `under-scoped`: a token granted fewer scopes than the tool now declares,
|
|
381
|
+
* so the call would fail at the provider; it needs signing in again.
|
|
382
|
+
*/
|
|
383
|
+
export function userSecretGap(
|
|
384
|
+
declared: { oauth: boolean; oauthScopes?: string[] },
|
|
385
|
+
status: Pick<SecretConfigStatus, 'userConfigured' | 'userAuthorized' | 'grantedScopes'> & { userKind?: SecretKind | null } | undefined,
|
|
386
|
+
): UserSecretGap | null {
|
|
387
|
+
if (!status?.userConfigured) return 'missing';
|
|
388
|
+
const declaredKind: SecretKind = declared.oauth ? 'oauth' : 'static';
|
|
389
|
+
if (status.userKind && status.userKind !== declaredKind) return 'wrong-kind';
|
|
390
|
+
if (declared.oauth && status.userAuthorized !== true) return 'unauthorized';
|
|
391
|
+
if (declared.oauth && !scopesCovered(declared.oauthScopes, status.grantedScopes)) return 'under-scoped';
|
|
392
|
+
return null;
|
|
393
|
+
}
|
|
394
|
+
|
|
345
395
|
/**
|
|
346
396
|
* Is the stored row the KIND the manual now declares — i.e. would the thing the
|
|
347
397
|
* UI is about to offer actually work?
|