@nylorun/runtime 0.20.0-beta → 0.21.0-beta
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/CHANGELOG.md +64 -0
- package/README.md +15 -10
- package/dist/api/components.d.ts +155 -36
- package/dist/api/components.js +3 -3
- package/dist/api/http/app.js +2 -0
- package/dist/api/http/routes/mcp.d.ts +9 -0
- package/dist/api/http/routes/mcp.js +32 -0
- package/dist/api/http/routes/vaults.d.ts +1 -9
- package/dist/api/http/routes/vaults.js +3 -103
- package/dist/api/openapi.js +6 -3
- package/dist/artifacts/media-types.d.ts +2 -0
- package/dist/artifacts/media-types.js +5 -0
- package/dist/gates/http-tool.d.ts +7 -0
- package/dist/gates/http-tool.js +34 -3
- package/dist/gates/mcp-handler.d.ts +4 -1
- package/dist/gates/mcp-handler.js +64 -8
- package/dist/gates/tenant-vaults.d.ts +9 -15
- package/dist/gates/tenant-vaults.js +9 -17
- package/dist/gates/tool-client.js +36 -17
- package/dist/gates/tool-contract.d.ts +19 -3
- package/dist/gates/tool-contract.js +9 -3
- package/dist/gates/tool-gate.d.ts +2 -2
- package/dist/harness/calls.d.ts +2 -0
- package/dist/harness/calls.js +13 -3
- package/dist/harness-api/record.d.ts +7 -6
- package/dist/harness-api/record.js +99 -17
- package/dist/harness-api/server.js +35 -27
- package/dist/harness-api/start.js +2 -1
- package/dist/host/config-for.d.ts +0 -2
- package/dist/host/config-for.js +0 -1
- package/dist/host/gates.js +0 -1
- package/dist/host/main.js +13 -3
- package/dist/host/stack-config.d.ts +5 -8
- package/dist/host/stack-config.js +8 -19
- package/dist/index.d.ts +0 -1
- package/dist/keys/client.js +1 -9
- package/dist/keys/keys.d.ts +11 -13
- package/dist/keys/keys.js +5 -7
- package/dist/management-openapi.json +315 -345
- package/dist/mcp/connect.d.ts +159 -13
- package/dist/mcp/connect.js +538 -55
- package/dist/mcp/pool.d.ts +11 -2
- package/dist/mcp/pool.js +74 -27
- package/dist/mcp/preview.d.ts +35 -0
- package/dist/mcp/preview.js +215 -0
- package/dist/mcp/snapshot.d.ts +79 -5
- package/dist/mcp/snapshot.js +145 -27
- package/dist/model/catalog.d.ts +14 -0
- package/dist/model/catalog.js +14 -1
- package/dist/model/pi-model.js +36 -2
- package/dist/openapi.json +362 -123
- package/dist/redact.d.ts +19 -1
- package/dist/redact.js +42 -13
- package/dist/sandbox/session-sandbox.d.ts +7 -0
- package/dist/sandbox/session-sandbox.js +89 -28
- package/dist/store/postgres/drizzle/0016_mcp_oauth_removed.sql +5 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +7 -0
- package/dist/store/postgres/schema.d.ts +2 -261
- package/dist/store/postgres/schema.js +2 -36
- package/dist/store/postgres/store.js +1 -18
- package/dist/store/postgres/tenant.d.ts +14 -0
- package/dist/store/postgres/tenant.js +22 -2
- package/dist/store/types.d.ts +2 -8
- package/dist/tenant/artifact-tool.d.ts +9 -1
- package/dist/tenant/artifact-tool.js +113 -9
- package/dist/tenant/context.d.ts +5 -6
- package/dist/tenant/effects.d.ts +2 -2
- package/dist/tenant/effects.js +20 -5
- package/dist/tenant/ephemeral.d.ts +0 -6
- package/dist/tenant/ephemeral.js +0 -1
- package/dist/tenant/outbound.d.ts +14 -5
- package/dist/tenant/outbound.js +21 -9
- package/dist/tenant/runtime.js +9 -14
- package/dist/tenant/sessions.js +20 -3
- package/dist/tenant/store-pg.js +9 -0
- package/dist/tenant/tool-results.d.ts +57 -0
- package/dist/tenant/tool-results.js +298 -0
- package/dist/tenant/tool-search.d.ts +43 -0
- package/dist/tenant/tool-search.js +100 -0
- package/dist/tenant/transcript.d.ts +108 -0
- package/dist/tenant/transcript.js +13 -0
- package/dist/tenant/types.d.ts +0 -14
- package/dist/vault/crypto.d.ts +0 -7
- package/dist/vault/crypto.js +0 -16
- package/dist/vault/headers.d.ts +17 -0
- package/dist/vault/headers.js +61 -0
- package/dist/vault/service.d.ts +11 -68
- package/dist/vault/service.js +83 -438
- package/dist/vault/sources.d.ts +20 -48
- package/dist/vault/sources.js +25 -189
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
- package/dist/vault/oauth.d.ts +0 -55
- package/dist/vault/oauth.js +0 -186
package/dist/redact.d.ts
CHANGED
|
@@ -1 +1,19 @@
|
|
|
1
|
-
export
|
|
1
|
+
export interface ScrubOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Replace only `secrets` (R2b C8, Q16): no value under a secret-looking key, and no inline
|
|
4
|
+
* image data. A tool's answer keeps fields such as `nextToken`.
|
|
5
|
+
*/
|
|
6
|
+
readonly valuesOnly?: boolean;
|
|
7
|
+
/** Told how many times a secret was replaced. */
|
|
8
|
+
readonly counted?: (replacements: number) => void;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* `value` with each of `secrets` (those of at least 8 characters) replaced by `[redacted]`. By
|
|
12
|
+
* default also any value under a key such as `token` or `secret`, and inline image data.
|
|
13
|
+
*/
|
|
14
|
+
export declare function scrub(value: unknown, secrets: readonly string[], options?: ScrubOptions): unknown;
|
|
15
|
+
/** `value` with `secrets` alone replaced (`valuesOnly`), and how many replacements were made. */
|
|
16
|
+
export declare function scrubValues<T>(value: T, secrets: readonly string[]): {
|
|
17
|
+
value: T;
|
|
18
|
+
redacted: number;
|
|
19
|
+
};
|
package/dist/redact.js
CHANGED
|
@@ -1,14 +1,43 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `value` with each of `secrets` (those of at least 8 characters) replaced by `[redacted]`. By
|
|
3
|
+
* default also any value under a key such as `token` or `secret`, and inline image data.
|
|
4
|
+
*/
|
|
5
|
+
export function scrub(value, secrets, options = {}) {
|
|
6
|
+
// The longest first, so a header value goes whole before the token inside it.
|
|
7
|
+
const sorted = secrets.filter((secret) => secret.length >= 8).sort((a, b) => b.length - a.length);
|
|
8
|
+
let replaced = 0;
|
|
9
|
+
const walk = (item) => {
|
|
10
|
+
if (typeof item === "string") {
|
|
11
|
+
const text = options.valuesOnly
|
|
12
|
+
? item
|
|
13
|
+
: item.replace(/data:image\/[a-z0-9.+-]+;base64,[A-Za-z0-9+/=]+/giu, "[inline image data redacted]");
|
|
14
|
+
return sorted.reduce((current, secret) => {
|
|
15
|
+
const parts = current.split(secret);
|
|
16
|
+
replaced += parts.length - 1;
|
|
17
|
+
return parts.join("[redacted]");
|
|
18
|
+
}, text);
|
|
19
|
+
}
|
|
20
|
+
if (Array.isArray(item))
|
|
21
|
+
return item.map(walk);
|
|
22
|
+
if (item && typeof item === "object")
|
|
23
|
+
return Object.fromEntries(Object.entries(item).map(([key, entry]) => [
|
|
24
|
+
key,
|
|
25
|
+
!options.valuesOnly &&
|
|
26
|
+
/^(authorization|api[_-]?key|(?:access|refresh|id|auth)[_-]?token|token|secret|password|cookie|credentials?)$/iu.test(key)
|
|
27
|
+
? "[redacted]"
|
|
28
|
+
: walk(entry),
|
|
29
|
+
]));
|
|
30
|
+
return item;
|
|
31
|
+
};
|
|
32
|
+
const result = walk(value);
|
|
33
|
+
options.counted?.(replaced);
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
/** `value` with `secrets` alone replaced (`valuesOnly`), and how many replacements were made. */
|
|
37
|
+
export function scrubValues(value, secrets) {
|
|
38
|
+
if (secrets.length === 0)
|
|
39
|
+
return { value, redacted: 0 };
|
|
40
|
+
let redacted = 0;
|
|
41
|
+
const scrubbed = scrub(value, secrets, { valuesOnly: true, counted: (count) => (redacted = count) });
|
|
42
|
+
return { value: redacted === 0 ? value : scrubbed, redacted };
|
|
14
43
|
}
|
|
@@ -9,3 +9,10 @@ export type SandboxedManifest = {
|
|
|
9
9
|
};
|
|
10
10
|
/** The agent's manifest with the sandbox capability added, or why it cannot take one. */
|
|
11
11
|
export declare function withSandboxCapability(manifest: AgentManifest, spec: SandboxManifest): SandboxedManifest;
|
|
12
|
+
/**
|
|
13
|
+
* The pinned manifest of an agent session without a sandbox: `read_artifact` for each agent of
|
|
14
|
+
* the tree with a remote MCP server or an HTTP tool (R2b C11), and `nylorun.tools` for each with
|
|
15
|
+
* a remote MCP server (R2b C10). Undefined when nothing is added, and the session pins its
|
|
16
|
+
* definition as it is.
|
|
17
|
+
*/
|
|
18
|
+
export declare function withPlatformTools(manifest: AgentManifest): SandboxedManifest | undefined;
|
|
@@ -1,13 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Gives a session the sandbox chosen when it was opened
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
2
|
+
* Gives a session the sandbox chosen when it was opened, and the platform tools its agents
|
|
3
|
+
* need. An agent session's pinned manifest is its definition plus:
|
|
4
|
+
*
|
|
5
|
+
* - with a sandbox, the `nylorun.sandbox` capability (the six built-in tools, the sandbox
|
|
6
|
+
* instructions and the resolved spec) and the `nylorun.artifacts` capability
|
|
7
|
+
* (`save_artifact`), also added to each agent it uses as a tool, so the tree shares one spec.
|
|
8
|
+
* The sandbox's instructions name the agent's skills' folders (`/skills/<name>/`);
|
|
9
|
+
* - for each agent of the tree with a remote MCP server or an HTTP tool, `read_artifact` in its
|
|
10
|
+
* `nylorun.artifacts` capability (R2b C11), with or without a sandbox: the Runtime stores a
|
|
11
|
+
* result of those tools too large to show as an artifact, and the model reads it in pages.
|
|
12
|
+
* An agent that declares a tool named `read_artifact` keeps its own, and sees previews only;
|
|
13
|
+
* - for each agent of the tree with a remote MCP server, the `nylorun.tools` capability (R2b
|
|
14
|
+
* C10), empty: when the session defers some of the agent's MCP tools, its session tools put
|
|
15
|
+
* `tool_search` and `tool_call` there. An agent that declares either name defers nothing.
|
|
16
|
+
*
|
|
17
|
+
* The definition in the registry never changes.
|
|
8
18
|
*/
|
|
9
19
|
import { AgentManifestSchema } from "@nylorun/core/contracts";
|
|
10
|
-
import { artifactsCapabilityManifest, hashManifest, sandboxCapabilityManifest, } from "@nylorun/core/define";
|
|
20
|
+
import { READ_ARTIFACT_TOOL, TOOL_CALL_TOOL, TOOL_SEARCH_TOOL, TOOLS_CAPABILITY_ID, artifactsCapabilityManifest, hashManifest, sandboxCapabilityManifest, toolsCapabilityManifest, } from "@nylorun/core/define";
|
|
11
21
|
import { sandboxSpecOf } from "./share.js";
|
|
12
22
|
function isAgentManifest(value) {
|
|
13
23
|
return (typeof value === "object" &&
|
|
@@ -19,35 +29,72 @@ function isAgentManifest(value) {
|
|
|
19
29
|
function skillNamesOf(manifest) {
|
|
20
30
|
return manifest.capabilities.flatMap((capability) => Object.keys(capability.skills ?? {})).sort();
|
|
21
31
|
}
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
32
|
+
/**
|
|
33
|
+
* True when the agent itself declares a remote MCP server or an HTTP tool, whose results the
|
|
34
|
+
* Runtime may store as artifacts (R2b C11), and no tool of its own is named `read_artifact`.
|
|
35
|
+
*/
|
|
36
|
+
function readsStoredResults(manifest) {
|
|
37
|
+
const remote = manifest.capabilities.some((capability) => Object.keys(capability.mcpServers ?? {}).length > 0 ||
|
|
38
|
+
(capability.tools ?? []).some((tool) => tool.http !== undefined));
|
|
39
|
+
const taken = manifest.capabilities.some((capability) => (capability.tools ?? []).some((tool) => tool.name === READ_ARTIFACT_TOOL));
|
|
40
|
+
return remote && !taken;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* True when the agent itself declares a remote MCP server, some of whose tools the session may
|
|
44
|
+
* defer (R2b C10), and names no tool `tool_search` or `tool_call` (it then keeps every tool in
|
|
45
|
+
* its list).
|
|
46
|
+
*/
|
|
47
|
+
function defersTools(manifest) {
|
|
48
|
+
const servers = manifest.capabilities.some((capability) => Object.keys(capability.mcpServers ?? {}).length > 0);
|
|
49
|
+
const taken = manifest.capabilities.some((capability) => capability.id === TOOLS_CAPABILITY_ID ||
|
|
50
|
+
(capability.tools ?? []).some((tool) => tool.name === TOOL_SEARCH_TOOL || tool.name === TOOL_CALL_TOOL));
|
|
51
|
+
return servers && !taken;
|
|
52
|
+
}
|
|
53
|
+
/** `manifest` with the session's capabilities added; the same object when none are. */
|
|
54
|
+
function addCapabilities(manifest, spec) {
|
|
55
|
+
let changed = false;
|
|
56
|
+
const capabilities = manifest.capabilities.map((capability) => {
|
|
57
|
+
if (capability.tools === undefined)
|
|
58
|
+
return capability;
|
|
59
|
+
let toolsChanged = false;
|
|
60
|
+
const tools = capability.tools.map((tool) => {
|
|
61
|
+
// Agents used as tools share the session's sandbox; flow agents used as tools run in
|
|
62
|
+
// linked sessions that inherit it. One that declares its own sandbox keeps it.
|
|
63
|
+
if (tool.agent === undefined || !isAgentManifest(tool.agent))
|
|
64
|
+
return tool;
|
|
65
|
+
const agent = addCapabilities(tool.agent, sandboxSpecOf(tool.agent) === undefined ? spec : undefined);
|
|
66
|
+
if (agent === tool.agent)
|
|
67
|
+
return tool;
|
|
68
|
+
toolsChanged = true;
|
|
69
|
+
return { ...tool, agent };
|
|
36
70
|
});
|
|
71
|
+
if (!toolsChanged)
|
|
72
|
+
return capability;
|
|
73
|
+
changed = true;
|
|
74
|
+
return { ...capability, tools };
|
|
75
|
+
});
|
|
76
|
+
const save = spec !== undefined;
|
|
77
|
+
const read = readsStoredResults(manifest);
|
|
78
|
+
const defer = defersTools(manifest);
|
|
79
|
+
if (!save && !read && !defer && !changed)
|
|
80
|
+
return manifest;
|
|
37
81
|
return {
|
|
38
82
|
...manifest,
|
|
39
83
|
// With a sandbox comes `save_artifact`, so files the agent makes reach the user (F8.1). The
|
|
40
84
|
// sandbox's instructions name where the agent's skills are (R2 M4).
|
|
41
85
|
capabilities: [
|
|
42
86
|
...capabilities,
|
|
43
|
-
|
|
44
|
-
|
|
87
|
+
...(spec === undefined
|
|
88
|
+
? []
|
|
89
|
+
: [sandboxCapabilityManifest(spec, { skills: skillNamesOf(manifest) })]),
|
|
90
|
+
...(save || read ? [artifactsCapabilityManifest({ save, read })] : []),
|
|
91
|
+
// Empty: when the session defers MCP tools, its tools put tool_search and tool_call here.
|
|
92
|
+
...(defer ? [toolsCapabilityManifest()] : []),
|
|
45
93
|
],
|
|
46
94
|
};
|
|
47
95
|
}
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
const sandboxed = addCapability(manifest, spec);
|
|
96
|
+
/** `sandboxed` checked as a manifest, with its hash. */
|
|
97
|
+
function checked(original, sandboxed) {
|
|
51
98
|
const parsed = AgentManifestSchema.safeParse(sandboxed);
|
|
52
99
|
if (!parsed.success) {
|
|
53
100
|
const issues = parsed.error.issues.map((issue) => issue.message);
|
|
@@ -55,9 +102,23 @@ export function withSandboxCapability(manifest, spec) {
|
|
|
55
102
|
return {
|
|
56
103
|
ok: false,
|
|
57
104
|
message: clash
|
|
58
|
-
? `'${
|
|
59
|
-
: `'${
|
|
105
|
+
? `'${original.id}' declares a tool named like a sandbox tool (bash, read, write, edit, grep, glob, save_artifact). Rename it, or open the session with sandbox: false.`
|
|
106
|
+
: `'${original.id}' cannot take this sandbox: ${[...new Set(issues)].join("; ")}`,
|
|
60
107
|
};
|
|
61
108
|
}
|
|
62
109
|
return { ok: true, manifest: sandboxed, manifestHash: hashManifest(sandboxed) };
|
|
63
110
|
}
|
|
111
|
+
/** The agent's manifest with the sandbox capability added, or why it cannot take one. */
|
|
112
|
+
export function withSandboxCapability(manifest, spec) {
|
|
113
|
+
return checked(manifest, addCapabilities(manifest, spec));
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* The pinned manifest of an agent session without a sandbox: `read_artifact` for each agent of
|
|
117
|
+
* the tree with a remote MCP server or an HTTP tool (R2b C11), and `nylorun.tools` for each with
|
|
118
|
+
* a remote MCP server (R2b C10). Undefined when nothing is added, and the session pins its
|
|
119
|
+
* definition as it is.
|
|
120
|
+
*/
|
|
121
|
+
export function withPlatformTools(manifest) {
|
|
122
|
+
const pinned = addCapabilities(manifest, undefined);
|
|
123
|
+
return pinned === manifest ? undefined : checked(manifest, pinned);
|
|
124
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
DROP TABLE "nylorun"."oauth_pending" CASCADE;--> statement-breakpoint
|
|
2
|
+
INSERT INTO "nylorun"."vault_audit" ("id", "at", "actor", "action", "vault_id", "credential_id", "target", "outcome")
|
|
3
|
+
SELECT gen_random_uuid()::text, to_char(now() AT TIME ZONE 'UTC', 'YYYY-MM-DD"T"HH24:MI:SS.MS"Z"'), 'migration', 'delete', "vault_id", "id", "binding_json"::jsonb ->> 'url', 'deleted'
|
|
4
|
+
FROM "nylorun"."vault_credentials" WHERE "type" = 'oauth' ORDER BY "vault_id", "id";--> statement-breakpoint
|
|
5
|
+
DELETE FROM "nylorun"."vault_credentials" WHERE "type" = 'oauth';
|
|
@@ -1048,14 +1048,14 @@ export declare const vaultCredentials: import("drizzle-orm/pg-core").PgTableWith
|
|
|
1048
1048
|
tableName: "vault_credentials";
|
|
1049
1049
|
dataType: "string";
|
|
1050
1050
|
columnType: "PgText";
|
|
1051
|
-
data: "bearer" | "
|
|
1051
|
+
data: "bearer" | "headers" | "model";
|
|
1052
1052
|
driverParam: string;
|
|
1053
1053
|
notNull: true;
|
|
1054
1054
|
hasDefault: false;
|
|
1055
1055
|
isPrimaryKey: false;
|
|
1056
1056
|
isAutoincrement: false;
|
|
1057
1057
|
hasRuntimeDefault: false;
|
|
1058
|
-
enumValues: ["bearer", "
|
|
1058
|
+
enumValues: ["bearer", "headers", "model"];
|
|
1059
1059
|
baseColumn: never;
|
|
1060
1060
|
identity: undefined;
|
|
1061
1061
|
generated: undefined;
|
|
@@ -1442,264 +1442,6 @@ export declare const vaultIdempotency: import("drizzle-orm/pg-core").PgTableWith
|
|
|
1442
1442
|
};
|
|
1443
1443
|
dialect: 'pg';
|
|
1444
1444
|
}>;
|
|
1445
|
-
/**
|
|
1446
|
-
* An MCP OAuth connect between its start and its callback (F9 C2): found by the SHA-256 of its
|
|
1447
|
-
* `state`, used once, for ten minutes. The PKCE verifier and any client secret are sealed under
|
|
1448
|
-
* the vault key (`sealBytes`), which only the keys module holds.
|
|
1449
|
-
*/
|
|
1450
|
-
export declare const oauthPending: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
1451
|
-
name: "oauth_pending";
|
|
1452
|
-
schema: "nylorun";
|
|
1453
|
-
columns: {
|
|
1454
|
-
stateHash: import("drizzle-orm/pg-core").PgColumn<{
|
|
1455
|
-
name: "stateHash";
|
|
1456
|
-
tableName: "oauth_pending";
|
|
1457
|
-
dataType: "string";
|
|
1458
|
-
columnType: "PgText";
|
|
1459
|
-
data: string;
|
|
1460
|
-
driverParam: string;
|
|
1461
|
-
notNull: true;
|
|
1462
|
-
hasDefault: false;
|
|
1463
|
-
isPrimaryKey: true;
|
|
1464
|
-
isAutoincrement: false;
|
|
1465
|
-
hasRuntimeDefault: false;
|
|
1466
|
-
enumValues: [string, ...string[]];
|
|
1467
|
-
baseColumn: never;
|
|
1468
|
-
identity: undefined;
|
|
1469
|
-
generated: undefined;
|
|
1470
|
-
}, {}, {}>;
|
|
1471
|
-
vaultId: import("drizzle-orm/pg-core").PgColumn<{
|
|
1472
|
-
name: "vaultId";
|
|
1473
|
-
tableName: "oauth_pending";
|
|
1474
|
-
dataType: "string";
|
|
1475
|
-
columnType: "PgText";
|
|
1476
|
-
data: string;
|
|
1477
|
-
driverParam: string;
|
|
1478
|
-
notNull: true;
|
|
1479
|
-
hasDefault: false;
|
|
1480
|
-
isPrimaryKey: false;
|
|
1481
|
-
isAutoincrement: false;
|
|
1482
|
-
hasRuntimeDefault: false;
|
|
1483
|
-
enumValues: [string, ...string[]];
|
|
1484
|
-
baseColumn: never;
|
|
1485
|
-
identity: undefined;
|
|
1486
|
-
generated: undefined;
|
|
1487
|
-
}, {}, {}>;
|
|
1488
|
-
server: import("drizzle-orm/pg-core").PgColumn<{
|
|
1489
|
-
name: "server";
|
|
1490
|
-
tableName: "oauth_pending";
|
|
1491
|
-
dataType: "string";
|
|
1492
|
-
columnType: "PgText";
|
|
1493
|
-
data: string;
|
|
1494
|
-
driverParam: string;
|
|
1495
|
-
notNull: true;
|
|
1496
|
-
hasDefault: false;
|
|
1497
|
-
isPrimaryKey: false;
|
|
1498
|
-
isAutoincrement: false;
|
|
1499
|
-
hasRuntimeDefault: false;
|
|
1500
|
-
enumValues: [string, ...string[]];
|
|
1501
|
-
baseColumn: never;
|
|
1502
|
-
identity: undefined;
|
|
1503
|
-
generated: undefined;
|
|
1504
|
-
}, {}, {}>;
|
|
1505
|
-
url: import("drizzle-orm/pg-core").PgColumn<{
|
|
1506
|
-
name: "url";
|
|
1507
|
-
tableName: "oauth_pending";
|
|
1508
|
-
dataType: "string";
|
|
1509
|
-
columnType: "PgText";
|
|
1510
|
-
data: string;
|
|
1511
|
-
driverParam: string;
|
|
1512
|
-
notNull: true;
|
|
1513
|
-
hasDefault: false;
|
|
1514
|
-
isPrimaryKey: false;
|
|
1515
|
-
isAutoincrement: false;
|
|
1516
|
-
hasRuntimeDefault: false;
|
|
1517
|
-
enumValues: [string, ...string[]];
|
|
1518
|
-
baseColumn: never;
|
|
1519
|
-
identity: undefined;
|
|
1520
|
-
generated: undefined;
|
|
1521
|
-
}, {}, {}>;
|
|
1522
|
-
tokenEndpoint: import("drizzle-orm/pg-core").PgColumn<{
|
|
1523
|
-
name: "tokenEndpoint";
|
|
1524
|
-
tableName: "oauth_pending";
|
|
1525
|
-
dataType: "string";
|
|
1526
|
-
columnType: "PgText";
|
|
1527
|
-
data: string;
|
|
1528
|
-
driverParam: string;
|
|
1529
|
-
notNull: true;
|
|
1530
|
-
hasDefault: false;
|
|
1531
|
-
isPrimaryKey: false;
|
|
1532
|
-
isAutoincrement: false;
|
|
1533
|
-
hasRuntimeDefault: false;
|
|
1534
|
-
enumValues: [string, ...string[]];
|
|
1535
|
-
baseColumn: never;
|
|
1536
|
-
identity: undefined;
|
|
1537
|
-
generated: undefined;
|
|
1538
|
-
}, {}, {}>;
|
|
1539
|
-
clientId: import("drizzle-orm/pg-core").PgColumn<{
|
|
1540
|
-
name: "clientId";
|
|
1541
|
-
tableName: "oauth_pending";
|
|
1542
|
-
dataType: "string";
|
|
1543
|
-
columnType: "PgText";
|
|
1544
|
-
data: string;
|
|
1545
|
-
driverParam: string;
|
|
1546
|
-
notNull: true;
|
|
1547
|
-
hasDefault: false;
|
|
1548
|
-
isPrimaryKey: false;
|
|
1549
|
-
isAutoincrement: false;
|
|
1550
|
-
hasRuntimeDefault: false;
|
|
1551
|
-
enumValues: [string, ...string[]];
|
|
1552
|
-
baseColumn: never;
|
|
1553
|
-
identity: undefined;
|
|
1554
|
-
generated: undefined;
|
|
1555
|
-
}, {}, {}>;
|
|
1556
|
-
tokenEndpointAuth: import("drizzle-orm/pg-core").PgColumn<{
|
|
1557
|
-
name: "tokenEndpointAuth";
|
|
1558
|
-
tableName: "oauth_pending";
|
|
1559
|
-
dataType: "string";
|
|
1560
|
-
columnType: "PgText";
|
|
1561
|
-
data: "client_secret_basic" | "client_secret_post" | "none";
|
|
1562
|
-
driverParam: string;
|
|
1563
|
-
notNull: true;
|
|
1564
|
-
hasDefault: false;
|
|
1565
|
-
isPrimaryKey: false;
|
|
1566
|
-
isAutoincrement: false;
|
|
1567
|
-
hasRuntimeDefault: false;
|
|
1568
|
-
enumValues: ["none", "client_secret_basic", "client_secret_post"];
|
|
1569
|
-
baseColumn: never;
|
|
1570
|
-
identity: undefined;
|
|
1571
|
-
generated: undefined;
|
|
1572
|
-
}, {}, {}>;
|
|
1573
|
-
resource: import("drizzle-orm/pg-core").PgColumn<{
|
|
1574
|
-
name: "resource";
|
|
1575
|
-
tableName: "oauth_pending";
|
|
1576
|
-
dataType: "string";
|
|
1577
|
-
columnType: "PgText";
|
|
1578
|
-
data: string;
|
|
1579
|
-
driverParam: string;
|
|
1580
|
-
notNull: false;
|
|
1581
|
-
hasDefault: false;
|
|
1582
|
-
isPrimaryKey: false;
|
|
1583
|
-
isAutoincrement: false;
|
|
1584
|
-
hasRuntimeDefault: false;
|
|
1585
|
-
enumValues: [string, ...string[]];
|
|
1586
|
-
baseColumn: never;
|
|
1587
|
-
identity: undefined;
|
|
1588
|
-
generated: undefined;
|
|
1589
|
-
}, {}, {}>;
|
|
1590
|
-
kekId: import("drizzle-orm/pg-core").PgColumn<{
|
|
1591
|
-
name: "kekId";
|
|
1592
|
-
tableName: "oauth_pending";
|
|
1593
|
-
dataType: "string";
|
|
1594
|
-
columnType: "PgText";
|
|
1595
|
-
data: string;
|
|
1596
|
-
driverParam: string;
|
|
1597
|
-
notNull: true;
|
|
1598
|
-
hasDefault: false;
|
|
1599
|
-
isPrimaryKey: false;
|
|
1600
|
-
isAutoincrement: false;
|
|
1601
|
-
hasRuntimeDefault: false;
|
|
1602
|
-
enumValues: [string, ...string[]];
|
|
1603
|
-
baseColumn: never;
|
|
1604
|
-
identity: undefined;
|
|
1605
|
-
generated: undefined;
|
|
1606
|
-
}, {}, {}>;
|
|
1607
|
-
clientSecret: import("drizzle-orm/pg-core").PgColumn<{
|
|
1608
|
-
name: "clientSecret";
|
|
1609
|
-
tableName: "oauth_pending";
|
|
1610
|
-
dataType: "custom";
|
|
1611
|
-
columnType: "PgCustomColumn";
|
|
1612
|
-
data: Uint8Array<ArrayBufferLike>;
|
|
1613
|
-
driverParam: Buffer<ArrayBufferLike>;
|
|
1614
|
-
notNull: false;
|
|
1615
|
-
hasDefault: false;
|
|
1616
|
-
isPrimaryKey: false;
|
|
1617
|
-
isAutoincrement: false;
|
|
1618
|
-
hasRuntimeDefault: false;
|
|
1619
|
-
enumValues: undefined;
|
|
1620
|
-
baseColumn: never;
|
|
1621
|
-
identity: undefined;
|
|
1622
|
-
generated: undefined;
|
|
1623
|
-
}, {}, {
|
|
1624
|
-
pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
|
|
1625
|
-
}>;
|
|
1626
|
-
codeVerifier: import("drizzle-orm/pg-core").PgColumn<{
|
|
1627
|
-
name: "codeVerifier";
|
|
1628
|
-
tableName: "oauth_pending";
|
|
1629
|
-
dataType: "custom";
|
|
1630
|
-
columnType: "PgCustomColumn";
|
|
1631
|
-
data: Uint8Array<ArrayBufferLike>;
|
|
1632
|
-
driverParam: Buffer<ArrayBufferLike>;
|
|
1633
|
-
notNull: true;
|
|
1634
|
-
hasDefault: false;
|
|
1635
|
-
isPrimaryKey: false;
|
|
1636
|
-
isAutoincrement: false;
|
|
1637
|
-
hasRuntimeDefault: false;
|
|
1638
|
-
enumValues: undefined;
|
|
1639
|
-
baseColumn: never;
|
|
1640
|
-
identity: undefined;
|
|
1641
|
-
generated: undefined;
|
|
1642
|
-
}, {}, {
|
|
1643
|
-
pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
|
|
1644
|
-
}>;
|
|
1645
|
-
redirectUri: import("drizzle-orm/pg-core").PgColumn<{
|
|
1646
|
-
name: "redirectUri";
|
|
1647
|
-
tableName: "oauth_pending";
|
|
1648
|
-
dataType: "string";
|
|
1649
|
-
columnType: "PgText";
|
|
1650
|
-
data: string;
|
|
1651
|
-
driverParam: string;
|
|
1652
|
-
notNull: true;
|
|
1653
|
-
hasDefault: false;
|
|
1654
|
-
isPrimaryKey: false;
|
|
1655
|
-
isAutoincrement: false;
|
|
1656
|
-
hasRuntimeDefault: false;
|
|
1657
|
-
enumValues: [string, ...string[]];
|
|
1658
|
-
baseColumn: never;
|
|
1659
|
-
identity: undefined;
|
|
1660
|
-
generated: undefined;
|
|
1661
|
-
}, {}, {}>;
|
|
1662
|
-
expiresAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
1663
|
-
name: "expiresAt";
|
|
1664
|
-
tableName: "oauth_pending";
|
|
1665
|
-
dataType: "custom";
|
|
1666
|
-
columnType: "PgCustomColumn";
|
|
1667
|
-
data: string;
|
|
1668
|
-
driverParam: string;
|
|
1669
|
-
notNull: true;
|
|
1670
|
-
hasDefault: false;
|
|
1671
|
-
isPrimaryKey: false;
|
|
1672
|
-
isAutoincrement: false;
|
|
1673
|
-
hasRuntimeDefault: false;
|
|
1674
|
-
enumValues: undefined;
|
|
1675
|
-
baseColumn: never;
|
|
1676
|
-
identity: undefined;
|
|
1677
|
-
generated: undefined;
|
|
1678
|
-
}, {}, {
|
|
1679
|
-
pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
|
|
1680
|
-
}>;
|
|
1681
|
-
createdAt: import("drizzle-orm/pg-core").PgColumn<{
|
|
1682
|
-
name: "createdAt";
|
|
1683
|
-
tableName: "oauth_pending";
|
|
1684
|
-
dataType: "custom";
|
|
1685
|
-
columnType: "PgCustomColumn";
|
|
1686
|
-
data: string;
|
|
1687
|
-
driverParam: string;
|
|
1688
|
-
notNull: true;
|
|
1689
|
-
hasDefault: false;
|
|
1690
|
-
isPrimaryKey: false;
|
|
1691
|
-
isAutoincrement: false;
|
|
1692
|
-
hasRuntimeDefault: false;
|
|
1693
|
-
enumValues: undefined;
|
|
1694
|
-
baseColumn: never;
|
|
1695
|
-
identity: undefined;
|
|
1696
|
-
generated: undefined;
|
|
1697
|
-
}, {}, {
|
|
1698
|
-
pgColumnBuilderBrand: 'PgCustomColumnBuilderBrand';
|
|
1699
|
-
}>;
|
|
1700
|
-
};
|
|
1701
|
-
dialect: 'pg';
|
|
1702
|
-
}>;
|
|
1703
1445
|
export declare const tenantSettings: import("drizzle-orm/pg-core").PgTableWithColumns<{
|
|
1704
1446
|
name: "tenant_settings";
|
|
1705
1447
|
schema: "nylorun";
|
|
@@ -3924,7 +3666,6 @@ export type VaultRow = typeof vaults.$inferSelect;
|
|
|
3924
3666
|
export type VaultCredentialRow = typeof vaultCredentials.$inferSelect;
|
|
3925
3667
|
export type VaultAuditRow = Omit<typeof vaultAudit.$inferSelect, "ord">;
|
|
3926
3668
|
export type VaultIdempotencyRow = typeof vaultIdempotency.$inferSelect;
|
|
3927
|
-
export type OAuthPendingRow = typeof oauthPending.$inferSelect;
|
|
3928
3669
|
export type SigningKeyRow = typeof signingKeys.$inferSelect;
|
|
3929
3670
|
export type ModelUsageRow = typeof modelUsage.$inferSelect;
|
|
3930
3671
|
export type ModelBudgetRow = typeof modelBudgets.$inferSelect;
|
|
@@ -129,8 +129,8 @@ export const vaultCredentials = nylorun.table("vault_credentials", {
|
|
|
129
129
|
id: textC().primaryKey(),
|
|
130
130
|
vaultId: text().notNull(),
|
|
131
131
|
name: text().notNull(),
|
|
132
|
-
type: text({ enum: ["bearer", "
|
|
133
|
-
/** JSON text of the non-secret binding (
|
|
132
|
+
type: text({ enum: ["bearer", "headers", "model"] }).notNull(),
|
|
133
|
+
/** JSON text of the non-secret binding: url (and via, identity, header names), or provider and model. */
|
|
134
134
|
bindingJson: text().notNull(),
|
|
135
135
|
expiresAt: text(),
|
|
136
136
|
createdAt: textC().notNull(),
|
|
@@ -165,40 +165,6 @@ export const vaultIdempotency = nylorun.table("vault_idempotency", {
|
|
|
165
165
|
/** JSON text of the original response. */
|
|
166
166
|
response: text().notNull(),
|
|
167
167
|
});
|
|
168
|
-
/**
|
|
169
|
-
* An MCP OAuth connect between its start and its callback (F9 C2): found by the SHA-256 of its
|
|
170
|
-
* `state`, used once, for ten minutes. The PKCE verifier and any client secret are sealed under
|
|
171
|
-
* the vault key (`sealBytes`), which only the keys module holds.
|
|
172
|
-
*/
|
|
173
|
-
export const oauthPending = nylorun.table("oauth_pending", {
|
|
174
|
-
stateHash: text().primaryKey(),
|
|
175
|
-
vaultId: text().notNull(),
|
|
176
|
-
/** The MCP server's name in the agent, the credential's name. */
|
|
177
|
-
server: text().notNull(),
|
|
178
|
-
/** The MCP server's URL (normalized): the credential's binding. */
|
|
179
|
-
url: text().notNull(),
|
|
180
|
-
tokenEndpoint: text().notNull(),
|
|
181
|
-
clientId: text().notNull(),
|
|
182
|
-
/** How the client authenticates at the token endpoint: `none`, `client_secret_basic` or `client_secret_post`. */
|
|
183
|
-
tokenEndpointAuth: text({ enum: ["none", "client_secret_basic", "client_secret_post"] }).notNull(),
|
|
184
|
-
/** The RFC 8707 resource indicator sent with the authorization request, if any. */
|
|
185
|
-
resource: text(),
|
|
186
|
-
kekId: text().notNull(),
|
|
187
|
-
/** Sealed; null for a public client. */
|
|
188
|
-
clientSecret: bytes(),
|
|
189
|
-
/** Sealed. */
|
|
190
|
-
codeVerifier: bytes().notNull(),
|
|
191
|
-
redirectUri: text().notNull(),
|
|
192
|
-
expiresAt: textC().notNull(),
|
|
193
|
-
createdAt: textC().notNull(),
|
|
194
|
-
}, (t) => [
|
|
195
|
-
foreignKey({
|
|
196
|
-
name: "oauth_pending_vault_id_fkey",
|
|
197
|
-
columns: [t.vaultId],
|
|
198
|
-
foreignColumns: [vaults.id],
|
|
199
|
-
}).onDelete("cascade"),
|
|
200
|
-
index("oauth_pending_expires").on(t.expiresAt),
|
|
201
|
-
]);
|
|
202
168
|
export const tenantSettings = nylorun.table("tenant_settings", {
|
|
203
169
|
key: text().primaryKey(),
|
|
204
170
|
value: text().notNull(),
|
|
@@ -57,7 +57,7 @@ import { database, driverError } from "./db.js";
|
|
|
57
57
|
import { expectedSchemaVersion, readSchemaVersion } from "./migrate.js";
|
|
58
58
|
import { createPostgresRecordReader } from "./record.js";
|
|
59
59
|
import { postgresRecordWriter, postgresSandboxRecordWriter } from "./record-writer.js";
|
|
60
|
-
import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, sandboxEvents, sandboxResources, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults,
|
|
60
|
+
import { artifacts, artifactVersions, artifactContent, definitionFiles, definitionFileUses, commands, definitions, effects, links, modelBudgets, modelUsage, principals, sandboxes, sandboxEvents, sandboxResources, sessionEvents, sessionLogHeads, sessions, toJson, toolCrossings, signingKeys, tenant, tenantSettings, vaultAudit, vaultCredentials, vaultIdempotency, vaults, } from "./schema.js";
|
|
61
61
|
export function createPostgresSessionStore(options) {
|
|
62
62
|
return new PostgresSessionStore(options);
|
|
63
63
|
}
|
|
@@ -765,23 +765,6 @@ class PostgresTx {
|
|
|
765
765
|
this.check();
|
|
766
766
|
await this.db.insert(vaultIdempotency).values(row);
|
|
767
767
|
}
|
|
768
|
-
async insertOAuthPending(row) {
|
|
769
|
-
this.check();
|
|
770
|
-
await this.db.insert(oauthPending).values(row);
|
|
771
|
-
}
|
|
772
|
-
async takeOAuthPending(stateHash) {
|
|
773
|
-
this.check();
|
|
774
|
-
const [row] = await this.db
|
|
775
|
-
.delete(oauthPending)
|
|
776
|
-
.where(eq(oauthPending.stateHash, stateHash))
|
|
777
|
-
.returning();
|
|
778
|
-
return row;
|
|
779
|
-
}
|
|
780
|
-
async deleteExpiredOAuthPending(now) {
|
|
781
|
-
this.check();
|
|
782
|
-
const result = await this.db.delete(oauthPending).where(lt(oauthPending.expiresAt, now));
|
|
783
|
-
return result.count;
|
|
784
|
-
}
|
|
785
768
|
// --- signing keys --------------------------------------------------------
|
|
786
769
|
async lockSigningKeys() {
|
|
787
770
|
this.check();
|