Repository navigation
v0.112.0
Install or update: npm i -g cotal-ai@0.112.0
Changes in this release
-
Serve several spaces from one auth service process as their full primary.
cotal auth-service --spaces <manifest> --server <url>, without--callout-only, holds one lane per space: the space's callout, authority plane and plane claim, its loopback exchange and JWKS on a port of its own, recorded in that space'sauth-service.json, and the public face its manifest entry names. Lanes share the process and nothing else, so one space's keys never sign for another, and a fence or a lost broker connection closes that space's lane alone; the host reopens it every 5 seconds while it fails. Lane lines carry a[<space>]prefix. An embedder passes its secret store torunAuthService(args, store)withspacesinargs, as it does for one space.The manifest for this host is version 2, one object per space:
{"version": 2, "spaces": [{"space": "<s>", "exchangePublicPort": 7451, "exchangeTrustedProxy": true}]}. An entry takesexchangePublicPort,exchangePublicUrl,exchangeTrustedProxy,advertisedServerandagentProvisioningUrlunder the rules of the flags they replace, and two spaces naming one port refuse the manifest.--portand the public-face flags refuse with--spaces;--server,--auth-timeoutand--service-endpointsapply to every lane. A changed entry closes that space's lane and opens it again. At startup the host serves every space it can, names each one it cannot, and retries those, so one tenant's fault does not keep the others down at a restart.Every multi-space host,
auth-service --callout-only --spacesanddeliver --spacesincluded, now writes<manifest>.appliedbeside its manifest, holding the SHA-256 of the manifest it applied, once every space that manifest does not name has no lane left. Removing a space from each manifest that names it and waiting for each acknowledgment stops one space without stopping the others. A lane that does not confirm its close holds the acknowledgment back until a retry closes it, and its space is not opened again meanwhile. A refused all-or-none startup no longer reopens the lanes it closed.Breaking: a host writes
<manifest>.appliedbefore it opens any lane and refuses to start when it cannot, so the manifest's directory must be writable by the host. This applies to existingauth-service --callout-only --spacesanddeliver --spaceshosts too: give the host write access to its manifest's directory before upgrading.parseSpaceManifesttakes an optional settings parser for version 2 manifests, andrunSpaceHosttakes per-space settings and astartuppolicy; the callout and delivery hosts keep their version 1 manifests, and the callout host keeps all-or-none startup.auth-service --spacesruns now say to keep the entry, since theauth-serviceservice preset has no form for--spaces. -
The auth callout derives its xkey shared key with a nats-server once per server key, instead of twice on every connect (once to open the request and once to seal the response). That X25519 step was most of the callout's crypto CPU. The sealed bytes are unchanged, and every request still passes every check: the mandatory xkey, the dropped unsealed request, and the signed
server_id.xkeymatching the sealing header. Each callout keeps at most 64 server keys and drops the least recently used. A key is kept only for a request that passed every check, so a forgedNats-Server-Xkeyheader never grows it.@cotal-ai/authnow depends ontweetnacldirectly, the same version@nats-io/nkeysalready installs. -
Update refuses an unsafe config ancestor before any repair, seed or binary replacement.
-
cotal updateno longer reinstalls a first-party operator extension that is already at the running CLI's version. When the extension is recorded at that version with the spec update installs, the extensions prefix lock records it at that version, and every package the lock records is on disk at its recorded version, the extension pass verifies it in the update process, rebinds its shared peers to this CLI's copies, and prints a verified line. Any other extension is still reinstalled in an isolated child, now after a line that says why. On a current machine each extension used to cost a full npm install on every run. -
cotal deliver --spacesnow starts with the spaces it can serve instead of refusing unless every space opens. It names each space it cannot serve with the reason, retries those every 5 seconds, and its ready line names the spaces it retries. One space's fault at a restart no longer keeps every other space's delivery down, nor the plane-claim liveness oracle each lane answers, which an auth service restarting after a crash needs. A space whose lease a single-space daemon still holds opens once that daemon stops. A manifest that does not read or parse whole still refuses startup.Breaking: a supervisor or script that relied on
deliver --spacesexiting nonzero when one space could not open now sees the host start; read its ready line or its per-space lines for the spaces it retries.
What's Changed
- perf(auth): derive the callout's xkey shared key once per server key by @davidfarah2003 in #4967
- test(smoke): give the issued-store-binders suite its own ci-suites fragment by @davidfarah2003 in #4972
- feat(auth,workspace)!: serve several spaces as their full auth service from one process by @davidfarah2003 in #4966
- fix(cli): refuse an unsafe config ancestor before update writes by @davidfarah2003 in #4968
- feat(delivery)!: start a multi-space delivery host with the spaces it can serve by @davidfarah2003 in #4973
- fix(cli): verify a current operator extension on update instead of reinstalling it by @davidfarah2003 in #4974
- chore(release): version packages by @davidfarah2003 in #4971
Full Changelog: v0.111.1...v0.112.0