@nylorun/runtime 0.15.2-beta → 0.17.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 +134 -0
- package/README.md +68 -29
- package/dist/adapters/execution/restate.d.ts +9 -1
- package/dist/adapters/execution/restate.js +64 -5
- package/dist/adapters/sandbox/local.d.ts +10 -0
- package/dist/adapters/sandbox/local.js +195 -0
- package/dist/adapters/sandbox/virtual.js +36 -1
- package/dist/admin-openapi.json +341 -7
- package/dist/api/a2a/tasks.js +6 -1
- package/dist/api/ag-ui/endpoint.js +1 -2
- package/dist/api/ag-ui/history.js +6 -1
- package/dist/api/ag-ui/routes.d.ts +1 -1
- package/dist/api/ag-ui/routes.js +15 -13
- package/dist/api/components.d.ts +2667 -711
- package/dist/api/components.js +24 -11
- package/dist/api/gate/keys.d.ts +4 -3
- package/dist/api/gate/routes.d.ts +19 -3
- package/dist/api/gate/routes.js +162 -53
- package/dist/api/http/app.js +6 -0
- package/dist/api/http/define.d.ts +19 -12
- package/dist/api/http/define.js +13 -27
- package/dist/api/http/routes/access.d.ts +3 -19
- package/dist/api/http/routes/access.js +12 -172
- package/dist/api/http/routes/actions.js +0 -1
- package/dist/api/http/routes/artifacts.d.ts +11 -0
- package/dist/api/http/routes/artifacts.js +516 -0
- package/dist/api/http/routes/me.d.ts +13 -0
- package/dist/api/http/routes/me.js +45 -0
- package/dist/api/http/routes/sandboxes.d.ts +9 -0
- package/dist/api/http/routes/sandboxes.js +150 -0
- package/dist/api/http/routes/sessions.js +9 -13
- package/dist/api/http/routes/tenant.js +36 -2
- package/dist/api/http/routes/vaults.d.ts +12 -3
- package/dist/api/http/routes/vaults.js +122 -54
- package/dist/api/openapi.js +4 -10
- package/dist/artifacts/config.d.ts +23 -0
- package/dist/artifacts/config.js +27 -0
- package/dist/artifacts/export.d.ts +8 -0
- package/dist/artifacts/export.js +205 -0
- package/dist/artifacts/files.d.ts +36 -0
- package/dist/artifacts/files.js +45 -0
- package/dist/artifacts/folders.d.ts +60 -0
- package/dist/artifacts/folders.js +209 -0
- package/dist/artifacts/links.d.ts +28 -0
- package/dist/artifacts/links.js +92 -0
- package/dist/artifacts/media-types.d.ts +13 -0
- package/dist/artifacts/media-types.js +80 -0
- package/dist/artifacts/parts.d.ts +34 -0
- package/dist/artifacts/parts.js +38 -0
- package/dist/artifacts/service.d.ts +74 -0
- package/dist/artifacts/service.js +301 -0
- package/dist/artifacts/workspace.d.ts +60 -0
- package/dist/artifacts/workspace.js +57 -0
- package/dist/artifacts/zip.d.ts +10 -0
- package/dist/artifacts/zip.js +126 -0
- package/dist/blob/fs.d.ts +13 -0
- package/dist/blob/fs.js +194 -0
- package/dist/blob/index.d.ts +9 -0
- package/dist/blob/index.js +9 -0
- package/dist/blob/s3.d.ts +42 -0
- package/dist/blob/s3.js +366 -0
- package/dist/blob/types.d.ts +108 -0
- package/dist/blob/types.js +85 -0
- package/dist/core/sandbox-routes.d.ts +2 -2
- package/dist/core/sandbox-routes.js +4 -3
- package/dist/execution/memory.d.ts +11 -1
- package/dist/execution/memory.js +77 -3
- package/dist/execution/types.d.ts +54 -1
- package/dist/execution/types.js +31 -0
- package/dist/gates/contract.d.ts +14 -13
- package/dist/gates/contract.js +13 -12
- package/dist/gates/egress.d.ts +72 -0
- package/dist/gates/egress.js +319 -0
- package/dist/gates/handler.d.ts +3 -0
- package/dist/gates/handler.js +3 -2
- package/dist/gates/http-client.d.ts +3 -2
- package/dist/gates/http-client.js +17 -6
- package/dist/gates/in-process.d.ts +13 -1
- package/dist/gates/in-process.js +11 -0
- package/dist/gates/inflight.d.ts +23 -4
- package/dist/gates/inflight.js +18 -4
- package/dist/gates/mcp-handler.js +5 -1
- package/dist/gates/model-gate.d.ts +6 -2
- package/dist/gates/tenant-vaults.d.ts +18 -9
- package/dist/gates/tenant-vaults.js +17 -12
- package/dist/gates/tool-calls.d.ts +9 -5
- package/dist/gates/tool-calls.js +6 -6
- package/dist/gates/tool-client.d.ts +9 -2
- package/dist/gates/tool-client.js +56 -22
- package/dist/gates/tool-contract.d.ts +12 -7
- package/dist/gates/tool-contract.js +10 -4
- package/dist/gates/tool-gate.d.ts +1 -0
- package/dist/harness/calls.d.ts +52 -0
- package/dist/harness/calls.js +113 -0
- package/dist/harness/executors.d.ts +22 -0
- package/dist/harness/executors.js +96 -0
- package/dist/harness/main.d.ts +6 -0
- package/dist/harness/main.js +103 -0
- package/dist/harness/pod.d.ts +21 -0
- package/dist/harness/pod.js +119 -0
- package/dist/harness/run-tokens.d.ts +18 -0
- package/dist/harness/run-tokens.js +15 -0
- package/dist/harness/service.d.ts +46 -0
- package/dist/harness/service.js +179 -0
- package/dist/harness/ws-client.d.ts +43 -0
- package/dist/harness/ws-client.js +122 -0
- package/dist/harness/ws-port.d.ts +22 -0
- package/dist/harness/ws-port.js +78 -0
- package/dist/harness-api/in-process.d.ts +24 -0
- package/dist/harness-api/in-process.js +119 -0
- package/dist/harness-api/record.d.ts +44 -0
- package/dist/harness-api/record.js +250 -0
- package/dist/harness-api/renew.d.ts +37 -0
- package/dist/harness-api/renew.js +77 -0
- package/dist/harness-api/server.d.ts +104 -0
- package/dist/harness-api/server.js +408 -0
- package/dist/harness-api/start.d.ts +36 -0
- package/dist/harness-api/start.js +118 -0
- package/dist/harness-api/workspace.d.ts +53 -0
- package/dist/harness-api/workspace.js +201 -0
- package/dist/harness-api/ws-server.d.ts +34 -0
- package/dist/harness-api/ws-server.js +227 -0
- package/dist/host/admin-api.d.ts +12 -5
- package/dist/host/admin-api.js +72 -6
- package/dist/host/app.d.ts +0 -1
- package/dist/host/app.js +35 -24
- package/dist/host/config-for.d.ts +4 -0
- package/dist/host/config-for.js +2 -0
- package/dist/host/config.d.ts +0 -6
- package/dist/host/create-host.d.ts +3 -10
- package/dist/host/create-host.js +4 -1
- package/dist/host/gates.d.ts +27 -2
- package/dist/host/gates.js +52 -2
- package/dist/host/http.d.ts +4 -1
- package/dist/host/http.js +6 -1
- package/dist/host/main.js +167 -37
- package/dist/host/stack-config.d.ts +112 -9
- package/dist/host/stack-config.js +222 -20
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/keys/client.js +9 -1
- package/dist/keys/keys.d.ts +12 -2
- package/dist/keys/keys.js +8 -0
- package/dist/mcp/connect.js +2 -1
- package/dist/mcp/pool.d.ts +1 -0
- package/dist/mcp/pool.js +1 -0
- package/dist/mcp/snapshot.d.ts +8 -1
- package/dist/mcp/snapshot.js +28 -0
- package/dist/media.d.ts +5 -24
- package/dist/media.js +5 -0
- package/dist/model/pi-model.d.ts +6 -2
- package/dist/model/pi-model.js +39 -22
- package/dist/node/index.d.ts +1 -1
- package/dist/node/index.js +1 -1
- package/dist/openapi.json +14084 -9426
- package/dist/record/index.d.ts +1 -0
- package/dist/record/index.js +1 -0
- package/dist/record/sandbox.d.ts +25 -0
- package/dist/record/sandbox.js +43 -0
- package/dist/sandbox/capability.d.ts +3 -0
- package/dist/sandbox/capability.js +10 -0
- package/dist/sandbox/egress-token.d.ts +26 -0
- package/dist/sandbox/egress-token.js +8 -0
- package/dist/sandbox/join.d.ts +37 -0
- package/dist/sandbox/join.js +165 -0
- package/dist/sandbox/manager.d.ts +99 -34
- package/dist/sandbox/manager.js +216 -84
- package/dist/sandbox/placement.d.ts +27 -0
- package/dist/sandbox/placement.js +44 -0
- package/dist/sandbox/pods/client.d.ts +90 -0
- package/dist/sandbox/pods/client.js +79 -0
- package/dist/sandbox/pods/lifecycle.d.ts +91 -0
- package/dist/sandbox/pods/lifecycle.js +178 -0
- package/dist/sandbox/pods/name.d.ts +1 -0
- package/dist/sandbox/pods/name.js +28 -0
- package/dist/sandbox/pods/network-gate.d.ts +25 -0
- package/dist/sandbox/pods/network-gate.js +71 -0
- package/dist/sandbox/pods/reconcile.d.ts +11 -0
- package/dist/sandbox/pods/reconcile.js +152 -0
- package/dist/sandbox/pods/spec.d.ts +45 -0
- package/dist/sandbox/pods/spec.js +62 -0
- package/dist/sandbox/records.d.ts +29 -0
- package/dist/sandbox/records.js +79 -0
- package/dist/sandbox/resolve.d.ts +5 -0
- package/dist/sandbox/resolve.js +3 -2
- package/dist/sandbox/session-sandbox.js +7 -5
- package/dist/sandbox/share.d.ts +11 -0
- package/dist/sandbox/share.js +10 -0
- package/dist/sandbox/tenant-config.d.ts +16 -1
- package/dist/sandbox/tenant-config.js +9 -0
- package/dist/sandbox/types.d.ts +29 -1
- package/dist/sandbox/types.js +13 -1
- package/dist/store/postgres/drizzle/0004_sandbox_resources.sql +20 -0
- package/dist/store/postgres/drizzle/0005_artifacts.sql +27 -0
- package/dist/store/postgres/drizzle/0006_folder_artifacts.sql +12 -0
- package/dist/store/postgres/drizzle/0007_sandbox_pods.sql +14 -0
- package/dist/store/postgres/drizzle/0008_installation_vaults.sql +2 -0
- package/dist/store/postgres/drizzle/0009_oauth_pending.sql +19 -0
- package/dist/store/postgres/drizzle/0010_oss_auth_removals.sql +3 -0
- package/dist/store/postgres/drizzle/meta/_journal.json +49 -0
- package/dist/store/postgres/record-writer.d.ts +6 -1
- package/dist/store/postgres/record-writer.js +20 -2
- package/dist/store/postgres/schema.d.ts +1168 -250
- package/dist/store/postgres/schema.js +174 -28
- package/dist/store/postgres/store.js +339 -103
- package/dist/store/postgres/tenant.d.ts +1 -1
- package/dist/store/postgres/tenant.js +2 -2
- package/dist/store/types.d.ts +163 -32
- package/dist/streams/control.d.ts +2 -5
- package/dist/streams/control.js +5 -8
- package/dist/streams/types.d.ts +8 -8
- package/dist/streams/types.js +1 -1
- package/dist/tenant/advance.js +218 -160
- package/dist/tenant/artifact-tool.d.ts +5 -0
- package/dist/tenant/artifact-tool.js +119 -0
- package/dist/tenant/auth.d.ts +13 -9
- package/dist/tenant/auth.js +25 -32
- package/dist/tenant/commands.js +31 -10
- package/dist/tenant/context.d.ts +83 -26
- package/dist/tenant/delivery-token.js +4 -4
- package/dist/tenant/effects.d.ts +24 -14
- package/dist/tenant/effects.js +10 -398
- package/dist/tenant/ephemeral.d.ts +14 -2
- package/dist/tenant/ephemeral.js +8 -1
- package/dist/tenant/history.d.ts +13 -23
- package/dist/tenant/history.js +14 -62
- package/dist/tenant/host-token.d.ts +92 -0
- package/dist/tenant/host-token.js +179 -0
- package/dist/tenant/identity-file.d.ts +75 -0
- package/dist/tenant/identity-file.js +202 -0
- package/dist/tenant/issuers.d.ts +48 -0
- package/dist/tenant/issuers.js +311 -0
- package/dist/tenant/jwt.js +3 -3
- package/dist/tenant/module.js +1 -0
- package/dist/tenant/operator-keys.d.ts +18 -0
- package/dist/tenant/operator-keys.js +55 -0
- package/dist/tenant/outbound.d.ts +30 -0
- package/dist/tenant/outbound.js +142 -10
- package/dist/tenant/paths.d.ts +2 -1
- package/dist/tenant/paths.js +3 -1
- package/dist/tenant/principals.d.ts +2 -11
- package/dist/tenant/principals.js +10 -30
- package/dist/tenant/reset.d.ts +5 -2
- package/dist/tenant/reset.js +22 -2
- package/dist/tenant/run-grants.d.ts +49 -0
- package/dist/tenant/run-grants.js +62 -0
- package/dist/tenant/run-token.d.ts +70 -0
- package/dist/tenant/run-token.js +138 -0
- package/dist/tenant/runtime.d.ts +42 -0
- package/dist/tenant/runtime.js +134 -33
- package/dist/tenant/sandboxes.d.ts +119 -0
- package/dist/tenant/sandboxes.js +551 -0
- package/dist/tenant/session-streams.d.ts +6 -10
- package/dist/tenant/session-streams.js +9 -27
- package/dist/tenant/session.d.ts +2 -13
- package/dist/tenant/session.js +4 -28
- package/dist/tenant/sessions.d.ts +6 -1
- package/dist/tenant/sessions.js +29 -2
- package/dist/tenant/signing-keys.d.ts +2 -1
- package/dist/tenant/signing-keys.js +2 -2
- package/dist/tenant/status.d.ts +8 -3
- package/dist/tenant/status.js +5 -0
- package/dist/tenant/streams.d.ts +8 -2
- package/dist/tenant/streams.js +25 -6
- package/dist/tenant/sweep.js +37 -4
- package/dist/tenant/types.d.ts +39 -1
- package/dist/tenant/worker.d.ts +11 -5
- package/dist/tenant/worker.js +12 -6
- package/dist/vault/crypto.d.ts +7 -0
- package/dist/vault/crypto.js +16 -0
- package/dist/vault/oauth.d.ts +55 -0
- package/dist/vault/oauth.js +186 -0
- package/dist/vault/service.d.ts +54 -7
- package/dist/vault/service.js +261 -17
- package/dist/vault/sources.d.ts +54 -0
- package/dist/vault/sources.js +185 -0
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +14 -10
- package/dist/adapters/media.d.ts +0 -24
- package/dist/adapters/media.js +0 -111
- package/dist/host/cors.d.ts +0 -27
- package/dist/host/cors.js +0 -64
- package/dist/tenant/access-policy.d.ts +0 -30
- package/dist/tenant/access-policy.js +0 -52
- package/dist/tenant/browser.d.ts +0 -15
- package/dist/tenant/browser.js +0 -39
- package/dist/tenant/subject-limits.d.ts +0 -16
- package/dist/tenant/subject-limits.js +0 -45
- package/dist/tenant/tokens.d.ts +0 -14
- package/dist/tenant/tokens.js +0 -180
package/dist/tenant/paths.js
CHANGED
|
@@ -24,7 +24,8 @@ export function hostPaths(hostRoot) {
|
|
|
24
24
|
* root after realpath.
|
|
25
25
|
*
|
|
26
26
|
* The directory holds what stays on the Host (the Tenant's data is its database): `home/`,
|
|
27
|
-
* `tmp/`, `sandboxes/`, `plugin-data/`, `
|
|
27
|
+
* `tmp/`, `sandboxes/`, `plugin-data/`, `blobs/` (the `fs` BlobStore, when the Host has no
|
|
28
|
+
* Object store), `logs/tenant.log`. The vault key is the one exception:
|
|
28
29
|
* it lives beside the Tenant directory, in `<hostRoot>/keys/vault-kek`, which the local stack
|
|
29
30
|
* mounts only into the gateway (F4.2), never into the runtime container.
|
|
30
31
|
*/
|
|
@@ -41,6 +42,7 @@ export function tenantPaths(hostRoot) {
|
|
|
41
42
|
tmp: join(root, "tmp"),
|
|
42
43
|
sandboxes: join(root, "sandboxes"),
|
|
43
44
|
pluginData: join(root, "plugin-data"),
|
|
45
|
+
blobs: join(root, "blobs"),
|
|
44
46
|
logs: join(root, "logs"),
|
|
45
47
|
log: join(root, "logs", "tenant.log"),
|
|
46
48
|
};
|
|
@@ -2,23 +2,14 @@ import type { InitialPrincipal } from "../store/postgres/tenant.js";
|
|
|
2
2
|
export type { PrincipalRow } from "../store/types.js";
|
|
3
3
|
/** Principal id of the Studio key derived from the admin key. */
|
|
4
4
|
export declare const STUDIO_PRINCIPAL_ID = "studio";
|
|
5
|
-
/** The derived principal Projects use (`PROJECT_PRINCIPAL_ID` in `@nylorun/admin`). */
|
|
6
|
-
export declare const PROJECT_PRINCIPAL_ID = "project";
|
|
7
|
-
/** The derived principals a Host registers when not told otherwise. */
|
|
8
|
-
export declare const DEFAULT_DERIVED_PRINCIPALS: readonly string[];
|
|
9
5
|
/** The Studio key of `tenantId`: HMAC-SHA256 of the admin key. */
|
|
10
6
|
export declare function deriveStudioKey(adminKey: string, tenantId: string): string;
|
|
11
|
-
/** The key of derived principal `principalId` on `tenantId`: HMAC-SHA256 of the admin key. */
|
|
12
|
-
export declare function deriveTenantKey(adminKey: string, tenantId: string, principalId: string): string;
|
|
13
|
-
/** Whether `id` may name a derived principal: the client's name, never `studio`. */
|
|
14
|
-
export declare function isDerivedPrincipalId(id: string): boolean;
|
|
15
7
|
/**
|
|
16
|
-
* The principals a Host's Tenant is created with: `studio`,
|
|
17
|
-
*
|
|
8
|
+
* The principals a Host's Tenant is created with: `studio`, and an application principal when
|
|
9
|
+
* a key is given (the ephemeral Runtime). Keys are hashed here.
|
|
18
10
|
*/
|
|
19
11
|
export declare function hostPrincipals(options: {
|
|
20
12
|
adminKey: string;
|
|
21
|
-
derived?: readonly string[];
|
|
22
13
|
application?: {
|
|
23
14
|
principalId: string;
|
|
24
15
|
key: string;
|
|
@@ -1,43 +1,27 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The principals the Host gives its Tenant when it creates it (tenancy.md §4
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* only their hashes.
|
|
2
|
+
* The principals the Host gives its Tenant when it creates it (tenancy.md §4): the Studio
|
|
3
|
+
* principal, whose key the admin key derives, so Studio (and an app embedding it) stores none,
|
|
4
|
+
* and, for the ephemeral Runtime, one application principal with a key of its own. The Tenant
|
|
5
|
+
* keeps only their hashes. Every other application key is an operator key
|
|
6
|
+
* (`PUT /v1/admin/keys/{id}`, `operator-keys.ts`); no other key is derived.
|
|
6
7
|
*
|
|
7
|
-
* The
|
|
8
|
-
* (`admin/src/derived-credentials.ts`: `deriveStudioToken
|
|
9
|
-
*
|
|
8
|
+
* The derivation is the one `@nylorun/admin` computes on the client side
|
|
9
|
+
* (`admin/src/derived-credentials.ts`: `deriveStudioToken`); both sides must stay byte for byte
|
|
10
|
+
* the same.
|
|
10
11
|
*/
|
|
11
12
|
import { createHmac } from "node:crypto";
|
|
12
|
-
import { DERIVED_PRINCIPAL_ID_PATTERN } from "@nylorun/core/compatibility";
|
|
13
13
|
import { hashToken } from "../core/bearer.js";
|
|
14
14
|
/** Principal id of the Studio key derived from the admin key. */
|
|
15
15
|
export const STUDIO_PRINCIPAL_ID = "studio";
|
|
16
|
-
/** The derived principal Projects use (`PROJECT_PRINCIPAL_ID` in `@nylorun/admin`). */
|
|
17
|
-
export const PROJECT_PRINCIPAL_ID = "project";
|
|
18
|
-
/** The derived principals a Host registers when not told otherwise. */
|
|
19
|
-
export const DEFAULT_DERIVED_PRINCIPALS = [PROJECT_PRINCIPAL_ID];
|
|
20
16
|
/** The Studio key of `tenantId`: HMAC-SHA256 of the admin key. */
|
|
21
17
|
export function deriveStudioKey(adminKey, tenantId) {
|
|
22
18
|
return hmac(adminKey, ["nylorun/studio/v1", tenantId]);
|
|
23
19
|
}
|
|
24
|
-
/** The key of derived principal `principalId` on `tenantId`: HMAC-SHA256 of the admin key. */
|
|
25
|
-
export function deriveTenantKey(adminKey, tenantId, principalId) {
|
|
26
|
-
return hmac(adminKey, ["nylorun/principal/v1", principalId, tenantId]);
|
|
27
|
-
}
|
|
28
|
-
/** Whether `id` may name a derived principal: the client's name, never `studio`. */
|
|
29
|
-
export function isDerivedPrincipalId(id) {
|
|
30
|
-
return DERIVED_PRINCIPAL_ID_PATTERN.test(id) && id !== STUDIO_PRINCIPAL_ID;
|
|
31
|
-
}
|
|
32
20
|
/**
|
|
33
|
-
* The principals a Host's Tenant is created with: `studio`,
|
|
34
|
-
*
|
|
21
|
+
* The principals a Host's Tenant is created with: `studio`, and an application principal when
|
|
22
|
+
* a key is given (the ephemeral Runtime). Keys are hashed here.
|
|
35
23
|
*/
|
|
36
24
|
export function hostPrincipals(options) {
|
|
37
|
-
const derived = options.derived ?? DEFAULT_DERIVED_PRINCIPALS;
|
|
38
|
-
for (const id of derived)
|
|
39
|
-
if (!isDerivedPrincipalId(id))
|
|
40
|
-
throw new Error(`Derived principal id '${id}' must match ${DERIVED_PRINCIPAL_ID_PATTERN} and not be '${STUDIO_PRINCIPAL_ID}'`);
|
|
41
25
|
return (tenantId) => [
|
|
42
26
|
...(options.application
|
|
43
27
|
? [
|
|
@@ -52,10 +36,6 @@ export function hostPrincipals(options) {
|
|
|
52
36
|
credentialHash: options.studioCredentialHash ??
|
|
53
37
|
hashToken(deriveStudioKey(options.adminKey, tenantId)),
|
|
54
38
|
},
|
|
55
|
-
...[...new Set(derived)].map((id) => ({
|
|
56
|
-
id,
|
|
57
|
-
credentialHash: hashToken(deriveTenantKey(options.adminKey, tenantId, id)),
|
|
58
|
-
})),
|
|
59
39
|
];
|
|
60
40
|
}
|
|
61
41
|
/** HMAC-SHA256 (hex) of `parts` joined by NUL bytes, keyed with the admin key. */
|
package/dist/tenant/reset.d.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import type { ResetScope, SessionStore } from "../store/types.js";
|
|
2
|
-
import type {
|
|
2
|
+
import type { WorkspacePort } from "../harness-api/workspace.js";
|
|
3
3
|
import type { TenantPaths } from "./types.js";
|
|
4
|
+
import type { BlobStore } from "../blob/index.js";
|
|
4
5
|
export type { ResetScope } from "../store/types.js";
|
|
5
6
|
export interface ResetTenantContext {
|
|
6
7
|
store: SessionStore;
|
|
7
|
-
sandbox:
|
|
8
|
+
sandbox: WorkspacePort;
|
|
8
9
|
paths: TenantPaths;
|
|
10
|
+
/** Where the deleted artifacts' bytes are; they are removed after the store wipe. */
|
|
11
|
+
blobs?: BlobStore;
|
|
9
12
|
/** Clear in-memory session observers after the store wipe. */
|
|
10
13
|
clearSessionState: () => void;
|
|
11
14
|
}
|
package/dist/tenant/reset.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, renameSync, rmSync, writeFileSync, } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { detachAllSessions } from "./sandboxes.js";
|
|
4
|
+
import { contentKey } from "../artifacts/folders.js";
|
|
3
5
|
/**
|
|
4
6
|
* Rename `dir` to a sibling, delete the sibling, recreate an empty `dir`.
|
|
5
7
|
* Failure before rename leaves the original intact; after rename the empty
|
|
@@ -39,11 +41,29 @@ export async function resetTenant(ctx, scope) {
|
|
|
39
41
|
const clearSandboxes = scope === "sandboxes" || scope === "all";
|
|
40
42
|
const clearAll = scope === "all";
|
|
41
43
|
if (clearSandboxes) {
|
|
42
|
-
await ctx.sandbox.
|
|
44
|
+
await ctx.sandbox.removeAll();
|
|
43
45
|
}
|
|
44
|
-
|
|
46
|
+
// The artifacts the reset deletes: their rows go in its transaction, their bytes after it.
|
|
47
|
+
const blobKeys = await ctx.store.tx(async (t) => {
|
|
48
|
+
// Sandbox resources outlive their sessions: a sessions reset only detaches them.
|
|
49
|
+
if (clearSessions && !clearSandboxes)
|
|
50
|
+
await detachAllSessions(t);
|
|
51
|
+
const scoped = clearAll ? "all" : "sessions";
|
|
52
|
+
const keys = clearSessions ? await t.artifactBlobKeys(scoped) : [];
|
|
53
|
+
// Folders' content-addressed files: those no remaining folder names (F8.2).
|
|
54
|
+
const content = clearSessions ? await t.artifactContentShas(scoped) : [];
|
|
55
|
+
await t.reset(scope);
|
|
56
|
+
const kept = await t.referencedArtifactContent(content);
|
|
57
|
+
for (const sha of content)
|
|
58
|
+
if (!kept.has(sha))
|
|
59
|
+
keys.push(contentKey(sha));
|
|
60
|
+
return keys;
|
|
61
|
+
});
|
|
45
62
|
if (clearSessions)
|
|
46
63
|
ctx.clearSessionState();
|
|
64
|
+
if (ctx.blobs)
|
|
65
|
+
for (const key of blobKeys)
|
|
66
|
+
await ctx.blobs.delete(key).catch(() => undefined);
|
|
47
67
|
if (clearSandboxes)
|
|
48
68
|
replaceDirectory(ctx.paths.sandboxes);
|
|
49
69
|
if (clearAll) {
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run grants (F5, gate trust): the run token each advance of this process holds while it owns
|
|
3
|
+
* a session (`run-token.ts`). The advance mints one when it takes the lease (`grantRun`), the
|
|
4
|
+
* lease heartbeat re-mints it before it expires (`renewRunGrant`), and it goes when the
|
|
5
|
+
* advance ends or loses the lease (`dropRunGrant`). The HTTP gate clients read the session's
|
|
6
|
+
* token on every request (`RunTokens`), so a re-mint applies to the next call.
|
|
7
|
+
*
|
|
8
|
+
* Only a Runtime whose gates are a service has grants (`TenantContext.runGrants`). With the
|
|
9
|
+
* gates in this process nothing is minted (G6): the trust boundary is the gate's HTTP route.
|
|
10
|
+
*/
|
|
11
|
+
import type { Lease, TenantContext } from "./context.js";
|
|
12
|
+
import { type RunGrant } from "./run-token.js";
|
|
13
|
+
/** What a gate client reads: the current run token of a session, if an advance holds one. */
|
|
14
|
+
export interface RunTokens {
|
|
15
|
+
token(sessionId: string): string | undefined;
|
|
16
|
+
}
|
|
17
|
+
/** The run grants of this process's advances, by session id. */
|
|
18
|
+
export interface RunGrants extends RunTokens {
|
|
19
|
+
get(sessionId: string): RunGrant | undefined;
|
|
20
|
+
set(grant: RunGrant): void;
|
|
21
|
+
/** Forgets the grant of `sessionId` if it is the one of `epoch`: a newer advance's stays. */
|
|
22
|
+
drop(sessionId: string, epoch: number): void;
|
|
23
|
+
}
|
|
24
|
+
export declare function createRunGrants(): RunGrants;
|
|
25
|
+
type GrantContext = Pick<TenantContext, "keys" | "config" | "runGrants">;
|
|
26
|
+
/** What a run token names of the session: its root agent and the turn the advance runs. */
|
|
27
|
+
export interface RunOf {
|
|
28
|
+
readonly agentId: string;
|
|
29
|
+
readonly activeTurnId: string | null;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Mints and registers the run token of the advance that just took `lease`. Nothing when the
|
|
33
|
+
* gates run in this process, or the session has no active turn (it makes no gate call).
|
|
34
|
+
*
|
|
35
|
+
* Never throws: an advance may make no gate call at all (a model the Tenant serves itself, a
|
|
36
|
+
* workflow step), so a keys service that does not answer must not stop it. Without a grant
|
|
37
|
+
* the session's model calls fail as when the gateway is down, its MCP requests use core's
|
|
38
|
+
* credential, and the heartbeat tries again (`renewRunGrant`).
|
|
39
|
+
*/
|
|
40
|
+
export declare function grantRun(ctx: GrantContext, lease: Lease, run: RunOf): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Re-mints the grant of `lease` when less than `RUN_TOKEN_RENEW_SECONDS` remain, or mints it
|
|
43
|
+
* when the first mint failed. `active` is false once the advance ended: a token minted after
|
|
44
|
+
* that is not registered.
|
|
45
|
+
*/
|
|
46
|
+
export declare function renewRunGrant(ctx: GrantContext, lease: Lease, run: RunOf, active?: () => boolean): Promise<void>;
|
|
47
|
+
/** Forgets the grant of `lease` (the advance ended, or lost the lease). */
|
|
48
|
+
export declare function dropRunGrant(ctx: Pick<TenantContext, "runGrants">, lease: Lease): void;
|
|
49
|
+
export {};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { mintRunToken, RUN_TOKEN_RENEW_SECONDS } from "./run-token.js";
|
|
2
|
+
export function createRunGrants() {
|
|
3
|
+
const grants = new Map();
|
|
4
|
+
return {
|
|
5
|
+
token: (sessionId) => grants.get(sessionId)?.token,
|
|
6
|
+
get: (sessionId) => grants.get(sessionId),
|
|
7
|
+
set(grant) {
|
|
8
|
+
const held = grants.get(grant.claims.sessionId);
|
|
9
|
+
// An older advance of the same session (a lease lost while it still ran) never replaces it.
|
|
10
|
+
if (held && held.claims.epoch > grant.claims.epoch)
|
|
11
|
+
return;
|
|
12
|
+
grants.set(grant.claims.sessionId, grant);
|
|
13
|
+
},
|
|
14
|
+
drop(sessionId, epoch) {
|
|
15
|
+
if (grants.get(sessionId)?.claims.epoch === epoch)
|
|
16
|
+
grants.delete(sessionId);
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Mints and registers the run token of the advance that just took `lease`. Nothing when the
|
|
22
|
+
* gates run in this process, or the session has no active turn (it makes no gate call).
|
|
23
|
+
*
|
|
24
|
+
* Never throws: an advance may make no gate call at all (a model the Tenant serves itself, a
|
|
25
|
+
* workflow step), so a keys service that does not answer must not stop it. Without a grant
|
|
26
|
+
* the session's model calls fail as when the gateway is down, its MCP requests use core's
|
|
27
|
+
* credential, and the heartbeat tries again (`renewRunGrant`).
|
|
28
|
+
*/
|
|
29
|
+
export async function grantRun(ctx, lease, run) {
|
|
30
|
+
if (!ctx.runGrants || !run.activeTurnId)
|
|
31
|
+
return;
|
|
32
|
+
try {
|
|
33
|
+
ctx.runGrants.set(await mintRunToken(ctx, lease, run));
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
ctx.config.logger.warn("advance could not mint its run token", {
|
|
37
|
+
sessionId: lease.sessionId,
|
|
38
|
+
message: error instanceof Error ? error.message : String(error),
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Re-mints the grant of `lease` when less than `RUN_TOKEN_RENEW_SECONDS` remain, or mints it
|
|
44
|
+
* when the first mint failed. `active` is false once the advance ended: a token minted after
|
|
45
|
+
* that is not registered.
|
|
46
|
+
*/
|
|
47
|
+
export async function renewRunGrant(ctx, lease, run, active = () => true) {
|
|
48
|
+
if (!ctx.runGrants || !run.activeTurnId)
|
|
49
|
+
return;
|
|
50
|
+
const held = ctx.runGrants.get(lease.sessionId);
|
|
51
|
+
if (held && held.claims.epoch !== lease.epoch)
|
|
52
|
+
return;
|
|
53
|
+
if (held && held.claims.expiresAt - Date.now() > RUN_TOKEN_RENEW_SECONDS * 1000)
|
|
54
|
+
return;
|
|
55
|
+
const grant = await mintRunToken(ctx, lease, held ? { agentId: held.claims.agentId, activeTurnId: held.claims.turnId } : run);
|
|
56
|
+
if (active())
|
|
57
|
+
ctx.runGrants.set(grant);
|
|
58
|
+
}
|
|
59
|
+
/** Forgets the grant of `lease` (the advance ended, or lost the lease). */
|
|
60
|
+
export function dropRunGrant(ctx, lease) {
|
|
61
|
+
ctx.runGrants?.drop(lease.sessionId, lease.epoch);
|
|
62
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { importJWK } from "jose";
|
|
2
|
+
import type { Keys } from "../keys/keys.js";
|
|
3
|
+
import type { SessionStore } from "../store/types.js";
|
|
4
|
+
import type { Lease } from "./context.js";
|
|
5
|
+
export declare const RUN_TOKEN_TYP = "nylorun-run+jwt";
|
|
6
|
+
export declare const RUN_TOKEN_AUD = "nylorun-gates";
|
|
7
|
+
/** How long a run token lives. */
|
|
8
|
+
export declare const RUN_TOKEN_TTL_SECONDS: number;
|
|
9
|
+
/** The lease heartbeat re-mints a token with less than this left. */
|
|
10
|
+
export declare const RUN_TOKEN_RENEW_SECONDS: number;
|
|
11
|
+
/** What a verified run token says: one lease of one session's turn. */
|
|
12
|
+
export interface RunClaims {
|
|
13
|
+
readonly tenantId: string;
|
|
14
|
+
readonly sessionId: string;
|
|
15
|
+
readonly turnId: string;
|
|
16
|
+
/** The session's root agent: the ledger's and the agent budget's scope. */
|
|
17
|
+
readonly agentId: string;
|
|
18
|
+
/** The lease epoch: the fence. */
|
|
19
|
+
readonly epoch: number;
|
|
20
|
+
/** Milliseconds since the epoch. */
|
|
21
|
+
readonly expiresAt: number;
|
|
22
|
+
}
|
|
23
|
+
/** A minted run token and what it says. */
|
|
24
|
+
export interface RunGrant {
|
|
25
|
+
readonly token: string;
|
|
26
|
+
readonly claims: RunClaims;
|
|
27
|
+
}
|
|
28
|
+
/** Who mints: the Tenant's keys and id (a `TenantContext` is one). */
|
|
29
|
+
export interface RunTokenSigner {
|
|
30
|
+
readonly keys: Keys;
|
|
31
|
+
readonly config: {
|
|
32
|
+
readonly tenantId: string;
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Mints the run token of `lease` over `session`'s active turn. Throws when the session has
|
|
37
|
+
* no active turn: there is no run to name.
|
|
38
|
+
*/
|
|
39
|
+
export declare function mintRunToken(signer: RunTokenSigner, lease: Lease, session: {
|
|
40
|
+
readonly agentId: string;
|
|
41
|
+
readonly activeTurnId: string | null;
|
|
42
|
+
}): Promise<RunGrant>;
|
|
43
|
+
/** A verified token's claims, or why it was refused (logged, never answered). */
|
|
44
|
+
export type RunTokenVerdict = {
|
|
45
|
+
readonly ok: true;
|
|
46
|
+
readonly claims: RunClaims;
|
|
47
|
+
} | {
|
|
48
|
+
readonly ok: false;
|
|
49
|
+
readonly reason: string;
|
|
50
|
+
};
|
|
51
|
+
type PublicKey = Awaited<ReturnType<typeof importJWK>>;
|
|
52
|
+
/**
|
|
53
|
+
* Public keys imported by key id. The key row is read on every verification, so a new key
|
|
54
|
+
* (a rotation) and a revoked one apply at once; only the imported key object is kept.
|
|
55
|
+
*/
|
|
56
|
+
export type RunTokenKeyCache = Map<string, PublicKey>;
|
|
57
|
+
/**
|
|
58
|
+
* Verifies a run token of Tenant `tenantId` against the public keys in `store`: everything a
|
|
59
|
+
* forger controls (size, shape, header) is checked before any key is read, then the
|
|
60
|
+
* signature, `iss`, `aud`, `typ`, lifetime and claims. A revoked key refuses even a token it
|
|
61
|
+
* signed while it was live.
|
|
62
|
+
*/
|
|
63
|
+
export declare function verifyRunToken(store: SessionStore, tenantId: string, raw: string, cache?: RunTokenKeyCache): Promise<RunTokenVerdict>;
|
|
64
|
+
/**
|
|
65
|
+
* Why calls under `claims` are stale, or undefined while its lease is still the session's
|
|
66
|
+
* (G4): the session's epoch is the token's, its active turn is the token's, and it is not
|
|
67
|
+
* cancelled. One indexed read of the session row.
|
|
68
|
+
*/
|
|
69
|
+
export declare function staleRun(store: SessionStore, claims: RunClaims): Promise<string | undefined>;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run tokens (F5, gate trust): the ES256 JWT core mints for one advance's lease of a session.
|
|
3
|
+
* It is the only credential of a model call at the gates, and the credential of a session's
|
|
4
|
+
* remote MCP calls. The gates take session, turn and agent from it, never from the body, and
|
|
5
|
+
* check on every call that the lease it names is still the session's (`staleRun`).
|
|
6
|
+
*
|
|
7
|
+
* Signed by the keys service with the Tenant's current signing key, like subject and delivery
|
|
8
|
+
* tokens, and told apart from them by `typ` and `aud`. Internal: not in `openapi.json`. A token
|
|
9
|
+
* lives `RUN_TOKEN_TTL_SECONDS`, no longer than a delivery token, so a key rotation never
|
|
10
|
+
* revokes a live one (`signing-keys.ts`).
|
|
11
|
+
*
|
|
12
|
+
* ```text
|
|
13
|
+
* header { alg: ES256, typ: nylorun-run+jwt, kid }
|
|
14
|
+
* claims { iss: urn:nylorun:tenant:<id>, aud: nylorun-gates, sub: <sessionId>,
|
|
15
|
+
* trn: <turnId>, agt: <root agentId>, epc: <lease epoch>, iat, exp, jti }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
import { randomUUID } from "node:crypto";
|
|
19
|
+
import { errors, importJWK, jwtVerify } from "jose";
|
|
20
|
+
import { tenantTokenIssuer } from "@nylorun/core/contracts";
|
|
21
|
+
import { CLOCK_TOLERANCE_SECONDS, tokenKeyId } from "./jwt.js";
|
|
22
|
+
export const RUN_TOKEN_TYP = "nylorun-run+jwt";
|
|
23
|
+
export const RUN_TOKEN_AUD = "nylorun-gates";
|
|
24
|
+
/** How long a run token lives. */
|
|
25
|
+
export const RUN_TOKEN_TTL_SECONDS = 15 * 60;
|
|
26
|
+
/** The lease heartbeat re-mints a token with less than this left. */
|
|
27
|
+
export const RUN_TOKEN_RENEW_SECONDS = 5 * 60;
|
|
28
|
+
/** Allowed spread between `iat` and `exp` beyond the lifetime. */
|
|
29
|
+
const LIFETIME_SLACK_SECONDS = 60;
|
|
30
|
+
/**
|
|
31
|
+
* Mints the run token of `lease` over `session`'s active turn. Throws when the session has
|
|
32
|
+
* no active turn: there is no run to name.
|
|
33
|
+
*/
|
|
34
|
+
export async function mintRunToken(signer, lease, session) {
|
|
35
|
+
const turnId = session.activeTurnId;
|
|
36
|
+
if (!turnId)
|
|
37
|
+
throw new Error(`Session ${lease.sessionId} has no active turn to mint a run token for`);
|
|
38
|
+
const tenantId = signer.config.tenantId;
|
|
39
|
+
const iat = Math.floor(Date.now() / 1000);
|
|
40
|
+
const exp = iat + RUN_TOKEN_TTL_SECONDS;
|
|
41
|
+
// Signed by the keys service (F4.2): this process never holds the private key.
|
|
42
|
+
const { token } = await signer.keys.sign({
|
|
43
|
+
typ: RUN_TOKEN_TYP,
|
|
44
|
+
claims: {
|
|
45
|
+
iss: tenantTokenIssuer(tenantId),
|
|
46
|
+
aud: RUN_TOKEN_AUD,
|
|
47
|
+
sub: lease.sessionId,
|
|
48
|
+
trn: turnId,
|
|
49
|
+
agt: session.agentId,
|
|
50
|
+
epc: lease.epoch,
|
|
51
|
+
iat,
|
|
52
|
+
exp,
|
|
53
|
+
jti: randomUUID(),
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
return {
|
|
57
|
+
token,
|
|
58
|
+
claims: {
|
|
59
|
+
tenantId,
|
|
60
|
+
sessionId: lease.sessionId,
|
|
61
|
+
turnId,
|
|
62
|
+
agentId: session.agentId,
|
|
63
|
+
epoch: lease.epoch,
|
|
64
|
+
expiresAt: exp * 1000,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Verifies a run token of Tenant `tenantId` against the public keys in `store`: everything a
|
|
70
|
+
* forger controls (size, shape, header) is checked before any key is read, then the
|
|
71
|
+
* signature, `iss`, `aud`, `typ`, lifetime and claims. A revoked key refuses even a token it
|
|
72
|
+
* signed while it was live.
|
|
73
|
+
*/
|
|
74
|
+
export async function verifyRunToken(store, tenantId, raw, cache = new Map()) {
|
|
75
|
+
const refused = (reason) => ({ ok: false, reason: `run_token_${reason}` });
|
|
76
|
+
const checked = tokenKeyId(raw, RUN_TOKEN_TYP);
|
|
77
|
+
if ("refused" in checked)
|
|
78
|
+
return refused(checked.refused);
|
|
79
|
+
const { kid } = checked;
|
|
80
|
+
const row = await store.tx((t) => t.signingKey(kid));
|
|
81
|
+
if (!row)
|
|
82
|
+
return refused("key_unknown");
|
|
83
|
+
let key = cache.get(kid);
|
|
84
|
+
if (!key) {
|
|
85
|
+
key = await importJWK({ ...JSON.parse(row.publicJwk), alg: "ES256" }, "ES256");
|
|
86
|
+
cache.set(kid, key);
|
|
87
|
+
}
|
|
88
|
+
let payload;
|
|
89
|
+
try {
|
|
90
|
+
const verified = await jwtVerify(raw, key, {
|
|
91
|
+
algorithms: ["ES256"],
|
|
92
|
+
issuer: tenantTokenIssuer(tenantId),
|
|
93
|
+
audience: RUN_TOKEN_AUD,
|
|
94
|
+
typ: RUN_TOKEN_TYP,
|
|
95
|
+
clockTolerance: CLOCK_TOLERANCE_SECONDS,
|
|
96
|
+
requiredClaims: ["sub", "iat", "exp", "jti"],
|
|
97
|
+
});
|
|
98
|
+
payload = verified.payload;
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
return refused(error instanceof errors.JWTExpired ? "expired" : "invalid");
|
|
102
|
+
}
|
|
103
|
+
if (row.state === "revoked")
|
|
104
|
+
return refused("key_revoked");
|
|
105
|
+
const { sub, trn, agt, epc, iat, exp } = payload;
|
|
106
|
+
if (typeof sub !== "string" ||
|
|
107
|
+
sub === "" ||
|
|
108
|
+
typeof trn !== "string" ||
|
|
109
|
+
trn === "" ||
|
|
110
|
+
typeof agt !== "string" ||
|
|
111
|
+
agt === "" ||
|
|
112
|
+
typeof epc !== "number" ||
|
|
113
|
+
!Number.isSafeInteger(epc) ||
|
|
114
|
+
epc < 1 ||
|
|
115
|
+
exp - iat > RUN_TOKEN_TTL_SECONDS + LIFETIME_SLACK_SECONDS)
|
|
116
|
+
return refused("claims");
|
|
117
|
+
return {
|
|
118
|
+
ok: true,
|
|
119
|
+
claims: { tenantId, sessionId: sub, turnId: trn, agentId: agt, epoch: epc, expiresAt: exp * 1000 },
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Why calls under `claims` are stale, or undefined while its lease is still the session's
|
|
124
|
+
* (G4): the session's epoch is the token's, its active turn is the token's, and it is not
|
|
125
|
+
* cancelled. One indexed read of the session row.
|
|
126
|
+
*/
|
|
127
|
+
export async function staleRun(store, claims) {
|
|
128
|
+
const state = await store.tx((t) => t.runState(claims.sessionId));
|
|
129
|
+
if (!state)
|
|
130
|
+
return "the session is gone";
|
|
131
|
+
if (state.epoch !== claims.epoch)
|
|
132
|
+
return "another advance owns the session now";
|
|
133
|
+
if (state.activeTurnId !== claims.turnId)
|
|
134
|
+
return "the turn has ended";
|
|
135
|
+
if (state.status === "cancelled")
|
|
136
|
+
return "the turn was cancelled";
|
|
137
|
+
return undefined;
|
|
138
|
+
}
|
package/dist/tenant/runtime.d.ts
CHANGED
|
@@ -8,6 +8,13 @@ import { type StreamsStatus } from "./streams.js";
|
|
|
8
8
|
import { type TenantExecution, type TenantWorker } from "./worker.js";
|
|
9
9
|
import { type ToolGate } from "../gates/tool-gate.js";
|
|
10
10
|
import { type Keys } from "../keys/keys.js";
|
|
11
|
+
import type { RunGrants } from "./run-grants.js";
|
|
12
|
+
import { type BlobStore } from "../blob/index.js";
|
|
13
|
+
import type { HarnessChannel, MemoryPortsOptions } from "@nylorun/core/harness-api";
|
|
14
|
+
import { type HarnessPeer } from "../harness-api/server.js";
|
|
15
|
+
import { type HostAuthority } from "../sandbox/join.js";
|
|
16
|
+
import type { TenantPods } from "./context.js";
|
|
17
|
+
import { type OperatorKeys } from "./operator-keys.js";
|
|
11
18
|
/** TENANTS-CCR: test/injection hooks until TenantConfig gains them. */
|
|
12
19
|
export type TenantOpenHooks = {
|
|
13
20
|
modelProvider?: ModelProvider;
|
|
@@ -26,6 +33,11 @@ export type TenantOpenHooks = {
|
|
|
26
33
|
* process never reads, creates or holds the vault key. Without one, it does them here.
|
|
27
34
|
*/
|
|
28
35
|
keys?: Keys;
|
|
36
|
+
/**
|
|
37
|
+
* The run grants the gates service's clients read (F5): each advance mints its session's
|
|
38
|
+
* run token into them. Give the same object to `modelGate` and `toolGate`.
|
|
39
|
+
*/
|
|
40
|
+
runGrants?: RunGrants;
|
|
29
41
|
vaultKek?: Buffer | string | null;
|
|
30
42
|
/** When true, create the KEK file on first vault write (tests / new Tenants). */
|
|
31
43
|
createKekIfMissing?: boolean;
|
|
@@ -50,6 +62,28 @@ export type TenantOpenHooks = {
|
|
|
50
62
|
hostRelay?: boolean;
|
|
51
63
|
/** How long a retired stream basin is kept after a reset (tests). Default 60 s. */
|
|
52
64
|
retireGraceMs?: number;
|
|
65
|
+
/**
|
|
66
|
+
* The Object store, owned by the caller (the Host's `s3` BlobStore, D35). Without one the
|
|
67
|
+
* Tenant keeps blobs on disk under `paths.blobs` (the `fs` adapter: embedding, tests).
|
|
68
|
+
*/
|
|
69
|
+
blobs?: BlobStore;
|
|
70
|
+
/**
|
|
71
|
+
* The Tenant's harness (F6.1, F6.2): `memory` (default) runs one in this process over a memory
|
|
72
|
+
* channel, with the Tenant's MCP pool and SandboxManager; `json` the same through JSON with
|
|
73
|
+
* every frame validated (tests). `remote` runs none: harnesses attach with
|
|
74
|
+
* `TenantHandle.attachHarness` (the Harness API listener, `NYLORUN_HARNESS=remote`), and the
|
|
75
|
+
* one that declares `workspace` holds the workspaces; this process has no MCP pool and no
|
|
76
|
+
* SandboxManager. `ws` is `remote` with a harness service in this process over a loopback
|
|
77
|
+
* WebSocket (tests).
|
|
78
|
+
*/
|
|
79
|
+
harness?: "memory" | "json" | "ws" | "remote";
|
|
80
|
+
/** Sees each frame of the in-process harness's channel (tests and benchmarks). */
|
|
81
|
+
harnessTap?: MemoryPortsOptions["tap"];
|
|
82
|
+
/**
|
|
83
|
+
* Sandbox pods (F7.2): the sandboxes service (`NYLORUN_SANDBOXES_URL`) and the Runtime image
|
|
84
|
+
* pods copy the engine from. Without it, kind `pod` is `sandbox_unavailable`.
|
|
85
|
+
*/
|
|
86
|
+
pods?: TenantPods;
|
|
53
87
|
} & OpenedTenant;
|
|
54
88
|
export declare class TenantRuntime implements TenantHandle {
|
|
55
89
|
private readonly ctx;
|
|
@@ -59,12 +93,17 @@ export declare class TenantRuntime implements TenantHandle {
|
|
|
59
93
|
private readonly detach;
|
|
60
94
|
/** How long close waits for running advances: the execution's advance grace period. */
|
|
61
95
|
private readonly closeGraceMs;
|
|
96
|
+
private readonly harness?;
|
|
97
|
+
private readonly hosts?;
|
|
62
98
|
private constructor();
|
|
99
|
+
/** The Tenant's side of a sandbox pod's join (F7.2). */
|
|
100
|
+
hostAuthority(): HostAuthority | undefined;
|
|
63
101
|
static open(config: TenantConfig, hooks: TenantOpenHooks): Promise<TenantRuntime>;
|
|
64
102
|
fetch(request: Request, node: NodeBindings): Promise<Response>;
|
|
65
103
|
authorize(sessionId: string, request: {
|
|
66
104
|
url: string;
|
|
67
105
|
serverName?: string;
|
|
106
|
+
agentId?: string;
|
|
68
107
|
}): Promise<AuthorizeResult>;
|
|
69
108
|
summary(): Promise<TenantSummary>;
|
|
70
109
|
drain(activeWork: "drain" | "cancel", timeoutMs?: number): Promise<void>;
|
|
@@ -80,6 +119,9 @@ export declare class TenantRuntime implements TenantHandle {
|
|
|
80
119
|
streamsStatus(): Promise<StreamsStatus>;
|
|
81
120
|
/** Adds a callback to the Tenant sweep. Returns a function that removes it. */
|
|
82
121
|
onSweep(hook: () => Promise<void>): () => void;
|
|
122
|
+
attachHarness(channel: HarnessChannel, peer: HarnessPeer): () => void;
|
|
123
|
+
/** The Tenant's operator keys (F9 I1), over its store. */
|
|
124
|
+
operatorKeys(): OperatorKeys;
|
|
83
125
|
close(): Promise<void>;
|
|
84
126
|
}
|
|
85
127
|
/**
|