@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
|
@@ -11,6 +11,9 @@ import { DEFAULT_BRANCH } from '@bevel-software/platform-shared';
|
|
|
11
11
|
import { AccessControlService } from '../access-control.service.js';
|
|
12
12
|
import { GroupsAdminService, GroupsAdminError } from '../groups-admin.service.js';
|
|
13
13
|
import { createGroup, addGroupMember, GroupsEditError } from '../groups-edit.js';
|
|
14
|
+
import { workspaceIdForBranch } from '../../../shared/workspace-id.js';
|
|
15
|
+
import { AccessDeniedError } from '../../access-model/index.js';
|
|
16
|
+
import { UNSHOWN_REFERENCE_REFUSAL } from '../reference-scan.js';
|
|
14
17
|
|
|
15
18
|
const KB = 'knowledge-base';
|
|
16
19
|
const ADMIN: AuthUser = { id: 'u-admin', email: 'admin@x.io', name: 'Admin' } as AuthUser;
|
|
@@ -108,6 +111,7 @@ describe('GroupsAdminService', () => {
|
|
|
108
111
|
workspace,
|
|
109
112
|
workflow.svc,
|
|
110
113
|
new AccessControlService(workspace as never, KB, new NodeFs()),
|
|
114
|
+
new NodeFs(),
|
|
111
115
|
KB,
|
|
112
116
|
() => DEFAULT_BRANCH,
|
|
113
117
|
);
|
|
@@ -126,7 +130,7 @@ describe('GroupsAdminService', () => {
|
|
|
126
130
|
'roles.yaml',
|
|
127
131
|
'roles:\n Admin:\n - admin@x.io\n Reviewer:\n - rev@x.io\n - group:gtm team\n',
|
|
128
132
|
);
|
|
129
|
-
const roster = await service.getRoster();
|
|
133
|
+
const roster = await service.getRoster('admin@x.io');
|
|
130
134
|
expect(roster.mode).toBe('manual');
|
|
131
135
|
expect(roster.groupsHealth).toEqual({ ok: true });
|
|
132
136
|
expect(roster.groups.map((g) => g.displayName).sort()).toEqual(['GTM Team', 'Product']);
|
|
@@ -141,7 +145,7 @@ describe('GroupsAdminService', () => {
|
|
|
141
145
|
|
|
142
146
|
it('a broken MANUAL groups.yaml answers the roster with 422 + the parse message', async () => {
|
|
143
147
|
await write(repo, 'groups.yaml', 'groups:\n - not\n - a\n - mapping\n');
|
|
144
|
-
const err = await service.getRoster().catch((e: unknown) => e);
|
|
148
|
+
const err = await service.getRoster('admin@x.io').catch((e: unknown) => e);
|
|
145
149
|
expect(err).toBeInstanceOf(GroupsAdminError);
|
|
146
150
|
expect((err as GroupsAdminError).status).toBe(422);
|
|
147
151
|
expect((err as GroupsAdminError).message).toMatch(/groups.yaml/);
|
|
@@ -152,7 +156,7 @@ describe('GroupsAdminService', () => {
|
|
|
152
156
|
|
|
153
157
|
it('a broken SYNCED file keeps IdP mode: empty roster + groupsHealth marker (no manual fallback)', async () => {
|
|
154
158
|
await write(repo, 'synced-groups.yaml', 'groups:\n - not\n - a\n - mapping\n');
|
|
155
|
-
const roster = await service.getRoster();
|
|
159
|
+
const roster = await service.getRoster('admin@x.io');
|
|
156
160
|
expect(roster.mode).toBe('idp');
|
|
157
161
|
// Falling back to groups.yaml would resurrect retired manual groups.
|
|
158
162
|
expect(roster.groups).toEqual([]);
|
|
@@ -218,7 +222,7 @@ describe('GroupsAdminService', () => {
|
|
|
218
222
|
|
|
219
223
|
it('IdP mode: mutations refuse with the typed 409; reads still work', async () => {
|
|
220
224
|
await write(repo, 'synced-groups.yaml', 'groups:\n Engineering:\n - ada@x.io\n');
|
|
221
|
-
const roster = await service.getRoster();
|
|
225
|
+
const roster = await service.getRoster('admin@x.io');
|
|
222
226
|
expect(roster.mode).toBe('idp');
|
|
223
227
|
// The roster IS the synced file now — not the retired manual list.
|
|
224
228
|
expect(roster.groups.map((g) => g.canonical)).toEqual(['engineering']);
|
|
@@ -241,18 +245,106 @@ describe('GroupsAdminService', () => {
|
|
|
241
245
|
});
|
|
242
246
|
|
|
243
247
|
it('canonical-changing rename rewrites grant references in ONE commit', async () => {
|
|
244
|
-
await write(
|
|
248
|
+
await write(
|
|
249
|
+
repo,
|
|
250
|
+
'Knowledge/Sales/access.md',
|
|
251
|
+
'---\nread:\n - GTM Team\n - group/GTM Team\nwrite:\n - deny GTM Team\n---\n',
|
|
252
|
+
);
|
|
245
253
|
await service.renameGroup(ADMIN, 'gtm team', 'Go To Market');
|
|
246
254
|
|
|
247
255
|
expect(await groupsYaml()).toContain('Go To Market:');
|
|
248
256
|
const rewritten = await fs.readFile(path.join(repo, 'Knowledge/Sales/access.md'), 'utf-8');
|
|
249
|
-
|
|
250
|
-
expect(rewritten).toContain('-
|
|
257
|
+
// Rewritten as the explicit group token, whatever the old spelling.
|
|
258
|
+
expect(rewritten).toContain('- group/Go To Market');
|
|
259
|
+
expect(rewritten).toContain('- deny group/Go To Market');
|
|
251
260
|
expect(rewritten).not.toContain('GTM Team');
|
|
252
261
|
expect(commits).toHaveLength(1);
|
|
253
262
|
expect(commits[0].summary).toContain('gtm team → Go To Market');
|
|
254
263
|
});
|
|
255
264
|
|
|
265
|
+
// Another person's private plugin is closed to the Admin: the rewrite still
|
|
266
|
+
// covers it (no reference left behind). Whether the Admin may WRITE it is
|
|
267
|
+
// the commit gate's call — see the gated cases below; this stub allows it.
|
|
268
|
+
it('rename rewrites a file the Admin cannot read when the commit allows it', async () => {
|
|
269
|
+
await write(
|
|
270
|
+
repo,
|
|
271
|
+
'Plugins/Sara/access.md',
|
|
272
|
+
'---\nread:\n - deny everyone\n - Sara <sara@x.io>\nwrite:\n - Sara <sara@x.io>\n---\n',
|
|
273
|
+
);
|
|
274
|
+
await write(repo, 'Plugins/Sara/Notes.md', "---\nread: ['group/GTM Team']\n---\n# Notes\n");
|
|
275
|
+
const access = new AccessControlService(stubWorkspace(root) as never, KB, new NodeFs());
|
|
276
|
+
expect(await access.canRead(workspaceIdForBranch(DEFAULT_BRANCH), ADMIN.email, 'Plugins/Sara/Notes.md')).toBe(false);
|
|
277
|
+
|
|
278
|
+
await service.renameGroup(ADMIN, 'gtm team', 'Go To Market');
|
|
279
|
+
|
|
280
|
+
expect(await fs.readFile(path.join(repo, 'Plugins/Sara/Notes.md'), 'utf-8')).toBe(
|
|
281
|
+
"---\nread: ['group/Go To Market']\n---\n# Notes\n",
|
|
282
|
+
);
|
|
283
|
+
expect(commits).toHaveLength(1);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe('rename against the commit write gate', () => {
|
|
287
|
+
// The real commit gates every touched path on the actor's write rules and
|
|
288
|
+
// refuses the first one they may not write (git.service
|
|
289
|
+
// `assertCanWriteAtRef`); this stub does the same through the live model.
|
|
290
|
+
function gatedService(): { gated: GroupsAdminService; gatedCommits: { summary: string }[] } {
|
|
291
|
+
const workspace = stubWorkspace(root);
|
|
292
|
+
const access = new AccessControlService(workspace as never, KB, new NodeFs());
|
|
293
|
+
const workflow = stubWorkflow();
|
|
294
|
+
const svc = workflow.svc as unknown as Record<string, unknown>;
|
|
295
|
+
svc.commitChanges = async (ws: string, user: AuthUser, summary: string, onlyPaths: string[] = []) => {
|
|
296
|
+
const rel = onlyPaths.map((p) => p.slice(KB.length + 1));
|
|
297
|
+
const verdicts = await access.canWriteBatch(ws, user.email, rel);
|
|
298
|
+
const denied = rel.find((p) => verdicts.get(p) !== true);
|
|
299
|
+
if (denied) throw new AccessDeniedError({ path: denied, eligibleRoles: [], eligibleUsers: [] });
|
|
300
|
+
workflow.commits.push({ summary });
|
|
301
|
+
return {} as unknown;
|
|
302
|
+
};
|
|
303
|
+
const gated = new GroupsAdminService(workspace, workflow.svc, access, new NodeFs(), KB, () => DEFAULT_BRANCH);
|
|
304
|
+
return { gated, gatedCommits: workflow.commits };
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
const SARA_ACCESS = '---\nread:\n - deny everyone\n - Sara <sara@x.io>\nwrite:\n - Sara <sara@x.io>\n---\n';
|
|
308
|
+
|
|
309
|
+
it('a file the Admin cannot read refuses generically, never naming it, and writes nothing', async () => {
|
|
310
|
+
await write(repo, 'Plugins/Sara/access.md', SARA_ACCESS);
|
|
311
|
+
const notes = "---\nread: ['group/GTM Team']\n---\n# Notes\n";
|
|
312
|
+
await write(repo, 'Plugins/Sara/Notes.md', notes);
|
|
313
|
+
const { gated, gatedCommits } = gatedService();
|
|
314
|
+
|
|
315
|
+
const err = await gated.renameGroup(ADMIN, 'gtm team', 'Go To Market').catch((e: unknown) => e);
|
|
316
|
+
expect(err).toBeInstanceOf(GroupsAdminError);
|
|
317
|
+
expect((err as GroupsAdminError).status).toBe(422);
|
|
318
|
+
expect((err as Error).message).toBe(UNSHOWN_REFERENCE_REFUSAL);
|
|
319
|
+
expect((err as Error).message).not.toContain('Sara');
|
|
320
|
+
// Restored: the hidden file, and the roster, as they were.
|
|
321
|
+
expect(await fs.readFile(path.join(repo, 'Plugins/Sara/Notes.md'), 'utf-8')).toBe(notes);
|
|
322
|
+
expect(await groupsYaml()).toBe(GROUPS);
|
|
323
|
+
expect(gatedCommits).toHaveLength(0);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
it('a file the Admin can read but not write keeps the refusal that names it', async () => {
|
|
327
|
+
await write(repo, 'Knowledge/Locked/access.md', '---\nread:\n - everyone\nwrite:\n - deny Admin\n---\n');
|
|
328
|
+
await write(repo, 'Knowledge/Locked/Plan.md', '---\nread:\n - group/GTM Team\n---\n# Plan\n');
|
|
329
|
+
const { gated } = gatedService();
|
|
330
|
+
|
|
331
|
+
const err = await gated.renameGroup(ADMIN, 'gtm team', 'Go To Market').catch((e: unknown) => e);
|
|
332
|
+
expect(err).toBeInstanceOf(AccessDeniedError);
|
|
333
|
+
expect((err as AccessDeniedError).access.path).toMatch(/^Knowledge\/Locked\//);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('a hidden file that names something else does not block the rename', async () => {
|
|
337
|
+
await write(repo, 'Plugins/Sara/access.md', SARA_ACCESS);
|
|
338
|
+
await write(repo, 'Plugins/Sara/Notes.md', "---\nread: ['group/Product']\n---\n# Notes\n");
|
|
339
|
+
await write(repo, 'Knowledge/Sales/access.md', '---\nread:\n - group/GTM Team\n---\n');
|
|
340
|
+
const { gated, gatedCommits } = gatedService();
|
|
341
|
+
|
|
342
|
+
await gated.renameGroup(ADMIN, 'gtm team', 'Go To Market');
|
|
343
|
+
expect(await fs.readFile(path.join(repo, 'Knowledge/Sales/access.md'), 'utf-8')).toContain('group/Go To Market');
|
|
344
|
+
expect(gatedCommits).toHaveLength(1);
|
|
345
|
+
});
|
|
346
|
+
});
|
|
347
|
+
|
|
256
348
|
it('rename rewrites a BODY-GOVERNED access.md (rules live below the frontmatter)', async () => {
|
|
257
349
|
// New-format file: frontmatter governs access.md itself, the body is the
|
|
258
350
|
// folder's rules — exactly what the resolver enforces.
|
|
@@ -262,14 +354,15 @@ describe('GroupsAdminService', () => {
|
|
|
262
354
|
'---\nwrite:\n - Admin\n---\nread:\n - GTM Team\nwrite:\n - deny GTM Team\n',
|
|
263
355
|
);
|
|
264
356
|
// The scan must see the body rule too (delete warnings / referencedBy).
|
|
265
|
-
const roster = await service.getRoster();
|
|
357
|
+
const roster = await service.getRoster('admin@x.io');
|
|
266
358
|
const gtm = roster.groups.find((g) => g.canonical === 'gtm team');
|
|
267
359
|
expect(gtm?.referencedBy).toContainEqual({ path: 'Knowledge/Sales/access.md', verb: 'read' });
|
|
268
360
|
|
|
269
361
|
await service.renameGroup(ADMIN, 'gtm team', 'Go To Market');
|
|
270
362
|
const rewritten = await fs.readFile(path.join(repo, 'Knowledge/Sales/access.md'), 'utf-8');
|
|
271
|
-
|
|
272
|
-
expect(rewritten).toContain('-
|
|
363
|
+
// Rewritten as the explicit group token, whatever the old spelling.
|
|
364
|
+
expect(rewritten).toContain('- group/Go To Market');
|
|
365
|
+
expect(rewritten).toContain('- deny group/Go To Market');
|
|
273
366
|
expect(rewritten).not.toContain('GTM Team');
|
|
274
367
|
// The frontmatter self-rule is a rule source too, and Admin is untouched.
|
|
275
368
|
expect(rewritten).toContain('- Admin');
|
|
@@ -303,6 +396,7 @@ describe('GroupsAdminService', () => {
|
|
|
303
396
|
workspace,
|
|
304
397
|
workflow.svc,
|
|
305
398
|
new AccessControlService(workspace as never, KB, new NodeFs()),
|
|
399
|
+
new NodeFs(),
|
|
306
400
|
KB,
|
|
307
401
|
() => DEFAULT_BRANCH,
|
|
308
402
|
);
|
|
@@ -349,6 +443,7 @@ describe('GroupsAdminService', () => {
|
|
|
349
443
|
workspace,
|
|
350
444
|
workflow.svc,
|
|
351
445
|
new AccessControlService(workspace as never, KB, new NodeFs()),
|
|
446
|
+
new NodeFs(),
|
|
352
447
|
KB,
|
|
353
448
|
() => DEFAULT_BRANCH,
|
|
354
449
|
);
|
|
@@ -388,6 +483,7 @@ describe('GroupsAdminService', () => {
|
|
|
388
483
|
workspace,
|
|
389
484
|
workflow.svc,
|
|
390
485
|
new AccessControlService(workspace as never, KB, new NodeFs()),
|
|
486
|
+
new NodeFs(),
|
|
391
487
|
KB,
|
|
392
488
|
() => DEFAULT_BRANCH,
|
|
393
489
|
);
|
|
@@ -421,27 +517,124 @@ describe('groups-edit guardrails', () => {
|
|
|
421
517
|
});
|
|
422
518
|
|
|
423
519
|
describe('groups roster referencedBy — the mirror of the roles roster attribution', () => {
|
|
424
|
-
it('a group
|
|
520
|
+
it('a group sharing a role name owns only its group/ hits; bare and role/ hits are the role’s', async () => {
|
|
425
521
|
const root2 = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-groups-shadow-'));
|
|
426
522
|
try {
|
|
427
523
|
const repo2 = path.join(root2, KB);
|
|
428
|
-
// A group named Reviewer shares the Reviewer role's name.
|
|
429
|
-
// precedence gives the
|
|
430
|
-
//
|
|
524
|
+
// A group named Reviewer shares the Reviewer role's name. Role-first
|
|
525
|
+
// precedence gives the ROLE the bare key, so the bare and role/ hits
|
|
526
|
+
// belong to the ROLE roster; the group's reference is its group/ hit.
|
|
527
|
+
// The bare hit is reported so an Admin can rewrite it if the group
|
|
528
|
+
// was meant.
|
|
431
529
|
await write(repo2, 'roles.yaml', ROLES); // declares role Reviewer
|
|
432
|
-
await write(repo2, 'groups.yaml', 'groups:\n Reviewer:\n - pat@x.io\n');
|
|
433
|
-
await write(repo2, '
|
|
530
|
+
await write(repo2, 'groups.yaml', 'groups:\n Reviewer:\n - pat@x.io\n Ops:\n - ops@x.io\n');
|
|
531
|
+
await write(repo2, 'ops/access.md', '---\nread:\n - Ops\nwrite:\n - group/Ops\n---\n');
|
|
532
|
+
await write(
|
|
533
|
+
repo2,
|
|
534
|
+
'team/access.md',
|
|
535
|
+
'---\nread:\n - Reviewer\nwrite:\n - role/Reviewer\nowner:\n - group/Reviewer\ndownload:\n - deny Reviewer\n---\n',
|
|
536
|
+
);
|
|
434
537
|
const workspace = stubWorkspace(root2);
|
|
435
538
|
const svc = new GroupsAdminService(
|
|
436
539
|
workspace,
|
|
437
540
|
stubWorkflow().svc,
|
|
438
541
|
new AccessControlService(workspace as never, KB, new NodeFs()),
|
|
542
|
+
new NodeFs(),
|
|
439
543
|
KB,
|
|
440
544
|
() => DEFAULT_BRANCH,
|
|
441
545
|
);
|
|
442
|
-
|
|
546
|
+
// rev@x.io holds the Reviewer role, so it can read team/access.md.
|
|
547
|
+
const roster = await svc.getRoster('rev@x.io');
|
|
443
548
|
const reviewer = roster.groups.find((g) => g.canonical === 'reviewer')!;
|
|
444
|
-
expect(reviewer.referencedBy).toEqual([{ path: 'team/access.md', verb: '
|
|
549
|
+
expect(reviewer.referencedBy).toEqual([{ path: 'team/access.md', verb: 'owner' }]);
|
|
550
|
+
// A bare DENIAL changed meaning too (it now denies the role, not the
|
|
551
|
+
// group), so it is reported alongside the bare grant.
|
|
552
|
+
expect(reviewer.bareNameResolvesToRole).toEqual([
|
|
553
|
+
{ path: 'team/access.md', verb: 'read' },
|
|
554
|
+
{ path: 'team/access.md', verb: 'download' },
|
|
555
|
+
]);
|
|
556
|
+
// A group no role shares a name with keeps its bare hits, and has nothing
|
|
557
|
+
// to report. ops@x.io is in Ops, so it can read ops/access.md.
|
|
558
|
+
const ops = (await svc.getRoster('ops@x.io')).groups.find((g) => g.canonical === 'ops')!;
|
|
559
|
+
expect(ops.referencedBy).toEqual(
|
|
560
|
+
expect.arrayContaining([
|
|
561
|
+
{ path: 'ops/access.md', verb: 'read' },
|
|
562
|
+
{ path: 'ops/access.md', verb: 'write' },
|
|
563
|
+
]),
|
|
564
|
+
);
|
|
565
|
+
expect(ops.referencedBy).toHaveLength(2);
|
|
566
|
+
expect(ops.bareNameResolvesToRole).toEqual([]);
|
|
567
|
+
} finally {
|
|
568
|
+
await fs.rm(root2, { recursive: true, force: true });
|
|
569
|
+
}
|
|
570
|
+
});
|
|
571
|
+
|
|
572
|
+
it('bareNameResolvesToRole names only the files the viewer can read', async () => {
|
|
573
|
+
const root2 = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-groups-disclose-'));
|
|
574
|
+
try {
|
|
575
|
+
const repo2 = path.join(root2, KB);
|
|
576
|
+
await write(repo2, 'roles.yaml', ROLES); // Admin: admin@x.io, Reviewer: rev@x.io
|
|
577
|
+
await write(repo2, 'groups.yaml', 'groups:\n Reviewer:\n - pat@x.io\n');
|
|
578
|
+
await write(repo2, 'access.md', '---\nread:\n - everyone\nwrite:\n - Admin\n---\n');
|
|
579
|
+
// Two bare Reviewer rules: one in an open folder, one in a node only
|
|
580
|
+
// the Reviewer role may read.
|
|
581
|
+
await write(repo2, 'team/access.md', '---\nwrite:\n - Reviewer\n---\n');
|
|
582
|
+
await write(repo2, 'secret/Plan.md', '---\nread:\n - deny everyone\n - Reviewer\n---\n# Plan\n');
|
|
583
|
+
const workspace = stubWorkspace(root2);
|
|
584
|
+
const access = new AccessControlService(workspace as never, KB, new NodeFs());
|
|
585
|
+
const svc = new GroupsAdminService(workspace, stubWorkflow().svc, access, new NodeFs(), KB, () => DEFAULT_BRANCH);
|
|
586
|
+
const rowsFor = async (email: string) =>
|
|
587
|
+
(await svc.getRoster(email)).groups.find((g) => g.canonical === 'reviewer')!.bareNameResolvesToRole;
|
|
588
|
+
|
|
589
|
+
expect(await rowsFor('rev@x.io')).toEqual(
|
|
590
|
+
expect.arrayContaining([
|
|
591
|
+
{ path: 'team/access.md', verb: 'write' },
|
|
592
|
+
{ path: 'secret/Plan.md', verb: 'read' },
|
|
593
|
+
]),
|
|
594
|
+
);
|
|
595
|
+
// pat@x.io is in the Reviewer GROUP, not the role: the bare grant is the
|
|
596
|
+
// role's, so the secret file is closed to pat, and so is its path.
|
|
597
|
+
expect(await access.canRead(workspaceIdForBranch(DEFAULT_BRANCH), 'pat@x.io', 'secret/Plan.md')).toBe(false);
|
|
598
|
+
expect(await rowsFor('pat@x.io')).toEqual([{ path: 'team/access.md', verb: 'write' }]);
|
|
599
|
+
} finally {
|
|
600
|
+
await fs.rm(root2, { recursive: true, force: true });
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
|
|
604
|
+
it('referencedBy names only the files the viewer can read and omits the rest entirely, uncounted', async () => {
|
|
605
|
+
const root2 = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-groups-disclose-refs-'));
|
|
606
|
+
try {
|
|
607
|
+
const repo2 = path.join(root2, KB);
|
|
608
|
+
await write(repo2, 'roles.yaml', ROLES); // Admin: admin@x.io, Reviewer: rev@x.io
|
|
609
|
+
await write(repo2, 'groups.yaml', 'groups:\n Ops:\n - ops@x.io\n');
|
|
610
|
+
await write(repo2, 'access.md', '---\nread:\n - everyone\nwrite:\n - Admin\n---\n');
|
|
611
|
+
// Two group/Ops rules: one in an open folder, one in a node only the
|
|
612
|
+
// Reviewer role may read.
|
|
613
|
+
await write(repo2, 'team/access.md', '---\nwrite:\n - group/Ops\n---\n');
|
|
614
|
+
await write(
|
|
615
|
+
repo2,
|
|
616
|
+
'secret/Plan.md',
|
|
617
|
+
'---\nread:\n - deny everyone\n - Reviewer\nowner:\n - deny group/Ops\n---\n# Plan\n',
|
|
618
|
+
);
|
|
619
|
+
const workspace = stubWorkspace(root2);
|
|
620
|
+
const svc = new GroupsAdminService(
|
|
621
|
+
workspace,
|
|
622
|
+
stubWorkflow().svc,
|
|
623
|
+
new AccessControlService(workspace as never, KB, new NodeFs()),
|
|
624
|
+
new NodeFs(),
|
|
625
|
+
KB,
|
|
626
|
+
() => DEFAULT_BRANCH,
|
|
627
|
+
);
|
|
628
|
+
const opsFor = async (email: string) =>
|
|
629
|
+
(await svc.getRoster(email)).groups.find((g) => g.canonical === 'ops')!;
|
|
630
|
+
|
|
631
|
+
const asReviewer = await opsFor('rev@x.io');
|
|
632
|
+
expect(asReviewer.referencedBy.map((r) => r.path).sort()).toEqual(['secret/Plan.md', 'team/access.md']);
|
|
633
|
+
// The Admin cannot read secret/Plan.md: its rule is left out entirely —
|
|
634
|
+
// not named, and not counted either (Admin status does not grant read).
|
|
635
|
+
const asAdmin = await opsFor('admin@x.io');
|
|
636
|
+
expect(asAdmin.referencedBy).toEqual([{ path: 'team/access.md', verb: 'write' }]);
|
|
637
|
+
expect(asAdmin).not.toHaveProperty('referencesHidden');
|
|
445
638
|
} finally {
|
|
446
639
|
await fs.rm(root2, { recursive: true, force: true });
|
|
447
640
|
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
|
|
6
|
+
import { realDisk } from '../../../__tests__/real-disk.js';
|
|
7
|
+
import type { WorkspaceService } from '../../workspace/index.js';
|
|
8
|
+
import { AccessControlService } from '../access-control.service.js';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* `prospectiveHolderChanges`: who loses and who gains opening or editing a
|
|
12
|
+
* file or folder in a move, over a real on-disk tree. The holder lists name
|
|
13
|
+
* grants, so these tests are about the cases a list comparison gets wrong: a
|
|
14
|
+
* group still covered by `everyone` where it lands, and someone a rule there
|
|
15
|
+
* denies by name, even when their only access before was `everyone`.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
const KB_DIR = 'knowledge-base';
|
|
19
|
+
const rules = (body: string) => `---\n${body}---\n`;
|
|
20
|
+
|
|
21
|
+
describe('AccessControlService.prospectiveHolderChanges', () => {
|
|
22
|
+
let root: string;
|
|
23
|
+
let repo: string;
|
|
24
|
+
const workspaceId = 'ws-holder-changes';
|
|
25
|
+
|
|
26
|
+
beforeEach(async () => {
|
|
27
|
+
root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-holder-changes-'));
|
|
28
|
+
repo = path.join(root, workspaceId, KB_DIR);
|
|
29
|
+
});
|
|
30
|
+
afterEach(async () => {
|
|
31
|
+
if (root) await fs.rm(root, { recursive: true, force: true });
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
async function write(files: Record<string, string>): Promise<void> {
|
|
35
|
+
for (const [rel, contents] of Object.entries(files)) {
|
|
36
|
+
const abs = path.join(repo, rel);
|
|
37
|
+
await fs.mkdir(path.dirname(abs), { recursive: true });
|
|
38
|
+
await fs.writeFile(abs, contents);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const service = () =>
|
|
43
|
+
new AccessControlService(
|
|
44
|
+
{
|
|
45
|
+
getWorkspacePath: async () => path.join(root, workspaceId),
|
|
46
|
+
ensureRemotesFetched: async () => undefined,
|
|
47
|
+
} as unknown as WorkspaceService,
|
|
48
|
+
KB_DIR,
|
|
49
|
+
realDisk(),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
/** Everyone reads; Support and Operations each edit their own folder. */
|
|
53
|
+
const BASE = {
|
|
54
|
+
'roles.yaml': 'roles:\n Admin:\n - admin@x.io\n',
|
|
55
|
+
'groups.yaml': 'groups:\n Support:\n - bea@x.io\n Operations:\n - jonas@x.io\n',
|
|
56
|
+
'access.md': rules('read:\n - everyone\n'),
|
|
57
|
+
'Support/access.md': rules('write:\n - Support\n'),
|
|
58
|
+
'Support/Runbooks/Warranty claim.md': '# Warranty claim\n',
|
|
59
|
+
'Operations/access.md': rules('write:\n - Operations\n'),
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
it('a folder handed to another team: the old team loses editing, the new one gains it, and nobody loses opening it', async () => {
|
|
63
|
+
await write(BASE);
|
|
64
|
+
const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Operations/Runbooks');
|
|
65
|
+
expect(changes).toEqual({
|
|
66
|
+
lose: [{ kind: 'group', name: 'Support', verb: 'write' }],
|
|
67
|
+
gain: [{ kind: 'group', name: 'Operations', verb: 'write' }],
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('a person the destination denies by name loses access, though everyone may still read there', async () => {
|
|
72
|
+
await write({
|
|
73
|
+
...BASE,
|
|
74
|
+
'Team/access.md': rules('write:\n - Ana <ana@x.io>\n'),
|
|
75
|
+
'Team/plan.md': '# Plan\n',
|
|
76
|
+
'Closed/access.md': rules('read:\n - everyone\n - deny Ana <ana@x.io>\n'),
|
|
77
|
+
});
|
|
78
|
+
const changes = await service().prospectiveHolderChanges(workspaceId, 'Team/plan.md', 'Closed/plan.md');
|
|
79
|
+
expect(changes.lose).toEqual(
|
|
80
|
+
expect.arrayContaining([
|
|
81
|
+
{ kind: 'person', name: 'ana@x.io', email: 'ana@x.io', verb: 'read' },
|
|
82
|
+
{ kind: 'person', name: 'ana@x.io', email: 'ana@x.io', verb: 'write' },
|
|
83
|
+
]),
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('a person whose only access was everyone, and whom the destination denies by name, loses it', async () => {
|
|
88
|
+
await write({
|
|
89
|
+
...BASE,
|
|
90
|
+
'Closed/access.md': rules('read:\n - everyone\n - deny Leo <leo@x.io>\n'),
|
|
91
|
+
});
|
|
92
|
+
const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Closed/Runbooks');
|
|
93
|
+
expect(changes.lose).toContainEqual({ kind: 'person', name: 'leo@x.io', email: 'leo@x.io', verb: 'read' });
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('a group whose only read was everyone, and which the destination denies, loses it', async () => {
|
|
97
|
+
await write({
|
|
98
|
+
...BASE,
|
|
99
|
+
'Closed/access.md': rules('read:\n - everyone\n - deny Operations\n'),
|
|
100
|
+
});
|
|
101
|
+
const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Closed/Runbooks');
|
|
102
|
+
expect(changes.lose).toContainEqual({ kind: 'group', name: 'Operations', verb: 'read' });
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('a group the destination denies loses opening it, though everyone may still read there', async () => {
|
|
106
|
+
await write({
|
|
107
|
+
...BASE,
|
|
108
|
+
'Closed/access.md': rules('read:\n - everyone\n - deny Support\n'),
|
|
109
|
+
});
|
|
110
|
+
const changes = await service().prospectiveHolderChanges(workspaceId, 'Support/Runbooks', 'Closed/Runbooks');
|
|
111
|
+
expect(changes.lose).toEqual(
|
|
112
|
+
expect.arrayContaining([
|
|
113
|
+
{ kind: 'group', name: 'Support', verb: 'read' },
|
|
114
|
+
{ kind: 'group', name: 'Support', verb: 'write' },
|
|
115
|
+
]),
|
|
116
|
+
);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('a rename that carries its own rules changes nobody', async () => {
|
|
120
|
+
await write({
|
|
121
|
+
...BASE,
|
|
122
|
+
'Sales/access.md': rules('read:\n - Support\nwrite:\n - Support\n'),
|
|
123
|
+
'Sales/deal.md': '# Deal\n',
|
|
124
|
+
});
|
|
125
|
+
expect(await service().prospectiveHolderChanges(workspaceId, 'Sales', 'Revenue')).toEqual({ lose: [], gain: [] });
|
|
126
|
+
});
|
|
127
|
+
});
|