Skip to content

v0.112.0

Choose a tag to compare

@davidfarah2003 davidfarah2003 released this 27 Oct 21:20
d4543d7

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's auth-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 to runAuthService(args, store) with spaces in args, 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 takes exchangePublicPort, exchangePublicUrl, exchangeTrustedProxy, advertisedServer and agentProvisioningUrl under the rules of the flags they replace, and two spaces naming one port refuse the manifest. --port and the public-face flags refuse with --spaces; --server, --auth-timeout and --service-endpoints apply 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 --spaces and deliver --spaces included, now writes <manifest>.applied beside 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>.applied before 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 existing auth-service --callout-only --spaces and deliver --spaces hosts too: give the host write access to its manifest's directory before upgrading.

    parseSpaceManifest takes an optional settings parser for version 2 manifests, and runSpaceHost takes per-space settings and a startup policy; the callout and delivery hosts keep their version 1 manifests, and the callout host keeps all-or-none startup. auth-service --spaces runs now say to keep the entry, since the auth-service service 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.xkey matching 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 forged Nats-Server-Xkey header never grows it. @cotal-ai/auth now depends on tweetnacl directly, the same version @nats-io/nkeys already installs.

  • Update refuses an unsafe config ancestor before any repair, seed or binary replacement.

  • cotal update no 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 --spaces now 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 --spaces exiting 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

Full Changelog: v0.111.1...v0.112.0