@forgezero/agent 0.1.88 → 0.1.90

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.
Files changed (40) hide show
  1. package/README.md +23 -9
  2. package/dist/agent-heartbeat.d.ts +3 -0
  3. package/dist/agent-heartbeat.js +2 -1
  4. package/dist/bootstrap.d.ts +8 -1
  5. package/dist/bootstrap.js +241 -62
  6. package/dist/capacity-calibration.d.ts +35 -5
  7. package/dist/capacity-calibration.js +66 -22
  8. package/dist/cli/agent-install.d.ts +3 -0
  9. package/dist/community-rehearsal-host.js +7 -2
  10. package/dist/control.d.ts +3 -1
  11. package/dist/definition.js +83 -28
  12. package/dist/deploy-file.js +83 -28
  13. package/dist/deployment.d.ts +5 -0
  14. package/dist/egress-policy.d.ts +4 -0
  15. package/dist/fz-agent.js +450 -158
  16. package/dist/fz.js +429 -138
  17. package/dist/host-maintenance.js +1 -1
  18. package/dist/index.d.ts +7 -0
  19. package/dist/metal-bootstrap.js +1 -1
  20. package/dist/metal-helper-socket.js +7 -2
  21. package/dist/metal-provision.js +7 -2
  22. package/dist/migration-pull.d.ts +1 -0
  23. package/dist/migration-pull.js +4 -0
  24. package/dist/operator-bootstrap.d.ts +12 -0
  25. package/dist/operator-bootstrap.js +385 -72
  26. package/dist/platform-bootstrap-runtime.d.ts +1 -0
  27. package/dist/platform-bootstrap-runtime.js +47 -8
  28. package/dist/platform-fleet-verification.js +273 -95
  29. package/dist/platform-genesis.js +7 -2
  30. package/dist/platform-launch-profile.d.ts +1 -0
  31. package/dist/provision.d.ts +5 -1
  32. package/dist/provision.js +192 -75
  33. package/dist/recovery-host.js +1 -1
  34. package/dist/software-helper.js +144 -48
  35. package/dist/software.js +7 -2
  36. package/dist/ssh-bootstrap.d.ts +1 -0
  37. package/dist/ubuntu.js +7 -2
  38. package/dist/version.d.ts +1 -1
  39. package/package.json +1 -1
  40. package/schema/deploy-v3.json +5 -2
@@ -175,6 +175,7 @@ export interface PlatformActivationCommandResult {
175
175
  output: string;
176
176
  }
177
177
  export type PlatformActivationExec = (argv: readonly string[]) => Promise<PlatformActivationCommandResult>;
178
+ export declare const assertReleaseLinksContained: (path: string) => void;
178
179
  /** Agent-native blue/green activation with health and nginx rollback. */
179
180
  export declare function activatePlatformRelease(config: PlatformActivationConfig, requestedRelease: string, options?: {
180
181
  exec?: PlatformActivationExec;
@@ -355,7 +355,12 @@ async function executeSoftwareOperation(operation) {
355
355
  }
356
356
  if (software === "nginx") {
357
357
  const binary = await run(["/usr/sbin/nginx", "-v"]);
358
- return binary.exitCode === 0 ? run(["/usr/bin/systemctl", "is-active", "--quiet", "nginx.service"]) : binary;
358
+ if (binary.exitCode !== 0)
359
+ return binary;
360
+ if (!existsSync("/usr/lib/nginx/modules/ngx_http_headers_more_filter_module.so")) {
361
+ return { exitCode: 1, output: "Nginx response-header suppression module is unavailable" };
362
+ }
363
+ return run(["/usr/bin/systemctl", "is-active", "--quiet", "nginx.service"]);
359
364
  }
360
365
  if (software === "arangodb") {
361
366
  const binary = await run(["/usr/sbin/arangod", "--version"]);
@@ -387,7 +392,7 @@ async function executeSoftwareOperation(operation) {
387
392
  }
388
393
  if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client" || software === "git") {
389
394
  const packageName = software === "openssh-client" ? "openssh-client" : software === "docker" ? "docker.io" : software;
390
- const installed = await aptInstall(packageName);
395
+ const installed = software === "nginx" ? await aptInstallMany(["nginx", "libnginx-mod-http-headers-more-filter"]) : await aptInstall(packageName);
391
396
  if (installed.exitCode !== 0 || software !== "nginx" && software !== "docker")
392
397
  return installed;
393
398
  if (software === "docker") {
@@ -1050,12 +1055,26 @@ map $limit_conn_status $forgezero_retry_after { default ''; REJECTED 1; REJECTED
1050
1055
  server {
1051
1056
  listen 127.0.0.1:${input.publicPort};
1052
1057
  server_name _;
1058
+ server_tokens off;
1059
+ more_clear_headers Server X-Powered-By;
1053
1060
  limit_conn forgezero_admission ${concurrencyLimit};
1054
1061
  limit_conn_status 503;
1055
1062
  add_header Retry-After $forgezero_retry_after always;
1056
- location ^~ /api/ { proxy_pass http://forgezero; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $forgezero_connection; proxy_read_timeout 3600s; }
1057
- location ^~ /v1/ { proxy_pass http://forgezero; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Proto https; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection $forgezero_connection; proxy_read_timeout 3600s; }
1058
- location / { return 404; }
1063
+ error_page 400 403 404 405 408 413 414 429 500 502 503 504 = @transport_failure;
1064
+ location @transport_failure { internal; return 444; }
1065
+ location / {
1066
+ proxy_pass http://forgezero;
1067
+ proxy_http_version 1.1;
1068
+ proxy_intercept_errors off;
1069
+ proxy_hide_header Server;
1070
+ proxy_hide_header X-Powered-By;
1071
+ proxy_set_header Host $host;
1072
+ proxy_set_header X-Forwarded-Proto https;
1073
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
1074
+ proxy_set_header Upgrade $http_upgrade;
1075
+ proxy_set_header Connection $forgezero_connection;
1076
+ proxy_read_timeout 3600s;
1077
+ }
1059
1078
  }
1060
1079
  `
1061
1080
  };
@@ -1128,11 +1147,29 @@ var replaceLink = (path2, target) => {
1128
1147
  symlinkSync2(target, pending);
1129
1148
  renameSync2(pending, path2);
1130
1149
  };
1150
+ var assertReleaseLinksContained = (path2) => {
1151
+ const root = realpathSync(path2);
1152
+ const visit = (current2) => {
1153
+ const metadata = lstatSync(current2);
1154
+ if (metadata.isSymbolicLink()) {
1155
+ const target = realpathSync(current2);
1156
+ if (target !== root && !target.startsWith(`${root}/`)) {
1157
+ throw new Error("release contains a symbolic link outside its immutable root");
1158
+ }
1159
+ return;
1160
+ }
1161
+ if (metadata.isDirectory())
1162
+ for (const name of readdirSync(current2))
1163
+ visit(join2(current2, name));
1164
+ };
1165
+ visit(root);
1166
+ };
1131
1167
  var secureRelease = (path2, uid, gid) => {
1168
+ assertReleaseLinksContained(path2);
1132
1169
  const visit = (current2) => {
1133
1170
  const metadata = lstatSync(current2);
1134
1171
  if (metadata.isSymbolicLink())
1135
- throw new Error("release contains a symbolic link");
1172
+ return;
1136
1173
  chownSync(current2, uid, gid);
1137
1174
  chmodSync2(current2, metadata.isDirectory() ? 365 : 292);
1138
1175
  if (metadata.isDirectory())
@@ -1158,7 +1195,7 @@ async function activatePlatformRelease(config, requestedRelease, options = {}) {
1158
1195
  const sleep = options.sleep ?? Bun.sleep;
1159
1196
  const slots = join2(normalized.root, "slots");
1160
1197
  mkdirSync2(slots, { recursive: true, mode: 493 });
1161
- const slotFile = join2(normalized.root, ".forge-slot");
1198
+ const slotFile = join2(slots, ".active");
1162
1199
  const previousSlot = existsSync2(slotFile) ? readFileSync2(slotFile, "utf8").trim() : undefined;
1163
1200
  const target = previousSlot === "blue" ? "green" : "blue";
1164
1201
  const port = target === "blue" ? normalized.bluePort : normalized.greenPort;
@@ -1208,6 +1245,7 @@ async function activatePlatformRelease(config, requestedRelease, options = {}) {
1208
1245
  const test = await exec(["/usr/sbin/nginx", "-t"]);
1209
1246
  const reload = test.exitCode === 0 ? await exec(["/usr/sbin/nginx", "-s", "reload"]) : test;
1210
1247
  if (reload.exitCode !== 0) {
1248
+ const refusal = (reload.output || test.output).trim().slice(0, 2000);
1211
1249
  if (existsSync2(backup))
1212
1250
  renameSync2(backup, upstream);
1213
1251
  else
@@ -1215,7 +1253,7 @@ async function activatePlatformRelease(config, requestedRelease, options = {}) {
1215
1253
  await exec(["/usr/sbin/nginx", "-t"]);
1216
1254
  await exec(["/usr/sbin/nginx", "-s", "reload"]);
1217
1255
  await stopTarget();
1218
- throw new Error("nginx refused the promoted upstream");
1256
+ throw new Error(`nginx refused the promoted upstream${refusal ? `: ${refusal}` : ""}`);
1219
1257
  }
1220
1258
  rmSync2(backup, { force: true });
1221
1259
  writeFileSync2(slotFile, `${target}
@@ -1276,5 +1314,6 @@ export {
1276
1314
  platformApiCredentialSpecs,
1277
1315
  planPlatformActivation,
1278
1316
  planLocalOtlpProof,
1317
+ assertReleaseLinksContained,
1279
1318
  activatePlatformRelease
1280
1319
  };