@bevel-software/platform-core-backend 0.33.0 → 0.34.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 +19 -8
- package/agent-guide/html-views.md +231 -5
- package/agent-guide/tool-manuals.md +1 -1
- 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 +14 -7
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +16 -5
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +37 -12
- 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 +17 -9
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +12 -2
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +164 -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 +35 -29
- 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/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.tools.d.ts.map +1 -1
- package/dist/modules/agent-guide/agent-guide.tools.js +13 -3
- package/dist/modules/agent-guide/agent-guide.tools.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 +3 -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 +16 -1
- 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/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 +68 -13
- 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/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 +15 -3
- package/dist/modules/secrets-vault/secrets-vault.routes.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 +24 -12
- 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-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/tool-manuals.contract.d.ts +19 -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 +13 -6
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +23 -15
- package/dist/modules/tool-manuals/tool-manuals.service.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.tools.js +25 -10
- 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 +14 -9
- 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/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.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +460 -116
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- 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/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 +3 -3
- package/src/__tests__/pg-scratch.test.ts +69 -0
- package/src/__tests__/pg-scratch.ts +31 -0
- package/src/__tests__/slow-ripgrep.ts +65 -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/catalog-revision.ts +24 -2
- package/src/core/core-ports.ts +42 -0
- package/src/core/create-core-server.ts +13 -0
- package/src/core/create-core-services.ts +49 -12
- 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 +2 -0
- 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__/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 +17 -10
- package/src/modules/access/access-control.service.ts +158 -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 +43 -33
- 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/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 +31 -0
- package/src/modules/agent-guide/agent-guide.tools.ts +13 -2
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +1 -0
- package/src/modules/agent-instructions/compose.ts +3 -1
- package/src/modules/agent-instructions/shared-file-rules.ts +17 -1
- 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/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 +107 -17
- 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/secrets-vault.routes.ts +23 -3
- 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 +44 -13
- 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__/can-write.tools.test.ts +3 -1
- package/src/modules/tool-helpers/tool-context.ts +10 -0
- 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.service.test.ts +42 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +3 -3
- package/src/modules/tool-manuals/index.ts +6 -2
- package/src/modules/tool-manuals/tool-manuals.contract.ts +18 -6
- package/src/modules/tool-manuals/tool-manuals.routes.ts +40 -3
- package/src/modules/tool-manuals/tool-manuals.service.ts +31 -15
- package/src/modules/tool-manuals/tool-manuals.tools.ts +28 -11
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +2 -2
- 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 +14 -9
- 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 +2 -2
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +22 -10
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +393 -113
- 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 +500 -155
- package/src/shared/path-order.ts +37 -8
- 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/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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
+
import { StringDecoder } from 'node:string_decoder';
|
|
3
4
|
import { logger } from '../../shared/logging.js';
|
|
4
5
|
const log = logger('access');
|
|
5
6
|
import { isAbsence } from '../../shared/fs.contract.js';
|
|
@@ -7,10 +8,8 @@ import { assertOneSpecPerLine, isCommitSha, isGitTimeout } from '../../shared/gi
|
|
|
7
8
|
import { hashEmail } from '../../shared/email-identity.js';
|
|
8
9
|
import { NodeGitRunner } from '../workflow/index.js';
|
|
9
10
|
import { readRevSha } from '../kb-fs/index.js';
|
|
10
|
-
import { DEFAULT_KB_LAYOUT, PLUGIN_MANIFEST_FILE, isPersonalPluginDir, pluginIdentityOf, platformRestoreDestination, } from '@bevel-software/platform-shared';
|
|
11
|
-
import { AccessConfigError, AccessUnreadableError, synthesizePluginPrincipals } from '../access-model/index.js';
|
|
12
|
-
import { GROUPS_YAML, SYNCED_GROUPS_YAML, parseGroupsFile, } from '../access-model/index.js';
|
|
13
|
-
import { ADMIN_CANONICAL, EVERYONE_CANONICAL, EVERYONE_DISPLAY, KNOWN_VERBS, ROLE_TOKEN_PREFIX, accessMdSelfEntries, canonicalEmail, canonicalRoleName, isAccessMdPath, mergeGroupsIntoRoles, parseAccessFile, parseOwnAccessEntries, parseRolesYaml, requiredVerbsFor, sourceVerbsFor, } from '../access-model/index.js';
|
|
11
|
+
import { DEFAULT_KB_LAYOUT, PLUGIN_MANIFEST_FILE, isFrontmatterFence, isPersonalPluginDir, pluginIdentityOf, platformRestoreDestination, } from '@bevel-software/platform-shared';
|
|
12
|
+
import { AccessConfigError, AccessUnreadableError, synthesizePluginPrincipals, GROUPS_YAML, SYNCED_GROUPS_YAML, parseGroupsFile, ADMIN_CANONICAL, EVERYONE_CANONICAL, EVERYONE_DISPLAY, KNOWN_VERBS, ROLE_TOKEN_PREFIX, GROUP_TOKEN_PREFIX, splitPrincipalToken, accessMdSelfEntries, canonicalEmail, canonicalRoleName, isAccessMdPath, mergeGroupsIntoRoles, parseAccessFile, parseOwnAccessEntries, parseRolesYaml, requiredVerbsFor, sourceVerbsFor, } from '../access-model/index.js';
|
|
14
13
|
import { DIRECTORY_SYNC_BOT_EMAIL, DIRECTORY_SYNC_BOT_NAME, } from './directory-sync-bot.js';
|
|
15
14
|
/**
|
|
16
15
|
* Read many objects from a git repo in ONE `git cat-file --batch` process.
|
|
@@ -387,18 +386,22 @@ function addDerivedKeys(model, keys) {
|
|
|
387
386
|
* twin of `principalKeysOf`: a member's key set minus everything they hold
|
|
388
387
|
* for reasons of their own. `null` when no group of that name exists.
|
|
389
388
|
*
|
|
390
|
-
* Groups are keyed by their bare canonical name
|
|
391
|
-
*
|
|
392
|
-
*
|
|
389
|
+
* Groups are keyed by `group/<name>`, and by their bare canonical name
|
|
390
|
+
* when no role owns it (`mergeGroupsIntoRoles`); roles by the bare name and
|
|
391
|
+
* `role/<name>`. `group` may be spelled either way: a bare name whose record
|
|
392
|
+
* is a ROLE still finds the group through its `group/` alias, because this
|
|
393
|
+
* question is always asked of the group.
|
|
393
394
|
*/
|
|
394
395
|
function principalKeysOfGroup(model, group) {
|
|
395
|
-
const
|
|
396
|
-
const record = model.roles.byCanonical.get(
|
|
396
|
+
const { name } = splitPrincipalToken(canonicalRoleName(group));
|
|
397
|
+
const record = model.roles.byCanonical.get(`${GROUP_TOKEN_PREFIX}${name}`);
|
|
397
398
|
if (!record || record.kind !== 'group')
|
|
398
399
|
return null;
|
|
399
|
-
const keys = new Set(
|
|
400
|
+
const keys = new Set();
|
|
400
401
|
for (const [key, principal] of model.roles.byCanonical) {
|
|
401
|
-
if (principal
|
|
402
|
+
if (principal === record)
|
|
403
|
+
keys.add(key);
|
|
404
|
+
else if (principal.kind === 'role' && principal.groupRefs?.has(name))
|
|
402
405
|
keys.add(key);
|
|
403
406
|
}
|
|
404
407
|
// Plugin principals were expanded from role/group entries; a plugin that
|
|
@@ -454,9 +457,9 @@ function isAdminEmail(model, email) {
|
|
|
454
457
|
if (model.deploymentOwners.has(email))
|
|
455
458
|
return true;
|
|
456
459
|
const roles = model.roles.byEmail.get(email);
|
|
457
|
-
// Check the explicit `role/admin` alias
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
+
// Check the explicit `role/admin` alias: it is the role's whatever the
|
|
461
|
+
// bare key holds, and a group that happens to be named "Admin" is only
|
|
462
|
+
// ever `group/admin` — its members never inherit the capability.
|
|
460
463
|
return !!roles && roles.has(ADMIN_ROLE_KEY);
|
|
461
464
|
}
|
|
462
465
|
/**
|
|
@@ -649,26 +652,11 @@ function resolveGrantSourcesForVerb(model, verb, kind, relativePath, principal,
|
|
|
649
652
|
const out = [];
|
|
650
653
|
if (principal.kind === 'role') {
|
|
651
654
|
// A named principal can be spelled two ways in a file: the bare token and
|
|
652
|
-
//
|
|
653
|
-
//
|
|
654
|
-
//
|
|
655
|
-
//
|
|
656
|
-
//
|
|
657
|
-
// under either cuts off farther grants. (The revoke splice strips both
|
|
658
|
-
// spellings in this case too, so classification and removal agree.)
|
|
659
|
-
// - SHADOWED (a group owns the bare key): the spellings are DIFFERENT
|
|
660
|
-
// principals. A bare-token principal is the GROUP — only bare entries
|
|
661
|
-
// are its own; a `role/`-token principal is the ROLE — only `role/`
|
|
662
|
-
// entries are its own. Counting the other spelling would attribute a
|
|
663
|
-
// shadowed bare token to the role (hiding a real `role/<name>`
|
|
664
|
-
// ancestor grant and making its revoke a false no-op), or vice versa.
|
|
665
|
-
//
|
|
666
|
-
// - PINNED EXACT (`tokenMatch: 'exact'`): only the literally-spelled
|
|
667
|
-
// token is this principal's entry, shadowing notwithstanding. The
|
|
668
|
-
// caller pinned the same identity into the splice it is checking —
|
|
669
|
-
// a GROUP whose group has VANISHED reads "unshadowed" here, and the
|
|
670
|
-
// alias-tolerant pair would then attribute a same-named role's
|
|
671
|
-
// surviving `role/<name>` grant to the group.
|
|
655
|
+
// its explicit `role/<name>` or `group/<name>` token. Which spellings
|
|
656
|
+
// are THIS principal's entries is `ownTokensOf`'s one rule — the bare
|
|
657
|
+
// token counts only when the bare key is this principal's (the role
|
|
658
|
+
// when one exists, else the group), and a pinned `'exact'` counts the
|
|
659
|
+
// literal spelling alone.
|
|
672
660
|
const tokens = ownTokensOf(model, principal.role, tokenMatch);
|
|
673
661
|
for (const scope of scopes) {
|
|
674
662
|
const states = tokens.map((t) => scope.byRole.get(t));
|
|
@@ -698,20 +686,37 @@ function resolveGrantSourcesForVerb(model, verb, kind, relativePath, principal,
|
|
|
698
686
|
}
|
|
699
687
|
/**
|
|
700
688
|
* WHICH token spellings in a file are THIS role-shaped principal's own entries
|
|
701
|
-
* —
|
|
702
|
-
*
|
|
703
|
-
*
|
|
704
|
-
*
|
|
705
|
-
*
|
|
689
|
+
* — in one place because the grant walk, the denial walk and the revoke splice
|
|
690
|
+
* must all agree on it (a disagreement attributes a bare token to the wrong
|
|
691
|
+
* principal, which is how a "restrict" silently strips a same-named role's
|
|
692
|
+
* grant).
|
|
693
|
+
*
|
|
694
|
+
* - `role/X` is the role: its own entries are `role/X`, plus the bare `X`
|
|
695
|
+
* unless a GROUP owns the bare key (no role X exists, a group X does).
|
|
696
|
+
* - `group/X` is the group: `group/X`, plus the bare `X` unless a ROLE
|
|
697
|
+
* owns it — under role-first precedence a same-named role always does.
|
|
698
|
+
* - A bare `X` is whoever owns the bare key, with that kind's explicit
|
|
699
|
+
* spelling; a bare token with no record (`everyone`, a plugin token, a
|
|
700
|
+
* vanished principal) is just itself plus the `role/` spelling a legacy
|
|
701
|
+
* role grant may carry.
|
|
702
|
+
* - PINNED EXACT (`tokenMatch: 'exact'`): only the literal spelling. The
|
|
703
|
+
* caller pinned the same identity into the splice it is checking.
|
|
706
704
|
*/
|
|
707
705
|
function ownTokensOf(model, role, tokenMatch) {
|
|
708
706
|
const canonical = canonicalRoleName(role);
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
: [
|
|
707
|
+
if (tokenMatch === 'exact')
|
|
708
|
+
return [canonical];
|
|
709
|
+
const { prefix, name } = splitPrincipalToken(canonical);
|
|
710
|
+
const bareOwner = model.roles.byCanonical.get(name)?.kind;
|
|
711
|
+
if (prefix === 'role')
|
|
712
|
+
return bareOwner === 'group' ? [canonical] : [name, canonical];
|
|
713
|
+
if (prefix === 'group')
|
|
714
|
+
return bareOwner === 'role' ? [canonical] : [name, canonical];
|
|
715
|
+
if (bareOwner === 'group')
|
|
716
|
+
return [name, `${GROUP_TOKEN_PREFIX}${name}`];
|
|
717
|
+
if (bareOwner === 'plugin')
|
|
718
|
+
return [name];
|
|
719
|
+
return [name, `${ROLE_TOKEN_PREFIX}${name}`];
|
|
715
720
|
}
|
|
716
721
|
/**
|
|
717
722
|
* The polarity twin of {@link resolveGrantSourcesForVerb}: every file scope
|
|
@@ -836,6 +841,73 @@ function parentDirOf(relativePath) {
|
|
|
836
841
|
const cut = relativePath.lastIndexOf('/');
|
|
837
842
|
return cut === -1 ? '' : relativePath.slice(0, cut);
|
|
838
843
|
}
|
|
844
|
+
/** The first read of {@link frontmatterHead}; each later one doubles, up to the last. */
|
|
845
|
+
const HEAD_FIRST_READ = 1_024;
|
|
846
|
+
const HEAD_LAST_READ = 64 * 1_024;
|
|
847
|
+
/**
|
|
848
|
+
* The start of `file` that holds everything its frontmatter can say: its
|
|
849
|
+
* first line when that is no fence (no frontmatter at all), the text through
|
|
850
|
+
* the closing fence when there is one, and the whole file when an opening
|
|
851
|
+
* fence is never closed. Scanned for its frontmatter (`scanFrontmatter`), it
|
|
852
|
+
* answers exactly as the whole file does, by the same fence rule
|
|
853
|
+
* (`isFrontmatterFence`) — and a file with no frontmatter costs one small
|
|
854
|
+
* read however long it is.
|
|
855
|
+
*/
|
|
856
|
+
async function frontmatterHead(file) {
|
|
857
|
+
const handle = await fs.open(file, 'r');
|
|
858
|
+
try {
|
|
859
|
+
const decoder = new StringDecoder('utf8');
|
|
860
|
+
// What was read, kept as it was decoded and joined once, when answered:
|
|
861
|
+
// each character is scanned once, however long a line runs.
|
|
862
|
+
const pieces = [];
|
|
863
|
+
let before = 0;
|
|
864
|
+
// The line being read so far, folded (see `foldLine`), or null once it
|
|
865
|
+
// can no longer be a fence.
|
|
866
|
+
let line = '';
|
|
867
|
+
let first = true;
|
|
868
|
+
let position = 0;
|
|
869
|
+
for (let size = HEAD_FIRST_READ;; size = Math.min(size * 2, HEAD_LAST_READ)) {
|
|
870
|
+
const chunk = Buffer.allocUnsafe(size);
|
|
871
|
+
const { bytesRead } = await handle.read(chunk, 0, size, position);
|
|
872
|
+
if (bytesRead === 0)
|
|
873
|
+
return pieces.join('') + decoder.end();
|
|
874
|
+
position += bytesRead;
|
|
875
|
+
const piece = decoder.write(chunk.subarray(0, bytesRead));
|
|
876
|
+
pieces.push(piece);
|
|
877
|
+
let from = 0;
|
|
878
|
+
for (let nl = piece.indexOf('\n'); nl !== -1; nl = piece.indexOf('\n', from)) {
|
|
879
|
+
const fence = line !== null && isFrontmatterFence(foldLine(line, piece.slice(from, nl)));
|
|
880
|
+
// The first line opens a block or there is none; after it, the first
|
|
881
|
+
// fence closes the block.
|
|
882
|
+
if (first ? !fence : fence)
|
|
883
|
+
return pieces.join('').slice(0, before + nl);
|
|
884
|
+
first = false;
|
|
885
|
+
line = '';
|
|
886
|
+
from = nl + 1;
|
|
887
|
+
}
|
|
888
|
+
if (line !== null) {
|
|
889
|
+
line = foldLine(line, piece.slice(from));
|
|
890
|
+
if (!'---'.startsWith(line.trim()))
|
|
891
|
+
line = null;
|
|
892
|
+
}
|
|
893
|
+
// A first line still unfinished that already cannot be a fence.
|
|
894
|
+
if (first && line === null)
|
|
895
|
+
return pieces.join('');
|
|
896
|
+
before += piece.length;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
899
|
+
finally {
|
|
900
|
+
await handle.close();
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* `line` continued by `more`, every run of whitespace folded to one space.
|
|
905
|
+
* Trimmed, it is `---` exactly when the unfolded line is, so it judges a fence
|
|
906
|
+
* as `isFrontmatterFence` does while staying a few characters long.
|
|
907
|
+
*/
|
|
908
|
+
function foldLine(line, more) {
|
|
909
|
+
return `${line}${more}`.replace(/\s+/g, ' ');
|
|
910
|
+
}
|
|
839
911
|
/**
|
|
840
912
|
* One file's own-entries, parsed as the path `asName` would be read.
|
|
841
913
|
*
|
|
@@ -946,15 +1018,15 @@ function eligibleHoldersResolved(model, verb, relativePath, fileOwn) {
|
|
|
946
1018
|
const { byRole, byEmail, everyone } = resolveAtPath(model, verb, relativePath, fileOwn);
|
|
947
1019
|
// (kind, display name) → one entry. The `byRole` keys are the merged
|
|
948
1020
|
// index's canonical tokens exactly as granted (bare, or the
|
|
949
|
-
// `role
|
|
950
|
-
// its kind — a `role/` alias always hits the role record, a
|
|
951
|
-
//
|
|
952
|
-
// record (the built-in `everyone`, or a grant naming a
|
|
953
|
-
// principal) degrades to 'role', the pre-groups display.
|
|
954
|
-
// name is granted as BOTH (
|
|
955
|
-
// group via
|
|
956
|
-
// principals, and collapsing them to one would hide the
|
|
957
|
-
//
|
|
1021
|
+
// `role/` or `group/` alias); the `byCanonical` record a key hits carries
|
|
1022
|
+
// its kind — a `role/` alias always hits the role record, a `group/` alias
|
|
1023
|
+
// the group record, a bare key the role when one exists, else the group. A
|
|
1024
|
+
// token with no record (the built-in `everyone`, or a grant naming a
|
|
1025
|
+
// since-vanished principal) degrades to 'role', the pre-groups display.
|
|
1026
|
+
// When one display name is granted as BOTH (the role plus a same-named
|
|
1027
|
+
// group via `group/`) BOTH entries survive — they are DIFFERENT
|
|
1028
|
+
// principals, and collapsing them to one would hide one of the grants from
|
|
1029
|
+
// every consumer of the eligible list.
|
|
958
1030
|
const byIdentity = new Map();
|
|
959
1031
|
const addPrincipal = (name, kind) => {
|
|
960
1032
|
const key = `${kind}\0${name.toLowerCase()}`;
|
|
@@ -997,9 +1069,9 @@ function eligibleHoldersResolved(model, verb, relativePath, fileOwn) {
|
|
|
997
1069
|
// access.md (it'd say "restricted to no one" when Admin is the answer).
|
|
998
1070
|
if (verb === 'write' &&
|
|
999
1071
|
(relativePath === 'roles.yaml' || isAccessMdPath(relativePath))) {
|
|
1000
|
-
// Look the Admin ROLE up via its explicit alias
|
|
1001
|
-
//
|
|
1002
|
-
//
|
|
1072
|
+
// Look the Admin ROLE up via its explicit alias, the key that is always
|
|
1073
|
+
// the role's. The override is the ROLE's capability, so the row's kind is
|
|
1074
|
+
// 'role' regardless.
|
|
1003
1075
|
const adminRole = model.roles.byCanonical.get(ADMIN_ROLE_KEY);
|
|
1004
1076
|
addPrincipal(adminRole ? adminRole.displayName : ADMIN_CANONICAL, 'role');
|
|
1005
1077
|
}
|
|
@@ -1323,7 +1395,11 @@ export class AccessControlService {
|
|
|
1323
1395
|
const model = await this.loadModel(workspaceId);
|
|
1324
1396
|
const email = canonicalEmail(userEmail);
|
|
1325
1397
|
const names = [];
|
|
1326
|
-
|
|
1398
|
+
// Each group once, through its `group/` alias (the bare key, when the
|
|
1399
|
+
// group owns it, is the same record).
|
|
1400
|
+
for (const [key, principal] of model.roles.byCanonical) {
|
|
1401
|
+
if (!key.startsWith(GROUP_TOKEN_PREFIX))
|
|
1402
|
+
continue;
|
|
1327
1403
|
if (principal.kind === 'group' && principal.emails.has(email))
|
|
1328
1404
|
names.push(principal.displayName);
|
|
1329
1405
|
}
|
|
@@ -1479,7 +1555,7 @@ export class AccessControlService {
|
|
|
1479
1555
|
*/
|
|
1480
1556
|
async previewAccessAfterRelocation(workspaceId, userEmail, fromPath, toPath, opts) {
|
|
1481
1557
|
const repoDir = await this.repoDir(workspaceId);
|
|
1482
|
-
const { isFolder, ownThere: own, landing } = await this.relocationSubject(repoDir, fromPath, toPath);
|
|
1558
|
+
const { isFolder, ownThere: own, landing } = await this.relocationSubject(repoDir, fromPath, toPath, opts?.sourceContent);
|
|
1483
1559
|
const model = withRelocatedAccessFiles(await this.loadModel(workspaceId), fromPath, toPath, { sourceRemains: opts?.sourceRemains === true, sourceIsFolder: isFolder, landing });
|
|
1484
1560
|
const machineOwned = this.machineOwnedWriteRule(userEmail, toPath);
|
|
1485
1561
|
return {
|
|
@@ -1604,9 +1680,9 @@ export class AccessControlService {
|
|
|
1604
1680
|
}
|
|
1605
1681
|
// Roles = the built-in `everyone` role plus every declared role's display
|
|
1606
1682
|
// name — ROLE principals only, never groups. Each role is enumerated via
|
|
1607
|
-
// its `role/<canonical>` alias key, which exists exactly once per role
|
|
1608
|
-
//
|
|
1609
|
-
//
|
|
1683
|
+
// its `role/<canonical>` alias key, which exists exactly once per role;
|
|
1684
|
+
// each group likewise via its `group/<canonical>` alias (a group that
|
|
1685
|
+
// owns its bare key is registered under both, as one record). `everyone`
|
|
1610
1686
|
// is surfaced so the share UI can grant public read; the grant route
|
|
1611
1687
|
// gates it to the `read` verb only (write/owner/download everyone stay a
|
|
1612
1688
|
// direct-access.md edit).
|
|
@@ -1620,7 +1696,7 @@ export class AccessControlService {
|
|
|
1620
1696
|
for (const [key, principal] of model.roles.byCanonical) {
|
|
1621
1697
|
if (key.startsWith(ROLE_TOKEN_PREFIX))
|
|
1622
1698
|
roles.push(principal.displayName);
|
|
1623
|
-
else if (principal.kind === 'group')
|
|
1699
|
+
else if (key.startsWith(GROUP_TOKEN_PREFIX) && principal.kind === 'group')
|
|
1624
1700
|
groups.push(principal.displayName);
|
|
1625
1701
|
else if (principal.kind === 'plugin' &&
|
|
1626
1702
|
principal.pluginName &&
|
|
@@ -1990,13 +2066,18 @@ export class AccessControlService {
|
|
|
1990
2066
|
* in the new (body-governed) format, where its frontmatter is self-access —
|
|
1991
2067
|
* see {@link accessMdSelfEntries}. A legacy `access.md` still yields null:
|
|
1992
2068
|
* its frontmatter IS the folder rules the dir chain already applies.
|
|
2069
|
+
*
|
|
2070
|
+
* Any other file declares them in its frontmatter alone, so only as much of
|
|
2071
|
+
* it is read as the frontmatter takes (see {@link frontmatterHead}): a batch
|
|
2072
|
+
* over a tree of megabyte transcripts reads a line of each, not the tree.
|
|
1993
2073
|
*/
|
|
1994
2074
|
async readOwnEntries(repoDir, relativePath) {
|
|
1995
2075
|
if (relativePath === 'roles.yaml')
|
|
1996
2076
|
return null;
|
|
2077
|
+
const file = path.join(repoDir, relativePath);
|
|
1997
2078
|
let text;
|
|
1998
2079
|
try {
|
|
1999
|
-
text = await fs.readFile(
|
|
2080
|
+
text = isAccessMdPath(relativePath) ? await fs.readFile(file, 'utf-8') : await frontmatterHead(file);
|
|
2000
2081
|
}
|
|
2001
2082
|
catch {
|
|
2002
2083
|
return null;
|
|
@@ -2028,18 +2109,26 @@ export class AccessControlService {
|
|
|
2028
2109
|
* Only absence is an answer (see `isAbsence`): a probe that failed on
|
|
2029
2110
|
* permissions or I/O does not say "this is a file", and reading a folder as
|
|
2030
2111
|
* one would resolve it through frontmatter it does not have.
|
|
2112
|
+
*
|
|
2113
|
+
* `sourceContent` is the text of a source that is NO repository path — a
|
|
2114
|
+
* file staged in the workspace's `tmp/` folder, which `copy_file` lands in
|
|
2115
|
+
* the repository. Nothing is probed on disk for it: it is one file by the
|
|
2116
|
+
* ref's own rule, and its text is read exactly as a repository file's is,
|
|
2117
|
+
* so the copy previews the rules it carries in.
|
|
2031
2118
|
*/
|
|
2032
|
-
async relocationSubject(repoDir, fromPath, toPath) {
|
|
2119
|
+
async relocationSubject(repoDir, fromPath, toPath, sourceContent) {
|
|
2033
2120
|
const nothing = { isFolder: false, ownHere: null, ownThere: null, landing: null };
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2121
|
+
if (sourceContent === undefined) {
|
|
2122
|
+
const fromStat = await fs.lstat(path.join(repoDir, fromPath)).catch((err) => {
|
|
2123
|
+
if (isAbsence(err))
|
|
2124
|
+
return null;
|
|
2125
|
+
throw err;
|
|
2126
|
+
});
|
|
2127
|
+
if (fromStat?.isSymbolicLink() === true)
|
|
2128
|
+
return nothing;
|
|
2129
|
+
if (fromStat?.isDirectory() === true)
|
|
2130
|
+
return { ...nothing, isFolder: true };
|
|
2131
|
+
}
|
|
2043
2132
|
// `roles.yaml` carries no own-entries wherever it sits, exactly as
|
|
2044
2133
|
// `readOwnEntries` has it; a read that fails for any reason is no rules,
|
|
2045
2134
|
// which is what the gates would say about the same file.
|
|
@@ -2047,7 +2136,7 @@ export class AccessControlService {
|
|
|
2047
2136
|
return nothing;
|
|
2048
2137
|
let text;
|
|
2049
2138
|
try {
|
|
2050
|
-
text = await fs.readFile(path.join(repoDir, fromPath), 'utf-8');
|
|
2139
|
+
text = sourceContent ?? (await fs.readFile(path.join(repoDir, fromPath), 'utf-8'));
|
|
2051
2140
|
}
|
|
2052
2141
|
catch {
|
|
2053
2142
|
return nothing;
|