@vellumai/credential-executor 0.10.7 → 0.10.8-dev.202607102228.5945895
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/node_modules/@vellumai/service-contracts/package.json +1 -2
- package/node_modules/@vellumai/service-contracts/src/__tests__/attachment-naming.test.ts +104 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +0 -2
- package/node_modules/@vellumai/service-contracts/src/attachment-naming.ts +118 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +3 -5
- package/node_modules/@vellumai/service-contracts/src/index.ts +2 -4
- package/node_modules/@vellumai/service-contracts/src/rpc.ts +4 -447
- package/package.json +2 -3
- package/src/__tests__/bulk-set-credentials.test.ts +1 -1
- package/src/__tests__/local-standalone.test.ts +5 -36
- package/src/__tests__/managed-integration.test.ts +112 -91
- package/src/__tests__/managed-reconnect.test.ts +2 -2
- package/src/__tests__/transport.test.ts +23 -27
- package/src/cli.ts +1 -1
- package/src/index.ts +8 -88
- package/src/main.ts +228 -340
- package/src/paths.ts +4 -20
- package/src/server.ts +52 -469
- package/node_modules/@vellumai/service-contracts/src/__tests__/grants.test.ts +0 -686
- package/node_modules/@vellumai/service-contracts/src/grants.ts +0 -184
- package/node_modules/@vellumai/service-contracts/src/rendering.ts +0 -135
- package/src/__tests__/command-executor.test.ts +0 -1879
- package/src/__tests__/command-validator.test.ts +0 -1405
- package/src/__tests__/command-workspace.test.ts +0 -1050
- package/src/__tests__/grant-store.test.ts +0 -689
- package/src/__tests__/http-executor.test.ts +0 -1336
- package/src/__tests__/http-policy.test.ts +0 -1069
- package/src/__tests__/local-materializers.test.ts +0 -860
- package/src/__tests__/local-token-refresh.test.ts +0 -361
- package/src/__tests__/manage-secure-command-tool.test.ts +0 -134
- package/src/__tests__/managed-lazy-getters.test.ts +0 -359
- package/src/__tests__/managed-materializers.test.ts +0 -1028
- package/src/__tests__/managed-rejection.test.ts +0 -43
- package/src/__tests__/toolstore.test.ts +0 -773
- package/src/audit/store.ts +0 -188
- package/src/commands/auth-adapters.ts +0 -169
- package/src/commands/egress-hooks.ts +0 -203
- package/src/commands/executor.ts +0 -1155
- package/src/commands/output-scan.ts +0 -157
- package/src/commands/profiles.ts +0 -286
- package/src/commands/validator.ts +0 -702
- package/src/commands/workspace.ts +0 -550
- package/src/grants/index.ts +0 -17
- package/src/grants/persistent-store.ts +0 -309
- package/src/grants/rpc-handlers.ts +0 -293
- package/src/grants/temporary-store.ts +0 -289
- package/src/http/audit.ts +0 -84
- package/src/http/executor.ts +0 -684
- package/src/http/path-template.ts +0 -245
- package/src/http/policy.ts +0 -238
- package/src/http/response-filter.ts +0 -233
- package/src/managed-errors.ts +0 -9
- package/src/managed-lazy-getters.ts +0 -106
- package/src/managed-main.ts +0 -822
- package/src/materializers/local-oauth-lookup.ts +0 -98
- package/src/materializers/local-token-refresh.ts +0 -287
- package/src/materializers/local.ts +0 -316
- package/src/materializers/managed-platform.ts +0 -295
- package/src/subjects/local.ts +0 -177
- package/src/subjects/managed.ts +0 -311
- package/src/subjects/policy.ts +0 -79
- package/src/toolstore/integrity.ts +0 -94
- package/src/toolstore/manifest.ts +0 -154
- package/src/toolstore/publish.ts +0 -571
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* CES grant proposal, grant record, and audit record schemas.
|
|
3
|
-
*
|
|
4
|
-
* These schemas define the wire format for:
|
|
5
|
-
* - HTTP grant proposals (requesting permission to make an authenticated HTTP call)
|
|
6
|
-
* - Command grant proposals (requesting permission to run an authenticated command)
|
|
7
|
-
* - Temporary grant decisions (approval/denial from a guardian)
|
|
8
|
-
* - Persistent grant records (stored by CES after approval)
|
|
9
|
-
* - Audit record summaries (materialization events)
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { z } from "zod";
|
|
13
|
-
|
|
14
|
-
// ---------------------------------------------------------------------------
|
|
15
|
-
// Grant proposal types
|
|
16
|
-
// ---------------------------------------------------------------------------
|
|
17
|
-
|
|
18
|
-
/**
|
|
19
|
-
* Proposal to make an authenticated HTTP request using a credential.
|
|
20
|
-
*/
|
|
21
|
-
export const HttpGrantProposalSchema = z.object({
|
|
22
|
-
type: z.literal("http"),
|
|
23
|
-
/** CES credential handle identifying which credential to use. */
|
|
24
|
-
credentialHandle: z.string(),
|
|
25
|
-
/** HTTP method (e.g. "GET", "POST"). */
|
|
26
|
-
method: z.string(),
|
|
27
|
-
/** Target URL. */
|
|
28
|
-
url: z.string(),
|
|
29
|
-
/** Human-readable description of why this request is needed. */
|
|
30
|
-
purpose: z.string(),
|
|
31
|
-
/** Optional constrained set of URL patterns this grant covers. */
|
|
32
|
-
allowedUrlPatterns: z.array(z.string()).optional(),
|
|
33
|
-
});
|
|
34
|
-
export type HttpGrantProposal = z.infer<typeof HttpGrantProposalSchema>;
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Proposal to run an authenticated command using credential environment variables.
|
|
38
|
-
*/
|
|
39
|
-
export const CommandGrantProposalSchema = z.object({
|
|
40
|
-
type: z.literal("command"),
|
|
41
|
-
/** CES credential handle identifying which credential to use. */
|
|
42
|
-
credentialHandle: z.string(),
|
|
43
|
-
/** The command to execute (without credential values — CES injects those). */
|
|
44
|
-
command: z.string(),
|
|
45
|
-
/** Human-readable description of why this command is needed. */
|
|
46
|
-
purpose: z.string(),
|
|
47
|
-
/** Optional constrained set of command patterns this grant covers. */
|
|
48
|
-
allowedCommandPatterns: z.array(z.string()).optional(),
|
|
49
|
-
});
|
|
50
|
-
export type CommandGrantProposal = z.infer<typeof CommandGrantProposalSchema>;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Union of all grant proposal types.
|
|
54
|
-
*/
|
|
55
|
-
export const GrantProposalSchema = z.discriminatedUnion("type", [
|
|
56
|
-
HttpGrantProposalSchema,
|
|
57
|
-
CommandGrantProposalSchema,
|
|
58
|
-
]);
|
|
59
|
-
export type GrantProposal = z.infer<typeof GrantProposalSchema>;
|
|
60
|
-
|
|
61
|
-
// ---------------------------------------------------------------------------
|
|
62
|
-
// Grant decisions (temporary — before persistence)
|
|
63
|
-
// ---------------------------------------------------------------------------
|
|
64
|
-
|
|
65
|
-
export const GrantDecision = {
|
|
66
|
-
Approved: "approved",
|
|
67
|
-
Denied: "denied",
|
|
68
|
-
} as const;
|
|
69
|
-
|
|
70
|
-
export type GrantDecision = (typeof GrantDecision)[keyof typeof GrantDecision];
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* A temporary grant decision from a guardian, before CES persists it.
|
|
74
|
-
*/
|
|
75
|
-
export const TemporaryGrantDecisionSchema = z.object({
|
|
76
|
-
/** The proposal this decision applies to. */
|
|
77
|
-
proposal: GrantProposalSchema,
|
|
78
|
-
/** Deterministic hash of the proposal (see rendering.ts). */
|
|
79
|
-
proposalHash: z.string(),
|
|
80
|
-
/** The guardian's decision. */
|
|
81
|
-
decision: z.enum(["approved", "denied"]),
|
|
82
|
-
/** Who made the decision (guardian identifier). */
|
|
83
|
-
decidedBy: z.string(),
|
|
84
|
-
/** ISO-8601 timestamp of the decision. */
|
|
85
|
-
decidedAt: z.string(),
|
|
86
|
-
/** Optional human-readable reason for the decision. */
|
|
87
|
-
reason: z.string().optional(),
|
|
88
|
-
/** How long the grant should remain valid (ISO-8601 duration, e.g. "PT1H"). */
|
|
89
|
-
ttl: z.string().optional(),
|
|
90
|
-
/**
|
|
91
|
-
* The type of grant to create. Determines persistence behaviour:
|
|
92
|
-
* - `allow_once`: Temporary single-use grant (consumed after one use)
|
|
93
|
-
* - `allow_10m`: Temporary timed grant (10-minute TTL)
|
|
94
|
-
* - `allow_conversation`: Temporary conversation-scoped grant (lives for conversation)
|
|
95
|
-
* - `always_allow`: Persistent grant (survives restart)
|
|
96
|
-
*
|
|
97
|
-
* When omitted, defaults to `always_allow` for backwards compatibility.
|
|
98
|
-
*/
|
|
99
|
-
grantType: z.enum(["allow_once", "allow_10m", "allow_conversation", "always_allow"]).optional(),
|
|
100
|
-
});
|
|
101
|
-
export type TemporaryGrantDecision = z.infer<
|
|
102
|
-
typeof TemporaryGrantDecisionSchema
|
|
103
|
-
>;
|
|
104
|
-
|
|
105
|
-
// ---------------------------------------------------------------------------
|
|
106
|
-
// Persistent grant records (CES-owned)
|
|
107
|
-
// ---------------------------------------------------------------------------
|
|
108
|
-
|
|
109
|
-
export const GrantStatus = {
|
|
110
|
-
Active: "active",
|
|
111
|
-
Expired: "expired",
|
|
112
|
-
Revoked: "revoked",
|
|
113
|
-
Consumed: "consumed",
|
|
114
|
-
} as const;
|
|
115
|
-
|
|
116
|
-
export type GrantStatus = (typeof GrantStatus)[keyof typeof GrantStatus];
|
|
117
|
-
|
|
118
|
-
/**
|
|
119
|
-
* A persistent grant record stored by CES.
|
|
120
|
-
*
|
|
121
|
-
* Grants authorize a specific agent connection to use a credential for a
|
|
122
|
-
* constrained purpose. They are never sent to the assistant with secret
|
|
123
|
-
* values — only metadata.
|
|
124
|
-
*/
|
|
125
|
-
export const PersistentGrantRecordSchema = z.object({
|
|
126
|
-
/** Unique grant identifier. */
|
|
127
|
-
grantId: z.string(),
|
|
128
|
-
/** The CES connection that created this grant. */
|
|
129
|
-
sessionId: z.string(),
|
|
130
|
-
/** The credential handle this grant authorizes. */
|
|
131
|
-
credentialHandle: z.string(),
|
|
132
|
-
/** The proposal type (http or command). */
|
|
133
|
-
proposalType: z.enum(["http", "command"]),
|
|
134
|
-
/** Deterministic hash of the original proposal. */
|
|
135
|
-
proposalHash: z.string(),
|
|
136
|
-
/** Constrained purposes — URL patterns for HTTP, command patterns for commands. */
|
|
137
|
-
allowedPurposes: z.array(z.string()),
|
|
138
|
-
/** Current grant status. */
|
|
139
|
-
status: z.enum(["active", "expired", "revoked", "consumed"]),
|
|
140
|
-
/** Who approved the grant. */
|
|
141
|
-
grantedBy: z.string(),
|
|
142
|
-
/** ISO-8601 timestamp when the grant was created. */
|
|
143
|
-
createdAt: z.string(),
|
|
144
|
-
/** ISO-8601 timestamp when the grant expires (null if no expiry). */
|
|
145
|
-
expiresAt: z.string().nullable(),
|
|
146
|
-
/** ISO-8601 timestamp when the grant was consumed (null if unconsumed). */
|
|
147
|
-
consumedAt: z.string().nullable(),
|
|
148
|
-
/** ISO-8601 timestamp when the grant was revoked (null if active). */
|
|
149
|
-
revokedAt: z.string().nullable(),
|
|
150
|
-
});
|
|
151
|
-
export type PersistentGrantRecord = z.infer<typeof PersistentGrantRecordSchema>;
|
|
152
|
-
|
|
153
|
-
// ---------------------------------------------------------------------------
|
|
154
|
-
// Audit record summaries
|
|
155
|
-
// ---------------------------------------------------------------------------
|
|
156
|
-
|
|
157
|
-
/**
|
|
158
|
-
* Summary of a credential materialization event, as exposed by CES
|
|
159
|
-
* for audit inspection.
|
|
160
|
-
*
|
|
161
|
-
* Audit records never contain secret values — only metadata about what
|
|
162
|
-
* was accessed, when, by whom, and whether it succeeded.
|
|
163
|
-
*/
|
|
164
|
-
export const AuditRecordSummarySchema = z.object({
|
|
165
|
-
/** Unique audit record identifier. */
|
|
166
|
-
auditId: z.string(),
|
|
167
|
-
/** The grant that authorized this materialization. */
|
|
168
|
-
grantId: z.string(),
|
|
169
|
-
/** The credential handle that was materialized. */
|
|
170
|
-
credentialHandle: z.string(),
|
|
171
|
-
/** The tool that triggered materialization. */
|
|
172
|
-
toolName: z.string(),
|
|
173
|
-
/** Target of the operation (URL for HTTP, command summary for commands). */
|
|
174
|
-
target: z.string(),
|
|
175
|
-
/** The CES connection that triggered materialization. */
|
|
176
|
-
sessionId: z.string(),
|
|
177
|
-
/** Whether the execution succeeded. */
|
|
178
|
-
success: z.boolean(),
|
|
179
|
-
/** Error message if execution failed (no secrets). */
|
|
180
|
-
errorMessage: z.string().optional(),
|
|
181
|
-
/** ISO-8601 timestamp of the materialization event. */
|
|
182
|
-
timestamp: z.string(),
|
|
183
|
-
});
|
|
184
|
-
export type AuditRecordSummary = z.infer<typeof AuditRecordSummarySchema>;
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Canonical proposal rendering and deterministic hashing.
|
|
3
|
-
*
|
|
4
|
-
* Both the assistant and CES must produce identical human-readable text and
|
|
5
|
-
* proposal hashes for the same proposal object. This module provides the
|
|
6
|
-
* shared implementations so neither side has to duplicate the logic.
|
|
7
|
-
*
|
|
8
|
-
* Hashing algorithm:
|
|
9
|
-
* 1. Recursively sort object keys (depth-first).
|
|
10
|
-
* 2. Serialize to a canonical JSON string with no whitespace.
|
|
11
|
-
* 3. SHA-256 hash the UTF-8 bytes and return a lowercase hex digest.
|
|
12
|
-
*
|
|
13
|
-
* This matches the algorithm used by `tool-approval-digest.ts` in the
|
|
14
|
-
* assistant, ensuring consistency across the approval pipeline.
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { createHash } from "node:crypto";
|
|
18
|
-
import type { GrantProposal } from "./grants.js";
|
|
19
|
-
|
|
20
|
-
// ---------------------------------------------------------------------------
|
|
21
|
-
// Canonical JSON serialization
|
|
22
|
-
// ---------------------------------------------------------------------------
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Recursively sort all object keys and return a deterministic JSON string.
|
|
26
|
-
*
|
|
27
|
-
* Handles nested objects, arrays (element order preserved), and primitive
|
|
28
|
-
* values. `undefined` values inside objects are omitted (matching
|
|
29
|
-
* JSON.stringify semantics). `null` is preserved.
|
|
30
|
-
*/
|
|
31
|
-
export function canonicalJsonSerialize(value: unknown): string {
|
|
32
|
-
return JSON.stringify(sortKeysDeep(value));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function sortKeysDeep(value: unknown): unknown {
|
|
36
|
-
if (value == null) return value;
|
|
37
|
-
|
|
38
|
-
if (Array.isArray(value)) {
|
|
39
|
-
return value.map(sortKeysDeep);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
if (typeof value === "object") {
|
|
43
|
-
const sorted: Record<string, unknown> = {};
|
|
44
|
-
const keys = Object.keys(value as Record<string, unknown>).sort();
|
|
45
|
-
for (const key of keys) {
|
|
46
|
-
sorted[key] = sortKeysDeep((value as Record<string, unknown>)[key]);
|
|
47
|
-
}
|
|
48
|
-
return sorted;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// Primitive — number, string, boolean
|
|
52
|
-
return value;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// ---------------------------------------------------------------------------
|
|
56
|
-
// Proposal hashing
|
|
57
|
-
// ---------------------------------------------------------------------------
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* Compute a deterministic SHA-256 hex digest for a grant proposal.
|
|
61
|
-
*
|
|
62
|
-
* Two proposals with the same canonical content (regardless of key ordering)
|
|
63
|
-
* will always produce the same hash. This hash is used to match grant
|
|
64
|
-
* decisions to proposals in the approval pipeline.
|
|
65
|
-
*/
|
|
66
|
-
export function hashProposal(proposal: GrantProposal): string {
|
|
67
|
-
const canonical = canonicalJsonSerialize(proposal);
|
|
68
|
-
return createHash("sha256").update(canonical, "utf8").digest("hex");
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// ---------------------------------------------------------------------------
|
|
72
|
-
// Human-readable proposal rendering
|
|
73
|
-
// ---------------------------------------------------------------------------
|
|
74
|
-
|
|
75
|
-
/**
|
|
76
|
-
* Render a grant proposal as a human-readable text block suitable for
|
|
77
|
-
* display in approval UIs and guardian notifications.
|
|
78
|
-
*
|
|
79
|
-
* The rendering is deterministic for the same proposal, so both assistant
|
|
80
|
-
* and CES produce identical text.
|
|
81
|
-
*/
|
|
82
|
-
export function renderProposal(proposal: GrantProposal): string {
|
|
83
|
-
switch (proposal.type) {
|
|
84
|
-
case "http":
|
|
85
|
-
return renderHttpProposal(proposal);
|
|
86
|
-
case "command":
|
|
87
|
-
return renderCommandProposal(proposal);
|
|
88
|
-
default: {
|
|
89
|
-
const _exhaustive: never = proposal;
|
|
90
|
-
throw new Error(`Unknown proposal type: ${(_exhaustive as GrantProposal).type}`);
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
function renderHttpProposal(proposal: GrantProposal & { type: "http" }): string {
|
|
96
|
-
const lines: string[] = [
|
|
97
|
-
`Authenticated HTTP Request`,
|
|
98
|
-
` Method: ${proposal.method}`,
|
|
99
|
-
` URL: ${proposal.url}`,
|
|
100
|
-
` Credential: ${proposal.credentialHandle}`,
|
|
101
|
-
` Purpose: ${proposal.purpose}`,
|
|
102
|
-
];
|
|
103
|
-
|
|
104
|
-
if (proposal.allowedUrlPatterns && proposal.allowedUrlPatterns.length > 0) {
|
|
105
|
-
lines.push(` Allowed URL patterns:`);
|
|
106
|
-
for (const pattern of proposal.allowedUrlPatterns) {
|
|
107
|
-
lines.push(` - ${pattern}`);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return lines.join("\n");
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
function renderCommandProposal(
|
|
115
|
-
proposal: GrantProposal & { type: "command" },
|
|
116
|
-
): string {
|
|
117
|
-
const lines: string[] = [
|
|
118
|
-
`Authenticated Command Execution`,
|
|
119
|
-
` Command: ${proposal.command}`,
|
|
120
|
-
` Credential: ${proposal.credentialHandle}`,
|
|
121
|
-
` Purpose: ${proposal.purpose}`,
|
|
122
|
-
];
|
|
123
|
-
|
|
124
|
-
if (
|
|
125
|
-
proposal.allowedCommandPatterns &&
|
|
126
|
-
proposal.allowedCommandPatterns.length > 0
|
|
127
|
-
) {
|
|
128
|
-
lines.push(` Allowed command patterns:`);
|
|
129
|
-
for (const pattern of proposal.allowedCommandPatterns) {
|
|
130
|
-
lines.push(` - ${pattern}`);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
return lines.join("\n");
|
|
135
|
-
}
|