@forgezero/agent 0.1.62 → 0.1.63
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 +36 -11
- package/dist/agent-heartbeat.js +1 -1
- package/dist/bootstrap-bundle.d.ts +31 -0
- package/dist/bootstrap-bundle.js +165 -0
- package/dist/bootstrap.d.ts +7 -17
- package/dist/bootstrap.js +407 -214
- package/dist/cli/agent-install.d.ts +2 -0
- package/dist/community-rehearsal-host.js +7 -5
- package/dist/definition.js +7 -5
- package/dist/deploy-file.js +7 -5
- package/dist/deployment.d.ts +16 -0
- package/dist/fz-agent.js +486 -363
- package/dist/fz.js +499 -305
- package/dist/metal-bootstrap.js +1 -1
- package/dist/metal-helper-socket.js +0 -2
- package/dist/metal-provision.js +0 -2
- package/dist/operator-bootstrap.d.ts +1 -1
- package/dist/operator-bootstrap.js +509 -307
- package/dist/platform-bootstrap-runtime.d.ts +0 -2
- package/dist/platform-bootstrap-runtime.js +0 -4
- package/dist/platform-fleet-verification.js +110 -44
- package/dist/provision.d.ts +4 -1
- package/dist/provision.js +15 -7
- package/dist/software-helper.js +7 -5
- package/dist/software.d.ts +1 -1
- package/dist/software.js +7 -5
- package/dist/version.d.ts +1 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -51,6 +51,7 @@ Every row links to the detailed explanation and named-import/example area below.
|
|
|
51
51
|
| @forgezero/agent/agent-update | Verified Agent update planning against the platform release coordinate. | Bun/Node host | [Details + example](#forgezero-agent-agent-update) |
|
|
52
52
|
| @forgezero/agent/agent-update-helper | Root-owned fixed update operations with registry origin and integrity validation. | Bun/Node host | [Details + example](#forgezero-agent-agent-update-helper) |
|
|
53
53
|
| @forgezero/agent/bootstrap | Typed one-time platform bootstrap and internal API-driven enrolled-compute activation contracts. | Bun/Node host | [Details + example](#forgezero-agent-bootstrap) |
|
|
54
|
+
| @forgezero/agent/bootstrap-bundle | Owner-only exact-revision Git bundle and SHA-256 manifest for credential-free release generation one. | Bun/Node host | [Details + example](#forgezero-agent-bootstrap-bundle) |
|
|
54
55
|
| @forgezero/agent/operator-bootstrap | Pinned-host operator transport that stages owner-only handoffs and invokes the same typed platform bootstrap through the caller-approved SSH agent. | Bun/Node host | [Details + example](#forgezero-agent-operator-bootstrap) |
|
|
55
56
|
| @forgezero/agent/host-maintenance | Closed host maintenance plans for staging transaction rehearsal and fleet-fenced schema consolidation through fixed transient systemd units. | Bun/Node host | [Details + example](#forgezero-agent-host-maintenance) |
|
|
56
57
|
| @forgezero/agent/capacity-calibration | One-time target-local safe-concurrency calibration with private evidence. | Bun/Node host | [Details + example](#forgezero-agent-capacity-calibration) |
|
|
@@ -82,7 +83,8 @@ bun add -g @forgezero/agent — Install the version-matched fz operator CLI and
|
|
|
82
83
|
fz deploy init — Create a typed forgezero.deploy.ts and its canonical inert execution plan.
|
|
83
84
|
fz deploy compile — Compile and validate TypeScript deployment intent into .fz/deploy.plan.json.
|
|
84
85
|
fz deploy check — Refuse stale plans, unsafe provider/action coordinates and unresolved deployment blockers.
|
|
85
|
-
fz bootstrap platform
|
|
86
|
+
fz bootstrap platform bundle --root /absolute/api --branch dev --output /secure/forgezero/development/api.bundle — Build one verified release-generation-one source bundle without a Git credential.
|
|
87
|
+
fz bootstrap platform remote apply --bootstrap-config /secure/forgezero/development/dev-fz-n1-remote.json — Dry-plan one pinned operator-to-guest bootstrap; add --apply only after review.
|
|
86
88
|
fz bootstrap platform --help — Inspect attended platform bootstrap inputs before applying them.
|
|
87
89
|
fz bootstrap metal --help — Inspect the identity-only physical provisioner bootstrap.
|
|
88
90
|
fz host transactions|schema-plan|schema-apply — Plan fixed supervised database maintenance; add --apply only after reviewing the exact argv and credential names.
|
|
@@ -93,7 +95,8 @@ bun add -g @forgezero/agent
|
|
|
93
95
|
fz deploy init
|
|
94
96
|
fz deploy compile
|
|
95
97
|
fz deploy check
|
|
96
|
-
fz bootstrap platform
|
|
98
|
+
fz bootstrap platform bundle --root /absolute/api --branch dev --output /secure/forgezero/development/api.bundle
|
|
99
|
+
fz bootstrap platform remote apply --bootstrap-config /secure/forgezero/development/dev-fz-n1-remote.json
|
|
97
100
|
fz bootstrap platform --help
|
|
98
101
|
fz bootstrap metal --help
|
|
99
102
|
fz host transactions|schema-plan|schema-apply
|
|
@@ -278,15 +281,39 @@ import type { AgentUpdateOutcome, AgentUpdateReceipt, AgentUpdateRequest, AgentU
|
|
|
278
281
|
<a id="forgezero-agent-bootstrap"></a>
|
|
279
282
|
## @forgezero/agent/bootstrap
|
|
280
283
|
|
|
281
|
-
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,
|
|
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.
|
|
282
285
|
|
|
283
286
|
```text
|
|
284
287
|
import { BOOTSTRAP_STATE_PATH, PLATFORM_BOOTSTRAP_PROFILES, applyBootstrap, bootstrapIdentityDigest, bootstrapStatus, localBootstrapHost } from '@forgezero/agent/bootstrap';
|
|
285
|
-
import { planBootstrap,
|
|
286
|
-
import { validatePlatformBootstrapSecrets } from '@forgezero/agent/bootstrap';
|
|
288
|
+
import { planBootstrap, readBootstrapConfig, resolveInstalledBootstrapKind, validateBootstrapConfig, validateEnrolledComputeBootstrapSecrets, validatePlatformBootstrapSecrets } from '@forgezero/agent/bootstrap';
|
|
287
289
|
import type { BootstrapConfig, BootstrapEnvironment, BootstrapHost, BootstrapPlan, BootstrapResult, BootstrapSecrets } from '@forgezero/agent/bootstrap';
|
|
288
290
|
import type { BootstrapStatus, BootstrapStep, DatabaseAgencyParticipation, DatabaseBootstrapRole, EnrolledComputeActivationConfig, EnrolledComputeBootstrapSecrets } from '@forgezero/agent/bootstrap';
|
|
289
|
-
import type { InstalledBootstrapKind, PlatformBootstrapConfig,
|
|
291
|
+
import type { InstalledBootstrapKind, PlatformBootstrapConfig, PlatformBootstrapProfile, PlatformBootstrapSecrets, PlatformEnrolmentSource } from '@forgezero/agent/bootstrap';
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
<a id="forgezero-agent-bootstrap-bundle"></a>
|
|
295
|
+
## @forgezero/agent/bootstrap-bundle
|
|
296
|
+
|
|
297
|
+
Owner-only exact-revision Git bundle and SHA-256 manifest for credential-free release generation one. Named value imports: BOOTSTRAP_BUNDLE_FORMAT, BOOTSTRAP_BUNDLE_KIND, MAX_BOOTSTRAP_BUNDLE_BYTES, buildBootstrapBundle, parseBootstrapBundleManifest, readBootstrapBundle, sha256File. Named type imports: BootstrapBundleBuildInput, BootstrapBundleBuildResult, BootstrapBundleCommand, BootstrapBundleCommandResult, BootstrapBundleManifest. Import only the names used by this file.
|
|
298
|
+
|
|
299
|
+
```text
|
|
300
|
+
import { BOOTSTRAP_BUNDLE_FORMAT, BOOTSTRAP_BUNDLE_KIND, MAX_BOOTSTRAP_BUNDLE_BYTES, buildBootstrapBundle, parseBootstrapBundleManifest, readBootstrapBundle } from '@forgezero/agent/bootstrap-bundle';
|
|
301
|
+
import { sha256File } from '@forgezero/agent/bootstrap-bundle';
|
|
302
|
+
import type { BootstrapBundleBuildInput, BootstrapBundleBuildResult, BootstrapBundleCommand, BootstrapBundleCommandResult, BootstrapBundleManifest } from '@forgezero/agent/bootstrap-bundle';
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## @forgezero/agent/bootstrap-bundle — Build release generation one without a deploy key
|
|
306
|
+
|
|
307
|
+
The builder refuses tracked drift, resolves one exact commit, creates an owner-only Git bundle and writes a byte-count/SHA-256 manifest. Bootstrap consumes the artifact after activation.
|
|
308
|
+
|
|
309
|
+
```text
|
|
310
|
+
import { buildBootstrapBundle, readBootstrapBundle } from '@forgezero/agent/bootstrap-bundle';
|
|
311
|
+
|
|
312
|
+
const built = await buildBootstrapBundle({
|
|
313
|
+
repositoryRoot: '/work/forgezero-api', branch: 'main',
|
|
314
|
+
outputPath: '/secure/forgezero/production/api.bundle'
|
|
315
|
+
});
|
|
316
|
+
await readBootstrapBundle(built.bundlePath, built.manifestPath);
|
|
290
317
|
```
|
|
291
318
|
|
|
292
319
|
<a id="forgezero-agent-operator-bootstrap"></a>
|
|
@@ -302,14 +329,12 @@ import type { OperatorPlatformBootstrapOptions, OperatorPlatformBootstrapPlan, O
|
|
|
302
329
|
|
|
303
330
|
## @forgezero/agent/operator-bootstrap — Run the same typed platform bootstrap from an operator laptop
|
|
304
331
|
|
|
305
|
-
The request contains
|
|
332
|
+
The request contains the pinned SSH transport, reviewed platform config, and one verified local Git bundle copied identically to every genesis compute. No repository key is created. Hidden credential values are sealed immediately as systemd credentials.
|
|
306
333
|
|
|
307
334
|
```text
|
|
308
|
-
fz bootstrap platform remote
|
|
309
|
-
--bootstrap-config /secure/forgezero/development/dev-fz-n1-remote.json
|
|
335
|
+
fz bootstrap platform remote apply --bootstrap-config /secure/forgezero/development/dev-fz-n1-remote.json
|
|
310
336
|
# Review, then allow the SSH-agent approval prompt:
|
|
311
|
-
fz bootstrap platform remote
|
|
312
|
-
--bootstrap-config /secure/forgezero/development/dev-fz-n1-remote.json --apply
|
|
337
|
+
fz bootstrap platform remote apply --bootstrap-config /secure/forgezero/development/dev-fz-n1-remote.json --apply
|
|
313
338
|
```
|
|
314
339
|
|
|
315
340
|
<a id="forgezero-agent-host-maintenance"></a>
|
package/dist/agent-heartbeat.js
CHANGED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export declare const BOOTSTRAP_BUNDLE_FORMAT: 1;
|
|
2
|
+
export declare const BOOTSTRAP_BUNDLE_KIND: "forgezero-api-git-bundle";
|
|
3
|
+
export declare const MAX_BOOTSTRAP_BUNDLE_BYTES: number;
|
|
4
|
+
export interface BootstrapBundleManifest {
|
|
5
|
+
format: typeof BOOTSTRAP_BUNDLE_FORMAT;
|
|
6
|
+
kind: typeof BOOTSTRAP_BUNDLE_KIND;
|
|
7
|
+
branch: string;
|
|
8
|
+
revision: string;
|
|
9
|
+
sha256: string;
|
|
10
|
+
bytes: number;
|
|
11
|
+
createdAt: string;
|
|
12
|
+
}
|
|
13
|
+
export interface BootstrapBundleBuildInput {
|
|
14
|
+
repositoryRoot: string;
|
|
15
|
+
outputPath: string;
|
|
16
|
+
branch: string;
|
|
17
|
+
}
|
|
18
|
+
export interface BootstrapBundleBuildResult {
|
|
19
|
+
bundlePath: string;
|
|
20
|
+
manifestPath: string;
|
|
21
|
+
manifest: BootstrapBundleManifest;
|
|
22
|
+
}
|
|
23
|
+
export interface BootstrapBundleCommandResult {
|
|
24
|
+
exitCode: number;
|
|
25
|
+
output: string;
|
|
26
|
+
}
|
|
27
|
+
export type BootstrapBundleCommand = (argv: readonly string[]) => Promise<BootstrapBundleCommandResult>;
|
|
28
|
+
export declare function sha256File(path: string): Promise<string>;
|
|
29
|
+
export declare function parseBootstrapBundleManifest(value: unknown): BootstrapBundleManifest;
|
|
30
|
+
export declare function readBootstrapBundle(bundlePath: string, manifestPath?: string): Promise<BootstrapBundleBuildResult>;
|
|
31
|
+
export declare function buildBootstrapBundle(input: BootstrapBundleBuildInput, exec?: BootstrapBundleCommand): Promise<BootstrapBundleBuildResult>;
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
// @bun
|
|
2
|
+
// src/bootstrap-bundle.ts
|
|
3
|
+
import { createHash, randomBytes } from "crypto";
|
|
4
|
+
import {
|
|
5
|
+
chmodSync,
|
|
6
|
+
createReadStream,
|
|
7
|
+
existsSync,
|
|
8
|
+
lstatSync,
|
|
9
|
+
mkdirSync,
|
|
10
|
+
readFileSync,
|
|
11
|
+
renameSync,
|
|
12
|
+
rmSync,
|
|
13
|
+
writeFileSync
|
|
14
|
+
} from "fs";
|
|
15
|
+
import { dirname, isAbsolute, resolve } from "path";
|
|
16
|
+
var BOOTSTRAP_BUNDLE_FORMAT = 1;
|
|
17
|
+
var BOOTSTRAP_BUNDLE_KIND = "forgezero-api-git-bundle";
|
|
18
|
+
var MAX_BOOTSTRAP_BUNDLE_BYTES = 512 * 1024 * 1024;
|
|
19
|
+
var run = async (argv) => {
|
|
20
|
+
const child = Bun.spawn([...argv], { stdin: "ignore", stdout: "pipe", stderr: "pipe" });
|
|
21
|
+
const [stdout, stderr, exitCode] = await Promise.all([
|
|
22
|
+
new Response(child.stdout).text(),
|
|
23
|
+
new Response(child.stderr).text(),
|
|
24
|
+
child.exited
|
|
25
|
+
]);
|
|
26
|
+
return { exitCode, output: `${stdout}${stderr}`.slice(0, 65536) };
|
|
27
|
+
};
|
|
28
|
+
var checked = async (exec, argv, label) => {
|
|
29
|
+
const result = await exec(argv);
|
|
30
|
+
if (result.exitCode !== 0)
|
|
31
|
+
throw new Error(`${label} failed${result.output.trim() ? `: ${result.output.trim()}` : ""}`);
|
|
32
|
+
return result.output.trim();
|
|
33
|
+
};
|
|
34
|
+
async function sha256File(path) {
|
|
35
|
+
const hash = createHash("sha256");
|
|
36
|
+
await new Promise((resolveDone, reject) => {
|
|
37
|
+
const stream = createReadStream(path);
|
|
38
|
+
stream.on("data", (chunk) => hash.update(chunk));
|
|
39
|
+
stream.on("error", reject);
|
|
40
|
+
stream.on("end", resolveDone);
|
|
41
|
+
});
|
|
42
|
+
return hash.digest("hex");
|
|
43
|
+
}
|
|
44
|
+
var branchName = (value) => {
|
|
45
|
+
if (typeof value !== "string" || !/^[A-Za-z0-9](?:[A-Za-z0-9._/-]{0,126}[A-Za-z0-9])?$/.test(value) || value.includes("..") || value.includes("//") || value.startsWith("-")) {
|
|
46
|
+
throw new Error("bootstrap bundle branch is malformed");
|
|
47
|
+
}
|
|
48
|
+
return value;
|
|
49
|
+
};
|
|
50
|
+
function parseBootstrapBundleManifest(value) {
|
|
51
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
52
|
+
throw new Error("bootstrap bundle manifest must be an object");
|
|
53
|
+
const source = value;
|
|
54
|
+
const allowed = ["format", "kind", "branch", "revision", "sha256", "bytes", "createdAt"];
|
|
55
|
+
const unknown = Object.keys(source).filter((key) => !allowed.includes(key));
|
|
56
|
+
if (unknown.length)
|
|
57
|
+
throw new Error(`bootstrap bundle manifest contains unknown field ${unknown[0]}`);
|
|
58
|
+
if (source.format !== BOOTSTRAP_BUNDLE_FORMAT || source.kind !== BOOTSTRAP_BUNDLE_KIND) {
|
|
59
|
+
throw new Error("bootstrap bundle manifest format is unsupported");
|
|
60
|
+
}
|
|
61
|
+
branchName(source.branch);
|
|
62
|
+
if (typeof source.revision !== "string" || !/^[a-f0-9]{40}$/.test(source.revision)) {
|
|
63
|
+
throw new Error("bootstrap bundle revision must be an exact lowercase Git commit");
|
|
64
|
+
}
|
|
65
|
+
if (typeof source.sha256 !== "string" || !/^[a-f0-9]{64}$/.test(source.sha256)) {
|
|
66
|
+
throw new Error("bootstrap bundle digest is malformed");
|
|
67
|
+
}
|
|
68
|
+
if (!Number.isSafeInteger(source.bytes) || Number(source.bytes) < 1 || Number(source.bytes) > MAX_BOOTSTRAP_BUNDLE_BYTES) {
|
|
69
|
+
throw new Error("bootstrap bundle size is outside the supported boundary");
|
|
70
|
+
}
|
|
71
|
+
if (typeof source.createdAt !== "string" || Number.isNaN(Date.parse(source.createdAt))) {
|
|
72
|
+
throw new Error("bootstrap bundle creation time is malformed");
|
|
73
|
+
}
|
|
74
|
+
return source;
|
|
75
|
+
}
|
|
76
|
+
function ownerRegularFile(path, maximum, label) {
|
|
77
|
+
if (!isAbsolute(path) || resolve(path) !== path || /[\r\n\0]/.test(path)) {
|
|
78
|
+
throw new Error(`${label} path must be canonical and absolute`);
|
|
79
|
+
}
|
|
80
|
+
const value = lstatSync(path);
|
|
81
|
+
const uid = process.getuid?.() ?? value.uid;
|
|
82
|
+
if (!value.isFile() || value.isSymbolicLink() || value.uid !== uid || value.nlink !== 1 || (value.mode & 63) !== 0 || value.size < 1 || value.size > maximum) {
|
|
83
|
+
throw new Error(`${label} must be an owner-only regular file with one link and at most ${maximum} bytes`);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
async function readBootstrapBundle(bundlePath, manifestPath = `${bundlePath}.json`) {
|
|
87
|
+
ownerRegularFile(bundlePath, MAX_BOOTSTRAP_BUNDLE_BYTES, "bootstrap bundle");
|
|
88
|
+
ownerRegularFile(manifestPath, 16 * 1024, "bootstrap bundle manifest");
|
|
89
|
+
let parsed;
|
|
90
|
+
try {
|
|
91
|
+
parsed = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
92
|
+
} catch {
|
|
93
|
+
throw new Error("bootstrap bundle manifest is not valid JSON");
|
|
94
|
+
}
|
|
95
|
+
const manifest = parseBootstrapBundleManifest(parsed);
|
|
96
|
+
const size = lstatSync(bundlePath).size;
|
|
97
|
+
if (size !== manifest.bytes || await sha256File(bundlePath) !== manifest.sha256) {
|
|
98
|
+
throw new Error("bootstrap bundle bytes do not match their manifest");
|
|
99
|
+
}
|
|
100
|
+
return { bundlePath, manifestPath, manifest };
|
|
101
|
+
}
|
|
102
|
+
async function buildBootstrapBundle(input, exec = run) {
|
|
103
|
+
const repositoryRoot = resolve(input.repositoryRoot);
|
|
104
|
+
const outputPath = resolve(input.outputPath);
|
|
105
|
+
const manifestPath = `${outputPath}.json`;
|
|
106
|
+
const branch = branchName(input.branch);
|
|
107
|
+
if (!isAbsolute(input.outputPath) || outputPath !== input.outputPath) {
|
|
108
|
+
throw new Error("bootstrap bundle output must be a canonical absolute path");
|
|
109
|
+
}
|
|
110
|
+
if (existsSync(outputPath) || existsSync(manifestPath)) {
|
|
111
|
+
throw new Error("bootstrap bundle output already exists");
|
|
112
|
+
}
|
|
113
|
+
const root = lstatSync(repositoryRoot);
|
|
114
|
+
if (!root.isDirectory() || root.isSymbolicLink())
|
|
115
|
+
throw new Error("bootstrap bundle source must be a real directory");
|
|
116
|
+
mkdirSync(dirname(outputPath), { recursive: true, mode: 448 });
|
|
117
|
+
const parent = lstatSync(dirname(outputPath));
|
|
118
|
+
const uid = process.getuid?.() ?? parent.uid;
|
|
119
|
+
if (!parent.isDirectory() || parent.isSymbolicLink() || parent.uid !== uid || (parent.mode & 63) !== 0) {
|
|
120
|
+
throw new Error("bootstrap bundle output directory must be caller-owned and owner-only");
|
|
121
|
+
}
|
|
122
|
+
const dirty = await checked(exec, ["git", "-C", repositoryRoot, "status", "--porcelain=v1", "--untracked-files=no"], "Git worktree check");
|
|
123
|
+
if (dirty)
|
|
124
|
+
throw new Error("bootstrap bundle source has tracked changes; commit the reviewed API release first");
|
|
125
|
+
const revision = (await checked(exec, ["git", "-C", repositoryRoot, "rev-parse", "--verify", `refs/heads/${branch}^{commit}`], "Git branch resolution")).toLowerCase();
|
|
126
|
+
if (!/^[a-f0-9]{40}$/.test(revision))
|
|
127
|
+
throw new Error("bootstrap bundle branch did not resolve to one exact commit");
|
|
128
|
+
const temporary = `${outputPath}.next.${process.pid}.${randomBytes(6).toString("hex")}`;
|
|
129
|
+
try {
|
|
130
|
+
await checked(exec, ["git", "-C", repositoryRoot, "bundle", "create", temporary, `refs/heads/${branch}`], "Git bundle creation");
|
|
131
|
+
chmodSync(temporary, 384);
|
|
132
|
+
const file = lstatSync(temporary);
|
|
133
|
+
if (!file.isFile() || file.isSymbolicLink() || file.size < 1 || file.size > MAX_BOOTSTRAP_BUNDLE_BYTES) {
|
|
134
|
+
throw new Error("created bootstrap bundle is outside the supported boundary");
|
|
135
|
+
}
|
|
136
|
+
await checked(exec, ["git", "bundle", "verify", temporary], "Git bundle verification");
|
|
137
|
+
const manifest = {
|
|
138
|
+
format: BOOTSTRAP_BUNDLE_FORMAT,
|
|
139
|
+
kind: BOOTSTRAP_BUNDLE_KIND,
|
|
140
|
+
branch,
|
|
141
|
+
revision,
|
|
142
|
+
sha256: await sha256File(temporary),
|
|
143
|
+
bytes: file.size,
|
|
144
|
+
createdAt: new Date().toISOString()
|
|
145
|
+
};
|
|
146
|
+
const manifestTemporary = `${manifestPath}.next.${process.pid}.${randomBytes(6).toString("hex")}`;
|
|
147
|
+
writeFileSync(manifestTemporary, `${JSON.stringify(manifest, null, 2)}
|
|
148
|
+
`, { mode: 384, flag: "wx" });
|
|
149
|
+
renameSync(temporary, outputPath);
|
|
150
|
+
renameSync(manifestTemporary, manifestPath);
|
|
151
|
+
return { bundlePath: outputPath, manifestPath, manifest };
|
|
152
|
+
} catch (cause) {
|
|
153
|
+
rmSync(temporary, { force: true });
|
|
154
|
+
throw cause;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
export {
|
|
158
|
+
sha256File,
|
|
159
|
+
readBootstrapBundle,
|
|
160
|
+
parseBootstrapBundleManifest,
|
|
161
|
+
buildBootstrapBundle,
|
|
162
|
+
MAX_BOOTSTRAP_BUNDLE_BYTES,
|
|
163
|
+
BOOTSTRAP_BUNDLE_KIND,
|
|
164
|
+
BOOTSTRAP_BUNDLE_FORMAT
|
|
165
|
+
};
|
package/dist/bootstrap.d.ts
CHANGED
|
@@ -15,8 +15,11 @@ export interface PlatformBootstrapConfig {
|
|
|
15
15
|
computeReference: string;
|
|
16
16
|
nodeHostname: string;
|
|
17
17
|
apiUrl: string;
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
/** One attended local source used only for release generation one. */
|
|
19
|
+
bootstrapBundle: {
|
|
20
|
+
bundleFile: string;
|
|
21
|
+
manifestFile: string;
|
|
22
|
+
};
|
|
20
23
|
deployRoot?: string;
|
|
21
24
|
telemetryEndpoint: string;
|
|
22
25
|
/**
|
|
@@ -76,6 +79,8 @@ export interface EnrolledComputeActivationConfig {
|
|
|
76
79
|
profile?: string;
|
|
77
80
|
deployRoot?: string;
|
|
78
81
|
software?: SoftwareRequirement[];
|
|
82
|
+
/** Compatibility-only per-node SSH deploy key. GitHub App is the scalable default. */
|
|
83
|
+
gitDeployKey?: boolean;
|
|
79
84
|
installCloudflared?: boolean;
|
|
80
85
|
installWarp?: boolean;
|
|
81
86
|
/** Optional node-specific attended Tunnel/KV/Mesh handoff, identical to platform hosts. */
|
|
@@ -136,13 +141,6 @@ export interface BootstrapResult {
|
|
|
136
141
|
inviteUrl: string;
|
|
137
142
|
};
|
|
138
143
|
}
|
|
139
|
-
export interface PlatformBootstrapPreparation {
|
|
140
|
-
kind: 'platform';
|
|
141
|
-
prepared: true;
|
|
142
|
-
identityDigest: string;
|
|
143
|
-
gitPublicKey: string;
|
|
144
|
-
next: 'register this read-only deploy key, then run --apply concurrently on all three genesis Agency members';
|
|
145
|
-
}
|
|
146
144
|
export interface BootstrapStatus {
|
|
147
145
|
initialized: boolean;
|
|
148
146
|
kind?: BootstrapConfig['kind'];
|
|
@@ -182,14 +180,6 @@ export declare const BOOTSTRAP_STATE_PATH = "/var/lib/forgezero/bootstrap.json";
|
|
|
182
180
|
export declare function validateBootstrapConfig(value: BootstrapConfig): BootstrapConfig;
|
|
183
181
|
export declare function planBootstrap(input: BootstrapConfig, initialized?: boolean): BootstrapPlan;
|
|
184
182
|
export declare function bootstrapIdentityDigest(config: BootstrapConfig): string;
|
|
185
|
-
/**
|
|
186
|
-
* Install only the common Agent boundary and generate its machine-local Git
|
|
187
|
-
* identity. Private repositories cannot be deployed until the owner registers
|
|
188
|
-
* this public key, so pretending one monolithic first command can do both is a
|
|
189
|
-
* sequencing bug. The bound intent makes the later apply resumable and refuses
|
|
190
|
-
* a different config after this first privileged mutation.
|
|
191
|
-
*/
|
|
192
|
-
export declare function preparePlatformBootstrap(input: PlatformBootstrapConfig, host?: BootstrapHost): Promise<PlatformBootstrapPreparation>;
|
|
193
183
|
export declare function bootstrapStatus(host?: BootstrapHost): Promise<BootstrapStatus>;
|
|
194
184
|
export declare function applyBootstrap(input: BootstrapConfig, host?: BootstrapHost, secrets?: BootstrapSecrets, dependencies?: {
|
|
195
185
|
fetcher?: typeof fetch;
|