@bevel-software/platform-core-backend 0.15.1 → 0.20.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/THIRD-PARTY-NOTICES.md +4 -4
- package/dist/core/catalog-cache-invalidation.d.ts +16 -0
- package/dist/core/catalog-cache-invalidation.d.ts.map +1 -1
- package/dist/core/catalog-cache-invalidation.js +6 -1
- package/dist/core/catalog-cache-invalidation.js.map +1 -1
- package/dist/core/catalog-revision.d.ts +39 -0
- package/dist/core/catalog-revision.d.ts.map +1 -0
- package/dist/core/catalog-revision.js +94 -0
- package/dist/core/catalog-revision.js.map +1 -0
- package/dist/core/create-core-server.d.ts +7 -0
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +221 -75
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +52 -2
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +222 -87
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +138 -0
- package/dist/core/lifecycle.d.ts.map +1 -0
- package/dist/core/lifecycle.js +218 -0
- package/dist/core/lifecycle.js.map +1 -0
- package/dist/core/public-config.d.ts +82 -0
- package/dist/core/public-config.d.ts.map +1 -0
- package/dist/core/public-config.js +78 -0
- package/dist/core/public-config.js.map +1 -0
- package/dist/core/readiness.d.ts +86 -0
- package/dist/core/readiness.d.ts.map +1 -0
- package/dist/core/readiness.js +56 -0
- package/dist/core/readiness.js.map +1 -0
- package/dist/core-config.d.ts +30 -0
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +64 -2
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +215 -11
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +57 -11
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +616 -155
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access-mutation.service.d.ts +71 -5
- package/dist/modules/access/access-mutation.service.d.ts.map +1 -1
- package/dist/modules/access/access-mutation.service.js +161 -13
- package/dist/modules/access/access-mutation.service.js.map +1 -1
- package/dist/modules/access/access-view.d.ts +147 -0
- package/dist/modules/access/access-view.d.ts.map +1 -0
- package/dist/modules/access/access-view.js +211 -0
- package/dist/modules/access/access-view.js.map +1 -0
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +255 -79
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/admin-locked-commit.d.ts +2 -3
- package/dist/modules/access/admin-locked-commit.d.ts.map +1 -1
- package/dist/modules/access/admin-locked-commit.js +9 -8
- package/dist/modules/access/admin-locked-commit.js.map +1 -1
- package/dist/modules/access/admin-route-helpers.d.ts.map +1 -1
- package/dist/modules/access/admin-route-helpers.js +4 -4
- package/dist/modules/access/admin-route-helpers.js.map +1 -1
- package/dist/modules/access/change-read-gate.d.ts +53 -0
- package/dist/modules/access/change-read-gate.d.ts.map +1 -0
- package/dist/modules/access/change-read-gate.js +134 -0
- package/dist/modules/access/change-read-gate.js.map +1 -0
- package/dist/modules/access/creator-access.d.ts +33 -39
- package/dist/modules/access/creator-access.d.ts.map +1 -1
- package/dist/modules/access/creator-access.js +92 -119
- package/dist/modules/access/creator-access.js.map +1 -1
- package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
- package/dist/modules/access/directory-sync-bot.js +3 -1
- package/dist/modules/access/directory-sync-bot.js.map +1 -1
- package/dist/modules/access/groups-admin.service.d.ts +3 -3
- package/dist/modules/access/groups-admin.service.js +2 -2
- package/dist/modules/access/reference-scan.d.ts +1 -1
- package/dist/modules/access/reference-scan.d.ts.map +1 -1
- package/dist/modules/access/reference-scan.js +5 -4
- package/dist/modules/access/reference-scan.js.map +1 -1
- package/dist/modules/access/roles-admin.service.d.ts +72 -13
- package/dist/modules/access/roles-admin.service.d.ts.map +1 -1
- package/dist/modules/access/roles-admin.service.js +71 -13
- package/dist/modules/access/roles-admin.service.js.map +1 -1
- package/dist/modules/access/synced-groups-committer.d.ts.map +1 -1
- package/dist/modules/access/synced-groups-committer.js +8 -6
- package/dist/modules/access/synced-groups-committer.js.map +1 -1
- package/dist/modules/access/synced-groups-writer.d.ts.map +1 -1
- package/dist/modules/access/synced-groups-writer.js +3 -8
- package/dist/modules/access/synced-groups-writer.js.map +1 -1
- package/dist/modules/access/user-access-removal.service.d.ts +209 -0
- package/dist/modules/access/user-access-removal.service.d.ts.map +1 -0
- package/dist/modules/access/user-access-removal.service.js +662 -0
- package/dist/modules/access/user-access-removal.service.js.map +1 -0
- package/dist/modules/access-model/access-errors.d.ts +32 -1
- package/dist/modules/access-model/access-errors.d.ts.map +1 -1
- package/dist/modules/access-model/access-errors.js +38 -11
- package/dist/modules/access-model/access-errors.js.map +1 -1
- package/dist/modules/access-model/access-grammar.d.ts +49 -24
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +68 -48
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/access-model/access-splice.d.ts.map +1 -1
- package/dist/modules/access-model/access-splice.js +18 -18
- package/dist/modules/access-model/access-splice.js.map +1 -1
- package/dist/modules/access-model/access-template.d.ts +22 -0
- package/dist/modules/access-model/access-template.d.ts.map +1 -0
- package/dist/modules/access-model/access-template.js +42 -0
- package/dist/modules/access-model/access-template.js.map +1 -0
- package/dist/modules/access-model/change-gate.d.ts +65 -0
- package/dist/modules/access-model/change-gate.d.ts.map +1 -0
- package/dist/modules/access-model/change-gate.js +25 -0
- package/dist/modules/access-model/change-gate.js.map +1 -0
- package/dist/modules/access-model/creator.d.ts +13 -16
- package/dist/modules/access-model/creator.d.ts.map +1 -1
- package/dist/modules/access-model/creator.js.map +1 -1
- package/dist/modules/access-model/frontmatter-lines.d.ts +27 -0
- package/dist/modules/access-model/frontmatter-lines.d.ts.map +1 -0
- package/dist/modules/access-model/frontmatter-lines.js +74 -0
- package/dist/modules/access-model/frontmatter-lines.js.map +1 -0
- package/dist/modules/access-model/plugin-principals.d.ts +5 -3
- package/dist/modules/access-model/plugin-principals.d.ts.map +1 -1
- package/dist/modules/access-model/plugin-principals.js +11 -17
- package/dist/modules/access-model/plugin-principals.js.map +1 -1
- package/dist/modules/access-model/roles-yaml-guard.d.ts +73 -2
- package/dist/modules/access-model/roles-yaml-guard.d.ts.map +1 -1
- package/dist/modules/access-model/roles-yaml-guard.js +153 -3
- package/dist/modules/access-model/roles-yaml-guard.js.map +1 -1
- package/dist/modules/admin/admin-access.service.d.ts.map +1 -1
- package/dist/modules/admin/admin-access.service.js +5 -2
- package/dist/modules/admin/admin-access.service.js.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +21 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.js +38 -0
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -0
- package/dist/modules/agent-instructions/compose.d.ts +71 -0
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -0
- package/dist/modules/agent-instructions/compose.js +234 -0
- package/dist/modules/agent-instructions/compose.js.map +1 -0
- package/dist/modules/agent-instructions/index.d.ts +4 -0
- package/dist/modules/agent-instructions/index.d.ts.map +1 -0
- package/dist/modules/agent-instructions/index.js +4 -0
- package/dist/modules/agent-instructions/index.js.map +1 -0
- package/dist/modules/agent-instructions/read-preamble.d.ts +37 -0
- package/dist/modules/agent-instructions/read-preamble.d.ts.map +1 -0
- package/dist/modules/agent-instructions/read-preamble.js +81 -0
- package/dist/modules/agent-instructions/read-preamble.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts +54 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -0
- package/dist/modules/audit/agent-audit.service.js +290 -0
- package/dist/modules/audit/agent-audit.service.js.map +1 -0
- package/dist/modules/audit/agent-rest-audit.middleware.d.ts +40 -0
- package/dist/modules/audit/agent-rest-audit.middleware.d.ts.map +1 -0
- package/dist/modules/audit/agent-rest-audit.middleware.js +75 -0
- package/dist/modules/audit/agent-rest-audit.middleware.js.map +1 -0
- package/dist/modules/audit/audit.contract.d.ts +145 -0
- package/dist/modules/audit/audit.contract.d.ts.map +1 -0
- package/dist/modules/audit/audit.contract.js +35 -0
- package/dist/modules/audit/audit.contract.js.map +1 -0
- package/dist/modules/audit/audit.routes.d.ts +21 -0
- package/dist/modules/audit/audit.routes.d.ts.map +1 -0
- package/dist/modules/audit/audit.routes.js +157 -0
- package/dist/modules/audit/audit.routes.js.map +1 -0
- package/dist/modules/audit/event-classifier.d.ts +52 -0
- package/dist/modules/audit/event-classifier.d.ts.map +1 -0
- package/dist/modules/audit/event-classifier.js +123 -0
- package/dist/modules/audit/event-classifier.js.map +1 -0
- package/dist/modules/audit/index.d.ts +7 -0
- package/dist/modules/audit/index.d.ts.map +1 -0
- package/dist/modules/audit/index.js +7 -0
- package/dist/modules/audit/index.js.map +1 -0
- package/dist/modules/audit/request-audit.d.ts +57 -0
- package/dist/modules/audit/request-audit.d.ts.map +1 -0
- package/dist/modules/audit/request-audit.js +117 -0
- package/dist/modules/audit/request-audit.js.map +1 -0
- package/dist/modules/auth/account-erasure.service.d.ts +30 -4
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
- package/dist/modules/auth/account-erasure.service.js +96 -10
- package/dist/modules/auth/account-erasure.service.js.map +1 -1
- package/dist/modules/auth/account.routes.d.ts +6 -3
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +109 -10
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts +10 -3
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +9 -4
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +89 -5
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +160 -25
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts +46 -3
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +99 -21
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +14 -2
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.d.ts.map +1 -1
- package/dist/modules/connection-probe/connection-probe.service.js +56 -7
- package/dist/modules/connection-probe/connection-probe.service.js.map +1 -1
- package/dist/modules/database/advisory-lock.d.ts +103 -0
- package/dist/modules/database/advisory-lock.d.ts.map +1 -0
- package/dist/modules/database/advisory-lock.js +320 -0
- package/dist/modules/database/advisory-lock.js.map +1 -0
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +9 -1
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +859 -99
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +218 -0
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +26 -6
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.d.ts.map +1 -1
- package/dist/modules/declared-variables/declared-variables.routes.js +4 -2
- package/dist/modules/declared-variables/declared-variables.routes.js.map +1 -1
- package/dist/modules/diff/diff.routes.d.ts.map +1 -1
- package/dist/modules/diff/diff.routes.js +2 -4
- package/dist/modules/diff/diff.routes.js.map +1 -1
- package/dist/modules/diff/diff.service.d.ts +4 -1
- package/dist/modules/diff/diff.service.d.ts.map +1 -1
- package/dist/modules/diff/diff.service.js +84 -81
- package/dist/modules/diff/diff.service.js.map +1 -1
- package/dist/modules/{workspace → kb-fs}/bevel-ignore.d.ts +14 -9
- package/dist/modules/kb-fs/bevel-ignore.d.ts.map +1 -0
- package/dist/modules/{workspace → kb-fs}/bevel-ignore.js +24 -14
- package/dist/modules/kb-fs/bevel-ignore.js.map +1 -0
- package/dist/modules/kb-fs/file-change-notifier.d.ts.map +1 -1
- package/dist/modules/kb-fs/file-change-notifier.js +3 -1
- package/dist/modules/kb-fs/file-change-notifier.js.map +1 -1
- package/dist/modules/kb-fs/git-guarded-filesystem.d.ts +45 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.d.ts.map +1 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.js +117 -0
- package/dist/modules/kb-fs/git-guarded-filesystem.js.map +1 -0
- package/dist/modules/kb-fs/locking-filesystem.d.ts +113 -18
- package/dist/modules/kb-fs/locking-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/locking-filesystem.js +353 -76
- package/dist/modules/kb-fs/locking-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/node-fs.d.ts +23 -0
- package/dist/modules/kb-fs/node-fs.d.ts.map +1 -0
- package/dist/modules/kb-fs/node-fs.js +158 -0
- package/dist/modules/kb-fs/node-fs.js.map +1 -0
- package/dist/modules/kb-fs/read-only-filesystem.d.ts +10 -9
- package/dist/modules/kb-fs/read-only-filesystem.d.ts.map +1 -1
- package/dist/modules/kb-fs/read-only-filesystem.js +18 -9
- package/dist/modules/kb-fs/read-only-filesystem.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +100 -3
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +195 -3
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.js +4 -2
- package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.service.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.service.js +7 -5
- package/dist/modules/kb-sync/kb-sync.service.js.map +1 -1
- package/dist/modules/marketplace/git-http.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/git-http.routes.js +6 -4
- package/dist/modules/marketplace/git-http.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts +12 -2
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js +32 -3
- package/dist/modules/marketplace/github-facade/github-facade-admin.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts +27 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js +45 -0
- package/dist/modules/marketplace/github-facade/github-facade-credentials.service.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.routes.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.routes.js +30 -6
- package/dist/modules/marketplace/github-facade/github-facade.routes.js.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts +21 -9
- package/dist/modules/marketplace/github-facade/github-facade.service.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/github-facade.service.js +60 -19
- package/dist/modules/marketplace/github-facade/github-facade.service.js.map +1 -1
- package/dist/modules/marketplace/github-facade/index.d.ts +1 -1
- package/dist/modules/marketplace/github-facade/index.d.ts.map +1 -1
- package/dist/modules/marketplace/github-facade/index.js +1 -1
- package/dist/modules/marketplace/github-facade/index.js.map +1 -1
- package/dist/modules/marketplace/marketplace-repo.service.d.ts +14 -1
- package/dist/modules/marketplace/marketplace-repo.service.d.ts.map +1 -1
- package/dist/modules/marketplace/marketplace-repo.service.js +26 -8
- package/dist/modules/marketplace/marketplace-repo.service.js.map +1 -1
- package/dist/modules/mcp/downstream-pool.d.ts +107 -0
- package/dist/modules/mcp/downstream-pool.d.ts.map +1 -0
- package/dist/modules/mcp/downstream-pool.js +221 -0
- package/dist/modules/mcp/downstream-pool.js.map +1 -0
- package/dist/modules/mcp/downstream-token-refresh.d.ts +77 -0
- package/dist/modules/mcp/downstream-token-refresh.d.ts.map +1 -0
- package/dist/modules/mcp/downstream-token-refresh.js +166 -0
- package/dist/modules/mcp/downstream-token-refresh.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli-args.d.ts +78 -0
- package/dist/modules/mcp/first-call-probe.cli-args.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli-args.js +151 -0
- package/dist/modules/mcp/first-call-probe.cli-args.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli.d.ts +2 -0
- package/dist/modules/mcp/first-call-probe.cli.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.cli.js +62 -0
- package/dist/modules/mcp/first-call-probe.cli.js.map +1 -0
- package/dist/modules/mcp/first-call-probe.d.ts +165 -0
- package/dist/modules/mcp/first-call-probe.d.ts.map +1 -0
- package/dist/modules/mcp/first-call-probe.js +298 -0
- package/dist/modules/mcp/first-call-probe.js.map +1 -0
- package/dist/modules/mcp/manual-failure-memo.d.ts +42 -17
- package/dist/modules/mcp/manual-failure-memo.d.ts.map +1 -1
- package/dist/modules/mcp/manual-failure-memo.js +79 -23
- package/dist/modules/mcp/manual-failure-memo.js.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.d.ts +10 -5
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +56 -16
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.routes.d.ts +4 -4
- package/dist/modules/mcp/mcp.routes.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.routes.js +91 -180
- package/dist/modules/mcp/mcp.routes.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +226 -61
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +758 -161
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts +59 -0
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +184 -10
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js +3 -1
- package/dist/modules/mcp/oauth/oauth-consent.routes.js.map +1 -1
- package/dist/modules/mcp/surface-log-throttle.d.ts +59 -0
- package/dist/modules/mcp/surface-log-throttle.d.ts.map +1 -0
- package/dist/modules/mcp/surface-log-throttle.js +94 -0
- package/dist/modules/mcp/surface-log-throttle.js.map +1 -0
- package/dist/modules/plugins/compile/compile-marketplace.d.ts +13 -6
- package/dist/modules/plugins/compile/compile-marketplace.d.ts.map +1 -1
- package/dist/modules/plugins/compile/compile-marketplace.js +119 -36
- package/dist/modules/plugins/compile/compile-marketplace.js.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts +8 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.d.ts.map +1 -1
- package/dist/modules/plugins/compile/marketplace-compiler.service.js +9 -6
- package/dist/modules/plugins/compile/marketplace-compiler.service.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js +32 -9
- package/dist/modules/plugins/discovery/bundle-dialect/bundle.source.js.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts +26 -6
- package/dist/modules/plugins/discovery/bundle-dialect/registry.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js +71 -14
- package/dist/modules/plugins/discovery/bundle-dialect/registry.js.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts +4 -2
- package/dist/modules/plugins/discovery/kb-plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/kb-plugin-source.js +9 -6
- package/dist/modules/plugins/discovery/kb-plugin-source.js.map +1 -1
- package/dist/modules/plugins/discovery/native.source.d.ts +2 -1
- package/dist/modules/plugins/discovery/native.source.d.ts.map +1 -1
- package/dist/modules/plugins/discovery/native.source.js +22 -4
- package/dist/modules/plugins/discovery/native.source.js.map +1 -1
- package/dist/modules/plugins/discovery/plugin-source.d.ts +17 -3
- package/dist/modules/plugins/discovery/plugin-source.d.ts.map +1 -1
- package/dist/modules/plugins/index.d.ts +6 -3
- package/dist/modules/plugins/index.d.ts.map +1 -1
- package/dist/modules/plugins/index.js +6 -3
- package/dist/modules/plugins/index.js.map +1 -1
- package/dist/modules/plugins/join-request-jobs.service.d.ts +250 -0
- package/dist/modules/plugins/join-request-jobs.service.d.ts.map +1 -0
- package/dist/modules/plugins/join-request-jobs.service.js +602 -0
- package/dist/modules/plugins/join-request-jobs.service.js.map +1 -0
- package/dist/modules/plugins/join-request-records.store.d.ts +161 -0
- package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -0
- package/dist/modules/plugins/join-request-records.store.js +179 -0
- package/dist/modules/plugins/join-request-records.store.js.map +1 -0
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-requests.service.js +4 -2
- package/dist/modules/plugins/join-requests.service.js.map +1 -1
- package/dist/modules/plugins/plugin-links.d.ts +4 -1
- package/dist/modules/plugins/plugin-links.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.js +6 -3
- package/dist/modules/plugins/plugin-links.js.map +1 -1
- package/dist/modules/plugins/plugin-links.service.d.ts +2 -5
- package/dist/modules/plugins/plugin-links.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-links.service.js +4 -13
- package/dist/modules/plugins/plugin-links.service.js.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.d.ts +91 -19
- package/dist/modules/plugins/plugin-provision.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-provision.service.js +183 -38
- package/dist/modules/plugins/plugin-provision.service.js.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts +3 -1
- package/dist/modules/plugins/plugin-rename.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugin-rename.service.js +20 -11
- package/dist/modules/plugins/plugin-rename.service.js.map +1 -1
- package/dist/modules/plugins/plugins.contract.d.ts +52 -4
- package/dist/modules/plugins/plugins.contract.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts +38 -5
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +190 -116
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/plugins/plugins.service.d.ts +38 -6
- package/dist/modules/plugins/plugins.service.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.service.js +86 -17
- package/dist/modules/plugins/plugins.service.js.map +1 -1
- package/dist/modules/plugins/plugins.tools.d.ts +25 -0
- package/dist/modules/plugins/plugins.tools.d.ts.map +1 -0
- package/dist/modules/plugins/plugins.tools.js +82 -0
- package/dist/modules/plugins/plugins.tools.js.map +1 -0
- package/dist/modules/plugins/teams.routes.d.ts +42 -0
- package/dist/modules/plugins/teams.routes.d.ts.map +1 -0
- package/dist/modules/plugins/teams.routes.js +79 -0
- package/dist/modules/plugins/teams.routes.js.map +1 -0
- package/dist/modules/secrets-vault/db-secrets-vault.service.d.ts +40 -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 +202 -37
- 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.map +1 -1
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.d.ts.map +1 -1
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js +5 -3
- package/dist/modules/secrets-vault/mcp-oauth-discovery.service.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js +3 -1
- package/dist/modules/secrets-vault/secrets-variable-loader.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts +78 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.contract.js +40 -0
- package/dist/modules/secrets-vault/secrets-vault.contract.js.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.d.ts.map +1 -1
- package/dist/modules/secrets-vault/secrets-vault.routes.js +106 -52
- package/dist/modules/secrets-vault/secrets-vault.routes.js.map +1 -1
- package/dist/modules/settings/connection-check.d.ts +118 -0
- package/dist/modules/settings/connection-check.d.ts.map +1 -0
- package/dist/modules/settings/connection-check.js +287 -0
- package/dist/modules/settings/connection-check.js.map +1 -0
- package/dist/modules/settings/deployment-settings.service.d.ts +162 -8
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +375 -52
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/git-root-folders.d.ts +54 -0
- package/dist/modules/settings/git-root-folders.d.ts.map +1 -0
- package/dist/modules/settings/git-root-folders.js +130 -0
- package/dist/modules/settings/git-root-folders.js.map +1 -0
- package/dist/modules/settings/oidc-check.d.ts +85 -0
- package/dist/modules/settings/oidc-check.d.ts.map +1 -0
- package/dist/modules/settings/oidc-check.js +172 -0
- package/dist/modules/settings/oidc-check.js.map +1 -0
- package/dist/modules/settings/setup.routes.d.ts +31 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +400 -108
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/allowed-tools-check.d.ts +132 -0
- package/dist/modules/skills/allowed-tools-check.d.ts.map +1 -0
- package/dist/modules/skills/allowed-tools-check.js +260 -0
- package/dist/modules/skills/allowed-tools-check.js.map +1 -0
- package/dist/modules/skills/index.d.ts +3 -1
- package/dist/modules/skills/index.d.ts.map +1 -1
- package/dist/modules/skills/index.js +1 -0
- package/dist/modules/skills/index.js.map +1 -1
- package/dist/modules/skills/pending-skills.service.d.ts +6 -11
- package/dist/modules/skills/pending-skills.service.d.ts.map +1 -1
- package/dist/modules/skills/pending-skills.service.js +18 -70
- package/dist/modules/skills/pending-skills.service.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.js +9 -6
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +44 -10
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.d.ts +8 -1
- package/dist/modules/skills/skills.routes.d.ts.map +1 -1
- package/dist/modules/skills/skills.routes.js +16 -2
- package/dist/modules/skills/skills.routes.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +31 -7
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +191 -81
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts +4 -1
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +41 -6
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/connection-key-rejection.d.ts +18 -0
- package/dist/modules/tool-auth/connection-key-rejection.d.ts.map +1 -0
- package/dist/modules/tool-auth/connection-key-rejection.js +20 -0
- package/dist/modules/tool-auth/connection-key-rejection.js.map +1 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts +14 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.d.ts.map +1 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.js +67 -0
- package/dist/modules/tool-auth/connection-keys-admin.routes.js.map +1 -0
- package/dist/modules/tool-auth/external-api-key.interface.d.ts +72 -8
- 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 +17 -6
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +83 -27
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +15 -2
- package/dist/modules/tool-auth/internal-token.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.js +6 -2
- package/dist/modules/tool-auth/internal-token.service.js.map +1 -1
- package/dist/modules/tool-auth/key-or-session.middleware.d.ts +23 -0
- package/dist/modules/tool-auth/key-or-session.middleware.d.ts.map +1 -0
- package/dist/modules/tool-auth/key-or-session.middleware.js +39 -0
- package/dist/modules/tool-auth/key-or-session.middleware.js.map +1 -0
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +15 -1
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +17 -6
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts +14 -0
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +28 -6
- package/dist/modules/tool-helpers/tool-context.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +22 -5
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +6 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.js +7 -1
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
- package/dist/modules/tool-manuals/index.d.ts +2 -1
- package/dist/modules/tool-manuals/index.d.ts.map +1 -1
- package/dist/modules/tool-manuals/index.js +1 -0
- package/dist/modules/tool-manuals/index.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-json-discovery.js +8 -6
- package/dist/modules/tool-manuals/mcp-json-discovery.js.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts +10 -2
- package/dist/modules/tool-manuals/mcp-server-edit.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/mcp-server-edit.service.js +12 -15
- package/dist/modules/tool-manuals/mcp-server-edit.service.js.map +1 -1
- package/dist/modules/tool-manuals/pending-tools.service.d.ts +50 -0
- package/dist/modules/tool-manuals/pending-tools.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/pending-tools.service.js +149 -0
- package/dist/modules/tool-manuals/pending-tools.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-delete.service.d.ts +135 -0
- package/dist/modules/tool-manuals/tool-delete.service.d.ts.map +1 -0
- package/dist/modules/tool-manuals/tool-delete.service.js +303 -0
- package/dist/modules/tool-manuals/tool-delete.service.js.map +1 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts +161 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.contract.js +9 -0
- package/dist/modules/tool-manuals/tool-manuals.contract.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts +19 -2
- package/dist/modules/tool-manuals/tool-manuals.routes.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.routes.js +127 -57
- package/dist/modules/tool-manuals/tool-manuals.routes.js.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts +119 -5
- package/dist/modules/tool-manuals/tool-manuals.service.d.ts.map +1 -1
- package/dist/modules/tool-manuals/tool-manuals.service.js +404 -74
- 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 +78 -6
- package/dist/modules/tool-manuals/tool-manuals.tools.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 +88 -54
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/event-bus.d.ts +10 -4
- package/dist/modules/workflow/event-bus.d.ts.map +1 -1
- package/dist/modules/workflow/event-bus.js +14 -11
- package/dist/modules/workflow/event-bus.js.map +1 -1
- package/dist/modules/workflow/events.routes.d.ts +17 -2
- package/dist/modules/workflow/events.routes.d.ts.map +1 -1
- package/dist/modules/workflow/events.routes.js +31 -12
- package/dist/modules/workflow/events.routes.js.map +1 -1
- package/dist/modules/workflow/file-lock.service.d.ts +22 -4
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
- package/dist/modules/workflow/file-lock.service.js +27 -4
- package/dist/modules/workflow/file-lock.service.js.map +1 -1
- package/dist/modules/workflow/git/change-request-link.d.ts +20 -0
- package/dist/modules/workflow/git/change-request-link.d.ts.map +1 -0
- package/dist/modules/workflow/git/change-request-link.js +34 -0
- package/dist/modules/workflow/git/change-request-link.js.map +1 -0
- package/dist/modules/workflow/git/git-version.d.ts.map +1 -1
- package/dist/modules/workflow/git/git-version.js +3 -1
- package/dist/modules/workflow/git/git-version.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +263 -4
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +528 -118
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.d.ts +36 -0
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -0
- package/dist/modules/workflow/git/node-git-runner.js +273 -0
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts +51 -2
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +157 -25
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts +11 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +24 -4
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.d.ts +15 -8
- package/dist/modules/workflow/pending-commits.worker.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.worker.js +107 -58
- package/dist/modules/workflow/pending-commits.worker.js.map +1 -1
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
- package/dist/modules/workflow/recovery-bot.js +3 -1
- package/dist/modules/workflow/recovery-bot.js.map +1 -1
- package/dist/modules/workflow/review-workflow/approval-lock.d.ts +60 -0
- package/dist/modules/workflow/review-workflow/approval-lock.d.ts.map +1 -0
- package/dist/modules/workflow/review-workflow/approval-lock.js +116 -0
- package/dist/modules/workflow/review-workflow/approval-lock.js.map +1 -0
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts +54 -7
- package/dist/modules/workflow/review-workflow/review-workflow.interface.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts +64 -0
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +269 -90
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/sanitize-error.d.ts +5 -2
- package/dist/modules/workflow/sanitize-error.d.ts.map +1 -1
- package/dist/modules/workflow/sanitize-error.js +8 -4
- package/dist/modules/workflow/sanitize-error.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts +2 -0
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +259 -29
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +166 -14
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +906 -106
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/empty-dirs.d.ts +15 -0
- package/dist/modules/workspace/empty-dirs.d.ts.map +1 -0
- package/dist/modules/workspace/empty-dirs.js +90 -0
- package/dist/modules/workspace/empty-dirs.js.map +1 -0
- package/dist/modules/workspace/file-readers/content-mode.d.ts +50 -0
- package/dist/modules/workspace/file-readers/content-mode.d.ts.map +1 -0
- package/dist/modules/workspace/file-readers/content-mode.js +55 -0
- package/dist/modules/workspace/file-readers/content-mode.js.map +1 -0
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts +4 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js +4 -1
- package/dist/modules/workspace/file-readers/doc-extract.service.js.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.types.d.ts +5 -2
- package/dist/modules/workspace/file-readers/doc-extract.types.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/doc-extract.types.js +7 -4
- package/dist/modules/workspace/file-readers/doc-extract.types.js.map +1 -1
- package/dist/modules/workspace/file-readers/document-reader.d.ts +2 -0
- package/dist/modules/workspace/file-readers/document-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/document-reader.js +5 -0
- package/dist/modules/workspace/file-readers/document-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/extract-docx.d.ts +6 -0
- package/dist/modules/workspace/file-readers/extract-docx.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/extract-docx.js +6 -0
- package/dist/modules/workspace/file-readers/extract-docx.js.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.d.ts +24 -5
- package/dist/modules/workspace/file-readers/file-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.js +11 -6
- package/dist/modules/workspace/file-readers/file-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.js +6 -1
- package/dist/modules/workspace/file-readers/file-reader.registry.js.map +1 -1
- package/dist/modules/workspace/file-readers/image-reader.d.ts +7 -5
- package/dist/modules/workspace/file-readers/image-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/image-reader.js +9 -5
- package/dist/modules/workspace/file-readers/image-reader.js.map +1 -1
- package/dist/modules/workspace/file-readers/ooxml-text.d.ts +3 -0
- package/dist/modules/workspace/file-readers/ooxml-text.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/ooxml-text.js +39 -2
- package/dist/modules/workspace/file-readers/ooxml-text.js.map +1 -1
- package/dist/modules/workspace/file-readers/text-reader.d.ts +29 -1
- package/dist/modules/workspace/file-readers/text-reader.d.ts.map +1 -1
- package/dist/modules/workspace/file-readers/text-reader.js +57 -3
- package/dist/modules/workspace/file-readers/text-reader.js.map +1 -1
- package/dist/modules/workspace/git-internals.middleware.d.ts +28 -0
- package/dist/modules/workspace/git-internals.middleware.d.ts.map +1 -0
- package/dist/modules/workspace/git-internals.middleware.js +93 -0
- package/dist/modules/workspace/git-internals.middleware.js.map +1 -0
- package/dist/modules/workspace/not-found.d.ts +80 -0
- package/dist/modules/workspace/not-found.d.ts.map +1 -0
- package/dist/modules/workspace/not-found.js +112 -0
- package/dist/modules/workspace/not-found.js.map +1 -0
- package/dist/modules/workspace/session-ontology.gate.d.ts +1 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +1 -1
- package/dist/modules/workspace/session-ontology.gate.js +1 -1
- package/dist/modules/workspace/session-ontology.gate.js.map +1 -1
- package/dist/modules/workspace/startup/beside-checkout.d.ts +42 -0
- package/dist/modules/workspace/startup/beside-checkout.d.ts.map +1 -0
- package/dist/modules/workspace/startup/beside-checkout.js +110 -0
- package/dist/modules/workspace/startup/beside-checkout.js.map +1 -0
- package/dist/modules/workspace/startup/kb-git.d.ts +7 -12
- package/dist/modules/workspace/startup/kb-git.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-git.js +34 -35
- package/dist/modules/workspace/startup/kb-git.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +95 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +257 -55
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts +45 -0
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js +417 -385
- package/dist/modules/workspace/startup/steps/groups-to-plugins.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts +48 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js +183 -0
- package/dist/modules/workspace/startup/steps/personal-spaces.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts +51 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js +158 -0
- package/dist/modules/workspace/startup/steps/plugin-display-names.step.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.d.ts +64 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.js +97 -0
- package/dist/modules/workspace/startup/steps/plugin-layout.js.map +1 -0
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts +7 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js +45 -81
- package/dist/modules/workspace/startup/steps/plugin-manifests.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts +3 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js +4 -12
- package/dist/modules/workspace/startup/steps/roles-yaml.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts +6 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +154 -78
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts +96 -24
- package/dist/modules/workspace/startup/steps/template-files.step.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-files.step.js +446 -138
- package/dist/modules/workspace/startup/steps/template-files.step.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +94 -0
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -0
- package/dist/modules/workspace/startup/steps/template-source.js +160 -0
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts +14 -2
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +649 -238
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +298 -12
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +933 -269
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +42 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +1626 -146
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +76 -0
- package/dist/modules/workspace/write-denial.d.ts.map +1 -0
- package/dist/modules/workspace/write-denial.js +138 -0
- package/dist/modules/workspace/write-denial.js.map +1 -0
- package/dist/shared/canonical-file-identity.d.ts +64 -0
- package/dist/shared/canonical-file-identity.d.ts.map +1 -0
- package/dist/shared/canonical-file-identity.js +92 -0
- package/dist/shared/canonical-file-identity.js.map +1 -0
- package/dist/shared/domain-errors.d.ts +108 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +137 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/email-identity.d.ts +32 -0
- package/dist/shared/email-identity.d.ts.map +1 -0
- package/dist/shared/email-identity.js +37 -0
- package/dist/shared/email-identity.js.map +1 -0
- package/dist/shared/fs.contract.d.ts +206 -0
- package/dist/shared/fs.contract.d.ts.map +1 -0
- package/dist/shared/fs.contract.js +79 -0
- package/dist/shared/fs.contract.js.map +1 -0
- package/dist/shared/git-failure.d.ts +80 -0
- package/dist/shared/git-failure.d.ts.map +1 -0
- package/dist/shared/git-failure.js +139 -0
- package/dist/shared/git-failure.js.map +1 -0
- package/dist/shared/git-internals.d.ts +23 -0
- package/dist/shared/git-internals.d.ts.map +1 -0
- package/dist/shared/git-internals.js +181 -0
- package/dist/shared/git-internals.js.map +1 -0
- package/dist/shared/git.contract.d.ts +157 -0
- package/dist/shared/git.contract.d.ts.map +1 -0
- package/dist/shared/git.contract.js +103 -0
- package/dist/shared/git.contract.js.map +1 -0
- package/dist/shared/http-errors.d.ts +33 -0
- package/dist/shared/http-errors.d.ts.map +1 -0
- package/dist/shared/http-errors.js +35 -0
- package/dist/shared/http-errors.js.map +1 -0
- package/dist/shared/logger.contract.d.ts +63 -0
- package/dist/shared/logger.contract.d.ts.map +1 -0
- package/dist/shared/logger.contract.js +126 -0
- package/dist/shared/logger.contract.js.map +1 -0
- package/dist/shared/logging.d.ts +31 -0
- package/dist/shared/logging.d.ts.map +1 -0
- package/dist/shared/logging.js +92 -0
- package/dist/shared/logging.js.map +1 -0
- package/dist/shared/path-containment.d.ts +21 -0
- package/dist/shared/path-containment.d.ts.map +1 -0
- package/dist/shared/path-containment.js +34 -0
- package/dist/shared/path-containment.js.map +1 -0
- package/dist/shared/pending-proposals.d.ts +71 -0
- package/dist/shared/pending-proposals.d.ts.map +1 -0
- package/dist/shared/pending-proposals.js +98 -0
- package/dist/shared/pending-proposals.js.map +1 -0
- package/dist/shared/printable.d.ts +22 -0
- package/dist/shared/printable.d.ts.map +1 -0
- package/dist/shared/printable.js +65 -0
- package/dist/shared/printable.js.map +1 -0
- package/dist/shared/redact-secret.d.ts +30 -0
- package/dist/shared/redact-secret.d.ts.map +1 -0
- package/dist/shared/redact-secret.js +114 -0
- package/dist/shared/redact-secret.js.map +1 -0
- package/dist/shared/rename-no-replace.d.ts +119 -0
- package/dist/shared/rename-no-replace.d.ts.map +1 -0
- package/dist/shared/rename-no-replace.js +323 -0
- package/dist/shared/rename-no-replace.js.map +1 -0
- package/dist/shared/ssrf.d.ts.map +1 -1
- package/dist/shared/ssrf.js +49 -18
- package/dist/shared/ssrf.js.map +1 -1
- package/dist/version.d.ts +10 -6
- package/dist/version.d.ts.map +1 -1
- package/dist/version.js +10 -6
- package/dist/version.js.map +1 -1
- package/kb-template/.bevelignore +4 -3
- package/kb-template/AGENTS.md +281 -36
- package/kb-template/KnowledgeBase/How to get started.md +1 -1
- package/kb-template/access.md +5 -3
- package/kb-template/mcp-description.md +27 -0
- package/migrations/0006_api_tokens_revoked_by.sql +1 -0
- package/migrations/0007_github_facade_registered.sql +1 -0
- package/migrations/0008_change_request_apply_failure.sql +4 -0
- package/migrations/0009_change_request_apply_failure_kind.sql +13 -0
- package/migrations/0010_plugin_join_requests.sql +15 -0
- package/migrations/0011_plugin_join_request_claim.sql +11 -0
- package/migrations/0012_agent_audit.sql +41 -0
- package/migrations/0013_agent_identity_and_key_soft_delete.sql +29 -0
- package/migrations/meta/0006_snapshot.json +1723 -0
- package/migrations/meta/0007_snapshot.json +1729 -0
- package/migrations/meta/0008_snapshot.json +1753 -0
- package/migrations/meta/0009_snapshot.json +1759 -0
- package/migrations/meta/0010_snapshot.json +1872 -0
- package/migrations/meta/0011_snapshot.json +1884 -0
- package/migrations/meta/0012_snapshot.json +2247 -0
- package/migrations/meta/0013_snapshot.json +2259 -0
- package/migrations/meta/_journal.json +56 -0
- package/package.json +7 -6
- package/src/__tests__/core-config.domain.test.ts +67 -2
- package/src/__tests__/kb-layout-config.test.ts +186 -1
- package/src/__tests__/open-change-gate.ts +15 -0
- package/src/core/__tests__/catalog-cache-invalidation.test.ts +83 -3
- package/src/core/__tests__/catalog-revision.test.ts +190 -0
- package/src/core/__tests__/lifecycle.test.ts +369 -0
- package/src/core/__tests__/public-config.test.ts +30 -0
- package/src/core/__tests__/readiness.test.ts +109 -0
- package/src/core/catalog-cache-invalidation.ts +20 -1
- package/src/core/catalog-revision.ts +110 -0
- package/src/core/create-core-server.ts +286 -79
- package/src/core/create-core-services.ts +315 -81
- package/src/core/lifecycle.ts +312 -0
- package/src/core/public-config.ts +86 -0
- package/src/core/readiness.ts +123 -0
- package/src/core-config.ts +70 -4
- package/src/index.ts +15 -0
- package/src/modules/access/__tests__/access-control.admin-root-floor.test.ts +362 -0
- package/src/modules/access/__tests__/access-control.atref-batch.test.ts +2 -1
- package/src/modules/access/__tests__/access-control.atref-cache.test.ts +46 -22
- package/src/modules/access/__tests__/access-control.deny-dependents.test.ts +215 -0
- package/src/modules/access/__tests__/access-control.download-read.test.ts +268 -0
- package/src/modules/access/__tests__/access-control.everyone-read.test.ts +145 -0
- package/src/modules/access/__tests__/access-control.group-read.test.ts +163 -0
- package/src/modules/access/__tests__/access-control.invalidate-race.test.ts +2 -0
- package/src/modules/access/__tests__/access-control.platform-restore.test.ts +152 -0
- package/src/modules/access/__tests__/access-control.prospective.test.ts +189 -0
- package/src/modules/access/__tests__/access-control.read-batch.test.ts +2 -1
- package/src/modules/access/__tests__/access-control.service.test.ts +123 -78
- package/src/modules/access/__tests__/access-groups.test.ts +47 -14
- package/src/modules/access/__tests__/access-md-format.test.ts +2 -1
- package/src/modules/access/__tests__/access-mutation.service.test.ts +52 -4
- package/src/modules/access/__tests__/access-own-read-grant.test.ts +2 -0
- package/src/modules/access/__tests__/access-personal-plugin.test.ts +153 -0
- package/src/modules/access/__tests__/access-plugin-principals.test.ts +18 -1
- package/src/modules/access/__tests__/access-restrict-here.test.ts +450 -0
- package/src/modules/access/__tests__/access.routes.batch.test.ts +139 -0
- package/src/modules/access/__tests__/access.routes.folder-governs.test.ts +394 -0
- package/src/modules/access/__tests__/access.routes.group-grant.test.ts +6 -2
- package/src/modules/access/__tests__/access.routes.overrides.test.ts +3 -2
- package/src/modules/access/__tests__/access.routes.proposal-branch.test.ts +234 -0
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +216 -0
- package/src/modules/access/__tests__/access.routes.revoke.test.ts +7 -2
- package/src/modules/access/__tests__/access.routes.unknown-email.test.ts +360 -0
- package/src/modules/access/__tests__/change-read-gate.test.ts +272 -0
- package/src/modules/access/__tests__/creator-access.test.ts +81 -83
- package/src/modules/access/__tests__/grant-sources.test.ts +3 -2
- package/src/modules/access/__tests__/groups-admin.service.test.ts +6 -5
- package/src/modules/access/__tests__/roles-admin.security.test.ts +196 -0
- package/src/modules/access/__tests__/roles-admin.service.test.ts +127 -2
- package/src/modules/access/__tests__/roles-capabilities.test.ts +5 -4
- package/src/modules/access/__tests__/roles.routes.test.ts +5 -2
- package/src/modules/access/__tests__/user-access-removal.service.test.ts +402 -0
- package/src/modules/access/__tests__/users-db-double.ts +63 -0
- package/src/modules/access/access-control.interface.ts +251 -11
- package/src/modules/access/access-control.service.ts +719 -164
- package/src/modules/access/access-mutation.service.ts +182 -13
- package/src/modules/access/access-view.ts +316 -0
- package/src/modules/access/access.routes.ts +293 -95
- package/src/modules/access/admin-locked-commit.ts +12 -14
- package/src/modules/access/admin-route-helpers.ts +4 -4
- package/src/modules/access/change-read-gate.ts +148 -0
- package/src/modules/access/creator-access.ts +89 -124
- package/src/modules/access/directory-sync-bot.ts +4 -1
- package/src/modules/access/groups-admin.service.ts +3 -3
- package/src/modules/access/reference-scan.ts +5 -5
- package/src/modules/access/roles-admin.service.ts +94 -15
- package/src/modules/access/synced-groups-committer.ts +10 -15
- package/src/modules/access/synced-groups-writer.ts +3 -12
- package/src/modules/access/user-access-removal.service.ts +711 -0
- package/src/modules/access-model/__tests__/access-splice.test.ts +63 -1
- package/src/modules/access-model/__tests__/frontmatter-fences.test.ts +71 -0
- package/src/modules/access-model/__tests__/roles-yaml-guard.test.ts +131 -0
- package/src/modules/access-model/access-errors.ts +56 -15
- package/src/modules/access-model/access-grammar.ts +85 -48
- package/src/modules/access-model/access-splice.ts +18 -18
- package/src/modules/access-model/access-template.ts +44 -0
- package/src/modules/access-model/change-gate.ts +80 -0
- package/src/modules/access-model/creator.ts +18 -21
- package/src/modules/access-model/frontmatter-lines.ts +98 -0
- package/src/modules/access-model/plugin-principals.ts +12 -19
- package/src/modules/access-model/roles-yaml-guard.ts +182 -4
- package/src/modules/admin/admin-access.service.ts +6 -2
- package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +100 -0
- package/src/modules/agent-instructions/__tests__/compose.test.ts +256 -0
- package/src/modules/agent-instructions/__tests__/read-preamble.test.ts +135 -0
- package/src/modules/agent-instructions/agent-instructions.routes.ts +41 -0
- package/src/modules/agent-instructions/compose.ts +271 -0
- package/src/modules/agent-instructions/index.ts +14 -0
- package/src/modules/agent-instructions/read-preamble.ts +88 -0
- package/src/modules/audit/__tests__/agent-audit.service.test.ts +370 -0
- package/src/modules/audit/__tests__/agent-rest-audit.middleware.test.ts +113 -0
- package/src/modules/audit/__tests__/audit.routes.test.ts +201 -0
- package/src/modules/audit/__tests__/event-classifier.test.ts +121 -0
- package/src/modules/audit/agent-audit.service.ts +316 -0
- package/src/modules/audit/agent-rest-audit.middleware.ts +83 -0
- package/src/modules/audit/audit.contract.ts +164 -0
- package/src/modules/audit/audit.routes.ts +168 -0
- package/src/modules/audit/event-classifier.ts +155 -0
- package/src/modules/audit/index.ts +14 -0
- package/src/modules/audit/request-audit.ts +141 -0
- package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +209 -0
- package/src/modules/auth/__tests__/account.routes.test.ts +178 -2
- package/src/modules/auth/__tests__/auth.middleware.test.ts +78 -0
- package/src/modules/auth/__tests__/auth.service.test.ts +338 -5
- package/src/modules/auth/__tests__/oidc-auth-provider.test.ts +352 -12
- package/src/modules/auth/__tests__/onboarding-done.route.test.ts +3 -1
- package/src/modules/auth/account-erasure.service.ts +117 -10
- package/src/modules/auth/account.routes.ts +115 -14
- package/src/modules/auth/auth.routes.ts +20 -7
- package/src/modules/auth/auth.service.ts +187 -28
- package/src/modules/auth/oidc-auth-provider.ts +120 -22
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +109 -1
- package/src/modules/code-mode/code-mode.tool.ts +13 -2
- package/src/modules/connection-probe/__tests__/connection-probe.service.test.ts +78 -0
- package/src/modules/connection-probe/connection-probe.service.ts +59 -7
- package/src/modules/database/__tests__/advisory-lease.test.ts +152 -0
- package/src/modules/database/__tests__/advisory-lock.test.ts +147 -0
- package/src/modules/database/advisory-lock.ts +346 -0
- package/src/modules/database/connection.ts +9 -1
- package/src/modules/database/core-schema.ts +227 -0
- package/src/modules/database/migrate.ts +27 -6
- package/src/modules/declared-variables/declared-variables.routes.ts +6 -3
- package/src/modules/diff/__tests__/diff.service.seed-atomicity.test.ts +3 -0
- package/src/modules/diff/__tests__/diff.service.test.ts +3 -0
- package/src/modules/diff/diff.routes.ts +2 -4
- package/src/modules/diff/diff.service.ts +80 -79
- package/src/modules/kb-fs/__tests__/locking-filesystem.test.ts +472 -9
- package/src/modules/kb-fs/__tests__/node-fs.test.ts +409 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +210 -1
- package/src/modules/{workspace → kb-fs}/bevel-ignore.ts +22 -15
- package/src/modules/kb-fs/file-change-notifier.ts +4 -1
- package/src/modules/kb-fs/git-guarded-filesystem.ts +136 -0
- package/src/modules/kb-fs/locking-filesystem.ts +399 -109
- package/src/modules/kb-fs/node-fs.ts +165 -0
- package/src/modules/kb-fs/read-only-filesystem.ts +18 -9
- package/src/modules/kb-fs/repo-path.ts +213 -3
- package/src/modules/kb-sync/kb-sync.routes.ts +5 -2
- package/src/modules/kb-sync/kb-sync.service.ts +8 -5
- package/src/modules/marketplace/__tests__/github-facade.test.ts +134 -2
- package/src/modules/marketplace/__tests__/marketplace-git.test.ts +2 -1
- package/src/modules/marketplace/__tests__/marketplace-repo.head.test.ts +47 -0
- package/src/modules/marketplace/git-http.routes.ts +7 -4
- package/src/modules/marketplace/github-facade/github-facade-admin.routes.ts +35 -3
- package/src/modules/marketplace/github-facade/github-facade-credentials.service.ts +55 -0
- package/src/modules/marketplace/github-facade/github-facade.routes.ts +32 -6
- package/src/modules/marketplace/github-facade/github-facade.service.ts +80 -19
- package/src/modules/marketplace/github-facade/index.ts +1 -0
- package/src/modules/marketplace/marketplace-repo.service.ts +23 -8
- package/src/modules/mcp/__tests__/bevel-oauth-provider.test.ts +183 -13
- package/src/modules/mcp/__tests__/downstream-pool.test.ts +278 -0
- package/src/modules/mcp/__tests__/downstream-token-refresh.test.ts +178 -0
- package/src/modules/mcp/__tests__/fake-downstream-mcp-server.ts +156 -0
- package/src/modules/mcp/__tests__/first-call-probe.cli-args.test.ts +178 -0
- package/src/modules/mcp/__tests__/first-call-probe.test.ts +414 -0
- package/src/modules/mcp/__tests__/manual-failure-memo.test.ts +98 -6
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +68 -7
- package/src/modules/mcp/__tests__/mcp-routes-harness.ts +1 -3
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +1055 -59
- package/src/modules/mcp/__tests__/mcp.routes.local-token.test.ts +24 -4
- package/src/modules/mcp/__tests__/mcp.routes.stateless.test.ts +182 -0
- package/src/modules/mcp/__tests__/mcp.service.test.ts +391 -6
- package/src/modules/mcp/__tests__/surface-log-throttle.test.ts +169 -0
- package/src/modules/mcp/downstream-pool.ts +256 -0
- package/src/modules/mcp/downstream-token-refresh.ts +170 -0
- package/src/modules/mcp/first-call-probe.cli-args.ts +159 -0
- package/src/modules/mcp/first-call-probe.cli.ts +60 -0
- package/src/modules/mcp/first-call-probe.ts +418 -0
- package/src/modules/mcp/manual-failure-memo.ts +81 -23
- package/src/modules/mcp/mcp-auth.middleware.ts +56 -16
- package/src/modules/mcp/mcp.routes.ts +386 -482
- package/src/modules/mcp/mcp.service.ts +905 -177
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +189 -8
- package/src/modules/mcp/oauth/oauth-consent.routes.ts +4 -4
- package/src/modules/mcp/surface-log-throttle.ts +120 -0
- package/src/modules/plugins/__tests__/bundle-dialect.e2e.test.ts +10 -7
- package/src/modules/plugins/__tests__/bundle-dialect.test.ts +165 -0
- package/src/modules/plugins/__tests__/compile-marketplace.test.ts +139 -10
- package/src/modules/plugins/__tests__/fake-join-request-store.ts +189 -0
- package/src/modules/plugins/__tests__/join-request-jobs.service.test.ts +608 -0
- package/src/modules/plugins/__tests__/plugin-creation-display-name.test.ts +241 -0
- package/src/modules/plugins/__tests__/plugin-index.service.test.ts +148 -7
- package/src/modules/plugins/__tests__/plugin-links.service.test.ts +10 -13
- package/src/modules/plugins/__tests__/plugin-names.test.ts +77 -0
- package/src/modules/plugins/__tests__/plugin-provision.service.test.ts +129 -19
- package/src/modules/plugins/__tests__/plugin-rename.service.test.ts +91 -29
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +370 -19
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +131 -0
- package/src/modules/plugins/__tests__/teams.routes.test.ts +248 -0
- package/src/modules/plugins/compile/compile-marketplace.ts +143 -46
- package/src/modules/plugins/compile/marketplace-compiler.service.ts +8 -7
- package/src/modules/plugins/discovery/__tests__/kb-plugin-source.test.ts +56 -20
- package/src/modules/plugins/discovery/bundle-dialect/bundle.source.ts +30 -9
- package/src/modules/plugins/discovery/bundle-dialect/registry.ts +93 -18
- package/src/modules/plugins/discovery/kb-plugin-source.ts +10 -7
- package/src/modules/plugins/discovery/native.source.ts +21 -3
- package/src/modules/plugins/discovery/plugin-source.ts +17 -3
- package/src/modules/plugins/index.ts +16 -3
- package/src/modules/plugins/join-request-jobs.service.ts +675 -0
- package/src/modules/plugins/join-request-records.store.ts +353 -0
- package/src/modules/plugins/join-requests.service.ts +7 -4
- package/src/modules/plugins/plugin-links.service.ts +4 -17
- package/src/modules/plugins/plugin-links.ts +6 -3
- package/src/modules/plugins/plugin-provision.service.ts +209 -37
- package/src/modules/plugins/plugin-rename.service.ts +21 -9
- package/src/modules/plugins/plugins.contract.ts +52 -4
- package/src/modules/plugins/plugins.routes.ts +204 -124
- package/src/modules/plugins/plugins.service.ts +92 -18
- package/src/modules/plugins/plugins.tools.ts +88 -0
- package/src/modules/plugins/teams.routes.ts +129 -0
- package/src/modules/secrets-vault/__tests__/connect-pending.route.test.ts +359 -15
- package/src/modules/secrets-vault/__tests__/db-secrets-vault.oauth.test.ts +248 -0
- package/src/modules/secrets-vault/__tests__/namespace-secrets.test.ts +202 -0
- package/src/modules/secrets-vault/db-secrets-vault.service.ts +217 -35
- package/src/modules/secrets-vault/index.ts +1 -0
- package/src/modules/secrets-vault/mcp-oauth-discovery.service.ts +6 -3
- package/src/modules/secrets-vault/secrets-variable-loader.ts +4 -4
- package/src/modules/secrets-vault/secrets-vault.contract.ts +93 -0
- package/src/modules/secrets-vault/secrets-vault.routes.ts +99 -38
- package/src/modules/settings/__tests__/connection-check.test.ts +233 -0
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +223 -6
- package/src/modules/settings/__tests__/git-root-folders.test.ts +247 -0
- package/src/modules/settings/__tests__/oidc-check.test.ts +185 -0
- package/src/modules/settings/__tests__/setup.routes.boot-failure.test.ts +119 -0
- package/src/modules/settings/__tests__/setup.routes.layout-phase.test.ts +170 -0
- package/src/modules/settings/__tests__/setup.routes.oidc.test.ts +555 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +667 -16
- package/src/modules/settings/connection-check.ts +351 -0
- package/src/modules/settings/deployment-settings.service.ts +444 -59
- package/src/modules/settings/git-root-folders.ts +171 -0
- package/src/modules/settings/oidc-check.ts +229 -0
- package/src/modules/settings/setup.routes.ts +456 -110
- package/src/modules/skills/__tests__/allowed-tools-check.test.ts +224 -0
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +210 -0
- package/src/modules/skills/__tests__/pending-skills.service.test.ts +3 -3
- package/src/modules/skills/__tests__/skills.routes.warnings.test.ts +91 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +223 -2
- package/src/modules/skills/allowed-tools-check.ts +352 -0
- package/src/modules/skills/index.ts +4 -0
- package/src/modules/skills/pending-skills.service.ts +21 -82
- package/src/modules/skills/skill-access-requests.routes.ts +10 -6
- package/src/modules/skills/skills.contract.ts +43 -11
- package/src/modules/skills/skills.routes.ts +16 -1
- package/src/modules/skills/skills.service.ts +214 -84
- package/src/modules/skills/skills.tools.ts +43 -5
- package/src/modules/tool-auth/__tests__/connection-key-rejection.test.ts +192 -0
- package/src/modules/tool-auth/__tests__/connection-keys-admin.routes.test.ts +116 -0
- package/src/modules/tool-auth/__tests__/external-api-key.service.test.ts +153 -8
- package/src/modules/tool-auth/__tests__/internal-token.service.test.ts +6 -0
- package/src/modules/tool-auth/connection-key-rejection.ts +25 -0
- package/src/modules/tool-auth/connection-keys-admin.routes.ts +76 -0
- package/src/modules/tool-auth/external-api-key.interface.ts +78 -8
- package/src/modules/tool-auth/external-api-key.service.ts +98 -33
- package/src/modules/tool-auth/internal-token.service.ts +16 -2
- package/src/modules/tool-auth/key-or-session.middleware.ts +45 -0
- package/src/modules/tool-auth/tool-auth.middleware.ts +33 -8
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +228 -0
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +33 -4
- package/src/modules/tool-helpers/tool-context.ts +46 -7
- package/src/modules/tool-helpers/tool-handler.ts +23 -5
- package/src/modules/tool-helpers/tool.contract.ts +5 -0
- package/src/modules/tool-manuals/__tests__/mcp-server-edit.service.test.ts +2 -1
- package/src/modules/tool-manuals/__tests__/pending-tools.service.test.ts +411 -0
- package/src/modules/tool-manuals/__tests__/tool-delete.route.test.ts +133 -0
- package/src/modules/tool-manuals/__tests__/tool-delete.service.test.ts +469 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.archive.route.test.ts +21 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.cli.test.ts +9 -4
- package/src/modules/tool-manuals/__tests__/tool-manuals.detail.route.test.ts +6 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.routes.test.ts +254 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.invalid.test.ts +577 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.mcp-oauth.test.ts +6 -1
- package/src/modules/tool-manuals/__tests__/tool-manuals.pending.route.test.ts +102 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.restart.test.ts +285 -0
- package/src/modules/tool-manuals/__tests__/tool-manuals.service.test.ts +178 -2
- package/src/modules/tool-manuals/__tests__/tool-manuals.tools.test.ts +114 -2
- package/src/modules/tool-manuals/index.ts +3 -0
- package/src/modules/tool-manuals/mcp-json-discovery.ts +13 -10
- package/src/modules/tool-manuals/mcp-server-edit.service.ts +11 -14
- package/src/modules/tool-manuals/pending-tools.service.ts +179 -0
- package/src/modules/tool-manuals/tool-delete.service.ts +401 -0
- package/src/modules/tool-manuals/tool-manuals.contract.ts +165 -0
- package/src/modules/tool-manuals/tool-manuals.routes.ts +138 -54
- package/src/modules/tool-manuals/tool-manuals.service.ts +432 -87
- package/src/modules/tool-manuals/tool-manuals.tools.ts +81 -6
- package/src/modules/workflow/__tests__/apply-failure.test.ts +1038 -0
- package/src/modules/workflow/__tests__/event-bus.test.ts +61 -9
- package/src/modules/workflow/__tests__/fake-file-lock-db.ts +199 -0
- package/src/modules/workflow/__tests__/file-lock.service.path-identity.test.ts +237 -0
- package/src/modules/workflow/__tests__/format-affected-owners.test.ts +18 -0
- package/src/modules/workflow/__tests__/merge-announces-tree.test.ts +220 -0
- package/src/modules/workflow/__tests__/pending-commits.worker.concurrency.test.ts +187 -0
- package/src/modules/workflow/__tests__/preserve-roles-yaml.test.ts +2 -0
- package/src/modules/workflow/__tests__/sanitize-error.test.ts +10 -0
- package/src/modules/workflow/__tests__/workflow.routes.folder-proposals.test.ts +128 -0
- package/src/modules/workflow/__tests__/workflow.routes.fork-point-file.test.ts +149 -0
- package/src/modules/workflow/__tests__/workflow.routes.lock-path.test.ts +305 -0
- package/src/modules/workflow/__tests__/workflow.service.branch-in-use.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.commitFileWhileLocked.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.deleted-branch-sweep.test.ts +2 -0
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +294 -25
- package/src/modules/workflow/__tests__/workflow.service.folder-proposals.test.ts +564 -0
- package/src/modules/workflow/__tests__/workflow.service.platform-restore.test.ts +135 -0
- package/src/modules/workflow/__tests__/workflow.service.read-gate.test.ts +172 -0
- package/src/modules/workflow/__tests__/workflow.service.releaseLock.test.ts +14 -0
- package/src/modules/workflow/__tests__/workflow.service.sync.test.ts +5 -0
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +281 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +158 -7
- package/src/modules/workflow/agent-tools/workflow.tools.ts +93 -64
- package/src/modules/workflow/event-bus.ts +26 -28
- package/src/modules/workflow/events.routes.ts +56 -21
- package/src/modules/workflow/file-lock.service.ts +27 -4
- package/src/modules/workflow/git/__tests__/change-request-link.test.ts +43 -0
- package/src/modules/workflow/git/__tests__/git.service.accessGating.test.ts +1 -0
- package/src/modules/workflow/git/__tests__/git.service.changedFilesForPr.test.ts +238 -1
- package/src/modules/workflow/git/__tests__/git.service.forkPoint.test.ts +245 -0
- package/src/modules/workflow/git/__tests__/git.service.list-branches.test.ts +35 -0
- package/src/modules/workflow/git/__tests__/git.service.mergeChangeRequest.test.ts +149 -0
- package/src/modules/workflow/git/__tests__/git.service.revertPathsAndPush.test.ts +177 -0
- package/src/modules/workflow/git/__tests__/node-git-runner.test.ts +114 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +69 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.list-fetch.test.ts +121 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.placeholder.test.ts +79 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-cancel.test.ts +1 -1
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-update.test.ts +111 -0
- package/src/modules/workflow/git/change-request-link.ts +35 -0
- package/src/modules/workflow/git/git-version.ts +5 -2
- package/src/modules/workflow/git/git.service.ts +684 -144
- package/src/modules/workflow/git/node-git-runner.ts +315 -0
- package/src/modules/workflow/git/pull-request.service.ts +179 -27
- package/src/modules/workflow/pending-commits.service.ts +26 -7
- package/src/modules/workflow/pending-commits.worker.ts +114 -69
- package/src/modules/workflow/recovery-bot.ts +4 -1
- package/src/modules/workflow/review-workflow/__tests__/approval-states.test.ts +180 -1
- package/src/modules/workflow/review-workflow/__tests__/cancel-pr.test.ts +1 -1
- package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +520 -0
- package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +84 -0
- package/src/modules/workflow/review-workflow/__tests__/merge-gate.test.ts +89 -77
- package/src/modules/workflow/review-workflow/approval-lock.ts +122 -0
- package/src/modules/workflow/review-workflow/review-workflow.interface.ts +59 -7
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +309 -105
- package/src/modules/workflow/sanitize-error.ts +9 -4
- package/src/modules/workflow/workflow.routes.ts +273 -29
- package/src/modules/workflow/workflow.service.ts +1087 -171
- package/src/modules/workspace/__tests__/empty-dirs.test.ts +44 -0
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +301 -0
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +883 -0
- package/src/modules/workspace/__tests__/workspace-paths-inside-the-repo.test.ts +464 -0
- package/src/modules/workspace/__tests__/workspace.routes.branch-errors.test.ts +139 -0
- package/src/modules/workspace/__tests__/workspace.routes.create-grant.test.ts +189 -37
- package/src/modules/workspace/__tests__/workspace.routes.delete.test.ts +51 -11
- package/src/modules/workspace/__tests__/workspace.routes.download-implies-read.test.ts +161 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +109 -10
- package/src/modules/workspace/__tests__/workspace.routes.file-writes.test.ts +624 -0
- package/src/modules/workspace/__tests__/workspace.routes.folders.test.ts +409 -0
- package/src/modules/workspace/__tests__/workspace.routes.move-platform-files.test.ts +327 -0
- package/src/modules/workspace/__tests__/workspace.routes.read-gate.test.ts +25 -6
- package/src/modules/workspace/__tests__/workspace.service.ensure-remotes-fetched.test.ts +109 -0
- package/src/modules/workspace/__tests__/workspace.service.list-cloned.test.ts +6 -5
- package/src/modules/workspace/__tests__/workspace.service.move-never-overwrites.test.ts +218 -0
- package/src/modules/workspace/__tests__/workspace.service.read-filter.test.ts +56 -1
- package/src/modules/workspace/__tests__/workspace.service.test.ts +811 -42
- package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +197 -0
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +128 -0
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +212 -0
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +2632 -110
- package/src/modules/workspace/__tests__/write-denial.test.ts +75 -0
- package/src/modules/workspace/empty-dirs.ts +79 -0
- package/src/modules/workspace/file-readers/README.md +32 -0
- package/src/modules/workspace/file-readers/__tests__/doc-extract.test.ts +59 -2
- package/src/modules/workspace/file-readers/__tests__/file-reader.registry.test.ts +133 -4
- package/src/modules/workspace/file-readers/__tests__/fixtures/soft-break.docx +0 -0
- package/src/modules/workspace/file-readers/__tests__/fixtures/tab.docx +0 -0
- package/src/modules/workspace/file-readers/content-mode.ts +87 -0
- package/src/modules/workspace/file-readers/doc-extract.service.ts +4 -1
- package/src/modules/workspace/file-readers/doc-extract.types.ts +8 -4
- package/src/modules/workspace/file-readers/document-reader.ts +6 -0
- package/src/modules/workspace/file-readers/extract-docx.ts +6 -0
- package/src/modules/workspace/file-readers/file-reader.registry.ts +9 -1
- package/src/modules/workspace/file-readers/file-reader.ts +27 -6
- package/src/modules/workspace/file-readers/image-reader.ts +10 -5
- package/src/modules/workspace/file-readers/ooxml-text.ts +38 -2
- package/src/modules/workspace/file-readers/text-reader.ts +61 -4
- package/src/modules/workspace/git-internals.middleware.ts +86 -0
- package/src/modules/workspace/not-found.ts +119 -0
- package/src/modules/workspace/session-ontology.gate.ts +1 -1
- package/src/modules/workspace/startup/__tests__/beside-checkout.test.ts +181 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.degraded.test.ts +361 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +53 -16
- package/src/modules/workspace/startup/beside-checkout.ts +112 -0
- package/src/modules/workspace/startup/kb-git.ts +43 -36
- package/src/modules/workspace/startup/kb-startup-runner.ts +303 -63
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +1215 -73
- package/src/modules/workspace/startup/steps/groups-to-plugins.step.ts +460 -417
- package/src/modules/workspace/startup/steps/personal-spaces.step.ts +191 -0
- package/src/modules/workspace/startup/steps/plugin-display-names.step.ts +169 -0
- package/src/modules/workspace/startup/steps/plugin-layout.ts +110 -0
- package/src/modules/workspace/startup/steps/plugin-manifests.step.ts +46 -85
- package/src/modules/workspace/startup/steps/roles-yaml.step.ts +6 -12
- package/src/modules/workspace/startup/steps/seed-tree.ts +159 -78
- package/src/modules/workspace/startup/steps/template-files.step.ts +492 -141
- package/src/modules/workspace/startup/steps/template-source.ts +168 -0
- package/src/modules/workspace/workspace.routes.ts +687 -257
- package/src/modules/workspace/workspace.service.ts +1000 -303
- package/src/modules/workspace/workspace.tools.ts +1823 -180
- package/src/modules/workspace/write-denial.ts +189 -0
- package/src/shared/__tests__/canonical-file-identity.test.ts +154 -0
- package/src/shared/__tests__/email-identity.test.ts +35 -0
- package/src/shared/__tests__/filename.test.ts +0 -0
- package/src/shared/__tests__/frontmatter-id.test.ts +5 -0
- package/src/shared/__tests__/git-failure.test.ts +198 -0
- package/src/shared/__tests__/git-internals.test.ts +156 -0
- package/src/shared/__tests__/http-errors.test.ts +42 -0
- package/src/shared/__tests__/logging.test.ts +185 -0
- package/src/shared/__tests__/path-containment.test.ts +60 -0
- package/src/shared/__tests__/pending-proposals.readAt.test.ts +102 -0
- package/src/shared/__tests__/printable.test.ts +64 -0
- package/src/shared/__tests__/redact-secret.test.ts +122 -0
- package/src/shared/__tests__/rename-no-replace.test.ts +466 -0
- package/src/shared/__tests__/ssrf.test.ts +20 -0
- package/src/shared/canonical-file-identity.ts +92 -0
- package/src/shared/domain-errors.ts +149 -0
- package/src/shared/email-identity.ts +38 -0
- package/src/shared/fs.contract.ts +225 -0
- package/src/shared/git-failure.ts +196 -0
- package/src/shared/git-internals.ts +179 -0
- package/src/shared/git.contract.ts +170 -0
- package/src/shared/http-errors.ts +36 -0
- package/src/shared/logger.contract.ts +141 -0
- package/src/shared/logging.ts +96 -0
- package/src/shared/path-containment.ts +34 -0
- package/src/shared/pending-proposals.ts +161 -0
- package/src/shared/printable.ts +68 -0
- package/src/shared/redact-secret.ts +118 -0
- package/src/shared/rename-no-replace.ts +386 -0
- package/src/shared/ssrf.ts +44 -16
- package/src/version.ts +10 -6
- package/dist/modules/access/access-errors.d.ts +0 -34
- package/dist/modules/access/access-errors.d.ts.map +0 -1
- package/dist/modules/access/access-errors.js +0 -40
- package/dist/modules/access/access-errors.js.map +0 -1
- package/dist/modules/access/access-splice.d.ts +0 -140
- package/dist/modules/access/access-splice.d.ts.map +0 -1
- package/dist/modules/access/access-splice.js +0 -389
- package/dist/modules/access/access-splice.js.map +0 -1
- package/dist/modules/access/group-files.d.ts +0 -83
- package/dist/modules/access/group-files.d.ts.map +0 -1
- package/dist/modules/access/group-files.js +0 -167
- package/dist/modules/access/group-files.js.map +0 -1
- package/dist/modules/access/kb-read-filter.d.ts +0 -41
- package/dist/modules/access/kb-read-filter.d.ts.map +0 -1
- package/dist/modules/access/kb-read-filter.js +0 -60
- package/dist/modules/access/kb-read-filter.js.map +0 -1
- package/dist/modules/access/render-roles-yaml.d.ts +0 -22
- package/dist/modules/access/render-roles-yaml.d.ts.map +0 -1
- package/dist/modules/access/render-roles-yaml.js +0 -56
- package/dist/modules/access/render-roles-yaml.js.map +0 -1
- package/dist/modules/access/roles-yaml-guard.d.ts +0 -56
- package/dist/modules/access/roles-yaml-guard.d.ts.map +0 -1
- package/dist/modules/access/roles-yaml-guard.js +0 -79
- package/dist/modules/access/roles-yaml-guard.js.map +0 -1
- package/dist/modules/diff/diff-paths.d.ts +0 -2
- package/dist/modules/diff/diff-paths.d.ts.map +0 -1
- package/dist/modules/diff/diff-paths.js +0 -9
- package/dist/modules/diff/diff-paths.js.map +0 -1
- package/dist/modules/groups/group-provision.service.d.ts +0 -130
- package/dist/modules/groups/group-provision.service.d.ts.map +0 -1
- package/dist/modules/groups/group-provision.service.js +0 -288
- package/dist/modules/groups/group-provision.service.js.map +0 -1
- package/dist/modules/groups/groups.contract.d.ts +0 -106
- package/dist/modules/groups/groups.contract.d.ts.map +0 -1
- package/dist/modules/groups/groups.contract.js +0 -36
- package/dist/modules/groups/groups.contract.js.map +0 -1
- package/dist/modules/groups/groups.routes.d.ts +0 -42
- package/dist/modules/groups/groups.routes.d.ts.map +0 -1
- package/dist/modules/groups/groups.routes.js +0 -379
- package/dist/modules/groups/groups.routes.js.map +0 -1
- package/dist/modules/groups/groups.service.d.ts +0 -60
- package/dist/modules/groups/groups.service.d.ts.map +0 -1
- package/dist/modules/groups/groups.service.js +0 -172
- package/dist/modules/groups/groups.service.js.map +0 -1
- package/dist/modules/groups/index.d.ts +0 -7
- package/dist/modules/groups/index.d.ts.map +0 -1
- package/dist/modules/groups/index.js +0 -6
- package/dist/modules/groups/index.js.map +0 -1
- package/dist/modules/groups/join-proposals.d.ts +0 -53
- package/dist/modules/groups/join-proposals.d.ts.map +0 -1
- package/dist/modules/groups/join-proposals.js +0 -67
- package/dist/modules/groups/join-proposals.js.map +0 -1
- package/dist/modules/groups/join-requests.service.d.ts +0 -81
- package/dist/modules/groups/join-requests.service.d.ts.map +0 -1
- package/dist/modules/groups/join-requests.service.js +0 -135
- package/dist/modules/groups/join-requests.service.js.map +0 -1
- package/dist/modules/mcp/mcp-session-store.d.ts +0 -74
- package/dist/modules/mcp/mcp-session-store.d.ts.map +0 -1
- package/dist/modules/mcp/mcp-session-store.js +0 -131
- package/dist/modules/mcp/mcp-session-store.js.map +0 -1
- package/dist/modules/workflow/file-change-notifier.d.ts +0 -38
- package/dist/modules/workflow/file-change-notifier.d.ts.map +0 -1
- package/dist/modules/workflow/file-change-notifier.js +0 -22
- package/dist/modules/workflow/file-change-notifier.js.map +0 -1
- package/dist/modules/workflow/git/branch-name.d.ts +0 -10
- package/dist/modules/workflow/git/branch-name.d.ts.map +0 -1
- package/dist/modules/workflow/git/branch-name.js +0 -76
- package/dist/modules/workflow/git/branch-name.js.map +0 -1
- package/dist/modules/workflow/git/clone-config.d.ts +0 -61
- package/dist/modules/workflow/git/clone-config.d.ts.map +0 -1
- package/dist/modules/workflow/git/clone-config.js +0 -69
- package/dist/modules/workflow/git/clone-config.js.map +0 -1
- package/dist/modules/workflow/git/mutex.d.ts +0 -11
- package/dist/modules/workflow/git/mutex.d.ts.map +0 -1
- package/dist/modules/workflow/git/mutex.js +0 -23
- package/dist/modules/workflow/git/mutex.js.map +0 -1
- package/dist/modules/workflow/locking-filesystem.d.ts +0 -137
- package/dist/modules/workflow/locking-filesystem.d.ts.map +0 -1
- package/dist/modules/workflow/locking-filesystem.js +0 -553
- package/dist/modules/workflow/locking-filesystem.js.map +0 -1
- package/dist/modules/workflow/read-only-filesystem.d.ts +0 -24
- package/dist/modules/workflow/read-only-filesystem.d.ts.map +0 -1
- package/dist/modules/workflow/read-only-filesystem.js +0 -39
- package/dist/modules/workflow/read-only-filesystem.js.map +0 -1
- package/dist/modules/workflow/workflow.errors.d.ts +0 -197
- package/dist/modules/workflow/workflow.errors.d.ts.map +0 -1
- package/dist/modules/workflow/workflow.errors.js +0 -298
- package/dist/modules/workflow/workflow.errors.js.map +0 -1
- package/dist/modules/workspace/bevel-ignore.d.ts.map +0 -1
- package/dist/modules/workspace/bevel-ignore.js.map +0 -1
- package/dist/modules/workspace/kb-seed.interface.d.ts +0 -36
- package/dist/modules/workspace/kb-seed.interface.d.ts.map +0 -1
- package/dist/modules/workspace/kb-seed.interface.js +0 -2
- package/dist/modules/workspace/kb-seed.interface.js.map +0 -1
- package/dist/modules/workspace/kb-seed.service.d.ts +0 -125
- package/dist/modules/workspace/kb-seed.service.d.ts.map +0 -1
- package/dist/modules/workspace/kb-seed.service.js +0 -535
- package/dist/modules/workspace/kb-seed.service.js.map +0 -1
- package/dist/modules/workspace/plugins-migration.d.ts +0 -50
- package/dist/modules/workspace/plugins-migration.d.ts.map +0 -1
- package/dist/modules/workspace/plugins-migration.js +0 -379
- package/dist/modules/workspace/plugins-migration.js.map +0 -1
- package/dist/shared/fs-errors.d.ts +0 -8
- package/dist/shared/fs-errors.d.ts.map +0 -1
- package/dist/shared/fs-errors.js +0 -11
- package/dist/shared/fs-errors.js.map +0 -1
- package/dist/shared/fs-walk.d.ts +0 -23
- package/dist/shared/fs-walk.d.ts.map +0 -1
- package/dist/shared/fs-walk.js +0 -42
- package/dist/shared/fs-walk.js.map +0 -1
- package/dist/shared/hash-email.d.ts +0 -11
- package/dist/shared/hash-email.d.ts.map +0 -1
- package/dist/shared/hash-email.js +0 -14
- package/dist/shared/hash-email.js.map +0 -1
- package/dist/shared/kb-walk.d.ts +0 -52
- package/dist/shared/kb-walk.d.ts.map +0 -1
- package/dist/shared/kb-walk.js +0 -76
- package/dist/shared/kb-walk.js.map +0 -1
- package/src/modules/diff/diff-paths.ts +0 -9
- package/src/modules/mcp/__tests__/mcp-session-store.test.ts +0 -151
- package/src/modules/mcp/__tests__/mcp.routes.session.test.ts +0 -226
- package/src/modules/mcp/mcp-session-store.ts +0 -162
- package/src/shared/__tests__/fs-walk.test.ts +0 -63
- package/src/shared/__tests__/kb-walk.test.ts +0 -107
- package/src/shared/fs-errors.ts +0 -10
- package/src/shared/fs-walk.ts +0 -45
- package/src/shared/hash-email.ts +0 -14
- package/src/shared/kb-walk.ts +0 -95
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
import fs from 'node:fs/promises';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
3
|
+
import { logger } from '../../shared/logging.js';
|
|
4
|
+
const log = logger('access');
|
|
5
|
+
import { isAbsence } from '../../shared/fs.contract.js';
|
|
6
|
+
import { isGitTimeout } from '../../shared/git.contract.js';
|
|
7
|
+
import { hashEmail } from '../../shared/email-identity.js';
|
|
8
|
+
import { NodeGitRunner } from '../workflow/git/node-git-runner.js';
|
|
9
|
+
import { PLUGINS_DIR, PLUGIN_MANIFEST_FILE, isPersonalPluginDir, pluginIdentityOf, platformRestoreDestination, } from '@bevel-software/platform-shared';
|
|
9
10
|
import { AccessConfigError, AccessUnreadableError } from '../access-model/access-errors.js';
|
|
11
|
+
import { WorkflowDomainError } from '../../shared/domain-errors.js';
|
|
10
12
|
import { synthesizePluginPrincipals } from '../access-model/plugin-principals.js';
|
|
11
13
|
import { GROUPS_YAML, SYNCED_GROUPS_YAML, parseGroupsFile, } from '../access-model/group-files.js';
|
|
12
|
-
import { ADMIN_CANONICAL, EVERYONE_CANONICAL, EVERYONE_DISPLAY, KNOWN_VERBS, ROLE_TOKEN_PREFIX, accessMdSelfEntries, canonicalEmail, canonicalRoleName, isAccessMdPath, mergeGroupsIntoRoles, parseAccessFile, parseOwnAccessEntries, parseRolesYaml, sourceVerbsFor, } from '../access-model/access-grammar.js';
|
|
14
|
+
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/access-grammar.js';
|
|
13
15
|
import { DIRECTORY_SYNC_BOT_EMAIL, DIRECTORY_SYNC_BOT_NAME, } from './directory-sync-bot.js';
|
|
14
|
-
const execFileAsync = promisify(execFile);
|
|
15
16
|
/**
|
|
16
17
|
* Read many objects from a git repo in ONE `git cat-file --batch` process.
|
|
17
18
|
* `specs` are `<ref>:<path>` lines; the result array is index-aligned with
|
|
@@ -20,61 +21,36 @@ const execFileAsync = promisify(execFile);
|
|
|
20
21
|
* request: `<oid> <type> <size>\n<size bytes>\n`, or `<spec> missing\n`
|
|
21
22
|
* (the spec may itself contain spaces, hence the endsWith checks).
|
|
22
23
|
*/
|
|
23
|
-
function catFileBatch(repoDir, specs) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const errChunks = [];
|
|
30
|
-
child.stdout.on('data', (c) => chunks.push(c));
|
|
31
|
-
child.stderr.on('data', (c) => errChunks.push(c));
|
|
32
|
-
// A dying git can close stdin mid-write; the 'close' handler below still
|
|
33
|
-
// fires with the exit code, which is the error we want to surface.
|
|
34
|
-
child.stdin.on('error', () => undefined);
|
|
35
|
-
child.on('error', reject);
|
|
36
|
-
child.on('close', (code) => {
|
|
37
|
-
if (code !== 0) {
|
|
38
|
-
reject(new Error(`git cat-file --batch exited ${code}: ${Buffer.concat(errChunks).toString('utf-8').trim()}`));
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
try {
|
|
42
|
-
const out = Buffer.concat(chunks);
|
|
43
|
-
const results = [];
|
|
44
|
-
let off = 0;
|
|
45
|
-
for (let i = 0; i < specs.length; i++) {
|
|
46
|
-
const nl = out.indexOf(0x0a, off);
|
|
47
|
-
if (nl < 0)
|
|
48
|
-
throw new Error('unexpected end of git cat-file output');
|
|
49
|
-
const header = out.subarray(off, nl).toString('utf-8');
|
|
50
|
-
off = nl + 1;
|
|
51
|
-
if (header.endsWith(' missing') || header.endsWith(' ambiguous')) {
|
|
52
|
-
results.push(null);
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
const parts = header.split(' ');
|
|
56
|
-
const size = Number(parts[2]);
|
|
57
|
-
if (parts.length !== 3 || !Number.isInteger(size) || size < 0) {
|
|
58
|
-
throw new Error(`unexpected git cat-file header: ${header}`);
|
|
59
|
-
}
|
|
60
|
-
// Non-blob (a directory path resolves to a tree) → null, but the
|
|
61
|
-
// payload still has to be skipped to stay aligned.
|
|
62
|
-
results.push(parts[1] === 'blob' ? out.subarray(off, off + size).toString('utf-8') : null);
|
|
63
|
-
off += size + 1; // payload + trailing LF
|
|
64
|
-
}
|
|
65
|
-
resolve(results);
|
|
66
|
-
}
|
|
67
|
-
catch (err) {
|
|
68
|
-
reject(err);
|
|
69
|
-
}
|
|
70
|
-
});
|
|
71
|
-
child.stdin.write(`${specs.join('\n')}\n`);
|
|
72
|
-
child.stdin.end();
|
|
24
|
+
async function catFileBatch(runner, repoDir, specs) {
|
|
25
|
+
// Bytes, not text: every `<size>` in the header counts bytes, and the walk
|
|
26
|
+
// below has to step by that count through content that is not all ASCII.
|
|
27
|
+
const { stdout: out } = await runner.run(repoDir, ['cat-file', '--batch'], {
|
|
28
|
+
input: `${specs.join('\n')}\n`,
|
|
29
|
+
encoding: 'buffer',
|
|
73
30
|
});
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
31
|
+
const results = [];
|
|
32
|
+
let off = 0;
|
|
33
|
+
for (let i = 0; i < specs.length; i++) {
|
|
34
|
+
const nl = out.indexOf(0x0a, off);
|
|
35
|
+
if (nl < 0)
|
|
36
|
+
throw new Error('unexpected end of git cat-file output');
|
|
37
|
+
const header = out.subarray(off, nl).toString('utf-8');
|
|
38
|
+
off = nl + 1;
|
|
39
|
+
if (header.endsWith(' missing') || header.endsWith(' ambiguous')) {
|
|
40
|
+
results.push(null);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const parts = header.split(' ');
|
|
44
|
+
const size = Number(parts[2]);
|
|
45
|
+
if (parts.length !== 3 || !Number.isInteger(size) || size < 0) {
|
|
46
|
+
throw new Error(`unexpected git cat-file header: ${header}`);
|
|
47
|
+
}
|
|
48
|
+
// Non-blob (a directory path resolves to a tree) → null, but the
|
|
49
|
+
// payload still has to be skipped to stay aligned.
|
|
50
|
+
results.push(parts[1] === 'blob' ? out.subarray(off, off + size).toString('utf-8') : null);
|
|
51
|
+
off += size + 1; // payload + trailing LF
|
|
52
|
+
}
|
|
53
|
+
return results;
|
|
78
54
|
}
|
|
79
55
|
function isBuiltInRole(canonicalRole) {
|
|
80
56
|
return canonicalRole === EVERYONE_CANONICAL;
|
|
@@ -89,13 +65,13 @@ function roleKnown(roles, canonicalRole) {
|
|
|
89
65
|
* even when the synced file is empty or malformed — falling back would
|
|
90
66
|
* resurrect retired manual groups); otherwise `groups.yaml` → manual mode.
|
|
91
67
|
*
|
|
92
|
-
* `read` returns null for a genuinely-absent file
|
|
93
|
-
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
68
|
+
* `read` returns null for a genuinely-absent file — ENOENT/ENOTDIR, the
|
|
69
|
+
* reader's judgement through the fs probe — and THROWS for any other failure.
|
|
70
|
+
* Every thrown error — notably one on `synced-groups.yaml` — is treated as a
|
|
71
|
+
* BROKEN source: no groups, no fallback to the manual file (falling back
|
|
72
|
+
* would resurrect retired groups), and an `ok: false` health marker.
|
|
73
|
+
* Structural parse failures degrade the same way; this function never throws
|
|
74
|
+
* (except to let an `AccessUnreadableError` through — see below).
|
|
99
75
|
*/
|
|
100
76
|
export async function loadActiveGroups(read) {
|
|
101
77
|
const broken = (file, reason) => ({
|
|
@@ -118,15 +94,10 @@ export async function loadActiveGroups(read) {
|
|
|
118
94
|
// the same error; groups cannot be the one input that does not.
|
|
119
95
|
if (err instanceof AccessUnreadableError)
|
|
120
96
|
throw err;
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
// A non-absence read error on the SYNCED source must NOT fall back to
|
|
126
|
-
// groups.yaml — the synced file may exist and its manual predecessor is
|
|
127
|
-
// retired. Broken-groups instead.
|
|
128
|
-
return broken(SYNCED_GROUPS_YAML, err instanceof Error ? err.message : String(err));
|
|
129
|
-
}
|
|
97
|
+
// A read error on the SYNCED source must NOT fall back to groups.yaml —
|
|
98
|
+
// the synced file may exist and its manual predecessor is retired.
|
|
99
|
+
// Broken-groups instead.
|
|
100
|
+
return broken(SYNCED_GROUPS_YAML, err instanceof Error ? err.message : String(err));
|
|
130
101
|
}
|
|
131
102
|
const sourceFile = syncedText !== null ? SYNCED_GROUPS_YAML : GROUPS_YAML;
|
|
132
103
|
let text;
|
|
@@ -140,10 +111,7 @@ export async function loadActiveGroups(read) {
|
|
|
140
111
|
catch (err) {
|
|
141
112
|
if (err instanceof AccessUnreadableError)
|
|
142
113
|
throw err; // see above
|
|
143
|
-
|
|
144
|
-
text = null;
|
|
145
|
-
else
|
|
146
|
-
return broken(GROUPS_YAML, err instanceof Error ? err.message : String(err));
|
|
114
|
+
return broken(GROUPS_YAML, err instanceof Error ? err.message : String(err));
|
|
147
115
|
}
|
|
148
116
|
}
|
|
149
117
|
if (text === null)
|
|
@@ -195,13 +163,13 @@ function accessFileListener(repoDir, out, pluginDirs) {
|
|
|
195
163
|
// Treat as if the file didn't exist for resolution purposes.
|
|
196
164
|
// Admin-rescue on access.md paths still lets an admin fix it.
|
|
197
165
|
for (const e of parsed.errors)
|
|
198
|
-
|
|
166
|
+
log.warn(`${e} — file ignored`);
|
|
199
167
|
return;
|
|
200
168
|
}
|
|
201
169
|
for (const w of parsed.warnings)
|
|
202
|
-
|
|
170
|
+
log.warn(w);
|
|
203
171
|
if (out.has(parsed.file.dir)) {
|
|
204
|
-
|
|
172
|
+
log.warn(`${rel}: duplicate access.md for directory '${parsed.file.dir}' — keeping the first one seen`);
|
|
205
173
|
return;
|
|
206
174
|
}
|
|
207
175
|
out.set(parsed.file.dir, parsed.file);
|
|
@@ -224,15 +192,24 @@ function parseManifestText(text) {
|
|
|
224
192
|
}
|
|
225
193
|
function resolveScopes(model, verb, relativePath, fileOwn) {
|
|
226
194
|
const target = verb;
|
|
195
|
+
// Both lists come from the grammar's one dependency graph (`VERB_REQUIRES`):
|
|
196
|
+
// the verbs whose grant confers the target, and the verbs the target
|
|
197
|
+
// presupposes, whose denial strips it.
|
|
227
198
|
const supersets = sourceVerbsFor(verb).filter((v) => v !== verb);
|
|
199
|
+
const prerequisites = requiredVerbsFor(verb).filter((v) => v !== verb);
|
|
228
200
|
// Build one scope's effective verdicts. The target verb contributes both
|
|
229
|
-
// grants and denials
|
|
230
|
-
// never strips `read`)
|
|
231
|
-
//
|
|
232
|
-
//
|
|
201
|
+
// grants and denials. Superset verbs contribute grants only (a `deny write`
|
|
202
|
+
// never strips `read`); prerequisite verbs contribute DENIALS only (a `deny
|
|
203
|
+
// write` strips `owner`, a `deny read` strips all three — nobody owns what
|
|
204
|
+
// they may not edit, or edits what they may not open), and a `read` grant
|
|
205
|
+
// confers no `write`. Within the scope a grant always wins over a deny of
|
|
206
|
+
// the same principal, so a same-file grant of the target or of a superset
|
|
207
|
+
// overrides a deny of the target or of a prerequisite (`owner:` beats `deny
|
|
208
|
+
// write`, `write:` beats `deny read`).
|
|
233
209
|
const buildScope = (entries, filterRoles, source) => {
|
|
234
210
|
const byRole = new Map();
|
|
235
211
|
const byEmail = new Map();
|
|
212
|
+
const implied = { byRole: new Set(), byEmail: new Set() };
|
|
236
213
|
const set = (entry, state) => {
|
|
237
214
|
const map = entry.kind === 'role' ? byRole : byEmail;
|
|
238
215
|
const key = entry.kind === 'role' ? entry.role : entry.email;
|
|
@@ -240,8 +217,9 @@ function resolveScopes(model, verb, relativePath, fileOwn) {
|
|
|
240
217
|
return; // a grant in this scope sticks
|
|
241
218
|
map.set(key, state);
|
|
242
219
|
};
|
|
220
|
+
const skip = (entry) => filterRoles && entry.kind === 'role' && !roleKnown(model.roles, entry.role);
|
|
243
221
|
for (const entry of entries[target]) {
|
|
244
|
-
if (
|
|
222
|
+
if (skip(entry))
|
|
245
223
|
continue;
|
|
246
224
|
set(entry, entry.deny ? 'denied' : 'grant');
|
|
247
225
|
}
|
|
@@ -249,11 +227,27 @@ function resolveScopes(model, verb, relativePath, fileOwn) {
|
|
|
249
227
|
for (const entry of entries[src]) {
|
|
250
228
|
if (entry.deny)
|
|
251
229
|
continue; // grant-only fold
|
|
252
|
-
if (
|
|
230
|
+
if (skip(entry))
|
|
253
231
|
continue;
|
|
254
232
|
set(entry, 'grant');
|
|
255
233
|
}
|
|
256
234
|
}
|
|
235
|
+
// Last, so a target or superset GRANT already in the map stands, and a
|
|
236
|
+
// target's own `deny` line is never re-labelled as implied.
|
|
237
|
+
for (const src of prerequisites) {
|
|
238
|
+
for (const entry of entries[src]) {
|
|
239
|
+
if (!entry.deny)
|
|
240
|
+
continue; // deny-only fold
|
|
241
|
+
if (skip(entry))
|
|
242
|
+
continue;
|
|
243
|
+
const map = entry.kind === 'role' ? byRole : byEmail;
|
|
244
|
+
const key = entry.kind === 'role' ? entry.role : entry.email;
|
|
245
|
+
if (map.has(key))
|
|
246
|
+
continue; // an own verdict (grant or deny) is already the answer
|
|
247
|
+
map.set(key, 'denied');
|
|
248
|
+
(entry.kind === 'role' ? implied.byRole : implied.byEmail).add(key);
|
|
249
|
+
}
|
|
250
|
+
}
|
|
257
251
|
// The anonymous caller's verdict at this scope — what someone who holds
|
|
258
252
|
// exactly the PUBLIC keys (a plugin principal whose plugin admits
|
|
259
253
|
// everyone, so everyone holds it) resolves to, by the same tiers a named
|
|
@@ -279,7 +273,7 @@ function resolveScopes(model, verb, relativePath, fileOwn) {
|
|
|
279
273
|
: publicDeny
|
|
280
274
|
? 'denied'
|
|
281
275
|
: byRole.get(EVERYONE_CANONICAL);
|
|
282
|
-
return { byRole, byEmail, everyone, source };
|
|
276
|
+
return { byRole, byEmail, everyone, source, implied };
|
|
283
277
|
};
|
|
284
278
|
const scopes = [];
|
|
285
279
|
// The node's own frontmatter is the most specific scope. Role refs there are
|
|
@@ -330,6 +324,97 @@ function principalKeysOf(model, email) {
|
|
|
330
324
|
return own;
|
|
331
325
|
return new Set([...(own ?? []), ...pub]);
|
|
332
326
|
}
|
|
327
|
+
/** The explicit key of the Admin ROLE — never the bare token, which a same-named group may own. */
|
|
328
|
+
const ADMIN_ROLE_KEY = `${ROLE_TOKEN_PREFIX}${ADMIN_CANONICAL}`;
|
|
329
|
+
/**
|
|
330
|
+
* Add to `keys` what holding them confers on top: every plugin principal
|
|
331
|
+
* expanded from one of the keys, and the public keys every caller holds.
|
|
332
|
+
*/
|
|
333
|
+
function addDerivedKeys(model, keys) {
|
|
334
|
+
for (const [key, principal] of model.roles.byCanonical) {
|
|
335
|
+
if (principal.kind !== 'plugin' || !principal.sourceKeys)
|
|
336
|
+
continue;
|
|
337
|
+
for (const source of principal.sourceKeys) {
|
|
338
|
+
if (keys.has(source)) {
|
|
339
|
+
keys.add(key);
|
|
340
|
+
break;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
for (const key of model.roles.publicKeys ?? [])
|
|
345
|
+
keys.add(key);
|
|
346
|
+
return keys;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Every principal key that being in `group` confers — the group's OWN key,
|
|
350
|
+
* the roles that list the group (`group:<Name>` in roles.yaml), the plugin
|
|
351
|
+
* principals whose roster admits the group directly or through one of those
|
|
352
|
+
* roles, and the public keys every caller holds. This is the group-shaped
|
|
353
|
+
* twin of `principalKeysOf`: a member's key set minus everything they hold
|
|
354
|
+
* for reasons of their own. `null` when no group of that name exists.
|
|
355
|
+
*
|
|
356
|
+
* Groups are keyed by their bare canonical name (`mergeGroupsIntoRoles`);
|
|
357
|
+
* roles by `role/<name>`. A bare key whose record is a ROLE is not a group,
|
|
358
|
+
* however it was spelled.
|
|
359
|
+
*/
|
|
360
|
+
function principalKeysOfGroup(model, group) {
|
|
361
|
+
const canonical = canonicalRoleName(group);
|
|
362
|
+
const record = model.roles.byCanonical.get(canonical);
|
|
363
|
+
if (!record || record.kind !== 'group')
|
|
364
|
+
return null;
|
|
365
|
+
const keys = new Set([canonical]);
|
|
366
|
+
for (const [key, principal] of model.roles.byCanonical) {
|
|
367
|
+
if (principal.kind === 'role' && principal.groupRefs?.has(canonical))
|
|
368
|
+
keys.add(key);
|
|
369
|
+
}
|
|
370
|
+
// Plugin principals were expanded from role/group entries; a plugin that
|
|
371
|
+
// admits the group, or a role the group is folded into, admits the group.
|
|
372
|
+
return addDerivedKeys(model, keys);
|
|
373
|
+
}
|
|
374
|
+
/** The key set of a caller who holds nothing: `hasPermissionForKeys` then answers as `everyone`. */
|
|
375
|
+
const NO_KEYS = new Set();
|
|
376
|
+
/**
|
|
377
|
+
* The tier-2 half of `hasPermissionResolved` on its own: a verdict for a set
|
|
378
|
+
* of principal KEYS with no person behind them — no direct-email tier, no
|
|
379
|
+
* admin rescue, no machine-owned rule — only the Admin write floor, when the
|
|
380
|
+
* keys include the Admin role. Closest scope first; within a scope a
|
|
381
|
+
* grant to any key wins over a denial to another, exactly as for a person.
|
|
382
|
+
*/
|
|
383
|
+
function hasPermissionForKeys(model, verb, keys, relativePath, fileOwn) {
|
|
384
|
+
const adminFloor = verb === 'write' && keys.has(ADMIN_ROLE_KEY);
|
|
385
|
+
for (const scope of resolveScopes(model, verb, relativePath, fileOwn)) {
|
|
386
|
+
if (adminFloor && isAdminFloorScope(scope, relativePath))
|
|
387
|
+
return true;
|
|
388
|
+
let grant = false;
|
|
389
|
+
let deny = false;
|
|
390
|
+
for (const key of keys) {
|
|
391
|
+
const state = scope.byRole.get(key);
|
|
392
|
+
if (state === 'denied')
|
|
393
|
+
deny = true;
|
|
394
|
+
else if (state === 'grant')
|
|
395
|
+
grant = true;
|
|
396
|
+
}
|
|
397
|
+
if (grant)
|
|
398
|
+
return true;
|
|
399
|
+
if (deny)
|
|
400
|
+
return false;
|
|
401
|
+
if (scope.everyone)
|
|
402
|
+
return scope.everyone === 'grant';
|
|
403
|
+
}
|
|
404
|
+
return adminFloor;
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Whether a scope sits at the Admin write floor: the repository root's own
|
|
408
|
+
* `access.md`, or the own frontmatter of a file directly in the root (those
|
|
409
|
+
* files are part of the root, so their own rules cannot take Admin's write
|
|
410
|
+
* away either). A folder directly in the root is not covered — its own
|
|
411
|
+
* `access.md` is an ordinary subfolder scope that may exclude Admin.
|
|
412
|
+
*/
|
|
413
|
+
function isAdminFloorScope(scope, relativePath) {
|
|
414
|
+
if (scope.source.kind === 'own')
|
|
415
|
+
return !relativePath.includes('/');
|
|
416
|
+
return scope.source.path === 'access.md';
|
|
417
|
+
}
|
|
333
418
|
function isAdminEmail(model, email) {
|
|
334
419
|
if (model.deploymentOwners.has(email))
|
|
335
420
|
return true;
|
|
@@ -337,7 +422,7 @@ function isAdminEmail(model, email) {
|
|
|
337
422
|
// Check the explicit `role/admin` alias, NOT the bare token: bare-name
|
|
338
423
|
// precedence is group-first, so a group that happens to be named "Admin"
|
|
339
424
|
// owns the bare key — and its members must never inherit the capability.
|
|
340
|
-
return !!roles && roles.has(
|
|
425
|
+
return !!roles && roles.has(ADMIN_ROLE_KEY);
|
|
341
426
|
}
|
|
342
427
|
/**
|
|
343
428
|
* Resolve whether `userEmail` has `verb` on `relativePath`.
|
|
@@ -370,48 +455,76 @@ function isAdminEmail(model, email) {
|
|
|
370
455
|
* owner is whoever can already set `ADMIN_EMAIL`, so this concedes no
|
|
371
456
|
* authority they did not have; it only gives it a door.
|
|
372
457
|
*
|
|
458
|
+
* One floor for `write`, applied during the walk: an admin (same definition)
|
|
459
|
+
* always holds `write` at the repository root. When the walk reaches the root
|
|
460
|
+
* `access.md` (or the own frontmatter of a file directly in the root) — or runs
|
|
461
|
+
* out of scopes without a verdict — an admin is granted,
|
|
462
|
+
* whatever the root file says, so no root rule can lock the deployment out of
|
|
463
|
+
* its own tree. A NEARER scope still decides first: a subfolder that denies
|
|
464
|
+
* Admin (or denies `everyone` without naming Admin) excludes admins there like
|
|
465
|
+
* anyone else. The root file's own entries are not rewritten — the floor is a
|
|
466
|
+
* verdict, not a grant line — so `grantSources` stays file-backed.
|
|
467
|
+
*
|
|
373
468
|
* No special-cases for `read`/`download` — they fall through to scope resolution.
|
|
374
469
|
*/
|
|
375
470
|
function hasPermissionResolved(model, verb, userEmail, relativePath, fileOwn) {
|
|
471
|
+
return decidePermissionResolved(model, verb, userEmail, relativePath, fileOwn).allowed;
|
|
472
|
+
}
|
|
473
|
+
function decidePermissionResolved(model, verb, userEmail, relativePath, fileOwn) {
|
|
376
474
|
const email = canonicalEmail(userEmail);
|
|
377
475
|
if (verb === 'write') {
|
|
378
|
-
if (relativePath === 'roles.yaml')
|
|
379
|
-
return isAdminEmail(model, email);
|
|
380
|
-
|
|
381
|
-
|
|
476
|
+
if (relativePath === 'roles.yaml') {
|
|
477
|
+
return { allowed: isAdminEmail(model, email), scope: null, via: 'admin-rescue' };
|
|
478
|
+
}
|
|
479
|
+
if (isAccessMdPath(relativePath) && isAdminEmail(model, email)) {
|
|
480
|
+
return { allowed: true, scope: null, via: 'admin-rescue' };
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
const adminFloor = verb === 'write' && isAdminEmail(model, email);
|
|
484
|
+
// For write, the deployment owner IS Admin — the floor admits them, so the
|
|
485
|
+
// Admin rules along the way bind them too: a subfolder denying Admin excludes
|
|
486
|
+
// the owner exactly as it excludes the role's members.
|
|
487
|
+
let userRoles = principalKeysOf(model, email);
|
|
488
|
+
if (adminFloor && !userRoles?.has(ADMIN_ROLE_KEY)) {
|
|
489
|
+
userRoles = new Set([...(userRoles ?? []), ...principalKeysOfToken(model, ADMIN_ROLE_KEY)]);
|
|
382
490
|
}
|
|
383
|
-
const userRoles = principalKeysOf(model, email);
|
|
384
491
|
const scopes = resolveScopes(model, verb, relativePath, fileOwn);
|
|
385
492
|
for (const scope of scopes) {
|
|
493
|
+
if (adminFloor && isAdminFloorScope(scope, relativePath))
|
|
494
|
+
return { allowed: true, scope, via: 'admin-floor' };
|
|
386
495
|
// Tier 1 — direct email entry is the most specific verdict at this scope.
|
|
387
496
|
const direct = scope.byEmail.get(email);
|
|
388
497
|
if (direct)
|
|
389
|
-
return direct === 'grant';
|
|
498
|
+
return { allowed: direct === 'grant', scope, via: 'email', key: email };
|
|
390
499
|
// Tier 2 — the caller's roles. A grant via any one of them wins over a deny
|
|
391
500
|
// via another at this same scope (a `deny Engineer` doesn't undo an
|
|
392
501
|
// unrelated `Admin` grant).
|
|
393
502
|
if (userRoles && userRoles.size) {
|
|
394
|
-
let
|
|
395
|
-
let
|
|
503
|
+
let granted;
|
|
504
|
+
let denied;
|
|
396
505
|
for (const r of userRoles) {
|
|
397
506
|
const s = scope.byRole.get(r);
|
|
398
507
|
if (s === 'denied')
|
|
399
|
-
|
|
508
|
+
denied ??= r;
|
|
400
509
|
else if (s === 'grant')
|
|
401
|
-
|
|
510
|
+
granted ??= r;
|
|
402
511
|
}
|
|
403
|
-
if (
|
|
404
|
-
return true;
|
|
405
|
-
if (
|
|
406
|
-
return false;
|
|
512
|
+
if (granted !== undefined)
|
|
513
|
+
return { allowed: true, scope, via: 'principal', key: granted };
|
|
514
|
+
if (denied !== undefined)
|
|
515
|
+
return { allowed: false, scope, via: 'principal', key: denied };
|
|
407
516
|
}
|
|
408
517
|
// Tier 3 — the built-in `everyone` role (derived: a public plugin
|
|
409
518
|
// principal granted here counts, see `AccessScope.everyone`).
|
|
410
|
-
if (scope.everyone)
|
|
411
|
-
return scope.everyone === 'grant';
|
|
519
|
+
if (scope.everyone) {
|
|
520
|
+
return { allowed: scope.everyone === 'grant', scope, via: 'everyone', key: EVERYONE_CANONICAL };
|
|
521
|
+
}
|
|
412
522
|
// No verdict at this scope — fall through to the next (farther) one.
|
|
413
523
|
}
|
|
414
|
-
|
|
524
|
+
// No verdict anywhere (and no root access.md to stop at): the floor still holds.
|
|
525
|
+
return adminFloor
|
|
526
|
+
? { allowed: true, scope: null, via: 'admin-floor' }
|
|
527
|
+
: { allowed: false, scope: null, via: 'default-deny' };
|
|
415
528
|
}
|
|
416
529
|
/**
|
|
417
530
|
* The `access.md` that a FOLDER target's own grants live in — its direct scope.
|
|
@@ -438,6 +551,39 @@ function scopeToGrantSource(scope, kind, relativePath) {
|
|
|
438
551
|
return { kind: 'direct' };
|
|
439
552
|
return { kind: 'ancestor', path };
|
|
440
553
|
}
|
|
554
|
+
/**
|
|
555
|
+
* Where a scope's rules live, as the place a person edits: a folder (the
|
|
556
|
+
* directory of its `access.md`) or the target's own frontmatter.
|
|
557
|
+
*/
|
|
558
|
+
function decisionSourceOf(scope, kind, relativePath) {
|
|
559
|
+
if (scope.source.kind === 'own')
|
|
560
|
+
return { kind: 'frontmatter', path: relativePath, inherited: false };
|
|
561
|
+
const folder = path.posix.dirname(scope.source.path);
|
|
562
|
+
const dir = folder === '.' ? '' : folder;
|
|
563
|
+
const grant = scopeToGrantSource(scope, kind, relativePath);
|
|
564
|
+
return { kind: 'folder', path: dir, inherited: grant.kind === 'ancestor' };
|
|
565
|
+
}
|
|
566
|
+
/** A resolver decision in the terms `explainAccess` reports. */
|
|
567
|
+
function explainDecision(model, decision, kind, relativePath) {
|
|
568
|
+
const source = decision.scope ? decisionSourceOf(decision.scope, kind, relativePath) : null;
|
|
569
|
+
const base = { allowed: decision.allowed, source };
|
|
570
|
+
switch (decision.via) {
|
|
571
|
+
case 'admin-rescue':
|
|
572
|
+
case 'default-deny':
|
|
573
|
+
return { ...base, via: decision.via, principal: null };
|
|
574
|
+
case 'admin-floor':
|
|
575
|
+
return { ...base, via: decision.via, principal: 'Admin' };
|
|
576
|
+
case 'email':
|
|
577
|
+
return { ...base, via: 'person', principal: decision.key ?? null };
|
|
578
|
+
case 'everyone':
|
|
579
|
+
return { ...base, via: 'everyone', principal: EVERYONE_CANONICAL };
|
|
580
|
+
case 'principal': {
|
|
581
|
+
const key = decision.key ?? '';
|
|
582
|
+
const record = model.roles.byCanonical.get(key);
|
|
583
|
+
return { ...base, via: record?.kind ?? 'role', principal: record?.displayName ?? key };
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
}
|
|
441
587
|
/**
|
|
442
588
|
* Resolve EVERY file scope that names a principal for `verb`, ordered
|
|
443
589
|
* closest-first — the source-returning twin of `hasPermissionResolved`, but
|
|
@@ -487,13 +633,7 @@ function resolveGrantSourcesForVerb(model, verb, kind, relativePath, principal,
|
|
|
487
633
|
// a GROUP whose group has VANISHED reads "unshadowed" here, and the
|
|
488
634
|
// alias-tolerant pair would then attribute a same-named role's
|
|
489
635
|
// surviving `role/<name>` grant to the group.
|
|
490
|
-
const
|
|
491
|
-
const explicit = canonical.startsWith(ROLE_TOKEN_PREFIX);
|
|
492
|
-
const bare = explicit ? canonical.slice(ROLE_TOKEN_PREFIX.length) : canonical;
|
|
493
|
-
const shadowed = model.roles.byCanonical.get(bare)?.kind === 'group';
|
|
494
|
-
const tokens = tokenMatch === 'exact' || shadowed
|
|
495
|
-
? [explicit ? `${ROLE_TOKEN_PREFIX}${bare}` : bare]
|
|
496
|
-
: [bare, `${ROLE_TOKEN_PREFIX}${bare}`];
|
|
636
|
+
const tokens = ownTokensOf(model, principal.role, tokenMatch);
|
|
497
637
|
for (const scope of scopes) {
|
|
498
638
|
const states = tokens.map((t) => scope.byRole.get(t));
|
|
499
639
|
if (states.includes('grant')) {
|
|
@@ -520,6 +660,69 @@ function resolveGrantSourcesForVerb(model, verb, kind, relativePath, principal,
|
|
|
520
660
|
}
|
|
521
661
|
return out;
|
|
522
662
|
}
|
|
663
|
+
/**
|
|
664
|
+
* WHICH token spellings in a file are THIS role-shaped principal's own entries
|
|
665
|
+
* — the shadowing rule, in one place because the grant walk, the denial walk
|
|
666
|
+
* and the revoke splice must all agree on it (a disagreement attributes a
|
|
667
|
+
* shadowed bare token to the wrong principal, which is how a "restrict" silently
|
|
668
|
+
* strips a same-named role's grant). See `resolveGrantSourcesForVerb` for the
|
|
669
|
+
* full reasoning behind each branch.
|
|
670
|
+
*/
|
|
671
|
+
function ownTokensOf(model, role, tokenMatch) {
|
|
672
|
+
const canonical = canonicalRoleName(role);
|
|
673
|
+
const explicit = canonical.startsWith(ROLE_TOKEN_PREFIX);
|
|
674
|
+
const bare = explicit ? canonical.slice(ROLE_TOKEN_PREFIX.length) : canonical;
|
|
675
|
+
const shadowed = model.roles.byCanonical.get(bare)?.kind === 'group';
|
|
676
|
+
return tokenMatch === 'exact' || shadowed
|
|
677
|
+
? [explicit ? `${ROLE_TOKEN_PREFIX}${bare}` : bare]
|
|
678
|
+
: [bare, `${ROLE_TOKEN_PREFIX}${bare}`];
|
|
679
|
+
}
|
|
680
|
+
/**
|
|
681
|
+
* The polarity twin of {@link resolveGrantSourcesForVerb}: every file scope
|
|
682
|
+
* whose own entry for this principal DENIES `verb`, closest-first.
|
|
683
|
+
*
|
|
684
|
+
* Same walk, mirrored stopping rule. A grant in the principal's own entry at a
|
|
685
|
+
* scope ENDS the list — under closest-wins a farther deny is dead, and reporting
|
|
686
|
+
* it would have the dialog say "restricted" about a verb the principal holds.
|
|
687
|
+
* A grant or deny reaching the principal through a group/role/`everyone` is not
|
|
688
|
+
* their own entry: it is neither a denial to report nor a reason to stop, so the
|
|
689
|
+
* walk carries on past it, exactly as the grant twin does.
|
|
690
|
+
*
|
|
691
|
+
* Returns `[]` when the principal is not denied `verb` by any file entry.
|
|
692
|
+
*/
|
|
693
|
+
function resolveDenialSourcesForVerb(model, verb, kind, relativePath, principal, fileOwn, tokenMatch) {
|
|
694
|
+
const scopes = resolveScopes(model, verb, relativePath, fileOwn);
|
|
695
|
+
const out = [];
|
|
696
|
+
if (principal.kind === 'role') {
|
|
697
|
+
const tokens = ownTokensOf(model, principal.role, tokenMatch);
|
|
698
|
+
for (const scope of scopes) {
|
|
699
|
+
const states = tokens.map((t) => scope.byRole.get(t));
|
|
700
|
+
// A grant under EITHER spelling wins within the scope (`buildScope` lets a
|
|
701
|
+
// grant stick over a deny of the same principal), so it ends the walk
|
|
702
|
+
// whether or not the other spelling denies here.
|
|
703
|
+
if (states.includes('grant'))
|
|
704
|
+
break;
|
|
705
|
+
// Only a `deny <verb>` LINE is a source; a denial the scope implies from
|
|
706
|
+
// a prerequisite verb's line (`deny write` when asking about owner) is
|
|
707
|
+
// real but is not this verb's entry — the prerequisite's own report is
|
|
708
|
+
// where it can be lifted.
|
|
709
|
+
const written = tokens.some((t) => scope.byRole.get(t) === 'denied' && !scope.implied.byRole.has(t));
|
|
710
|
+
if (written)
|
|
711
|
+
out.push(scopeToGrantSource(scope, kind, relativePath));
|
|
712
|
+
}
|
|
713
|
+
return out;
|
|
714
|
+
}
|
|
715
|
+
const email = canonicalEmail(principal.email);
|
|
716
|
+
for (const scope of scopes) {
|
|
717
|
+
const own = scope.byEmail.get(email);
|
|
718
|
+
if (own === 'grant')
|
|
719
|
+
break;
|
|
720
|
+
if (own === 'denied' && !scope.implied.byEmail.has(email)) {
|
|
721
|
+
out.push(scopeToGrantSource(scope, kind, relativePath));
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
return out;
|
|
725
|
+
}
|
|
523
726
|
/**
|
|
524
727
|
* Build the repo-root → path chain of directory scopes that govern
|
|
525
728
|
* `relativePath`, e.g. `Knowledge/Sales/Foo.md` →
|
|
@@ -588,6 +791,32 @@ function canEveryoneReadResolved(model, relativePath, fileOwn) {
|
|
|
588
791
|
function canReadResolved(model, userEmail, relativePath, fileOwn) {
|
|
589
792
|
return hasPermissionResolved(model, 'read', userEmail, relativePath, fileOwn);
|
|
590
793
|
}
|
|
794
|
+
/**
|
|
795
|
+
* The key set someone holding exactly the principal behind `token` carries —
|
|
796
|
+
* the question "would a member of this principal be allowed?" put to
|
|
797
|
+
* `hasPermissionForKeys`. A group gets its full member key set
|
|
798
|
+
* (`principalKeysOfGroup`); a role or plugin principal gets every key its
|
|
799
|
+
* record is registered under (the bare name and the `role/` alias share one
|
|
800
|
+
* record) plus the plugin principals expanded from those keys; a token with no
|
|
801
|
+
* record (`everyone`, a vanished principal) is just itself. Public keys are
|
|
802
|
+
* always included — every caller holds them.
|
|
803
|
+
*/
|
|
804
|
+
function principalKeysOfToken(model, token) {
|
|
805
|
+
const record = model.roles.byCanonical.get(token);
|
|
806
|
+
if (record?.kind === 'group')
|
|
807
|
+
return principalKeysOfGroup(model, token) ?? new Set([token]);
|
|
808
|
+
const keys = new Set([token]);
|
|
809
|
+
if (!record) {
|
|
810
|
+
for (const key of model.roles.publicKeys ?? [])
|
|
811
|
+
keys.add(key);
|
|
812
|
+
return keys;
|
|
813
|
+
}
|
|
814
|
+
for (const [key, principal] of model.roles.byCanonical) {
|
|
815
|
+
if (principal === record)
|
|
816
|
+
keys.add(key);
|
|
817
|
+
}
|
|
818
|
+
return addDerivedKeys(model, keys);
|
|
819
|
+
}
|
|
591
820
|
function eligibleHoldersResolved(model, verb, relativePath, fileOwn) {
|
|
592
821
|
const { byRole, byEmail, everyone } = resolveAtPath(model, verb, relativePath, fileOwn);
|
|
593
822
|
// (kind, display name) → one entry. The `byRole` keys are the merged
|
|
@@ -607,17 +836,33 @@ function eligibleHoldersResolved(model, verb, relativePath, fileOwn) {
|
|
|
607
836
|
if (!byIdentity.has(key))
|
|
608
837
|
byIdentity.set(key, { name, kind });
|
|
609
838
|
};
|
|
839
|
+
// Every row is re-checked against the resolver. The collapsed view keeps a
|
|
840
|
+
// principal's closest OWN verdict, but a nearer scope can still decide for
|
|
841
|
+
// them without naming them — a `deny everyone` in a subfolder cuts off a
|
|
842
|
+
// root `write: Admin` — and a list that named them anyway would tell the
|
|
843
|
+
// dialog and the denial message that someone is eligible whom the gate then
|
|
844
|
+
// refuses.
|
|
845
|
+
const allowedFor = (keys) => hasPermissionForKeys(model, verb, keys, relativePath, fileOwn);
|
|
610
846
|
for (const [canonical, state] of byRole) {
|
|
611
847
|
if (state !== 'grant')
|
|
612
848
|
continue;
|
|
849
|
+
if (!allowedFor(principalKeysOfToken(model, canonical)))
|
|
850
|
+
continue;
|
|
613
851
|
const record = model.roles.byCanonical.get(canonical);
|
|
614
852
|
addPrincipal(record ? record.displayName : canonical, record?.kind ?? 'role');
|
|
615
853
|
}
|
|
854
|
+
// The Admin write floor (see `hasPermissionResolved`): Admin holds write here
|
|
855
|
+
// whenever no nearer scope excludes it, whether or not any file names it.
|
|
856
|
+
if (verb === 'write' && model.roles.byCanonical.has(ADMIN_ROLE_KEY)) {
|
|
857
|
+
const adminRole = model.roles.byCanonical.get(ADMIN_ROLE_KEY);
|
|
858
|
+
if (allowedFor(principalKeysOfToken(model, ADMIN_ROLE_KEY)))
|
|
859
|
+
addPrincipal(adminRole.displayName, 'role');
|
|
860
|
+
}
|
|
616
861
|
// The derived everyone verdict: a public plugin principal granted here
|
|
617
862
|
// means anyone signed in holds the verb, and a list that counts holders (an
|
|
618
863
|
// approval gate, a "restricted to" banner) must say so — as `everyone`, the
|
|
619
864
|
// same row a literal grant produces.
|
|
620
|
-
if (everyone === 'grant')
|
|
865
|
+
if (everyone === 'grant' && allowedFor(NO_KEYS))
|
|
621
866
|
addPrincipal(EVERYONE_CANONICAL, 'role');
|
|
622
867
|
// Mirror the admin overrides applied in `hasPermissionResolved`: write on
|
|
623
868
|
// `roles.yaml` and on any `access.md` is granted to Admin even if the
|
|
@@ -629,7 +874,7 @@ function eligibleHoldersResolved(model, verb, relativePath, fileOwn) {
|
|
|
629
874
|
// Look the Admin ROLE up via its explicit alias — the bare key may be
|
|
630
875
|
// owned by a same-named group under group-first precedence. The override
|
|
631
876
|
// is the ROLE's capability, so the row's kind is 'role' regardless.
|
|
632
|
-
const adminRole = model.roles.byCanonical.get(
|
|
877
|
+
const adminRole = model.roles.byCanonical.get(ADMIN_ROLE_KEY);
|
|
633
878
|
addPrincipal(adminRole ? adminRole.displayName : ADMIN_CANONICAL, 'role');
|
|
634
879
|
}
|
|
635
880
|
const principals = [...byIdentity.values()].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : a.kind < b.kind ? -1 : a.kind > b.kind ? 1 : 0);
|
|
@@ -641,11 +886,26 @@ function eligibleHoldersResolved(model, verb, relativePath, fileOwn) {
|
|
|
641
886
|
for (const [email, state] of byEmail) {
|
|
642
887
|
if (state !== 'grant')
|
|
643
888
|
continue;
|
|
889
|
+
if (!hasPermissionResolved(model, verb, email, relativePath, fileOwn))
|
|
890
|
+
continue;
|
|
644
891
|
users.push({ name: '', email });
|
|
645
892
|
}
|
|
646
893
|
users.sort((a, b) => a.email.localeCompare(b.email));
|
|
647
894
|
return { principals, roles, users };
|
|
648
895
|
}
|
|
896
|
+
/**
|
|
897
|
+
* Every individual the model names: `roles.yaml` members, emails named inline
|
|
898
|
+
* at this path's scope, and the deployment owner (Admin for the write floor
|
|
899
|
+
* even when `roles.yaml` does not list them).
|
|
900
|
+
*/
|
|
901
|
+
function namedCandidateEmails(model, byEmail) {
|
|
902
|
+
const candidates = new Set(model.deploymentOwners);
|
|
903
|
+
for (const email of model.roles.byEmail.keys())
|
|
904
|
+
candidates.add(email);
|
|
905
|
+
for (const email of byEmail.keys())
|
|
906
|
+
candidates.add(email);
|
|
907
|
+
return candidates;
|
|
908
|
+
}
|
|
649
909
|
/**
|
|
650
910
|
* Expand the eligible-writer set to the underlying emails.
|
|
651
911
|
*
|
|
@@ -665,12 +925,10 @@ function eligibleHolderEmailsResolved(model, verb, relativePath, fileOwn) {
|
|
|
665
925
|
// in an access.md entry at this path's scope (whether granted or denied —
|
|
666
926
|
// `hasPermissionResolved` filters denials out below). The built-in
|
|
667
927
|
// `everyone` role can grant arbitrary signed-in users, but this finite
|
|
668
|
-
// expansion can only return emails the access tree explicitly names.
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
for (const email of byEmail.keys())
|
|
673
|
-
candidates.add(email);
|
|
928
|
+
// expansion can only return emails the access tree explicitly names. The
|
|
929
|
+
// deployment owner is a candidate too: the Admin write floor admits them
|
|
930
|
+
// whether or not `roles.yaml` lists them.
|
|
931
|
+
const candidates = namedCandidateEmails(model, byEmail);
|
|
674
932
|
for (const email of candidates) {
|
|
675
933
|
if (hasPermissionResolved(model, verb, email, relativePath, fileOwn)) {
|
|
676
934
|
out.set(email, { name: '', email });
|
|
@@ -690,11 +948,7 @@ function eligibleHolderEmailsResolved(model, verb, relativePath, fileOwn) {
|
|
|
690
948
|
*/
|
|
691
949
|
function ineligibleNamedEmailsResolved(model, verb, relativePath, fileOwn) {
|
|
692
950
|
const { byEmail } = resolveAtPath(model, verb, relativePath, fileOwn);
|
|
693
|
-
const candidates =
|
|
694
|
-
for (const email of model.roles.byEmail.keys())
|
|
695
|
-
candidates.add(email);
|
|
696
|
-
for (const email of byEmail.keys())
|
|
697
|
-
candidates.add(email);
|
|
951
|
+
const candidates = namedCandidateEmails(model, byEmail);
|
|
698
952
|
const out = new Set();
|
|
699
953
|
for (const email of candidates) {
|
|
700
954
|
if (!hasPermissionResolved(model, verb, email, relativePath, fileOwn))
|
|
@@ -705,6 +959,8 @@ function ineligibleNamedEmailsResolved(model, verb, relativePath, fileOwn) {
|
|
|
705
959
|
export class AccessControlService {
|
|
706
960
|
workspaceService;
|
|
707
961
|
kbDirName;
|
|
962
|
+
disk;
|
|
963
|
+
gitRunner;
|
|
708
964
|
/**
|
|
709
965
|
* Per-workspace cache: `model` is the resolved access tree and `loadedAt`
|
|
710
966
|
* is when we computed it. We re-load on a TTL — the validator runs on
|
|
@@ -757,16 +1013,25 @@ export class AccessControlService {
|
|
|
757
1013
|
* environment, not from the knowledge base.
|
|
758
1014
|
*/
|
|
759
1015
|
deploymentOwners;
|
|
760
|
-
constructor(workspaceService, kbDirName,
|
|
1016
|
+
constructor(workspaceService, kbDirName, disk,
|
|
761
1017
|
/**
|
|
762
1018
|
* Emails that count as Admin for the two hardcoded `write` rescues,
|
|
763
1019
|
* whatever `roles.yaml` says — in practice `ADMIN_EMAIL`. Optional so the
|
|
764
1020
|
* many test fixtures that construct this service directly keep their
|
|
765
1021
|
* current behaviour (no owner, roles.yaml is the only authority).
|
|
766
1022
|
*/
|
|
767
|
-
deploymentOwners = []
|
|
1023
|
+
deploymentOwners = [],
|
|
1024
|
+
/**
|
|
1025
|
+
* How git is run — see `shared/git.contract.ts`. The composition root
|
|
1026
|
+
* passes the one runner; the default is the same runner on its default
|
|
1027
|
+
* deadline, kept for the same reason as `deploymentOwners` above: a great
|
|
1028
|
+
* many fixtures construct this service directly.
|
|
1029
|
+
*/
|
|
1030
|
+
gitRunner = new NodeGitRunner()) {
|
|
768
1031
|
this.workspaceService = workspaceService;
|
|
769
1032
|
this.kbDirName = kbDirName;
|
|
1033
|
+
this.disk = disk;
|
|
1034
|
+
this.gitRunner = gitRunner;
|
|
770
1035
|
this.deploymentOwners = new Set(deploymentOwners.filter(Boolean).map((e) => canonicalEmail(e)));
|
|
771
1036
|
}
|
|
772
1037
|
/**
|
|
@@ -853,6 +1118,35 @@ export class AccessControlService {
|
|
|
853
1118
|
});
|
|
854
1119
|
return result;
|
|
855
1120
|
}
|
|
1121
|
+
async canReadAsGroupBatch(workspaceId, group, relativePaths) {
|
|
1122
|
+
const model = await this.loadModel(workspaceId);
|
|
1123
|
+
const keys = principalKeysOfGroup(model, group);
|
|
1124
|
+
if (keys === null)
|
|
1125
|
+
return null;
|
|
1126
|
+
const repoDir = await this.repoDir(workspaceId);
|
|
1127
|
+
// The same per-path own-entries `canReadBatch` folds in: a file's own
|
|
1128
|
+
// frontmatter rules are part of the walk for a group as for a person.
|
|
1129
|
+
const owns = await Promise.all(relativePaths.map((p) => this.cachedOwnEntries(workspaceId, repoDir, p)));
|
|
1130
|
+
const result = new Map();
|
|
1131
|
+
relativePaths.forEach((p, i) => {
|
|
1132
|
+
result.set(p, hasPermissionForKeys(model, 'read', keys, p, owns[i]));
|
|
1133
|
+
});
|
|
1134
|
+
return result;
|
|
1135
|
+
}
|
|
1136
|
+
async canReadAsEveryoneBatch(workspaceId, relativePaths) {
|
|
1137
|
+
const model = await this.loadModel(workspaceId);
|
|
1138
|
+
const repoDir = await this.repoDir(workspaceId);
|
|
1139
|
+
const owns = await Promise.all(relativePaths.map((p) => this.cachedOwnEntries(workspaceId, repoDir, p)));
|
|
1140
|
+
const result = new Map();
|
|
1141
|
+
relativePaths.forEach((p, i) => {
|
|
1142
|
+
// No keys at all: the walk then falls through to each scope's derived
|
|
1143
|
+
// `everyone` verdict — the built-in entry, or a public plugin's grant
|
|
1144
|
+
// or denial, whichever the scope builder settled on — which is exactly
|
|
1145
|
+
// what a caller holding nothing of their own resolves to.
|
|
1146
|
+
result.set(p, hasPermissionForKeys(model, 'read', NO_KEYS, p, owns[i]));
|
|
1147
|
+
});
|
|
1148
|
+
return result;
|
|
1149
|
+
}
|
|
856
1150
|
async canWriteBatch(workspaceId, userEmail, relativePaths) {
|
|
857
1151
|
const model = await this.loadModel(workspaceId);
|
|
858
1152
|
const repoDir = await this.repoDir(workspaceId);
|
|
@@ -925,6 +1219,45 @@ export class AccessControlService {
|
|
|
925
1219
|
const own = await this.readOwnEntries(await this.repoDir(workspaceId), relativePath);
|
|
926
1220
|
return eligibleHoldersResolved(model, 'download', relativePath, own);
|
|
927
1221
|
}
|
|
1222
|
+
/**
|
|
1223
|
+
* The read and write holders of one file at its current path and at a path
|
|
1224
|
+
* it has not moved to yet (see the interface).
|
|
1225
|
+
*
|
|
1226
|
+
* A move changes nothing about the file's own frontmatter — that travels
|
|
1227
|
+
* with the bytes — and everything about the folder chain above it. So the
|
|
1228
|
+
* hypothetical side is the ordinary resolution with the destination path
|
|
1229
|
+
* substituted: the same model, the same own-entries (read from the SOURCE,
|
|
1230
|
+
* since nothing sits at the destination to read), resolved against the
|
|
1231
|
+
* destination's ancestors. One model load and one file read serve all four
|
|
1232
|
+
* lookups.
|
|
1233
|
+
*/
|
|
1234
|
+
async prospectiveHolders(workspaceId, fromPath, toPath) {
|
|
1235
|
+
const model = await this.loadModel(workspaceId);
|
|
1236
|
+
const repoDir = await this.repoDir(workspaceId);
|
|
1237
|
+
// A FILE question only. A folder carries its own `access.md` — which moves
|
|
1238
|
+
// with it and governs everything under it — so resolving it as a file
|
|
1239
|
+
// would read frontmatter it does not have and omit the rules it does,
|
|
1240
|
+
// naming principals that are not the ones a folder move changes. Refuse
|
|
1241
|
+
// rather than answer the wrong question convincingly.
|
|
1242
|
+
//
|
|
1243
|
+
// Only absence is an answer here (see `isAbsence`): a probe that failed on
|
|
1244
|
+
// permissions or I/O does not say "this is a file", and folding it into
|
|
1245
|
+
// one would let the very case above through on an unreadable source.
|
|
1246
|
+
const fromStat = await fs.stat(path.join(repoDir, fromPath)).catch((err) => {
|
|
1247
|
+
if (isAbsence(err))
|
|
1248
|
+
return null;
|
|
1249
|
+
throw err;
|
|
1250
|
+
});
|
|
1251
|
+
if (fromStat?.isDirectory()) {
|
|
1252
|
+
throw new WorkflowDomainError('prospective access answers for a file, not a folder', 400);
|
|
1253
|
+
}
|
|
1254
|
+
const own = await this.readOwnEntries(repoDir, fromPath);
|
|
1255
|
+
const holdersAt = (relativePath) => ({
|
|
1256
|
+
read: eligibleHoldersResolved(model, 'read', relativePath, own),
|
|
1257
|
+
write: eligibleHoldersResolved(model, 'write', relativePath, own),
|
|
1258
|
+
});
|
|
1259
|
+
return { before: holdersAt(fromPath), after: holdersAt(toPath) };
|
|
1260
|
+
}
|
|
928
1261
|
async eligibleWriterEmails(workspaceId, relativePath) {
|
|
929
1262
|
const model = await this.loadModel(workspaceId);
|
|
930
1263
|
const own = await this.readOwnEntries(await this.repoDir(workspaceId), relativePath);
|
|
@@ -951,6 +1284,85 @@ export class AccessControlService {
|
|
|
951
1284
|
}
|
|
952
1285
|
return out;
|
|
953
1286
|
}
|
|
1287
|
+
async denialSources(workspaceId, kind, relativePath, principal, opts) {
|
|
1288
|
+
const model = await this.loadModel(workspaceId);
|
|
1289
|
+
// Same own-scope rule as `grantSources`: a file target consults its own
|
|
1290
|
+
// frontmatter, a folder target's own access.md is already in the dir chain.
|
|
1291
|
+
const own = kind === 'file'
|
|
1292
|
+
? await this.readOwnEntries(await this.repoDir(workspaceId), relativePath)
|
|
1293
|
+
: null;
|
|
1294
|
+
const out = {};
|
|
1295
|
+
for (const verb of KNOWN_VERBS) {
|
|
1296
|
+
const sources = resolveDenialSourcesForVerb(model, verb, kind, relativePath, principal, own, opts?.tokenMatch);
|
|
1297
|
+
if (sources.length > 0)
|
|
1298
|
+
out[verb] = sources;
|
|
1299
|
+
}
|
|
1300
|
+
return out;
|
|
1301
|
+
}
|
|
1302
|
+
async locallyDeniedPrincipals(workspaceId, kind, relativePath) {
|
|
1303
|
+
const model = await this.loadModel(workspaceId);
|
|
1304
|
+
// The target's OWN entries, and only those — the one scope whose rules a
|
|
1305
|
+
// restriction made here is written into. A folder's are its `access.md` in
|
|
1306
|
+
// the dir model; a file node's are its own frontmatter.
|
|
1307
|
+
const own = kind === 'folder'
|
|
1308
|
+
? (model.accessFilesByDir.get(relativePath)?.entries ?? null)
|
|
1309
|
+
: await this.readOwnEntries(await this.repoDir(workspaceId), relativePath);
|
|
1310
|
+
if (!own)
|
|
1311
|
+
return { principals: [], users: [] };
|
|
1312
|
+
const byIdentity = new Map();
|
|
1313
|
+
const byEmail = new Map();
|
|
1314
|
+
for (const verb of KNOWN_VERBS) {
|
|
1315
|
+
for (const entry of own[verb] ?? []) {
|
|
1316
|
+
// Grants are already reported by the eligible lists; only the denials
|
|
1317
|
+
// are invisible there, and only they are this method's business.
|
|
1318
|
+
if (!entry.deny)
|
|
1319
|
+
continue;
|
|
1320
|
+
if (entry.kind === 'user') {
|
|
1321
|
+
if (!byEmail.has(entry.email)) {
|
|
1322
|
+
byEmail.set(entry.email, { name: entry.displayName, email: entry.email });
|
|
1323
|
+
}
|
|
1324
|
+
continue;
|
|
1325
|
+
}
|
|
1326
|
+
// A token naming a role nobody knows is not a rule: `loadModel` drops
|
|
1327
|
+
// such entries from every `access.md`, and `resolveScopes` filters them
|
|
1328
|
+
// out of a file's own frontmatter (the one scope it does not pre-filter)
|
|
1329
|
+
// — so the resolver denies nothing, `denialSources` reports nothing, and
|
|
1330
|
+
// a row here would claim a restriction the server does not enforce. Skip
|
|
1331
|
+
// it on the same rule, so this list and the denial sources agree.
|
|
1332
|
+
if (!roleKnown(model.roles, entry.role))
|
|
1333
|
+
continue;
|
|
1334
|
+
// Resolve the token's kind and display name through the SAME merged
|
|
1335
|
+
// index the eligible lists use, so a denied group keys as `g:` and a
|
|
1336
|
+
// denied role as `r:` — matching the row keys the view is built on. A
|
|
1337
|
+
// KNOWN token with no record is a built-in (`everyone`, `admin` before
|
|
1338
|
+
// roles.yaml names it), which displays as the role it is.
|
|
1339
|
+
const record = model.roles.byCanonical.get(entry.role);
|
|
1340
|
+
const name = record ? record.displayName : (entry.displayRole || entry.role);
|
|
1341
|
+
const kindOf = record?.kind ?? 'role';
|
|
1342
|
+
const key = `${kindOf}\0${name.toLowerCase()}`;
|
|
1343
|
+
if (!byIdentity.has(key))
|
|
1344
|
+
byIdentity.set(key, { name, kind: kindOf });
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
const principals = [...byIdentity.values()].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : a.kind < b.kind ? -1 : a.kind > b.kind ? 1 : 0);
|
|
1348
|
+
const users = [...byEmail.values()].sort((a, b) => a.email.localeCompare(b.email));
|
|
1349
|
+
return { principals, users };
|
|
1350
|
+
}
|
|
1351
|
+
async explainAccess(workspaceId, userEmail, kind, relativePath) {
|
|
1352
|
+
const model = await this.loadModel(workspaceId);
|
|
1353
|
+
// The same own-entries read `canRead`/`canWrite`/… make, whatever the
|
|
1354
|
+
// kind: a directory simply has none.
|
|
1355
|
+
const own = await this.readOwnEntries(await this.repoDir(workspaceId), relativePath);
|
|
1356
|
+
const out = {};
|
|
1357
|
+
for (const verb of KNOWN_VERBS) {
|
|
1358
|
+
const machineOwned = verb === 'write' ? this.machineOwnedWriteRule(userEmail, relativePath) : null;
|
|
1359
|
+
out[verb] =
|
|
1360
|
+
machineOwned !== null
|
|
1361
|
+
? { allowed: machineOwned, source: null, via: 'machine-owned', principal: null }
|
|
1362
|
+
: explainDecision(model, decidePermissionResolved(model, verb, userEmail, relativePath, own), kind, relativePath);
|
|
1363
|
+
}
|
|
1364
|
+
return out;
|
|
1365
|
+
}
|
|
954
1366
|
async kbPrincipals(workspaceId) {
|
|
955
1367
|
let model;
|
|
956
1368
|
try {
|
|
@@ -1043,7 +1455,7 @@ export class AccessControlService {
|
|
|
1043
1455
|
...namesByEmail.keys(),
|
|
1044
1456
|
]);
|
|
1045
1457
|
for (const email of candidates) {
|
|
1046
|
-
if (
|
|
1458
|
+
if (hashEmail(email) === hash) {
|
|
1047
1459
|
const displayName = namesByEmail.get(email) ?? email.split('@')[0];
|
|
1048
1460
|
return { email, displayName };
|
|
1049
1461
|
}
|
|
@@ -1062,7 +1474,7 @@ export class AccessControlService {
|
|
|
1062
1474
|
machineOwnedWriteRule(userEmail, relativePath) {
|
|
1063
1475
|
if (relativePath !== SYNCED_GROUPS_YAML)
|
|
1064
1476
|
return null;
|
|
1065
|
-
return userEmail
|
|
1477
|
+
return canonicalEmail(userEmail) === DIRECTORY_SYNC_BOT_EMAIL;
|
|
1066
1478
|
}
|
|
1067
1479
|
async canWriteAtRef(workspaceId, ref, userEmail, relativePath) {
|
|
1068
1480
|
const machineOwned = this.machineOwnedWriteRule(userEmail, relativePath);
|
|
@@ -1123,6 +1535,50 @@ export class AccessControlService {
|
|
|
1123
1535
|
const own = await this.readOwnEntriesAtRef(repoDir, loaded.resolvedRef, relativePath);
|
|
1124
1536
|
return eligibleHoldersResolved(loaded.model, 'write', relativePath, own);
|
|
1125
1537
|
}
|
|
1538
|
+
async holdsAdminRootWrite(workspaceId, userEmail) {
|
|
1539
|
+
const model = await this.loadModel(workspaceId);
|
|
1540
|
+
return isAdminEmail(model, canonicalEmail(userEmail));
|
|
1541
|
+
}
|
|
1542
|
+
async canRestorePlatformFile(workspaceId, userEmail, destinationRelativePath) {
|
|
1543
|
+
const target = platformRestoreDestination(destinationRelativePath);
|
|
1544
|
+
if (target === null)
|
|
1545
|
+
return false;
|
|
1546
|
+
const email = canonicalEmail(userEmail);
|
|
1547
|
+
let admin;
|
|
1548
|
+
try {
|
|
1549
|
+
admin = isAdminEmail(await this.loadModel(workspaceId), email);
|
|
1550
|
+
}
|
|
1551
|
+
catch {
|
|
1552
|
+
// The repository this rescue exists for is exactly the one whose
|
|
1553
|
+
// `roles.yaml` may be the file that went missing, and `loadModel`
|
|
1554
|
+
// throws when it cannot be read. With no model to ask, the deployment
|
|
1555
|
+
// owner is the only admin left — and they are the person who sets
|
|
1556
|
+
// `ADMIN_EMAIL`, so admitting them concedes nothing they did not have.
|
|
1557
|
+
admin = this.deploymentOwners.has(email);
|
|
1558
|
+
}
|
|
1559
|
+
if (!admin)
|
|
1560
|
+
return false;
|
|
1561
|
+
// A restore puts back what is MISSING, so the place it lands must be
|
|
1562
|
+
// empty. An `access.md` goes back only into a folder that has none —
|
|
1563
|
+
// into a folder that already has one it would not be a restore but a rule
|
|
1564
|
+
// change wearing a move's clothes, and the destination's own rules would
|
|
1565
|
+
// be the thing it bypassed the write gate to overwrite. The same holds at
|
|
1566
|
+
// the root: a move is a rename on disk, so landing `.bevelignore` on a
|
|
1567
|
+
// root that already has one would silently replace it, and the repository
|
|
1568
|
+
// was never missing that file to begin with.
|
|
1569
|
+
const destination = target.kind === 'root' ? target.name : path.join(target.dir, 'access.md');
|
|
1570
|
+
const repoDir = await this.repoDir(workspaceId);
|
|
1571
|
+
try {
|
|
1572
|
+
await fs.stat(path.join(repoDir, destination));
|
|
1573
|
+
return false;
|
|
1574
|
+
}
|
|
1575
|
+
catch (err) {
|
|
1576
|
+
if (isAbsence(err))
|
|
1577
|
+
return true;
|
|
1578
|
+
// Anything other than genuine absence is not an answer: fail closed.
|
|
1579
|
+
return false;
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1126
1582
|
async eligibleWritersForPathsAtRef(workspaceId, ref, relativePaths) {
|
|
1127
1583
|
const result = new Map();
|
|
1128
1584
|
// Machine-owned paths resolve without the model — same answer
|
|
@@ -1193,20 +1649,19 @@ export class AccessControlService {
|
|
|
1193
1649
|
return await fs.readFile(path.join(repoDir, filename), 'utf-8');
|
|
1194
1650
|
}
|
|
1195
1651
|
catch (err) {
|
|
1196
|
-
|
|
1197
|
-
if (code === 'ENOENT' || code === 'ENOTDIR')
|
|
1652
|
+
if (isAbsence(err))
|
|
1198
1653
|
return null;
|
|
1199
1654
|
throw err;
|
|
1200
1655
|
}
|
|
1201
1656
|
});
|
|
1202
1657
|
if (!activeGroups.health.ok) {
|
|
1203
|
-
|
|
1658
|
+
log.error(`groups source ${activeGroups.health.file} is broken (${activeGroups.health.reason}) — groups contribute nothing until it is fixed`);
|
|
1204
1659
|
}
|
|
1205
1660
|
for (const w of activeGroups.warnings)
|
|
1206
|
-
|
|
1661
|
+
log.warn(w);
|
|
1207
1662
|
const mergeWarnings = mergeGroupsIntoRoles(rolesParsed.index, activeGroups.groups, activeGroups.sourceFile);
|
|
1208
1663
|
for (const w of mergeWarnings)
|
|
1209
|
-
|
|
1664
|
+
log.warn(w);
|
|
1210
1665
|
const accessFiles = new Map();
|
|
1211
1666
|
// Walk the entire repo for `access.md` files. The access tree is
|
|
1212
1667
|
// structure-agnostic — any `access.md` at any depth (including repo
|
|
@@ -1222,7 +1677,7 @@ export class AccessControlService {
|
|
|
1222
1677
|
// / `roles.yaml` because `hasPermissionResolved` admin-rescues those
|
|
1223
1678
|
// paths, so the bad config remains fixable from inside the app.
|
|
1224
1679
|
const pluginDirs = new Map();
|
|
1225
|
-
await walkKb(repoDir, [accessFileListener(repoDir, accessFiles, pluginDirs)]);
|
|
1680
|
+
await this.disk.walkKb(repoDir, [accessFileListener(repoDir, accessFiles, pluginDirs)]);
|
|
1226
1681
|
// Plugin principals (`plugin/<Name>/<verb>`), derived from each plugin
|
|
1227
1682
|
// folder's own access.md — a plugin being a folder with a manifest, at
|
|
1228
1683
|
// any depth — after groups merged (so their rosters expand through the
|
|
@@ -1237,7 +1692,7 @@ export class AccessControlService {
|
|
|
1237
1692
|
for (const verb of KNOWN_VERBS) {
|
|
1238
1693
|
file.entries[verb] = file.entries[verb].filter((entry) => {
|
|
1239
1694
|
if (entry.kind === 'role' && !roleKnown(rolesParsed.index, entry.role)) {
|
|
1240
|
-
|
|
1695
|
+
log.warn(`${file.path}: '${verb}' references unknown role '${entry.displayRole}' — entry ignored`);
|
|
1241
1696
|
return false;
|
|
1242
1697
|
}
|
|
1243
1698
|
return true;
|
|
@@ -1318,7 +1773,7 @@ export class AccessControlService {
|
|
|
1318
1773
|
}
|
|
1319
1774
|
if (wanted.length === 0)
|
|
1320
1775
|
return result;
|
|
1321
|
-
const texts = await catFileBatch(repoDir, wanted.map((p) => `${ref}:${p}`));
|
|
1776
|
+
const texts = await catFileBatch(this.gitRunner, repoDir, wanted.map((p) => `${ref}:${p}`));
|
|
1322
1777
|
wanted.forEach((p, i) => {
|
|
1323
1778
|
const text = texts[i];
|
|
1324
1779
|
if (text === null)
|
|
@@ -1358,11 +1813,7 @@ export class AccessControlService {
|
|
|
1358
1813
|
*/
|
|
1359
1814
|
async showAtRefOutcome(repoDir, ref, relativePath) {
|
|
1360
1815
|
try {
|
|
1361
|
-
const { stdout } = await
|
|
1362
|
-
encoding: 'utf-8',
|
|
1363
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
1364
|
-
env: { ...process.env, LC_ALL: 'C', LANG: 'C' },
|
|
1365
|
-
});
|
|
1816
|
+
const { stdout } = await this.gitRunner.run(repoDir, ['show', `${ref}:${relativePath}`]);
|
|
1366
1817
|
return { kind: 'text', text: stdout };
|
|
1367
1818
|
}
|
|
1368
1819
|
catch (err) {
|
|
@@ -1381,7 +1832,7 @@ export class AccessControlService {
|
|
|
1381
1832
|
*/
|
|
1382
1833
|
async listAccessFilesAtRef(repoDir, ref) {
|
|
1383
1834
|
try {
|
|
1384
|
-
const { stdout } = await
|
|
1835
|
+
const { stdout } = await this.gitRunner.run(repoDir, ['ls-tree', '-r', '--name-only', ref]);
|
|
1385
1836
|
const out = [];
|
|
1386
1837
|
const pluginDirs = [];
|
|
1387
1838
|
for (const line of stdout.split('\n')) {
|
|
@@ -1470,11 +1921,21 @@ export class AccessControlService {
|
|
|
1470
1921
|
if (!ref || ref.startsWith('-'))
|
|
1471
1922
|
return null;
|
|
1472
1923
|
try {
|
|
1473
|
-
const { stdout } = await
|
|
1924
|
+
const { stdout } = await this.gitRunner.run(repoDir, [
|
|
1925
|
+
'rev-parse',
|
|
1926
|
+
'--verify',
|
|
1927
|
+
'--quiet',
|
|
1928
|
+
`${ref}^{commit}`,
|
|
1929
|
+
]);
|
|
1474
1930
|
const sha = stdout.trim();
|
|
1475
1931
|
return /^[0-9a-f]{40,64}$/.test(sha) ? sha : null;
|
|
1476
1932
|
}
|
|
1477
|
-
catch {
|
|
1933
|
+
catch (err) {
|
|
1934
|
+
// Null means "does not resolve". A deadline says nothing about the ref,
|
|
1935
|
+
// and as a null it would turn a stalled git into a gate that quietly
|
|
1936
|
+
// reads no roles at that ref; it surfaces instead, as a read failure.
|
|
1937
|
+
if (isGitTimeout(err))
|
|
1938
|
+
throw err;
|
|
1478
1939
|
return null;
|
|
1479
1940
|
}
|
|
1480
1941
|
}
|
|
@@ -1506,7 +1967,7 @@ export class AccessControlService {
|
|
|
1506
1967
|
if (outcome.kind === 'error') {
|
|
1507
1968
|
// The operational signal: one line per failed read, naming the commit
|
|
1508
1969
|
// and the path, so a run of these is visible in the logs.
|
|
1509
|
-
|
|
1970
|
+
logger(`access@${tag}`).warn(`git read of ${relativePath} failed; refusing to decide from a partial tree`);
|
|
1510
1971
|
throw new AccessUnreadableError(label, relativePath);
|
|
1511
1972
|
}
|
|
1512
1973
|
return outcome.kind === 'text' ? outcome.text : null;
|
|
@@ -1526,17 +1987,17 @@ export class AccessControlService {
|
|
|
1526
1987
|
// fires only on a file that was read and would not parse.
|
|
1527
1988
|
const activeGroups = await loadActiveGroups(read);
|
|
1528
1989
|
if (!activeGroups.health.ok) {
|
|
1529
|
-
|
|
1990
|
+
logger(`access@${tag}`).error(`groups source ${activeGroups.health.file} is broken (${activeGroups.health.reason}) — groups contribute nothing until it is fixed`);
|
|
1530
1991
|
}
|
|
1531
1992
|
for (const w of activeGroups.warnings)
|
|
1532
|
-
|
|
1993
|
+
logger(`access@${tag}`).warn(w);
|
|
1533
1994
|
const mergeWarnings = mergeGroupsIntoRoles(rolesParsed.index, activeGroups.groups, activeGroups.sourceFile);
|
|
1534
1995
|
for (const w of mergeWarnings)
|
|
1535
|
-
|
|
1996
|
+
logger(`access@${tag}`).warn(w);
|
|
1536
1997
|
const accessFiles = new Map();
|
|
1537
1998
|
const listed = await this.listAccessFilesAtRef(repoDir, commit);
|
|
1538
1999
|
if (listed === 'error') {
|
|
1539
|
-
|
|
2000
|
+
logger(`access@${tag}`).warn('listing access.md files failed; refusing to decide from a partial tree');
|
|
1540
2001
|
throw new AccessUnreadableError(label, 'access.md (ls-tree)');
|
|
1541
2002
|
}
|
|
1542
2003
|
for (const p of listed.accessFiles) {
|