Skip to content

v0.97.0

Choose a tag to compare

@davidfarah2003 davidfarah2003 released this 23 Oct 03:06
0b1c17b

Install or update: npm i -g cotal-ai@0.97.0

Changes in this release

  • Bind the daemon's existing void machine-status responder using the stock verified guest serve grant. Each serving credential is checked against the registered authority's issuer identity and the unchanged embedded contract. Flush the responder before ready, bind replacement connections, and stop responders on disconnect. Callers still need explicit exact-instance grants; the public descriptor identifies the endpoint and derived owner token and includes protocol and command schemas. No hostname, machine metadata or vitals are returned.
  • Add authorizeGuestServeGrant, the guest-side reconstitution seam SPEC §13.6 calls for: a service that registered through the service door turns its parsed credential result and its own embedded contract closure into the process-local serve grant serveEndpoint consumes, with no store access. It proves the binding before it brands: the witness names the pinned account, the access bearer's EdDSA signature verifies under the pinned issuer's published key and its closed claims name this issuer, space, owner, the serve duty and exactly this witness, the host's closure set and artifacts are the embedded ones byte for byte, and every closure verifies as manifest and root. The store-backed authorizeServeGrant and the host-only authorizeTrustedServeSnapshot are unchanged; the §13.7 surface read authorizeServeGrant runs is one function now, shared with the seam.
  • ServiceEndpointRenewal.credential() answers ServiceEndpointCredential: the validated credential result without renewalProof and renewalExpiresAt, which never leave the source, as a copy per caller. authorizeGuestServeGrant takes that type; it reads no renewal field. credential() is a required member of the interface, so an out-of-tree implementer adds it.
  • Add credential() to ServiceEndpointRenewal: the same single-flight pull as bearer(), answering the whole validated credential result (the witness, the host-authorized snapshot and the access bearer) a guest hands to authorizeGuestServeGrant. bearer() now delegates to that one pull, so concurrent bearer() and credential() calls share one request under the same persisted activate and renew ids, and an ended or closed source refuses both the same way with nothing sent. The stock source in @cotal-ai/auth implements it; no extra request or renewal loop is added.
  • The service endpoint authority's GET answer now carries the issuer identity a guest verifies its access bearer under: issuer, the exact iss the context mints, and keys, the public Ed25519 coordinates of the set GET /jwks publishes. parseServiceAuthorityInfo reads them, when answered, as a closed, bounded record, and the auth provider's serviceEndpointInfo returns them from the registered space's pinned authority URL, tenant path included, so a service passes serveAuthenticityOf(info) to authorizeGuestServeGrant as its authenticity, built from the door's own context. A door that predates the identity still parses, and a guest that needs it refuses to serve. Every key is checked as a canonical full-order Ed25519 point on the door, in the parser and in the seam, so a small-order key cannot make a signature no private key produced verify. The serving smoke now brands a live credential through the seam against the real door and refuses it under another key for the same kid.
  • The service door admits the schema closures a registration's commands reference. A registration may submit, with its cluster closures, the closure of each inputDigest and outputDigest its commands name; a submitted one is admitted only whole (its manifest at that digest, its root and every member present, and the bundle recompiling to that closure digest) and is published with the cluster artifacts, so a service registering through the door publishes its schemas the way an in-process registrant does. A registration that submits only its cluster closures is admitted as before and its persisted body and replay are unchanged. A hosted context with service endpoints publishes the canonical void closure (manifest and schema) create-only when it opens, under an effect scoped to exactly those two artifacts, so a payload-free command resolves against it whether or not its registration carried it. @cotal-ai/core exports parseClosureManifest.
  • The service authority's published keys are checked as canonical full-order Ed25519 points on the door, in parseServiceAuthorityInfo and in the guest seam, so a key of small order or non-canonical encoding is refused rather than letting a signature no private key made verify. The info parser accepts a door that predates the issuer identity, answering the four account fields alone, so a newer client and an older door no longer refuse each other; serveAuthenticityOf(info) builds the seam's authenticity from the answer and refuses when the identity is absent. The door refuses to publish more than 16 keys.
  • serveEndpoint(...).stop() settles when its connection closes mid-drain. nats-core settles a subscription drain on the server's PONG and rejects no pending flush when the connection closes, so a stop that raced the connection's close, or ran on a closed connection, never settled. Each drain is now bounded by the connection's own closed(), and in-flight handlers are still awaited before the stop reports stopped.
  • Own-broker service caller issuance. cotal up retains the system-account signing seed in the root's secret store, beside the seed-free trust record, at space creation and at --rotate-sys (the successor's seed replaces the retired account's). An auth service started with --service-endpoints composes the caller payload bootstrap from that record when it names the trust record's system account and the seed derives it: each bootstrap mints one 60 s VARZ-only observer credential, and the seed never leaves the daemon. A root with no retained seed opens the engine and door without caller issuance and says why; a record for another account refuses the start. @cotal-ai/workspace exports retainSystemSigningSeed, readSystemSigningSeed and systemSigningSeedKey.
  • Host service endpoints from the stock CLI. cotal up --user-auth --service-endpoints passes --service-endpoints to the auth service, which opens the service endpoint engine, the public /service-endpoint-authority door and the new authenticated /service-endpoint-host route. That route authenticates the caller's IdP token and derives the granter itself: decide, an owner-request revoke and the reads run as the proved owner on either face; name-bind, any other revoke and the admission operations are the operator's and are served on the loopback face under the exchange capability only, with the proved subject as the audit id. The body never carries a granter. The engine now serves the name-read the host contract already declared, scoped to the owner's own binding. cotal service-endpoint approve|refuse|proposal|operation|name|name-bind drives the route as the signed-in user: a decision reads the proposal, with the name binding that read carries, and decides at those revisions. Without the flag nothing changes: the engine stays off and both routes answer 404.

What's Changed

  • feat(core): add the guest-side serve grant seam for service-door services by @davidfarah2003 in #4385
  • test(manager): keep ef-continuity's recovery calls from expiring the resumed driver by @davidfarah2003 in #4389
  • test: move the ep-serve guest suite from the frozen list to its own fragment by @davidfarah2003 in #4391
  • feat(auth): answer the issuer and its public keys in the service endpoint authority info by @davidfarah2003 in #4390
  • test(daemon): gate the service-connect smoke and start its broker from a tokened config path by @davidfarah2003 in #4392
  • fix(core): refuse small-order issuer keys and read a pre-identity authority info answer by @davidfarah2003 in #4393
  • feat(auth): add credential() to the service endpoint renewal source by @davidfarah2003 in #4394
  • test(ci): read job-level concurrency groups in the workflow-concurrency guard by @davidfarah2003 in #4395
  • feat(auth): host service endpoints from the CLI with an authenticated host route by @davidfarah2003 in #4396
  • test(core): drive the y = -1 sign-bit small-order coordinate, and fix the issuer-keys changeset by @davidfarah2003 in #4397
  • fix(core): settle serveEndpoint stop() when the connection closes mid-drain by @davidfarah2003 in #4398
  • test(release): follow the version release and the separate install-check job in install-probe-ci by @davidfarah2003 in #4399
  • fix(auth): keep the renewal proof inside the renewal source by @davidfarah2003 in #4400
  • feat(auth): admit referenced schema closures at the service door and publish the canonical void closure by @davidfarah2003 in #4402
  • feat(auth): own-broker service caller issuance from a retained system-account signing seed by @davidfarah2003 in #4403
  • feat(daemon): serve the registered machine liveness command by @davidfarah2003 in #4404
  • chore(release): version packages by @davidfarah2003 in #4388

Full Changelog: v0.96.1...v0.97.0