@forgezero/agent 0.1.23 → 0.1.24

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.
@@ -56,6 +56,10 @@ export interface InstallOptions {
56
56
  warpOrganization?: string;
57
57
  warpClientIdCredentialPath?: string;
58
58
  warpClientSecretCredentialPath?: string;
59
+ cloudflareAccountId?: string;
60
+ cloudflareTunnelId?: string;
61
+ cloudflareVirtualNetworkId?: string;
62
+ cloudflareWarpPolicyId?: string;
59
63
  binPath?: string;
60
64
  sourceBinPath?: string;
61
65
  user?: string;
package/dist/fz-agent.js CHANGED
@@ -1158,6 +1158,26 @@ import {
1158
1158
  writeFileSync as writeFileSync2
1159
1159
  } from "fs";
1160
1160
  import { dirname as dirname2 } from "path";
1161
+ function privateNetworkAttachmentFromEnvironment(env = process.env) {
1162
+ const values = {
1163
+ accountId: env.FZ_CF_ACCOUNT_ID?.trim() ?? "",
1164
+ tunnelId: env.FZ_CF_TUNNEL_ID?.trim() ?? "",
1165
+ virtualNetworkId: env.FZ_CF_VIRTUAL_NETWORK_ID?.trim() ?? "",
1166
+ warpPolicyId: env.FZ_CF_WARP_POLICY_ID?.trim() ?? ""
1167
+ };
1168
+ const supplied = [values.accountId, values.tunnelId, values.virtualNetworkId, values.warpPolicyId].some(Boolean);
1169
+ if (!supplied)
1170
+ return;
1171
+ if (!values.accountId || !values.tunnelId || !values.warpPolicyId) {
1172
+ throw new Error("private-network attachment requires account, Tunnel and WARP policy ids");
1173
+ }
1174
+ return {
1175
+ accountId: values.accountId,
1176
+ tunnelId: values.tunnelId,
1177
+ ...values.virtualNetworkId ? { virtualNetworkId: values.virtualNetworkId } : {},
1178
+ warpPolicyId: values.warpPolicyId
1179
+ };
1180
+ }
1161
1181
  var validBinding = (value, expectedNodeKey) => {
1162
1182
  if (!value || typeof value !== "object")
1163
1183
  return false;
@@ -1204,6 +1224,7 @@ async function enrolGuestIdentity(options) {
1204
1224
  token,
1205
1225
  label: options.label,
1206
1226
  gitDeployPublicKey: options.gitDeployPublicKey,
1227
+ privateNetworkAttachment: options.privateNetworkAttachment,
1207
1228
  publicKeys: {
1208
1229
  ed25519: options.keys.ed25519.publicKey,
1209
1230
  mlDsa: options.keys.mlDsa.publicKey
@@ -2919,7 +2940,7 @@ function materializeWarpMdm(options) {
2919
2940
  }
2920
2941
 
2921
2942
  // src/version.ts
2922
- var VERSION = "0.1.23";
2943
+ var VERSION = "0.1.24";
2923
2944
 
2924
2945
  // src/index.ts
2925
2946
  function loadOrCreateSeed(path) {
@@ -3062,7 +3083,8 @@ if (import.meta.main) {
3062
3083
  nodeKey: nodeKey2,
3063
3084
  keys: keys2,
3064
3085
  label: process.env.FZ_NODE_LABEL,
3065
- gitDeployPublicKey: process.env.FZ_GIT_PUBLIC_KEY_FILE ? readFileSync5(process.env.FZ_GIT_PUBLIC_KEY_FILE, "utf8").trim() : undefined
3086
+ gitDeployPublicKey: process.env.FZ_GIT_PUBLIC_KEY_FILE ? readFileSync5(process.env.FZ_GIT_PUBLIC_KEY_FILE, "utf8").trim() : undefined,
3087
+ privateNetworkAttachment: privateNetworkAttachmentFromEnvironment()
3066
3088
  });
3067
3089
  console.log(`[agent] enrolled ${binding2.computeReference} in project ${binding2.projectKey}/${binding2.environmentKey}`);
3068
3090
  process.exit(0);
@@ -3280,7 +3302,8 @@ if (import.meta.main) {
3280
3302
  nodeKey,
3281
3303
  keys,
3282
3304
  label: process.env.FZ_NODE_LABEL,
3283
- gitDeployPublicKey: process.env.FZ_GIT_PUBLIC_KEY_FILE ? readFileSync5(process.env.FZ_GIT_PUBLIC_KEY_FILE, "utf8").trim() : undefined
3305
+ gitDeployPublicKey: process.env.FZ_GIT_PUBLIC_KEY_FILE ? readFileSync5(process.env.FZ_GIT_PUBLIC_KEY_FILE, "utf8").trim() : undefined,
3306
+ privateNetworkAttachment: privateNetworkAttachmentFromEnvironment()
3284
3307
  });
3285
3308
  console.log(`[agent] enrolled ${binding.computeReference} in project ${binding.projectKey}/${binding.environmentKey}`);
3286
3309
  }
package/dist/fz.js CHANGED
@@ -259,6 +259,16 @@ function agentEnrolmentUnit(options) {
259
259
  ` : "";
260
260
  const gitPublicKey = options.gitPublicKeyPath ? `Environment=FZ_GIT_PUBLIC_KEY_FILE=${options.gitPublicKeyPath}
261
261
  ` : "";
262
+ const networkAttachment = [
263
+ options.cloudflareAccountId ? `Environment=FZ_CF_ACCOUNT_ID=${options.cloudflareAccountId}
264
+ ` : "",
265
+ options.cloudflareTunnelId ? `Environment=FZ_CF_TUNNEL_ID=${options.cloudflareTunnelId}
266
+ ` : "",
267
+ options.cloudflareVirtualNetworkId ? `Environment=FZ_CF_VIRTUAL_NETWORK_ID=${options.cloudflareVirtualNetworkId}
268
+ ` : "",
269
+ options.cloudflareWarpPolicyId ? `Environment=FZ_CF_WARP_POLICY_ID=${options.cloudflareWarpPolicyId}
270
+ ` : ""
271
+ ].join("");
262
272
  const stateDir = options.enrolStatePath.replace(/\/[^/]+$/, "");
263
273
  return `[Unit]
264
274
  Description=Bind this machine to its ForgeZero compute
@@ -277,7 +287,7 @@ Environment=FZ_SEED_CREDENTIAL=agent-seed
277
287
  Environment=FZ_ENROL_TOKEN_CREDENTIAL=enrol-token
278
288
  Environment=FZ_ENROL_STATE_FILE=${options.enrolStatePath}
279
289
  Environment=FZ_API=${options.apiUrl}
280
- ${label}${gitPublicKey}ExecStart=${bin} enrol
290
+ ${label}${gitPublicKey}${networkAttachment}ExecStart=${bin} enrol
281
291
  # A '+' fixed command runs as root solely to remove the host-bound one-time
282
292
  # ciphertext. Tenant code and the agent never receive a privilege boundary.
283
293
  ExecStartPost=+/usr/bin/rm -f ${options.enrolTokenCredentialPath}
@@ -355,6 +365,21 @@ function agentUnit(options) {
355
365
  const warpEnabled = warpValues.every(Boolean);
356
366
  if (warpValues.some(Boolean) && !warpEnabled)
357
367
  throw new Error("WARP configuration must be supplied together");
368
+ const networkAttachmentValues = [
369
+ options.cloudflareAccountId,
370
+ options.cloudflareTunnelId,
371
+ options.cloudflareVirtualNetworkId,
372
+ options.cloudflareWarpPolicyId
373
+ ];
374
+ if (networkAttachmentValues.some(Boolean)) {
375
+ if (!options.cloudflareAccountId || !options.cloudflareTunnelId || !options.cloudflareWarpPolicyId) {
376
+ throw new Error("private-network attachment requires account, Tunnel and WARP policy ids");
377
+ }
378
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
379
+ if (!/^[a-f0-9]{32}$/i.test(options.cloudflareAccountId) || !uuid.test(options.cloudflareTunnelId) || options.cloudflareVirtualNetworkId && !uuid.test(options.cloudflareVirtualNetworkId) || !/^[A-Za-z0-9-]{1,64}$/.test(options.cloudflareWarpPolicyId)) {
380
+ throw new Error("private-network attachment coordinates are invalid");
381
+ }
382
+ }
358
383
  const enrolmentEnabled = Boolean(options.enrolTokenCredentialPath && options.enrolStatePath);
359
384
  const deploymentEnvironment = options.deploymentEnvironment ?? {};
360
385
  const deploymentCredentials = options.deploymentCredentials ?? {};
@@ -941,7 +966,7 @@ async function resolveIdentity(selector, socketPath) {
941
966
  }
942
967
 
943
968
  // src/version.ts
944
- var VERSION = "0.1.23";
969
+ var VERSION = "0.1.24";
945
970
 
946
971
  // src/cli/index.ts
947
972
  var DEFAULT_MODE = THRESHOLD_MODES[0].id;
@@ -1170,6 +1195,10 @@ async function cmdAgent(options, args) {
1170
1195
  warpOrganization: process.env.FZ_WARP_ORGANIZATION,
1171
1196
  warpClientIdCredentialPath: process.env.FZ_WARP_CLIENT_ID_CREDENTIAL_PATH,
1172
1197
  warpClientSecretCredentialPath: process.env.FZ_WARP_CLIENT_SECRET_CREDENTIAL_PATH,
1198
+ cloudflareAccountId: process.env.FZ_CF_ACCOUNT_ID,
1199
+ cloudflareTunnelId: process.env.FZ_CF_TUNNEL_ID,
1200
+ cloudflareVirtualNetworkId: process.env.FZ_CF_VIRTUAL_NETWORK_ID,
1201
+ cloudflareWarpPolicyId: process.env.FZ_CF_WARP_POLICY_ID,
1173
1202
  ...options.enrol ? {
1174
1203
  pullDeployments: true,
1175
1204
  enrolTokenSourcePath,
@@ -7,6 +7,14 @@ export interface GuestBinding {
7
7
  realm: 'platform' | 'tenant';
8
8
  tenantSlug?: string;
9
9
  }
10
+ export interface GuestPrivateNetworkAttachment {
11
+ accountId: string;
12
+ tunnelId: string;
13
+ virtualNetworkId?: string;
14
+ warpPolicyId: string;
15
+ }
16
+ /** Fail closed when setup supplied only part of a cross-network attachment. */
17
+ export declare function privateNetworkAttachmentFromEnvironment(env?: Record<string, string | undefined>): GuestPrivateNetworkAttachment | undefined;
10
18
  export interface GuestEnrolmentOptions {
11
19
  apiUrl: string;
12
20
  /** Already-unsealed systemd credential. Production uses this path. */
@@ -21,6 +29,7 @@ export interface GuestEnrolmentOptions {
21
29
  keys: NodeKeyPair;
22
30
  label?: string;
23
31
  gitDeployPublicKey?: string;
32
+ privateNetworkAttachment?: GuestPrivateNetworkAttachment;
24
33
  fetch?: (input: URL, init: RequestInit) => Promise<Response>;
25
34
  requestTimeoutMs?: number;
26
35
  }
@@ -68,6 +68,26 @@ async function postSignedNode(options, path, body) {
68
68
  }
69
69
 
70
70
  // src/guest-enrolment.ts
71
+ function privateNetworkAttachmentFromEnvironment(env = process.env) {
72
+ const values = {
73
+ accountId: env.FZ_CF_ACCOUNT_ID?.trim() ?? "",
74
+ tunnelId: env.FZ_CF_TUNNEL_ID?.trim() ?? "",
75
+ virtualNetworkId: env.FZ_CF_VIRTUAL_NETWORK_ID?.trim() ?? "",
76
+ warpPolicyId: env.FZ_CF_WARP_POLICY_ID?.trim() ?? ""
77
+ };
78
+ const supplied = [values.accountId, values.tunnelId, values.virtualNetworkId, values.warpPolicyId].some(Boolean);
79
+ if (!supplied)
80
+ return;
81
+ if (!values.accountId || !values.tunnelId || !values.warpPolicyId) {
82
+ throw new Error("private-network attachment requires account, Tunnel and WARP policy ids");
83
+ }
84
+ return {
85
+ accountId: values.accountId,
86
+ tunnelId: values.tunnelId,
87
+ ...values.virtualNetworkId ? { virtualNetworkId: values.virtualNetworkId } : {},
88
+ warpPolicyId: values.warpPolicyId
89
+ };
90
+ }
71
91
  var validBinding = (value, expectedNodeKey) => {
72
92
  if (!value || typeof value !== "object")
73
93
  return false;
@@ -114,6 +134,7 @@ async function enrolGuestIdentity(options) {
114
134
  token,
115
135
  label: options.label,
116
136
  gitDeployPublicKey: options.gitDeployPublicKey,
137
+ privateNetworkAttachment: options.privateNetworkAttachment,
117
138
  publicKeys: {
118
139
  ed25519: options.keys.ed25519.publicKey,
119
140
  mlDsa: options.keys.mlDsa.publicKey
@@ -138,6 +159,7 @@ async function enrolGuestIdentity(options) {
138
159
  return binding;
139
160
  }
140
161
  export {
162
+ privateNetworkAttachmentFromEnvironment,
141
163
  loadGuestBinding,
142
164
  enrolGuestIdentity
143
165
  };
@@ -101,6 +101,11 @@ export interface UnitOptions {
101
101
  warpOrganization?: string;
102
102
  warpClientIdCredentialPath?: string;
103
103
  warpClientSecretCredentialPath?: string;
104
+ /** Non-secret coordinates bound through the PQ-signed enrolment request. */
105
+ cloudflareAccountId?: string;
106
+ cloudflareTunnelId?: string;
107
+ cloudflareVirtualNetworkId?: string;
108
+ cloudflareWarpPolicyId?: string;
104
109
  /** Where `fz-agent` ended up. `bun add -g` puts it on PATH. */
105
110
  binPath?: string;
106
111
  /** Package-owned binary copied to binPath before hardened units start. */
package/dist/provision.js CHANGED
@@ -151,6 +151,16 @@ function agentEnrolmentUnit(options) {
151
151
  ` : "";
152
152
  const gitPublicKey = options.gitPublicKeyPath ? `Environment=FZ_GIT_PUBLIC_KEY_FILE=${options.gitPublicKeyPath}
153
153
  ` : "";
154
+ const networkAttachment = [
155
+ options.cloudflareAccountId ? `Environment=FZ_CF_ACCOUNT_ID=${options.cloudflareAccountId}
156
+ ` : "",
157
+ options.cloudflareTunnelId ? `Environment=FZ_CF_TUNNEL_ID=${options.cloudflareTunnelId}
158
+ ` : "",
159
+ options.cloudflareVirtualNetworkId ? `Environment=FZ_CF_VIRTUAL_NETWORK_ID=${options.cloudflareVirtualNetworkId}
160
+ ` : "",
161
+ options.cloudflareWarpPolicyId ? `Environment=FZ_CF_WARP_POLICY_ID=${options.cloudflareWarpPolicyId}
162
+ ` : ""
163
+ ].join("");
154
164
  const stateDir = options.enrolStatePath.replace(/\/[^/]+$/, "");
155
165
  return `[Unit]
156
166
  Description=Bind this machine to its ForgeZero compute
@@ -169,7 +179,7 @@ Environment=FZ_SEED_CREDENTIAL=agent-seed
169
179
  Environment=FZ_ENROL_TOKEN_CREDENTIAL=enrol-token
170
180
  Environment=FZ_ENROL_STATE_FILE=${options.enrolStatePath}
171
181
  Environment=FZ_API=${options.apiUrl}
172
- ${label}${gitPublicKey}ExecStart=${bin} enrol
182
+ ${label}${gitPublicKey}${networkAttachment}ExecStart=${bin} enrol
173
183
  # A '+' fixed command runs as root solely to remove the host-bound one-time
174
184
  # ciphertext. Tenant code and the agent never receive a privilege boundary.
175
185
  ExecStartPost=+/usr/bin/rm -f ${options.enrolTokenCredentialPath}
@@ -247,6 +257,21 @@ function agentUnit(options) {
247
257
  const warpEnabled = warpValues.every(Boolean);
248
258
  if (warpValues.some(Boolean) && !warpEnabled)
249
259
  throw new Error("WARP configuration must be supplied together");
260
+ const networkAttachmentValues = [
261
+ options.cloudflareAccountId,
262
+ options.cloudflareTunnelId,
263
+ options.cloudflareVirtualNetworkId,
264
+ options.cloudflareWarpPolicyId
265
+ ];
266
+ if (networkAttachmentValues.some(Boolean)) {
267
+ if (!options.cloudflareAccountId || !options.cloudflareTunnelId || !options.cloudflareWarpPolicyId) {
268
+ throw new Error("private-network attachment requires account, Tunnel and WARP policy ids");
269
+ }
270
+ const uuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
271
+ if (!/^[a-f0-9]{32}$/i.test(options.cloudflareAccountId) || !uuid.test(options.cloudflareTunnelId) || options.cloudflareVirtualNetworkId && !uuid.test(options.cloudflareVirtualNetworkId) || !/^[A-Za-z0-9-]{1,64}$/.test(options.cloudflareWarpPolicyId)) {
272
+ throw new Error("private-network attachment coordinates are invalid");
273
+ }
274
+ }
250
275
  const enrolmentEnabled = Boolean(options.enrolTokenCredentialPath && options.enrolStatePath);
251
276
  const deploymentEnvironment = options.deploymentEnvironment ?? {};
252
277
  const deploymentCredentials = options.deploymentCredentials ?? {};
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.23";
2
+ export declare const VERSION = "0.1.24";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "//": "Publishing happens from an operator's machine, not CI \u2014 CLAUDE.md records that the absence of CI is deliberate. npm's `provenance` attests a tarball was built by a recognised CI provider from a named commit, so it cannot be produced here: it was set, and the first publish failed with `Automatic provenance generation not supported for provider: null`. A setting that can never be satisfied is worse than none, because it reads as a guarantee nobody is getting. Restore it the day this publishes from CI, and not before.",
3
3
  "name": "@forgezero/agent",
4
- "version": "0.1.23",
4
+ "version": "0.1.24",
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "check": "tsc --noEmit",