@bevel-software/platform-core-backend 0.21.0 → 0.22.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/create-core-server.d.ts.map +1 -1
- package/dist/core/create-core-server.js +32 -2
- package/dist/core/create-core-server.js.map +1 -1
- package/dist/core/create-core-services.d.ts +13 -1
- package/dist/core/create-core-services.d.ts.map +1 -1
- package/dist/core/create-core-services.js +51 -5
- package/dist/core/create-core-services.js.map +1 -1
- package/dist/modules/access/access-requests.contract.d.ts +75 -0
- package/dist/modules/access/access-requests.contract.d.ts.map +1 -0
- package/dist/modules/access/access-requests.contract.js +20 -0
- package/dist/modules/access/access-requests.contract.js.map +1 -0
- package/dist/modules/access/access-requests.routes.d.ts +35 -0
- package/dist/modules/access/access-requests.routes.d.ts.map +1 -0
- package/dist/modules/access/access-requests.routes.js +237 -0
- package/dist/modules/access/access-requests.routes.js.map +1 -0
- package/dist/modules/access/access-requests.service.d.ts +123 -0
- package/dist/modules/access/access-requests.service.d.ts.map +1 -0
- package/dist/modules/access/access-requests.service.js +337 -0
- package/dist/modules/access/access-requests.service.js.map +1 -0
- package/dist/modules/access-model/access-grammar.d.ts +12 -0
- package/dist/modules/access-model/access-grammar.d.ts.map +1 -1
- package/dist/modules/access-model/access-grammar.js +24 -0
- package/dist/modules/access-model/access-grammar.js.map +1 -1
- package/dist/modules/auth/auth.service.d.ts +26 -1
- package/dist/modules/auth/auth.service.d.ts.map +1 -1
- package/dist/modules/auth/auth.service.js +11 -2
- package/dist/modules/auth/auth.service.js.map +1 -1
- package/dist/modules/github-app/github-app.client.d.ts +101 -0
- package/dist/modules/github-app/github-app.client.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.client.js +222 -0
- package/dist/modules/github-app/github-app.client.js.map +1 -0
- package/dist/modules/github-app/github-app.connection.d.ts +102 -0
- package/dist/modules/github-app/github-app.connection.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.connection.js +185 -0
- package/dist/modules/github-app/github-app.connection.js.map +1 -0
- package/dist/modules/github-app/github-app.routes.d.ts +59 -0
- package/dist/modules/github-app/github-app.routes.d.ts.map +1 -0
- package/dist/modules/github-app/github-app.routes.js +323 -0
- package/dist/modules/github-app/github-app.routes.js.map +1 -0
- package/dist/modules/github-app/index.d.ts +4 -0
- package/dist/modules/github-app/index.d.ts.map +1 -0
- package/dist/modules/github-app/index.js +4 -0
- package/dist/modules/github-app/index.js.map +1 -0
- package/dist/modules/kb-fs/remote-url.d.ts +22 -0
- package/dist/modules/kb-fs/remote-url.d.ts.map +1 -0
- package/dist/modules/kb-fs/remote-url.js +35 -0
- package/dist/modules/kb-fs/remote-url.js.map +1 -0
- package/dist/modules/plugins/join-proposals.d.ts +17 -5
- package/dist/modules/plugins/join-proposals.d.ts.map +1 -1
- package/dist/modules/plugins/join-proposals.js +76 -22
- package/dist/modules/plugins/join-proposals.js.map +1 -1
- package/dist/modules/plugins/join-requests.service.d.ts +111 -18
- package/dist/modules/plugins/join-requests.service.d.ts.map +1 -1
- package/dist/modules/plugins/join-requests.service.js +173 -29
- package/dist/modules/plugins/join-requests.service.js.map +1 -1
- package/dist/modules/plugins/plugins.routes.d.ts.map +1 -1
- package/dist/modules/plugins/plugins.routes.js +3 -2
- package/dist/modules/plugins/plugins.routes.js.map +1 -1
- package/dist/modules/settings/deployment-settings.service.d.ts +22 -1
- package/dist/modules/settings/deployment-settings.service.d.ts.map +1 -1
- package/dist/modules/settings/deployment-settings.service.js +93 -4
- package/dist/modules/settings/deployment-settings.service.js.map +1 -1
- package/dist/modules/settings/managed-repository.d.ts +43 -0
- package/dist/modules/settings/managed-repository.d.ts.map +1 -0
- package/dist/modules/settings/managed-repository.js +60 -0
- package/dist/modules/settings/managed-repository.js.map +1 -0
- package/dist/modules/settings/repository-source.d.ts +128 -0
- package/dist/modules/settings/repository-source.d.ts.map +1 -0
- package/dist/modules/settings/repository-source.js +150 -0
- package/dist/modules/settings/repository-source.js.map +1 -0
- package/dist/modules/settings/setup.routes.d.ts +27 -4
- package/dist/modules/settings/setup.routes.d.ts.map +1 -1
- package/dist/modules/settings/setup.routes.js +187 -13
- package/dist/modules/settings/setup.routes.js.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.d.ts +6 -8
- package/dist/modules/skills/skill-access-requests.routes.d.ts.map +1 -1
- package/dist/modules/skills/skill-access-requests.routes.js +24 -63
- package/dist/modules/skills/skill-access-requests.routes.js.map +1 -1
- package/dist/modules/tool-helpers/tool-context.d.ts.map +1 -1
- package/dist/modules/tool-helpers/tool-context.js +15 -0
- package/dist/modules/tool-helpers/tool-context.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 +38 -2
- package/dist/modules/workflow/agent-tools/workflow.tools.js.map +1 -1
- package/dist/modules/workflow/git/git.service.d.ts +3 -1
- package/dist/modules/workflow/git/git.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/git.service.js +17 -4
- package/dist/modules/workflow/git/git.service.js.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.d.ts.map +1 -1
- package/dist/modules/workflow/git/node-git-runner.js +5 -0
- package/dist/modules/workflow/git/node-git-runner.js.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.d.ts +45 -0
- package/dist/modules/workflow/git/pull-request.service.d.ts.map +1 -1
- package/dist/modules/workflow/git/pull-request.service.js +99 -0
- package/dist/modules/workflow/git/pull-request.service.js.map +1 -1
- package/dist/modules/workflow/workflow.routes.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.routes.js +3 -1
- package/dist/modules/workflow/workflow.routes.js.map +1 -1
- package/dist/modules/workflow/workflow.service.d.ts +34 -7
- package/dist/modules/workflow/workflow.service.d.ts.map +1 -1
- package/dist/modules/workflow/workflow.service.js +148 -48
- package/dist/modules/workflow/workflow.service.js.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts +66 -0
- package/dist/modules/workspace/startup/kb-startup-runner.d.ts.map +1 -1
- package/dist/modules/workspace/startup/kb-startup-runner.js +148 -0
- package/dist/modules/workspace/startup/kb-startup-runner.js.map +1 -1
- package/dist/modules/workspace/workspace.service.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.service.js +17 -1
- package/dist/modules/workspace/workspace.service.js.map +1 -1
- package/dist/modules/workspace/workspace.tools.d.ts.map +1 -1
- package/dist/modules/workspace/workspace.tools.js +28 -2
- package/dist/modules/workspace/workspace.tools.js.map +1 -1
- package/dist/shared/domain-errors.d.ts +39 -0
- package/dist/shared/domain-errors.d.ts.map +1 -1
- package/dist/shared/domain-errors.js +55 -0
- package/dist/shared/domain-errors.js.map +1 -1
- package/dist/shared/git.contract.d.ts +10 -0
- package/dist/shared/git.contract.d.ts.map +1 -1
- package/dist/shared/git.contract.js.map +1 -1
- package/package.json +3 -3
- package/src/core/create-core-server.ts +37 -1
- package/src/core/create-core-services.ts +65 -8
- package/src/modules/access/__tests__/access-requests.recut.test.ts +134 -0
- package/src/modules/access/__tests__/access-requests.routes.test.ts +610 -0
- package/src/modules/access/access-requests.contract.ts +93 -0
- package/src/modules/access/access-requests.routes.ts +286 -0
- package/src/modules/access/access-requests.service.ts +420 -0
- package/src/modules/access-model/access-grammar.ts +22 -0
- package/src/modules/auth/__tests__/auth.service.test.ts +38 -0
- package/src/modules/auth/auth.service.ts +28 -1
- package/src/modules/github-app/__tests__/github-app.test.ts +848 -0
- package/src/modules/github-app/github-app.client.ts +268 -0
- package/src/modules/github-app/github-app.connection.ts +204 -0
- package/src/modules/github-app/github-app.routes.ts +359 -0
- package/src/modules/github-app/index.ts +19 -0
- package/src/modules/kb-fs/__tests__/remote-url.test.ts +38 -0
- package/src/modules/kb-fs/remote-url.ts +35 -0
- package/src/modules/plugins/__tests__/join-proposals.test.ts +100 -19
- package/src/modules/plugins/__tests__/join-requests.service.test.ts +27 -11
- package/src/modules/plugins/__tests__/join-requests.settlement.test.ts +371 -0
- package/src/modules/plugins/__tests__/plugins.routes.test.ts +1 -1
- package/src/modules/plugins/join-proposals.ts +87 -19
- package/src/modules/plugins/join-requests.service.ts +199 -39
- package/src/modules/plugins/plugins.routes.ts +3 -2
- package/src/modules/settings/__tests__/repository-source.test.ts +191 -0
- package/src/modules/settings/__tests__/setup.routes.git-mode.test.ts +353 -0
- package/src/modules/settings/__tests__/setup.routes.github-app.test.ts +282 -0
- package/src/modules/settings/__tests__/setup.routes.managed-phase.test.ts +233 -0
- package/src/modules/settings/deployment-settings.service.ts +109 -3
- package/src/modules/settings/managed-repository.ts +68 -0
- package/src/modules/settings/repository-source.ts +197 -0
- package/src/modules/settings/setup.routes.ts +214 -10
- package/src/modules/skills/__tests__/skill-access-requests.routes.test.ts +5 -1
- package/src/modules/skills/skill-access-requests.routes.ts +25 -75
- package/src/modules/tool-helpers/tool-context.ts +15 -0
- package/src/modules/workflow/__tests__/apply-failure.test.ts +9 -1
- package/src/modules/workflow/__tests__/workflow.service.facade.test.ts +159 -8
- package/src/modules/workflow/__tests__/workflow.service.update-from-target.test.ts +146 -40
- package/src/modules/workflow/agent-tools/__tests__/workflow.tools.test.ts +141 -1
- package/src/modules/workflow/agent-tools/workflow.tools.ts +49 -3
- package/src/modules/workflow/git/__tests__/git.service.pull.test.ts +121 -0
- package/src/modules/workflow/git/__tests__/pull-request.service.getPrDetail.test.ts +145 -2
- package/src/modules/workflow/git/__tests__/pull-request.service.viewer-can-delete.test.ts +166 -0
- package/src/modules/workflow/git/git.service.ts +25 -4
- package/src/modules/workflow/git/node-git-runner.ts +6 -0
- package/src/modules/workflow/git/pull-request.service.ts +119 -0
- package/src/modules/workflow/workflow.routes.ts +3 -1
- package/src/modules/workflow/workflow.service.ts +170 -52
- package/src/modules/workspace/__tests__/workspace.service.unknown-branch.test.ts +43 -0
- package/src/modules/workspace/__tests__/workspace.tools.branch-errors.test.ts +233 -7
- package/src/modules/workspace/__tests__/workspace.tools.test.ts +35 -3
- package/src/modules/workspace/startup/__tests__/kb-startup-runner.test.ts +211 -0
- package/src/modules/workspace/startup/kb-startup-runner.ts +159 -0
- package/src/modules/workspace/workspace.service.ts +17 -1
- package/src/modules/workspace/workspace.tools.ts +35 -0
- package/src/shared/domain-errors.ts +58 -0
- package/src/shared/git.contract.ts +10 -0
|
@@ -61,6 +61,16 @@ export interface GitCredentials {
|
|
|
61
61
|
username(): string;
|
|
62
62
|
/** The token in effect, or null when the deployment has none configured. */
|
|
63
63
|
token(): string | null;
|
|
64
|
+
/**
|
|
65
|
+
* Make sure {@link token} answers with a credential that is still good,
|
|
66
|
+
* for one that is not fixed: a token a host issues for an hour has to be
|
|
67
|
+
* renewed by asking the host, which `token` cannot do, being read where
|
|
68
|
+
* nothing can wait. The runner awaits this before every call it makes. A
|
|
69
|
+
* failure here is not the call's failure: git runs with the token in
|
|
70
|
+
* hand, and the host says what it thinks of it. Absent for a credential
|
|
71
|
+
* that does not expire.
|
|
72
|
+
*/
|
|
73
|
+
prepare?(): Promise<void>;
|
|
64
74
|
}
|
|
65
75
|
/** The username git is given when a deployment names none. */
|
|
66
76
|
export declare const DEFAULT_GIT_USERNAME = "x-access-token";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.contract.d.ts","sourceRoot":"","sources":["../../src/shared/git.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,QAAQ,IAAI,MAAM,CAAC;IACnB,4EAA4E;IAC5E,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"git.contract.d.ts","sourceRoot":"","sources":["../../src/shared/git.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,QAAQ,IAAI,MAAM,CAAC;IACnB,4EAA4E;IAC5E,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC;IACvB;;;;;;;;OAQG;IACH,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC3B;AAED,8DAA8D;AAC9D,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAE5C,iEAAiE;AACjE,eAAO,MAAM,kBAAkB,EAAE,cAG/B,CAAC;AAEH,0EAA0E;AAC1E,wBAAgB,cAAc,CAC5B,QAAQ,GAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAwB,EACxD,KAAK,GAAE,MAAM,GAAG,IAAI,GAAG,CAAC,MAAM,MAAM,GAAG,IAAI,CAAQ,GAClD,cAAc,CAOhB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAMrF;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY,CAAC,IAAI,GAAG,MAAM;IACzC,MAAM,EAAE,IAAI,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;;OAOG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,WAAY,SAAQ,KAAK;IACpC,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAE3B;;;;;OAKG;gBACS,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAO;CAOnG;AAED,kFAAkF;AAClF,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAElD;AAED;;;;;;GAMG;AACH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,WAAW,EAAE,cAAc,CAAC;IACrC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG;QAAE,QAAQ,EAAE,QAAQ,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;IAC9G,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,CAAC,EAAE,aAAa,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;CACvG"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"git.contract.js","sourceRoot":"","sources":["../../src/shared/git.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;
|
|
1
|
+
{"version":3,"file":"git.contract.js","sourceRoot":"","sources":["../../src/shared/git.contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAsCH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,oBAAoB,GAAG,gBAAgB,CAAC;AAErD;;;;;GAKG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC;AAE5C,iEAAiE;AACjE,MAAM,CAAC,MAAM,kBAAkB,GAAmB,MAAM,CAAC,MAAM,CAAC;IAC9D,QAAQ,EAAE,GAAG,EAAE,CAAC,oBAAoB;IACpC,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI;CAClB,CAAC,CAAC;AAEH,0EAA0E;AAC1E,MAAM,UAAU,cAAc,CAC5B,WAAoC,oBAAoB,EACxD,QAA+C,IAAI;IAEnD,MAAM,IAAI,GAAG,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;IACxE,MAAM,MAAM,GAAG,OAAO,KAAK,KAAK,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;IACjE,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI,EAAE,IAAI,oBAAoB;QAC9C,KAAK,EAAE,GAAG,EAAE,CAAC,MAAM,EAAE,IAAI,IAAI;KAC9B,CAAC;AACJ,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,KAAgC;IAC3E,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC9D,wEAAwE;IACxE,2EAA2E;IAC3E,wCAAwC;IACxC,OAAO,QAAQ,CAAC,OAAO,CAAC,iBAAiB,EAAE,SAAS,CAAC,CAAC;AACxD,CAAC;AA8CD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,OAAO,WAAY,SAAQ,KAAK;IACpC,0DAA0D;IACjD,QAAQ,CAAU;IAC3B,+DAA+D;IACtD,MAAM,CAAU;IACzB,+DAA+D;IACtD,QAAQ,CAAU;IAE3B;;;;;OAKG;IACH,YAAY,OAAe,EAAE,OAAmE,EAAE;QAChG,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,aAAa,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,IAAI,KAAK,CAAC;IACzC,CAAC;CACF;AAED,kFAAkF;AAClF,MAAM,UAAU,YAAY,CAAC,GAAY;IACvC,OAAO,GAAG,YAAY,WAAW,IAAI,GAAG,CAAC,QAAQ,CAAC;AACpD,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bevel-software/platform-core-backend",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.22.0",
|
|
4
4
|
"description": "Open-source core backend of the Bevel platform: git-backed knowledge workspace, workflow (branches/change requests/locks/SSE), skills, tools, secrets vault, access control and the remote MCP surface.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -52,8 +52,8 @@
|
|
|
52
52
|
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.3/xlsx-0.20.3.tgz",
|
|
53
53
|
"yaml": "^2.9.0",
|
|
54
54
|
"zod": "^3.24.0",
|
|
55
|
-
"@bevel-software/platform-mcp-core": "0.
|
|
56
|
-
"@bevel-software/platform-shared": "0.
|
|
55
|
+
"@bevel-software/platform-mcp-core": "0.22.0",
|
|
56
|
+
"@bevel-software/platform-shared": "0.22.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@types/adm-zip": "^0.5.8",
|
|
@@ -10,6 +10,7 @@ import { createDiffRoutes } from '../modules/diff/diff.routes.js';
|
|
|
10
10
|
import { createWorkflowRoutes } from '../modules/workflow/workflow.routes.js';
|
|
11
11
|
import { createEventsRoutes } from '../modules/workflow/events.routes.js';
|
|
12
12
|
import { createAccessRoutes } from '../modules/access/access.routes.js';
|
|
13
|
+
import { createAccessRequestRoutes } from '../modules/access/access-requests.routes.js';
|
|
13
14
|
import { createMcpRoutes } from '../modules/mcp/mcp.routes.js';
|
|
14
15
|
import { createOAuthConsentRoutes } from '../modules/mcp/oauth/oauth-consent.routes.js';
|
|
15
16
|
import { mcpAuthRouter } from '@modelcontextprotocol/sdk/server/auth/router.js';
|
|
@@ -50,7 +51,8 @@ import { createConnectionKeysAdminRoutes } from '../modules/tool-auth/connection
|
|
|
50
51
|
import { createAuditRoutes } from '../modules/audit/audit.routes.js';
|
|
51
52
|
import { createAgentRestAuditMiddleware } from '../modules/audit/agent-rest-audit.middleware.js';
|
|
52
53
|
import { EXTERNAL_KB_MANUAL_NAME } from '../modules/tool-manuals/tool-manuals.contract.js';
|
|
53
|
-
import { createSetupRoutes } from '../modules/settings/setup.routes.js';
|
|
54
|
+
import { createSetupRoutes, isComplete } from '../modules/settings/setup.routes.js';
|
|
55
|
+
import { createGitHubAppRoutes } from '../modules/github-app/index.js';
|
|
54
56
|
import { oidcRedirectUri } from '../modules/auth/oidc-auth-provider.js';
|
|
55
57
|
import { repositoryConnectionCheck } from '../modules/settings/connection-check.js';
|
|
56
58
|
import { rootFolderListerFor } from '../modules/settings/git-root-folders.js';
|
|
@@ -591,6 +593,18 @@ export async function createCoreServer(
|
|
|
591
593
|
core.kb,
|
|
592
594
|
[core.config.adminEmail],
|
|
593
595
|
));
|
|
596
|
+
// Asking for Can edit or Owner on an item from its Manage access dialog, and
|
|
597
|
+
// the editors' Accept / Decline. Mounted beside the access routes it shares
|
|
598
|
+
// its gate with: the request is refused by the same canWrite it would
|
|
599
|
+
// otherwise have to wait for.
|
|
600
|
+
app.use('/api', core.authMiddleware, createAccessRequestRoutes({
|
|
601
|
+
accessControl: core.accessControl,
|
|
602
|
+
workspaceService: core.workspaceService,
|
|
603
|
+
authService: core.authService,
|
|
604
|
+
workflow: core.workflowService,
|
|
605
|
+
lifecycle: core.joinRequestsService,
|
|
606
|
+
kb: core.kb,
|
|
607
|
+
}));
|
|
594
608
|
app.use(
|
|
595
609
|
'/api',
|
|
596
610
|
core.authMiddleware,
|
|
@@ -700,8 +714,30 @@ export async function createCoreServer(
|
|
|
700
714
|
repositoryConnectionCheck(core.gitRunner),
|
|
701
715
|
rootFolderListerFor(core.gitRunner),
|
|
702
716
|
oidcRedirectUri(core.config.publicBackendUrl),
|
|
717
|
+
// The two sign-in checks keep their defaults.
|
|
718
|
+
undefined,
|
|
719
|
+
undefined,
|
|
720
|
+
{
|
|
721
|
+
source: core.repositorySource,
|
|
722
|
+
ensureManaged: (branch) => core.managedRepository.ensure(core.gitRunner, branch),
|
|
723
|
+
githubApp: core.githubApp,
|
|
724
|
+
},
|
|
703
725
|
),
|
|
704
726
|
);
|
|
727
|
+
// Connecting a repository on GitHub through a GitHub App: the round trips
|
|
728
|
+
// to GitHub the setup screen starts, behind the same sign-in.
|
|
729
|
+
app.use(
|
|
730
|
+
'/api',
|
|
731
|
+
core.authMiddleware,
|
|
732
|
+
createGitHubAppRoutes({
|
|
733
|
+
settings: core.settings,
|
|
734
|
+
connection: core.githubApp,
|
|
735
|
+
adminAccess: core.adminAccess,
|
|
736
|
+
publicBackendUrl: core.config.publicBackendUrl,
|
|
737
|
+
publicFrontendUrl: core.config.publicFrontendUrl,
|
|
738
|
+
isComplete: () => isComplete(core.settings, core.kb, core.repositorySource),
|
|
739
|
+
}),
|
|
740
|
+
);
|
|
705
741
|
const toolPageUser = async (userId: string): Promise<AuthUser | undefined> => {
|
|
706
742
|
const u = await core.authService.getUserById(userId);
|
|
707
743
|
return u ? ({ id: u.id, email: u.email, name: u.name } as AuthUser) : undefined;
|
|
@@ -30,7 +30,10 @@ import { KbSyncService } from '../modules/kb-sync/kb-sync.service.js';
|
|
|
30
30
|
import { NodeFs } from '../modules/kb-fs/node-fs.js';
|
|
31
31
|
import { assertKbDirNameFree } from '../modules/kb-fs/repo-path.js';
|
|
32
32
|
import type { IFsProbe, ITreeWalker } from '../shared/fs.contract.js';
|
|
33
|
-
import {
|
|
33
|
+
import type { IGitRunner } from '../shared/git.contract.js';
|
|
34
|
+
import { ManagedRepository, MANAGED_DEFAULT_BRANCH } from '../modules/settings/managed-repository.js';
|
|
35
|
+
import { RepositorySource } from '../modules/settings/repository-source.js';
|
|
36
|
+
import { GitHubAppConnection } from '../modules/github-app/index.js';
|
|
34
37
|
import { AdvisoryLease, AdvisoryLock } from '../modules/database/advisory-lock.js';
|
|
35
38
|
import { holdCommitWorkerLease, withStartupTask, type LeaseLoopHandle } from './lifecycle.js';
|
|
36
39
|
|
|
@@ -186,6 +189,15 @@ export interface CoreServices {
|
|
|
186
189
|
* first-time setup completion — and never again while the process serves.
|
|
187
190
|
*/
|
|
188
191
|
kbStartupRunner: KbStartupRunner;
|
|
192
|
+
/**
|
|
193
|
+
* Where the knowledge base's repository is and what git presents to it,
|
|
194
|
+
* whichever way the deployment was given one (see `RepositorySource`).
|
|
195
|
+
*/
|
|
196
|
+
repositorySource: RepositorySource;
|
|
197
|
+
/** The repository the deployment keeps for itself, when that is the way it chose. */
|
|
198
|
+
managedRepository: ManagedRepository;
|
|
199
|
+
/** The connection to GitHub through a GitHub App, when that is the way it chose. */
|
|
200
|
+
githubApp: GitHubAppConnection;
|
|
189
201
|
/**
|
|
190
202
|
* The startup phase's retry when the boot survived an unreachable remote
|
|
191
203
|
* — set by `startCore`, stopped by `stopCore` (see `core/lifecycle.ts`);
|
|
@@ -434,18 +446,49 @@ export async function createCoreServices(
|
|
|
434
446
|
// settings catalogue knows `GIT_TOKEN` alone. Handed to the runner, which
|
|
435
447
|
// puts the token into each child's environment — never into this
|
|
436
448
|
// process's, which several knowledge bases may share.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
449
|
+
//
|
|
450
|
+
// Both come from the repository source, which is the one place that knows
|
|
451
|
+
// a deployment can be given its repository in more than one way; what
|
|
452
|
+
// comes back is the address and the credential, as it always was.
|
|
453
|
+
const managedRepository = new ManagedRepository(path.join(config.backupsRoot, 'managed-repository'));
|
|
454
|
+
const githubApp = new GitHubAppConnection({
|
|
455
|
+
read: (key) => settings.resolve(key),
|
|
456
|
+
sourceOf: (key) => settings.sourceOf(key),
|
|
457
|
+
});
|
|
458
|
+
const repositorySource = new RepositorySource({
|
|
459
|
+
read: (key) => settings.resolve(key),
|
|
460
|
+
fallback: { username: config.gitUsername, token: config.gitToken },
|
|
461
|
+
managed: managedRepository,
|
|
462
|
+
githubApp,
|
|
463
|
+
});
|
|
464
|
+
const gitCredentialsInEffect = repositorySource.credentials;
|
|
441
465
|
// How git is run, for every module that runs it: one environment, one buffer
|
|
442
466
|
// ceiling, one error shape, and — the reason it exists — one deadline, so a
|
|
443
467
|
// git that never returns cannot hold a workspace (and with it the commit
|
|
444
468
|
// queue) open indefinitely. See `shared/git.contract.ts`.
|
|
445
469
|
const gitRunner = new NodeGitRunner(config.gitTimeoutMs, gitCredentialsInEffect);
|
|
470
|
+
// A deployment that keeps its own repository has it before anything asks
|
|
471
|
+
// for it: one that chose the mode through the environment never passes
|
|
472
|
+
// through the save that would have created it, and the startup phase's
|
|
473
|
+
// first question would be asked of a folder that is not there. Left to
|
|
474
|
+
// that phase to report if it cannot be made: its failures are classified
|
|
475
|
+
// and shown on the setup screen, where a throw here would take the screen
|
|
476
|
+
// down with the boot.
|
|
477
|
+
if (repositorySource.mode() === 'managed') {
|
|
478
|
+
await managedRepository
|
|
479
|
+
.ensure(gitRunner, settings.resolve('defaultBranch') || MANAGED_DEFAULT_BRANCH)
|
|
480
|
+
.catch((err: unknown) => logger('setup').error('the managed repository could not be created:', { err }));
|
|
481
|
+
}
|
|
482
|
+
// One reached through a GitHub App has a token in hand before anything
|
|
483
|
+
// reads it: a working copy's credential helper is stamped according to
|
|
484
|
+
// whether there is a token, by code that cannot wait for one. A failure is
|
|
485
|
+
// the startup phase's to report, for the same reason as above.
|
|
486
|
+
if (repositorySource.mode() === 'github-app') {
|
|
487
|
+
await githubApp.prepare().catch(() => undefined);
|
|
488
|
+
}
|
|
446
489
|
const workspaceService = new WorkspaceService(
|
|
447
490
|
config.workspacesRoot,
|
|
448
|
-
() =>
|
|
491
|
+
() => repositorySource.url(),
|
|
449
492
|
kb,
|
|
450
493
|
disk,
|
|
451
494
|
gitRunner,
|
|
@@ -484,8 +527,12 @@ export async function createCoreServices(
|
|
|
484
527
|
// Getters, not values: the remote and the branch model can arrive from the
|
|
485
528
|
// setup screen after this object exists, and the setup-completion run is
|
|
486
529
|
// the first thing that needs them.
|
|
487
|
-
kbRepoUrl: () =>
|
|
530
|
+
kbRepoUrl: () => repositorySource.url(),
|
|
488
531
|
workspacesRoot: config.workspacesRoot,
|
|
532
|
+
// Under the backups root, a persistent volume of its own and one nothing
|
|
533
|
+
// sweeps: a working copy of a repository that was replaced is kept there,
|
|
534
|
+
// never deleted (see the runner's `reconcileClonesWithConfiguredRepository`).
|
|
535
|
+
setAsideRoot: path.join(config.backupsRoot, 'replaced-working-copies'),
|
|
489
536
|
kbDirName,
|
|
490
537
|
templateDir: config.kbTemplateDir,
|
|
491
538
|
defaultBranch: () => kb.defaultBranch,
|
|
@@ -693,7 +740,14 @@ export async function createCoreServices(
|
|
|
693
740
|
// (the request's branch vs the default branch), so it holds no state — it
|
|
694
741
|
// only needs to read files at refs and to close a request whose proposals
|
|
695
742
|
// have all landed.
|
|
696
|
-
const joinRequestsService = new JoinRequestsService(
|
|
743
|
+
const joinRequestsService = new JoinRequestsService(
|
|
744
|
+
workspaceService,
|
|
745
|
+
workflowService,
|
|
746
|
+
kb,
|
|
747
|
+
// Read-only: the one question a request asks of the resolver is whether
|
|
748
|
+
// the person it names already holds what it proposes.
|
|
749
|
+
accessControl,
|
|
750
|
+
);
|
|
697
751
|
// The OTHER half of a join request: the row the subscribe endpoint writes
|
|
698
752
|
// before it answers, and the branch/clone/commit/push/change-request work
|
|
699
753
|
// that runs against it afterwards. The row is what lets the click be
|
|
@@ -1237,6 +1291,9 @@ export async function createCoreServices(
|
|
|
1237
1291
|
toolDeleteService,
|
|
1238
1292
|
workspaceService,
|
|
1239
1293
|
kbStartupRunner,
|
|
1294
|
+
repositorySource,
|
|
1295
|
+
managedRepository,
|
|
1296
|
+
githubApp,
|
|
1240
1297
|
settings,
|
|
1241
1298
|
kb,
|
|
1242
1299
|
kbDirName,
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { execFile } from 'node:child_process';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import fs from 'node:fs/promises';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import os from 'node:os';
|
|
7
|
+
|
|
8
|
+
import { spliceGrant } from '../../access-model/access-splice.js';
|
|
9
|
+
import { pendingProposals } from '../../plugins/join-proposals.js';
|
|
10
|
+
|
|
11
|
+
const execFileAsync = promisify(execFile);
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* WHY A REQUEST BRANCH IS CUT AGAIN FROM LIVE, proved against real git.
|
|
15
|
+
*
|
|
16
|
+
* Opening a change request merges the target branch INTO its source branch.
|
|
17
|
+
* A request branch survives being declined — that is what lets the dialog say
|
|
18
|
+
* "your last request wasn't accepted" — so the next request finds a branch
|
|
19
|
+
* whose base may be old. Writing the new proposal onto it and opening the
|
|
20
|
+
* request then asks git to merge live into a branch that edited the same
|
|
21
|
+
* rules file from a different starting point, and git does what git does.
|
|
22
|
+
*
|
|
23
|
+
* The person asking is told to "resolve on reader2/join-artest3-04i7dr4", a
|
|
24
|
+
* branch they cannot reach, and every retry says the same thing. There is no
|
|
25
|
+
* route out of it for them, which is what made this worth a fix rather than a
|
|
26
|
+
* better error message.
|
|
27
|
+
*
|
|
28
|
+
* Everything below is plain git on a scratch repo: no app, no doubles. The
|
|
29
|
+
* first case is the bug, kept so the fix cannot quietly stop being necessary;
|
|
30
|
+
* the second is the fix.
|
|
31
|
+
*/
|
|
32
|
+
describe('a request branch whose base has moved', () => {
|
|
33
|
+
let root: string;
|
|
34
|
+
let repo: string;
|
|
35
|
+
|
|
36
|
+
const RULES = 'Research/access.md';
|
|
37
|
+
const LIVE = 'live';
|
|
38
|
+
const REQUEST = 'reader2/join-research-abc1234-def5678';
|
|
39
|
+
const RITA = { kind: 'user' as const, email: 'rita@x.io', displayName: 'Rita' };
|
|
40
|
+
const RAVI = { kind: 'user' as const, email: 'ravi@x.io', displayName: 'Ravi' };
|
|
41
|
+
|
|
42
|
+
const git = (...args: string[]) => execFileAsync('git', ['-C', repo, ...args]);
|
|
43
|
+
|
|
44
|
+
const readRules = async () => fs.readFile(path.join(repo, RULES), 'utf-8');
|
|
45
|
+
const writeRules = async (text: string) => {
|
|
46
|
+
await fs.mkdir(path.dirname(path.join(repo, RULES)), { recursive: true });
|
|
47
|
+
await fs.writeFile(path.join(repo, RULES), text);
|
|
48
|
+
};
|
|
49
|
+
const commit = async (message: string) => {
|
|
50
|
+
await git('add', '-A');
|
|
51
|
+
await git('commit', '-q', '-m', message);
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
/** What opening a change request does: merge live INTO the request branch. */
|
|
55
|
+
async function mergeLiveIntoRequest(): Promise<{ ok: boolean; conflicted: string[] }> {
|
|
56
|
+
try {
|
|
57
|
+
await git('merge', '--no-edit', LIVE);
|
|
58
|
+
return { ok: true, conflicted: [] };
|
|
59
|
+
} catch {
|
|
60
|
+
const { stdout } = await execFileAsync('git', [
|
|
61
|
+
'-C',
|
|
62
|
+
repo,
|
|
63
|
+
'diff',
|
|
64
|
+
'--name-only',
|
|
65
|
+
'--diff-filter=U',
|
|
66
|
+
]);
|
|
67
|
+
await git('merge', '--abort');
|
|
68
|
+
return { ok: false, conflicted: stdout.split('\n').filter(Boolean) };
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
beforeEach(async () => {
|
|
73
|
+
root = await fs.mkdtemp(path.join(os.tmpdir(), 'bevel-recut-'));
|
|
74
|
+
repo = path.join(root, 'kb');
|
|
75
|
+
await fs.mkdir(repo, { recursive: true });
|
|
76
|
+
await git('init', '-q', '-b', LIVE);
|
|
77
|
+
await git('config', 'user.email', 'test@bevel.software');
|
|
78
|
+
await git('config', 'user.name', 'Test');
|
|
79
|
+
await writeRules('---\n---\nowner:\n - Ed <ed@x.io>\n');
|
|
80
|
+
await commit('the rules as they were');
|
|
81
|
+
|
|
82
|
+
// Ravi asked for Owner, and it was declined. The branch stays behind.
|
|
83
|
+
await git('checkout', '-q', '-b', REQUEST);
|
|
84
|
+
await writeRules(spliceGrant(await readRules(), 'owner', RAVI, { target: 'folder' }).text);
|
|
85
|
+
await commit('Request owner access to Research');
|
|
86
|
+
await git('checkout', '-q', LIVE);
|
|
87
|
+
|
|
88
|
+
// Then an editor grants somebody else Can edit here — an ordinary click in
|
|
89
|
+
// the dialog, and the only thing this scenario needs to go wrong.
|
|
90
|
+
await writeRules(spliceGrant(await readRules(), 'write', RITA, { target: 'folder' }).text);
|
|
91
|
+
await commit('Ed grants Rita Can edit');
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
afterEach(async () => {
|
|
95
|
+
await fs.rm(root, { recursive: true, force: true });
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('CONFLICTS when the stale branch is written to and the request opened on it', async () => {
|
|
99
|
+
// What this did before: splice onto live's text, write it to the branch as
|
|
100
|
+
// it stands, open the request. The content is right; the history is not.
|
|
101
|
+
await git('checkout', '-q', REQUEST);
|
|
102
|
+
const live = await execFileAsync('git', ['-C', repo, 'show', `${LIVE}:${RULES}`]);
|
|
103
|
+
await writeRules(spliceGrant(live.stdout, 'write', RAVI, { target: 'folder' }).text);
|
|
104
|
+
await commit('Request can edit access to Research');
|
|
105
|
+
|
|
106
|
+
const merged = await mergeLiveIntoRequest();
|
|
107
|
+
expect(merged.ok).toBe(false);
|
|
108
|
+
expect(merged.conflicted).toEqual([RULES]);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it('is CLEAN once the branch is cut again from live first', async () => {
|
|
112
|
+
// The fix: the answered request's branch is deleted and recut from live,
|
|
113
|
+
// so live's tip is the merge base and there is nothing to reconcile.
|
|
114
|
+
await git('branch', '-q', '-D', REQUEST);
|
|
115
|
+
await git('checkout', '-q', '-b', REQUEST, LIVE);
|
|
116
|
+
await writeRules(spliceGrant(await readRules(), 'write', RAVI, { target: 'folder' }).text);
|
|
117
|
+
await commit('Request can edit access to Research');
|
|
118
|
+
|
|
119
|
+
const merged = await mergeLiveIntoRequest();
|
|
120
|
+
expect(merged.ok).toBe(true);
|
|
121
|
+
|
|
122
|
+
// And the branch proposes exactly one thing — asked of the function the
|
|
123
|
+
// app itself asks, rather than of the diff's line-by-line shape (a splice
|
|
124
|
+
// may rewrite a whole block without proposing anything more). Rita's
|
|
125
|
+
// grant is already on live, so it is nothing new; the declined Owner
|
|
126
|
+
// proposal went with the branch that carried it.
|
|
127
|
+
const branchText = (await execFileAsync('git', ['-C', repo, 'show', `${REQUEST}:${RULES}`]))
|
|
128
|
+
.stdout;
|
|
129
|
+
const liveText = (await execFileAsync('git', ['-C', repo, 'show', `${LIVE}:${RULES}`])).stdout;
|
|
130
|
+
expect(pendingProposals(branchText, liveText, RULES)).toEqual([
|
|
131
|
+
expect.objectContaining({ verb: 'write', id: `user:${RAVI.email}` }),
|
|
132
|
+
]);
|
|
133
|
+
});
|
|
134
|
+
});
|