@corenel/harness 0.18.0 → 0.19.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.
@@ -1622,6 +1622,13 @@ export class SidecarServer {
1622
1622
  return false;
1623
1623
  }
1624
1624
  }
1625
+ /** The issuer named on the identity challenge: the verifier's own, when it
1626
+ * has one and it is a sane length. Explanation only (see the protocol's
1627
+ * `identity-challenge.issuer`); never part of a verdict. */
1628
+ challengeIssuer() {
1629
+ const iss = this.opts.identity?.issuer;
1630
+ return typeof iss === 'string' && iss.length > 0 && iss.length <= 512 ? iss : undefined;
1631
+ }
1625
1632
  /** THE IDENTITY GATE (spec 2026-09-29-device-enrollment-design, Phase 2),
1626
1633
  * run inside the credential check once the device key is proven -- for an
1627
1634
  * enrollment, BEFORE the code is burned -- so a code alone never enrolls an
@@ -1642,7 +1649,7 @@ export class SidecarServer {
1642
1649
  }
1643
1650
  const nonce = makeNonce();
1644
1651
  const orgId = this.opts.admission?.orgId;
1645
- this.ch.send({ t: 'identity-challenge', nonce, sidecarId, ...(orgId ? { orgId } : {}) });
1652
+ this.ch.send({ t: 'identity-challenge', nonce, sidecarId, ...(orgId ? { orgId } : {}), ...(this.challengeIssuer() ? { issuer: this.challengeIssuer() } : {}) });
1646
1653
  const verdict = await this.awaitAndVerifyIdentity(sidecarId, nonce, jkt, IDENTITY_TIMEOUT_MS);
1647
1654
  if (!verdict.ok) {
1648
1655
  this.opts.log?.(`identity: unverified (${verdict.reason})`);
@@ -1694,7 +1701,7 @@ export class SidecarServer {
1694
1701
  try {
1695
1702
  const nonce = makeNonce();
1696
1703
  const orgId = this.opts.admission?.orgId;
1697
- this.ch.send({ t: 'identity-challenge', nonce, sidecarId, ...(orgId ? { orgId } : {}) });
1704
+ this.ch.send({ t: 'identity-challenge', nonce, sidecarId, ...(orgId ? { orgId } : {}), ...(this.challengeIssuer() ? { issuer: this.challengeIssuer() } : {}) });
1698
1705
  const verdict = await this.awaitAndVerifyIdentity(sidecarId, nonce, jkt, RECHECK_TIMEOUT_MS);
1699
1706
  if (this.closed)
1700
1707
  return;
@@ -2198,7 +2205,6 @@ export class SidecarServer {
2198
2205
  await this.replayDrained();
2199
2206
  if (this.closed)
2200
2207
  return;
2201
- this.opts.log?.(`paired — ${this.tools.size} ${this.tools.size === 1 ? 'tool' : 'tools'} advertised (host dir: ${this.hostStateDir})`);
2202
2208
  if (!dirNamePending) {
2203
2209
  this.sendWelcome(null);
2204
2210
  return;
@@ -2352,6 +2358,11 @@ export class SidecarServer {
2352
2358
  * The browser re-pairs once approved. */
2353
2359
  const pending = this.memberPending();
2354
2360
  const tools = pending || this.peerDaemon ? [] : [...this.tools.values()].map(({ run: _run, ...decl }) => decl);
2361
+ /* The count THIS connection is sent, not the daemon's total: a pending
2362
+ * member gets none, and a log that said otherwise hid exactly that. */
2363
+ const toolNote = `${tools.length} ${tools.length === 1 ? 'tool' : 'tools'}`;
2364
+ const why = pending ? ' (pending member: nothing is shared until the admin approves)' : this.peerDaemon ? ' (peer daemon)' : '';
2365
+ this.opts.log?.(`paired — ${toolNote} advertised${why} (host dir: ${this.hostStateDir})`);
2355
2366
  const full = this.opts.info;
2356
2367
  const info = !full ? undefined
2357
2368
  : pending ? { ...(full.id !== undefined ? { id: full.id } : {}), ...(full.name !== undefined ? { name: full.name } : {}) }
@@ -4562,6 +4573,7 @@ export class SidecarServer {
4562
4573
  ...(reply.adminLabel !== undefined ? { adminLabel: reply.adminLabel } : {}),
4563
4574
  ...(reply.adminId !== undefined ? { adminId: reply.adminId } : {}),
4564
4575
  ...(reply.admin !== undefined ? { admin: reply.admin } : {}),
4576
+ ...(reply.noAdmin === true ? { noAdmin: true } : {}),
4565
4577
  ...(reply.members ? {
4566
4578
  members: reply.members.map((r) => ({
4567
4579
  userId: r.userId, status: r.status, firstSeen: r.firstSeen, label: r.label,