nylorun 0.8.0-beta → 0.11.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 +138 -0
- package/README.md +78 -34
- package/dist/cli.js +12 -2
- package/dist/doctor.js +2 -2
- package/dist/project/link.d.ts +21 -7
- package/dist/project/link.js +30 -6
- package/dist/project/seed.d.ts +2 -1
- package/dist/project/seed.js +5 -5
- package/dist/stack/commands.d.ts +39 -12
- package/dist/stack/commands.js +163 -111
- package/dist/stack/compose-file.d.ts +15 -14
- package/dist/stack/compose-file.js +40 -41
- package/dist/stack/env-file.d.ts +3 -17
- package/dist/stack/env-file.js +6 -41
- package/dist/stack/host-files.d.ts +0 -3
- package/dist/stack/host-files.js +2 -3
- package/dist/stack/index.d.ts +6 -0
- package/dist/stack/index.js +12 -1
- package/dist/stack/keys.d.ts +4 -0
- package/dist/stack/keys.js +74 -0
- package/dist/stack/mcp.d.ts +8 -0
- package/dist/stack/mcp.js +114 -0
- package/dist/stack/operator-keys.d.ts +39 -0
- package/dist/stack/operator-keys.js +138 -0
- package/dist/stack/paths.d.ts +18 -12
- package/dist/stack/paths.js +5 -7
- package/dist/stack/ports.d.ts +0 -2
- package/dist/stack/ports.js +0 -2
- package/dist/stack/prepare.d.ts +2 -4
- package/dist/stack/prepare.js +4 -7
- package/dist/stack/sandbox.js +1 -1
- package/package.json +4 -4
- package/dist/project/derived-key.d.ts +0 -8
- package/dist/project/derived-key.js +0 -18
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,143 @@
|
|
|
1
1
|
# nylorun
|
|
2
2
|
|
|
3
|
+
## 0.11.0-beta
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 713e676: **Remote MCP servers only (blueprint D47).** Nylorun accepts `streamable-http` and `sse` MCP servers, declared by URL and reached through the gates; stdio servers and plugin roots are gone. See MIGRATION.md.
|
|
8
|
+
|
|
9
|
+
- **Breaking (`@nylorun/core`):** `McpServerManifest` and the manifest schema keep only `streamable-http` and `sse`. A `stdio` server is refused by `.mcp({...})` (`McpError`, code `mcp.stdio`), by `Agent.from` and by the wire schema, all with one message (`stdioMcpRefusal`): "MCP server 'x' uses stdio; Nylorun accepts remote MCP servers only (streamable-http or sse). Run the server behind an HTTP transport and declare its URL." `PutAgentRequest` loses `pluginRoots`, `CapabilityDeclaration` loses `pluginRoot`, and the Harness API's `RunRouting` loses `pluginRoots`.
|
|
10
|
+
- **Breaking (`@nylorun/agents`):** `.plugin()` and `plugin()` throw `PluginError` (code `plugin.mcp-stdio`) for a stdio server in a plugin's `mcp.json`; its remote servers and skills load as before. `saveAgent` no longer sends plugin roots. `prepareStdioLaunch`, `expandPluginPlaceholders` and `StdioLaunch` are removed.
|
|
11
|
+
- **Breaking (`@nylorun/runtime`):** no stdio MCP launcher: `PUT /v1/agents/:id` refuses a stdio server (`400`) and `pluginRoots`. `TenantConfig.childEnv`, `TenantPaths.pluginData` and `tmp`, `tenantChildEnvironment`, `startEphemeralRuntime({ baseline })` and `configForFactory`'s `baseline` and `hostConfig` are removed; the harness service no longer takes `childEnv` or `paths.pluginData`.
|
|
12
|
+
- `nylorun`: the local stack no longer mounts the Host root's `plugins/` into the runtime and harness containers, nor the Tenant's `plugin-data/`, `home/` and `tmp/` into the harness, which now mounts only `sandboxes/`.
|
|
13
|
+
|
|
14
|
+
- c135267: **Action endpoints are removed (manifest-only agents, M6).** The Runtime runs no code of yours during a session: an agent's tools are HTTP tools, remote MCP servers, agents used as tools and the Runtime's built-ins. Protocol stays 8; the `action-endpoints` feature is gone, so a client that requires it is refused. See MIGRATION.md, "Action endpoints are removed".
|
|
15
|
+
|
|
16
|
+
- **Breaking (`@nylorun/core`):** the `Action`, endpoint (`PutEndpointsRequest`, `Endpoint`, `EndpointHealth`, …) and delivery schemas, `SIGNATURE_HEADER`, `OUTCOME_HEADER`, `DELIVERY_TOKEN_TYPE` and the `action.*` events (`action.pending`, `.delivered`, `.delivery_failed`, `.completed`, `.uncertain`) are removed, and `ToolDefinition.background` with them. `ActionOutcome` is renamed `EffectOutcome`. Tenant status loses `checks.endpoints`, `agents[].registered` and `agents[].endpoint`, and `counts.pendingActions`; the session view loses `actions`. A `turn.paused` interaction carries the tool call's `callId`. New `codeToolsOf` and `codeToolRefusal` name a definition's tools that would run your code. The Harness API is v2 (`HARNESS_API_VERSION = 2`): `TurnStart.options.holdMs` and `effect.resolved` are removed.
|
|
17
|
+
- **Breaking (`@nylorun/harness`):** held runs are gone: `createHarness` loses `holdMs`, and `apiHost` its `hold` option.
|
|
18
|
+
- **Breaking (`@nylorun/agents`):** `createActionHandler`, `executeAction`, `createActionSandbox`, `definitionDeclaresSandbox`, `isActionSandboxTool` and the `Action`, `ActionOutcome`, `ActionHandler`, `ActionHandlerOptions`, `RegisterOptions`, `ExecuteActionOptions` and `ExecutableDefinition` types are removed. `saveAgent` refuses a code tool (`tool({ run })`) or a flow tool stage before sending; its `implementationVersion` is optional (`NYLORUN_IMPLEMENTATION_VERSION`, else `dev`).
|
|
19
|
+
- **Breaking (`@nylorun/runtime`):** `/v1/endpoints` and `/v1/actions/*` answer `404`; delivery tokens, the deliverer, background tools, held runs (`TenantConfig.actionHoldMs`), `DurableExecution.deliver`, the Restate `NylorunAction` object, the `action_result` wake and the gates service's `/nylorun/v1/deliveries` are removed, and a migration drops the `actions` and `endpoints` tables. `PUT /v1/agents/:id` refuses a definition with a code tool or a flow tool stage (`400`); a tool the Runtime cannot run fails with `tool.unavailable`. The fixture model answers in text when the agent offers no `lookup_order` tool.
|
|
20
|
+
- **Breaking (`@nylorun/cli`):** `nylo endpoints` is removed (a usage error that says why); `nylo status` shows uncertain effects instead of pending Actions.
|
|
21
|
+
- **Breaking (`@nylorun/create-agent`):** the starter saves its agent with `saveAgent` and runs no server: no Action endpoint, `PORT` or `NYLORUN_ACTIONS_URL`. Its assistant has no tools, with a commented `http()` tool to start from.
|
|
22
|
+
- `nylorun`: the local stack's comments speak of MCP servers and HTTP tools on this machine, not Action endpoints.
|
|
23
|
+
- `@nylorun/studio`: the `action.*` event views and delivery status are removed; the chat shows `tool.completed`, and the Agent Manifest tab lists tools without a target as code tools.
|
|
24
|
+
|
|
25
|
+
### Patch Changes
|
|
26
|
+
|
|
27
|
+
- Pin core to the tested release.
|
|
28
|
+
- Pin runtime to the tested release.
|
|
29
|
+
- Pin studio to the tested release.
|
|
30
|
+
- Updated dependencies [4bd2a0b]
|
|
31
|
+
- Updated dependencies [a64aaca]
|
|
32
|
+
- Updated dependencies [40b7648]
|
|
33
|
+
- Updated dependencies [713e676]
|
|
34
|
+
- Updated dependencies [c135267]
|
|
35
|
+
- Updated dependencies [d36f0d9]
|
|
36
|
+
- Updated dependencies [107b07d]
|
|
37
|
+
- @nylorun/core@0.15.0-beta
|
|
38
|
+
|
|
39
|
+
## 0.10.0-beta
|
|
40
|
+
|
|
41
|
+
### Major Changes
|
|
42
|
+
|
|
43
|
+
- 7f763c3: **The Admin API and the operator listener are gone (Runtime and Management APIs, step A5).** Host work moves to the machine: `nylorun` runs `nylorun-operate` inside the runtime container, and every remote client uses the Runtime API or the Management API.
|
|
44
|
+
|
|
45
|
+
- **Breaking (`@nylorun/runtime`):** `/v1/admin/*` (status, host, shutdown, keys, openapi.json) is removed; it answers like any unknown route. The operator listener, `NYLORUN_ADMIN_LISTEN_PORT`, `NYLORUN_ADMIN_LISTEN_HOST`, `NYLORUN_ADMIN_ALLOWED_HOSTS` and `host.json`'s `adminPort` are gone, and so is the `admin-openapi.json` package file. Stop the Host with SIGTERM. `nylorun-operate status [--json]` reports the version, protocol and the Tenant's id, name, state and cause, exiting 2 when the Tenant is not open. `/ready` adds `harness: { mode, connected }` while the Tenant is open. `startEphemeralRuntime` loses `operatorListener` and `adminUrl`. The admin key stays: it derives Studio's key.
|
|
46
|
+
- **Breaking (`@nylorun/admin`):** `createAdmin()` is the Management API client (`tenant`, `keys`, `models`, `vaults`, `signingKeys`, `settings`) with a management key: explicit `{ url, key }`, else `NYLORUN_RUNTIME_URL` + `NYLORUN_MANAGEMENT_KEY`, else the Project link's or the local Host root's management key. `status()`, `adminUrl`, the Admin API keys, `NYLORUN_ADMIN_URL`/`NYLORUN_ADMIN_KEY` and `OPERATOR_KEYS_FEATURE` are removed; `deriveStudioToken` and `mintStudioLoginToken` stay.
|
|
47
|
+
- **Breaking (`@nylorun/core`):** `admin-status` leaves `PROTOCOL_FEATURES` (the Host still advertises it for protocol 5–7 clients) and `operator-keys` is removed; `AdminStatusSchema`, `AdminHostStatusSchema`, `HostAggregateSchema` and `HostShutdownResponseSchema` are removed.
|
|
48
|
+
- **Breaking (`nylorun`):** no admin port: `NYLORUN_ADMIN_PORT` is no longer written or published (an existing one is ignored). `nylorun start` waits for `/ready`, and `nylorun status` reads readiness from `/ready` and the Tenant from `nylorun-operate status`.
|
|
49
|
+
- `@nylorun/cli`: `nylo status` no longer falls back to the Admin API; when the Tenant does not answer it points to `npx nylorun status`.
|
|
50
|
+
|
|
51
|
+
### Minor Changes
|
|
52
|
+
|
|
53
|
+
- 3b3bdc6: **The clients use management keys (Runtime and Management APIs, step A3).** The protocol stays at 7; every client keeps working against a protocol 7 Runtime's routes.
|
|
54
|
+
|
|
55
|
+
- `nylorun`: `nylorun start` keeps an application key (`project`) and a management key (`project-management`) for a Project, in `<Host root>/project-credentials.json` and the Project's `.nylorun/credentials.json` (still format 1, with new `managementKey` and `managementPrincipalId` fields). A credentials file holding only an application key gains a management key at the next start. Commands outside a project keep `cli` and `cli-management`. Keys are issued through `nylorun-operate` in the runtime container instead of the Admin API, and `nylorun key put <id> --management` puts a management key. Seeding the Tenant and `nylorun mcp connect` use the management key (`/v1/tenant/vaults`). Studio reaches the Runtime's public listener.
|
|
56
|
+
- `@nylorun/cli`: `status`, `reset`, `configure`, `doctor` and `access signing-keys` use the Management API through `@nylorun/admin` with the Project's management key, or `NYLORUN_MANAGEMENT_KEY`.
|
|
57
|
+
- `@nylorun/studio`: local Studio needs no login. A request on the published loopback address (`localhost` or `127.0.0.1` at Studio's port) acts as signed in; hosts behind a sign-in proxy and embedding keep their login, and state-changing requests still need Studio's own `Origin`. Studio learns its Tenant from `GET /v1/tenant` with its key instead of the Admin API, and its Connections page manages vaults through `@nylorun/admin/client` at `/v1/tenant/vaults`.
|
|
58
|
+
- **Breaking (`@nylorun/admin`, `@nylorun/runtime`): Studio's key is derived from the admin key alone.** `deriveStudioToken(adminKey)` takes no Tenant id (HMAC-SHA256 over `nylorun/studio/v2`). The Host registers the new key's hash at its next start, replacing the old one; an app that embeds Studio and derives its key must update.
|
|
59
|
+
- `@nylorun/core`: `ProjectCredentialsFileSchema` gains optional `managementKey` and `managementPrincipalId`.
|
|
60
|
+
|
|
61
|
+
### Patch Changes
|
|
62
|
+
|
|
63
|
+
- b28bdd7: **Local MCP servers work on a local Tenant, and a server that does not connect shows.** Additive; the protocol stays at 7.
|
|
64
|
+
|
|
65
|
+
- `@nylorun/runtime`: remote MCP servers (`streamable-http`, `sse`) are reached under the Host's address policy, as Action endpoints are (`NYLORUN_ENDPOINT_*`, `tenant/outbound.ts`). In the local Docker stack `localhost`, `127.0.0.1` and `[::1]` now mean the machine that runs Docker (`host.docker.internal`), so `.mcp({ x: { type: "streamable-http", url: "http://localhost:3002/x" } })` connects where it used to fail with `fetch failed`. With `NYLORUN_ENDPOINT_PRIVATE=refuse` a server on a private address is refused; with `NYLORUN_ENDPOINT_HTTP=refuse` an `http` server is refused. Redirects are still not followed. A connection failure now names its cause (`connect ECONNREFUSED …`) instead of `fetch failed`. This applies in the gateway, a harness process and an in-process Tenant. `guardedFetch` takes `stream: true`: the answer streams, unbounded, with no timeout but the caller's signal.
|
|
66
|
+
- `@nylorun/core`: new session event `mcp.discovered`, recorded once on the session's first turn with the MCP snapshot: one entry per declared server with `outcome` (`connected`, `refused`, `failed`), `message` and the number of `tools` it added (`McpDiscoveredPayloadSchema`, `McpServerOutcomeSchema`). A server that does not connect adds no tools for the session's life; this is where that shows in the event log, beside `mcpDiagnostics`.
|
|
67
|
+
- `@nylorun/agents`: `.plugin()` and `plugin()` emit a process warning (`NylorunPluginWarning`, the diagnostic's code) for each part of the package they skip, so building or registering the agent says when a plugin's MCP server was dropped. The `plugin.mcp-server-skipped` message now says why: for example, plain `http` is accepted only for `localhost`, `127.0.0.1` or `[::1]`.
|
|
68
|
+
- `@nylorun/studio`: the event list labels `mcp.discovered` and summarizes each server's outcome.
|
|
69
|
+
|
|
70
|
+
- 7a22f7f: **`nylorun start` opens no browser.** `start` (and `up`) prints the Runtime and Studio URLs, says to run `nylorun studio` to sign a browser in to Studio, and ends with a pointer to `nylorun --help`. It no longer mints a Studio login token or opens Studio, also in a terminal. `--no-open` is still accepted and ignored. `nylorun studio` signs a browser in as before.
|
|
71
|
+
- Pin core to the tested release.
|
|
72
|
+
- Pin runtime to the tested release.
|
|
73
|
+
- Pin studio to the tested release.
|
|
74
|
+
- Updated dependencies [3b3bdc6]
|
|
75
|
+
- Updated dependencies [6576e12]
|
|
76
|
+
- Updated dependencies [b28bdd7]
|
|
77
|
+
- Updated dependencies [cc107b1]
|
|
78
|
+
- Updated dependencies [7f763c3]
|
|
79
|
+
- Updated dependencies [98b0d37]
|
|
80
|
+
- Updated dependencies [c66d8ed]
|
|
81
|
+
- @nylorun/core@0.14.0-beta
|
|
82
|
+
|
|
83
|
+
## 0.9.0-beta
|
|
84
|
+
|
|
85
|
+
### Major Changes
|
|
86
|
+
|
|
87
|
+
- bd478ee: **Subject tokens, browser keys and derived principals leave open source (F9 I3, protocol 7).** Upgrade these with the Runtime: they speak protocol 7, which this Runtime serves beside 4, 5 and 6; protocol 6 clients keep working on every route that remains. Browsers and apps present a trusted issuer's token (F9 I2), servers an operator key (F9 I1), and a person's own credentials come from the operator's credential resolver (F9 C1). See MIGRATION.md.
|
|
88
|
+
|
|
89
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): subject tokens are gone.** `POST /v1/tokens`, `POST /v1/access/revocations`, subject-token verification, revocation epochs and the `subject.revoked` stream signal are removed; the routes answer `404`, and a JWT no trusted issuer signed is the opaque `404`. A stream opened with a token now ends only at its expiry (`event: nylorun.closed`, reason `token_expired`; `StreamClosedFrame` loses `revoked`). Migration `0010_oss_auth_removals` drops the `subject_epochs`, `subject_usage` and `publishable_keys` tables. The `token` caller is a trusted issuer's token only: it loses `role`, `limits` and `epoch`, and `issuer` is always set; `GET /v1/me` no longer reports `via: token`. Core drops `SUBJECT_TOKEN_TYPE`, `SUBJECT_TOKEN_AUDIENCE`, `subjectTokenIssuer` (the Runtime's own tokens use `tenantTokenIssuer`, same value), `CreateTokenRequest`/`Response`, `RevokeSubject*`, `SubjectTokenClaims`, `TOKEN_TTL_MIN_SECONDS` and `TOKEN_TTL_DEFAULT_SECONDS`; `TOKEN_SCOPES` is `agents:read`, `sessions:own`, `sandboxes:write`.
|
|
90
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): the access policy and role limits are gone.** `GET`/`PUT /v1/access/policy` answer `404`, a turn is never refused with `429 limit_exceeded` for a role (limit requests at your proxy), and an existing `access.policy` setting is ignored. Core drops `AccessPolicy*`, `AccessRole*`, `RoleLimits*`, `DEFAULT_ACCESS_POLICY`, `PutAccessPolicyRequest` and `ROLE_NAME_PATTERN`.
|
|
91
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`): publishable keys and the Runtime's CORS are gone.** `/v1/access/publishable-keys*` answer `404`, `Nylorun-Key` is ignored, `NYLORUN_BROWSER_ACCESS` and `browserAccess` (host.json, `createHost`, `startEphemeralRuntime`) are removed, and the Runtime sends no CORS headers. A request with `Origin` reaches the Tenant routes of the public listener with no toggle: a trusted issuer's token is served, an application key or delivery token is `403 origin_rejected`; admin routes, `/health`, `/ready` and the operator listener still refuse `Origin`. Any `OPTIONS` request is `204` with `Allow` and no CORS header: the operator's proxy answers preflights. Route declarations lose `browser` (`x-nylorun-browser` leaves the OpenAPI document) and the `publishable` credential; the token security scheme is `issuerToken`. Core drops `PUBLISHABLE_KEY_HEADER`, `PUBLISHABLE_KEY_PATTERN`, `PUBLISHABLE_KEY_ID_PATTERN`, `tenantOfPublishableKey`, `newPublishableKey`, `newPublishableKeyId`, `PublishableKey*`, `OriginEntrySchema`, `originAllowed` and `LOOPBACK_ORIGIN_WILDCARDS`.
|
|
92
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/agents`): vault routes are application-only, and `vaults:own` is retired.** Every `/v1/vaults` route takes an application key acting for no one (operator keys, Studio); a request acting for a subject or a trusted issuer's token gets `403 scope_required`. `vaults:own` leaves `SUBJECT_SCOPES`, `TOKEN_SCOPES` and the issuer scopes; `Nylorun-Scopes` may still name it and it grants nothing. Existing user vaults stay attachable to their own owner's sessions. `client.createVault` takes `{ scope: "installation" }` or `ownerUserId`, and `client.listVaults()` takes an optional owner.
|
|
93
|
+
- **Breaking (`@nylorun/runtime`, `@nylorun/core`, `@nylorun/admin`, `nylorun`): derived principals are gone.** Only Studio's key is derived from the admin key. `NYLORUN_DERIVED_PRINCIPALS` is ignored and no longer written, `hostPrincipals` takes no `derived`, `startEphemeralRuntime` no `derivedPrincipals`, and `@nylorun/admin` drops `deriveTenantKey`, `PROJECT_PRINCIPAL_ID` and `admin.deriveTenantKey`. Keys an earlier Host derived stay in the database and keep working as ordinary keys; replace them with operator keys. Core renames `DERIVED_PRINCIPAL_ID_PATTERN` to `APPLICATION_KEY_ID_PATTERN`.
|
|
94
|
+
- **Breaking (`@nylorun/agents`):** `createTokenEndpoint`, `createBrowserClient` and the `@nylorun/agents/browser` entry, `client.tokens`, `TokensClient`, `PublishableKeysClient`, `client.access.getPolicy`/`putPolicy`/`revokeSubject`/`publishableKeys` and `Destination.publishableKey` are removed. `client.access.signingKeys` and `client.access.jwks()` stay, and `Destination.token` takes a trusted issuer's tokens.
|
|
95
|
+
- **Breaking (`@nylorun/cli`):** `nylo access policy|keys|revoke|token` are removed and name what replaces them; `nylo access signing-keys list|rotate|revoke` stays.
|
|
96
|
+
- **Breaking (`@nylorun/core`, `@nylorun/agents`, `@nylorun/studio`): the Studio embed message `open.babai` is now `open.session`** (`{ sessionId }`): it asks the embedding app to open that session in its own UI. Studio sends no such message itself.
|
|
97
|
+
- **Breaking (`nylorun`): Studio embedding is opt-in.** No origin may frame Studio by default; list your app's origins with `nylorun start --studio-embed-origin <origin>`. A Tenant's `.env` from an earlier nylorun keeps the origins it had until `--studio-embed-origin-reset`.
|
|
98
|
+
- `PROTOCOL_VERSION` is 7 and `HOST_PROTOCOL` 4–7; the Host features `subject-tokens`, `browser-access` and `derived-principals` are removed. `@nylorun/studio` and `@nylorun/create-agent` speak protocol 7.
|
|
99
|
+
|
|
100
|
+
### Minor Changes
|
|
101
|
+
|
|
102
|
+
- 8773586: **Installation vaults and a credential resolver (F9 C1).** A session's MCP credential now comes from its attached vaults, then from the operator's own credential resolver; nothing changes for existing vaults, and the protocol stays at 6.
|
|
103
|
+
|
|
104
|
+
- Installation vaults: `POST /v1/vaults` takes `scope: "installation"` (no `ownerUserId`) from an application key acting for no one; a request acting for a subject gets `403`. The vault is owned by `installation`, now a reserved subject like `host`. Any session may attach one and select its credentials. `GET /v1/vaults` from an application key lists them after the named person's vaults, and lists only them without `ownerUserId`; a request acting for a subject never sees one (the opaque `404`). The host model vault stays hidden and unattachable. Migration 0008 adds the scope.
|
|
105
|
+
- The credential resolver: `NYLORUN_RESOLVER_URL` and `NYLORUN_RESOLVER_TOKEN` on the gateway (`TenantConfig.resolver` and `startEphemeralRuntime({ resolver })` in process). When the session's vaults hold nothing for a remote MCP server's URL, the Runtime POSTs `{ owner, session, turn, target: { kind: "mcp", server, agent, url } }` with the resolver's bearer: `200 { headers, expiresAt? }` is used, `404` goes without a credential, and anything else or no answer within 5 s refuses the server with `credential_unavailable`. Owner and turn come from the session row. Answers are cached per owner and URL until `expiresAt`, at most 5 minutes (60 s without one), and concurrent misses share one request. See DEPLOYMENT.md, Credentials.
|
|
106
|
+
- `nylorun`: the gateway's Compose service passes `NYLORUN_RESOLVER_URL` and `NYLORUN_RESOLVER_TOKEN` from the shell that runs `nylorun start` (unset by default).
|
|
107
|
+
- Studio: the Vault page is now **Connections**, and creates installation vaults.
|
|
108
|
+
|
|
109
|
+
- e1bfb4b: **MCP OAuth connect for installation vaults (F9 C2).** The installation can sign in once to a remote MCP server that uses OAuth, and every session that attaches the vault uses the credential. Additive; the protocol stays at 6.
|
|
110
|
+
|
|
111
|
+
- `POST /v1/vaults/{vaultId}/oauth/start` (application keys acting for no one, installation vaults only) takes `{ url, server, clientId? }` and answers `{ authorizeUrl, expiresAt }`. The Runtime discovers the server's authorization server (RFC 9728, then RFC 8414), registers itself (RFC 7591) unless `clientId` names a registered client, and starts an S256 PKCE sign-in whose `state` works once, for ten minutes. A server without registration and no `clientId` is `400 oauth_client_required`.
|
|
112
|
+
- `GET /v1/oauth/callback` takes the browser back: anonymous and unversioned like an artifact link, it exchanges the code and stores an `oauth` credential bound to the URL, named after `server` (connecting again rotates it), and answers a small HTML page. An unknown, used or expired `state` is `oauth_state_invalid`; the authorization server's refusal is `oauth_failed`. The callback's base is `NYLORUN_PUBLIC_URL` (`TenantConfig.publicUrl`), else the start request's origin.
|
|
113
|
+
- Every OAuth step runs in the gateway's keys module (F9-D14): the runtime container never sees a token, the PKCE verifier or a client secret, and makes no outbound call. Migration 0009 adds `oauth_pending`, with the verifier and secret sealed under the vault key. `Keys` gains `startOAuth` and `finishOAuth`.
|
|
114
|
+
- OAuth requests, including refresh of every OAuth vault credential, now go through `guardedFetch` (`tenant/outbound.ts`): the `NYLORUN_ENDPOINT_*` address policy checked on the address connected to, no redirects, a bounded answer. With `NYLORUN_ENDPOINT_PRIVATE=refuse` a token endpoint on a private address is refused, where refresh used to call it.
|
|
115
|
+
- `@nylorun/core`: `ERROR_CODES` adds `oauth_client_required`, `oauth_state_invalid` and `oauth_failed`; `StartOAuthRequestSchema` and `StartOAuthResponseSchema`.
|
|
116
|
+
- `nylorun mcp connect <url> --server <name> [--vault <id>] [--client-id <id>]`: creates the installation vault `mcp` if needed, opens the sign-in page and waits up to 10 minutes for the credential. See DEPLOYMENT.md, "Connecting a remote MCP server with OAuth".
|
|
117
|
+
|
|
118
|
+
- 5cfaed9: **Operator keys, and project links on them (F9 I1).** The Admin API manages the Tenant's application keys by name: `PUT /v1/admin/keys/{id}` creates a key or rotates it and returns it once, `GET /v1/admin/keys` lists every key's id, role and issue time (never the keys), and `DELETE /v1/admin/keys/{id}` removes one. A rotated or deleted key stops authenticating on its next request. Ids follow `^[a-z][a-z0-9-]{0,31}$`; `studio` (derived from the admin key) is refused. Keys keep today's format (64 hex) and only their SHA-256 is stored, in the existing principals table (no migration). Host feature `operator-keys` (additive, protocol unchanged); core adds the `OperatorKey`, `ListOperatorKeysResponse`, `PutOperatorKeyResponse` and `DeleteOperatorKeyResponse` schemas.
|
|
119
|
+
|
|
120
|
+
- `@nylorun/admin`: `admin.keys.put(id)`, `admin.keys.list()` and `admin.keys.delete(id)`; they refuse with `incompatible_host` when the Host lacks `operator-keys`.
|
|
121
|
+
- `nylorun key put|list|rm <id>` manages a running local Tenant's keys; `put` prints the key once on stdout.
|
|
122
|
+
- `nylorun start` no longer derives the project's key. It keeps `.nylorun/credentials.json` while its key still reaches the Tenant (one authenticated read); otherwise it gives the project the operator key `project`, which the Host root keeps in `project-credentials.json` (0600) so every checkout linked to the Tenant shares it. An existing derived project key keeps working and is adopted.
|
|
123
|
+
- `nylorun sandbox` uses the linked project's key, or the operator key `cli` it puts once and keeps in `<Host root>/cli-credentials.json` (0600).
|
|
124
|
+
- The ephemeral Runtime (`startEphemeralRuntime`) no longer registers the derived `project` principal; pass `derivedPrincipals: ["project"]` to keep it. Derived principals (`NYLORUN_DERIVED_PRINCIPALS`, `deriveTenantKey`) still work on a Host.
|
|
125
|
+
|
|
126
|
+
- b906050: **Studio for a team (F9 S1).** Studio can sit behind a sign-in proxy such as oauth2-proxy. A request with no Studio session that carries a JWT, in `X-Forwarded-Access-Token` or as an `Authorization` bearer that is not a Studio session, signs in when the Runtime's `GET /v1/me` verifies it and reports the `studio` scope: Studio sets its usual signed session cookie, which records the subject for its write log and ends no later than the token (at most the usual 30 days), and serves the request. Studio never trusts the header unverified and keeps nothing else. A token without the scope gets `403` naming `studio`; a token the Runtime refuses, or one that is not a JWT, gets `401`. Admitted people get Studio's Tenant-wide view; the CLI sign-in and embedding are unchanged, and a valid embed bearer session still wins. New `NYLORUN_STUDIO_ALLOWED_HOSTS`: extra `Host` values Studio serves, comma-separated (`studio.acme.dev`); its state changes accept that host's `https` and `http` origins, and the cookie is `Secure` when the proxy sends `X-Forwarded-Proto: https`. The default is unchanged: only `localhost` and `127.0.0.1` on the published port. `nylorun start` passes `NYLORUN_STUDIO_ALLOWED_HOSTS` from its environment to the Studio container.
|
|
127
|
+
- c0b604e: **Trusted issuers (F9 I2).** The Tenant API accepts JWTs from the operator's own identity provider as bearers, configured in an identity file: `NYLORUN_IDENTITY_FILE` names a YAML file listing each issuer's `name`, `issuer`, `audience`, `jwks` URL or static PEM `keys`, a `subject` template over scalar claims (`u:{sub}`), `scopes` from a claim or a fixed list, `allowedScopes`, an optional `agents` allowlist, optional `sandboxes` grant templates (`{org_id}/*`) and `maxLifetime`. A malformed file stops the boot, naming the issuer and the field; a subject template without a claim is malformed. A bearer whose unverified `iss` names an issuer is verified with RS256, ES256 or EdDSA only, up to 16 KiB, `aud` matching, `exp` and `iat` required and `exp − iat` within `maxLifetime`, and becomes a token caller (`role: issuer:<name>`) with the issuer's scopes, agents and rendered sandbox grants; subject revocation does not reach it. JWKS keys are fetched only from the configured URL (no redirects), cached by `kid`, refetched at most once a minute for an unknown `kid`; while a JWKS is unreachable cached keys keep working and a new `kid` is `401 issuer_unavailable` (new error code). A browser request with an issuer token needs no publishable key (CORS comes from the operator's proxy). New: `GET /v1/me` reports the subject, scopes, agents, sandbox grants and `via` (`application:<id>`, `subject`, `token` or `issuer:<name>`) of any credential; the issuer-only scope `studio`; `ISSUER_SCOPES`, `CALLER_SCOPES` and `MeResponseSchema` in `@nylorun/core/contracts`; `parseIdentityFile` and `createTrustedIssuers` in `@nylorun/runtime`, and an `issuers` option on `startEphemeralRuntime`; Host feature `trusted-issuers` (additive, protocol unchanged). `nylorun start` sets `NYLORUN_IDENTITY_FILE=/nylorun/identity.yaml` on the runtime container when `<Host root>/identity.yaml` exists.
|
|
128
|
+
|
|
129
|
+
### Patch Changes
|
|
130
|
+
|
|
131
|
+
- Pin core to the tested release.
|
|
132
|
+
- Pin runtime to the tested release.
|
|
133
|
+
- Pin studio to the tested release.
|
|
134
|
+
- Updated dependencies [8773586]
|
|
135
|
+
- Updated dependencies [e1bfb4b]
|
|
136
|
+
- Updated dependencies [5cfaed9]
|
|
137
|
+
- Updated dependencies [bd478ee]
|
|
138
|
+
- Updated dependencies [c0b604e]
|
|
139
|
+
- @nylorun/core@0.13.0-beta
|
|
140
|
+
|
|
3
141
|
## 0.8.0-beta
|
|
4
142
|
|
|
5
143
|
### Major Changes
|
package/README.md
CHANGED
|
@@ -34,8 +34,8 @@ npx nylorun doctor # Node 24+, Docker, Compose v2, and the Tenan
|
|
|
34
34
|
## Commands
|
|
35
35
|
|
|
36
36
|
```sh
|
|
37
|
-
nylorun up|start [--tenant <name>] [--no-link] [--no-studio] [--
|
|
38
|
-
# create (first run) and start the Tenant; link the project; print the URLs
|
|
37
|
+
nylorun up|start [--tenant <name>] [--no-link] [--no-studio] [--allow-downgrade] [--studio-embed-origin <origin>]... [--studio-embed-origin-reset] [--restate-ui]
|
|
38
|
+
# create (first run) and start the Tenant; link the project; print the URLs
|
|
39
39
|
# --restate-ui (or NYLORUN_RESTATE_UI=1): publish Restate's UI on loopback for this start
|
|
40
40
|
nylorun down|stop [--tenant <name> | --all] # stop the containers (--all: every Tenant's); keep volumes
|
|
41
41
|
nylorun status [--tenant <name>] [--json] # the Tenant, its Host root and id, services, endpoints, Runtime health
|
|
@@ -46,6 +46,10 @@ nylorun ls [--json] # the Tenants on this machine, with their sta
|
|
|
46
46
|
nylorun delete <tenant> --yes # remove a Tenant: containers, volumes, Host root and vault key
|
|
47
47
|
nylorun sandbox ls [--tenant <name>] [--label <key=value>]... [--json] # the running Tenant's sandboxes
|
|
48
48
|
nylorun sandbox rm <id> [--tenant <name>] # delete a sandbox and its files
|
|
49
|
+
nylorun key put <id> [--management] [--tenant <name>] # create or rotate the Tenant's application key <id> (--management: a management key); prints it once
|
|
50
|
+
nylorun key list [--tenant <name>] [--json] # the Tenant's keys: id, role, when issued
|
|
51
|
+
nylorun key rm <id> [--tenant <name>] # delete a key: it stops working at once
|
|
52
|
+
nylorun mcp connect <url> --server <name> [--vault <id>] [--client-id <id>] [--tenant <name>] [--no-open] # sign the Tenant in to a remote MCP server with OAuth
|
|
49
53
|
nylorun doctor [--json] # prerequisites and the Tenant's health
|
|
50
54
|
nylorun telemetry [status|enable|disable] # Studio's anonymous usage analytics
|
|
51
55
|
nylorun sandbox enable --context <name> [--tenant <name>] [--host-address <ip>] [--bind-address <ip>] [--no-pull]
|
|
@@ -131,14 +135,22 @@ recorded version.
|
|
|
131
135
|
## The Project link
|
|
132
136
|
|
|
133
137
|
`nylorun start` in a project waits until the Tenant is open
|
|
134
|
-
(`/
|
|
138
|
+
(`/ready`), then writes, in a `.nylorun/` directory (mode 0700, with
|
|
135
139
|
its own `.gitignore` of `*`):
|
|
136
140
|
|
|
137
141
|
- `link.json`: `{ "format": 3, "tenant", "tenantId", "hostUrl", "hostId" }`.
|
|
138
142
|
`tenant` is the local Tenant's name; the Tenant id is information only:
|
|
139
143
|
nothing in a request selects a Tenant.
|
|
140
|
-
- `credentials.json` (mode 0600):
|
|
141
|
-
|
|
144
|
+
- `credentials.json` (mode 0600): `{ "format": 1, "applicationKey",
|
|
145
|
+
"principalId", "managementKey", "managementPrincipalId" }`, the application
|
|
146
|
+
key `project` (for the Runtime API) and the management key
|
|
147
|
+
`project-management` (for the Management API). A later `start` keeps the file
|
|
148
|
+
while both keys still reach the Tenant (one authenticated read each);
|
|
149
|
+
otherwise it writes the Tenant's `project` and `project-management` keys,
|
|
150
|
+
which the Host root keeps in `project-credentials.json` (mode 0600) so every
|
|
151
|
+
checkout linked to the Tenant shares them, or puts new ones through
|
|
152
|
+
`nylorun-operate keys`. A file from an earlier release, with only an
|
|
153
|
+
application key, keeps it and gains the management key.
|
|
142
154
|
|
|
143
155
|
Later starts reuse the Tenant and rewrite the link only when the Tenant's name,
|
|
144
156
|
URL, Host or id changed (after `nylorun reset`, for example). When it writes a
|
|
@@ -154,9 +166,37 @@ both share it. `--no-link` starts a Tenant without linking the working
|
|
|
154
166
|
directory (scripts). A link of an older nylorun (format 0 to 2) counts as no
|
|
155
167
|
link: `start` replaces it.
|
|
156
168
|
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
169
|
+
No key is derived from the admin key but Studio's. A project holds the
|
|
170
|
+
application key `project` and the management key `project-management`; a key
|
|
171
|
+
an older nylorun derived for it keeps working while it authenticates and is
|
|
172
|
+
replaced by the application key otherwise.
|
|
173
|
+
|
|
174
|
+
## Keys
|
|
175
|
+
|
|
176
|
+
Every Tenant serves the Runtime API, which takes **application keys**, and the
|
|
177
|
+
Management API (`/v1/tenant/*`), which takes **management keys**
|
|
178
|
+
([SELF_HOSTING.md](../SELF_HOSTING.md#keys)). `nylorun key` manages both on the
|
|
179
|
+
running Tenant through `nylorun-operate` in its runtime container, so only this
|
|
180
|
+
machine can issue a management key.
|
|
181
|
+
|
|
182
|
+
`nylorun key put <id>` creates the application key `<id>` (or rotates it: the
|
|
183
|
+
previous key stops working at once) and prints it once on stdout; with
|
|
184
|
+
`--management` it puts a management key. `nylorun key list [--json]` shows each
|
|
185
|
+
key's id, role and when it was issued, never the keys; `nylorun key rm <id>`
|
|
186
|
+
deletes one. Ids match `^[a-z][a-z0-9-]{0,31}$`; `studio` belongs to Studio and
|
|
187
|
+
`bootstrap` to `NYLORUN_MANAGEMENT_KEY_FILE`, and both are refused. Putting an
|
|
188
|
+
id that holds the other role is refused. Give each app server its own
|
|
189
|
+
application key. `nylorun sandbox` and `nylorun mcp` use the linked project's
|
|
190
|
+
keys, or the keys `cli` and `cli-management` they put once and keep in
|
|
191
|
+
`<Host root>/cli-credentials.json` (mode 0600).
|
|
192
|
+
|
|
193
|
+
`nylorun mcp connect <url> --server <name>` signs the running Tenant in to a
|
|
194
|
+
remote MCP server that uses OAuth: it opens the server's sign-in page in the
|
|
195
|
+
browser and waits until the Runtime has stored the credential in the
|
|
196
|
+
installation vault `mcp` (created if needed; `--vault <id>` picks another),
|
|
197
|
+
which sessions attach with `vaultIds`. Pass `--client-id` when the server does
|
|
198
|
+
not let clients register themselves. See
|
|
199
|
+
[Connecting a remote MCP server with OAuth](../DEPLOYMENT.md#connecting-a-remote-mcp-server-with-oauth).
|
|
160
200
|
|
|
161
201
|
## The containers
|
|
162
202
|
|
|
@@ -174,12 +214,9 @@ project, and each has the label `dev.nylorun.tenant: <name>`. For Tenant `shop`:
|
|
|
174
214
|
| Volumes | `nylorun-shop-postgres`, `nylorun-shop-restate`, `nylorun-shop-s2-lite`, `nylorun-shop-rustfs`, `nylorun-shop-workspaces` |
|
|
175
215
|
|
|
176
216
|
The `harness` container (the Runtime image as `--service harness`) runs agent
|
|
177
|
-
turns
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
Host root's `plugins/` read-only at its own path: put a plugin whose stdio MCP
|
|
181
|
-
server the agent runs under `~/.nylorun/tenants/<name>/plugins/` and load it from
|
|
182
|
-
there. `NYLORUN_HARNESS=in-process` in `.env` rolls back to running them in the
|
|
217
|
+
turns and workspaces, apart from the `runtime` container. It holds only the
|
|
218
|
+
harness token (`NYLORUN_HARNESS_TOKEN` in `.env`) and mounts only the Tenant
|
|
219
|
+
directory's `sandboxes/`. `NYLORUN_HARNESS=in-process` in `.env` rolls back to running them in the
|
|
183
220
|
`runtime` container (no `harness` container); `nylorun status` shows which.
|
|
184
221
|
|
|
185
222
|
Postgres initialises the Tenant's database with C collation. Restate runs with
|
|
@@ -187,8 +224,8 @@ its own defaults. A running Tenant uses about 1.2 GB, most of it Restate; stop
|
|
|
187
224
|
the Tenants you are not using (`nylorun stop`, or `nylorun stop --all`). The Runtime and Studio images are pinned by
|
|
188
225
|
this release (`package.json` `nylorun.runtime` and `nylorun.studio`);
|
|
189
226
|
`NYLORUN_RUNTIME_IMAGE` and `NYLORUN_STUDIO_IMAGE` override them (local builds,
|
|
190
|
-
CI). Ports publish on loopback only: the Runtime on `8787
|
|
191
|
-
|
|
227
|
+
CI). Ports publish on loopback only: the Runtime on `8787` and Studio on
|
|
228
|
+
`4161`, or free ports chosen on the
|
|
192
229
|
Tenant's first start, avoiding the ports other Tenants keep, and kept in its
|
|
193
230
|
`.env`. Restate's UI and admin API (unauthenticated) are not published; `nylorun
|
|
194
231
|
start --restate-ui` (or `NYLORUN_RESTATE_UI=1`) publishes them for that start on
|
|
@@ -196,14 +233,18 @@ start --restate-ui` (or `NYLORUN_RESTATE_UI=1`) publishes them for that start on
|
|
|
196
233
|
|
|
197
234
|
`start`, `status`, `ls` and `nylorun studio` give Studio as
|
|
198
235
|
`http://localhost:<port>` (`studio.url` in `status --json`). Studio has no
|
|
199
|
-
password
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
--no-open` prints the login URL (it
|
|
236
|
+
password, and `start` opens no browser: it prints the URLs and says to run
|
|
237
|
+
`nylorun studio` to sign a browser in (`--no-open` is accepted and ignored).
|
|
238
|
+
`nylorun studio` asks the Studio container for a single-use login token with the
|
|
239
|
+
admin key (`POST /_studio/login-tokens`) and opens
|
|
240
|
+
`http://localhost:<port>/login?token=…` on the Tenant's page in the browser.
|
|
241
|
+
That sets a session cookie for 30 days, which survives Studio restarts, so the
|
|
242
|
+
printed URL keeps working in that browser. The token itself is never printed
|
|
243
|
+
unless no browser starts; `nylorun studio --no-open` prints the login URL (it
|
|
244
|
+
works once, for two minutes) instead.
|
|
245
|
+
Studio needs no login on its published loopback address (`localhost` or
|
|
246
|
+
`127.0.0.1` at its port): a browser on this machine is served as signed in. A
|
|
247
|
+
host behind a sign-in proxy and an embedding app keep their sign-in.
|
|
207
248
|
|
|
208
249
|
Browsers share cookies across the ports of one host, so each Tenant's Studio
|
|
209
250
|
sets its own session cookie, `nylorun_studio_<name>`
|
|
@@ -212,14 +253,16 @@ out of another.
|
|
|
212
253
|
|
|
213
254
|
### Embedding Studio in a desktop app
|
|
214
255
|
|
|
215
|
-
A desktop
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
`~/.nylorun/tenants/<name>/docker/.env`) may frame it
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
`
|
|
222
|
-
|
|
256
|
+
A desktop or web app can show Studio inside its own window, in an iframe loaded
|
|
257
|
+
from Studio's URL (`studio.url` in `nylorun status --json`). Embedding is
|
|
258
|
+
opt-in: only exact origins listed in `NYLORUN_STUDIO_FRAME_ANCESTORS` (in
|
|
259
|
+
`~/.nylorun/tenants/<name>/docker/.env`) may frame it, and the list is empty by
|
|
260
|
+
default. Add the app's origins once with `nylorun start --studio-embed-origin
|
|
261
|
+
<origin>` (for example `app://localhost`, or a dev server's
|
|
262
|
+
`http://localhost:1420`); the list is kept across starts until
|
|
263
|
+
`--studio-embed-origin-reset`, and `nylorun status` shows it under `Embeds`.
|
|
264
|
+
Wildcards are refused. A Tenant started by an older nylorun keeps the origins it
|
|
265
|
+
had.
|
|
223
266
|
|
|
224
267
|
The app's backend mints a single-use login token for the Tenant with
|
|
225
268
|
`mintStudioLoginToken` from `@nylorun/admin` (it needs the admin key), and its
|
|
@@ -279,8 +322,9 @@ The **Host root** is `~/.nylorun/tenants/<name>/`, or `NYLORUN_HOME`. It is
|
|
|
279
322
|
bind-mounted into the Runtime and Studio containers, and holds `tenant.json`
|
|
280
323
|
(`{ "format": 1, "name", "project"? }`: the Tenant's name and the project it
|
|
281
324
|
was created for), `host.json` (the client-facing host and port),
|
|
282
|
-
`host-credentials.json` (the admin key, mode 0600),
|
|
283
|
-
`
|
|
325
|
+
`host-credentials.json` (the admin key, mode 0600), `project-credentials.json`
|
|
326
|
+
and `cli-credentials.json` (the keys `project` and `project-management`, `cli`
|
|
327
|
+
and `cli-management`, mode 0600, when they were put), the Docker Compose files in `docker/`, the Tenant directory `tenant/` (homes, logs) and `keys/vault-kek`,
|
|
284
328
|
the Tenant's vault key, which only the gateway container mounts. The Tenant's data lives in its Postgres, Restate and S2 volumes.
|
|
285
329
|
|
|
286
330
|
`nylorun reset` deletes the selected Tenant's volumes, `tenant/` and `keys/`, and keeps
|
package/dist/cli.js
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
import "./baseline.js";
|
|
3
3
|
import { baselineEnv } from "./baseline.js";
|
|
4
4
|
import { CliError } from "./errors.js";
|
|
5
|
-
import { isStackCommand, sandboxCommand, sandboxUsage, stackCommand, stackUsage, studioCommand, } from "./stack/index.js";
|
|
6
|
-
const usage = `nylorun <up|down|start|stop|status|logs|studio|reset|ls|delete|sandbox|doctor|telemetry>
|
|
5
|
+
import { isStackCommand, keyCommand, keyUsage, mcpCommand, mcpUsage, sandboxCommand, sandboxUsage, stackCommand, stackUsage, studioCommand, } from "./stack/index.js";
|
|
6
|
+
const usage = `nylorun <up|down|start|stop|status|logs|studio|reset|ls|delete|sandbox|key|mcp|doctor|telemetry>
|
|
7
7
|
|
|
8
8
|
Local Tenants (Docker Compose), one per project:
|
|
9
9
|
${stackUsage}
|
|
10
10
|
${sandboxUsage}
|
|
11
|
+
${keyUsage}
|
|
12
|
+
${mcpUsage}
|
|
11
13
|
doctor [--json] check Node, Docker and Compose v2, and the Tenant's health
|
|
12
14
|
telemetry [status|enable|disable] Studio's anonymous usage analytics (on unless disabled,
|
|
13
15
|
NYLORUN_TELEMETRY_DISABLED=1, DO_NOT_TRACK=1 or CI)
|
|
@@ -50,6 +52,14 @@ async function main() {
|
|
|
50
52
|
process.exitCode = await sandboxCommand(args, baselineEnv());
|
|
51
53
|
return;
|
|
52
54
|
}
|
|
55
|
+
if (command === "mcp") {
|
|
56
|
+
process.exitCode = await mcpCommand(args, baselineEnv());
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (command === "key") {
|
|
60
|
+
process.exitCode = await keyCommand(args, baselineEnv());
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
53
63
|
if (isStackCommand(command)) {
|
|
54
64
|
process.exitCode = await stackCommand(command, args, baselineEnv());
|
|
55
65
|
return;
|
package/dist/doctor.js
CHANGED
|
@@ -42,7 +42,7 @@ export async function doctorStack(options) {
|
|
|
42
42
|
(!report.tenant.runtime.healthy ||
|
|
43
43
|
!report.tenant.gateway.healthy ||
|
|
44
44
|
(report.tenant.harness.mode === "remote" && !report.tenant.harness.healthy) ||
|
|
45
|
-
report.tenant.tenant
|
|
45
|
+
(report.tenant.tenant !== undefined && report.tenant.tenant.state !== "open"));
|
|
46
46
|
const failed = !nodeOk || !checks.docker.ok || checks.compose?.ok === false || broken;
|
|
47
47
|
if (options.json) {
|
|
48
48
|
log(JSON.stringify(report, null, 2));
|
|
@@ -103,7 +103,7 @@ export async function doctorStack(options) {
|
|
|
103
103
|
"tenant id",
|
|
104
104
|
local.tenant.state === "open"
|
|
105
105
|
? `✓ ${local.tenant.id ?? "?"} open`
|
|
106
|
-
: `✗ ${local.tenant.id ?? "?"} unavailable${local.tenant.cause ? `: ${local.tenant.cause
|
|
106
|
+
: `✗ ${local.tenant.id ?? "?"} unavailable${local.tenant.cause || local.tenant.message ? `: ${[local.tenant.cause, local.tenant.message].filter(Boolean).join(": ")}` : " (opening)"}`,
|
|
107
107
|
]);
|
|
108
108
|
rows.push(["studio", `${local.studio.url ?? "?"} · ${local.studio.state}`]);
|
|
109
109
|
}
|
package/dist/project/link.d.ts
CHANGED
|
@@ -22,13 +22,27 @@ export declare function writeProjectLink(projectRoot: string, link: {
|
|
|
22
22
|
hostId: string;
|
|
23
23
|
tenantId: string;
|
|
24
24
|
}): Promise<void>;
|
|
25
|
-
/**
|
|
26
|
-
|
|
25
|
+
/**
|
|
26
|
+
* An application key and its principal, and the management key and its principal when the file
|
|
27
|
+
* has one: `credentials.json`'s content (format 1).
|
|
28
|
+
*/
|
|
29
|
+
export interface KeyCredentials {
|
|
27
30
|
applicationKey: string;
|
|
28
31
|
principalId: string;
|
|
29
|
-
|
|
32
|
+
management?: {
|
|
33
|
+
key: string;
|
|
34
|
+
principalId: string;
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
/** The Project's keys, or undefined when absent or unreadable. */
|
|
38
|
+
export declare function readProjectCredentials(projectRoot: string): Promise<KeyCredentials | undefined>;
|
|
39
|
+
/**
|
|
40
|
+
* A credentials file (`{ format: 1, applicationKey, principalId, managementKey?,
|
|
41
|
+
* managementPrincipalId? }`): the Project's, or one the nylorun commands keep in the Host root.
|
|
42
|
+
* Undefined when absent or unreadable.
|
|
43
|
+
*/
|
|
44
|
+
export declare function readCredentialsFile(path: string): Promise<KeyCredentials | undefined>;
|
|
30
45
|
/** `.nylorun/credentials.json` (format 1, mode 0600). */
|
|
31
|
-
export declare function writeProjectCredentials(projectRoot: string, credentials:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}): Promise<void>;
|
|
46
|
+
export declare function writeProjectCredentials(projectRoot: string, credentials: KeyCredentials): Promise<void>;
|
|
47
|
+
/** A credentials file (format 1), written atomically with mode 0600. */
|
|
48
|
+
export declare function writeCredentialsFile(path: string, credentials: KeyCredentials): Promise<void>;
|
package/dist/project/link.js
CHANGED
|
@@ -67,13 +67,27 @@ export async function writeProjectLink(projectRoot, link) {
|
|
|
67
67
|
tenantId: link.tenantId,
|
|
68
68
|
});
|
|
69
69
|
}
|
|
70
|
-
/** The Project's
|
|
70
|
+
/** The Project's keys, or undefined when absent or unreadable. */
|
|
71
71
|
export async function readProjectCredentials(projectRoot) {
|
|
72
|
+
return await readCredentialsFile(credentialsPath(projectRoot));
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* A credentials file (`{ format: 1, applicationKey, principalId, managementKey?,
|
|
76
|
+
* managementPrincipalId? }`): the Project's, or one the nylorun commands keep in the Host root.
|
|
77
|
+
* Undefined when absent or unreadable.
|
|
78
|
+
*/
|
|
79
|
+
export async function readCredentialsFile(path) {
|
|
72
80
|
try {
|
|
73
|
-
const value = JSON.parse(await readFile(
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
81
|
+
const value = JSON.parse(await readFile(path, "utf8"));
|
|
82
|
+
if (typeof value.applicationKey !== "string" || typeof value.principalId !== "string")
|
|
83
|
+
return undefined;
|
|
84
|
+
return {
|
|
85
|
+
applicationKey: value.applicationKey,
|
|
86
|
+
principalId: value.principalId,
|
|
87
|
+
...(typeof value.managementKey === "string" && typeof value.managementPrincipalId === "string"
|
|
88
|
+
? { management: { key: value.managementKey, principalId: value.managementPrincipalId } }
|
|
89
|
+
: {}),
|
|
90
|
+
};
|
|
77
91
|
}
|
|
78
92
|
catch {
|
|
79
93
|
return undefined;
|
|
@@ -82,9 +96,19 @@ export async function readProjectCredentials(projectRoot) {
|
|
|
82
96
|
/** `.nylorun/credentials.json` (format 1, mode 0600). */
|
|
83
97
|
export async function writeProjectCredentials(projectRoot, credentials) {
|
|
84
98
|
await ensureProjectDir(projectRoot);
|
|
85
|
-
await
|
|
99
|
+
await writeCredentialsFile(credentialsPath(projectRoot), credentials);
|
|
100
|
+
}
|
|
101
|
+
/** A credentials file (format 1), written atomically with mode 0600. */
|
|
102
|
+
export async function writeCredentialsFile(path, credentials) {
|
|
103
|
+
await writePrivate(path, {
|
|
86
104
|
format: 1,
|
|
87
105
|
applicationKey: credentials.applicationKey,
|
|
88
106
|
principalId: credentials.principalId,
|
|
107
|
+
...(credentials.management
|
|
108
|
+
? {
|
|
109
|
+
managementKey: credentials.management.key,
|
|
110
|
+
managementPrincipalId: credentials.management.principalId,
|
|
111
|
+
}
|
|
112
|
+
: {}),
|
|
89
113
|
});
|
|
90
114
|
}
|
package/dist/project/seed.d.ts
CHANGED
|
@@ -21,7 +21,8 @@ export declare function readProjectEnv(projectRoot: string): Record<string, stri
|
|
|
21
21
|
export declare function seedTenant(input: {
|
|
22
22
|
fetch: FetchLike;
|
|
23
23
|
runtimeUrl: string;
|
|
24
|
-
|
|
24
|
+
/** The Project's management key: seeding is the Management API's. */
|
|
25
|
+
managementKey: string;
|
|
25
26
|
projectRoot: string;
|
|
26
27
|
}): Promise<SeedResult>;
|
|
27
28
|
export {};
|
package/dist/project/seed.js
CHANGED
|
@@ -45,11 +45,11 @@ function modelFromEnv(env, projectRoot) {
|
|
|
45
45
|
}
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
48
|
-
async function call(fetch, url,
|
|
48
|
+
async function call(fetch, url, managementKey, init = {}) {
|
|
49
49
|
const response = await fetch(url, {
|
|
50
50
|
...(init.method ? { method: init.method } : {}),
|
|
51
51
|
headers: {
|
|
52
|
-
authorization: `Bearer ${
|
|
52
|
+
authorization: `Bearer ${managementKey}`,
|
|
53
53
|
[PROTOCOL_HEADER]: String(PROTOCOL_VERSION),
|
|
54
54
|
accept: "application/json",
|
|
55
55
|
...(init.body === undefined ? {} : { "content-type": "application/json" }),
|
|
@@ -76,7 +76,7 @@ export async function seedTenant(input) {
|
|
|
76
76
|
const result = { applied: [], kept: [] };
|
|
77
77
|
const sandbox = env.NYLORUN_SANDBOX?.trim();
|
|
78
78
|
if (sandbox === "auto" || sandbox === "virtual") {
|
|
79
|
-
const body = (await call(input.fetch, `${base}/v1/tenant/config/seed`, input.
|
|
79
|
+
const body = (await call(input.fetch, `${base}/v1/tenant/config/seed`, input.managementKey, {
|
|
80
80
|
method: "PUT",
|
|
81
81
|
body: { requestId: randomUUID(), sandbox: { backend: sandbox } },
|
|
82
82
|
}));
|
|
@@ -90,12 +90,12 @@ export async function seedTenant(input) {
|
|
|
90
90
|
const seeded = modelFromEnv(env, input.projectRoot);
|
|
91
91
|
if (!seeded)
|
|
92
92
|
return result;
|
|
93
|
-
const current = (await call(input.fetch, `${base}/v1/tenant/model`, input.
|
|
93
|
+
const current = (await call(input.fetch, `${base}/v1/tenant/model`, input.managementKey));
|
|
94
94
|
if (current.configured === true) {
|
|
95
95
|
result.kept.push("model");
|
|
96
96
|
return result;
|
|
97
97
|
}
|
|
98
|
-
await call(input.fetch, `${base}/v1/tenant/model`, input.
|
|
98
|
+
await call(input.fetch, `${base}/v1/tenant/model`, input.managementKey, {
|
|
99
99
|
method: "PUT",
|
|
100
100
|
body: {
|
|
101
101
|
requestId: randomUUID(),
|