@vellumai/vellum-gateway 0.7.3 → 0.8.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/AGENTS.md +10 -0
- package/Dockerfile +4 -2
- package/bun.lock +8 -1
- package/knip.json +1 -0
- package/package.json +2 -1
- package/src/__tests__/contact-prompt-submit.test.ts +5 -5
- package/src/__tests__/contact-store-mark-channel-verified.test.ts +177 -0
- package/src/__tests__/contacts-control-plane-proxy.test.ts +297 -6
- package/src/__tests__/contacts-control-plane-route-match.test.ts +16 -0
- package/src/__tests__/edge-auth.test.ts +253 -0
- package/src/__tests__/edge-guardian-auth.test.ts +198 -0
- package/src/__tests__/ipc-route-policy-coverage.test.ts +297 -0
- package/src/__tests__/ipc-route-policy.test.ts +43 -0
- package/src/__tests__/ipc-server-watchdog.test.ts +189 -0
- package/src/__tests__/live-voice-websocket.test.ts +1 -1
- package/src/__tests__/slack-normalize.test.ts +132 -0
- package/src/auth/guardian-bootstrap.ts +3 -1
- package/src/auth/ipc-route-policy.ts +34 -0
- package/src/db/assistant-db-proxy.ts +76 -7
- package/src/db/contact-store.ts +767 -1
- package/src/db/schema.ts +29 -0
- package/src/feature-flag-registry.json +17 -17
- package/src/handlers/handle-inbound.ts +9 -23
- package/src/http/middleware/auth.ts +193 -40
- package/src/http/router.ts +26 -4
- package/src/http/routes/channel-verification-session-proxy.ts +53 -6
- package/src/http/routes/contact-prompt.ts +44 -15
- package/src/http/routes/contacts-control-plane-proxy.ts +329 -2
- package/src/http/routes/contacts-control-plane-route-match.ts +12 -0
- package/src/http/routes/ipc-runtime-proxy.test.ts +38 -43
- package/src/http/routes/ipc-runtime-proxy.ts +2 -2
- package/src/http/routes/log-export.test.ts +1 -0
- package/src/http/routes/log-export.ts +9 -2
- package/src/http/routes/log-tail.test.ts +10 -9
- package/src/http/routes/log-tail.ts +5 -2
- package/src/http/routes/pair.ts +8 -0
- package/src/http/routes/twilio-voice-webhook.ts +11 -2
- package/src/index.ts +98 -13
- package/src/ipc/assistant-client.test.ts +67 -15
- package/src/ipc/assistant-client.ts +12 -118
- package/src/ipc/risk-classification-handlers.test.ts +76 -0
- package/src/ipc/risk-classification-handlers.ts +20 -9
- package/src/ipc/server.ts +113 -46
- package/src/logger.ts +71 -17
- package/src/post-assistant-ready.ts +9 -3
- package/src/risk/bash-risk-classifier.test.ts +106 -0
- package/src/risk/bash-risk-classifier.ts +19 -15
- package/src/risk/command-registry/commands/assistant.ts +75 -26
- package/src/risk/command-registry.test.ts +3 -1
- package/src/risk/shell-parser.test.ts +159 -0
- package/src/risk/shell-parser.ts +150 -19
- package/src/runtime/client.ts +0 -11
- package/src/schema.ts +32 -0
- package/src/slack/normalize.test.ts +5 -0
- package/src/slack/normalize.ts +7 -0
- package/src/velay/bridge-utils.ts +10 -0
- package/src/velay/client.test.ts +156 -0
- package/src/velay/client.ts +83 -0
- package/src/velay/http-bridge.test.ts +29 -0
- package/src/velay/http-bridge.ts +7 -0
- package/src/velay/protocol.ts +12 -1
- package/src/verification/outbound-voice-verification-sync.ts +171 -0
- package/src/verification/voice-approval-sync.ts +107 -0
|
@@ -98,7 +98,9 @@ interface GuardianLookupRow {
|
|
|
98
98
|
* Find the existing guardian contact for the "vellum" channel.
|
|
99
99
|
* Mirrors assistant's `findGuardianForChannel("vellum")`.
|
|
100
100
|
*/
|
|
101
|
-
async function findVellumGuardian(): Promise<{
|
|
101
|
+
export async function findVellumGuardian(): Promise<{
|
|
102
|
+
principalId: string;
|
|
103
|
+
} | null> {
|
|
102
104
|
const rows = await assistantDbQuery<GuardianLookupRow>(
|
|
103
105
|
`SELECT c.id AS contact_id, c.principal_id
|
|
104
106
|
FROM contacts c
|
|
@@ -48,12 +48,34 @@ type PolicyEntry =
|
|
|
48
48
|
*/
|
|
49
49
|
const POLICY_TABLE: PolicyEntry[] = [
|
|
50
50
|
// Admin / internal
|
|
51
|
+
//
|
|
52
|
+
// Every operationId whose daemon-side route policy is gateway-only
|
|
53
|
+
// (`allowedPrincipalTypes: ["svc_gateway"]` in
|
|
54
|
+
// `assistant/src/runtime/auth/route-policy.ts`) MUST have a matching
|
|
55
|
+
// entry here. The gateway IPC proxy default-allows operationIds with
|
|
56
|
+
// no policy entry, so an authenticated edge JWT could otherwise reach
|
|
57
|
+
// them by setting `X-Vellum-Proxy-Server: ipc`, bypassing the daemon
|
|
58
|
+
// HTTP router entirely.
|
|
59
|
+
//
|
|
60
|
+
// The `ipc-route-policy-coverage.test.ts` lint enforces this invariant
|
|
61
|
+
// by walking the daemon route source files at test time.
|
|
51
62
|
["admin_rollbackmigrations_post", ["internal.write"], ["svc_gateway"]],
|
|
63
|
+
["channel_inbound", ["ingress.write"], ["svc_gateway"]],
|
|
64
|
+
["emit_event", ["internal.write"], ["svc_gateway"]],
|
|
65
|
+
["internal_mcp_add", ["internal.write"], ["svc_gateway"]],
|
|
52
66
|
["internal_mcp_auth_start", ["internal.write"], ["svc_gateway"]],
|
|
53
67
|
["internal_mcp_auth_status", ["internal.write"], ["svc_gateway"]],
|
|
68
|
+
["internal_mcp_list", ["internal.write"], ["svc_gateway"]],
|
|
54
69
|
["internal_mcp_reload", ["internal.write"], ["svc_gateway"]],
|
|
70
|
+
["internal_mcp_remove", ["internal.write"], ["svc_gateway"]],
|
|
71
|
+
["internal_oauth_callback", ["internal.write"], ["svc_gateway"]],
|
|
55
72
|
["internal_oauth_connect_start", ["internal.write"], ["svc_gateway"]],
|
|
56
73
|
["internal_oauth_connect_status", ["internal.write"], ["svc_gateway"]],
|
|
74
|
+
["internal_twilio_connect_action", ["internal.write"], ["svc_gateway"]],
|
|
75
|
+
["internal_twilio_status", ["internal.write"], ["svc_gateway"]],
|
|
76
|
+
["internal_twilio_voice_webhook", ["internal.write"], ["svc_gateway"]],
|
|
77
|
+
["upgrade_broadcast", ["internal.write"], ["svc_gateway"]],
|
|
78
|
+
["workspace_commit", ["internal.write"], ["svc_gateway"]],
|
|
57
79
|
|
|
58
80
|
// Calls
|
|
59
81
|
["calls_answer", ["calls.write"]],
|
|
@@ -134,6 +156,18 @@ const POLICY_TABLE: PolicyEntry[] = [
|
|
|
134
156
|
["listMemoryItems", ["settings.read"]],
|
|
135
157
|
["updateMemoryItem", ["settings.write"]],
|
|
136
158
|
|
|
159
|
+
// Inference profile sessions
|
|
160
|
+
["inference_profile_close", ["chat.write"]],
|
|
161
|
+
["inference_profile_list", ["chat.read"]],
|
|
162
|
+
["inference_profile_open", ["chat.write"]],
|
|
163
|
+
|
|
164
|
+
// Inference provider connections
|
|
165
|
+
["inference_provider_connections_create", ["settings.write"]],
|
|
166
|
+
["inference_provider_connections_delete", ["settings.write"]],
|
|
167
|
+
["inference_provider_connections_get", ["settings.read"]],
|
|
168
|
+
["inference_provider_connections_list", ["settings.read"]],
|
|
169
|
+
["inference_provider_connections_update", ["settings.write"]],
|
|
170
|
+
|
|
137
171
|
// Notification intent
|
|
138
172
|
["notificationintentresult_post", ["settings.write"]],
|
|
139
173
|
|
|
@@ -13,9 +13,12 @@
|
|
|
13
13
|
* gateway's own database.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
IpcHandlerError,
|
|
18
|
+
ipcCallAssistant,
|
|
19
|
+
} from "../ipc/assistant-client.js";
|
|
17
20
|
|
|
18
|
-
type SqliteValue = string | number | null | Uint8Array;
|
|
21
|
+
export type SqliteValue = string | number | null | Uint8Array;
|
|
19
22
|
|
|
20
23
|
interface DbProxyResult {
|
|
21
24
|
rows?: Record<string, SqliteValue>[];
|
|
@@ -28,11 +31,11 @@ async function dbProxy(
|
|
|
28
31
|
mode: "query" | "run" | "exec",
|
|
29
32
|
bind?: SqliteValue[],
|
|
30
33
|
): Promise<DbProxyResult> {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
return (await ipcCallAssistant("db_proxy", {
|
|
35
|
+
sql,
|
|
36
|
+
mode,
|
|
37
|
+
bind,
|
|
38
|
+
})) as DbProxyResult;
|
|
36
39
|
}
|
|
37
40
|
|
|
38
41
|
/**
|
|
@@ -66,3 +69,69 @@ export async function assistantDbRun(
|
|
|
66
69
|
export async function assistantDbExec(sql: string): Promise<void> {
|
|
67
70
|
await dbProxy(sql, "exec");
|
|
68
71
|
}
|
|
72
|
+
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
// Transaction helper
|
|
75
|
+
// ---------------------------------------------------------------------------
|
|
76
|
+
|
|
77
|
+
export interface AssistantDbTransactionStep {
|
|
78
|
+
/** The SQL write statement to execute. */
|
|
79
|
+
sql: string;
|
|
80
|
+
/** Positional bind parameters. */
|
|
81
|
+
bind?: SqliteValue[];
|
|
82
|
+
/**
|
|
83
|
+
* If set, abort the transaction (rollback) when this step's row-change
|
|
84
|
+
* count is below this threshold. Used for stale-write detection — e.g.
|
|
85
|
+
* "increment use_count only if status = 'active' AND use_count < max_uses",
|
|
86
|
+
* with `requireChanges: 1` to abort when no rows match.
|
|
87
|
+
*/
|
|
88
|
+
requireChanges?: number;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export type AssistantDbTransactionResult =
|
|
92
|
+
| {
|
|
93
|
+
ok: true;
|
|
94
|
+
results: Array<{ changes: number; lastInsertRowid: number }>;
|
|
95
|
+
}
|
|
96
|
+
| {
|
|
97
|
+
ok: false;
|
|
98
|
+
reason: "require_changes_failed";
|
|
99
|
+
failedStep: number;
|
|
100
|
+
actualChanges: number;
|
|
101
|
+
requiredChanges: number;
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Execute multiple write statements against the assistant's SQLite DB inside
|
|
106
|
+
* a single atomic transaction (BEGIN IMMEDIATE). All steps commit together;
|
|
107
|
+
* any throw — including a `requireChanges` constraint failure — rolls back
|
|
108
|
+
* the entire batch.
|
|
109
|
+
*
|
|
110
|
+
* Use this when several writes must succeed or fail as a unit (e.g. invite
|
|
111
|
+
* redemption: contact-channel upsert + invite-use record).
|
|
112
|
+
*
|
|
113
|
+
* Error handling:
|
|
114
|
+
* - `requireChanges` violations return `{ ok: false, reason: "require_changes_failed", ... }`.
|
|
115
|
+
* - Handler-level failures (SQL constraint errors, malformed params) throw
|
|
116
|
+
* `IpcHandlerError` so the underlying SQL message is preserved.
|
|
117
|
+
* - Transport failures (socket missing, daemon unreachable, timeout) throw
|
|
118
|
+
* `IpcTransportError`. Use this to distinguish retryable vs.
|
|
119
|
+
* non-retryable failures.
|
|
120
|
+
*
|
|
121
|
+
* Read-modify-write across steps is not supported. Use SQL-level conditions
|
|
122
|
+
* (WHERE clauses, ON CONFLICT) plus `requireChanges` for stale-write detection.
|
|
123
|
+
*/
|
|
124
|
+
export async function assistantDbTransaction(
|
|
125
|
+
steps: AssistantDbTransactionStep[],
|
|
126
|
+
): Promise<AssistantDbTransactionResult> {
|
|
127
|
+
return (await ipcCallAssistant("db_proxy_transaction", {
|
|
128
|
+
steps,
|
|
129
|
+
})) as AssistantDbTransactionResult;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Re-export so callers in this module's domain (gateway DB write helpers)
|
|
134
|
+
* can identify SQL/handler failures from the assistant DB proxy without
|
|
135
|
+
* importing from the IPC client directly.
|
|
136
|
+
*/
|
|
137
|
+
export { IpcHandlerError };
|