@forgezero/agent 0.1.122 → 0.1.124

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.
@@ -917,7 +917,7 @@ async function postSignedNode(options, path, body) {
917
917
  }
918
918
 
919
919
  // src/version.ts
920
- var VERSION3 = "0.1.122";
920
+ var VERSION3 = "0.1.124";
921
921
 
922
922
  // src/agent-heartbeat.ts
923
923
  function readAgentHostMetrics() {
package/dist/bootstrap.js CHANGED
@@ -1460,7 +1460,7 @@ var UPDATE_RETRY_BASE_MS = 5 * 60000;
1460
1460
  var UPDATE_RETRY_MAX_MS = 24 * 60 * 60000;
1461
1461
 
1462
1462
  // src/version.ts
1463
- var VERSION = "0.1.122";
1463
+ var VERSION = "0.1.124";
1464
1464
 
1465
1465
  // src/software.ts
1466
1466
  var PINNED_BUN_VERSION = "1.3.14";
@@ -6,7 +6,9 @@ export declare const COMMUNITY_CREDENTIAL_PARENT = "/etc/forgezero-rehearsal";
6
6
  export declare const COMMUNITY_CREDENTIAL_ROOT = "/etc/forgezero-rehearsal/creds";
7
7
  export declare const COMMUNITY_REHEARSAL_STARTER_PORT = 18528;
8
8
  export declare const COMMUNITY_REHEARSAL_COORDINATOR_PORT = 18529;
9
+ export declare const COMMUNITY_REHEARSAL_DATABASE_PORT_RANGE = "18528:18539";
9
10
  export declare const COMMUNITY_REHEARSAL_API_PORT = 18787;
11
+ export declare const COMMUNITY_REHEARSAL_FIREWALL_COMMENT = "fz-community-rehearsal";
10
12
  export interface CommunityRehearsalNode {
11
13
  name: string;
12
14
  address: string;
@@ -44,6 +46,8 @@ export type CommunityRehearsalHostRequest = {
44
46
  export type CommunityHostOperation = {
45
47
  kind: 'remove-tree';
46
48
  path: typeof COMMUNITY_DATABASE_ROOT | typeof COMMUNITY_REHEARSAL_ROOT | typeof COMMUNITY_CREDENTIAL_PARENT;
49
+ } | {
50
+ kind: 'clear-firewall';
47
51
  } | {
48
52
  kind: 'write';
49
53
  path: string;
@@ -70,5 +74,6 @@ export declare function planCommunityRehearsalPrepare(request: Extract<Community
70
74
  }>): CommunityHostOperation[];
71
75
  /** Remove only the dedicated rehearsal units, credentials, release and data. */
72
76
  export declare function planCommunityRehearsalCleanup(): CommunityHostOperation[];
77
+ export declare function communityRehearsalFirewallRuleNumbers(status: string): number[];
73
78
  /** Execute only the dedicated four-node rehearsal operation selected by a typed request. */
74
79
  export declare function runCommunityRehearsalHost(request: CommunityRehearsalHostRequest): Promise<Record<string, unknown>>;
@@ -574,7 +574,9 @@ var COMMUNITY_CREDENTIAL_PARENT = "/etc/forgezero-rehearsal";
574
574
  var COMMUNITY_CREDENTIAL_ROOT = "/etc/forgezero-rehearsal/creds";
575
575
  var COMMUNITY_REHEARSAL_STARTER_PORT = 18528;
576
576
  var COMMUNITY_REHEARSAL_COORDINATOR_PORT = 18529;
577
+ var COMMUNITY_REHEARSAL_DATABASE_PORT_RANGE = "18528:18539";
577
578
  var COMMUNITY_REHEARSAL_API_PORT = 18787;
579
+ var COMMUNITY_REHEARSAL_FIREWALL_COMMENT = "fz-community-rehearsal";
578
580
  var RELEASE = /^[a-f0-9]{64}$/;
579
581
  var SAFE_NAME = /^[a-z][a-z0-9-]{0,62}$/;
580
582
  async function ensureCommunityRehearsalArango(execute = executeSoftwareOperation) {
@@ -703,10 +705,10 @@ User=forgezero
703
705
  Group=forgezero
704
706
  WorkingDirectory=${COMMUNITY_REHEARSAL_ROOT}/current
705
707
  LoadCredentialEncrypted=arangodb-jwt:${COMMUNITY_CREDENTIAL_ROOT}/arangodb-jwt.cred
706
- Environment=HOST=127.0.0.1
708
+ Environment=HOST=${node.address}
707
709
  Environment=PORT=${COMMUNITY_REHEARSAL_API_PORT}
708
710
  Environment=NODE_NAME=${node.name}
709
- Environment=ARANGO_URL=http://127.0.0.1:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}
711
+ Environment=ARANGO_URL=http://${node.address}:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}
710
712
  Environment=ARANGO_URLS=${urls}
711
713
  Environment=ARANGO_READ_PREFERRED_URLS=${readPreferred}
712
714
  Environment=ARANGO_READ_PREFERRED_FALLBACK=error
@@ -737,6 +739,41 @@ function planCommunityRehearsalPrepare(request) {
737
739
  { kind: "exec", argv: ["/usr/sbin/arangod", "--version"] },
738
740
  { kind: "exec", argv: ["/usr/bin/systemctl", "stop", "forgezero-community-api.service"], accepted: [0, 5] },
739
741
  { kind: "exec", argv: ["/usr/bin/systemctl", "stop", "forgezero-rehearsal-db.service"], accepted: [0, 5] },
742
+ { kind: "clear-firewall" },
743
+ ...topology.map(({ address }) => ({
744
+ kind: "exec",
745
+ argv: [
746
+ "/usr/sbin/ufw",
747
+ "allow",
748
+ "from",
749
+ address,
750
+ "to",
751
+ "any",
752
+ "port",
753
+ COMMUNITY_REHEARSAL_DATABASE_PORT_RANGE,
754
+ "proto",
755
+ "tcp",
756
+ "comment",
757
+ COMMUNITY_REHEARSAL_FIREWALL_COMMENT
758
+ ]
759
+ })),
760
+ ...topology.map(({ address }) => ({
761
+ kind: "exec",
762
+ argv: [
763
+ "/usr/sbin/ufw",
764
+ "allow",
765
+ "from",
766
+ address,
767
+ "to",
768
+ "any",
769
+ "port",
770
+ String(COMMUNITY_REHEARSAL_API_PORT),
771
+ "proto",
772
+ "tcp",
773
+ "comment",
774
+ COMMUNITY_REHEARSAL_FIREWALL_COMMENT
775
+ ]
776
+ })),
740
777
  { kind: "remove-tree", path: COMMUNITY_DATABASE_ROOT },
741
778
  { kind: "exec", argv: ["/usr/bin/install", "-d", "-m", "0700", "-o", "root", "-g", "root", COMMUNITY_CREDENTIAL_ROOT] },
742
779
  { kind: "exec", argv: ["/usr/bin/install", "-d", "-m", "0700", "-o", "arangodb", "-g", "arangodb", COMMUNITY_DATABASE_ROOT] },
@@ -765,6 +802,7 @@ function planCommunityRehearsalCleanup() {
765
802
  { kind: "remove-tree", path: COMMUNITY_DATABASE_ROOT },
766
803
  { kind: "remove-tree", path: COMMUNITY_REHEARSAL_ROOT },
767
804
  { kind: "remove-tree", path: COMMUNITY_CREDENTIAL_PARENT },
805
+ { kind: "clear-firewall" },
768
806
  { kind: "exec", argv: ["/usr/bin/systemctl", "daemon-reload"] },
769
807
  { kind: "exec", argv: ["/usr/bin/systemctl", "reset-failed", "forgezero-community-api.service", "forgezero-rehearsal-db.service"], accepted: [0, 1, 5] }
770
808
  ];
@@ -784,6 +822,8 @@ async function applyOperations(operations) {
784
822
  for (const operation of operations) {
785
823
  if (operation.kind === "remove-tree")
786
824
  rmSync2(operation.path, { recursive: true, force: true });
825
+ else if (operation.kind === "clear-firewall")
826
+ await clearCommunityRehearsalFirewall();
787
827
  else if (operation.kind === "write") {
788
828
  mkdirSync2(dirname2(operation.path), { recursive: true });
789
829
  writeFileSync2(operation.path, operation.content, { mode: operation.mode });
@@ -806,8 +846,28 @@ async function applyOperations(operations) {
806
846
  }
807
847
  }
808
848
  }
849
+ function communityRehearsalFirewallRuleNumbers(status) {
850
+ return status.split(/\r?\n/).flatMap((line) => {
851
+ if (!line.includes(`# ${COMMUNITY_REHEARSAL_FIREWALL_COMMENT}`))
852
+ return [];
853
+ const match = line.match(/^\[\s*(\d+)\]/);
854
+ return match ? [Number(match[1])] : [];
855
+ }).filter((number) => Number.isSafeInteger(number) && number > 0).sort((left, right) => right - left);
856
+ }
857
+ async function clearCommunityRehearsalFirewall() {
858
+ const status = await exec(["/usr/sbin/ufw", "status", "numbered"]);
859
+ if (status.exitCode !== 0)
860
+ throw new Error(`unable to inspect rehearsal firewall rules: ${status.output.trim()}`);
861
+ for (const number of communityRehearsalFirewallRuleNumbers(status.output)) {
862
+ const removed = await exec(["/usr/sbin/ufw", "--force", "delete", String(number)]);
863
+ if (removed.exitCode !== 0) {
864
+ throw new Error(`unable to remove rehearsal firewall rule ${number}: ${removed.output.trim()}`);
865
+ }
866
+ }
867
+ }
809
868
  var responseFor = async (request) => {
810
- const base = `http://127.0.0.1:${COMMUNITY_REHEARSAL_API_PORT}`;
869
+ const node = request.topology.find((entry) => entry.name === request.node);
870
+ const base = `http://${node.address}:${COMMUNITY_REHEARSAL_API_PORT}`;
811
871
  if (request.operation === "health")
812
872
  return fetch(`${base}/health`, { signal: AbortSignal.timeout(15000) });
813
873
  if (request.operation === "init")
@@ -869,7 +929,7 @@ async function runCommunityRehearsalHost(request) {
869
929
  }
870
930
  if (request.action === "database-ready" || request.action === "starter-ready" || request.action === "api-ready") {
871
931
  const starter = topology.find((entry) => entry.starter);
872
- const url = request.action === "database-ready" ? `http://127.0.0.1:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}/_api/version` : request.action === "starter-ready" ? `http://${starter.address}:${COMMUNITY_REHEARSAL_STARTER_PORT}/version` : `http://127.0.0.1:${COMMUNITY_REHEARSAL_API_PORT}/health`;
932
+ const url = request.action === "database-ready" ? `http://${node.address}:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}/_api/version` : request.action === "starter-ready" ? `http://${starter.address}:${COMMUNITY_REHEARSAL_STARTER_PORT}/version` : `http://${node.address}:${COMMUNITY_REHEARSAL_API_PORT}/health`;
873
933
  const response2 = await fetch(url, { signal: AbortSignal.timeout(2000) }).catch(() => {
874
934
  return;
875
935
  });
@@ -892,9 +952,12 @@ export {
892
952
  planCommunityRehearsalCleanup,
893
953
  parseCommunityRehearsalHostRequest,
894
954
  ensureCommunityRehearsalArango,
955
+ communityRehearsalFirewallRuleNumbers,
895
956
  COMMUNITY_REHEARSAL_VERSION,
896
957
  COMMUNITY_REHEARSAL_STARTER_PORT,
897
958
  COMMUNITY_REHEARSAL_ROOT,
959
+ COMMUNITY_REHEARSAL_FIREWALL_COMMENT,
960
+ COMMUNITY_REHEARSAL_DATABASE_PORT_RANGE,
898
961
  COMMUNITY_REHEARSAL_COORDINATOR_PORT,
899
962
  COMMUNITY_REHEARSAL_API_PORT,
900
963
  COMMUNITY_DATABASE_ROOT,
package/dist/fz-agent.js CHANGED
@@ -9640,7 +9640,7 @@ async function writeAndCloseProcessInput(input, value) {
9640
9640
  }
9641
9641
 
9642
9642
  // src/version.ts
9643
- var VERSION2 = "0.1.122";
9643
+ var VERSION2 = "0.1.124";
9644
9644
 
9645
9645
  // src/ssh-bootstrap.ts
9646
9646
  class SshBootstrapError extends Error {
@@ -17122,7 +17122,9 @@ var COMMUNITY_CREDENTIAL_PARENT = "/etc/forgezero-rehearsal";
17122
17122
  var COMMUNITY_CREDENTIAL_ROOT = "/etc/forgezero-rehearsal/creds";
17123
17123
  var COMMUNITY_REHEARSAL_STARTER_PORT = 18528;
17124
17124
  var COMMUNITY_REHEARSAL_COORDINATOR_PORT = 18529;
17125
+ var COMMUNITY_REHEARSAL_DATABASE_PORT_RANGE = "18528:18539";
17125
17126
  var COMMUNITY_REHEARSAL_API_PORT = 18787;
17127
+ var COMMUNITY_REHEARSAL_FIREWALL_COMMENT = "fz-community-rehearsal";
17126
17128
  var RELEASE = /^[a-f0-9]{64}$/;
17127
17129
  var SAFE_NAME2 = /^[a-z][a-z0-9-]{0,62}$/;
17128
17130
  async function ensureCommunityRehearsalArango(execute3 = executeSoftwareOperation) {
@@ -17251,10 +17253,10 @@ User=forgezero
17251
17253
  Group=forgezero
17252
17254
  WorkingDirectory=${COMMUNITY_REHEARSAL_ROOT}/current
17253
17255
  LoadCredentialEncrypted=arangodb-jwt:${COMMUNITY_CREDENTIAL_ROOT}/arangodb-jwt.cred
17254
- Environment=HOST=127.0.0.1
17256
+ Environment=HOST=${node.address}
17255
17257
  Environment=PORT=${COMMUNITY_REHEARSAL_API_PORT}
17256
17258
  Environment=NODE_NAME=${node.name}
17257
- Environment=ARANGO_URL=http://127.0.0.1:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}
17259
+ Environment=ARANGO_URL=http://${node.address}:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}
17258
17260
  Environment=ARANGO_URLS=${urls}
17259
17261
  Environment=ARANGO_READ_PREFERRED_URLS=${readPreferred}
17260
17262
  Environment=ARANGO_READ_PREFERRED_FALLBACK=error
@@ -17285,6 +17287,41 @@ function planCommunityRehearsalPrepare(request) {
17285
17287
  { kind: "exec", argv: ["/usr/sbin/arangod", "--version"] },
17286
17288
  { kind: "exec", argv: ["/usr/bin/systemctl", "stop", "forgezero-community-api.service"], accepted: [0, 5] },
17287
17289
  { kind: "exec", argv: ["/usr/bin/systemctl", "stop", "forgezero-rehearsal-db.service"], accepted: [0, 5] },
17290
+ { kind: "clear-firewall" },
17291
+ ...topology.map(({ address }) => ({
17292
+ kind: "exec",
17293
+ argv: [
17294
+ "/usr/sbin/ufw",
17295
+ "allow",
17296
+ "from",
17297
+ address,
17298
+ "to",
17299
+ "any",
17300
+ "port",
17301
+ COMMUNITY_REHEARSAL_DATABASE_PORT_RANGE,
17302
+ "proto",
17303
+ "tcp",
17304
+ "comment",
17305
+ COMMUNITY_REHEARSAL_FIREWALL_COMMENT
17306
+ ]
17307
+ })),
17308
+ ...topology.map(({ address }) => ({
17309
+ kind: "exec",
17310
+ argv: [
17311
+ "/usr/sbin/ufw",
17312
+ "allow",
17313
+ "from",
17314
+ address,
17315
+ "to",
17316
+ "any",
17317
+ "port",
17318
+ String(COMMUNITY_REHEARSAL_API_PORT),
17319
+ "proto",
17320
+ "tcp",
17321
+ "comment",
17322
+ COMMUNITY_REHEARSAL_FIREWALL_COMMENT
17323
+ ]
17324
+ })),
17288
17325
  { kind: "remove-tree", path: COMMUNITY_DATABASE_ROOT },
17289
17326
  { kind: "exec", argv: ["/usr/bin/install", "-d", "-m", "0700", "-o", "root", "-g", "root", COMMUNITY_CREDENTIAL_ROOT] },
17290
17327
  { kind: "exec", argv: ["/usr/bin/install", "-d", "-m", "0700", "-o", "arangodb", "-g", "arangodb", COMMUNITY_DATABASE_ROOT] },
@@ -17313,6 +17350,7 @@ function planCommunityRehearsalCleanup() {
17313
17350
  { kind: "remove-tree", path: COMMUNITY_DATABASE_ROOT },
17314
17351
  { kind: "remove-tree", path: COMMUNITY_REHEARSAL_ROOT },
17315
17352
  { kind: "remove-tree", path: COMMUNITY_CREDENTIAL_PARENT },
17353
+ { kind: "clear-firewall" },
17316
17354
  { kind: "exec", argv: ["/usr/bin/systemctl", "daemon-reload"] },
17317
17355
  { kind: "exec", argv: ["/usr/bin/systemctl", "reset-failed", "forgezero-community-api.service", "forgezero-rehearsal-db.service"], accepted: [0, 1, 5] }
17318
17356
  ];
@@ -17332,6 +17370,8 @@ async function applyOperations(operations) {
17332
17370
  for (const operation of operations) {
17333
17371
  if (operation.kind === "remove-tree")
17334
17372
  rmSync13(operation.path, { recursive: true, force: true });
17373
+ else if (operation.kind === "clear-firewall")
17374
+ await clearCommunityRehearsalFirewall();
17335
17375
  else if (operation.kind === "write") {
17336
17376
  mkdirSync17(dirname15(operation.path), { recursive: true });
17337
17377
  writeFileSync17(operation.path, operation.content, { mode: operation.mode });
@@ -17354,8 +17394,28 @@ async function applyOperations(operations) {
17354
17394
  }
17355
17395
  }
17356
17396
  }
17397
+ function communityRehearsalFirewallRuleNumbers(status) {
17398
+ return status.split(/\r?\n/).flatMap((line) => {
17399
+ if (!line.includes(`# ${COMMUNITY_REHEARSAL_FIREWALL_COMMENT}`))
17400
+ return [];
17401
+ const match = line.match(/^\[\s*(\d+)\]/);
17402
+ return match ? [Number(match[1])] : [];
17403
+ }).filter((number2) => Number.isSafeInteger(number2) && number2 > 0).sort((left, right) => right - left);
17404
+ }
17405
+ async function clearCommunityRehearsalFirewall() {
17406
+ const status = await exec(["/usr/sbin/ufw", "status", "numbered"]);
17407
+ if (status.exitCode !== 0)
17408
+ throw new Error(`unable to inspect rehearsal firewall rules: ${status.output.trim()}`);
17409
+ for (const number2 of communityRehearsalFirewallRuleNumbers(status.output)) {
17410
+ const removed = await exec(["/usr/sbin/ufw", "--force", "delete", String(number2)]);
17411
+ if (removed.exitCode !== 0) {
17412
+ throw new Error(`unable to remove rehearsal firewall rule ${number2}: ${removed.output.trim()}`);
17413
+ }
17414
+ }
17415
+ }
17357
17416
  var responseFor = async (request) => {
17358
- const base = `http://127.0.0.1:${COMMUNITY_REHEARSAL_API_PORT}`;
17417
+ const node = request.topology.find((entry) => entry.name === request.node);
17418
+ const base = `http://${node.address}:${COMMUNITY_REHEARSAL_API_PORT}`;
17359
17419
  if (request.operation === "health")
17360
17420
  return fetch(`${base}/health`, { signal: AbortSignal.timeout(15000) });
17361
17421
  if (request.operation === "init")
@@ -17417,7 +17477,7 @@ async function runCommunityRehearsalHost(request) {
17417
17477
  }
17418
17478
  if (request.action === "database-ready" || request.action === "starter-ready" || request.action === "api-ready") {
17419
17479
  const starter = topology.find((entry) => entry.starter);
17420
- const url = request.action === "database-ready" ? `http://127.0.0.1:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}/_api/version` : request.action === "starter-ready" ? `http://${starter.address}:${COMMUNITY_REHEARSAL_STARTER_PORT}/version` : `http://127.0.0.1:${COMMUNITY_REHEARSAL_API_PORT}/health`;
17480
+ const url = request.action === "database-ready" ? `http://${node.address}:${COMMUNITY_REHEARSAL_COORDINATOR_PORT}/_api/version` : request.action === "starter-ready" ? `http://${starter.address}:${COMMUNITY_REHEARSAL_STARTER_PORT}/version` : `http://${node.address}:${COMMUNITY_REHEARSAL_API_PORT}/health`;
17421
17481
  const response2 = await fetch(url, { signal: AbortSignal.timeout(2000) }).catch(() => {
17422
17482
  return;
17423
17483
  });
package/dist/fz.js CHANGED
@@ -4844,7 +4844,7 @@ var UPDATE_RETRY_BASE_MS = 5 * 60000;
4844
4844
  var UPDATE_RETRY_MAX_MS = 24 * 60 * 60000;
4845
4845
 
4846
4846
  // src/version.ts
4847
- var VERSION2 = "0.1.122";
4847
+ var VERSION2 = "0.1.124";
4848
4848
 
4849
4849
  // src/software.ts
4850
4850
  var PINNED_BUN_VERSION = "1.3.14";
@@ -366,7 +366,7 @@ function systemdAgentEgressDirectives(loopbackTcpPorts = []) {
366
366
  }
367
367
 
368
368
  // src/version.ts
369
- var VERSION = "0.1.122";
369
+ var VERSION = "0.1.124";
370
370
 
371
371
  // src/otel-collector.ts
372
372
  var FORGEZERO_OTEL_COLLECTOR_UNIT = "forgezero-otel-collector.service";
@@ -1460,7 +1460,7 @@ var UPDATE_RETRY_BASE_MS = 5 * 60000;
1460
1460
  var UPDATE_RETRY_MAX_MS = 24 * 60 * 60000;
1461
1461
 
1462
1462
  // src/version.ts
1463
- var VERSION = "0.1.122";
1463
+ var VERSION = "0.1.124";
1464
1464
 
1465
1465
  // src/software.ts
1466
1466
  var PINNED_BUN_VERSION = "1.3.14";
@@ -3020,7 +3020,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
3020
3020
  }
3021
3021
 
3022
3022
  // src/version.ts
3023
- var VERSION3 = "0.1.122";
3023
+ var VERSION3 = "0.1.124";
3024
3024
 
3025
3025
  // src/egress-policy.ts
3026
3026
  import { realpathSync as realpathSync3 } from "node:fs";
package/dist/provision.js CHANGED
@@ -3020,7 +3020,7 @@ function requestSoftware(requirements, socketPath = DEFAULT_SOFTWARE_HELPER_SOCK
3020
3020
  }
3021
3021
 
3022
3022
  // src/version.ts
3023
- var VERSION3 = "0.1.122";
3023
+ var VERSION3 = "0.1.124";
3024
3024
 
3025
3025
  // src/egress-policy.ts
3026
3026
  import { realpathSync as realpathSync3 } from "node:fs";
package/dist/version.d.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  /** One package version shared by both public binaries. Pinned to package.json by tests. */
2
- export declare const VERSION = "0.1.122";
2
+ export declare const VERSION = "0.1.124";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@forgezero/agent",
3
- "version": "0.1.122",
3
+ "version": "0.1.124",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "check": "tsc --noEmit",