@vellumai/credential-executor 0.6.6 → 0.7.1
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/Dockerfile +1 -1
- package/bun.lock +15 -7
- package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
- package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
- package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
- package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
- package/package.json +5 -4
- package/src/__tests__/bulk-set-credentials.test.ts +1 -1
- package/src/__tests__/ces-migrations-002-api-keys.test.ts +185 -0
- package/src/__tests__/ces-migrations-runner.test.ts +227 -0
- package/src/__tests__/cli.test.ts +139 -0
- package/src/__tests__/command-executor.test.ts +71 -42
- package/src/__tests__/http-executor.test.ts +1 -1
- package/src/__tests__/local-materializers.test.ts +1 -1
- package/src/__tests__/local-token-refresh.test.ts +65 -38
- package/src/__tests__/managed-integration.test.ts +1 -1
- package/src/__tests__/managed-lazy-getters.test.ts +1 -1
- package/src/__tests__/managed-materializers.test.ts +1 -1
- package/src/__tests__/managed-rejection.test.ts +1 -1
- package/src/__tests__/toolstore.test.ts +65 -20
- package/src/__tests__/transport.test.ts +13 -4
- package/src/audit/store.ts +2 -2
- package/src/cli.ts +158 -0
- package/src/commands/executor.ts +2 -2
- package/src/grants/rpc-handlers.ts +1 -1
- package/src/http/__tests__/credential-routes-normalization.test.ts +202 -0
- package/src/http/audit.ts +1 -1
- package/src/http/credential-routes.ts +53 -7
- package/src/http/executor.ts +2 -2
- package/src/http/policy.ts +1 -1
- package/src/main.ts +120 -50
- package/src/managed-errors.ts +2 -2
- package/src/managed-lazy-getters.ts +4 -4
- package/src/managed-main.ts +9 -3
- package/src/materializers/local-oauth-lookup.ts +7 -6
- package/src/materializers/local-token-refresh.ts +25 -15
- package/src/materializers/local.ts +1 -1
- package/src/migrations/001-no-op.ts +19 -0
- package/src/migrations/002-api-keys-to-credentials.ts +60 -0
- package/src/migrations/registry.ts +15 -0
- package/src/migrations/runner.ts +146 -0
- package/src/migrations/types.ts +54 -0
- package/src/paths.ts +15 -11
- package/src/server.ts +2 -2
- package/src/subjects/local.ts +2 -2
- package/src/subjects/managed.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/tsconfig.json +0 -0
package/Dockerfile
CHANGED
|
@@ -14,7 +14,7 @@ RUN curl -fsSL https://bun.sh/install | bash -s "bun-v1.3.11"
|
|
|
14
14
|
ENV PATH="/root/.bun/bin:${PATH}"
|
|
15
15
|
|
|
16
16
|
# Copy shared packages first (needed for repo-local dependencies)
|
|
17
|
-
COPY packages/
|
|
17
|
+
COPY packages/service-contracts ./packages/service-contracts
|
|
18
18
|
COPY packages/credential-storage ./packages/credential-storage
|
|
19
19
|
COPY packages/egress-proxy ./packages/egress-proxy
|
|
20
20
|
|
package/bun.lock
CHANGED
|
@@ -5,9 +5,9 @@
|
|
|
5
5
|
"": {
|
|
6
6
|
"name": "@vellumai/credential-executor",
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@vellumai/ces-contracts": "file:../packages/ces-contracts",
|
|
9
8
|
"@vellumai/credential-storage": "file:../packages/credential-storage",
|
|
10
9
|
"@vellumai/egress-proxy": "file:../packages/egress-proxy",
|
|
10
|
+
"@vellumai/service-contracts": "file:../packages/service-contracts",
|
|
11
11
|
"pino": "9.14.0",
|
|
12
12
|
"pino-pretty": "13.1.3",
|
|
13
13
|
},
|
|
@@ -22,13 +22,15 @@
|
|
|
22
22
|
|
|
23
23
|
"@types/bun": ["@types/bun@1.3.10", "", { "dependencies": { "bun-types": "1.3.10" } }, "sha512-0+rlrUrOrTSskibryHbvQkDOWRJwJZqZlxrUs1u4oOoTln8+WIXBPmAuCF35SWB2z4Zl3E84Nl/D0P7803nigQ=="],
|
|
24
24
|
|
|
25
|
-
"@types/node": ["@types/node@25.
|
|
25
|
+
"@types/node": ["@types/node@25.6.0", "", { "dependencies": { "undici-types": "~7.19.0" } }, "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ=="],
|
|
26
26
|
|
|
27
|
-
"@
|
|
27
|
+
"@types/ws": ["@types/ws@8.5.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw=="],
|
|
28
28
|
|
|
29
|
-
"@vellumai/credential-storage": ["@vellumai/credential-storage@file:../packages/credential-storage", { "devDependencies": { "@types/bun": "
|
|
29
|
+
"@vellumai/credential-storage": ["@vellumai/credential-storage@file:../packages/credential-storage", { "devDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" } }],
|
|
30
30
|
|
|
31
|
-
"@vellumai/egress-proxy": ["@vellumai/egress-proxy@file:../packages/egress-proxy", { "devDependencies": { "@types/bun": "
|
|
31
|
+
"@vellumai/egress-proxy": ["@vellumai/egress-proxy@file:../packages/egress-proxy", { "devDependencies": { "@types/bun": "1.3.10", "typescript": "5.9.3" } }],
|
|
32
|
+
|
|
33
|
+
"@vellumai/service-contracts": ["@vellumai/service-contracts@file:../packages/service-contracts", { "dependencies": { "zod": "4.3.6" }, "devDependencies": { "@types/bun": "1.2.4", "typescript": "5.7.3" } }],
|
|
32
34
|
|
|
33
35
|
"atomic-sleep": ["atomic-sleep@1.0.0", "", {}, "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="],
|
|
34
36
|
|
|
@@ -40,7 +42,7 @@
|
|
|
40
42
|
|
|
41
43
|
"end-of-stream": ["end-of-stream@1.4.5", "", { "dependencies": { "once": "^1.4.0" } }, "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg=="],
|
|
42
44
|
|
|
43
|
-
"fast-copy": ["fast-copy@4.0.
|
|
45
|
+
"fast-copy": ["fast-copy@4.0.3", "", {}, "sha512-58apWr0GUiDFM8+3afrO6eYwJBn9ZAhDOzG3L+/9llab/haCARS2UIfffmOurYLwbgDRs8n0rfr6qAAPEAuAQw=="],
|
|
44
46
|
|
|
45
47
|
"fast-safe-stringify": ["fast-safe-stringify@2.1.1", "", {}, "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA=="],
|
|
46
48
|
|
|
@@ -84,12 +86,18 @@
|
|
|
84
86
|
|
|
85
87
|
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
86
88
|
|
|
87
|
-
"undici-types": ["undici-types@7.
|
|
89
|
+
"undici-types": ["undici-types@7.19.2", "", {}, "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg=="],
|
|
88
90
|
|
|
89
91
|
"wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="],
|
|
90
92
|
|
|
91
93
|
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
|
92
94
|
|
|
95
|
+
"@vellumai/service-contracts/@types/bun": ["@types/bun@1.2.4", "", { "dependencies": { "bun-types": "1.2.4" } }, "sha512-QtuV5OMR8/rdKJs213iwXDpfVvnskPXY/S0ZiFbsTjQZycuqPbMW8Gf/XhLfwE5njW8sxI2WjISURXPlHypMFA=="],
|
|
96
|
+
|
|
97
|
+
"@vellumai/service-contracts/typescript": ["typescript@5.7.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw=="],
|
|
98
|
+
|
|
93
99
|
"pino-pretty/pino-abstract-transport": ["pino-abstract-transport@3.0.0", "", { "dependencies": { "split2": "^4.0.0" } }, "sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg=="],
|
|
100
|
+
|
|
101
|
+
"@vellumai/service-contracts/@types/bun/bun-types": ["bun-types@1.2.4", "", { "dependencies": { "@types/node": "*", "@types/ws": "~8.5.10" } }, "sha512-nDPymR207ZZEoWD4AavvEaa/KZe/qlrbMSchqpQwovPZCKc7pwMoENjEtHgMKaAjJhy+x6vfqSBA1QU3bJgs0Q=="],
|
|
94
102
|
}
|
|
95
103
|
}
|
|
@@ -3,8 +3,13 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Ensures the package:
|
|
5
5
|
* 1. Does NOT import from the assistant daemon or CES modules.
|
|
6
|
-
* 2.
|
|
7
|
-
*
|
|
6
|
+
* 2. Does NOT import from x-client packages (@vellumai/assistant-client,
|
|
7
|
+
* @vellumai/ces-client, @vellumai/gateway-client).
|
|
8
|
+
* 3. Does NOT import from @vellumai/service-contracts runtime/internal modules
|
|
9
|
+
* (the aggregate root or any subpath beyond what credential-storage needs
|
|
10
|
+
* for pure type definitions is not required at all).
|
|
11
|
+
* 4. Exposes only local storage/runtime abstractions.
|
|
12
|
+
* 5. Remains portable and self-contained.
|
|
8
13
|
*/
|
|
9
14
|
|
|
10
15
|
import { describe, expect, test } from "bun:test";
|
|
@@ -59,6 +64,21 @@ const FORBIDDEN_IMPORT_PATTERNS = [
|
|
|
59
64
|
/from\s+["'].*\/tools\//,
|
|
60
65
|
/from\s+["'].*\/oauth\/oauth-store/,
|
|
61
66
|
/from\s+["'].*\/security\/secure-keys/,
|
|
67
|
+
|
|
68
|
+
// x-client packages (must not depend on any typed service client)
|
|
69
|
+
/from\s+["']@vellumai\/assistant-client(?:\/|["'])/,
|
|
70
|
+
/require\s*\(\s*["']@vellumai\/assistant-client(?:\/|["'])/,
|
|
71
|
+
/from\s+["']@vellumai\/ces-client(?:\/|["'])/,
|
|
72
|
+
/require\s*\(\s*["']@vellumai\/ces-client(?:\/|["'])/,
|
|
73
|
+
/from\s+["']@vellumai\/gateway-client(?:\/|["'])/,
|
|
74
|
+
/require\s*\(\s*["']@vellumai\/gateway-client(?:\/|["'])/,
|
|
75
|
+
|
|
76
|
+
// service-contracts aggregate root or internal subpaths
|
|
77
|
+
// credential-storage is a lower-layer package and must not depend on
|
|
78
|
+
// service-contracts (which sits at the same layer but deals with RPC
|
|
79
|
+
// protocol types, not storage abstractions).
|
|
80
|
+
/from\s+["']@vellumai\/service-contracts(?:\/|["'])/,
|
|
81
|
+
/require\s*\(\s*["']@vellumai\/service-contracts(?:\/|["'])/,
|
|
62
82
|
];
|
|
63
83
|
|
|
64
84
|
describe("package boundary", () => {
|
|
@@ -68,7 +88,7 @@ describe("package boundary", () => {
|
|
|
68
88
|
expect(sourceFiles.length).toBeGreaterThan(0);
|
|
69
89
|
});
|
|
70
90
|
|
|
71
|
-
test("does not import from assistant or
|
|
91
|
+
test("does not import from assistant, CES, x-client, or service-contracts modules", () => {
|
|
72
92
|
const violations: string[] = [];
|
|
73
93
|
|
|
74
94
|
for (const file of sourceFiles) {
|
|
@@ -101,7 +121,7 @@ describe("package boundary", () => {
|
|
|
101
121
|
expect(pkg.private).toBe(true);
|
|
102
122
|
});
|
|
103
123
|
|
|
104
|
-
test("package.json does not depend on assistant or
|
|
124
|
+
test("package.json does not depend on assistant, CES, x-client, or service-contracts packages", () => {
|
|
105
125
|
const pkg = JSON.parse(
|
|
106
126
|
readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"),
|
|
107
127
|
);
|
|
@@ -113,8 +133,14 @@ describe("package boundary", () => {
|
|
|
113
133
|
const forbidden = Object.keys(allDeps).filter(
|
|
114
134
|
(dep) =>
|
|
115
135
|
dep.includes("assistant") ||
|
|
116
|
-
dep.includes("
|
|
117
|
-
|
|
136
|
+
dep.includes("daemon") ||
|
|
137
|
+
[
|
|
138
|
+
"@vellumai/ces-client",
|
|
139
|
+
"@vellumai/ces-contracts",
|
|
140
|
+
"@vellumai/service-contracts",
|
|
141
|
+
"@vellumai/assistant-client",
|
|
142
|
+
"@vellumai/gateway-client",
|
|
143
|
+
].includes(dep),
|
|
118
144
|
);
|
|
119
145
|
expect(forbidden).toEqual([]);
|
|
120
146
|
});
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
* These tests ensure the egress-proxy package remains isolated from
|
|
5
5
|
* assistant runtime and CES server implementation modules. If a direct
|
|
6
6
|
* import of those modules is introduced, these tests will fail.
|
|
7
|
+
*
|
|
8
|
+
* Tightened boundaries (added):
|
|
9
|
+
* - Does NOT import from x-client packages (@vellumai/assistant-client,
|
|
10
|
+
* @vellumai/ces-client, @vellumai/gateway-client).
|
|
11
|
+
* - Does NOT import from @vellumai/service-contracts (the egress-proxy
|
|
12
|
+
* package deals only with proxy session lifecycle and must not depend on
|
|
13
|
+
* CES wire-protocol types).
|
|
7
14
|
*/
|
|
8
15
|
|
|
9
16
|
import { describe, expect, test } from "bun:test";
|
|
@@ -66,6 +73,25 @@ const FORBIDDEN_PATTERNS = [
|
|
|
66
73
|
/require\s*\(.*\/gateway\/src\//,
|
|
67
74
|
/import\s+['"].*\/gateway\/src\//,
|
|
68
75
|
/import\s+['"]@vellumai\/vellum-gateway/,
|
|
76
|
+
|
|
77
|
+
// x-client packages (must not depend on any typed service client)
|
|
78
|
+
/from\s+['"]@vellumai\/assistant-client(?:\/|['"])/,
|
|
79
|
+
/import\s+['"]@vellumai\/assistant-client(?:\/|['"])/,
|
|
80
|
+
/require\s*\(['"]@vellumai\/assistant-client(?:\/|['"])/,
|
|
81
|
+
/from\s+['"]@vellumai\/ces-client(?:\/|['"])/,
|
|
82
|
+
/import\s+['"]@vellumai\/ces-client(?:\/|['"])/,
|
|
83
|
+
/require\s*\(['"]@vellumai\/ces-client(?:\/|['"])/,
|
|
84
|
+
/from\s+['"]@vellumai\/gateway-client(?:\/|['"])/,
|
|
85
|
+
/import\s+['"]@vellumai\/gateway-client(?:\/|['"])/,
|
|
86
|
+
/require\s*\(['"]@vellumai\/gateway-client(?:\/|['"])/,
|
|
87
|
+
|
|
88
|
+
// service-contracts (RPC protocol types — egress-proxy must not depend on CES wire types)
|
|
89
|
+
/from\s+['"]@vellumai\/service-contracts(?:\/|['"])/,
|
|
90
|
+
/import\s+['"]@vellumai\/service-contracts(?:\/|['"])/,
|
|
91
|
+
/require\s*\(['"]@vellumai\/service-contracts(?:\/|['"])/,
|
|
92
|
+
/from\s+['"]@vellumai\/ces-contracts(?:\/|['"])/,
|
|
93
|
+
/import\s+['"]@vellumai\/ces-contracts(?:\/|['"])/,
|
|
94
|
+
/require\s*\(['"]@vellumai\/ces-contracts(?:\/|['"])/,
|
|
69
95
|
];
|
|
70
96
|
|
|
71
97
|
describe("package boundary", () => {
|
|
@@ -94,7 +120,7 @@ describe("package boundary", () => {
|
|
|
94
120
|
}
|
|
95
121
|
});
|
|
96
122
|
|
|
97
|
-
test("package.json has no dependencies on assistant, CES, or
|
|
123
|
+
test("package.json has no dependencies on assistant, CES, gateway, x-client, or service-contracts", async () => {
|
|
98
124
|
const pkgJsonPath = resolve(PKG_SRC, "..", "package.json");
|
|
99
125
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
100
126
|
|
|
@@ -109,6 +135,11 @@ describe("package boundary", () => {
|
|
|
109
135
|
"@vellumai/assistant",
|
|
110
136
|
"@vellumai/ces",
|
|
111
137
|
"@vellumai/vellum-gateway",
|
|
138
|
+
"@vellumai/assistant-client",
|
|
139
|
+
"@vellumai/ces-client",
|
|
140
|
+
"@vellumai/ces-contracts",
|
|
141
|
+
"@vellumai/gateway-client",
|
|
142
|
+
"@vellumai/service-contracts",
|
|
112
143
|
];
|
|
113
144
|
|
|
114
145
|
for (const dep of forbidden) {
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "@vellumai/
|
|
2
|
+
"name": "@vellumai/service-contracts",
|
|
3
3
|
"version": "0.0.1",
|
|
4
4
|
"private": true,
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"exports": {
|
|
8
8
|
".": "./src/index.ts",
|
|
9
|
+
"./credential-rpc": "./src/credential-rpc.ts",
|
|
10
|
+
"./trust-rules": "./src/trust-rules.ts",
|
|
9
11
|
"./handles": "./src/handles.ts",
|
|
10
12
|
"./grants": "./src/grants.ts",
|
|
11
13
|
"./rpc": "./src/rpc.ts",
|
|
12
14
|
"./rendering": "./src/rendering.ts",
|
|
13
|
-
"./
|
|
15
|
+
"./error": "./src/error.ts"
|
|
14
16
|
},
|
|
15
17
|
"scripts": {
|
|
16
18
|
"typecheck": "bunx tsc --noEmit",
|
package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tests for @vellumai/
|
|
2
|
+
* Tests for @vellumai/service-contracts
|
|
3
3
|
*
|
|
4
4
|
* These tests verify:
|
|
5
5
|
* 1. The package can be consumed independently (no assistant/ or CES imports).
|
|
@@ -30,6 +30,10 @@ describe("package independence", () => {
|
|
|
30
30
|
"../grants.ts",
|
|
31
31
|
"../rpc.ts",
|
|
32
32
|
"../rendering.ts",
|
|
33
|
+
"../transport.ts",
|
|
34
|
+
"../credential-rpc.ts",
|
|
35
|
+
"../trust-rules.ts",
|
|
36
|
+
"../error.ts",
|
|
33
37
|
];
|
|
34
38
|
|
|
35
39
|
for (const file of sourceFiles) {
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Package boundary tests for @vellumai/service-contracts.
|
|
3
|
+
*
|
|
4
|
+
* Ensures the package:
|
|
5
|
+
* 1. Does NOT import from assistant, gateway, credential-executor, or other
|
|
6
|
+
* service runtime modules.
|
|
7
|
+
* 2. Does NOT import from runtime shared packages that sit above it in the
|
|
8
|
+
* dependency hierarchy (@vellumai/credential-storage, @vellumai/egress-proxy,
|
|
9
|
+
* @vellumai/skill-host-contracts).
|
|
10
|
+
* 3. Does NOT import from x-client packages (@vellumai/assistant-client,
|
|
11
|
+
* @vellumai/ces-client, @vellumai/gateway-client).
|
|
12
|
+
* 4. Remains a pure schema/type package — no runtime dependencies beyond zod.
|
|
13
|
+
*
|
|
14
|
+
* @vellumai/service-contracts is the lowest layer of the shared packages
|
|
15
|
+
* hierarchy and must not depend on any higher-layer package.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { describe, expect, test } from "bun:test";
|
|
19
|
+
import { readFileSync, readdirSync, statSync } from "node:fs";
|
|
20
|
+
import { join, resolve } from "node:path";
|
|
21
|
+
|
|
22
|
+
const PACKAGE_ROOT = resolve(import.meta.dirname, "../..");
|
|
23
|
+
const SRC_DIR = join(PACKAGE_ROOT, "src");
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Recursively collect all .ts source files, excluding test and declaration files.
|
|
27
|
+
*/
|
|
28
|
+
function collectSourceFiles(dir: string): string[] {
|
|
29
|
+
const files: string[] = [];
|
|
30
|
+
for (const entry of readdirSync(dir)) {
|
|
31
|
+
const full = join(dir, entry);
|
|
32
|
+
const stat = statSync(full);
|
|
33
|
+
if (stat.isDirectory()) {
|
|
34
|
+
if (entry === "node_modules" || entry === "__tests__") continue;
|
|
35
|
+
files.push(...collectSourceFiles(full));
|
|
36
|
+
} else if (
|
|
37
|
+
entry.endsWith(".ts") &&
|
|
38
|
+
!entry.endsWith(".test.ts") &&
|
|
39
|
+
!entry.endsWith(".d.ts")
|
|
40
|
+
) {
|
|
41
|
+
files.push(full);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return files;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Patterns that must NOT appear in any import/require statement within
|
|
49
|
+
* source files. These catch imports from higher-layer packages that would
|
|
50
|
+
* create a forbidden upward dependency.
|
|
51
|
+
*/
|
|
52
|
+
const FORBIDDEN_IMPORT_PATTERNS = [
|
|
53
|
+
// Assistant runtime
|
|
54
|
+
/from\s+["'](?:\.\.\/)*assistant(?:\/|["'])/,
|
|
55
|
+
/require\s*\(\s*["'](?:\.\.\/)*assistant(?:\/|["'])/,
|
|
56
|
+
/from\s+["']@vellumai\/assistant(?:\/|["'])/,
|
|
57
|
+
/require\s*\(\s*["']@vellumai\/assistant(?:\/|["'])/,
|
|
58
|
+
|
|
59
|
+
// Gateway
|
|
60
|
+
/from\s+["'](?:\.\.\/)*gateway(?:\/|["'])/,
|
|
61
|
+
/require\s*\(\s*["'](?:\.\.\/)*gateway(?:\/|["'])/,
|
|
62
|
+
/from\s+["']@vellumai\/(?:vellum-)?gateway(?:\/|["'])/,
|
|
63
|
+
/require\s*\(\s*["']@vellumai\/(?:vellum-)?gateway(?:\/|["'])/,
|
|
64
|
+
|
|
65
|
+
// Credential executor
|
|
66
|
+
/from\s+["'](?:\.\.\/)*credential-executor(?:\/|["'])/,
|
|
67
|
+
/require\s*\(\s*["'](?:\.\.\/)*credential-executor(?:\/|["'])/,
|
|
68
|
+
/from\s+["']@vellumai\/credential-executor(?:\/|["'])/,
|
|
69
|
+
/require\s*\(\s*["']@vellumai\/credential-executor(?:\/|["'])/,
|
|
70
|
+
|
|
71
|
+
// Runtime shared packages (higher layer)
|
|
72
|
+
/from\s+["']@vellumai\/credential-storage(?:\/|["'])/,
|
|
73
|
+
/require\s*\(\s*["']@vellumai\/credential-storage(?:\/|["'])/,
|
|
74
|
+
/from\s+["']@vellumai\/egress-proxy(?:\/|["'])/,
|
|
75
|
+
/require\s*\(\s*["']@vellumai\/egress-proxy(?:\/|["'])/,
|
|
76
|
+
/from\s+["']@vellumai\/skill-host-contracts(?:\/|["'])/,
|
|
77
|
+
/require\s*\(\s*["']@vellumai\/skill-host-contracts(?:\/|["'])/,
|
|
78
|
+
|
|
79
|
+
// x-client packages (higher layer)
|
|
80
|
+
/from\s+["']@vellumai\/assistant-client(?:\/|["'])/,
|
|
81
|
+
/require\s*\(\s*["']@vellumai\/assistant-client(?:\/|["'])/,
|
|
82
|
+
/from\s+["']@vellumai\/ces-client(?:\/|["'])/,
|
|
83
|
+
/require\s*\(\s*["']@vellumai\/ces-client(?:\/|["'])/,
|
|
84
|
+
/from\s+["']@vellumai\/gateway-client(?:\/|["'])/,
|
|
85
|
+
/require\s*\(\s*["']@vellumai\/gateway-client(?:\/|["'])/,
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
describe("package boundary", () => {
|
|
89
|
+
const sourceFiles = collectSourceFiles(SRC_DIR);
|
|
90
|
+
|
|
91
|
+
test("has source files to validate", () => {
|
|
92
|
+
expect(sourceFiles.length).toBeGreaterThan(0);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("does not import from runtime or higher-layer packages", () => {
|
|
96
|
+
const violations: string[] = [];
|
|
97
|
+
|
|
98
|
+
for (const file of sourceFiles) {
|
|
99
|
+
const content = readFileSync(file, "utf-8");
|
|
100
|
+
const lines = content.split("\n");
|
|
101
|
+
|
|
102
|
+
for (let i = 0; i < lines.length; i++) {
|
|
103
|
+
const line = lines[i];
|
|
104
|
+
for (const pattern of FORBIDDEN_IMPORT_PATTERNS) {
|
|
105
|
+
if (pattern.test(line)) {
|
|
106
|
+
const relative = file.replace(PACKAGE_ROOT + "/", "");
|
|
107
|
+
violations.push(`${relative}:${i + 1}: ${line.trim()}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (violations.length > 0) {
|
|
114
|
+
throw new Error(
|
|
115
|
+
`Found ${violations.length} forbidden import(s) in service-contracts package:\n` +
|
|
116
|
+
violations.map((v) => ` - ${v}`).join("\n") +
|
|
117
|
+
"\n\n" +
|
|
118
|
+
"@vellumai/service-contracts is a pure schema/type package and must not\n" +
|
|
119
|
+
"import from runtime services or higher-layer packages.",
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
test("package.json declares it as private", () => {
|
|
125
|
+
const pkg = JSON.parse(
|
|
126
|
+
readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"),
|
|
127
|
+
);
|
|
128
|
+
expect(pkg.private).toBe(true);
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
test("package.json does not depend on runtime or higher-layer packages", () => {
|
|
132
|
+
const pkg = JSON.parse(
|
|
133
|
+
readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"),
|
|
134
|
+
);
|
|
135
|
+
const allDeps = {
|
|
136
|
+
...pkg.dependencies,
|
|
137
|
+
...pkg.devDependencies,
|
|
138
|
+
...pkg.peerDependencies,
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
const forbidden = Object.keys(allDeps).filter((dep) =>
|
|
142
|
+
[
|
|
143
|
+
"@vellumai/assistant",
|
|
144
|
+
"@vellumai/credential-storage",
|
|
145
|
+
"@vellumai/egress-proxy",
|
|
146
|
+
"@vellumai/skill-host-contracts",
|
|
147
|
+
"@vellumai/assistant-client",
|
|
148
|
+
"@vellumai/ces-client",
|
|
149
|
+
"@vellumai/gateway-client",
|
|
150
|
+
].includes(dep),
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
expect(forbidden).toEqual([]);
|
|
154
|
+
});
|
|
155
|
+
});
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vellumai/service-contracts/credential-rpc
|
|
3
|
+
*
|
|
4
|
+
* Domain entrypoint for the CES (Credential Execution Service) transport and
|
|
5
|
+
* RPC surface. Re-exports the transport/RPC/handles/grants/rendering/error
|
|
6
|
+
* contracts without the trust-rule helpers.
|
|
7
|
+
*
|
|
8
|
+
* Prefer this subpath over the root `.` import when you only need the
|
|
9
|
+
* credential RPC surface:
|
|
10
|
+
*
|
|
11
|
+
* import { CesRpcMethod, MakeAuthenticatedRequestSchema } from "@vellumai/service-contracts/credential-rpc";
|
|
12
|
+
*
|
|
13
|
+
* For trust-rule types use the dedicated subpath:
|
|
14
|
+
*
|
|
15
|
+
* import { TrustRule, parseTrustRule } from "@vellumai/service-contracts/trust-rules";
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
export * from "./transport.js";
|
|
19
|
+
export * from "./error.js";
|
|
20
|
+
export * from "./handles.js";
|
|
21
|
+
export * from "./grants.js";
|
|
22
|
+
export * from "./rendering.js";
|
|
23
|
+
export * from "./rpc.js";
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vellumai/service-contracts — aggregate export (compat entry point)
|
|
3
|
+
*
|
|
4
|
+
* This is a compatibility aggregate that re-exports everything from all
|
|
5
|
+
* submodules. Prefer the explicit domain subpaths for new code:
|
|
6
|
+
*
|
|
7
|
+
* - `@vellumai/service-contracts/credential-rpc` — transport, RPC, handles, grants, rendering, error
|
|
8
|
+
* - `@vellumai/service-contracts/trust-rules` — trust-rule types and parsing helpers
|
|
9
|
+
*
|
|
10
|
+
* Fine-grained subpaths are also available for low-friction migration:
|
|
11
|
+
* `./rpc`, `./handles`, `./grants`, `./rendering`, `./error`, `./trust-rules`
|
|
12
|
+
*
|
|
13
|
+
* Neutral wire-protocol contracts for communication between the assistant
|
|
14
|
+
* daemon and the Credential Execution Service (CES). This package is
|
|
15
|
+
* intentionally free of imports from `assistant/` or any CES implementation
|
|
16
|
+
* module so that both sides can depend on it without circular references.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
export * from "./transport.js";
|
|
20
|
+
export * from "./error.js";
|
|
21
|
+
export * from "./handles.js";
|
|
22
|
+
export * from "./grants.js";
|
|
23
|
+
export * from "./rpc.js";
|
|
24
|
+
export * from "./rendering.js";
|
|
25
|
+
export * from "./trust-rules.js";
|
package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts}
RENAMED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Transport-level handshake and envelope schemas.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* module so that both sides can depend on it without circular references.
|
|
4
|
+
* Extracted from the aggregate index to allow credential-rpc.ts to import
|
|
5
|
+
* the full transport surface without creating a circular dependency through
|
|
6
|
+
* index.ts.
|
|
8
7
|
*/
|
|
9
8
|
|
|
10
9
|
import { z } from "zod";
|
|
@@ -35,9 +34,8 @@ export const HandshakeRequestSchema = z.object({
|
|
|
35
34
|
assistantApiKey: z.string().optional(),
|
|
36
35
|
/**
|
|
37
36
|
* Optional platform assistant ID passed from the assistant runtime.
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
* so CES can use it for platform credential materialisation.
|
|
37
|
+
* The assistant ID is not available at CES startup (warm-pool pods),
|
|
38
|
+
* so the assistant forwards it here for platform credential materialisation.
|
|
41
39
|
*/
|
|
42
40
|
assistantId: z.string().optional(),
|
|
43
41
|
});
|
|
@@ -75,16 +73,6 @@ export const RpcEnvelopeSchema = z.object({
|
|
|
75
73
|
});
|
|
76
74
|
export type RpcEnvelope = z.infer<typeof RpcEnvelopeSchema>;
|
|
77
75
|
|
|
78
|
-
// ---------------------------------------------------------------------------
|
|
79
|
-
// RPC error (defined in error.ts to avoid circular deps with rpc.ts)
|
|
80
|
-
// ---------------------------------------------------------------------------
|
|
81
|
-
|
|
82
|
-
export {
|
|
83
|
-
RpcErrorSchema,
|
|
84
|
-
type RpcError,
|
|
85
|
-
MANAGED_LOCAL_STATIC_REJECTION_ERROR,
|
|
86
|
-
} from "./error.js";
|
|
87
|
-
|
|
88
76
|
// ---------------------------------------------------------------------------
|
|
89
77
|
// Tool request / response base shapes
|
|
90
78
|
// ---------------------------------------------------------------------------
|
|
@@ -143,13 +131,3 @@ export const TransportMessageSchema = z.discriminatedUnion("type", [
|
|
|
143
131
|
RpcEnvelopeSchema.extend({ type: z.literal("rpc") }),
|
|
144
132
|
]);
|
|
145
133
|
export type TransportMessage = z.infer<typeof TransportMessageSchema>;
|
|
146
|
-
|
|
147
|
-
// ---------------------------------------------------------------------------
|
|
148
|
-
// Re-exports from sub-modules
|
|
149
|
-
// ---------------------------------------------------------------------------
|
|
150
|
-
|
|
151
|
-
export * from "./handles.js";
|
|
152
|
-
export * from "./grants.js";
|
|
153
|
-
export * from "./rpc.js";
|
|
154
|
-
export * from "./rendering.js";
|
|
155
|
-
export * from "./trust-rules.js";
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trust rule types shared between the assistant daemon and the gateway.
|
|
3
|
+
*
|
|
4
|
+
* These are extracted from `assistant/src/permissions/types.ts` and
|
|
5
|
+
* `assistant/src/permissions/trust-store.ts` so that both packages can
|
|
6
|
+
* reference a single canonical definition.
|
|
7
|
+
*
|
|
8
|
+
* Tools are grouped into "families" based on how their permission candidates
|
|
9
|
+
* are constructed and matched:
|
|
10
|
+
*
|
|
11
|
+
* - **Scoped**: tools whose candidates include a filesystem path and obey
|
|
12
|
+
* directory-boundary scope constraints (`file_read`, `file_write`,
|
|
13
|
+
* `file_edit`, `host_file_read`, `host_file_write`, `host_file_edit`,
|
|
14
|
+
* `host_file_transfer`, `bash`, `host_bash`).
|
|
15
|
+
* - **URL**: tools whose candidates include a URL (`web_fetch`,
|
|
16
|
+
* `network_request`).
|
|
17
|
+
* - **Managed skill**: tools that manage first-party skill packages
|
|
18
|
+
* (`scaffold_managed_skill`, `delete_managed_skill`).
|
|
19
|
+
* - **Skill load**: the `skill_load` tool, which uses a distinct candidate
|
|
20
|
+
* namespace (`skill_load:selector` or `skill_load_dynamic:selector`).
|
|
21
|
+
* - **Generic**: everything else (computer-use tools, UI surface tools,
|
|
22
|
+
* recall, skill_execute, etc.).
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
// Trust decision
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
|
|
29
|
+
/** The possible decisions a trust rule can make. */
|
|
30
|
+
export type TrustDecision = "allow" | "deny" | "ask";
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Tool family constants
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Tools whose permission candidates are scoped to a filesystem path and obey
|
|
38
|
+
* directory-boundary scope constraints.
|
|
39
|
+
*/
|
|
40
|
+
export const SCOPED_TOOLS = [
|
|
41
|
+
"file_read",
|
|
42
|
+
"file_write",
|
|
43
|
+
"file_edit",
|
|
44
|
+
"host_file_read",
|
|
45
|
+
"host_file_write",
|
|
46
|
+
"host_file_edit",
|
|
47
|
+
"host_file_transfer",
|
|
48
|
+
"bash",
|
|
49
|
+
"host_bash",
|
|
50
|
+
] as const;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Tools whose permission candidates include a URL.
|
|
54
|
+
*/
|
|
55
|
+
export const URL_TOOLS = ["web_fetch", "network_request"] as const;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Tools that manage first-party skill packages (scaffold/delete).
|
|
59
|
+
*/
|
|
60
|
+
export const MANAGED_SKILL_TOOLS = [
|
|
61
|
+
"scaffold_managed_skill",
|
|
62
|
+
"delete_managed_skill",
|
|
63
|
+
] as const;
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* The skill_load tool name. Separated from the array constants because
|
|
67
|
+
* skill_load is a singleton, not a family with multiple members.
|
|
68
|
+
*/
|
|
69
|
+
export const SKILL_LOAD_TOOL = "skill_load" as const;
|
|
70
|
+
|
|
71
|
+
/** Set for O(1) lookups when classifying tool names. */
|
|
72
|
+
const SCOPED_TOOLS_SET: ReadonlySet<string> = new Set(SCOPED_TOOLS);
|
|
73
|
+
const URL_TOOLS_SET: ReadonlySet<string> = new Set(URL_TOOLS);
|
|
74
|
+
const MANAGED_SKILL_TOOLS_SET: ReadonlySet<string> = new Set(
|
|
75
|
+
MANAGED_SKILL_TOOLS,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// ---------------------------------------------------------------------------
|
|
79
|
+
// Type guards
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
|
|
82
|
+
/** Returns true when the rule's tool belongs to the scoped-tool family. */
|
|
83
|
+
export function isScopedRule(rule: { tool: string }): boolean {
|
|
84
|
+
return SCOPED_TOOLS_SET.has(rule.tool);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** Returns true when the rule's tool belongs to the URL-tool family. */
|
|
88
|
+
export function isUrlRule(rule: { tool: string }): boolean {
|
|
89
|
+
return URL_TOOLS_SET.has(rule.tool);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Returns true when the rule's tool belongs to the managed-skill-tool family. */
|
|
93
|
+
export function isManagedSkillRule(rule: { tool: string }): boolean {
|
|
94
|
+
return MANAGED_SKILL_TOOLS_SET.has(rule.tool);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Returns true when the rule's tool is the skill_load tool. */
|
|
98
|
+
export function isSkillLoadRule(rule: { tool: string }): boolean {
|
|
99
|
+
return rule.tool === SKILL_LOAD_TOOL;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// ---------------------------------------------------------------------------
|
|
103
|
+
// Scope helper
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Return the effective scope for any trust rule. Only scoped rules carry a
|
|
108
|
+
* `scope` field; all other rule families return `"everywhere"`.
|
|
109
|
+
*/
|
|
110
|
+
export function ruleScope(rule: { tool: string; scope?: string }): string {
|
|
111
|
+
if (isScopedRule(rule)) {
|
|
112
|
+
return rule.scope ?? "everywhere";
|
|
113
|
+
}
|
|
114
|
+
return "everywhere";
|
|
115
|
+
}
|
|
116
|
+
|