@agent-native/core 0.201.0-nightly-20261005153421 → 0.201.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -22
- package/dist/a2a/server.d.ts +2 -2
- package/dist/a2a/server.js +13 -2
- package/dist/agent/thread-data-builder.d.ts +4 -0
- package/dist/agent/thread-data-builder.js +8 -0
- package/dist/agent-sql/analysis.d.ts +31 -0
- package/dist/agent-sql/analysis.js +169 -0
- package/dist/agent-sql/index.d.ts +4 -0
- package/dist/agent-sql/index.js +4 -0
- package/dist/agent-sql/lexer.d.ts +37 -0
- package/dist/agent-sql/lexer.js +357 -0
- package/dist/agent-sql/postgres.d.ts +51 -0
- package/dist/agent-sql/postgres.js +197 -0
- package/dist/agent-sql/query.d.ts +30 -0
- package/dist/agent-sql/query.js +514 -0
- package/dist/catalog.json +24 -24
- package/dist/client/analytics/index.d.ts +1 -1
- package/dist/client/analytics/index.js +1 -1
- package/dist/client/analytics.d.ts +8 -0
- package/dist/client/analytics.js +17 -2
- package/dist/client/session-replay.js +3 -2
- package/dist/identity/offboard.js +31 -3
- package/dist/identity/rekey.d.ts +12 -1
- package/dist/identity/rekey.js +77 -6
- package/dist/identity/retired-emails.d.ts +23 -0
- package/dist/identity/retired-emails.js +55 -0
- package/dist/mcp/actions/create-org-service-token.js +20 -8
- package/dist/mcp/actions/service-token-access.d.ts +1 -0
- package/dist/mcp/actions/service-token-access.js +41 -24
- package/dist/mcp/build-server.d.ts +20 -6
- package/dist/mcp/build-server.js +131 -35
- package/dist/mcp/connect-route.d.ts +4 -3
- package/dist/mcp/connect-route.js +140 -82
- package/dist/mcp/connect-store.d.ts +17 -11
- package/dist/mcp/connect-store.js +88 -60
- package/dist/mcp/credential-issuance.d.ts +23 -0
- package/dist/mcp/credential-issuance.js +77 -0
- package/dist/mcp/credential-membership.d.ts +26 -0
- package/dist/mcp/credential-membership.js +67 -0
- package/dist/mcp/oauth-route.js +133 -45
- package/dist/mcp/oauth-store.d.ts +15 -5
- package/dist/mcp/oauth-store.js +119 -34
- package/dist/mcp/oauth-token.d.ts +4 -0
- package/dist/mcp/oauth-token.js +5 -0
- package/dist/mcp/screen-memory-stdio.d.ts +7 -7
- package/dist/mcp/server.js +14 -0
- package/dist/onboarding/default-steps.js +1 -1
- package/dist/org/handlers.d.ts +1 -1
- package/dist/org/index.d.ts +2 -2
- package/dist/org/membership.d.ts +3 -1
- package/dist/org/membership.js +5 -2
- package/dist/provider-api/actions/custom-provider-registration.d.ts +12 -12
- package/dist/provider-api/actions/provider-api.d.ts +10 -10
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resource-changes/store.d.ts +2 -0
- package/dist/resource-changes/store.js +4 -0
- package/dist/resources/handlers.d.ts +1 -1
- package/dist/scripts/db/exec.js +28 -101
- package/dist/scripts/db/patch.js +14 -34
- package/dist/scripts/db/postgres-client.d.ts +8 -1
- package/dist/scripts/db/postgres-client.js +20 -6
- package/dist/scripts/db/query.js +31 -33
- package/dist/scripts/db/safety.d.ts +47 -2
- package/dist/scripts/db/safety.js +383 -137
- package/dist/scripts/db/scoping.d.ts +1 -0
- package/dist/scripts/db/scoping.js +3 -2
- package/dist/search/index-store.d.ts +21 -0
- package/dist/search/index-store.js +47 -0
- package/dist/search/indexer.js +35 -32
- package/dist/search/registry.d.ts +6 -3
- package/dist/search/registry.js +30 -8
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/server/agent-chat-plugin.js +18 -6
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/agent-engine-default-model-route.d.ts +1 -1
- package/dist/server/agent-run-context.js +9 -0
- package/dist/server/attribution.d.ts +2 -0
- package/dist/server/attribution.js +7 -1
- package/dist/server/auth.js +9 -0
- package/dist/server/credential-membership-unavailable.d.ts +13 -0
- package/dist/server/credential-membership-unavailable.js +22 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +1 -0
- package/dist/server/onboarding-html.js +1 -1
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/recap-image-route.js +4 -0
- package/dist/server/release-schema.js +4 -0
- package/dist/shared/docs-url.d.ts +3 -1
- package/dist/shared/docs-url.js +6 -3
- package/dist/shared/environment-lanes.d.ts +8 -0
- package/dist/shared/environment-lanes.js +26 -0
- package/dist/templates/chat/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/templates/chat/README.md +2 -2
- package/dist/templates/default/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/default/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/templates/default/app/routes/home.tsx +5 -1
- package/dist/templates/headless/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/headless/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/templates/workspace-core/.agents/skills/security/SKILL.md +9 -2
- package/dist/templates/workspace-core/.agents/skills/storing-data/SKILL.md +12 -7
- package/dist/tracking/providers.js +13 -1
- package/docs/content/authentication.mdx +5 -1
- package/docs/content/durable-background-runs.mdx +17 -8
- package/docs/content/external-agents.mdx +3 -1
- package/docs/content/mcp-protocol.mdx +6 -2
- package/docs/content/security.mdx +1 -1
- package/package.json +5 -4
- package/src/templates/chat/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/chat/.agents/skills/storing-data/SKILL.md +12 -7
- package/src/templates/chat/README.md +2 -2
- package/src/templates/default/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/default/.agents/skills/storing-data/SKILL.md +12 -7
- package/src/templates/default/app/routes/home.tsx +5 -1
- package/src/templates/headless/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/headless/.agents/skills/storing-data/SKILL.md +12 -7
- package/src/templates/workspace-core/.agents/skills/security/SKILL.md +9 -2
- package/src/templates/workspace-core/.agents/skills/storing-data/SKILL.md +12 -7
package/dist/scripts/db/patch.js
CHANGED
|
@@ -1,39 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { getDatabaseUrl
|
|
2
|
+
import { getDatabaseUrl } from "../../db/client.js";
|
|
3
3
|
import { parseArgs, fail } from "../utils.js";
|
|
4
4
|
import { createPostgresScriptClient } from "./postgres-client.js";
|
|
5
|
-
import { assertNoRawDbAccessControlPatchTarget, assertNoSensitiveFrameworkTables, } from "./safety.js";
|
|
5
|
+
import { assertNoRawDbAccessControlPatchTarget, assertNoSensitiveFrameworkTables, finalRawDbSql, readRawDbPatchStatement, validateRawDbPatchWhere, verifyRawDbStatement, } from "./safety.js";
|
|
6
6
|
import { buildScopingPostgres } from "./scoping.js";
|
|
7
7
|
function isValidIdentifier(value) {
|
|
8
8
|
return /^[A-Za-z_][A-Za-z0-9_]*$/.test(value);
|
|
9
9
|
}
|
|
10
|
-
function validateWhere(where) {
|
|
11
|
-
if (where.includes(";"))
|
|
12
|
-
fail("--where must not contain ';'");
|
|
13
|
-
const stripped = where
|
|
14
|
-
.replace(/'(?:''|[^'])*'/g, "''")
|
|
15
|
-
.replace(/"(?:""|[^"])*"/g, '""')
|
|
16
|
-
.toUpperCase();
|
|
17
|
-
const blocked = [
|
|
18
|
-
" INSERT ",
|
|
19
|
-
" UPDATE ",
|
|
20
|
-
" DELETE ",
|
|
21
|
-
" DROP ",
|
|
22
|
-
" ALTER ",
|
|
23
|
-
" CREATE ",
|
|
24
|
-
" TRUNCATE ",
|
|
25
|
-
" GRANT ",
|
|
26
|
-
" REVOKE ",
|
|
27
|
-
"--",
|
|
28
|
-
"/*",
|
|
29
|
-
];
|
|
30
|
-
const padded = ` ${stripped} `;
|
|
31
|
-
for (const keyword of blocked) {
|
|
32
|
-
if (padded.includes(keyword)) {
|
|
33
|
-
fail(`--where must not contain "${keyword.trim()}"`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
10
|
function parseEdits(parsed) {
|
|
38
11
|
let edits;
|
|
39
12
|
if (parsed.edits) {
|
|
@@ -352,10 +325,12 @@ Options:
|
|
|
352
325
|
if (!isValidIdentifier(table) || !isValidIdentifier(column)) {
|
|
353
326
|
fail("--table and --column must be plain identifiers");
|
|
354
327
|
}
|
|
355
|
-
|
|
328
|
+
validateRawDbPatchWhere(where);
|
|
356
329
|
assertNoSensitiveFrameworkTables(table, "patch");
|
|
357
330
|
assertNoRawDbAccessControlPatchTarget(table, column);
|
|
358
|
-
|
|
331
|
+
// `--where` is spliced into both statements, so each is read as a whole.
|
|
332
|
+
const select = finalRawDbSql(readRawDbPatchStatement(`SELECT "${column}" AS __val FROM "${table}" WHERE ${where}`, "select").sql, "read");
|
|
333
|
+
const update = finalRawDbSql(readRawDbPatchStatement(`UPDATE "${table}" SET "${column}" = ? WHERE ${where}`, "update").sql, "patch");
|
|
359
334
|
const jsonOps = parseJsonOps(parsed);
|
|
360
335
|
const options = {
|
|
361
336
|
table,
|
|
@@ -377,8 +352,10 @@ Options:
|
|
|
377
352
|
for (const statement of scoping.setup)
|
|
378
353
|
await tx.unsafe(statement);
|
|
379
354
|
try {
|
|
380
|
-
|
|
381
|
-
const selected = await tx.unsafe(
|
|
355
|
+
await verifyRawDbStatement(tx, select.statement);
|
|
356
|
+
const selected = await tx.unsafe(select.sql, [], {
|
|
357
|
+
singleStatement: true,
|
|
358
|
+
});
|
|
382
359
|
if (selected.length === 0) {
|
|
383
360
|
fail(`No rows matched: ${table} WHERE ${where}. ` +
|
|
384
361
|
"(Database scoping filters results to the current user; the row may exist but be owned by someone else.)");
|
|
@@ -392,7 +369,10 @@ Options:
|
|
|
392
369
|
}
|
|
393
370
|
const edited = applyEditsToValue(original, options);
|
|
394
371
|
if (edited.applied > 0) {
|
|
395
|
-
await tx
|
|
372
|
+
await verifyRawDbStatement(tx, update.statement);
|
|
373
|
+
await tx.unsafe(update.sql, [edited.content], {
|
|
374
|
+
singleStatement: true,
|
|
375
|
+
});
|
|
396
376
|
}
|
|
397
377
|
output = {
|
|
398
378
|
table,
|
|
@@ -1,8 +1,15 @@
|
|
|
1
1
|
export interface PostgresScriptRows extends Array<Record<string, unknown>> {
|
|
2
2
|
count?: number;
|
|
3
3
|
}
|
|
4
|
+
export interface PostgresScriptQueryOptions {
|
|
5
|
+
/**
|
|
6
|
+
* Have the server refuse text with more than one statement. Set it for
|
|
7
|
+
* agent-written SQL, so the database enforces what the guards checked.
|
|
8
|
+
*/
|
|
9
|
+
singleStatement?: boolean;
|
|
10
|
+
}
|
|
4
11
|
export interface PostgresScriptClient {
|
|
5
|
-
unsafe(sql: string, args?: unknown[]): Promise<PostgresScriptRows>;
|
|
12
|
+
unsafe(sql: string, args?: unknown[], options?: PostgresScriptQueryOptions): Promise<PostgresScriptRows>;
|
|
6
13
|
begin<T>(fn: (tx: PostgresScriptClient) => Promise<T>): Promise<T>;
|
|
7
14
|
end(): Promise<void>;
|
|
8
15
|
}
|
|
@@ -5,6 +5,8 @@ function rowsResult(rows, affectedRows) {
|
|
|
5
5
|
result.count = affectedRows ?? 0;
|
|
6
6
|
return result;
|
|
7
7
|
}
|
|
8
|
+
// PGlite's query() always uses the extended protocol, which runs one
|
|
9
|
+
// statement, so singleStatement needs no handling here.
|
|
8
10
|
function pgliteClient(client) {
|
|
9
11
|
return {
|
|
10
12
|
async unsafe(sql, args) {
|
|
@@ -30,16 +32,28 @@ export async function createPostgresScriptClient(url) {
|
|
|
30
32
|
const { default: postgres } = await import("postgres");
|
|
31
33
|
const client = postgres(url);
|
|
32
34
|
return {
|
|
33
|
-
|
|
34
|
-
return args === undefined
|
|
35
|
-
? client.unsafe(sql)
|
|
36
|
-
: client.unsafe(sql, args);
|
|
37
|
-
},
|
|
35
|
+
...postgresJsQueries(client),
|
|
38
36
|
async begin(fn) {
|
|
39
|
-
return client.begin((tx) => fn(
|
|
37
|
+
return client.begin((tx) => fn({
|
|
38
|
+
...postgresJsQueries(tx),
|
|
39
|
+
begin: () => {
|
|
40
|
+
throw new Error("Nested transactions are not supported.");
|
|
41
|
+
},
|
|
42
|
+
end: async () => { },
|
|
43
|
+
}));
|
|
40
44
|
},
|
|
41
45
|
end() {
|
|
42
46
|
return client.end();
|
|
43
47
|
},
|
|
44
48
|
};
|
|
45
49
|
}
|
|
50
|
+
function postgresJsQueries(sql) {
|
|
51
|
+
return {
|
|
52
|
+
unsafe(query, args, options) {
|
|
53
|
+
// postgres.js uses the simple protocol when there are no arguments, and
|
|
54
|
+
// that protocol runs every statement in the text. The extended protocol
|
|
55
|
+
// runs one.
|
|
56
|
+
return sql.unsafe(query, args ?? [], options?.singleStatement ? { simple: false } : undefined);
|
|
57
|
+
},
|
|
58
|
+
};
|
|
59
|
+
}
|
package/dist/scripts/db/query.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import { assertHostedRuntimeDatabase, getLocalDatabaseUrl,
|
|
2
|
+
import { assertHostedRuntimeDatabase, getLocalDatabaseUrl, } from "../../db/client.js";
|
|
3
3
|
import { getRequestOrgId, getRequestUserEmail, } from "../../server/request-context.js";
|
|
4
4
|
import { parseArgs, fail } from "../utils.js";
|
|
5
5
|
import { tryForwardDbQueryToDevServer } from "./dev-query-proxy.js";
|
|
6
6
|
import { createPostgresScriptClient } from "./postgres-client.js";
|
|
7
|
-
import {
|
|
7
|
+
import { finalRawDbSql, readRawDbReadStatement, verifyRawDbStatement, } from "./safety.js";
|
|
8
8
|
import { buildScopingPostgres } from "./scoping.js";
|
|
9
9
|
function parseSqlArgs(raw) {
|
|
10
10
|
if (!raw)
|
|
@@ -46,48 +46,46 @@ function printTable(rows, sql, format) {
|
|
|
46
46
|
.join(" | "));
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
|
+
// Thrown to end db-query's transaction with a rollback. The per-user views
|
|
50
|
+
// are created inside it, and the read-only switch blocks dropping them.
|
|
51
|
+
const READ_ONLY_ROLLBACK = Symbol("db-query rollback");
|
|
49
52
|
export async function runDbQuery(options) {
|
|
50
53
|
const sqlArgs = options.sqlArgs ?? [];
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
54
|
-
.trim();
|
|
55
|
-
const upper = stripped.toUpperCase();
|
|
56
|
-
if (!upper.startsWith("SELECT") &&
|
|
57
|
-
!upper.startsWith("WITH") &&
|
|
58
|
-
!upper.startsWith("EXPLAIN")) {
|
|
59
|
-
fail("Only SELECT, WITH, and EXPLAIN queries are allowed. Use db-exec for writes.");
|
|
60
|
-
}
|
|
61
|
-
assertNoSensitiveFrameworkTables(stripped, "read");
|
|
62
|
-
assertNoSchemaQualifiedTables(stripped, "read");
|
|
63
|
-
let query = options.sql;
|
|
54
|
+
const statement = readRawDbReadStatement(options.sql);
|
|
55
|
+
let query = statement.sql;
|
|
64
56
|
if (options.limit &&
|
|
65
|
-
(
|
|
66
|
-
|
|
67
|
-
query = `${
|
|
57
|
+
(statement.keyword === "select" || statement.keyword === "with") &&
|
|
58
|
+
!statement.tokens.some((token) => token.kind === "word" && token.value === "limit")) {
|
|
59
|
+
query = `${statement.sql}\nLIMIT ${options.limit}`;
|
|
68
60
|
}
|
|
61
|
+
const executed = finalRawDbSql(query, "read");
|
|
69
62
|
if (!options.databaseUrl)
|
|
70
63
|
assertHostedRuntimeDatabase();
|
|
71
64
|
const url = options.databaseUrl ?? getLocalDatabaseUrl("pglite:./data/pglite");
|
|
72
65
|
const client = await createPostgresScriptClient(url);
|
|
73
66
|
try {
|
|
74
67
|
let rows = [];
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
68
|
+
try {
|
|
69
|
+
await client.begin(async (tx) => {
|
|
70
|
+
const scoping = await buildScopingPostgres(tx);
|
|
71
|
+
for (const setup of scoping.setup)
|
|
72
|
+
await tx.unsafe(setup);
|
|
73
|
+
// From here on the transaction cannot write, so a data-modifying CTE,
|
|
74
|
+
// SELECT INTO, or EXPLAIN ANALYZE of a write fails instead of running.
|
|
75
|
+
await tx.unsafe("SET TRANSACTION READ ONLY");
|
|
76
|
+
await verifyRawDbStatement(tx, executed.statement);
|
|
77
|
+
const result = await tx.unsafe(executed.sql, sqlArgs, {
|
|
78
|
+
singleStatement: true,
|
|
79
|
+
});
|
|
82
80
|
rows = Array.from(result);
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
}
|
|
90
|
-
return { rows, sql:
|
|
81
|
+
throw READ_ONLY_ROLLBACK;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (error !== READ_ONLY_ROLLBACK)
|
|
86
|
+
throw error;
|
|
87
|
+
}
|
|
88
|
+
return { rows, sql: executed.sql };
|
|
91
89
|
}
|
|
92
90
|
finally {
|
|
93
91
|
await client.end();
|
|
@@ -1,4 +1,49 @@
|
|
|
1
|
+
import { type AgentPostgresStatement, type AgentSqlQueryRunner } from "../../agent-sql/postgres.js";
|
|
1
2
|
export declare function assertNoSensitiveFrameworkTables(sql: string, operation: "read" | "write" | "patch"): void;
|
|
2
|
-
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Reads one db-query statement and applies every check that needs no
|
|
5
|
+
* database. Returns the statement as it will run.
|
|
6
|
+
*/
|
|
7
|
+
export declare function readRawDbReadStatement(sql: string): AgentPostgresStatement;
|
|
8
|
+
/**
|
|
9
|
+
* Reads one db-exec statement and applies every check that needs no
|
|
10
|
+
* database, including the access-control write rules. `label` prefixes
|
|
11
|
+
* errors, e.g. "Statement 2".
|
|
12
|
+
*/
|
|
13
|
+
export declare function readRawDbWriteStatement(sql: string, label?: string): AgentPostgresStatement;
|
|
14
|
+
/**
|
|
15
|
+
* Converts `?` placeholders and re-reads the result, so the guards have seen
|
|
16
|
+
* exactly the text that executes. Refuses if converting again would change
|
|
17
|
+
* the text, since the PGlite client converts a second time.
|
|
18
|
+
*/
|
|
19
|
+
export declare function finalRawDbSql(sql: string, kind: "read" | "write" | "patch", label?: string): {
|
|
20
|
+
sql: string;
|
|
21
|
+
statement: AgentPostgresStatement;
|
|
22
|
+
};
|
|
23
|
+
/**
|
|
24
|
+
* The database-side checks: run inside the transaction, after the per-user
|
|
25
|
+
* views exist and immediately before the statement executes.
|
|
26
|
+
* `columnsByTable` comes from the scoping context; it lets an INSERT without a
|
|
27
|
+
* column list be refused when the table has access-control columns.
|
|
28
|
+
*/
|
|
29
|
+
export declare function verifyRawDbStatement(db: AgentSqlQueryRunner, statement: AgentPostgresStatement, options?: {
|
|
30
|
+
columnsByTable?: Map<string, string[]>;
|
|
31
|
+
label?: string;
|
|
32
|
+
}): Promise<void>;
|
|
33
|
+
/**
|
|
34
|
+
* The table an INSERT writes and the columns it lists, or null when the
|
|
35
|
+
* statement is not an INSERT the guards can read. `columns` is null when the
|
|
36
|
+
* INSERT has no column list.
|
|
37
|
+
*/
|
|
38
|
+
export declare function rawDbInsertTarget(statement: AgentPostgresStatement): {
|
|
39
|
+
table: string;
|
|
40
|
+
columns: string[] | null;
|
|
41
|
+
} | null;
|
|
4
42
|
export declare function assertNoRawDbAccessControlPatchTarget(table: string, column: string): void;
|
|
43
|
+
/**
|
|
44
|
+
* Validates db-patch's `--where`, which is spliced into a SELECT and an
|
|
45
|
+
* UPDATE. Both full statements are read and verified again before they run.
|
|
46
|
+
*/
|
|
47
|
+
export declare function validateRawDbPatchWhere(where: string): void;
|
|
48
|
+
/** Reads a statement db-patch built from its arguments. */
|
|
49
|
+
export declare function readRawDbPatchStatement(sql: string, keyword: "select" | "update"): AgentPostgresStatement;
|