@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
|
@@ -40,11 +40,10 @@ import type { IAccessControl } from './access-control.interface.js';
|
|
|
40
40
|
import { isAbsence } from '../../shared/fs.contract.js';
|
|
41
41
|
import { isTextBytes } from '../workspace/index.js';
|
|
42
42
|
import {
|
|
43
|
-
type Verb,
|
|
44
43
|
ADMIN_CANONICAL,
|
|
45
44
|
KNOWN_VERBS,
|
|
46
|
-
ROLE_TOKEN_PREFIX,
|
|
47
45
|
canonicalRoleName,
|
|
46
|
+
splitPrincipalToken,
|
|
48
47
|
accessFrontmatterExtensionList,
|
|
49
48
|
} from '../access-model/index.js';
|
|
50
49
|
import {
|
|
@@ -52,9 +51,8 @@ import {
|
|
|
52
51
|
spliceGrant,
|
|
53
52
|
validatePrincipal,
|
|
54
53
|
AccessSpliceError,
|
|
55
|
-
type Principal,
|
|
56
|
-
type TokenMatch,
|
|
57
54
|
} from '../access-model/index.js';
|
|
55
|
+
import type { Verb, Principal, TokenMatch } from '../access-model/index.js';
|
|
58
56
|
import { WorkflowDomainError } from '../../shared/domain-errors.js';
|
|
59
57
|
import {
|
|
60
58
|
canCarryFrontmatter,
|
|
@@ -90,23 +88,21 @@ export const ADMIN_ROOT_WRITE_MESSAGE =
|
|
|
90
88
|
* this target touches the Admin ROLE's write at the repository root — the
|
|
91
89
|
* root folder's `access.md`, or a file directly in the root. The resolver
|
|
92
90
|
* ignores such a rule anyway (the Admin write floor), so writing it would only
|
|
93
|
-
* leave a line that says something the app does not do. A bare
|
|
94
|
-
*
|
|
95
|
-
*
|
|
91
|
+
* leave a line that says something the app does not do. A bare `Admin` is the
|
|
92
|
+
* role (a bare name is always the role when one exists, and roles.yaml always
|
|
93
|
+
* declares Admin); `group/Admin` is a group and never the role. Targets arrive
|
|
94
|
+
* in one spelling: the routes refuse `.` and `..` segments.
|
|
96
95
|
*/
|
|
97
96
|
export function removesAdminRootWrite(
|
|
98
97
|
kind: TargetKind,
|
|
99
98
|
repoRelTarget: string,
|
|
100
99
|
principal: Principal,
|
|
101
100
|
verb: Verb | undefined,
|
|
102
|
-
tokenMatch: TokenMatch,
|
|
103
101
|
): boolean {
|
|
104
102
|
if (principal.kind !== 'role') return false;
|
|
105
103
|
if (!touchesRootWrite(kind, repoRelTarget, verb)) return false;
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
if (!explicit && tokenMatch === 'exact') return false;
|
|
109
|
-
return (explicit ? canonical.slice(ROLE_TOKEN_PREFIX.length) : canonical) === ADMIN_CANONICAL;
|
|
104
|
+
const { prefix, name } = splitPrincipalToken(canonicalRoleName(principal.role));
|
|
105
|
+
return prefix !== 'group' && name === ADMIN_CANONICAL;
|
|
110
106
|
}
|
|
111
107
|
|
|
112
108
|
/** Whether a mutation on `verb` (absent = every verb) at this target reaches write at the repository root. */
|
|
@@ -276,38 +272,40 @@ export class AccessMutationService {
|
|
|
276
272
|
}
|
|
277
273
|
|
|
278
274
|
/**
|
|
279
|
-
* How a REVOKE of `principal` matches file tokens
|
|
275
|
+
* How a REVOKE of `principal` matches file tokens. `'name'` strips the
|
|
276
|
+
* principal's explicit spelling AND the bare name (never the other kind's
|
|
277
|
+
* explicit spelling — see `TokenMatch`); `'exact'` strips the literal
|
|
278
|
+
* spelling alone. The bare name is stripped only when it is THIS
|
|
279
|
+
* principal's under role-first precedence:
|
|
280
280
|
*
|
|
281
|
-
* -
|
|
282
|
-
*
|
|
283
|
-
* group's,
|
|
284
|
-
*
|
|
285
|
-
*
|
|
286
|
-
*
|
|
287
|
-
*
|
|
288
|
-
*
|
|
281
|
+
* - A ROLE (`role/<name>`, or a bare name) owns the bare key unless no
|
|
282
|
+
* role of that name exists and a group does — then the bare token is
|
|
283
|
+
* the group's, and matching is `'exact'`. A model that fails to load
|
|
284
|
+
* keeps it `'exact'` too.
|
|
285
|
+
* - A GROUP (`group/<name>`) owns the bare key only while no role of
|
|
286
|
+
* that name exists — otherwise the bare token is the role's, and
|
|
287
|
+
* matching is `'exact'`. A group that has VANISHED from the active
|
|
288
|
+
* source still reads correctly: the question is whether a ROLE holds
|
|
289
|
+
* the name. A model that fails to load says nothing about roles, so a
|
|
290
|
+
* group revoke then stays `'exact'` rather than risk a role's grant.
|
|
289
291
|
*
|
|
290
292
|
* Judged against THIS workspace's merged principal index (`kbPrincipals` —
|
|
291
293
|
* the same model the resolver reads), so revoke agrees with resolution on
|
|
292
|
-
* who owns the bare key.
|
|
293
|
-
* unshadowed — matching degrades to the pre-groups name-level behavior.
|
|
294
|
-
*
|
|
295
|
-
* GROUP revokes never take the name-level path: the route passes
|
|
296
|
-
* `tokenMatch: 'exact'` explicitly (see `revoke`'s `opts`), because this
|
|
297
|
-
* shadow probe cannot tell a group apart from a role once the group has
|
|
298
|
-
* VANISHED from the active source — the bare name then reads "unshadowed"
|
|
299
|
-
* and a name-level group revoke would strip a same-named role's live
|
|
300
|
-
* `role/<Name>` grant.
|
|
294
|
+
* who owns the bare key.
|
|
301
295
|
*/
|
|
302
296
|
private async revokeTokenMatch(workspaceId: string, principal: Principal): Promise<TokenMatch> {
|
|
303
297
|
if (principal.kind !== 'role') return 'exact'; // user matching ignores the mode
|
|
304
|
-
const
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
298
|
+
const { prefix, name } = splitPrincipalToken(canonicalRoleName(principal.role));
|
|
299
|
+
const { roles, groups } = await this.accessControl.kbPrincipals(workspaceId);
|
|
300
|
+
const isRole = roles.some((r) => canonicalRoleName(r) === name);
|
|
301
|
+
if (prefix === 'group') {
|
|
302
|
+
// `roles` always carries at least `Everyone` once the model loads.
|
|
303
|
+
return isRole || roles.length === 0 ? 'exact' : 'name';
|
|
304
|
+
}
|
|
305
|
+
const isGroup = groups.some((g) => canonicalRoleName(g) === name);
|
|
306
|
+
// No roles at all means the model failed to load: stay exact, so a role
|
|
307
|
+
// revoke never strips a same-named group's bare grant.
|
|
308
|
+
return roles.length === 0 || (!isRole && isGroup) ? 'exact' : 'name';
|
|
311
309
|
}
|
|
312
310
|
|
|
313
311
|
/**
|
|
@@ -372,11 +370,10 @@ export class AccessMutationService {
|
|
|
372
370
|
// When present, strip ONLY this verb (a per-checkbox toggle in the share UI);
|
|
373
371
|
// absent strips the principal from every verb (the whole-principal Remove).
|
|
374
372
|
verb?: Verb,
|
|
375
|
-
// `tokenMatch` overrides the
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
//
|
|
379
|
-
// `role/<Name>` grant.
|
|
373
|
+
// `tokenMatch` overrides the derived matching (see revokeTokenMatch).
|
|
374
|
+
// One production caller: the plugin-links unlink pins `'exact'` for its
|
|
375
|
+
// `plugin/<Name>/<verb>` tokens. Pin only `'exact'` — a pinned `'name'`
|
|
376
|
+
// would bypass the guard that never strips across kinds.
|
|
380
377
|
opts?: { tokenMatch?: TokenMatch },
|
|
381
378
|
): Promise<{ changed: boolean; editPath: string }> {
|
|
382
379
|
void _actingUserEmail; // referenced to satisfy no-unused-vars until something consumes it
|
|
@@ -386,8 +383,8 @@ export class AccessMutationService {
|
|
|
386
383
|
// missing FILE node is a bad target and should surface, not silently no-op
|
|
387
384
|
// — same rule grant() uses.
|
|
388
385
|
const original = await this.readOrEmpty(workspaceId, kind, repoRelTarget, editPath);
|
|
389
|
-
// Alias-tolerant vs exact-token matching, decided by
|
|
390
|
-
// see revokeTokenMatch — unless the caller pinned it.
|
|
386
|
+
// Alias-tolerant vs exact-token matching, decided by who owns the bare
|
|
387
|
+
// name — see revokeTokenMatch — unless the caller pinned it.
|
|
391
388
|
const tokenMatch = opts?.tokenMatch ?? (await this.revokeTokenMatch(workspaceId, principal));
|
|
392
389
|
let next = original;
|
|
393
390
|
let changed = false;
|
|
@@ -409,7 +406,7 @@ export class AccessMutationService {
|
|
|
409
406
|
// Refused only when an Admin write entry would really go: a whole-row
|
|
410
407
|
// Remove at a root that grants Admin other verbs but no write line (write
|
|
411
408
|
// comes from the floor) strips those verbs as usual.
|
|
412
|
-
if (writeRemoved && removesAdminRootWrite(kind, repoRelTarget, principal, verb
|
|
409
|
+
if (writeRemoved && removesAdminRootWrite(kind, repoRelTarget, principal, verb)) {
|
|
413
410
|
throw adminRootWriteRefusal();
|
|
414
411
|
}
|
|
415
412
|
if (!changed) return { changed: false, editPath };
|
|
@@ -457,7 +454,7 @@ export class AccessMutationService {
|
|
|
457
454
|
repoRelTarget: string,
|
|
458
455
|
principal: Principal,
|
|
459
456
|
verb?: Verb,
|
|
460
|
-
// Same override as `revoke
|
|
457
|
+
// Same override as `revoke`; no production caller passes it here.
|
|
461
458
|
opts?: { tokenMatch?: TokenMatch },
|
|
462
459
|
): Promise<{ changed: boolean; editPath: string }> {
|
|
463
460
|
this.assertPrincipalSafe(principal);
|
|
@@ -465,10 +462,10 @@ export class AccessMutationService {
|
|
|
465
462
|
const original = await this.readOrEmpty(workspaceId, kind, repoRelTarget, editPath);
|
|
466
463
|
|
|
467
464
|
const verbsToDeny = verb ? [verb] : KNOWN_VERBS;
|
|
468
|
-
// Same
|
|
469
|
-
//
|
|
465
|
+
// Same matching as revoke(): the strip must not swallow a same-named
|
|
466
|
+
// OTHER principal's grant (`group/<name>` vs the role's bare/`role/`).
|
|
470
467
|
const tokenMatch = opts?.tokenMatch ?? (await this.revokeTokenMatch(workspaceId, principal));
|
|
471
|
-
if (removesAdminRootWrite(kind, repoRelTarget, principal, verb
|
|
468
|
+
if (removesAdminRootWrite(kind, repoRelTarget, principal, verb)) {
|
|
472
469
|
throw adminRootWriteRefusal();
|
|
473
470
|
}
|
|
474
471
|
// A PERSON who is an admin keeps root write through the floor, so a deny
|
|
@@ -508,10 +505,8 @@ export class AccessMutationService {
|
|
|
508
505
|
|
|
509
506
|
// (3) Assert the deny actually removed effective access on the targeted
|
|
510
507
|
// verb(s) — else roll back. The check evaluates the SAME token identity
|
|
511
|
-
// the deny above spliced (`tokenMatch` rides along)
|
|
512
|
-
//
|
|
513
|
-
// a same-named role's surviving `role/<Name>` grant as the group still
|
|
514
|
-
// having access — rolling back a fully effective deny as "ineffective".
|
|
508
|
+
// the deny above spliced (`tokenMatch` rides along), so a pinned exact
|
|
509
|
+
// deny is never judged by spellings it did not touch.
|
|
515
510
|
const stillHas = await this.principalStillHasAccess(
|
|
516
511
|
workspaceId,
|
|
517
512
|
kind,
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
EVERYONE_CANONICAL,
|
|
14
14
|
KNOWN_VERBS,
|
|
15
15
|
ROLE_TOKEN_PREFIX,
|
|
16
|
+
GROUP_TOKEN_PREFIX,
|
|
16
17
|
type Verb,
|
|
17
18
|
} from '../access-model/index.js';
|
|
18
19
|
|
|
@@ -51,13 +52,12 @@ export async function resolveAccessView(
|
|
|
51
52
|
// files). Keyed `u:<email>` / `r:<role>` / `g:<group>` to match the
|
|
52
53
|
// dialog's row keys, so each row can show where its access comes from and
|
|
53
54
|
// which verbs are removable here. Groups get their OWN `g:` namespace: a
|
|
54
|
-
// group and a role sharing a name are DIFFERENT principals (
|
|
55
|
-
// `role/<name>`), and one shared `r:` entry could only
|
|
56
|
-
// them. Each kind resolves through the token
|
|
57
|
-
// principal — a group through
|
|
58
|
-
//
|
|
59
|
-
//
|
|
60
|
-
// it has no alias). A row whose verbs resolve only via a
|
|
55
|
+
// group and a role sharing a name are DIFFERENT principals (`group/<name>`
|
|
56
|
+
// vs the bare name and `role/<name>`), and one shared `r:` entry could only
|
|
57
|
+
// describe one of them. Each kind resolves through the explicit token that
|
|
58
|
+
// IS that principal — a group through `group/<name>`, a role through
|
|
59
|
+
// `role/<name>` (the built-in `everyone` keeps its bare spelling, it has no
|
|
60
|
+
// alias); the bare spelling counts toward whichever kind owns it. A row whose verbs resolve only via a
|
|
61
61
|
// group/everyone/rescue has no source (the verb is absent) and renders
|
|
62
62
|
// non-actionable. Built over the union of every principal in the four
|
|
63
63
|
// eligible lists (kinded `principals`, with the name-only `roles` list as
|
|
@@ -96,9 +96,11 @@ export async function resolveAccessView(
|
|
|
96
96
|
await Promise.all([
|
|
97
97
|
...[...collectives.entries()].map(async ([key, p]) => {
|
|
98
98
|
const token =
|
|
99
|
-
p.kind === '
|
|
100
|
-
? `${
|
|
101
|
-
: p.name
|
|
99
|
+
p.kind === 'group'
|
|
100
|
+
? `${GROUP_TOKEN_PREFIX}${p.name}`
|
|
101
|
+
: p.kind === 'role' && canonicalRoleName(p.name) !== EVERYONE_CANONICAL
|
|
102
|
+
? `${ROLE_TOKEN_PREFIX}${p.name}`
|
|
103
|
+
: p.name;
|
|
102
104
|
const principal = { kind: 'role' as const, role: token };
|
|
103
105
|
const [grants, denied] = await Promise.all([
|
|
104
106
|
accessControl.grantSources(workspaceId, kind, repoRelTarget, principal),
|
|
@@ -19,6 +19,7 @@ import type {
|
|
|
19
19
|
} from './access-control.interface.js';
|
|
20
20
|
import type { WorkspaceService } from '../workspace/index.js';
|
|
21
21
|
import type { KbContext } from '../../shared/kb-context.js';
|
|
22
|
+
import type { ITreeWalker } from '../../shared/fs.contract.js';
|
|
22
23
|
import { branchForWorkspaceId } from '../../shared/workspace-id.js';
|
|
23
24
|
import type { AuthService, IAccountSwitchGuard } from '../auth/index.js';
|
|
24
25
|
import type { WorkflowService, WorkflowEventBus } from '../workflow/index.js';
|
|
@@ -39,7 +40,10 @@ import {
|
|
|
39
40
|
PLUGIN_TOKEN_PREFIX,
|
|
40
41
|
PLUGIN_TOKEN_VERBS,
|
|
41
42
|
ROLE_TOKEN_PREFIX,
|
|
43
|
+
GROUP_TOKEN_PREFIX,
|
|
44
|
+
splitPrincipalToken,
|
|
42
45
|
type PluginTokenVerb,
|
|
46
|
+
type Principal,
|
|
43
47
|
type Verb,
|
|
44
48
|
} from '../access-model/index.js';
|
|
45
49
|
import { listAccessDeclarationsUnder } from './access-declarations.js';
|
|
@@ -47,7 +51,6 @@ import { emailsInView, holderPrincipals, labelAccountHolders, resolveAccessView
|
|
|
47
51
|
import type { AccessView, LabelledAccessView } from './access-view.js';
|
|
48
52
|
import { toHttpError as sharedToHttpError, requireNonEmptyString as sharedRequireNonEmptyString } from './admin-route-helpers.js';
|
|
49
53
|
import { RolesAdminService } from './roles-admin.service.js';
|
|
50
|
-
import type { Principal } from '../access-model/index.js';
|
|
51
54
|
import type { Database } from '../database/index.js';
|
|
52
55
|
import { users } from '../database/index.js';
|
|
53
56
|
import { canonicalEmail } from '../../shared/email-identity.js';
|
|
@@ -91,6 +94,8 @@ export function createAccessRoutes(
|
|
|
91
94
|
eventBus: WorkflowEventBus,
|
|
92
95
|
db: Database,
|
|
93
96
|
kb: KbContext,
|
|
97
|
+
/** The composition root's walk, for the roles admin's reference scan. */
|
|
98
|
+
disk: ITreeWalker,
|
|
94
99
|
/** This deployment's configured admins — the break-glass recovery roster. */
|
|
95
100
|
recoveryAdmins: readonly string[] = [],
|
|
96
101
|
): express.Router {
|
|
@@ -101,6 +106,7 @@ export function createAccessRoutes(
|
|
|
101
106
|
workspaceService,
|
|
102
107
|
workflowService,
|
|
103
108
|
accessControl,
|
|
109
|
+
disk,
|
|
104
110
|
kbDirName,
|
|
105
111
|
() => kb.defaultBranch,
|
|
106
112
|
eventBus,
|
|
@@ -161,10 +167,10 @@ export function createAccessRoutes(
|
|
|
161
167
|
/**
|
|
162
168
|
* What the mutation routes accept as a principal. `group` and `plugin`
|
|
163
169
|
* exist only at this boundary: in the access.md entry grammar a group grant
|
|
164
|
-
* is
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
170
|
+
* is the `group/<Name>` token and a plugin grant is the
|
|
171
|
+
* `plugin/<Name>/<verb>` token, so both are spliced as role-shaped
|
|
172
|
+
* principals — the separate kinds buy validation against the right
|
|
173
|
+
* namespace and honest 404s.
|
|
168
174
|
*/
|
|
169
175
|
type RoutePrincipal =
|
|
170
176
|
| Principal
|
|
@@ -173,14 +179,16 @@ export function createAccessRoutes(
|
|
|
173
179
|
|
|
174
180
|
/**
|
|
175
181
|
* The role-shaped principal the splice layer actually writes/matches.
|
|
176
|
-
* - group →
|
|
177
|
-
*
|
|
178
|
-
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
182
|
+
* - group → the explicit `group/<Name>` token. Never the bare name:
|
|
183
|
+
* a bare name is the ROLE whenever one of that name exists,
|
|
184
|
+
* so a bare group grant could silently mean someone else.
|
|
185
|
+
* - role → the explicit `role/<Name>` token. Bare spellings in
|
|
186
|
+
* existing files remain read-compatible. The built-in
|
|
187
|
+
* `everyone` stays bare: it is not a roles.yaml role and
|
|
188
|
+
* has no `role/` alias.
|
|
181
189
|
*/
|
|
182
190
|
const asSplicePrincipal = (p: RoutePrincipal): Principal => {
|
|
183
|
-
if (p.kind === 'group') return { kind: 'role', role: p.group };
|
|
191
|
+
if (p.kind === 'group') return { kind: 'role', role: `${GROUP_TOKEN_PREFIX}${groupName(p.group)}` };
|
|
184
192
|
// Written with the folder's own casing; `parseAccessEntry` canonicalises
|
|
185
193
|
// the name half to the manifest slug on the way back in.
|
|
186
194
|
if (p.kind === 'plugin') return { kind: 'role', role: `${PLUGIN_TOKEN_PREFIX}${p.plugin.trim()}/${p.verb}` };
|
|
@@ -209,6 +217,14 @@ export function createAccessRoutes(
|
|
|
209
217
|
return p;
|
|
210
218
|
};
|
|
211
219
|
|
|
220
|
+
/** A group as the caller named it, without a `group/` prefix it may carry (casing kept). */
|
|
221
|
+
function groupName(group: string): string {
|
|
222
|
+
const raw = group.trim();
|
|
223
|
+
return splitPrincipalToken(canonicalRoleName(raw)).prefix === 'group'
|
|
224
|
+
? raw.slice(GROUP_TOKEN_PREFIX.length).trim()
|
|
225
|
+
: raw;
|
|
226
|
+
}
|
|
227
|
+
|
|
212
228
|
// Authentication gate only. Per PLAN §3 the workspace `:id` is a branch
|
|
213
229
|
// identifier — any authenticated user can read its access tree.
|
|
214
230
|
async function requireUser(
|
|
@@ -398,9 +414,20 @@ export function createAccessRoutes(
|
|
|
398
414
|
* nothing is moved.
|
|
399
415
|
*
|
|
400
416
|
* Gated like the sibling `overrides` route rather than the permissive
|
|
401
|
-
* `GET /access`: the caller must resolve read on the thing being moved
|
|
402
|
-
* lists name people, and someone who cannot
|
|
403
|
-
* learning who can
|
|
417
|
+
* `GET /access`: the caller must resolve read on the thing being moved AND
|
|
418
|
+
* on the destination folder. The lists name people, and someone who cannot
|
|
419
|
+
* see a thing has no business learning who can; the `after` lists and the
|
|
420
|
+
* `changes` are the destination folder's rules read back (whom it grants,
|
|
421
|
+
* whom it denies by name), so a folder the caller may not open tells them
|
|
422
|
+
* nothing either.
|
|
423
|
+
*
|
|
424
|
+
* `changes` is who loses and who gains `read` or `write` in the move, as the
|
|
425
|
+
* resolver judges each candidate on both sides
|
|
426
|
+
* (`prospectiveHolderChanges`) — the one answer the move dialog and the
|
|
427
|
+
* agent's `move_file` both show. The two lists are not that answer: they
|
|
428
|
+
* name grants, so a writer leaving a folder everyone reads shows as losing
|
|
429
|
+
* `read` it keeps, and a person the destination denies by name is on
|
|
430
|
+
* neither list.
|
|
404
431
|
*/
|
|
405
432
|
router.get('/workspace/:id/access/prospective', async (req, res) => {
|
|
406
433
|
const user = await requireUser(req, res);
|
|
@@ -429,13 +456,21 @@ export function createAccessRoutes(
|
|
|
429
456
|
res.status(403).json({ error: 'You do not have access to this file.' });
|
|
430
457
|
return;
|
|
431
458
|
}
|
|
459
|
+
if (!(await accessControl.canRead(req.params.id, user.email, toDir))) {
|
|
460
|
+
res.status(403).json({ error: 'You do not have access to this folder.' });
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
432
463
|
|
|
433
464
|
const name = from.slice(from.lastIndexOf('/') + 1);
|
|
434
465
|
const to = toDir ? `${toDir}/${name}` : name;
|
|
435
|
-
const { before, after } = await
|
|
466
|
+
const [{ before, after }, changes] = await Promise.all([
|
|
467
|
+
accessControl.prospectiveHolders(req.params.id, from, to),
|
|
468
|
+
accessControl.prospectiveHolderChanges(req.params.id, from, to),
|
|
469
|
+
]);
|
|
436
470
|
res.json({
|
|
437
471
|
before: { read: holderPrincipals(before.read), write: holderPrincipals(before.write) },
|
|
438
472
|
after: { read: holderPrincipals(after.read), write: holderPrincipals(after.write) },
|
|
473
|
+
changes,
|
|
439
474
|
});
|
|
440
475
|
} catch (err) {
|
|
441
476
|
const { status, body } = toHttpError(err);
|
|
@@ -511,8 +546,8 @@ export function createAccessRoutes(
|
|
|
511
546
|
* signed in — so the dialog can label them; it withholds nobody.
|
|
512
547
|
*
|
|
513
548
|
* A name shared by a group and a role is offered as BOTH — nothing is
|
|
514
|
-
* withheld:
|
|
515
|
-
*
|
|
549
|
+
* withheld: each is written with its own prefix (`group/<Name>`,
|
|
550
|
+
* `role/<Name>`), so the collision never reaches the file.
|
|
516
551
|
*/
|
|
517
552
|
router.get('/workspace/:id/access/suggest', async (req, res) => {
|
|
518
553
|
const user = await requireUser(req, res);
|
|
@@ -948,10 +983,10 @@ export function createAccessRoutes(
|
|
|
948
983
|
// uses — and one the caller may see (`visibleGroups`): a group hidden
|
|
949
984
|
// from the picker is refused here with the same words as one that
|
|
950
985
|
// does not exist, so the grant route is no oracle for group names.
|
|
951
|
-
// No role-collision refusal:
|
|
952
|
-
//
|
|
986
|
+
// No role-collision refusal: the grant is written `group/<Name>`,
|
|
987
|
+
// which always resolves to the group.
|
|
953
988
|
const groups = await visibleGroups(user.email, (await defaultBranchPrincipals()).groups);
|
|
954
|
-
const canonical = canonicalRoleName(principal.group);
|
|
989
|
+
const canonical = canonicalRoleName(groupName(principal.group));
|
|
955
990
|
if (!groups.some((g) => canonicalRoleName(g) === canonical)) {
|
|
956
991
|
throw new AccessMutationError(
|
|
957
992
|
`No group named "${principal.group}". Pick an existing group.`,
|
|
@@ -976,8 +1011,8 @@ export function createAccessRoutes(
|
|
|
976
1011
|
);
|
|
977
1012
|
}
|
|
978
1013
|
}
|
|
979
|
-
// Splice shape: group →
|
|
980
|
-
//
|
|
1014
|
+
// Splice shape: group → explicit `group/<Name>` token; role → explicit
|
|
1015
|
+
// `role/<Name>` token (see asSplicePrincipal).
|
|
981
1016
|
const splicePrincipal = asSplicePrincipal(principal);
|
|
982
1017
|
|
|
983
1018
|
const { gatePath } = gateAndEditPaths(kind, repoRelTarget);
|
|
@@ -1045,18 +1080,12 @@ export function createAccessRoutes(
|
|
|
1045
1080
|
try {
|
|
1046
1081
|
const mode = (req.body as { mode?: unknown }).mode;
|
|
1047
1082
|
const { repoRelTarget, kind, principal: routePrincipal } = parseMutationBody(req.body);
|
|
1048
|
-
// A group principal converts straight to
|
|
1049
|
-
//
|
|
1050
|
-
//
|
|
1083
|
+
// A group principal converts straight to its `group/<Name>` token — no
|
|
1084
|
+
// existence check (revoking a grant whose group has since vanished must
|
|
1085
|
+
// keep working). Which spellings a revoke strips is the mutation
|
|
1086
|
+
// service's call: `group/<Name>` never matches `role/<Name>`, and the
|
|
1087
|
+
// bare name only when no role of that name owns it.
|
|
1051
1088
|
const principal = asSplicePrincipal(routePrincipal);
|
|
1052
|
-
// GROUP revokes match the EXACT bare token only. The service's own
|
|
1053
|
-
// shadow probe decides exact-vs-name for roles, but it cannot know a
|
|
1054
|
-
// bare token was a GROUP once that group vanished from the active
|
|
1055
|
-
// source — the name would read "unshadowed" and name-level matching
|
|
1056
|
-
// would strip a same-named role's live `role/<Name>` grant. The route
|
|
1057
|
-
// still knows the caller's kind, so it pins the matching here.
|
|
1058
|
-
const revokeOpts =
|
|
1059
|
-
routePrincipal.kind === 'group' ? ({ tokenMatch: 'exact' } as const) : undefined;
|
|
1060
1089
|
// Optional `verb` scopes ALL three paths to a single verb: a default revoke
|
|
1061
1090
|
// strips just that verb; remove-from-parent removes just that verb on the
|
|
1062
1091
|
// ancestor; deny-here denies just that verb at the target. Absent ⇒ the
|
|
@@ -1112,7 +1141,7 @@ export function createAccessRoutes(
|
|
|
1112
1141
|
);
|
|
1113
1142
|
}
|
|
1114
1143
|
// Scope the ancestor revoke to the same verb the user acted on (if any).
|
|
1115
|
-
await mutation.revoke(workspaceId, 'folder', ancestorDir, principal, user.email, verb
|
|
1144
|
+
await mutation.revoke(workspaceId, 'folder', ancestorDir, principal, user.email, verb);
|
|
1116
1145
|
});
|
|
1117
1146
|
|
|
1118
1147
|
accessControl.invalidate(workspaceId);
|
|
@@ -1131,7 +1160,7 @@ export function createAccessRoutes(
|
|
|
1131
1160
|
await mutation.assertTargetHoldsText(workspaceId, kind, repoRelTarget);
|
|
1132
1161
|
await withEditLock(workspaceId, branch, gatePath, user, async () => {
|
|
1133
1162
|
// Scope the deny to the same verb the user acted on (if any).
|
|
1134
|
-
await mutation.denyHere(workspaceId, kind, repoRelTarget, principal, verb
|
|
1163
|
+
await mutation.denyHere(workspaceId, kind, repoRelTarget, principal, verb);
|
|
1135
1164
|
});
|
|
1136
1165
|
accessControl.invalidate(workspaceId);
|
|
1137
1166
|
logger('access.revoke.deny-here').info(
|
|
@@ -1150,7 +1179,7 @@ export function createAccessRoutes(
|
|
|
1150
1179
|
const editPath = gatePath;
|
|
1151
1180
|
let changed = false;
|
|
1152
1181
|
await withEditLock(workspaceId, branch, editPath, user, async () => {
|
|
1153
|
-
const r = await mutation.revoke(workspaceId, kind, repoRelTarget, principal, user.email, verb
|
|
1182
|
+
const r = await mutation.revoke(workspaceId, kind, repoRelTarget, principal, user.email, verb);
|
|
1154
1183
|
changed = r.changed;
|
|
1155
1184
|
});
|
|
1156
1185
|
|
|
@@ -1247,7 +1276,7 @@ export function createAccessRoutes(
|
|
|
1247
1276
|
// surface). The frontend hides the page, but the API must gate too — the
|
|
1248
1277
|
// roster exposes every role + member email.
|
|
1249
1278
|
await assertRolesAdmin(user.email);
|
|
1250
|
-
res.json({ roles: await rolesAdmin.getRoster() });
|
|
1279
|
+
res.json({ roles: await rolesAdmin.getRoster(user.email) });
|
|
1251
1280
|
} catch (err) {
|
|
1252
1281
|
const { status, body } = toHttpError(err);
|
|
1253
1282
|
res.status(status).json(body);
|
|
@@ -50,9 +50,11 @@ export function createGroupsAdminRoutes(deps: {
|
|
|
50
50
|
// role assignments) + `groupsHealth` (the broken-source banner marker; a
|
|
51
51
|
// broken MANUAL groups.yaml instead answers 422 with the parse message so
|
|
52
52
|
// the operator sees what to fix).
|
|
53
|
-
router.get('/admin/groups', requireAdmin, async (
|
|
53
|
+
router.get('/admin/groups', requireAdmin, async (req, res) => {
|
|
54
54
|
try {
|
|
55
|
-
|
|
55
|
+
// A read needs no commit attribution: the roster is filtered for the
|
|
56
|
+
// email `requireAdmin` just checked, with no second user lookup to fail.
|
|
57
|
+
res.json(await groupsAdmin.getRoster(req.userEmail!));
|
|
56
58
|
} catch (err) {
|
|
57
59
|
sendError(res, err);
|
|
58
60
|
}
|