@forgezero/agent 0.1.63 → 0.1.65
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.
- package/README.md +13 -9
- package/dist/agent-heartbeat.js +1 -1
- package/dist/bootstrap.d.ts +17 -1
- package/dist/bootstrap.js +115 -68
- package/dist/cli/agent-install.d.ts +9 -0
- package/dist/deployment.d.ts +11 -0
- package/dist/fz-agent.js +120 -70
- package/dist/fz.js +391 -103
- package/dist/metal-bootstrap.js +1 -1
- package/dist/operator-bootstrap.d.ts +42 -0
- package/dist/operator-bootstrap.js +294 -75
- package/dist/platform-fleet-verification.js +92 -66
- package/dist/provision.js +27 -26
- package/dist/version.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -281,14 +281,15 @@ import type { AgentUpdateOutcome, AgentUpdateReceipt, AgentUpdateRequest, AgentU
|
|
|
281
281
|
<a id="forgezero-agent-bootstrap"></a>
|
|
282
282
|
## @forgezero/agent/bootstrap
|
|
283
283
|
|
|
284
|
-
Typed one-time platform bootstrap and internal API-driven enrolled-compute activation contracts. Named value imports: BOOTSTRAP_STATE_PATH, PLATFORM_BOOTSTRAP_PROFILES, applyBootstrap, bootstrapIdentityDigest, bootstrapStatus, localBootstrapHost, planBootstrap, readBootstrapConfig, resolveInstalledBootstrapKind, validateBootstrapConfig, validateEnrolledComputeBootstrapSecrets, validatePlatformBootstrapSecrets. Named type imports: BootstrapConfig, BootstrapEnvironment, BootstrapHost, BootstrapPlan, BootstrapResult, BootstrapSecrets, BootstrapStatus, BootstrapStep, DatabaseAgencyParticipation, DatabaseBootstrapRole, EnrolledComputeActivationConfig, EnrolledComputeBootstrapSecrets, InstalledBootstrapKind, PlatformBootstrapConfig, PlatformBootstrapProfile, PlatformBootstrapSecrets, PlatformEnrolmentSource. Import only the names used by this file.
|
|
284
|
+
Typed one-time platform bootstrap and internal API-driven enrolled-compute activation contracts. Named value imports: BOOTSTRAP_STATE_PATH, PLATFORM_BOOTSTRAP_PROFILES, applyBootstrap, bootstrapIdentityDigest, bootstrapStatus, localBootstrapHost, planBootstrap, planBootstrapAgentInstall, readBootstrapConfig, resolveInstalledBootstrapKind, validateBootstrapConfig, validateEnrolledComputeBootstrapSecrets, validatePlatformBootstrapSecrets. Named type imports: BootstrapAgentInstallPhase, BootstrapConfig, BootstrapEnvironment, BootstrapHost, BootstrapPlan, BootstrapResult, BootstrapSecrets, BootstrapStatus, BootstrapStep, DatabaseAgencyParticipation, DatabaseBootstrapRole, EnrolledComputeActivationConfig, EnrolledComputeBootstrapSecrets, InstalledBootstrapKind, PlatformBootstrapConfig, PlatformBootstrapProfile, PlatformBootstrapSecrets, PlatformEnrolmentSource. Import only the names used by this file.
|
|
285
285
|
|
|
286
286
|
```text
|
|
287
287
|
import { BOOTSTRAP_STATE_PATH, PLATFORM_BOOTSTRAP_PROFILES, applyBootstrap, bootstrapIdentityDigest, bootstrapStatus, localBootstrapHost } from '@forgezero/agent/bootstrap';
|
|
288
|
-
import { planBootstrap, readBootstrapConfig, resolveInstalledBootstrapKind, validateBootstrapConfig, validateEnrolledComputeBootstrapSecrets
|
|
289
|
-
import
|
|
290
|
-
import type {
|
|
291
|
-
import type {
|
|
288
|
+
import { planBootstrap, planBootstrapAgentInstall, readBootstrapConfig, resolveInstalledBootstrapKind, validateBootstrapConfig, validateEnrolledComputeBootstrapSecrets } from '@forgezero/agent/bootstrap';
|
|
289
|
+
import { validatePlatformBootstrapSecrets } from '@forgezero/agent/bootstrap';
|
|
290
|
+
import type { BootstrapAgentInstallPhase, BootstrapConfig, BootstrapEnvironment, BootstrapHost, BootstrapPlan, BootstrapResult } from '@forgezero/agent/bootstrap';
|
|
291
|
+
import type { BootstrapSecrets, BootstrapStatus, BootstrapStep, DatabaseAgencyParticipation, DatabaseBootstrapRole, EnrolledComputeActivationConfig } from '@forgezero/agent/bootstrap';
|
|
292
|
+
import type { EnrolledComputeBootstrapSecrets, InstalledBootstrapKind, PlatformBootstrapConfig, PlatformBootstrapProfile, PlatformBootstrapSecrets, PlatformEnrolmentSource } from '@forgezero/agent/bootstrap';
|
|
292
293
|
```
|
|
293
294
|
|
|
294
295
|
<a id="forgezero-agent-bootstrap-bundle"></a>
|
|
@@ -319,12 +320,15 @@ await readBootstrapBundle(built.bundlePath, built.manifestPath);
|
|
|
319
320
|
<a id="forgezero-agent-operator-bootstrap"></a>
|
|
320
321
|
## @forgezero/agent/operator-bootstrap
|
|
321
322
|
|
|
322
|
-
Pinned-host operator transport that stages owner-only handoffs and invokes the same typed platform bootstrap through the caller-approved SSH agent. Named value imports: applyOperatorMetalBootstrap, applyOperatorPlatformBootstrap, planOperatorMetalBootstrap, planOperatorPlatformBootstrap, readOperatorMetalBootstrapRequest, readOperatorPlatformBootstrapRequest. Named type imports: OperatorCommand, OperatorCommandResult, OperatorMetalBootstrapMode, OperatorMetalBootstrapPlan, OperatorMetalBootstrapRequest, OperatorPlatformBootstrapMode, OperatorPlatformBootstrapOptions, OperatorPlatformBootstrapPlan, OperatorPlatformBootstrapRequest, OperatorSshHop. Import only the names used by this file.
|
|
323
|
+
Pinned-host operator transport that stages owner-only handoffs and invokes the same typed platform bootstrap through the caller-approved SSH agent. Named value imports: applyOperatorMetalBootstrap, applyOperatorPlatformBootstrap, applyOperatorPlatformFleetBootstrap, createOperatorSshHop, planOperatorMetalBootstrap, planOperatorPlatformBootstrap, planOperatorPlatformFleetBootstrap, readOperatorMetalBootstrapRequest, readOperatorPlatformBootstrapFleetRequest, readOperatorPlatformBootstrapRequest, writeOperatorMetalBootstrapRequest, writeOperatorPlatformBootstrapFleetRequest, writeOperatorPlatformBootstrapRequest. Named type imports: OperatorCommand, OperatorCommandResult, OperatorMetalBootstrapMode, OperatorMetalBootstrapPlan, OperatorMetalBootstrapRequest, OperatorPlatformBootstrapFleetOutcome, OperatorPlatformBootstrapFleetPlan, OperatorPlatformBootstrapFleetRequest, OperatorPlatformBootstrapFleetResult, OperatorPlatformBootstrapMode, OperatorPlatformBootstrapOptions, OperatorPlatformBootstrapPlan, OperatorPlatformBootstrapRequest, OperatorSshHop. Import only the names used by this file.
|
|
323
324
|
|
|
324
325
|
```text
|
|
325
|
-
import { applyOperatorMetalBootstrap, applyOperatorPlatformBootstrap,
|
|
326
|
-
import
|
|
327
|
-
import
|
|
326
|
+
import { applyOperatorMetalBootstrap, applyOperatorPlatformBootstrap, applyOperatorPlatformFleetBootstrap, createOperatorSshHop, planOperatorMetalBootstrap, planOperatorPlatformBootstrap } from '@forgezero/agent/operator-bootstrap';
|
|
327
|
+
import { planOperatorPlatformFleetBootstrap, readOperatorMetalBootstrapRequest, readOperatorPlatformBootstrapFleetRequest, readOperatorPlatformBootstrapRequest, writeOperatorMetalBootstrapRequest, writeOperatorPlatformBootstrapFleetRequest } from '@forgezero/agent/operator-bootstrap';
|
|
328
|
+
import { writeOperatorPlatformBootstrapRequest } from '@forgezero/agent/operator-bootstrap';
|
|
329
|
+
import type { OperatorCommand, OperatorCommandResult, OperatorMetalBootstrapMode, OperatorMetalBootstrapPlan, OperatorMetalBootstrapRequest, OperatorPlatformBootstrapFleetOutcome } from '@forgezero/agent/operator-bootstrap';
|
|
330
|
+
import type { OperatorPlatformBootstrapFleetPlan, OperatorPlatformBootstrapFleetRequest, OperatorPlatformBootstrapFleetResult, OperatorPlatformBootstrapMode, OperatorPlatformBootstrapOptions, OperatorPlatformBootstrapPlan } from '@forgezero/agent/operator-bootstrap';
|
|
331
|
+
import type { OperatorPlatformBootstrapRequest, OperatorSshHop } from '@forgezero/agent/operator-bootstrap';
|
|
328
332
|
```
|
|
329
333
|
|
|
330
334
|
## @forgezero/agent/operator-bootstrap — Run the same typed platform bootstrap from an operator laptop
|
package/dist/agent-heartbeat.js
CHANGED
package/dist/bootstrap.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { type ProvisionPlan } from './cli/agent-install';
|
|
2
|
+
import type { Capabilities } from './provision';
|
|
2
3
|
import { type SoftwareCommandResult, type SoftwareRequirement } from './software';
|
|
3
4
|
import { type PlatformSharedEnvironment } from './platform-bootstrap-runtime';
|
|
5
|
+
import { type BootstrapBundleManifest } from './bootstrap-bundle';
|
|
4
6
|
export declare const PLATFORM_BOOTSTRAP_PROFILES: readonly ["platform-db-api", "platform-api"];
|
|
5
7
|
export type PlatformBootstrapProfile = (typeof PLATFORM_BOOTSTRAP_PROFILES)[number];
|
|
6
8
|
export type DatabaseBootstrapRole = 'master' | 'joiner' | 'none';
|
|
@@ -149,6 +151,7 @@ export interface BootstrapStatus {
|
|
|
149
151
|
problems: string[];
|
|
150
152
|
}
|
|
151
153
|
export type InstalledBootstrapKind = 'compute' | 'metal';
|
|
154
|
+
export type BootstrapAgentInstallPhase = 'bootstrap' | 'enrol' | 'bound';
|
|
152
155
|
/** One host has one bootstrap authority. Dual state is never resolved by precedence. */
|
|
153
156
|
export declare function resolveInstalledBootstrapKind(states: {
|
|
154
157
|
compute: boolean;
|
|
@@ -174,7 +177,7 @@ export interface BootstrapHost {
|
|
|
174
177
|
}): Promise<SoftwareCommandResult>;
|
|
175
178
|
sleep?(milliseconds: number): Promise<void>;
|
|
176
179
|
ensureSoftware(requirements: readonly SoftwareRequirement[]): Promise<unknown>;
|
|
177
|
-
installAgent(config: BootstrapConfig): Promise<ProvisionPlan>;
|
|
180
|
+
installAgent(config: BootstrapConfig, phase: BootstrapAgentInstallPhase): Promise<ProvisionPlan>;
|
|
178
181
|
}
|
|
179
182
|
export declare const BOOTSTRAP_STATE_PATH = "/var/lib/forgezero/bootstrap.json";
|
|
180
183
|
export declare function validateBootstrapConfig(value: BootstrapConfig): BootstrapConfig;
|
|
@@ -185,4 +188,17 @@ export declare function applyBootstrap(input: BootstrapConfig, host?: BootstrapH
|
|
|
185
188
|
fetcher?: typeof fetch;
|
|
186
189
|
}): Promise<BootstrapResult>;
|
|
187
190
|
export declare function readBootstrapConfig(path: string): BootstrapConfig;
|
|
191
|
+
interface BootstrapAgentInitialBundle {
|
|
192
|
+
path: string;
|
|
193
|
+
manifestPath: string;
|
|
194
|
+
manifest: BootstrapBundleManifest;
|
|
195
|
+
}
|
|
196
|
+
/** Compose one real local Agent convergence without consulting mutable globals. */
|
|
197
|
+
export declare function planBootstrapAgentInstall(config: BootstrapConfig, phase: BootstrapAgentInstallPhase, context: {
|
|
198
|
+
capabilities: Capabilities;
|
|
199
|
+
hasBinding: boolean;
|
|
200
|
+
hasEnrolCredential: boolean;
|
|
201
|
+
initialBundle?: BootstrapAgentInitialBundle;
|
|
202
|
+
}): ProvisionPlan;
|
|
188
203
|
export declare function localBootstrapHost(): BootstrapHost;
|
|
204
|
+
export {};
|
package/dist/bootstrap.js
CHANGED
|
@@ -1396,7 +1396,7 @@ var UPDATE_RETRY_BASE_MS = 5 * 60000;
|
|
|
1396
1396
|
var UPDATE_RETRY_MAX_MS = 24 * 60 * 60000;
|
|
1397
1397
|
|
|
1398
1398
|
// src/version.ts
|
|
1399
|
-
var VERSION = "0.1.
|
|
1399
|
+
var VERSION = "0.1.65";
|
|
1400
1400
|
|
|
1401
1401
|
// src/software.ts
|
|
1402
1402
|
var PINNED_BUN_VERSION = "1.3.14";
|
|
@@ -2045,17 +2045,16 @@ function agentUnit(options) {
|
|
|
2045
2045
|
if (Boolean(options.pullMigrations) !== Boolean(options.lifecycleProfilePath)) {
|
|
2046
2046
|
throw new Error("migration pull and lifecycle profile must be supplied together");
|
|
2047
2047
|
}
|
|
2048
|
-
const
|
|
2049
|
-
if (
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
throw new Error("bootstrap pull, SSH credential, public key and target telemetry endpoint must be supplied together");
|
|
2048
|
+
const bootstrapIdentityEnabled = Boolean(options.bootstrapSshCredentialPath && options.bootstrapSshPublicKeyPath);
|
|
2049
|
+
if (Boolean(options.bootstrapSshCredentialPath) !== Boolean(options.bootstrapSshPublicKeyPath)) {
|
|
2050
|
+
throw new Error("bootstrap SSH credential and public key paths must be supplied together");
|
|
2051
|
+
}
|
|
2052
|
+
const bootstrapEnabled = Boolean(options.pullBootstrap);
|
|
2053
|
+
if (bootstrapEnabled && (!bootstrapIdentityEnabled || !options.bootstrapTargetTelemetryEndpoint) || !bootstrapEnabled && options.bootstrapTargetTelemetryEndpoint) {
|
|
2054
|
+
throw new Error("bootstrap pull, SSH identity and target telemetry endpoint must be supplied together");
|
|
2056
2055
|
}
|
|
2057
2056
|
const lifecycleHelperSocketPath = lifecycleEnabled ? systemdPath(options.lifecycleHelperSocketPath ?? LIFECYCLE_HELPER_SOCKET, "lifecycle helper socket") : undefined;
|
|
2058
|
-
const bootstrapSshCredentialPath =
|
|
2057
|
+
const bootstrapSshCredentialPath = bootstrapIdentityEnabled ? systemdPath(options.bootstrapSshCredentialPath, "bootstrap SSH credential") : undefined;
|
|
2059
2058
|
const warpValues = [
|
|
2060
2059
|
options.warpOrganization,
|
|
2061
2060
|
options.warpClientIdCredentialPath,
|
|
@@ -2294,15 +2293,13 @@ function planProvision(options) {
|
|
|
2294
2293
|
if (Boolean(options.pullMigrations) !== Boolean(options.lifecycleProfilePath)) {
|
|
2295
2294
|
throw new Error("migration pull and lifecycle profile must be supplied together");
|
|
2296
2295
|
}
|
|
2297
|
-
const
|
|
2298
|
-
if (
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
].some(Boolean) && !bootstrapEnabled) {
|
|
2305
|
-
throw new Error("bootstrap pull, SSH credential, public key and target telemetry endpoint must be supplied together");
|
|
2296
|
+
const bootstrapIdentityEnabled = Boolean(options.bootstrapSshCredentialPath && options.bootstrapSshPublicKeyPath);
|
|
2297
|
+
if (Boolean(options.bootstrapSshCredentialPath) !== Boolean(options.bootstrapSshPublicKeyPath) || options.bootstrapSshSourcePath && !bootstrapIdentityEnabled) {
|
|
2298
|
+
throw new Error("bootstrap SSH credential and public key paths must be supplied together");
|
|
2299
|
+
}
|
|
2300
|
+
const bootstrapEnabled = Boolean(options.pullBootstrap);
|
|
2301
|
+
if (bootstrapEnabled && (!bootstrapIdentityEnabled || !options.bootstrapTargetTelemetryEndpoint) || !bootstrapEnabled && options.bootstrapTargetTelemetryEndpoint) {
|
|
2302
|
+
throw new Error("bootstrap pull, SSH identity and target telemetry endpoint must be supplied together");
|
|
2306
2303
|
}
|
|
2307
2304
|
const warpValues = [
|
|
2308
2305
|
options.warpOrganization,
|
|
@@ -2312,13 +2309,13 @@ function planProvision(options) {
|
|
|
2312
2309
|
const warpEnabled = warpValues.every(Boolean);
|
|
2313
2310
|
if (warpValues.some(Boolean) && !warpEnabled)
|
|
2314
2311
|
throw new Error("WARP configuration must be supplied together");
|
|
2315
|
-
const enrolmentEnabled = Boolean(options.enrolTokenCredentialPath
|
|
2316
|
-
if (
|
|
2317
|
-
throw new Error("direct enrolment credential
|
|
2312
|
+
const enrolmentEnabled = Boolean(options.enrolTokenCredentialPath);
|
|
2313
|
+
if (options.enrolTokenCredentialPath && !options.enrolStatePath || options.enrolTokenSourcePath && (!options.enrolTokenCredentialPath || !options.enrolStatePath)) {
|
|
2314
|
+
throw new Error("direct enrolment credential requires its durable state path");
|
|
2318
2315
|
}
|
|
2319
2316
|
const enrolTokenSourcePath = options.enrolTokenSourcePath ? systemdPath(options.enrolTokenSourcePath, "enrolment source") : undefined;
|
|
2320
2317
|
const enrolTokenCredentialPath = enrolmentEnabled ? systemdPath(options.enrolTokenCredentialPath, "enrolment credential") : undefined;
|
|
2321
|
-
const enrolStatePath =
|
|
2318
|
+
const enrolStatePath = options.enrolStatePath ? systemdPath(options.enrolStatePath, "enrolment state") : undefined;
|
|
2322
2319
|
const enrolStateDir = enrolStatePath?.replace(/\/[^/]+$/, "");
|
|
2323
2320
|
const sourceBinPath = options.sourceBinPath ? systemdPath(options.sourceBinPath, "agent source binary") : undefined;
|
|
2324
2321
|
const binPath = options.binPath ? systemdPath(options.binPath, "agent binary") : undefined;
|
|
@@ -2330,8 +2327,8 @@ function planProvision(options) {
|
|
|
2330
2327
|
const gitPublicKeyDir = gitPublicKeyPath?.replace(/\/[^/]+$/, "");
|
|
2331
2328
|
const lifecycleProfilePath = lifecycleEnabled ? systemdPath(options.lifecycleProfilePath, "lifecycle profile") : undefined;
|
|
2332
2329
|
const lifecycleHelperSocketPath = lifecycleEnabled ? systemdPath(options.lifecycleHelperSocketPath ?? LIFECYCLE_HELPER_SOCKET, "lifecycle helper socket") : undefined;
|
|
2333
|
-
const bootstrapSshCredentialPath =
|
|
2334
|
-
const bootstrapSshPublicKeyPath =
|
|
2330
|
+
const bootstrapSshCredentialPath = bootstrapIdentityEnabled ? systemdPath(options.bootstrapSshCredentialPath, "bootstrap SSH credential") : undefined;
|
|
2331
|
+
const bootstrapSshPublicKeyPath = bootstrapIdentityEnabled ? systemdPath(options.bootstrapSshPublicKeyPath, "bootstrap SSH public key") : undefined;
|
|
2335
2332
|
const bootstrapSshSourcePath = options.bootstrapSshSourcePath ? systemdPath(options.bootstrapSshSourcePath, "bootstrap SSH private-key source") : undefined;
|
|
2336
2333
|
const bootstrapSshPublicKeyDir = bootstrapSshPublicKeyPath?.replace(/\/[^/]+$/, "");
|
|
2337
2334
|
const warpClientIdCredentialPath = warpEnabled ? systemdPath(options.warpClientIdCredentialPath, "WARP client-id credential") : undefined;
|
|
@@ -2431,7 +2428,7 @@ function planProvision(options) {
|
|
|
2431
2428
|
step("Git deploy identity directory", { kind: "directories", directories: [{ path: gitPublicKeyDir, mode: 493, owner: "root", group: "root" }] }),
|
|
2432
2429
|
step("unique encrypted Git deploy identity", { kind: "ensure-git-identity", credential: gitCredentialPath, publicKey: gitPublicKeyPath })
|
|
2433
2430
|
] : [],
|
|
2434
|
-
...
|
|
2431
|
+
...bootstrapIdentityEnabled ? [
|
|
2435
2432
|
step("bootstrap SSH public identity directory", { kind: "directories", directories: [
|
|
2436
2433
|
{ path: bootstrapSshPublicKeyDir, mode: 493, owner: "root", group: "root" }
|
|
2437
2434
|
] }),
|
|
@@ -2467,6 +2464,10 @@ function planProvision(options) {
|
|
|
2467
2464
|
{ argv: ["/usr/bin/rm", "-f", "/etc/systemd/system/forgezero-deploy-runner.socket"] },
|
|
2468
2465
|
{ argv: ["/usr/bin/systemctl", "daemon-reload"] }
|
|
2469
2466
|
] })] : [],
|
|
2467
|
+
...enrolStatePath && !enrolmentEnabled ? [step("retire consumed enrolment unit", { kind: "commands", commands: [
|
|
2468
|
+
{ argv: ["/usr/bin/systemctl", "disable", "--now", "forgezero-agent-enrol.service"], acceptedExitCodes: [0, 1, 5] },
|
|
2469
|
+
{ argv: ["/usr/bin/rm", "-f", ENROLMENT_UNIT_PATH] }
|
|
2470
|
+
] })] : [],
|
|
2470
2471
|
step("enable and converge services", { kind: "commands", commands: [
|
|
2471
2472
|
{ argv: ["/usr/bin/systemctl", "enable", ...enabledUnits] },
|
|
2472
2473
|
{ argv: ["/usr/bin/systemctl", "reset-failed", "forgezero-agent.service"], acceptedExitCodes: [0, 1] },
|
|
@@ -4181,7 +4182,15 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
|
|
|
4181
4182
|
if (connectorCapabilities?.meshConnectorToken && !host.exists(WARP_CONNECTOR_CREDENTIAL)) {
|
|
4182
4183
|
await seal(host, "CF_WARP_CONNECTOR_TOKEN", WARP_CONNECTOR_CREDENTIAL, connectorCapabilities.meshConnectorToken);
|
|
4183
4184
|
}
|
|
4184
|
-
|
|
4185
|
+
if (alreadyEnrolled) {
|
|
4186
|
+
await host.installAgent(config, "bound");
|
|
4187
|
+
} else if (config.kind === "platform") {
|
|
4188
|
+
if (bootstrapManifest)
|
|
4189
|
+
await host.installAgent(config, "bootstrap");
|
|
4190
|
+
} else {
|
|
4191
|
+
await host.installAgent(config, "enrol");
|
|
4192
|
+
await host.installAgent(config, "bound");
|
|
4193
|
+
}
|
|
4185
4194
|
if (config.kind === "platform" && config.firewall.enabled) {
|
|
4186
4195
|
await host.ensureSoftware(plan.software.filter(({ id }) => id === "ufw"));
|
|
4187
4196
|
} else
|
|
@@ -4331,7 +4340,19 @@ async function applyBootstrap(input, host = localBootstrapHost(), secrets, depen
|
|
|
4331
4340
|
`, 384);
|
|
4332
4341
|
host.remove(config.bootstrapBundle.bundleFile);
|
|
4333
4342
|
host.remove(config.bootstrapBundle.manifestFile);
|
|
4334
|
-
|
|
4343
|
+
}
|
|
4344
|
+
if (!alreadyEnrolled) {
|
|
4345
|
+
await checked3(host, [
|
|
4346
|
+
"curl",
|
|
4347
|
+
"--fail",
|
|
4348
|
+
"--silent",
|
|
4349
|
+
"--show-error",
|
|
4350
|
+
"--max-time",
|
|
4351
|
+
"10",
|
|
4352
|
+
`http://127.0.0.1:3000${runtime.healthPath}`
|
|
4353
|
+
], "release-one API health");
|
|
4354
|
+
await host.installAgent(config, "enrol");
|
|
4355
|
+
await host.installAgent(config, "bound");
|
|
4335
4356
|
}
|
|
4336
4357
|
}
|
|
4337
4358
|
if (config.cloudflareHandoff) {
|
|
@@ -4500,6 +4521,65 @@ function readBootstrapConfig(path) {
|
|
|
4500
4521
|
}
|
|
4501
4522
|
return validateBootstrapConfig(strictBootstrapDocument(JSON.parse(readFileSync5(path, "utf8"))));
|
|
4502
4523
|
}
|
|
4524
|
+
function planBootstrapAgentInstall(config, phase, context) {
|
|
4525
|
+
const { capabilities, hasBinding, hasEnrolCredential, initialBundle } = context;
|
|
4526
|
+
if (phase === "bootstrap") {
|
|
4527
|
+
if (config.kind !== "platform" || hasBinding || !initialBundle) {
|
|
4528
|
+
throw new Error("release-one Agent install requires an unbound platform host and verified bootstrap bundle");
|
|
4529
|
+
}
|
|
4530
|
+
} else if (phase === "enrol") {
|
|
4531
|
+
if (hasBinding || !hasEnrolCredential) {
|
|
4532
|
+
throw new Error("Agent enrolment requires one unbound host and its sealed one-use credential");
|
|
4533
|
+
}
|
|
4534
|
+
} else if (!hasBinding) {
|
|
4535
|
+
throw new Error("bound Agent convergence requires durable enrolment state");
|
|
4536
|
+
}
|
|
4537
|
+
const bound = phase === "bound";
|
|
4538
|
+
const enrolling = phase === "enrol";
|
|
4539
|
+
const authenticated = enrolling || bound;
|
|
4540
|
+
const bootstrapRunner = platformBootstrapRunner(config) || config.kind === "enrolled-compute" && Boolean(config.bootstrapRunner);
|
|
4541
|
+
const options = {
|
|
4542
|
+
capabilities,
|
|
4543
|
+
socketPath: DEFAULT_SOCKET2,
|
|
4544
|
+
seedPath: "/var/lib/forgezero/node.seed",
|
|
4545
|
+
controlSocketPath: CONTROL_SOCKET,
|
|
4546
|
+
repository: phase === "bootstrap" ? initialBundle.path : bound && config.kind === "enrolled-compute" ? config.repository : undefined,
|
|
4547
|
+
branch: phase === "bootstrap" ? initialBundle.manifest.branch : bound && config.kind === "enrolled-compute" ? config.branch : undefined,
|
|
4548
|
+
bootstrapBundlePath: phase === "bootstrap" ? initialBundle.path : undefined,
|
|
4549
|
+
bootstrapBundleManifestPath: phase === "bootstrap" ? initialBundle.manifestPath : undefined,
|
|
4550
|
+
profile: config.profile,
|
|
4551
|
+
deployRoot: config.deployRoot ?? "/opt/forgezero",
|
|
4552
|
+
deploymentCredentials: config.deploymentCredentials,
|
|
4553
|
+
publicApiUrl: config.apiUrl,
|
|
4554
|
+
gitCredentialPath: authenticated && config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/creds/git-deploy-key.cred" : undefined,
|
|
4555
|
+
gitPublicKeyPath: authenticated && config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/git/deploy.pub" : undefined,
|
|
4556
|
+
generateGitIdentity: authenticated && config.kind === "enrolled-compute" && config.gitDeployKey === true,
|
|
4557
|
+
pullDeployments: bound,
|
|
4558
|
+
pullMigrations: bound && config.kind === "platform",
|
|
4559
|
+
pullBootstrap: bound && bootstrapRunner,
|
|
4560
|
+
bootstrapSshCredentialPath: authenticated && bootstrapRunner ? BOOTSTRAP_SSH_CREDENTIAL : undefined,
|
|
4561
|
+
bootstrapSshSourcePath: enrolling && config.kind === "enrolled-compute" ? config.bootstrapRunner?.sshPrivateKeyFile : undefined,
|
|
4562
|
+
bootstrapSshPublicKeyPath: authenticated && bootstrapRunner ? BOOTSTRAP_SSH_PUBLIC_KEY : undefined,
|
|
4563
|
+
bootstrapTargetTelemetryEndpoint: bound && bootstrapRunner ? platformBootstrapRunner(config) ? config.telemetryEndpoint : config.kind === "enrolled-compute" ? config.bootstrapRunner?.targetTelemetryEndpoint : undefined : undefined,
|
|
4564
|
+
lifecycleProfilePath: bound && config.kind === "platform" ? LIFECYCLE_PROFILE : undefined,
|
|
4565
|
+
enforceEgress: true,
|
|
4566
|
+
nodeHostname: config.nodeHostname,
|
|
4567
|
+
telemetryEndpoint: config.telemetryEndpoint,
|
|
4568
|
+
binPath: "/usr/local/lib/forgezero/agent/fz-agent",
|
|
4569
|
+
sourceBinPath: PACKAGED_AGENT_BIN,
|
|
4570
|
+
...enrolling ? {
|
|
4571
|
+
enrolTokenCredentialPath: ENROL_CREDENTIAL,
|
|
4572
|
+
enrolStatePath: "/var/lib/forgezero/enrolment.json"
|
|
4573
|
+
} : bound ? { enrolStatePath: "/var/lib/forgezero/enrolment.json" } : {},
|
|
4574
|
+
...authenticated ? {
|
|
4575
|
+
apiUrl: config.apiUrl,
|
|
4576
|
+
project: config.kind === "enrolled-compute" ? config.realm : "platform",
|
|
4577
|
+
environment: config.kind === "enrolled-compute" ? undefined : config.environment,
|
|
4578
|
+
nodeLabel: config.kind === "enrolled-compute" ? config.nodeHostname : config.computeReference
|
|
4579
|
+
} : {}
|
|
4580
|
+
};
|
|
4581
|
+
return planInstall(options);
|
|
4582
|
+
}
|
|
4503
4583
|
function localBootstrapHost() {
|
|
4504
4584
|
const execute = async (argv, options = {}) => {
|
|
4505
4585
|
const child = Bun.spawn([...argv], { stdin: options.stdin === undefined ? "ignore" : "pipe", stdout: "pipe", stderr: "pipe" });
|
|
@@ -4547,10 +4627,10 @@ function localBootstrapHost() {
|
|
|
4547
4627
|
throw new Error(`Agent software requirements failed: ${result.output.trim()}`);
|
|
4548
4628
|
return result;
|
|
4549
4629
|
},
|
|
4550
|
-
async installAgent(config) {
|
|
4630
|
+
async installAgent(config, phase) {
|
|
4551
4631
|
const capabilities = await readCapabilities(localRunner);
|
|
4552
|
-
const deployRoot = config.deployRoot ?? "/opt/forgezero";
|
|
4553
4632
|
const hasBinding = existsSync5("/var/lib/forgezero/enrolment.json");
|
|
4633
|
+
const hasEnrolCredential = existsSync5(ENROL_CREDENTIAL);
|
|
4554
4634
|
const initialBundle = config.kind === "platform" && !existsSync5(BOOTSTRAP_RELEASE_EVIDENCE) ? {
|
|
4555
4635
|
path: config.bootstrapBundle.bundleFile,
|
|
4556
4636
|
manifestPath: config.bootstrapBundle.manifestFile,
|
|
@@ -4571,45 +4651,11 @@ function localBootstrapHost() {
|
|
|
4571
4651
|
writeFileSync5(LIFECYCLE_PROFILE, `${JSON.stringify(lifecycle, null, 2)}
|
|
4572
4652
|
`, { mode: 256 });
|
|
4573
4653
|
}
|
|
4574
|
-
const plan =
|
|
4654
|
+
const plan = planBootstrapAgentInstall(config, phase, {
|
|
4575
4655
|
capabilities,
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
repository: initialBundle?.path ?? (config.kind === "enrolled-compute" ? config.repository : undefined),
|
|
4580
|
-
branch: initialBundle?.manifest.branch ?? (config.kind === "enrolled-compute" ? config.branch : undefined),
|
|
4581
|
-
bootstrapBundlePath: initialBundle?.path,
|
|
4582
|
-
bootstrapBundleManifestPath: initialBundle?.manifestPath,
|
|
4583
|
-
profile: config.kind === "platform" ? config.profile : config.profile,
|
|
4584
|
-
deployRoot,
|
|
4585
|
-
deploymentCredentials: config.deploymentCredentials,
|
|
4586
|
-
publicApiUrl: config.apiUrl,
|
|
4587
|
-
gitCredentialPath: config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/creds/git-deploy-key.cred" : undefined,
|
|
4588
|
-
gitPublicKeyPath: config.kind === "enrolled-compute" && config.gitDeployKey ? "/etc/forgezero/git/deploy.pub" : undefined,
|
|
4589
|
-
generateGitIdentity: config.kind === "enrolled-compute" && config.gitDeployKey === true,
|
|
4590
|
-
pullDeployments: hasBinding,
|
|
4591
|
-
pullMigrations: config.kind === "platform" && hasBinding,
|
|
4592
|
-
pullBootstrap: platformBootstrapRunner(config) || config.kind === "enrolled-compute" && Boolean(config.bootstrapRunner),
|
|
4593
|
-
bootstrapSshCredentialPath: platformBootstrapRunner(config) || config.kind === "enrolled-compute" && config.bootstrapRunner ? BOOTSTRAP_SSH_CREDENTIAL : undefined,
|
|
4594
|
-
bootstrapSshSourcePath: config.kind === "enrolled-compute" ? config.bootstrapRunner?.sshPrivateKeyFile : undefined,
|
|
4595
|
-
bootstrapSshPublicKeyPath: platformBootstrapRunner(config) || config.kind === "enrolled-compute" && config.bootstrapRunner ? BOOTSTRAP_SSH_PUBLIC_KEY : undefined,
|
|
4596
|
-
bootstrapTargetTelemetryEndpoint: platformBootstrapRunner(config) ? config.telemetryEndpoint : config.kind === "enrolled-compute" ? config.bootstrapRunner?.targetTelemetryEndpoint : undefined,
|
|
4597
|
-
lifecycleProfilePath: config.kind === "platform" ? LIFECYCLE_PROFILE : undefined,
|
|
4598
|
-
enforceEgress: true,
|
|
4599
|
-
nodeHostname: config.nodeHostname,
|
|
4600
|
-
telemetryEndpoint: config.telemetryEndpoint,
|
|
4601
|
-
binPath: "/usr/local/lib/forgezero/agent/fz-agent",
|
|
4602
|
-
sourceBinPath: PACKAGED_AGENT_BIN,
|
|
4603
|
-
...existsSync5(ENROL_CREDENTIAL) || hasBinding ? {
|
|
4604
|
-
enrolTokenCredentialPath: existsSync5(ENROL_CREDENTIAL) ? ENROL_CREDENTIAL : undefined,
|
|
4605
|
-
enrolStatePath: "/var/lib/forgezero/enrolment.json"
|
|
4606
|
-
} : {},
|
|
4607
|
-
...hasBinding ? {
|
|
4608
|
-
apiUrl: config.apiUrl,
|
|
4609
|
-
project: config.kind === "enrolled-compute" ? config.realm : "platform",
|
|
4610
|
-
environment: config.kind === "enrolled-compute" ? undefined : config.environment,
|
|
4611
|
-
nodeLabel: config.kind === "enrolled-compute" ? config.nodeHostname : config.computeReference
|
|
4612
|
-
} : {}
|
|
4656
|
+
hasBinding,
|
|
4657
|
+
hasEnrolCredential,
|
|
4658
|
+
initialBundle
|
|
4613
4659
|
});
|
|
4614
4660
|
for (const unit of [{ path: plan.unitPath, unit: plan.unit }, ...plan.auxiliaryUnits]) {
|
|
4615
4661
|
mkdirSync5(dirname6(unit.path), { recursive: true, mode: 493 });
|
|
@@ -4626,6 +4672,7 @@ export {
|
|
|
4626
4672
|
validateBootstrapConfig,
|
|
4627
4673
|
resolveInstalledBootstrapKind,
|
|
4628
4674
|
readBootstrapConfig,
|
|
4675
|
+
planBootstrapAgentInstall,
|
|
4629
4676
|
planBootstrap,
|
|
4630
4677
|
localBootstrapHost,
|
|
4631
4678
|
bootstrapStatus,
|
|
@@ -84,6 +84,15 @@ export interface InstallOptions {
|
|
|
84
84
|
nodeHostname?: string;
|
|
85
85
|
telemetryEndpoint?: string;
|
|
86
86
|
}
|
|
87
|
+
export type GitIdentityInstallOptions = Pick<InstallOptions, 'gitCredentialPath' | 'gitPublicKeyPath' | 'generateGitIdentity'>;
|
|
88
|
+
/**
|
|
89
|
+
* Resolve the optional compatibility Git identity from the explicit install
|
|
90
|
+
* environment. An ordinary Agent install must not load a credential merely
|
|
91
|
+
* because the CLI knows its conventional pathname: systemd treats every
|
|
92
|
+
* LoadCredentialEncrypted entry as required and refuses to start when that
|
|
93
|
+
* file does not exist.
|
|
94
|
+
*/
|
|
95
|
+
export declare function resolveGitIdentityInstallOptions(environment: Readonly<Record<string, string | undefined>>): GitIdentityInstallOptions;
|
|
87
96
|
export declare function planInstall(options: InstallOptions): ProvisionPlan;
|
|
88
97
|
/** Execute the same ordered plan the control plane executes over SSH. */
|
|
89
98
|
export declare function applyPlan(plan: ProvisionPlan, run: (operation: CapabilityOperation | ProvisionOperation) => Promise<{
|
package/dist/deployment.d.ts
CHANGED
|
@@ -34,6 +34,8 @@ export interface DeploymentResult {
|
|
|
34
34
|
definitionDigest: string;
|
|
35
35
|
definitionVersion: number;
|
|
36
36
|
profile: string;
|
|
37
|
+
/** Resolved only from the validated plan and its bounded inputs at this revision. */
|
|
38
|
+
resolvedTargets?: readonly ResolvedDeploymentTarget[];
|
|
37
39
|
release: string;
|
|
38
40
|
ok: boolean;
|
|
39
41
|
phases: readonly RunResult[];
|
|
@@ -44,6 +46,15 @@ export interface DeploymentResult {
|
|
|
44
46
|
};
|
|
45
47
|
};
|
|
46
48
|
}
|
|
49
|
+
export interface ResolvedDeploymentTarget {
|
|
50
|
+
name: string;
|
|
51
|
+
profiles: readonly string[];
|
|
52
|
+
confidentialCompute: 'required' | 'preferred' | 'disabled';
|
|
53
|
+
labels: Readonly<Record<string, string>>;
|
|
54
|
+
minimum: number;
|
|
55
|
+
desired: number;
|
|
56
|
+
maximum: number;
|
|
57
|
+
}
|
|
47
58
|
/**
|
|
48
59
|
* How the credential-bearing agent may read one server-owned Git source.
|
|
49
60
|
* Secret values never appear in a deployment claim or checked-in pipeline.
|