@bevel-software/platform-core-backend 0.22.0 → 0.24.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/dist/core/core-ports.d.ts +11 -1
- package/dist/core/core-ports.d.ts.map +1 -1
- package/dist/core/core-ports.js.map +1 -1
- package/dist/core/create-core-server.d.ts +3 -3
- package/dist/core/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +46 -13
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +12 -2
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +137 -24
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/core/lifecycle.d.ts +46 -1
- package/dist/core/lifecycle.d.ts.map +1 -1
- package/dist/core/lifecycle.js +99 -13
- package/dist/core/lifecycle.js.map +1 -1
- package/dist/core-config.d.ts +16 -12
- package/dist/core-config.d.ts.map +1 -1
- package/dist/core-config.js +28 -13
- package/dist/core-config.js.map +1 -1
- package/dist/index.d.ts +6 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -3
- package/dist/index.js.map +1 -1
- package/dist/modules/access/access-control.interface.d.ts +42 -12
- package/dist/modules/access/access-control.interface.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.d.ts +67 -10
- package/dist/modules/access/access-control.service.d.ts.map +1 -1
- package/dist/modules/access/access-control.service.js +214 -35
- package/dist/modules/access/access-control.service.js.map +1 -1
- package/dist/modules/access/access.routes.d.ts.map +1 -1
- package/dist/modules/access/access.routes.js +17 -16
- package/dist/modules/access/access.routes.js.map +1 -1
- package/dist/modules/access/directory-sync-bot.d.ts.map +1 -1
- package/dist/modules/access/directory-sync-bot.js +7 -3
- package/dist/modules/access/directory-sync-bot.js.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts +8 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.d.ts.map +1 -1
- package/dist/modules/agent-instructions/agent-instructions.routes.js +8 -2
- package/dist/modules/agent-instructions/agent-instructions.routes.js.map +1 -1
- package/dist/modules/agent-instructions/compose.d.ts +38 -6
- package/dist/modules/agent-instructions/compose.d.ts.map +1 -1
- package/dist/modules/agent-instructions/compose.js +39 -6
- package/dist/modules/agent-instructions/compose.js.map +1 -1
- package/dist/modules/agent-instructions/index.d.ts +2 -1
- package/dist/modules/agent-instructions/index.d.ts.map +1 -1
- package/dist/modules/agent-instructions/index.js +2 -1
- package/dist/modules/agent-instructions/index.js.map +1 -1
- package/dist/modules/agent-instructions/shared-file-rules.d.ts +115 -0
- package/dist/modules/agent-instructions/shared-file-rules.d.ts.map +1 -0
- package/dist/modules/agent-instructions/shared-file-rules.js +272 -0
- package/dist/modules/agent-instructions/shared-file-rules.js.map +1 -0
- package/dist/modules/audit/agent-audit.service.d.ts.map +1 -1
- package/dist/modules/audit/agent-audit.service.js +4 -2
- package/dist/modules/audit/agent-audit.service.js.map +1 -1
- package/dist/modules/auth/account-admission.d.ts +58 -7
- package/dist/modules/auth/account-admission.d.ts.map +1 -1
- package/dist/modules/auth/account-admission.js +44 -1
- package/dist/modules/auth/account-admission.js.map +1 -1
- package/dist/modules/auth/account-erasure.service.d.ts.map +1 -1
- package/dist/modules/auth/account-erasure.service.js +57 -16
- package/dist/modules/auth/account-erasure.service.js.map +1 -1
- package/dist/modules/auth/account.routes.d.ts +1 -1
- package/dist/modules/auth/account.routes.d.ts.map +1 -1
- package/dist/modules/auth/account.routes.js +61 -5
- package/dist/modules/auth/account.routes.js.map +1 -1
- package/dist/modules/auth/auth.middleware.d.ts +1 -1
- package/dist/modules/auth/auth.middleware.d.ts.map +1 -1
- package/dist/modules/auth/auth.middleware.js +18 -7
- package/dist/modules/auth/auth.middleware.js.map +1 -1
- package/dist/modules/auth/auth.routes.d.ts.map +1 -1
- package/dist/modules/auth/auth.routes.js +8 -0
- package/dist/modules/auth/auth.routes.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +70 -2
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +197 -18
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.d.ts.map +1 -1
- package/dist/modules/auth/oidc-auth-provider.js +7 -2
- package/dist/modules/auth/oidc-auth-provider.js.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.d.ts +20 -2
- package/dist/modules/code-mode/code-mode.tool.d.ts.map +1 -1
- package/dist/modules/code-mode/code-mode.tool.js +66 -35
- package/dist/modules/code-mode/code-mode.tool.js.map +1 -1
- package/dist/modules/database/connection.d.ts +16 -0
- package/dist/modules/database/connection.d.ts.map +1 -1
- package/dist/modules/database/connection.js +117 -0
- package/dist/modules/database/connection.js.map +1 -1
- package/dist/modules/database/core-schema.d.ts +337 -120
- package/dist/modules/database/core-schema.d.ts.map +1 -1
- package/dist/modules/database/core-schema.js +116 -58
- package/dist/modules/database/core-schema.js.map +1 -1
- package/dist/modules/database/migrate.d.ts +8 -0
- package/dist/modules/database/migrate.d.ts.map +1 -1
- package/dist/modules/database/migrate.js +271 -1
- package/dist/modules/database/migrate.js.map +1 -1
- package/dist/modules/kb-fs/branch-name.d.ts.map +1 -1
- package/dist/modules/kb-fs/branch-name.js +12 -2
- package/dist/modules/kb-fs/branch-name.js.map +1 -1
- package/dist/modules/kb-fs/repo-path.d.ts +11 -16
- package/dist/modules/kb-fs/repo-path.d.ts.map +1 -1
- package/dist/modules/kb-fs/repo-path.js +79 -0
- package/dist/modules/kb-fs/repo-path.js.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.d.ts +2 -2
- package/dist/modules/kb-sync/kb-sync.routes.d.ts.map +1 -1
- package/dist/modules/kb-sync/kb-sync.routes.js +14 -3
- package/dist/modules/kb-sync/kb-sync.routes.js.map +1 -1
- package/dist/modules/kb-sync/sync-auth.d.ts +3 -1
- package/dist/modules/kb-sync/sync-auth.d.ts.map +1 -1
- package/dist/modules/kb-sync/sync-auth.js +1 -1
- package/dist/modules/kb-sync/sync-auth.js.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.d.ts.map +1 -1
- package/dist/modules/mcp/mcp-auth.middleware.js +21 -6
- package/dist/modules/mcp/mcp-auth.middleware.js.map +1 -1
- package/dist/modules/mcp/mcp.service.d.ts +8 -0
- package/dist/modules/mcp/mcp.service.d.ts.map +1 -1
- package/dist/modules/mcp/mcp.service.js +38 -8
- package/dist/modules/mcp/mcp.service.js.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.d.ts.map +1 -1
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js +3 -2
- package/dist/modules/mcp/oauth/bevel-oauth-provider.js.map +1 -1
- package/dist/modules/plugins/join-request-records.store.d.ts.map +1 -1
- package/dist/modules/plugins/join-request-records.store.js +7 -4
- package/dist/modules/plugins/join-request-records.store.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +8 -3
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/setup.routes.d.ts +52 -1
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +207 -19
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/skills.contract.d.ts +90 -18
- package/dist/modules/skills/skills.contract.d.ts.map +1 -1
- package/dist/modules/skills/skills.contract.js +4 -1
- package/dist/modules/skills/skills.contract.js.map +1 -1
- package/dist/modules/skills/skills.service.d.ts +98 -9
- package/dist/modules/skills/skills.service.d.ts.map +1 -1
- package/dist/modules/skills/skills.service.js +239 -37
- package/dist/modules/skills/skills.service.js.map +1 -1
- package/dist/modules/skills/skills.tools.d.ts +7 -0
- package/dist/modules/skills/skills.tools.d.ts.map +1 -1
- package/dist/modules/skills/skills.tools.js +71 -7
- package/dist/modules/skills/skills.tools.js.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.d.ts.map +1 -1
- package/dist/modules/tool-auth/external-api-key.service.js +12 -4
- package/dist/modules/tool-auth/external-api-key.service.js.map +1 -1
- package/dist/modules/tool-auth/internal-token.service.d.ts +3 -3
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts +16 -7
- package/dist/modules/tool-auth/tool-auth.middleware.d.ts.map +1 -1
- package/dist/modules/tool-auth/tool-auth.middleware.js +34 -12
- package/dist/modules/tool-auth/tool-auth.middleware.js.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts +2 -1
- package/dist/modules/tool-helpers/tool-handler.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-handler.js +25 -4
- package/dist/modules/tool-helpers/tool-handler.js.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.d.ts +3 -2
- package/dist/modules/tool-helpers/tool.contract.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool.contract.js.map +1 -1
- package/dist/modules/tool-helpers/validate-token.js +1 -1
- package/dist/modules/tool-helpers/validate-token.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 +42 -31
- package/dist/modules/tool-manuals/tool-manuals.tools.js.map +1 -1
- package/dist/modules/tool-registry/description-length.d.ts +80 -0
- package/dist/modules/tool-registry/description-length.d.ts.map +1 -0
- package/dist/modules/tool-registry/description-length.js +108 -0
- package/dist/modules/tool-registry/description-length.js.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts +98 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.d.ts.map +1 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.js +81 -0
- package/dist/modules/workflow/agent-tools/change-request-summary.js.map +1 -0
- package/dist/modules/workflow/agent-tools/workflow.tools.d.ts.map +1 -1
- package/dist/modules/workflow/agent-tools/workflow.tools.js +75 -35
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/file-lock.service.d.ts +24 -0
- package/dist/modules/workflow/file-lock.service.d.ts.map +1 -1
- package/dist/modules/workflow/file-lock.service.js +30 -0
- package/dist/modules/workflow/file-lock.service.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +94 -0
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +193 -3
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/pending-commits.service.d.ts +38 -0
- package/dist/modules/workflow/pending-commits.service.d.ts.map +1 -1
- package/dist/modules/workflow/pending-commits.service.js +60 -1
- package/dist/modules/workflow/pending-commits.service.js.map +1 -1
- package/dist/modules/workflow/recovery-bot.d.ts.map +1 -1
- package/dist/modules/workflow/recovery-bot.js +7 -3
- package/dist/modules/workflow/recovery-bot.js.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/review-workflow/review-workflow.service.js +12 -3
- package/dist/modules/workflow/review-workflow/review-workflow.service.js.map +1 -1
- package/dist/modules/workflow/workflow-hooks.d.ts +54 -32
- package/dist/modules/workflow/workflow-hooks.d.ts.map +1 -1
- package/dist/modules/workflow/workflow-hooks.js +16 -1
- package/dist/modules/workflow/workflow-hooks.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +60 -6
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +115 -5
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/agent-access.gate.d.ts +94 -0
- package/dist/modules/workspace/agent-access.gate.d.ts.map +1 -0
- package/dist/modules/workspace/agent-access.gate.js +123 -0
- package/dist/modules/workspace/agent-access.gate.js.map +1 -0
- package/dist/modules/workspace/agent-upload.routes.d.ts +77 -0
- package/dist/modules/workspace/agent-upload.routes.d.ts.map +1 -0
- package/dist/modules/workspace/agent-upload.routes.js +210 -0
- package/dist/modules/workspace/agent-upload.routes.js.map +1 -0
- package/dist/modules/workspace/agent-upload.store.d.ts +284 -0
- package/dist/modules/workspace/agent-upload.store.d.ts.map +1 -0
- package/dist/modules/workspace/agent-upload.store.js +553 -0
- package/dist/modules/workspace/agent-upload.store.js.map +1 -0
- package/dist/modules/workspace/routine-write-policy.d.ts +5 -6
- package/dist/modules/workspace/routine-write-policy.d.ts.map +1 -1
- package/dist/modules/workspace/routine-write-policy.js +5 -6
- package/dist/modules/workspace/routine-write-policy.js.map +1 -1
- package/dist/modules/workspace/session-sink.d.ts +5 -5
- package/dist/modules/workspace/set-aside-clone.d.ts +46 -0
- package/dist/modules/workspace/set-aside-clone.d.ts.map +1 -0
- package/dist/modules/workspace/set-aside-clone.js +92 -0
- package/dist/modules/workspace/set-aside-clone.js.map +1 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +59 -9
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +65 -24
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/seed-tree.js +3 -3
- package/dist/modules/workspace/startup/steps/seed-tree.js.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.d.ts +40 -0
- package/dist/modules/workspace/startup/steps/template-source.d.ts.map +1 -1
- package/dist/modules/workspace/startup/steps/template-source.js +46 -4
- package/dist/modules/workspace/startup/steps/template-source.js.map +1 -1
- package/dist/modules/workspace/upload-limits.d.ts +13 -0
- package/dist/modules/workspace/upload-limits.d.ts.map +1 -0
- package/dist/modules/workspace/upload-limits.js +13 -0
- package/dist/modules/workspace/upload-limits.js.map +1 -0
- package/dist/modules/workspace/workspace.routes.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.routes.js +93 -4
- package/dist/modules/workspace/workspace.routes.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts +128 -5
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +316 -58
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts +13 -11
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +791 -198
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/modules/workspace/write-denial.d.ts +0 -6
- package/dist/modules/workspace/write-denial.d.ts.map +1 -1
- package/dist/modules/workspace/write-denial.js +0 -6
- package/dist/modules/workspace/write-denial.js.map +1 -1
- package/dist/modules/workspace/zip-entry-rules.d.ts +114 -0
- package/dist/modules/workspace/zip-entry-rules.d.ts.map +1 -0
- package/dist/modules/workspace/zip-entry-rules.js +154 -0
- package/dist/modules/workspace/zip-entry-rules.js.map +1 -0
- package/dist/modules/write-access/write-access.d.ts +60 -0
- package/dist/modules/write-access/write-access.d.ts.map +1 -0
- package/dist/modules/write-access/write-access.js +129 -0
- package/dist/modules/write-access/write-access.js.map +1 -0
- package/dist/shared/column-crypto.d.ts +194 -0
- package/dist/shared/column-crypto.d.ts.map +1 -0
- package/dist/shared/column-crypto.js +144 -0
- package/dist/shared/column-crypto.js.map +1 -0
- package/dist/shared/domain-errors.d.ts +25 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +28 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/git.contract.d.ts +20 -0
- package/dist/shared/git.contract.d.ts.map +1 -1
- package/dist/shared/git.contract.js +26 -0
- package/dist/shared/git.contract.js.map +1 -1
- package/dist/shared/token-crypto.d.ts.map +1 -1
- package/dist/shared/token-crypto.js +25 -1
- package/dist/shared/token-crypto.js.map +1 -1
- package/dist/tenancy/static-tenant-source.d.ts +0 -1
- package/dist/tenancy/static-tenant-source.d.ts.map +1 -1
- package/dist/tenancy/static-tenant-source.js +1 -2
- package/dist/tenancy/static-tenant-source.js.map +1 -1
- package/dist/tenancy/tenant-secrets.d.ts +5 -1
- package/dist/tenancy/tenant-secrets.d.ts.map +1 -1
- package/dist/tenancy/tenant-secrets.js +4 -0
- package/dist/tenancy/tenant-secrets.js.map +1 -1
- package/kb-template/AGENTS.md +2 -0
- package/migrations/0014_change_request_closed_reason.sql +1 -0
- package/migrations/0015_account_deactivation.sql +3 -0
- package/migrations/0016_pii_encryption.sql +20 -0
- package/migrations/meta/0014_snapshot.json +2265 -0
- package/migrations/meta/0015_snapshot.json +2271 -0
- package/migrations/meta/0016_snapshot.json +2327 -0
- package/migrations/meta/_journal.json +21 -0
- package/package.json +3 -3
- package/src/__tests__/kb-layout-config.test.ts +0 -2
- package/src/__tests__/retired-settings.test.ts +96 -0
- package/src/core/__tests__/gated-boot.test.ts +132 -0
- package/src/core/__tests__/lifecycle.test.ts +241 -5
- package/src/core/__tests__/set-aside-root-is-one-place.test.ts +63 -0
- package/src/core/core-ports.ts +11 -1
- package/src/core/create-core-server.ts +52 -16
- package/src/core/create-core-services.ts +156 -24
- package/src/core/lifecycle.ts +117 -13
- package/src/core-config.ts +31 -14
- package/src/index.ts +30 -1
- package/src/modules/access/__tests__/access-control.preview-relocation.test.ts +385 -0
- package/src/modules/access/__tests__/access-control.prospective.test.ts +94 -18
- package/src/modules/access/__tests__/access.routes.prospective.test.ts +6 -7
- package/src/modules/access/__tests__/users-db-double.ts +21 -12
- package/src/modules/access/access-control.interface.ts +43 -12
- package/src/modules/access/access-control.service.ts +234 -36
- package/src/modules/access/access.routes.ts +17 -16
- package/src/modules/access/directory-sync-bot.ts +7 -3
- package/src/modules/agent-instructions/__tests__/agent-instructions.route.test.ts +11 -5
- package/src/modules/agent-instructions/__tests__/compose.test.ts +19 -10
- package/src/modules/agent-instructions/__tests__/shared-file-rules.test.ts +238 -0
- package/src/modules/agent-instructions/agent-instructions.routes.ts +12 -2
- package/src/modules/agent-instructions/compose.ts +50 -7
- package/src/modules/agent-instructions/index.ts +12 -0
- package/src/modules/agent-instructions/shared-file-rules.ts +314 -0
- package/src/modules/audit/agent-audit.service.ts +4 -2
- package/src/modules/auth/__tests__/account-deactivation.test.ts +253 -0
- package/src/modules/auth/__tests__/account-erasure.approval-gate.test.ts +6 -2
- package/src/modules/auth/__tests__/account.routes.test.ts +87 -6
- package/src/modules/auth/__tests__/auth.middleware.test.ts +45 -22
- package/src/modules/auth/__tests__/auth.service.test.ts +4 -2
- package/src/modules/auth/account-admission.ts +78 -9
- package/src/modules/auth/account-erasure.service.ts +69 -18
- package/src/modules/auth/account.routes.ts +63 -7
- package/src/modules/auth/auth.middleware.ts +19 -8
- package/src/modules/auth/auth.routes.ts +8 -0
- package/src/modules/auth/auth.service.ts +206 -23
- package/src/modules/auth/oidc-auth-provider.ts +7 -2
- package/src/modules/code-mode/__tests__/chain-runtime.e2e.test.ts +335 -0
- package/src/modules/code-mode/__tests__/code-mode.tool.test.ts +46 -2
- package/src/modules/code-mode/code-mode.tool.ts +80 -34
- package/src/modules/database/__tests__/connection.test.ts +12 -0
- package/src/modules/database/__tests__/pii-backfill.pg.test.ts +561 -0
- package/src/modules/database/connection.ts +117 -0
- package/src/modules/database/core-schema.ts +116 -58
- package/src/modules/database/migrate.ts +353 -1
- package/src/modules/kb-fs/__tests__/branch-name.test.ts +10 -0
- package/src/modules/kb-fs/__tests__/repo-path.test.ts +123 -0
- package/src/modules/kb-fs/branch-name.ts +14 -1
- package/src/modules/kb-fs/repo-path.ts +85 -0
- package/src/modules/kb-sync/__tests__/kb-sync.routes.test.ts +26 -1
- package/src/modules/kb-sync/kb-sync.routes.ts +14 -4
- package/src/modules/kb-sync/sync-auth.ts +2 -2
- package/src/modules/mcp/__tests__/mcp-auth.middleware.test.ts +60 -3
- package/src/modules/mcp/__tests__/mcp.e2e.test.ts +4 -3
- package/src/modules/mcp/__tests__/mcp.service.test.ts +115 -13
- package/src/modules/mcp/mcp-auth.middleware.ts +20 -6
- package/src/modules/mcp/mcp.service.ts +46 -7
- package/src/modules/mcp/oauth/bevel-oauth-provider.ts +3 -1
- package/src/modules/plugins/__tests__/plugins.tools.test.ts +2 -1
- package/src/modules/plugins/join-request-records.store.ts +7 -4
- package/src/modules/settings/__tests__/deployment-settings.service.test.ts +16 -0
- package/src/modules/settings/__tests__/setup.routes.git-mode.test.ts +91 -58
- package/src/modules/settings/__tests__/setup.routes.github-app.test.ts +25 -8
- package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +14 -11
- package/src/modules/settings/__tests__/setup.routes.repository-change.test.ts +390 -0
- package/src/modules/settings/__tests__/setup.routes.test.ts +3 -0
- package/src/modules/settings/deployment-settings.service.ts +8 -3
- package/src/modules/settings/setup.routes.ts +263 -19
- package/src/modules/skills/__tests__/allowed-tools-warn.tools.test.ts +2 -1
- package/src/modules/skills/__tests__/branch-skills.tools.test.ts +218 -0
- package/src/modules/skills/__tests__/skills.service.test.ts +229 -5
- package/src/modules/skills/skills.contract.ts +91 -18
- package/src/modules/skills/skills.service.ts +278 -41
- package/src/modules/skills/skills.tools.ts +80 -8
- package/src/modules/tool-auth/__tests__/manual-auth.middleware.test.ts +14 -1
- package/src/modules/tool-auth/external-api-key.service.ts +12 -4
- package/src/modules/tool-auth/internal-token.service.ts +3 -3
- package/src/modules/tool-auth/tool-auth.middleware.ts +34 -11
- package/src/modules/tool-helpers/__tests__/agent-roles-write.test.ts +5 -3
- package/src/modules/tool-helpers/__tests__/phase4-tools.test.ts +3 -3
- package/src/modules/tool-helpers/__tests__/validate-token.test.ts +11 -1
- package/src/modules/tool-helpers/tool-handler.ts +24 -4
- package/src/modules/tool-helpers/tool.contract.ts +3 -2
- package/src/modules/tool-helpers/validate-token.ts +1 -1
- package/src/modules/tool-manuals/tool-manuals.tools.ts +44 -31
- package/src/modules/tool-registry/__tests__/tool-description-length.test.ts +378 -0
- package/src/modules/tool-registry/description-length.ts +111 -0
- package/src/modules/workflow/__tests__/pending-commits.repository-replaced.test.ts +111 -0
- package/src/modules/workflow/__tests__/workflow.routes.history-read-gate.test.ts +25 -0
- package/src/modules/workflow/__tests__/workflow.service.repository-replaced.test.ts +249 -0
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +264 -6
- package/src/modules/workflow/agent-tools/change-request-summary.ts +182 -0
- package/src/modules/workflow/agent-tools/workflow.tools.ts +86 -35
- package/src/modules/workflow/file-lock.service.ts +31 -0
- package/src/modules/workflow/git/__tests__/git.service.fileBytesAtCommit.test.ts +260 -0
- package/src/modules/workflow/git/__tests__/git.service.prFetchFailure.test.ts +170 -0
- package/src/modules/workflow/git/git.service.ts +215 -1
- package/src/modules/workflow/pending-commits.service.ts +64 -2
- package/src/modules/workflow/recovery-bot.ts +7 -3
- package/src/modules/workflow/review-workflow/__tests__/carry-approvals-forward.test.ts +4 -0
- package/src/modules/workflow/review-workflow/__tests__/erase-approver.test.ts +25 -3
- package/src/modules/workflow/review-workflow/review-workflow.service.ts +12 -3
- package/src/modules/workflow/workflow-hooks.ts +64 -26
- package/src/modules/workflow/workflow.service.ts +125 -5
- package/src/modules/workspace/__tests__/agent-access.gate.test.ts +208 -0
- package/src/modules/workspace/__tests__/agent-uploads.test.ts +1604 -0
- package/src/modules/workspace/__tests__/escape-sequences.routes.test.ts +394 -0
- package/src/modules/workspace/__tests__/file-stat-access.test.ts +2 -1
- package/src/modules/workspace/__tests__/git-internals.security.test.ts +2 -1
- package/src/modules/workspace/__tests__/set-aside-clone.test.ts +52 -0
- package/src/modules/workspace/__tests__/workspace.routes.at-ref.test.ts +305 -0
- package/src/modules/workspace/__tests__/workspace.routes.download.test.ts +2 -0
- package/src/modules/workspace/__tests__/workspace.service.any-workspace-credentials.test.ts +156 -0
- package/src/modules/workspace/__tests__/workspace.service.forget-clone-races.test.ts +147 -0
- package/src/modules/workspace/__tests__/workspace.service.replaced-repository.test.ts +402 -0
- package/src/modules/workspace/__tests__/workspace.service.test.ts +77 -9
- package/src/modules/workspace/__tests__/workspace.tools.agents-file.test.ts +41 -39
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +2 -3
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +766 -56
- package/src/modules/workspace/agent-access.gate.ts +164 -0
- package/src/modules/workspace/agent-upload.routes.ts +214 -0
- package/src/modules/workspace/agent-upload.store.ts +668 -0
- package/src/modules/workspace/routine-write-policy.ts +5 -6
- package/src/modules/workspace/session-sink.ts +5 -5
- package/src/modules/workspace/set-aside-clone.ts +96 -0
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +86 -0
- package/src/modules/workspace/startup/kb-startup-runner.ts +115 -34
- package/src/modules/workspace/startup/steps/__tests__/steps.test.ts +9 -9
- package/src/modules/workspace/startup/steps/seed-tree.ts +3 -6
- package/src/modules/workspace/startup/steps/template-source.ts +53 -5
- package/src/modules/workspace/upload-limits.ts +12 -0
- package/src/modules/workspace/workspace.routes.ts +96 -5
- package/src/modules/workspace/workspace.service.ts +319 -61
- package/src/modules/workspace/workspace.tools.ts +894 -214
- package/src/modules/workspace/write-denial.ts +0 -8
- package/src/modules/workspace/zip-entry-rules.ts +173 -0
- package/src/modules/write-access/__tests__/write-access.test.ts +248 -0
- package/src/modules/write-access/write-access.ts +153 -0
- package/src/shared/__tests__/column-crypto.test.ts +217 -0
- package/src/shared/column-crypto.ts +218 -0
- package/src/shared/domain-errors.ts +31 -0
- package/src/shared/git.contract.ts +27 -0
- package/src/shared/token-crypto.ts +28 -1
- package/src/tenancy/__tests__/static-tenant-source.test.ts +4 -1
- package/src/tenancy/static-tenant-source.ts +1 -3
- package/src/tenancy/tenant-secrets.ts +5 -1
- package/dist/modules/workflow/session-ontology.policy.d.ts +0 -52
- package/dist/modules/workflow/session-ontology.policy.d.ts.map +0 -1
- package/dist/modules/workflow/session-ontology.policy.js +0 -62
- package/dist/modules/workflow/session-ontology.policy.js.map +0 -1
- package/dist/modules/workflow/session-ontology.service.d.ts +0 -105
- package/dist/modules/workflow/session-ontology.service.d.ts.map +0 -1
- package/dist/modules/workflow/session-ontology.service.js +0 -147
- package/dist/modules/workflow/session-ontology.service.js.map +0 -1
- package/dist/modules/workspace/session-ontology.gate.d.ts +0 -114
- package/dist/modules/workspace/session-ontology.gate.d.ts.map +0 -1
- package/dist/modules/workspace/session-ontology.gate.js +0 -161
- package/dist/modules/workspace/session-ontology.gate.js.map +0 -1
- package/dist/shared/kb-layout.d.ts +0 -39
- package/dist/shared/kb-layout.d.ts.map +0 -1
- package/dist/shared/kb-layout.js +0 -103
- package/dist/shared/kb-layout.js.map +0 -1
- package/dist/shared/kb-layout.test.d.ts +0 -2
- package/dist/shared/kb-layout.test.d.ts.map +0 -1
- package/dist/shared/kb-layout.test.js +0 -75
- package/dist/shared/kb-layout.test.js.map +0 -1
- package/src/modules/workflow/__tests__/session-ontology.policy.test.ts +0 -62
- package/src/modules/workflow/__tests__/session-ontology.service.test.ts +0 -201
- package/src/modules/workflow/session-ontology.policy.ts +0 -70
- package/src/modules/workflow/session-ontology.service.ts +0 -183
- package/src/modules/workspace/__tests__/session-ontology.gate.test.ts +0 -239
- package/src/modules/workspace/session-ontology.gate.ts +0 -191
- package/src/shared/kb-layout.test.ts +0 -98
- package/src/shared/kb-layout.ts +0 -102
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { migrate } from 'drizzle-orm/node-postgres/migrator';
|
|
2
|
+
import { sql } from 'drizzle-orm';
|
|
2
3
|
import { logger } from '../../shared/logging.js';
|
|
3
4
|
const log = logger('database');
|
|
4
|
-
import { DEFAULT_DB_SCHEMA, dbSchemaOf } from './connection.js';
|
|
5
|
+
import { DEFAULT_DB_SCHEMA, dbSchemaOf, piiKeysOf } from './connection.js';
|
|
5
6
|
import { AdvisoryLock, withAdvisoryLock } from './advisory-lock.js';
|
|
7
|
+
import { PII_SEALED_SHAPE_SQL_REGEX, isEncryptedBlob } from '../../shared/column-crypto.js';
|
|
6
8
|
/*
|
|
7
9
|
* ── Per-tier migration folders ──────────────────────────────────────────────
|
|
8
10
|
*
|
|
@@ -62,6 +64,9 @@ export async function runCoreMigrations(db, folder) {
|
|
|
62
64
|
log.info('Running core database migrations...');
|
|
63
65
|
await migrate(db, { migrationsFolder: folder, migrationsTable: '__drizzle_migrations_core', migrationsSchema });
|
|
64
66
|
log.info('Core migrations complete.');
|
|
67
|
+
// Under the same lock, before anything reads or writes a PII column:
|
|
68
|
+
// the data half of migration 0016, which SQL cannot do (see below).
|
|
69
|
+
await runPiiEncryptionBackfill(db);
|
|
65
70
|
}, { tenantKey });
|
|
66
71
|
}
|
|
67
72
|
/**
|
|
@@ -81,4 +86,269 @@ export async function runEnterpriseMigrations(db, folder) {
|
|
|
81
86
|
log.info('Enterprise migrations complete.');
|
|
82
87
|
}, { tenantKey });
|
|
83
88
|
}
|
|
89
|
+
const PII_BACKFILL_TABLES = [
|
|
90
|
+
{ table: 'users', key: ['id'], encrypted: ['email', 'name', 'avatar_url'], bidx: { source: 'email', column: 'email_bidx' } },
|
|
91
|
+
{ table: 'pr_file_approvals', key: ['id'], encrypted: ['approver_email', 'approver_name'], bidx: { source: 'approver_email', column: 'approver_email_bidx' } },
|
|
92
|
+
{ table: 'pr_merge_log', key: ['id'], encrypted: ['triggered_by_email', 'triggered_by_name', 'error'], bidx: { source: 'triggered_by_email', column: 'triggered_by_email_bidx' } },
|
|
93
|
+
{ table: 'pr_comments', key: ['id'], encrypted: ['author_email', 'author_name', 'body'], bidx: { source: 'author_email', column: 'author_email_bidx' } },
|
|
94
|
+
{ table: 'change_requests', key: ['id'], encrypted: ['author_email', 'author_name', 'title', 'body', 'apply_failure_reason', 'apply_failed_by_name'], bidx: { source: 'author_email', column: 'author_email_bidx' } },
|
|
95
|
+
{ table: 'pending_commits', key: ['id'], encrypted: ['author_email', 'author_name', 'last_error'], bidx: { source: 'author_email', column: 'author_email_bidx' } },
|
|
96
|
+
{ table: 'file_locks', key: ['workspace_id', 'branch', 'path'], encrypted: ['holder_name'] },
|
|
97
|
+
{ table: 'plugin_join_requests', key: ['id'], encrypted: ['requester_email', 'requester_name', 'failure_reason'], bidx: { source: 'requester_email', column: 'requester_email_bidx' } },
|
|
98
|
+
];
|
|
99
|
+
const ident = (name) => sql.raw(`"${name}"`);
|
|
100
|
+
/** A text column as it is stored: bytes, so the handle's connection does not open it. */
|
|
101
|
+
const asStored = (col) => sql `convert_to(${ident(col)}, 'UTF8') AS ${ident(col)}`;
|
|
102
|
+
/** What {@link asStored} selected, back as text; anything else as it came. */
|
|
103
|
+
const storedText = (value) => (Buffer.isBuffer(value) ? value.toString('utf8') : value);
|
|
104
|
+
/**
|
|
105
|
+
* A column "needs sealing" when it holds non-empty text that isn't a blob.
|
|
106
|
+
* The shape regex is deliberately used as a NEGATIVE filter: anything failing
|
|
107
|
+
* it — including plaintext that merely BEGINS with the prefix — is selected
|
|
108
|
+
* and sealed, and `isEncryptedBlob` is the same pattern, so the two can never
|
|
109
|
+
* disagree about a value. Sealed rows all match, keeping the steady-state scan
|
|
110
|
+
* an empty-result query.
|
|
111
|
+
*
|
|
112
|
+
* `trustShape` is false on the FIRST backfill of a database (see
|
|
113
|
+
* {@link isFirstBackfill}): nothing has been sealed yet, so a value in this
|
|
114
|
+
* shape is plaintext somebody typed, and every non-empty value is selected.
|
|
115
|
+
*/
|
|
116
|
+
function needsSealing(col, trustShape) {
|
|
117
|
+
if (!trustShape)
|
|
118
|
+
return sql `(${ident(col)} IS NOT NULL AND ${ident(col)} <> '')`;
|
|
119
|
+
return sql `(${ident(col)} IS NOT NULL AND ${ident(col)} <> '' AND ${ident(col)} !~ ${PII_SEALED_SHAPE_SQL_REGEX})`;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Whether this database has never been through the backfill: the blind-index
|
|
123
|
+
* column of `users` is still nullable. The backfill, the duplicate collapse
|
|
124
|
+
* and the constraints run in ONE transaction, so a nullable column means no
|
|
125
|
+
* backfill has ever committed here — and therefore that nothing in it is
|
|
126
|
+
* sealed, whatever it looks like.
|
|
127
|
+
*
|
|
128
|
+
* That is what lets a first backfill trust no shape at all. A blob is
|
|
129
|
+
* recognised by its shape, and a title or a display name is text a person
|
|
130
|
+
* chose: one typed in that shape before the upgrade would be read as sealed,
|
|
131
|
+
* skipped, and left in clear for good — and, sampled by
|
|
132
|
+
* {@link assertKeyOpensSealedRows}, would refuse the start for a key that is
|
|
133
|
+
* perfectly right. Once the first backfill has committed, every write goes
|
|
134
|
+
* through a handle that seals it, so no such value can arrive again.
|
|
135
|
+
*/
|
|
136
|
+
async function isFirstBackfill(tx) {
|
|
137
|
+
const result = await tx.execute(sql `
|
|
138
|
+
SELECT is_nullable FROM information_schema.columns
|
|
139
|
+
WHERE table_schema = current_schema() AND table_name = 'users' AND column_name = 'email_bidx'
|
|
140
|
+
`);
|
|
141
|
+
return result.rows[0]?.is_nullable === 'YES';
|
|
142
|
+
}
|
|
143
|
+
/** How many rows one backfill query reads: a table is walked in batches, never loaded whole. */
|
|
144
|
+
const BACKFILL_BATCH_ROWS = 500;
|
|
145
|
+
/**
|
|
146
|
+
* The configured key must open what earlier starts sealed. A rotated or
|
|
147
|
+
* mistyped `SECRETS_ENC_KEY` would otherwise go unnoticed here — sealed rows
|
|
148
|
+
* are exactly the ones the scan skips — and surface only as every login
|
|
149
|
+
* failing and every lookup by email missing, because the blind indexes would
|
|
150
|
+
* be computed under the new key. One sealed value per table is enough: all
|
|
151
|
+
* rows of a deployment are sealed under one key. Refusing the start is the
|
|
152
|
+
* loud failure; re-keying a database is a deliberate operation, not a boot.
|
|
153
|
+
*/
|
|
154
|
+
async function assertKeyOpensSealedRows(tx, keys) {
|
|
155
|
+
for (const t of PII_BACKFILL_TABLES) {
|
|
156
|
+
const col = t.bidx?.source ?? t.encrypted[0];
|
|
157
|
+
const sample = await tx.execute(sql `SELECT ${asStored(col)} FROM ${ident(t.table)} WHERE ${ident(col)} ~ ${PII_SEALED_SHAPE_SQL_REGEX} LIMIT 1`);
|
|
158
|
+
const value = storedText(sample.rows[0]?.[col]);
|
|
159
|
+
if (typeof value === 'string' && !keys.open(value).ok) {
|
|
160
|
+
throw new Error(`PII encryption: ${t.table}.${col} is sealed with a key the configured SECRETS_ENC_KEY ` +
|
|
161
|
+
'(for a tenant: the one derived from TENANT_MASTER_KEY) does not open — refusing to start. ' +
|
|
162
|
+
'Restore the key that sealed it; changing the key is a re-keying of the database, not a configuration change.');
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
async function backfillTable(tx, keys, t, trustShape) {
|
|
167
|
+
// The key columns are read as text beside themselves, so the next batch can
|
|
168
|
+
// be asked for by value whatever their type is (a uuid, a serial, a path).
|
|
169
|
+
const keyText = (k) => `${k}__key`;
|
|
170
|
+
const cols = [
|
|
171
|
+
...t.key.map(ident),
|
|
172
|
+
...t.key.map((k) => sql `${ident(k)}::text AS ${ident(keyText(k))}`),
|
|
173
|
+
...t.encrypted.map(asStored),
|
|
174
|
+
...(t.bidx ? [ident(t.bidx.column)] : []),
|
|
175
|
+
];
|
|
176
|
+
// Only rows with work left: the ciphertext prefix makes "unsealed" a plain
|
|
177
|
+
// SQL predicate, so a fully-sealed table costs one empty-result query.
|
|
178
|
+
const pending = [
|
|
179
|
+
...t.encrypted.map((col) => needsSealing(col, trustShape)),
|
|
180
|
+
...(t.bidx ? [sql `${ident(t.bidx.column)} IS NULL`] : []),
|
|
181
|
+
];
|
|
182
|
+
const keyTuple = sql `(${sql.join(t.key.map((k) => sql `${ident(k)}::text`), sql `, `)})`;
|
|
183
|
+
// A blob, as far as this pass may believe one. On a first backfill nothing
|
|
184
|
+
// is sealed yet, so nothing is believed (see `isFirstBackfill`).
|
|
185
|
+
const sealedAlready = (value) => trustShape && isEncryptedBlob(value);
|
|
186
|
+
let rewritten = 0;
|
|
187
|
+
/** The key of the last row read, as text: the next batch starts after it. */
|
|
188
|
+
let after = null;
|
|
189
|
+
// IN BATCHES, in key order. A table is never loaded whole: a deployment with
|
|
190
|
+
// years of change requests holds every title and body it ever had, and
|
|
191
|
+
// reading them into one result held the first start after the upgrade — and
|
|
192
|
+
// the memory of the process making it — for as long as that took. Walking by
|
|
193
|
+
// key rather than re-asking for "what is left" also ends: a row this pass
|
|
194
|
+
// leaves as it found it (a write overtook it) is passed, not met again.
|
|
195
|
+
for (;;) {
|
|
196
|
+
const past = after ? sql ` AND ${keyTuple} > (${sql.join(after.map((v) => sql `${v}`), sql `, `)})` : sql ``;
|
|
197
|
+
const result = await tx.execute(sql `SELECT ${sql.join(cols, sql `, `)} FROM ${ident(t.table)} WHERE (${sql.join(pending, sql ` OR `)})${past} ORDER BY ${keyTuple} LIMIT ${BACKFILL_BATCH_ROWS}`);
|
|
198
|
+
const batch = result.rows;
|
|
199
|
+
for (const read of batch) {
|
|
200
|
+
const row = Object.fromEntries(Object.entries(read).map(([col, value]) => [col, storedText(value)]));
|
|
201
|
+
const sets = [];
|
|
202
|
+
// Compare-and-swap: pin every value this row was read with, so a write
|
|
203
|
+
// that lands between scan and update makes this UPDATE match zero rows
|
|
204
|
+
// instead of clobbering the newer value.
|
|
205
|
+
const where = t.key.map((k) => sql `${ident(k)} = ${row[k]}`);
|
|
206
|
+
for (const col of t.encrypted) {
|
|
207
|
+
const value = row[col];
|
|
208
|
+
if (typeof value === 'string' && value !== '' && !sealedAlready(value)) {
|
|
209
|
+
sets.push(sql `${ident(col)} = ${keys.seal(value)}`);
|
|
210
|
+
where.push(sql `${ident(col)} = ${value}`);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (t.bidx) {
|
|
214
|
+
// The blind index is derived from its source, so it is (re)computed
|
|
215
|
+
// whenever the source is being sealed in this pass — a legacy writer
|
|
216
|
+
// that put a NEW plaintext email on an already-indexed row left a stale
|
|
217
|
+
// index behind, and sealing the email alone would freeze that mismatch
|
|
218
|
+
// — and whenever it was never filled. The source may already be
|
|
219
|
+
// ciphertext (an index that was never filled beside a sealed address);
|
|
220
|
+
// the index is always computed over the plaintext, never over a blob
|
|
221
|
+
// the key cannot open.
|
|
222
|
+
const source = row[t.bidx.source];
|
|
223
|
+
const stored = row[t.bidx.column];
|
|
224
|
+
const text = typeof source === 'string' ? source : '';
|
|
225
|
+
const sealingSource = text !== '' && !sealedAlready(text);
|
|
226
|
+
if (sealingSource || stored == null) {
|
|
227
|
+
const opened = sealedAlready(text) ? keys.open(text) : { ok: true, plain: text };
|
|
228
|
+
if (!opened.ok) {
|
|
229
|
+
throw new Error(`PII encryption backfill: ${t.table}.${t.bidx.source} cannot be decrypted with the ` +
|
|
230
|
+
'configured SECRETS_ENC_KEY — refusing to derive a blind index from ciphertext. ' +
|
|
231
|
+
'Restore the key that sealed it, then restart.');
|
|
232
|
+
}
|
|
233
|
+
sets.push(sql `${ident(t.bidx.column)} = ${keys.index(opened.plain)}`);
|
|
234
|
+
// Pin the index AND its source: if a concurrent writer replaces the
|
|
235
|
+
// email between scan and write, the CAS must not attach the OLD
|
|
236
|
+
// email's blind index to the NEW value.
|
|
237
|
+
where.push(sql `${ident(t.bidx.column)} IS NOT DISTINCT FROM ${stored ?? null}`);
|
|
238
|
+
where.push(sql `${ident(t.bidx.source)} IS NOT DISTINCT FROM ${source ?? null}`);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (sets.length === 0)
|
|
242
|
+
continue;
|
|
243
|
+
const updated = await tx.execute(sql `UPDATE ${ident(t.table)} SET ${sql.join(sets, sql `, `)} WHERE ${sql.join(where, sql ` AND `)}`);
|
|
244
|
+
rewritten += updated.rowCount ?? 0;
|
|
245
|
+
}
|
|
246
|
+
if (batch.length < BACKFILL_BATCH_ROWS)
|
|
247
|
+
return rewritten;
|
|
248
|
+
const last = batch[batch.length - 1];
|
|
249
|
+
after = t.key.map((k) => String(last[keyText(k)]));
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* The name on a refused apply that was recorded BEFORE this release: the
|
|
254
|
+
* address of whoever it names was never kept, so no blind index stands beside
|
|
255
|
+
* it and an account erasure has nothing to find it by.
|
|
256
|
+
*
|
|
257
|
+
* Matching it by display name instead got both mistakes at once: a person
|
|
258
|
+
* who had since changed their name kept the old one on the request for good,
|
|
259
|
+
* and somebody else of the same name had theirs taken away. So the name goes,
|
|
260
|
+
* once, here. The refusal itself stays, with its reason and its time; it
|
|
261
|
+
* reads "could not apply" without saying who. A refusal recorded from this
|
|
262
|
+
* release on carries its index and is never touched by this.
|
|
263
|
+
*/
|
|
264
|
+
async function clearUnindexedRefusalNames(tx) {
|
|
265
|
+
const cleared = await tx.execute(sql.raw(`
|
|
266
|
+
UPDATE "change_requests" SET "apply_failed_by_name" = NULL
|
|
267
|
+
WHERE "apply_failed_by_name" IS NOT NULL AND "apply_failed_by_email_bidx" IS NULL
|
|
268
|
+
`));
|
|
269
|
+
return cleared.rowCount ?? 0;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Legacy uniqueness was on the RAW email, so rows differing only by case or
|
|
273
|
+
* whitespace could coexist; under the normalized blind index they collide and
|
|
274
|
+
* the unique-index creation below would abort the start. Approval rows and
|
|
275
|
+
* join-request rows are the same logical row — collapse them, keeping the
|
|
276
|
+
* earliest. Colliding USER rows are distinct accounts; refuse loudly with the
|
|
277
|
+
* ids so an operator resolves the conflict deliberately instead of the
|
|
278
|
+
* upgrade guessing.
|
|
279
|
+
*/
|
|
280
|
+
async function resolveBidxCollisions(tx) {
|
|
281
|
+
await tx.execute(sql.raw(`
|
|
282
|
+
DELETE FROM "pr_file_approvals" a USING "pr_file_approvals" b
|
|
283
|
+
WHERE a."pr_number" = b."pr_number" AND a."path" = b."path"
|
|
284
|
+
AND a."approver_email_bidx" = b."approver_email_bidx" AND a."head_sha" = b."head_sha"
|
|
285
|
+
AND (a."approved_at" > b."approved_at" OR (a."approved_at" = b."approved_at" AND a."id" > b."id"))
|
|
286
|
+
`));
|
|
287
|
+
await tx.execute(sql.raw(`
|
|
288
|
+
DELETE FROM "plugin_join_requests" a USING "plugin_join_requests" b
|
|
289
|
+
WHERE a."plugin_key" = b."plugin_key" AND a."requester_email_bidx" = b."requester_email_bidx"
|
|
290
|
+
AND (a."created_at" > b."created_at" OR (a."created_at" = b."created_at" AND a."id" > b."id"))
|
|
291
|
+
`));
|
|
292
|
+
const dupes = await tx.execute(sql.raw(`
|
|
293
|
+
SELECT array_agg("id") AS ids FROM "users" GROUP BY "email_bidx" HAVING count(*) > 1
|
|
294
|
+
`));
|
|
295
|
+
if (dupes.rows.length > 0) {
|
|
296
|
+
const groups = dupes.rows.map((r) => r.ids.join(', '));
|
|
297
|
+
throw new Error('PII encryption backfill: multiple user rows share the same email after normalization ' +
|
|
298
|
+
'(case/whitespace variants of one address). Merge or delete the duplicates, then restart. ' +
|
|
299
|
+
`Conflicting user ids: [${groups.join('], [')}]`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
const PII_FINALIZE_STATEMENTS = [
|
|
303
|
+
'ALTER TABLE "users" ALTER COLUMN "email_bidx" SET NOT NULL',
|
|
304
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS "users_email_bidx_unq" ON "users" ("email_bidx")',
|
|
305
|
+
'ALTER TABLE "users" DROP CONSTRAINT IF EXISTS "users_email_unique"',
|
|
306
|
+
'ALTER TABLE "pr_file_approvals" ALTER COLUMN "approver_email_bidx" SET NOT NULL',
|
|
307
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS "pr_file_approvals_bidx_unq" ON "pr_file_approvals" ("pr_number","path","approver_email_bidx","head_sha")',
|
|
308
|
+
'DROP INDEX IF EXISTS "pr_file_approvals_unq"',
|
|
309
|
+
'ALTER TABLE "pr_merge_log" ALTER COLUMN "triggered_by_email_bidx" SET NOT NULL',
|
|
310
|
+
'ALTER TABLE "pr_comments" ALTER COLUMN "author_email_bidx" SET NOT NULL',
|
|
311
|
+
'ALTER TABLE "change_requests" ALTER COLUMN "author_email_bidx" SET NOT NULL',
|
|
312
|
+
'ALTER TABLE "pending_commits" ALTER COLUMN "author_email_bidx" SET NOT NULL',
|
|
313
|
+
'ALTER TABLE "plugin_join_requests" ALTER COLUMN "requester_email_bidx" SET NOT NULL',
|
|
314
|
+
'CREATE UNIQUE INDEX IF NOT EXISTS "plugin_join_requests_requester_bidx_plugin_unq" ON "plugin_join_requests" ("requester_email_bidx","plugin_key")',
|
|
315
|
+
'DROP INDEX IF EXISTS "plugin_join_requests_requester_plugin_unq"',
|
|
316
|
+
];
|
|
317
|
+
/**
|
|
318
|
+
* Encrypt pre-existing plaintext PII rows, fill the blind-index columns, and
|
|
319
|
+
* apply the constraints migration 0016 deferred. Idempotent; `runCoreMigrations`
|
|
320
|
+
* runs it under the migrations lock right after the history. The handle must
|
|
321
|
+
* hold the knowledge base's key (`createDb(url, { piiKey })`; the composition
|
|
322
|
+
* root's does): one that holds none is refused before anything is read.
|
|
323
|
+
*/
|
|
324
|
+
export async function runPiiEncryptionBackfill(db) {
|
|
325
|
+
const keys = piiKeysOf(db);
|
|
326
|
+
await db.transaction(async (tx) => {
|
|
327
|
+
const first = await isFirstBackfill(tx);
|
|
328
|
+
// Nothing is sealed before the first backfill, so there is no sealed row
|
|
329
|
+
// for the key to be checked against — and a value that only LOOKS sealed
|
|
330
|
+
// must not be taken for one (see `isFirstBackfill`).
|
|
331
|
+
if (!first)
|
|
332
|
+
await assertKeyOpensSealedRows(tx, keys);
|
|
333
|
+
let rewritten = 0;
|
|
334
|
+
for (const t of PII_BACKFILL_TABLES) {
|
|
335
|
+
rewritten += await backfillTable(tx, keys, t, !first);
|
|
336
|
+
}
|
|
337
|
+
if (rewritten > 0)
|
|
338
|
+
log.info(`PII encryption backfill: rewrote ${rewritten} row(s).`);
|
|
339
|
+
const cleared = await clearUnindexedRefusalNames(tx);
|
|
340
|
+
if (cleared > 0) {
|
|
341
|
+
log.info(`PII encryption backfill: took the name off ${cleared} refused apply(ies) recorded before this release.`);
|
|
342
|
+
}
|
|
343
|
+
// Only where the unique indexes are not up yet. Once they are, they are
|
|
344
|
+
// what keeps two rows from sharing an index, so there is nothing to
|
|
345
|
+
// collapse — and the collapse is two self-joins and an aggregate over
|
|
346
|
+
// whole tables, which every later start paid for nothing.
|
|
347
|
+
if (first)
|
|
348
|
+
await resolveBidxCollisions(tx);
|
|
349
|
+
for (const statement of PII_FINALIZE_STATEMENTS) {
|
|
350
|
+
await tx.execute(sql.raw(statement));
|
|
351
|
+
}
|
|
352
|
+
});
|
|
353
|
+
}
|
|
84
354
|
//# sourceMappingURL=migrate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/modules/database/migrate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,oCAAoC,CAAC;AAC7D,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAEjD,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;AAC/B,OAAO,EAAE,iBAAiB,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AAC/E,OAAO,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAEpE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;;;;;;;;GAaG;AACH,SAAS,aAAa,CAAC,EAAY;IACjC,MAAM,MAAM,GAAG,UAAU,CAAC,EAAE,CAAC,CAAC;IAC9B,OAAO,MAAM,KAAK,iBAAiB;QACjC,CAAC,CAAC,EAAE,SAAS,EAAE,EAAE,EAAE;QACnB,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC;AACtD,CAAC;AAED,8FAA8F;AAC9F,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAY,EAAE,MAAc;IAClE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IAC1D,MAAM,gBAAgB,CACpB,EAAE,EACF,YAAY,CAAC,UAAU,EACvB,KAAK,IAAI,EAAE;QACT,GAAG,CAAC,IAAI,CAAC,qCAAqC,CAAC,CAAC;QAChD,MAAM,OAAO,CAAC,EAAE,EAAE,EAAE,gBAAgB,EAAE,MAAM,EAAE,eAAe,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,CAAC,CAAC;QAChH,GAAG,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;IACxC,CAAC,EACD,EAAE,SAAS,EAAE,CACd,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,EAAY,EAAE,MAAc;IACxE,MAAM,EAAE,gBAAgB,EAAE,SAAS,EAAE,GAAG,aAAa,CAAC,EAAE,CAAC,CAAC;IAC1D,MAAM,gBAAgB,CACpB,EAAE,EACF,YAAY,CAAC,UAAU,EACvB,KAAK,IAAI,EAAE;QACT,GAAG,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QACtD,MAAM,OAAO,CAAC,EAAE,EAAE;YAChB,gBAAgB,EAAE,MAAM;YACxB,eAAe,EAAE,iCAAiC;YAClD,gBAAgB;SACjB,CAAC,CAAC;QACH,GAAG,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;IAC9C,CAAC,EACD,EAAE,SAAS,EAAE,CACd,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"migrate.js","sourceRoot":"","sources":["../../../src/modules/database/migrate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-name.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-fs/branch-name.ts"],"names":[],"mappings":"AASA,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AAIzC,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAwBxD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"branch-name.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-fs/branch-name.ts"],"names":[],"mappings":"AASA,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AAIzC,yEAAyE;AACzE,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAwBxD;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAsClE"}
|
|
@@ -49,8 +49,18 @@ export function assertValidRelativePath(relativePath) {
|
|
|
49
49
|
throw new WorkflowValidationError('path is required');
|
|
50
50
|
if (relativePath.length > 1024)
|
|
51
51
|
throw new WorkflowValidationError('path too long');
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
// NUL, every other C0 control and DEL. A NUL is named on its own because it
|
|
53
|
+
// terminates a C string and git's `-z` output; the rest are refused with it
|
|
54
|
+
// because a LINE BREAK in a path is a separator in git's line-oriented stdin
|
|
55
|
+
// protocols — `cat-file --batch` reads one `<ref>:<path>` per line, so
|
|
56
|
+
// `Docs/secret.md\nzzz` is two object names while every gate upstream was
|
|
57
|
+
// asked about one string. See `CONTROL_CHARACTERS` in `repo-path.ts`, which
|
|
58
|
+
// refuses the same range at the normaliser; this is the same rule at the
|
|
59
|
+
// check every path handed to git as a pathspec passes through.
|
|
60
|
+
// eslint-disable-next-line no-control-regex
|
|
61
|
+
if (/[\x00-\x1F\x7F]/.test(relativePath)) {
|
|
62
|
+
throw new WorkflowValidationError(relativePath.includes('\0') ? 'path contains NUL' : 'path contains a control character');
|
|
63
|
+
}
|
|
54
64
|
if (relativePath.includes('\\')) {
|
|
55
65
|
throw new WorkflowValidationError('path must use forward slashes only');
|
|
56
66
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branch-name.js","sourceRoot":"","sources":["../../../src/modules/kb-fs/branch-name.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;AAEzF,qFAAqF;AACrF,8EAA8E;AAC9E,+EAA+E;AAC/E,4FAA4F;AAC5F,mEAAmE;AACnE,wEAAwE;AACxE,oBAAoB;AACpB,OAAO,EACL,qBAAqB,EACrB,kBAAkB,EAClB,sBAAsB,GACvB,MAAM,iCAAiC,CAAC;AAEzC,MAAM,kBAAkB,GAAG,gCAAgC,CAAC;AAE5D,yEAAyE;AACzE,MAAM,UAAU,qBAAqB,CAAC,IAAY;IAChD,IAAI,CAAC,IAAI;QAAE,MAAM,IAAI,eAAe,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,IAAI,CAAC,MAAM,GAAG,GAAG;QAAE,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IACnE,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,eAAe,CAAC,6BAA6B,EAAE,IAAI,CAAC,CAAC;IACjE,CAAC;IACD,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,eAAe,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IAC1E,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,eAAe,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IAC1E,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7C,MAAM,IAAI,eAAe,CAAC,sBAAsB,EAAE,IAAI,CAAC,CAAC;IAC1D,CAAC;IACD,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,eAAe,CAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;IAC7E,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,eAAe,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC;IAC1E,0EAA0E;IAC1E,qEAAqE;IACrE,6DAA6D;IAC7D,KAAK,MAAM,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACtC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,IAAI,eAAe,CAAC,yBAAyB,EAAE,IAAI,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,eAAe,CAAC,2BAA2B,EAAE,IAAI,CAAC,CAAC;QAC/D,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,YAAoB;IAC1D,IAAI,CAAC,YAAY;QAAE,MAAM,IAAI,uBAAuB,CAAC,kBAAkB,CAAC,CAAC;IACzE,IAAI,YAAY,CAAC,MAAM,GAAG,IAAI;QAAE,MAAM,IAAI,uBAAuB,CAAC,eAAe,CAAC,CAAC;IACnF,IAAI,
|
|
1
|
+
{"version":3,"file":"branch-name.js","sourceRoot":"","sources":["../../../src/modules/kb-fs/branch-name.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* places it inside the clone; {@link assertInsideRepo} is then the check that
|
|
13
|
-
* what came out really is in there. A route or a tool that resolved a path of
|
|
14
|
-
* its own would be the drift this file exists to prevent — a `KnowledgeBase/`
|
|
15
|
-
* folder, a `Plugins/` folder and eight uploaded documents sitting beside a
|
|
16
|
-
* staging checkout is what it looked like the last time two spellings of this
|
|
17
|
-
* rule were allowed to exist.
|
|
2
|
+
* Whether `value` carries one of them — THE predicate, so the places that
|
|
3
|
+
* accept a NAME enforce the same rule as the normaliser that joins it into a
|
|
4
|
+
* path. The checkout folder name is the one that matters: it is not a caller's
|
|
5
|
+
* path, it is deployment configuration (`KB_DIR_NAME`, and the `kbDirName`
|
|
6
|
+
* setting), and it is PREFIXED onto every workspace-relative path. A name with
|
|
7
|
+
* a line break in it would therefore make the normaliser emit exactly the path
|
|
8
|
+
* this rule exists to exclude, from inputs that were each clean. Refused where
|
|
9
|
+
* the name is set — at boot in `core-config` and in the settings validator —
|
|
10
|
+
* so the deployment fails loudly instead of serving a path nothing downstream
|
|
11
|
+
* can safely read.
|
|
18
12
|
*/
|
|
13
|
+
export declare function hasControlCharacter(value: string): boolean;
|
|
19
14
|
/**
|
|
20
15
|
* True when `wsPath` is the repository folder or lies under it.
|
|
21
16
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo-path.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-fs/repo-path.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"repo-path.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-fs/repo-path.ts"],"names":[],"mappings":"AAoDA;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CASvE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CA+BxE;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CA2DhF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAY9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,SAAS,MAAM,EAAE,GACtB,IAAI,CAaN;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CACjC,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;IAAE,gBAAgB,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAC9F,IAAI,CAiBN;AAKD;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,SAAS,EAAE,MAAM,EACjB,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,GAChC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAiBzB"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { WorkflowValidationError } from '../../shared/domain-errors.js';
|
|
3
|
+
import { sanitizedPath } from '../../shared/printable.js';
|
|
3
4
|
/**
|
|
4
5
|
* Workspace-relative paths and the repository folder.
|
|
5
6
|
*
|
|
@@ -18,6 +19,49 @@ import { WorkflowValidationError } from '../../shared/domain-errors.js';
|
|
|
18
19
|
* staging checkout is what it looked like the last time two spellings of this
|
|
19
20
|
* rule were allowed to exist.
|
|
20
21
|
*/
|
|
22
|
+
/**
|
|
23
|
+
* NUL, the C0 controls (a line break among them) and DEL — refused in a
|
|
24
|
+
* workspace path wherever one enters.
|
|
25
|
+
*
|
|
26
|
+
* Not merely hygiene about names nobody can type. A `\n` is a SEPARATOR in
|
|
27
|
+
* git's own line-oriented stdin protocols: `cat-file --batch` reads one
|
|
28
|
+
* `<ref>:<path>` object name per LINE, so `Docs/secret.md\nzzz` is TWO specs.
|
|
29
|
+
* Everything upstream — the read gate, the download gate, the not-a-directory
|
|
30
|
+
* check — is then asked about the whole string, which names nothing, while git
|
|
31
|
+
* answers about `Docs/secret.md` and hands over its bytes. A file denied by
|
|
32
|
+
* its own frontmatter inside a folder its reader may list would be readable
|
|
33
|
+
* that way, and in a batch of several specs the extra answer shifts every
|
|
34
|
+
* result after it, so the access resolver reads one directory's `access.md` as
|
|
35
|
+
* another's.
|
|
36
|
+
*
|
|
37
|
+
* Refused HERE, at the normaliser every accepted path goes through, rather
|
|
38
|
+
* than at each route: the fence has to be at the mechanism, because the next
|
|
39
|
+
* caller to assemble a git spec from a path will not remember this. The
|
|
40
|
+
* shared `validateFilename` has always refused the same range per segment, so
|
|
41
|
+
* no name any surface can create is lost — this closes the gap between it and
|
|
42
|
+
* the paths that reach git. U+2028/U+2029 are NOT in it: they are nothing to
|
|
43
|
+
* git's protocols (which read bytes, and a line break there is 0x0A), a name
|
|
44
|
+
* carrying one is creatable today, and refusing it here would make an existing
|
|
45
|
+
* file unreadable. They are escaped for display instead, which is what
|
|
46
|
+
* `sanitizedPath` is for.
|
|
47
|
+
*/
|
|
48
|
+
// eslint-disable-next-line no-control-regex
|
|
49
|
+
const CONTROL_CHARACTERS = /[\x00-\x1F\x7F]/;
|
|
50
|
+
/**
|
|
51
|
+
* Whether `value` carries one of them — THE predicate, so the places that
|
|
52
|
+
* accept a NAME enforce the same rule as the normaliser that joins it into a
|
|
53
|
+
* path. The checkout folder name is the one that matters: it is not a caller's
|
|
54
|
+
* path, it is deployment configuration (`KB_DIR_NAME`, and the `kbDirName`
|
|
55
|
+
* setting), and it is PREFIXED onto every workspace-relative path. A name with
|
|
56
|
+
* a line break in it would therefore make the normaliser emit exactly the path
|
|
57
|
+
* this rule exists to exclude, from inputs that were each clean. Refused where
|
|
58
|
+
* the name is set — at boot in `core-config` and in the settings validator —
|
|
59
|
+
* so the deployment fails loudly instead of serving a path nothing downstream
|
|
60
|
+
* can safely read.
|
|
61
|
+
*/
|
|
62
|
+
export function hasControlCharacter(value) {
|
|
63
|
+
return CONTROL_CHARACTERS.test(value);
|
|
64
|
+
}
|
|
21
65
|
/**
|
|
22
66
|
* True when `wsPath` is the repository folder or lies under it.
|
|
23
67
|
*
|
|
@@ -32,6 +76,11 @@ import { WorkflowValidationError } from '../../shared/domain-errors.js';
|
|
|
32
76
|
export function isInsideRepo(wsPath, kbDirName) {
|
|
33
77
|
if (typeof wsPath !== 'string' || wsPath.includes('\\'))
|
|
34
78
|
return false;
|
|
79
|
+
// A control character is not a spelling of any path under the repository —
|
|
80
|
+
// see {@link CONTROL_CHARACTERS}. Refused here too, so the check AFTER the
|
|
81
|
+
// normaliser cannot pass one that somehow skipped it.
|
|
82
|
+
if (CONTROL_CHARACTERS.test(wsPath))
|
|
83
|
+
return false;
|
|
35
84
|
const segments = wsPath.replace(/\/$/, '').split('/');
|
|
36
85
|
if (segments[0] !== kbDirName)
|
|
37
86
|
return false;
|
|
@@ -52,6 +101,19 @@ export function isInsideRepo(wsPath, kbDirName) {
|
|
|
52
101
|
export function assertInsideRepo(wsPath, kbDirName) {
|
|
53
102
|
if (isInsideRepo(wsPath, kbDirName))
|
|
54
103
|
return;
|
|
104
|
+
// Said as what it is, before the suggestion below: a control character is
|
|
105
|
+
// not a path that landed in the wrong place, and a "use this instead"
|
|
106
|
+
// carrying an invisible character back to the caller would be nonsense.
|
|
107
|
+
if (typeof wsPath === 'string' && CONTROL_CHARACTERS.test(wsPath)) {
|
|
108
|
+
// Through `sanitizedPath`, like every other refusal that names a path: the
|
|
109
|
+
// character that makes this path invalid is also the character that would
|
|
110
|
+
// forge a second line of the answer, in the message and in the `path` a
|
|
111
|
+
// JSON consumer reads.
|
|
112
|
+
const shown = sanitizedPath(wsPath);
|
|
113
|
+
throw new WorkflowValidationError(`"${shown}" contains a control character: a line break, a NUL or another invisible byte is not part of any ` +
|
|
114
|
+
'file name, and git reads a line break in a path as the end of one object name and the start of another. ' +
|
|
115
|
+
'Remove it and send the name as it is written.', { kind: 'path-control-character', path: shown, kbDirName });
|
|
116
|
+
}
|
|
55
117
|
// The suggestion collapses what made the path wrong: backslashes, leading
|
|
56
118
|
// `./` or `/`, and any `..` climbing back out (a bare `..` included, so the
|
|
57
119
|
// suggestion is never itself a climb). The agent gets a path it can use.
|
|
@@ -101,6 +163,23 @@ export function normalizeWorkspacePath(wsPath, kbDirName) {
|
|
|
101
163
|
// read. Refused before anything is collapsed, never rewritten to `/`.
|
|
102
164
|
if (wsPath.includes('\\'))
|
|
103
165
|
refuse();
|
|
166
|
+
// A line break (or any other control character) is a SEPARATOR to git, not
|
|
167
|
+
// part of a name — see {@link CONTROL_CHARACTERS}. Refused before the path
|
|
168
|
+
// is normalised, so no gate downstream is ever asked about a string that
|
|
169
|
+
// means one thing to it and two things to git.
|
|
170
|
+
if (CONTROL_CHARACTERS.test(wsPath))
|
|
171
|
+
refuse();
|
|
172
|
+
// …and the FOLDER NAME, which is prefixed onto the result rather than read
|
|
173
|
+
// from it: a clean path joined to `kb\nname` comes out carrying the line
|
|
174
|
+
// break, so the normaliser would itself emit what the check above refuses.
|
|
175
|
+
// Said as the configuration error it is — the caller's path is fine, and an
|
|
176
|
+
// operator reading a refusal about their own path would have nothing to fix.
|
|
177
|
+
// `core-config` and the `kbDirName` setting validator both refuse this at
|
|
178
|
+
// the point it is SET, so reaching here means the two drifted.
|
|
179
|
+
if (CONTROL_CHARACTERS.test(kbDirName)) {
|
|
180
|
+
throw new WorkflowValidationError(`the configured checkout folder name (kbDirName / KB_DIR_NAME) contains a control character: "${sanitizedPath(kbDirName)}". ` +
|
|
181
|
+
'Every workspace path is prefixed with it, so no path can be resolved until the setting is corrected.', { kind: 'kb-dir-name-control-character', kbDirName: sanitizedPath(kbDirName) });
|
|
182
|
+
}
|
|
104
183
|
// The root-anchored form, and ONLY for the repository folder: `/<kbDirName>/…`
|
|
105
184
|
// is what the app's Copy path gives (it is the form a Markdown link resolves
|
|
106
185
|
// from) and names the same workspace path. `/tmp/x` and `//x` are not that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repo-path.js","sourceRoot":"","sources":["../../../src/modules/kb-fs/repo-path.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,uBAAuB,EAAE,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"repo-path.js","sourceRoot":"","sources":["../../../src/modules/kb-fs/repo-path.ts"],"names":[],"mappings":"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"}
|
|
@@ -39,10 +39,10 @@ export interface KbSyncRouteDeps {
|
|
|
39
39
|
/** The configured secret, read per request so a setup-screen save applies at once. */
|
|
40
40
|
syncSecret: () => string;
|
|
41
41
|
authService: {
|
|
42
|
-
|
|
42
|
+
resolveSession(token: string): Promise<{
|
|
43
43
|
userId: string;
|
|
44
44
|
email: string;
|
|
45
|
-
}
|
|
45
|
+
}>;
|
|
46
46
|
};
|
|
47
47
|
adminAccess: IAdminAccessService;
|
|
48
48
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"kb-sync.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-sync/kb-sync.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAI9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"kb-sync.routes.d.ts","sourceRoot":"","sources":["../../../src/modules/kb-sync/kb-sync.routes.ts"],"names":[],"mappings":"AAAA,OAAO,OAAO,MAAM,SAAS,CAAC;AAI9B,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AAEvE,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAKzE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,cAAc,CAAC;IACvB,sFAAsF;IACtF,UAAU,EAAE,MAAM,MAAM,CAAC;IACzB,WAAW,EAAE;QAAE,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC;IAC3F,WAAW,EAAE,mBAAmB,CAAC;CAClC;AAKD;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,iBAAiB,CAAC;AACnD,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CASvD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,UAAU,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAIjE;AAID,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CA+GxE"}
|
|
@@ -4,6 +4,7 @@ const log = logger('sync');
|
|
|
4
4
|
import { assertValidBranchName } from '../kb-fs/branch-name.js';
|
|
5
5
|
import { parseSyncPayload } from './sync-payload.js';
|
|
6
6
|
import { verifySyncCredential } from './sync-auth.js';
|
|
7
|
+
import { AuthBackendError } from '../auth/account-admission.js';
|
|
7
8
|
/** Cap on a webhook body. ADO's PR payloads run to a few hundred KB. */
|
|
8
9
|
const BODY_LIMIT = '2mb';
|
|
9
10
|
/**
|
|
@@ -52,6 +53,7 @@ export function createKbSyncRoutes(deps) {
|
|
|
52
53
|
async function handle(req, res, select) {
|
|
53
54
|
res.setHeader(SYNC_RESPONSE_HEADER, SYNC_RESPONSE_MARKER);
|
|
54
55
|
const raw = Buffer.isBuffer(req.body) ? req.body : undefined;
|
|
56
|
+
let lookupFailed = null;
|
|
55
57
|
const auth = await verifySyncCredential({
|
|
56
58
|
secret: deps.syncSecret(),
|
|
57
59
|
authorization: header(req, 'authorization'),
|
|
@@ -59,17 +61,26 @@ export function createKbSyncRoutes(deps) {
|
|
|
59
61
|
hubSignature: header(req, 'x-hub-signature-256'),
|
|
60
62
|
rawBody: raw,
|
|
61
63
|
}, {
|
|
62
|
-
verifyJwt: (token) => {
|
|
64
|
+
verifyJwt: async (token) => {
|
|
63
65
|
try {
|
|
64
|
-
return { email: deps.authService.
|
|
66
|
+
return { email: (await deps.authService.resolveSession(token)).email };
|
|
65
67
|
}
|
|
66
|
-
catch {
|
|
68
|
+
catch (err) {
|
|
69
|
+
if (err instanceof AuthBackendError)
|
|
70
|
+
lookupFailed = err;
|
|
67
71
|
return null;
|
|
68
72
|
}
|
|
69
73
|
},
|
|
70
74
|
isAdmin: (email) => deps.adminAccess.isAdmin(email),
|
|
71
75
|
});
|
|
72
76
|
if (!auth.ok) {
|
|
77
|
+
// The session's account could not be looked up: an outage, not a wrong
|
|
78
|
+
// credential, and saying 401 would send an admin to sign in again.
|
|
79
|
+
if (lookupFailed) {
|
|
80
|
+
log.error('session account lookup failed:', { err: lookupFailed.cause });
|
|
81
|
+
res.status(500).json({ error: 'Authentication backend unavailable' });
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
73
84
|
if (auth.status === 401)
|
|
74
85
|
res.setHeader('WWW-Authenticate', 'Bearer realm="hexis-sync"');
|
|
75
86
|
res.status(auth.status).json({ error: auth.message });
|