@camstack/system 1.2.395 → 1.2.396

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.
@@ -1,5 +1,5 @@
1
1
  import { Ln as storageOccupancyCapability, Vr as nodePin, X as backupCapability, dr as BaseAddon, ei as toNodeId, ri as EventCategory, rn as mayWriteToLocation } from "../../dist-0P1gm4Gd.mjs";
2
- import { a as BackupSnapshotRefusedError, c as BackupKeyFormatError, d as generateBackupKeyPair, f as parseBackupPublicKey, i as BackupCancelledError, n as precheckRestoreKey, o as SystemBackupService, p as parseBackupSecretKey, r as prepareRestoreArchive, u as ENCRYPTED_BACKUP_SUFFIX } from "../../restore-archive-KnMS8Uta.mjs";
2
+ import { a as BackupSnapshotRefusedError, c as BackupKeyFormatError, d as generateBackupKeyPair, f as parseBackupPublicKey, i as BackupCancelledError, n as precheckRestoreKey, o as SystemBackupService, p as parseBackupSecretKey, r as prepareRestoreArchive, u as ENCRYPTED_BACKUP_SUFFIX } from "../../restore-archive-0g91qMVF.mjs";
3
3
  import { randomUUID } from "node:crypto";
4
4
  import * as fsp from "node:fs/promises";
5
5
  import * as path$1 from "node:path";
@@ -7,6 +7,8 @@ export declare class SystemConfigAddon extends BaseAddon {
7
7
  readonly id = "system-config";
8
8
  private clusterSecretKeeper;
9
9
  private meshCaKeeper;
10
+ /** One warn per process when a retired cutover key is posted with a cluster save. */
11
+ private retiredClusterCutoverPatchWarned;
10
12
  constructor();
11
13
  protected onInitialize(): Promise<AddonInitResult<typeof systemConfigMeshActions>>;
12
14
  protected onShutdown(): Promise<void>;
@@ -30,7 +32,7 @@ export declare class SystemConfigAddon extends BaseAddon {
30
32
  /**
31
33
  * The admin UI / `addonSettings` cap prefer {@link BaseAddon.updateGlobalSettingsAsOperator}.
32
34
  * That BaseAddon path writes the generic addon store and never reaches
33
- * {@link writeClusterSection} / {@link writeMeshClearPort}. Route the operator
35
+ * {@link writeClusterSection}. Route the operator
34
36
  * write through the same section-aware path as {@link updateGlobalSettings}.
35
37
  */
36
38
  override updateGlobalSettingsAsOperator(patch: Record<string, unknown>, _nodeId?: string): Promise<void>;
@@ -43,12 +45,8 @@ export declare class SystemConfigAddon extends BaseAddon {
43
45
  * enforced (D821) — a legacy `meshAuth` in the patch is ignored.
44
46
  */
45
47
  private writeClusterSection;
46
- /**
47
- * `cluster.meshClearPort`: `off` is REFUSED while any online agent still
48
- * connects in clear (or the TLS listener is not up); the refusal names them.
49
- * Persist, then apply — an `on` save always passes.
50
- */
51
- private writeMeshClearPort;
48
+ /** Cutover keys were removed from the Cluster form; ignore stray posts from stale clients. */
49
+ private warnRetiredClusterCutoverPatch;
52
50
  /** Persist + publish mesh auth mode (always `enforced` after D821). */
53
51
  private writeMeshAuthMode;
54
52
  /**
@@ -88102,6 +88102,8 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88102
88102
  id = "system-config";
88103
88103
  clusterSecretKeeper = null;
88104
88104
  meshCaKeeper = null;
88105
+ /** One warn per process when a retired cutover key is posted with a cluster save. */
88106
+ retiredClusterCutoverPatchWarned = false;
88105
88107
  constructor() {
88106
88108
  super({});
88107
88109
  }
@@ -88337,52 +88339,18 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88337
88339
  title: SECTION_TITLES["cluster"],
88338
88340
  description: "Agents joining this hub. Every agent proves the cluster secret when it connects (challenge–response; the secret never crosses the network).",
88339
88341
  columns: 1,
88340
- fields: [
88341
- {
88342
- type: "password",
88343
- key: CLUSTER_SECRET_FIELD,
88344
- label: "Cluster secret",
88345
- description: "Mandatory — generated by the hub at first boot and stored in the keychain. To pair an agent: Reveal and copy it here, then enter it in the agent (its status page, or the desktop setup window). Saving a new value rotates it: every agent must then be given the new one."
88346
- },
88347
- {
88348
- type: "select",
88349
- key: MESH_CLEAR_PORT_FIELD,
88350
- label: "Clear mesh port (:6000)",
88351
- description: "On keeps the clear TCP port and UDP discovery next to the TLS port (:6443). Off closes both — refused while any connected agent has not enrolled with a join token (the Cluster page shows TLS / clear per node).",
88352
- default: "on",
88353
- options: [{
88354
- value: "on",
88355
- label: "On — accept clear agents"
88356
- }, {
88357
- value: "off",
88358
- label: "Off — mutual TLS only"
88359
- }]
88360
- },
88361
- {
88362
- type: "info",
88363
- key: "meshAuthStatus",
88364
- label: "Mesh authentication",
88365
- content: describeMeshStatus(getProcessMeshAuthStatus()),
88366
- variant: "info"
88367
- },
88368
- {
88369
- type: "text",
88370
- key: AGENT_DASHBOARD_ORIGINS_FIELD,
88371
- label: "Agent dashboard origins (NPM)",
88372
- description: "Extra origins allowed for Continue-with-hub unlock redirects (comma-separated), e.g. https://agent.example.com. LAN agents on :4444 are always allowed."
88373
- },
88374
- {
88375
- type: "addon-action-button",
88376
- key: "mintJoinTokenAction",
88377
- label: "Add agent",
88378
- description: "Mint a single-use join token (≤ 1 hour). Paste it into the agent setup instead of copying the cluster secret. The token is shown once in the result.",
88379
- addonId: "system-config",
88380
- action: "mintJoinToken",
88381
- buttonLabel: "Add agent",
88382
- variant: "primary",
88383
- successMessage: "Join token (copy now): {token}"
88384
- }
88385
- ]
88342
+ fields: [{
88343
+ type: "password",
88344
+ key: CLUSTER_SECRET_FIELD,
88345
+ label: "Cluster secret",
88346
+ description: "Mandatory — generated by the hub at first boot and stored in the keychain. To pair an agent: Reveal and copy it here, then enter it in the agent (its status page, or the desktop setup window). Saving a new value rotates it: every agent must then be given the new one."
88347
+ }, {
88348
+ type: "info",
88349
+ key: "meshAuthStatus",
88350
+ label: "Mesh authentication",
88351
+ content: describeMeshStatus(getProcessMeshAuthStatus()),
88352
+ variant: "info"
88353
+ }]
88386
88354
  }
88387
88355
  ] };
88388
88356
  }
@@ -88406,7 +88374,7 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88406
88374
  /**
88407
88375
  * The admin UI / `addonSettings` cap prefer {@link BaseAddon.updateGlobalSettingsAsOperator}.
88408
88376
  * That BaseAddon path writes the generic addon store and never reaches
88409
- * {@link writeClusterSection} / {@link writeMeshClearPort}. Route the operator
88377
+ * {@link writeClusterSection}. Route the operator
88410
88378
  * write through the same section-aware path as {@link updateGlobalSettings}.
88411
88379
  */
88412
88380
  async updateGlobalSettingsAsOperator(patch, _nodeId) {
@@ -88457,8 +88425,7 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88457
88425
  */
88458
88426
  async writeClusterSection(patch) {
88459
88427
  const { [MESH_AUTH_MODE_FIELD]: _legacyMode, [MESH_CLEAR_PORT_FIELD]: clearPort, [AGENT_DASHBOARD_ORIGINS_FIELD]: dashboardOrigins, ...secretPatch } = patch;
88460
- if (clearPort !== void 0) await this.writeMeshClearPort(clearPort);
88461
- if (dashboardOrigins !== void 0) await this.ctx.settings.setSection("cluster", { [AGENT_DASHBOARD_ORIGINS_FIELD]: typeof dashboardOrigins === "string" ? dashboardOrigins : "" });
88428
+ if (clearPort !== void 0 || dashboardOrigins !== void 0) this.warnRetiredClusterCutoverPatch(clearPort !== void 0, dashboardOrigins !== void 0);
88462
88429
  await this.writeMeshAuthMode("enforced");
88463
88430
  if (Object.keys(secretPatch).length === 0) return;
88464
88431
  if (require_dist.isSecretClear(secretPatch["clusterSecret"])) throw new Error("The cluster secret is mandatory and cannot be cleared — save a new value to rotate it");
@@ -88466,26 +88433,14 @@ var SystemConfigAddon = class extends require_dist.BaseAddon {
88466
88433
  this.ctx.logger.info("Cluster secret updated");
88467
88434
  await this.clusterSecretKeeper?.reload();
88468
88435
  }
88469
- /**
88470
- * `cluster.meshClearPort`: `off` is REFUSED while any online agent still
88471
- * connects in clear (or the TLS listener is not up); the refusal names them.
88472
- * Persist, then apply — an `on` save always passes.
88473
- */
88474
- async writeMeshClearPort(value) {
88475
- if (!isMeshClearPortMode(value)) throw new Error(`system-config: meshClearPort must be 'on' or 'off'`);
88476
- const stored = (await this.ctx.settings.getSection("cluster"))[MESH_CLEAR_PORT_FIELD];
88477
- if (parseMeshClearPortMode(stored) === value) return;
88478
- const decision = checkProcessMeshClearPort(value);
88479
- if (!decision.allowed) {
88480
- this.ctx.logger.warn("mesh clear port switch-off refused", { meta: {
88481
- blocking: decision.blocking,
88482
- error: decision.error
88483
- } });
88484
- throw new Error(decision.error);
88485
- }
88486
- await this.ctx.settings.setSection("cluster", { [MESH_CLEAR_PORT_FIELD]: value });
88487
- await applyProcessMeshClearPort(value);
88488
- this.ctx.logger.info("Mesh clear port switched", { meta: { mode: value } });
88436
+ /** Cutover keys were removed from the Cluster form; ignore stray posts from stale clients. */
88437
+ warnRetiredClusterCutoverPatch(hadMeshClearPort, hadAgentDashboardOrigins) {
88438
+ if (this.retiredClusterCutoverPatchWarned) return;
88439
+ this.retiredClusterCutoverPatchWarned = true;
88440
+ this.ctx.logger.warn("cluster save ignored retired cutover field(s) — use Pipeline → Cluster / Nodes", { meta: {
88441
+ meshClearPort: hadMeshClearPort,
88442
+ agentDashboardOrigins: hadAgentDashboardOrigins
88443
+ } });
88489
88444
  }
88490
88445
  /** Persist + publish mesh auth mode (always `enforced` after D821). */
88491
88446
  async writeMeshAuthMode(mode) {