@cotal-ai/auth 0.67.0 → 0.69.0
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/dist/authority-client.d.ts +4 -4
- package/dist/authority-client.d.ts.map +1 -1
- package/dist/authority-client.js +5 -5
- package/dist/authority-client.js.map +1 -1
- package/dist/barrier-evict.d.ts +27 -5
- package/dist/barrier-evict.d.ts.map +1 -1
- package/dist/barrier-evict.js +9 -9
- package/dist/barrier-evict.js.map +1 -1
- package/dist/commands.js +1 -16
- package/dist/commands.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/ledger-scanner.d.ts.map +1 -1
- package/dist/ledger-scanner.js +2 -7
- package/dist/ledger-scanner.js.map +1 -1
- package/dist/login.d.ts +3 -2
- package/dist/login.d.ts.map +1 -1
- package/dist/login.js +19 -7
- package/dist/login.js.map +1 -1
- package/dist/managed-agent-enrollment.d.ts.map +1 -1
- package/dist/managed-agent-enrollment.js +18 -36
- package/dist/managed-agent-enrollment.js.map +1 -1
- package/dist/manager-authority.d.ts +23 -12
- package/dist/manager-authority.d.ts.map +1 -1
- package/dist/manager-authority.js +52 -22
- package/dist/manager-authority.js.map +1 -1
- package/dist/manager-contract.d.ts +1 -1
- package/dist/manager-contract.d.ts.map +1 -1
- package/dist/manager-contract.js +5 -7
- package/dist/manager-contract.js.map +1 -1
- package/dist/manager-maintenance.d.ts +1 -1
- package/dist/manager-maintenance.d.ts.map +1 -1
- package/dist/manager-maintenance.js +12 -9
- package/dist/manager-maintenance.js.map +1 -1
- package/dist/plane-claim.d.ts +12 -2
- package/dist/plane-claim.d.ts.map +1 -1
- package/dist/plane-claim.js +30 -23
- package/dist/plane-claim.js.map +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +1 -22
- package/dist/provider.js.map +1 -1
- package/dist/records-scanner.d.ts.map +1 -1
- package/dist/records-scanner.js +3 -8
- package/dist/records-scanner.js.map +1 -1
- package/dist/serialized.d.ts +8 -0
- package/dist/serialized.d.ts.map +1 -0
- package/dist/serialized.js +15 -0
- package/dist/serialized.js.map +1 -0
- package/dist/service.d.ts +12 -3
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +109 -123
- package/dist/service.js.map +1 -1
- package/package.json +4 -3
package/dist/service.js
CHANGED
|
@@ -57,9 +57,9 @@ import { createHash, randomBytes } from "node:crypto";
|
|
|
57
57
|
import { createServer } from "node:http";
|
|
58
58
|
import { resolve } from "node:path";
|
|
59
59
|
import { connect, credsAuthenticator } from "@nats-io/transport-node";
|
|
60
|
-
import { jetstreamManager } from "@nats-io/jetstream";
|
|
60
|
+
import { jetstream, jetstreamManager } from "@nats-io/jetstream";
|
|
61
61
|
import { Kvm } from "@nats-io/kv";
|
|
62
|
-
import { CotalEndpoint, deprovisionAgent, isConcreteChannel, provisionAgentDurables, contractDigest, contractRefToHex, contractStoreContext, endpointToken, fetchContractArtifact, verifyClusterManifest, verifyClusterRoot, admissionBucket, admissionMediatorGrants, assertDerivedOwnerToken, assertLifecycleToken, assertValidOwnerToken, authorizeTrustedServeSnapshot, commitSiblingIssuance, credsClaims, EpEnvelopeError, ensureAuthorityStores, epAuthBucket, isReachable, jwtFromCreds, managedRetirementOpId, mintCreds, mintPublicUserJwt, newIdentity, observeHostedRunAttempt, openRecordsBucket, parseEndpointGate, parseServiceSpec, parseServiceStatus, rawDigest, parseSecretStoreIdentity, readCheckpointStatus, readRunAdmission, readRunRecord, readSvcRecordLeader, reconcileEndpointGate, sameSecretStoreIdentity, recordSpecKey, recordStatusKey, RECORD_KINDS, recordsBucket, remoteManagerActors, retirementFrontierStreams, runDriverCaller, serveIssuanceGateKv, standaloneConnectOpts, STANDING_RENEWABLE_TTL_SEC, withIssuerSession, acceptedReadGrant, actorLedgerSource, connectionAcceptedToken, importNativeSubjectPermissions, mintGeneration, parseActorLedgerSource, writeAcceptedRow, invokeCommand, resolveService, contractArtifactCanonicalBytes, DEV_OWNER, endpointRegistrationBarrier, mintLifecycleUid, principalKey, provisionEndpointGateOpen, publishContractArtifact, registerServiceInstance, registerServingInstance } from "@cotal-ai/core";
|
|
62
|
+
import { CotalEndpoint, deprovisionAgent, isConcreteChannel, provisionAgentDurables, contractDigest, contractRefToHex, contractStoreContext, endpointToken, fetchContractArtifact, verifyClusterManifest, verifyClusterRoot, admissionBucket, admissionMediatorGrants, assertDerivedOwnerToken, assertLifecycleToken, assertValidOwnerToken, authorizeTrustedServeSnapshot, commitSiblingIssuance, credsClaims, EpEnvelopeError, ensureAuthorityStores, epAuthBucket, isReachable, jwtFromCreds, managedRetirementOpId, mintCreds, mintPublicUserJwt, newIdentity, newTakeoverId, observeHostedRunAttempt, openRecordsBucket, parseEndpointGate, parseServiceSpec, parseServiceStatus, rawDigest, parseSecretStoreIdentity, readCheckpointStatus, readRunAdmission, readRunRecord, readSvcRecordLeader, reconcileEndpointGate, replayRunJournal, sameSecretStoreIdentity, recordSpecKey, recordStatusKey, RECORD_KINDS, recordsBucket, remoteManagerActors, retirementFrontierStreams, runDriverCaller, serveIssuanceGateKv, standaloneConnectOpts, STANDING_RENEWABLE_TTL_SEC, withIssuerSession, acceptedReadGrant, actorLedgerSource, connectionAcceptedToken, importNativeSubjectPermissions, mintGeneration, parseActorLedgerSource, writeAcceptedRow, invokeCommand, resolveService, contractArtifactCanonicalBytes, DEV_OWNER, endpointRegistrationBarrier, mintLifecycleUid, principalKey, provisionEndpointGateOpen, publishContractArtifact, registerServiceInstance, registerServingInstance } from "@cotal-ai/core";
|
|
63
63
|
import { findCotalRoot, loadManagerInstanceIdentity, userAuthStateDir, workspaceSecretStore, createAuthInstanceIdentity, loadAuthInstanceIdentity } from "@cotal-ai/workspace";
|
|
64
64
|
import { decodeJwt } from "jose";
|
|
65
65
|
import { deriveOwnerForIdpSubject, platformControlOwner } from "./derive.js";
|
|
@@ -90,6 +90,7 @@ import { makeDeliveryAdminEvictor, makeDeliveryAdminHolderEvictor } from "./barr
|
|
|
90
90
|
import { resumeAgentRetirement, runAgentRetirementBarrier } from "./retirement-barrier.js";
|
|
91
91
|
import { makeRetirementCleaners } from "./retirement-cleaner.js";
|
|
92
92
|
import { makeDrainRepairers } from "./drain-repair.js";
|
|
93
|
+
import { serializedFor } from "./serialized.js";
|
|
93
94
|
import { joinOrStartRetirement, openAuthAdminListener } from "./auth-admin.js";
|
|
94
95
|
import { AUTH_SERVICE_ENDPOINT, authClusterArtifacts, authContractArtifactValues } from "./auth-service-contract.js";
|
|
95
96
|
import { drainTargetForEndpoint, openAdmissionMediator } from "./admission-mediator.js";
|
|
@@ -122,20 +123,12 @@ const PUBLIC_PEER_BUCKETS_MAX = 1024; // bounded LRU of per-peer failure buckets
|
|
|
122
123
|
const PUBLIC_MAX_IN_FLIGHT = 64; // global concurrent-admission cap on the public listener
|
|
123
124
|
const PUBLIC_DEADLINE_MS = 10_000; // hard wall-clock deadline per public request
|
|
124
125
|
const HOST_FENCE_POLL_MS = 1_000; // how often awaitHostFence re-reads the host gate
|
|
125
|
-
const OBSERVED_RUN_REQUEST_WINDOW_MS = 5 * 60_000; // how long an observed served
|
|
126
|
+
const OBSERVED_RUN_REQUEST_WINDOW_MS = 5 * 60_000; // how long an observed served run request can still be forwarded
|
|
126
127
|
/** Enrollment and retirement preparation of one managed agent run one at a time, so neither acts on
|
|
127
128
|
* a grant the other is still writing or releasing. The chain lives at module level, keyed by the
|
|
128
129
|
* ledger directory, so two plane instances over one ledger share it. */
|
|
129
130
|
const MANAGED_ALIAS_CHAINS = new Map();
|
|
130
|
-
const serializedForAlias = (dir, owner, actor, fn) => {
|
|
131
|
-
const key = `${resolve(dir)}:${principalKey(owner, actor).key}`;
|
|
132
|
-
const run = (MANAGED_ALIAS_CHAINS.get(key) ?? Promise.resolve()).then(fn, fn);
|
|
133
|
-
const tail = run.then(() => undefined, () => undefined);
|
|
134
|
-
MANAGED_ALIAS_CHAINS.set(key, tail);
|
|
135
|
-
void tail.then(() => { if (MANAGED_ALIAS_CHAINS.get(key) === tail)
|
|
136
|
-
MANAGED_ALIAS_CHAINS.delete(key); });
|
|
137
|
-
return run;
|
|
138
|
-
};
|
|
131
|
+
const serializedForAlias = (dir, owner, actor, fn) => serializedFor(MANAGED_ALIAS_CHAINS, `${resolve(dir)}:${principalKey(owner, actor).key}`, fn);
|
|
139
132
|
/** Package-internal policy step for the hosted retirement requester. The HTTP production door calls
|
|
140
133
|
* this after deriving the owner and manager actors; broker-free smokes exercise the same decision. */
|
|
141
134
|
export function authorizeRemoteManagerRetirement(args) {
|
|
@@ -310,6 +303,9 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
310
303
|
let recordsScanner;
|
|
311
304
|
let barrierReg;
|
|
312
305
|
let closing = false;
|
|
306
|
+
// A failed open throws its own error, so a release failing on the way out is only logged: the
|
|
307
|
+
// row stays held and the next open reclaims it like a crash.
|
|
308
|
+
const releaseAfterFailedOpen = async () => hold?.release().catch((r) => log(r.message));
|
|
313
309
|
// The plane-fatal channel (fact HIGH: a fenced plane must never keep serving): the mid-life
|
|
314
310
|
// fence resolves it, every authority operation refuses from then on, and the composition root
|
|
315
311
|
// downs the daemon. A clean close never resolves it.
|
|
@@ -349,7 +345,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
349
345
|
closing = true;
|
|
350
346
|
await recordsCand?.close();
|
|
351
347
|
await ledgerCand?.close();
|
|
352
|
-
await
|
|
348
|
+
await releaseAfterFailedOpen();
|
|
353
349
|
await barrier?.close();
|
|
354
350
|
await remoteIssuer.close();
|
|
355
351
|
await reader.close();
|
|
@@ -415,7 +411,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
415
411
|
closing = true;
|
|
416
412
|
await recordsScanner.close();
|
|
417
413
|
await scanner.close();
|
|
418
|
-
await
|
|
414
|
+
await releaseAfterFailedOpen();
|
|
419
415
|
await barrier.close();
|
|
420
416
|
await remoteIssuer.close();
|
|
421
417
|
await reader.close();
|
|
@@ -438,7 +434,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
438
434
|
closing = true;
|
|
439
435
|
await recordsScanner.close();
|
|
440
436
|
await scanner.close();
|
|
441
|
-
await
|
|
437
|
+
await releaseAfterFailedOpen();
|
|
442
438
|
await barrier.close();
|
|
443
439
|
await remoteIssuer.close();
|
|
444
440
|
await reader.close();
|
|
@@ -447,6 +443,9 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
447
443
|
}
|
|
448
444
|
const fileArm = ledgerAuthorizeConnect(opts.dir);
|
|
449
445
|
const recordsJsm = await jetstreamManager(remoteIssuer.nc);
|
|
446
|
+
const authKv = await new Kvm(remoteIssuer.nc).open(epAuthBucket(space));
|
|
447
|
+
const managerIssuanceGate = (instanceId) => serveIssuanceGateKv(authKv, space, { endpoint: "manager", instanceId });
|
|
448
|
+
const observeManagerGate = async (instanceId) => managerIssuanceGate(instanceId).observe();
|
|
450
449
|
const loadLocalManager = opts.localManager ?? (() => undefined);
|
|
451
450
|
// Standing renewal and a served resume or answer read the manager surface from the REGISTERED
|
|
452
451
|
// service spec at the gate's registration revision: spec (leader read) -> closure manifest -> root
|
|
@@ -475,7 +474,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
475
474
|
};
|
|
476
475
|
const managerGate = async (owner, instanceId) => {
|
|
477
476
|
const localManager = loadLocalManager();
|
|
478
|
-
const gate = await
|
|
477
|
+
const gate = await observeManagerGate(instanceId);
|
|
479
478
|
if (!gate)
|
|
480
479
|
return "unknown";
|
|
481
480
|
if (gate.state !== "open")
|
|
@@ -549,8 +548,8 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
549
548
|
if (fatalReason !== undefined)
|
|
550
549
|
throw new EpEnvelopeError("unavailable", `the auth service for space "${space}" is momentarily unavailable (it detected a fault and is restarting); retry shortly`);
|
|
551
550
|
};
|
|
552
|
-
// The
|
|
553
|
-
//
|
|
551
|
+
// The plane holds only the data account's signing key. The operator and system halves stay blank
|
|
552
|
+
// because core's mint reads only the space, the account pub and the signing seed.
|
|
554
553
|
const issuerAuth = () => ({
|
|
555
554
|
space,
|
|
556
555
|
operator: { seed: "", jwt: "" },
|
|
@@ -560,10 +559,11 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
560
559
|
// The source check the issuing host resolves with: an actor-ledger row is attested here, from the
|
|
561
560
|
// ledger this service owns; every other coordinate goes to core's check (SPEC 13.15).
|
|
562
561
|
const composedSourceIsLive = (session) => (source) => parseActorLedgerSource(source) ? Promise.resolve(ledgerActorSourceIsLive(opts.dir)(source)) : session.sourceIsLive(source);
|
|
563
|
-
// A served resume or answer
|
|
564
|
-
//
|
|
565
|
-
// are the manager's word. The manager
|
|
566
|
-
//
|
|
562
|
+
// A served run-start is admitted, and a served resume or answer issued, only for a request this
|
|
563
|
+
// host saw its caller publish, and only once; a resume or answer only for what that request's
|
|
564
|
+
// envelope asked (SPEC 14.8): the forward's coordinates are the manager's word. The manager
|
|
565
|
+
// forwards from inside the handler serving the request, so an observation older than the window
|
|
566
|
+
// has no forward left to bind; the window also bounds the table.
|
|
567
567
|
const observedRunRequests = new Map();
|
|
568
568
|
for (const subject of servedRunRequestSubjects(space))
|
|
569
569
|
remoteIssuer.nc.subscribe(subject, {
|
|
@@ -590,7 +590,6 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
590
590
|
observedRunRequests.delete(subject);
|
|
591
591
|
return observed !== undefined && observed.expires > Date.now() ? observed.request : undefined;
|
|
592
592
|
};
|
|
593
|
-
const observeManagerGate = async (instanceId) => serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId }).observe();
|
|
594
593
|
// A managed lifecycle's broker footprint, released under a deprovisioner pinned to that uid, so
|
|
595
594
|
// no call here can reach a same-name successor's durables.
|
|
596
595
|
const deprovisionManagedFootprint = async (owner, actor, lifecycleUid, memberChannels) => {
|
|
@@ -656,7 +655,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
656
655
|
space,
|
|
657
656
|
managerGate: async (owner, instanceId) => {
|
|
658
657
|
const verdict = await managerGate(owner, assertLifecycleToken(instanceId, "serving.instanceId"));
|
|
659
|
-
const gate = await
|
|
658
|
+
const gate = await observeManagerGate(instanceId);
|
|
660
659
|
return { verdict, ...(gate ? { processEpoch: gate.processEpoch } : {}) };
|
|
661
660
|
},
|
|
662
661
|
}, principal, claim);
|
|
@@ -731,7 +730,6 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
731
730
|
issueManagerServiceAuthority: async (holder) => {
|
|
732
731
|
refuseIfFenced();
|
|
733
732
|
const { owner } = holder;
|
|
734
|
-
const observeManagerGate = async (instanceId) => (await serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId }).observe()) ?? null;
|
|
735
733
|
return issueRemoteManagerAuthority({
|
|
736
734
|
...holder,
|
|
737
735
|
authorizeRenewal: ({ owner: o, request: r }) => authorizeRemoteManagerRenewal({
|
|
@@ -746,7 +744,8 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
746
744
|
},
|
|
747
745
|
}),
|
|
748
746
|
issue: async ({ actors, request: r }) => {
|
|
749
|
-
const
|
|
747
|
+
const signer = { space, account: dataAccount };
|
|
748
|
+
const credential = async (key, profile, actor, opts) => mintPublicUserJwt(signer, r.identities[key].id, profile, { ...opts, principal: { owner, actor }, lifecycleUid: r.managerLifecycleUid });
|
|
750
749
|
const credentials = {};
|
|
751
750
|
const siblingOn = (gate, observed) => async (key, profile, actor) => {
|
|
752
751
|
const issued = await credential(key, profile, actor, profile === "goal-writer" ? { goalWriter: { endpoint: "manager" }, expiresInSeconds: standingTtl } : { expiresInSeconds: standingTtl });
|
|
@@ -767,7 +766,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
767
766
|
return issued;
|
|
768
767
|
};
|
|
769
768
|
if (r.operation === "renew") {
|
|
770
|
-
const gate =
|
|
769
|
+
const gate = managerIssuanceGate(r.instanceId);
|
|
771
770
|
const observed = await gate.observe();
|
|
772
771
|
if (!observed || observed.state !== "open")
|
|
773
772
|
throw new EpEnvelopeError("failed-precondition", "manager-service renewal found no current open manager gate");
|
|
@@ -798,7 +797,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
798
797
|
throw new EpEnvelopeError("permission-denied", "manager-service session proof does not match this owner/lifecycle");
|
|
799
798
|
const session = r.session;
|
|
800
799
|
const exp = Math.min(session.exp, Math.floor(Date.now() / 1000) + 24 * 60 * 60);
|
|
801
|
-
credentials.sessionServing = await mintPublicUserJwt(
|
|
800
|
+
credentials.sessionServing = await mintPublicUserJwt(signer, session.id, "session-serving", {
|
|
802
801
|
principal: { owner, actor: actors.serve },
|
|
803
802
|
lifecycleUid: r.managerLifecycleUid,
|
|
804
803
|
sessionServing: { endpoint: "manager", sessionId: session.sessionId, epoch: session.epoch },
|
|
@@ -810,7 +809,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
810
809
|
const expectedProof = remoteManagerRegistrationProof(owner, r);
|
|
811
810
|
if (r.registrationProof !== expectedProof)
|
|
812
811
|
throw new EpEnvelopeError("permission-denied", "manager-service transfer reader proof does not match this owner/lifecycle");
|
|
813
|
-
credentials.transferReader = await mintPublicUserJwt(
|
|
812
|
+
credentials.transferReader = await mintPublicUserJwt(signer, r.transferReader.id, "transfer-reader", { principal: { owner, actor: actors.serve }, lifecycleUid: r.managerLifecycleUid, transferReader: { instanceId: r.instanceId } });
|
|
814
813
|
return { credentials };
|
|
815
814
|
}
|
|
816
815
|
if (r.operation === "retire") {
|
|
@@ -818,13 +817,13 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
818
817
|
if (r.registrationProof !== expectedProof)
|
|
819
818
|
throw new EpEnvelopeError("permission-denied", "manager-service retirement proof does not match this owner/lifecycle");
|
|
820
819
|
const retirement = r.retirement;
|
|
821
|
-
const gate =
|
|
820
|
+
const gate = managerIssuanceGate(r.instanceId);
|
|
822
821
|
const observed = await gate.observe();
|
|
823
822
|
authorizeRemoteManagerRetirement({
|
|
824
823
|
owner, serveActor: actors.serve, instanceId: r.instanceId,
|
|
825
824
|
targetOwner: retirement.target.owner, serveEpoch: retirement.serveEpoch, gate: observed,
|
|
826
825
|
});
|
|
827
|
-
credentials.retirementRequester = await mintPublicUserJwt(
|
|
826
|
+
credentials.retirementRequester = await mintPublicUserJwt(signer, retirement.id, "retirement-requester", {
|
|
828
827
|
principal: { owner, actor: actors.serve },
|
|
829
828
|
lifecycleUid: r.managerLifecycleUid,
|
|
830
829
|
retirementRequester: {
|
|
@@ -839,7 +838,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
839
838
|
if (r.operation === "renewStandingBundle") {
|
|
840
839
|
// authorizeRenewal fresh-checked account, owner, epoch and the current-registration proof
|
|
841
840
|
// (which binds the held nkeys and lifecycle). Re-observe so every row binds one revision.
|
|
842
|
-
const gate =
|
|
841
|
+
const gate = managerIssuanceGate(r.instanceId);
|
|
843
842
|
const observed = await gate.observe();
|
|
844
843
|
if (!observed || observed.state !== "open" || observed.processEpoch !== r.processEpoch)
|
|
845
844
|
throw new EpEnvelopeError("conflict", "manager-service standing renewal gate moved before issuance");
|
|
@@ -851,7 +850,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
851
850
|
remoteManager: { instanceId: r.instanceId, owner, actor: actors.executor },
|
|
852
851
|
expiresInSeconds: 5 * 60,
|
|
853
852
|
});
|
|
854
|
-
credentials.serve = await mintPublicUserJwt(
|
|
853
|
+
credentials.serve = await mintPublicUserJwt(signer, r.identities.serve.id, "endpoint-serve", {
|
|
855
854
|
principal: { owner, actor: actors.serve },
|
|
856
855
|
lifecycleUid: r.managerLifecycleUid,
|
|
857
856
|
expiresInSeconds: standingTtl,
|
|
@@ -864,7 +863,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
864
863
|
return { credentials };
|
|
865
864
|
}
|
|
866
865
|
if (r.operation === "renewRunDriver") {
|
|
867
|
-
const gate =
|
|
866
|
+
const gate = managerIssuanceGate(r.instanceId);
|
|
868
867
|
const observed = await gate.observe();
|
|
869
868
|
if (!observed || observed.state !== "open" || observed.processEpoch !== r.processEpoch)
|
|
870
869
|
throw new EpEnvelopeError("conflict", "manager-service run renewal gate moved before issuance");
|
|
@@ -886,14 +885,13 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
886
885
|
epoch: r.run.epoch,
|
|
887
886
|
owner,
|
|
888
887
|
};
|
|
889
|
-
|
|
890
|
-
credentials.runDriver = await mintPublicUserJwt(auth, r.run.driverId, "run-driver", {
|
|
888
|
+
credentials.runDriver = await mintPublicUserJwt(signer, r.run.driverId, "run-driver", {
|
|
891
889
|
principal: { owner, actor: caller.actor },
|
|
892
890
|
lifecycleUid: r.managerLifecycleUid,
|
|
893
891
|
runDriver: binding,
|
|
894
892
|
expiresInSeconds: standingTtl,
|
|
895
893
|
});
|
|
896
|
-
credentials.runMediator = await mintPublicUserJwt(
|
|
894
|
+
credentials.runMediator = await mintPublicUserJwt(signer, r.run.mediatorId, "run-mediator", {
|
|
897
895
|
principal: { owner, actor: caller.actor },
|
|
898
896
|
lifecycleUid: r.managerLifecycleUid,
|
|
899
897
|
// Renewed with the placement the attempt was issued with (authorizeRemoteRunAttempt).
|
|
@@ -911,19 +909,17 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
911
909
|
// cross HTTP, so the host independently validates the deterministic proof + canonical
|
|
912
910
|
// artifact set and scopes the JWT to the already-registered instance rails. The grant
|
|
913
911
|
// rows are reconstructed from the canonical manager command set by the host protocol.
|
|
914
|
-
const gate =
|
|
912
|
+
const gate = managerIssuanceGate(r.instanceId);
|
|
915
913
|
const observed = await gate.observe();
|
|
916
914
|
if (!observed)
|
|
917
915
|
throw new EpEnvelopeError("failed-precondition", "manager-service activation found no issuance gate");
|
|
918
|
-
credentials.serve = await mintPublicUserJwt(
|
|
916
|
+
credentials.serve = await mintPublicUserJwt(signer, r.identities.serve.id, "endpoint-serve", {
|
|
919
917
|
principal: { owner, actor: actors.serve },
|
|
920
918
|
lifecycleUid: r.managerLifecycleUid,
|
|
921
919
|
expiresInSeconds: standingTtl,
|
|
922
|
-
endpointServe: reconstructRemoteManagerServeGrant(r, owner,
|
|
920
|
+
endpointServe: reconstructRemoteManagerServeGrant(r, owner, observed),
|
|
923
921
|
serveIssuance: gate,
|
|
924
922
|
});
|
|
925
|
-
if (!observed)
|
|
926
|
-
throw new EpEnvelopeError("failed-precondition", "manager-service activation found no issuance gate");
|
|
927
923
|
const sibling = siblingOn(gate, observed);
|
|
928
924
|
credentials.goalWriter = await sibling("goalWriter", "goal-writer", actors.goalWriter);
|
|
929
925
|
credentials.sessionLedger = await sibling("sessionLedger", "session-ledger", actors.sessionLedger);
|
|
@@ -942,27 +938,20 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
942
938
|
maintainRemoteManager: async (holder) => {
|
|
943
939
|
refuseIfFenced();
|
|
944
940
|
const { owner } = holder;
|
|
945
|
-
const gateKv = await new Kvm(remoteIssuer.nc).open(epAuthBucket(space));
|
|
946
941
|
const authorized = await authorizeRemoteManagerMaintenance({
|
|
947
942
|
...holder,
|
|
948
943
|
space,
|
|
949
944
|
scanner,
|
|
950
|
-
observeManagerGate
|
|
945
|
+
observeManagerGate,
|
|
951
946
|
});
|
|
952
|
-
const
|
|
947
|
+
const evictHolders = makeDeliveryAdminHolderEvictor({ space, server, dataAccount, log });
|
|
953
948
|
if (authorized.operation === "evict-family-principal") {
|
|
954
|
-
const
|
|
955
|
-
return completeRemoteManagerMaintenance(authorized, owner, {
|
|
949
|
+
const evictions = await evictHolders(authorized.principals);
|
|
950
|
+
return completeRemoteManagerMaintenance(authorized, owner, { evictions });
|
|
956
951
|
}
|
|
957
952
|
const principalOracle = makeDeliveryAdminPrincipalOracle({ space, server, dataAccount, log });
|
|
958
953
|
const executorIdentity = newIdentity();
|
|
959
|
-
const
|
|
960
|
-
space,
|
|
961
|
-
operator: { seed: "", jwt: "" },
|
|
962
|
-
account: { pub: dataAccount.pub, seed: "", jwt: "", signingSeed: dataAccount.signingSeed, signingPub: "" },
|
|
963
|
-
sys: { pub: "", jwt: "" },
|
|
964
|
-
};
|
|
965
|
-
const executorCreds = await mintCreds(hostAuth, executorIdentity, "endpoint-serve-executor", {
|
|
954
|
+
const executorCreds = await mintCreds(issuerAuth(), executorIdentity, "endpoint-serve-executor", {
|
|
966
955
|
endpointServeExecutor: { endpoint: "manager", instanceId: authorized.targetInstanceId },
|
|
967
956
|
expiresInSeconds: 60,
|
|
968
957
|
});
|
|
@@ -984,7 +973,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
984
973
|
const result = await principalOracle(principal);
|
|
985
974
|
return { state: result.state, detail: result.note ?? `delivery-daemon principal sweep, sweepComplete=${String(result.sweepComplete)}` };
|
|
986
975
|
},
|
|
987
|
-
evictHolders:
|
|
976
|
+
evictHolders: async (holders) => (await evictHolders(holders)).map((e) => e.verifiedGone),
|
|
988
977
|
log,
|
|
989
978
|
});
|
|
990
979
|
}
|
|
@@ -999,10 +988,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
999
988
|
...holder,
|
|
1000
989
|
proofSecret: dataAccount.signingSeed,
|
|
1001
990
|
space,
|
|
1002
|
-
observeManagerGate
|
|
1003
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1004
|
-
return gate.observe();
|
|
1005
|
-
},
|
|
991
|
+
observeManagerGate,
|
|
1006
992
|
});
|
|
1007
993
|
},
|
|
1008
994
|
verifyManagedAgentEnrollment: async ({ owner, scope, request }) => {
|
|
@@ -1013,10 +999,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1013
999
|
proofSecret: dataAccount.signingSeed,
|
|
1014
1000
|
space,
|
|
1015
1001
|
request,
|
|
1016
|
-
observeManagerGate
|
|
1017
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1018
|
-
return gate.observe();
|
|
1019
|
-
},
|
|
1002
|
+
observeManagerGate,
|
|
1020
1003
|
});
|
|
1021
1004
|
},
|
|
1022
1005
|
verifyManagedAgentPrepareRetirement: async ({ owner, scope, request }) => {
|
|
@@ -1027,10 +1010,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1027
1010
|
proofSecret: dataAccount.signingSeed,
|
|
1028
1011
|
space,
|
|
1029
1012
|
request,
|
|
1030
|
-
observeManagerGate
|
|
1031
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1032
|
-
return gate.observe();
|
|
1033
|
-
},
|
|
1013
|
+
observeManagerGate,
|
|
1034
1014
|
});
|
|
1035
1015
|
},
|
|
1036
1016
|
enrollManagedAgent: async ({ owner, scope, request, sentinelCreds, agentBearerExchangeUrl }) => {
|
|
@@ -1155,10 +1135,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1155
1135
|
dir: opts.dir,
|
|
1156
1136
|
proofSecret: dataAccount.signingSeed,
|
|
1157
1137
|
space,
|
|
1158
|
-
observeManagerGate
|
|
1159
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1160
|
-
return gate.observe();
|
|
1161
|
-
},
|
|
1138
|
+
observeManagerGate,
|
|
1162
1139
|
};
|
|
1163
1140
|
return request.kind === "manager-managed-agent-runtime-status"
|
|
1164
1141
|
? authorizeRemoteManagedAgentRuntimeStatus({ ...args, request })
|
|
@@ -1169,10 +1146,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1169
1146
|
const { owner } = holder;
|
|
1170
1147
|
const authorized = await authorizeRemoteManagerGoalIndexScan({
|
|
1171
1148
|
...holder, proofSecret: dataAccount.signingSeed, space,
|
|
1172
|
-
observeManagerGate
|
|
1173
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1174
|
-
return gate.observe();
|
|
1175
|
-
},
|
|
1149
|
+
observeManagerGate,
|
|
1176
1150
|
});
|
|
1177
1151
|
return completeRemoteManagerGoalIndexScan(authorized, owner, await recordsScanner.scanManagerGoalIndex(owner));
|
|
1178
1152
|
},
|
|
@@ -1185,10 +1159,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1185
1159
|
space,
|
|
1186
1160
|
dir: opts.dir,
|
|
1187
1161
|
request,
|
|
1188
|
-
observeManagerGate
|
|
1189
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1190
|
-
return gate.observe();
|
|
1191
|
-
},
|
|
1162
|
+
observeManagerGate,
|
|
1192
1163
|
});
|
|
1193
1164
|
},
|
|
1194
1165
|
admitManagerRun: async ({ request, ...holder }) => {
|
|
@@ -1196,17 +1167,11 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1196
1167
|
const { owner } = holder;
|
|
1197
1168
|
requireManagerAuthorityHolder(holder, String(request?.instanceId), 'manager run admission needs scope "supervise"; spawn/admin do not imply it');
|
|
1198
1169
|
const runId = parseRemoteRunAdmissionRequest(request).run.runId;
|
|
1199
|
-
|
|
1200
|
-
space,
|
|
1201
|
-
operator: { seed: "", jwt: "" },
|
|
1202
|
-
account: { pub: dataAccount.pub, seed: "", jwt: "", signingSeed: dataAccount.signingSeed, signingPub: "" },
|
|
1203
|
-
sys: { pub: "", jwt: "" },
|
|
1204
|
-
};
|
|
1205
|
-
return withIssuerSession({ servers: server, space, auth: hostAuth, tls: false }, async (session) => {
|
|
1170
|
+
return withIssuerSession({ servers: server, space, auth: issuerAuth(), tls: false }, async (session) => {
|
|
1206
1171
|
const admitterNc = await connect({
|
|
1207
1172
|
servers: server,
|
|
1208
1173
|
...standaloneConnectOpts({
|
|
1209
|
-
creds: await mintCreds(
|
|
1174
|
+
creds: await mintCreds(issuerAuth(), newIdentity(), "run-admitter", { runAdmitter: { endpoint: "manager", runId }, expiresInSeconds: 60 }),
|
|
1210
1175
|
tls: false,
|
|
1211
1176
|
}),
|
|
1212
1177
|
maxReconnectAttempts: 0,
|
|
@@ -1214,12 +1179,10 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1214
1179
|
try {
|
|
1215
1180
|
return await admitRemoteRun({
|
|
1216
1181
|
request, owner, space, accountPublicKey: dataAccount.pub, proofSecret: dataAccount.signingSeed, endpoint: "manager",
|
|
1217
|
-
observeManagerGate
|
|
1218
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1219
|
-
return gate.observe();
|
|
1220
|
-
},
|
|
1182
|
+
observeManagerGate,
|
|
1221
1183
|
issued: session.store,
|
|
1222
1184
|
sourceIsLive: composedSourceIsLive(session),
|
|
1185
|
+
takeObserved: takeObservedRunRequest,
|
|
1223
1186
|
admissions: await new Kvm(admitterNc).open(admissionBucket(space)),
|
|
1224
1187
|
});
|
|
1225
1188
|
}
|
|
@@ -1253,12 +1216,28 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1253
1216
|
accountPublicKey: dataAccount.pub,
|
|
1254
1217
|
proofSecret: dataAccount.signingSeed,
|
|
1255
1218
|
endpoint: "manager",
|
|
1256
|
-
observeManagerGate
|
|
1257
|
-
const gate = serveIssuanceGateKv(await new Kvm(remoteIssuer.nc).open(epAuthBucket(space)), space, { endpoint: "manager", instanceId });
|
|
1258
|
-
return gate.observe();
|
|
1259
|
-
},
|
|
1219
|
+
observeManagerGate,
|
|
1260
1220
|
readAdmission: (runId) => readRunAdmission(recordsJsm, space, "manager", runId),
|
|
1261
1221
|
readRunStatus: async (runId) => (await readRunRecord(recordsKv, "manager", runId))?.status?.value,
|
|
1222
|
+
// Replayed under a read operator minted for that one run, the rows the manager's own read rides.
|
|
1223
|
+
readJournal: async (runId) => {
|
|
1224
|
+
const takeoverId = newTakeoverId();
|
|
1225
|
+
const readerNc = await connect({
|
|
1226
|
+
servers: server,
|
|
1227
|
+
...standaloneConnectOpts({
|
|
1228
|
+
creds: await mintCreds(issuerAuth(), newIdentity(), "run-operator", { runOperator: { endpoint: "manager", takeoverId, runId }, expiresInSeconds: 60 }),
|
|
1229
|
+
tls: false,
|
|
1230
|
+
}),
|
|
1231
|
+
maxReconnectAttempts: 0,
|
|
1232
|
+
});
|
|
1233
|
+
try {
|
|
1234
|
+
const replay = await replayRunJournal(jetstream(readerNc), await jetstreamManager(readerNc), space, runId, takeoverId);
|
|
1235
|
+
return replay.records.flatMap((stored) => stored.record.kind === "step" ? [stored.record.entry] : []);
|
|
1236
|
+
}
|
|
1237
|
+
finally {
|
|
1238
|
+
await readerNc.drain().catch(() => readerNc.close());
|
|
1239
|
+
}
|
|
1240
|
+
},
|
|
1262
1241
|
checkpointWaiting: async (token) => (await readCheckpointStatus(recordsKv, { endpoint: "manager", token }))?.value.state === "waiting",
|
|
1263
1242
|
checkpointSettled: async (token) => {
|
|
1264
1243
|
const status = (await readCheckpointStatus(recordsKv, { endpoint: "manager", token }))?.value;
|
|
@@ -1269,21 +1248,15 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1269
1248
|
const grant = req.attempt?.served !== undefined || req.operator?.served !== undefined
|
|
1270
1249
|
? await withIssuerSession({ servers: server, space, auth: issuerAuth(), tls: false }, (session) => authorize(session))
|
|
1271
1250
|
: await authorize();
|
|
1272
|
-
const hostAuth = {
|
|
1273
|
-
space,
|
|
1274
|
-
operator: { seed: "", jwt: "" },
|
|
1275
|
-
account: { pub: dataAccount.pub, seed: "", jwt: "", signingSeed: dataAccount.signingSeed, signingPub: "" },
|
|
1276
|
-
sys: { pub: "", jwt: "" },
|
|
1277
|
-
};
|
|
1278
1251
|
if (grant.kind === "attempt") {
|
|
1279
1252
|
const caller = runDriverCaller(grant.driver.runDriver.runId, owner);
|
|
1280
|
-
const driver = await mintPublicUserJwt(
|
|
1253
|
+
const driver = await mintPublicUserJwt(issuerAuth(), grant.driver.id, "run-driver", {
|
|
1281
1254
|
principal: { owner, actor: caller.actor },
|
|
1282
1255
|
lifecycleUid: req.managerLifecycleUid,
|
|
1283
1256
|
runDriver: grant.driver.runDriver,
|
|
1284
1257
|
expiresInSeconds: standingTtl,
|
|
1285
1258
|
});
|
|
1286
|
-
const mediator = await mintPublicUserJwt(
|
|
1259
|
+
const mediator = await mintPublicUserJwt(issuerAuth(), grant.mediator.id, "run-mediator", {
|
|
1287
1260
|
principal: { owner, actor: caller.actor },
|
|
1288
1261
|
lifecycleUid: req.managerLifecycleUid,
|
|
1289
1262
|
runMediator: grant.mediator.runMediator,
|
|
@@ -1306,7 +1279,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1306
1279
|
credentials: { driver, mediator },
|
|
1307
1280
|
};
|
|
1308
1281
|
}
|
|
1309
|
-
const operator = await mintPublicUserJwt(
|
|
1282
|
+
const operator = await mintPublicUserJwt(issuerAuth(), grant.operator.id, "run-operator", {
|
|
1310
1283
|
principal: { owner, actor: req.actor },
|
|
1311
1284
|
lifecycleUid: req.managerLifecycleUid,
|
|
1312
1285
|
runOperator: grant.operator.runOperator,
|
|
@@ -1331,7 +1304,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1331
1304
|
},
|
|
1332
1305
|
observeManagerInstance: async (instanceId) => {
|
|
1333
1306
|
refuseIfFenced();
|
|
1334
|
-
const gate = await
|
|
1307
|
+
const gate = await observeManagerGate(instanceId);
|
|
1335
1308
|
const rec = await readSvcRecordLeader(recordsJsm, space, recordSpecKey(RECORD_KINDS.svc, ["manager", instanceId]));
|
|
1336
1309
|
return { registered: rec !== undefined && !("deleted" in rec), gate: gate ?? null };
|
|
1337
1310
|
},
|
|
@@ -1356,7 +1329,7 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1356
1329
|
},
|
|
1357
1330
|
observeEndpointGate: async (endpoint, instanceId) => {
|
|
1358
1331
|
refuseIfFenced();
|
|
1359
|
-
return await serveIssuanceGateKv(
|
|
1332
|
+
return await serveIssuanceGateKv(authKv, space, { endpoint, instanceId }).observe();
|
|
1360
1333
|
},
|
|
1361
1334
|
fenced,
|
|
1362
1335
|
close: async () => {
|
|
@@ -1368,10 +1341,14 @@ export async function openAuthAuthorityPlane(opts) {
|
|
|
1368
1341
|
await reader.close();
|
|
1369
1342
|
await recordsScanner.close();
|
|
1370
1343
|
await scanner.close();
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1344
|
+
try {
|
|
1345
|
+
await hold.release();
|
|
1346
|
+
}
|
|
1347
|
+
finally {
|
|
1348
|
+
await barrier.close();
|
|
1349
|
+
await remoteIssuer.close();
|
|
1350
|
+
await writer.close();
|
|
1351
|
+
}
|
|
1375
1352
|
},
|
|
1376
1353
|
};
|
|
1377
1354
|
}
|
|
@@ -1522,7 +1499,13 @@ export async function runAuthService(args, store) {
|
|
|
1522
1499
|
// The CLI wrapper, not the context, owns process signals and exit codes.
|
|
1523
1500
|
const stop = async () => {
|
|
1524
1501
|
clearAuthServiceInfo(dir); // a dead service must not satisfy the next start's readiness poll
|
|
1525
|
-
|
|
1502
|
+
try {
|
|
1503
|
+
await started.handle.close();
|
|
1504
|
+
}
|
|
1505
|
+
catch (e) {
|
|
1506
|
+
console.error(`✗ auth-service: ${e.message} - exiting`);
|
|
1507
|
+
process.exit(1);
|
|
1508
|
+
}
|
|
1526
1509
|
process.exit(0);
|
|
1527
1510
|
};
|
|
1528
1511
|
process.on("SIGINT", () => void stop());
|
|
@@ -1549,7 +1532,10 @@ export async function runAuthService(args, store) {
|
|
|
1549
1532
|
* installs no process signal handler, never exits the process, never selects a root from cwd,
|
|
1550
1533
|
* and has no local manager. It returns only after the authority plane, the callout subscription
|
|
1551
1534
|
* and the loopback listener are bound. A failed start releases what it acquired and throws. A
|
|
1552
|
-
* mid-life fence or broker loss makes only this context `unavailable` and closes its resources.
|
|
1535
|
+
* mid-life fence or broker loss makes only this context `unavailable` and closes its resources.
|
|
1536
|
+
* `close()` rejects when the context did not release its plane claim (SPEC 13.13): the row was
|
|
1537
|
+
* no longer its own, or the release write failed. The next start reclaims a row left held through
|
|
1538
|
+
* the liveness oracle. */
|
|
1553
1539
|
export async function startAuthService(inputs) {
|
|
1554
1540
|
if (!inputs.context?.accountPublicKey || !inputs.context.lifecycleUid || !inputs.space || !inputs.servers || !inputs.stateDir)
|
|
1555
1541
|
throw new Error("auth-service: hosted context needs an account, lifecycle, space, server and stateDir");
|
|
@@ -1585,7 +1571,7 @@ export async function startAuthService(inputs) {
|
|
|
1585
1571
|
...(inputs.platformControl !== undefined ? { platformControl: inputs.platformControl } : {}),
|
|
1586
1572
|
...(inputs.standingRenewableTtlSeconds !== undefined ? { standingRenewableTtlSeconds: inputs.standingRenewableTtlSeconds } : {}),
|
|
1587
1573
|
});
|
|
1588
|
-
return started.handle;
|
|
1574
|
+
return { ...started.handle, readiness: () => ({ ...started.status(), context: inputs.context }) };
|
|
1589
1575
|
}
|
|
1590
1576
|
async function startAuthContext(o) {
|
|
1591
1577
|
const { space, server, dir, secrets, port } = o;
|
|
@@ -1758,8 +1744,12 @@ async function startAuthContext(o) {
|
|
|
1758
1744
|
closePromise = (async () => {
|
|
1759
1745
|
await Promise.all([closeServer(http), closeServer(publicHttp)]);
|
|
1760
1746
|
await reader?.client.then((c) => c.close(), () => { });
|
|
1761
|
-
|
|
1762
|
-
|
|
1747
|
+
try {
|
|
1748
|
+
await plane.close();
|
|
1749
|
+
}
|
|
1750
|
+
finally {
|
|
1751
|
+
await callNc.close();
|
|
1752
|
+
}
|
|
1763
1753
|
})();
|
|
1764
1754
|
return closePromise;
|
|
1765
1755
|
};
|
|
@@ -1771,11 +1761,11 @@ async function startAuthContext(o) {
|
|
|
1771
1761
|
if (end.kind === "fenced" || end.cause !== undefined || closePromise === undefined) {
|
|
1772
1762
|
state = "unavailable";
|
|
1773
1763
|
cause = end.kind === "fenced" ? end.cause : `broker connection closed${end.cause !== undefined ? ` (${end.cause})` : ""}`;
|
|
1774
|
-
|
|
1764
|
+
// A later close() returns this same promise, so its failure still reaches the host.
|
|
1765
|
+
close().catch(() => { });
|
|
1775
1766
|
}
|
|
1776
1767
|
return end;
|
|
1777
1768
|
});
|
|
1778
|
-
const context = o.context ?? { accountPublicKey: keys.dataAccount.pub, lifecycleUid: "" };
|
|
1779
1769
|
const platformControl = o.platformControl;
|
|
1780
1770
|
const host = platformControl?.host;
|
|
1781
1771
|
// The human route's retained-validation composition, for the platform holder.
|
|
@@ -1878,15 +1868,11 @@ async function startAuthContext(o) {
|
|
|
1878
1868
|
}
|
|
1879
1869
|
},
|
|
1880
1870
|
} : {}),
|
|
1881
|
-
readiness() {
|
|
1882
|
-
if (state === "unavailable")
|
|
1883
|
-
return { state, context, cause: cause ?? "auth-service context is unavailable" };
|
|
1884
|
-
return { state: closePromise === undefined ? "ready" : "draining", context };
|
|
1885
|
-
},
|
|
1886
1871
|
drain: close,
|
|
1887
1872
|
close,
|
|
1888
1873
|
};
|
|
1889
|
-
|
|
1874
|
+
const status = () => state === "unavailable" ? { state, cause: cause ?? "auth-service context is unavailable" } : { state: closePromise === undefined ? "ready" : "draining" };
|
|
1875
|
+
return { handle: service, status, ended };
|
|
1890
1876
|
}
|
|
1891
1877
|
catch (e) {
|
|
1892
1878
|
// A failed start releases only what THIS context acquired, in reverse order.
|