@forgezero/agent 0.1.53 → 0.1.55

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.
@@ -4,6 +4,7 @@ import {
4
4
  accessSync,
5
5
  chmodSync,
6
6
  copyFileSync,
7
+ existsSync,
7
8
  mkdtempSync,
8
9
  mkdirSync,
9
10
  readFileSync,
@@ -24,6 +25,7 @@ var OS_CATALOG = [
24
25
  ];
25
26
  var SOFTWARE_CATALOG = [
26
27
  { id: "bun", version: "1.3.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
28
+ { id: "docker", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
27
29
  { id: "nginx", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
28
30
  { id: "arangodb", version: "3.11.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
29
31
  { id: "cloudflared", version: "2026.7.3", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
@@ -33,6 +35,7 @@ var SOFTWARE_CATALOG = [
33
35
  ];
34
36
  var UBUNTU_2604_X64 = [
35
37
  { requirement: { id: "bun", version: "1.3.14" } },
38
+ { requirement: { id: "docker", version: "ubuntu-26.04" } },
36
39
  { requirement: { id: "nginx", version: "ubuntu-26.04" } },
37
40
  { requirement: { id: "arangodb", version: "3.11.14" } },
38
41
  { requirement: { id: "cloudflared", version: "2026.7.3" } },
@@ -41,6 +44,15 @@ var UBUNTU_2604_X64 = [
41
44
  { requirement: { id: "openssh-client", version: "ubuntu-26.04" } }
42
45
  ];
43
46
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
47
+ var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
48
+ var DOCKER_DAEMON_CONFIG = `${JSON.stringify({
49
+ "data-root": "/var/lib/docker",
50
+ "storage-driver": "overlay2",
51
+ "live-restore": true,
52
+ "log-driver": "local",
53
+ "log-opts": { "max-size": "10m", "max-file": "3" }
54
+ }, null, 2)}
55
+ `;
44
56
  var softwareSpawnFailure = (cause, argv) => cause.code === "ENOENT" ? { exitCode: 127, output: `executable is absent: ${argv[0]}` } : undefined;
45
57
  var runSoftwareCommand = async (argv, env = {}) => {
46
58
  let child;
@@ -83,6 +95,15 @@ async function executeSoftwareOperation(operation) {
83
95
  if (operation.kind === "check") {
84
96
  if (software === "bun")
85
97
  return run(["/usr/local/bin/bun", "--version"]).then((r) => ({ ...r, exitCode: successful(r, /^1\.3\.14\s*$/m) ? 0 : 1 }));
98
+ if (software === "docker") {
99
+ const binary = await run(["/usr/bin/docker", "--version"]);
100
+ if (!successful(binary, /Docker version/))
101
+ return { ...binary, exitCode: 1 };
102
+ if (!existsSync(DOCKER_DAEMON_PATH) || readFileSync(DOCKER_DAEMON_PATH, "utf8") !== DOCKER_DAEMON_CONFIG)
103
+ return { exitCode: 1, output: "Docker daemon policy is absent or differs from the reviewed ForgeZero policy" };
104
+ const active = await run(["/usr/bin/systemctl", "is-active", "--quiet", "docker.service"]);
105
+ return active.exitCode === 0 ? { exitCode: 0, output: binary.output } : active;
106
+ }
86
107
  if (software === "nginx") {
87
108
  const binary = await run(["/usr/sbin/nginx", "-v"]);
88
109
  return binary.exitCode === 0 ? run(["/usr/bin/systemctl", "is-active", "--quiet", "nginx.service"]) : binary;
@@ -115,11 +136,22 @@ async function executeSoftwareOperation(operation) {
115
136
  return { exitCode: 1, output: cause instanceof Error ? cause.message : String(cause) };
116
137
  }
117
138
  }
118
- if (software === "nginx" || software === "ufw" || software === "openssh-client") {
119
- const installed = await aptInstall(software === "openssh-client" ? "openssh-client" : software);
120
- if (installed.exitCode !== 0 || software !== "nginx")
139
+ if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client") {
140
+ const packageName = software === "openssh-client" ? "openssh-client" : software === "docker" ? "docker.io" : software;
141
+ const installed = await aptInstall(packageName);
142
+ if (installed.exitCode !== 0 || software !== "nginx" && software !== "docker")
121
143
  return installed;
122
- return run(["/usr/bin/systemctl", "enable", "--now", "nginx.service"]);
144
+ if (software === "docker") {
145
+ mkdirSync("/etc/docker", { recursive: true, mode: 493 });
146
+ if (existsSync(DOCKER_DAEMON_PATH) && readFileSync(DOCKER_DAEMON_PATH, "utf8") !== DOCKER_DAEMON_CONFIG) {
147
+ return { exitCode: 2, output: "refusing to overwrite an existing Docker daemon configuration that differs from the reviewed ForgeZero policy" };
148
+ }
149
+ if (!existsSync(DOCKER_DAEMON_PATH))
150
+ writeFileSync(DOCKER_DAEMON_PATH, DOCKER_DAEMON_CONFIG, { mode: 420, flag: "wx" });
151
+ const enabled = await run(["/usr/bin/systemctl", "enable", "docker.service"]);
152
+ return enabled.exitCode === 0 ? run(["/usr/bin/systemctl", "restart", "docker.service"]) : enabled;
153
+ }
154
+ return run(["/usr/bin/systemctl", "enable", "--now", `${software}.service`]);
123
155
  }
124
156
  const directory = mkdtempSync(join(tmpdir(), "forgezero-software-"));
125
157
  try {
@@ -204,7 +236,7 @@ function validateSoftwareRequirements(value, _options = {}) {
204
236
  if (Object.keys(row).some((key) => key !== "id" && key !== "version")) {
205
237
  throw new Error("software requirement contains an unknown field");
206
238
  }
207
- if (!["bun", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
239
+ if (!["bun", "docker", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
208
240
  throw new Error("software requirement coordinate is invalid");
209
241
  }
210
242
  const requirement = { id: row.id, version: row.version };
@@ -0,0 +1,36 @@
1
+ import type { ApplicationComponent } from './deploy';
2
+ import type { ServiceActivationState } from './service-supervisor';
3
+ export interface ContainerBuildRequest {
4
+ key: string;
5
+ revision: string;
6
+ root: string;
7
+ release: string;
8
+ component: string;
9
+ application: ApplicationComponent;
10
+ noCache?: boolean;
11
+ }
12
+ export interface ContainerActivateRequest extends ContainerBuildRequest {
13
+ image: string;
14
+ }
15
+ export interface ContainerBuildResult {
16
+ image: string;
17
+ digest: string;
18
+ }
19
+ export interface ContainerHost {
20
+ realpath(path: string): string;
21
+ exists(path: string): boolean;
22
+ read(path: string): string;
23
+ write(path: string, content: string, mode: number): void;
24
+ remove(path: string): void;
25
+ list(path: string): string[];
26
+ mkdir(path: string, mode: number): void;
27
+ exec(argv: readonly string[]): Promise<{
28
+ exitCode: number;
29
+ output: string;
30
+ }>;
31
+ health(port: number, path: string, timeoutMs: number, method: 'GET' | 'HEAD', expectedStatus: readonly number[]): Promise<boolean>;
32
+ sleep(ms: number): Promise<void>;
33
+ now(): number;
34
+ }
35
+ export declare function buildContainerImage(requestValue: ContainerBuildRequest, host?: ContainerHost): Promise<ContainerBuildResult>;
36
+ export declare function activateContainer(requestValue: ContainerActivateRequest, host?: ContainerHost): Promise<ServiceActivationState>;
@@ -4,6 +4,7 @@ import {
4
4
  accessSync,
5
5
  chmodSync,
6
6
  copyFileSync,
7
+ existsSync,
7
8
  mkdtempSync,
8
9
  mkdirSync,
9
10
  readFileSync,
@@ -24,6 +25,7 @@ var OS_CATALOG = [
24
25
  ];
25
26
  var SOFTWARE_CATALOG = [
26
27
  { id: "bun", version: "1.3.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
28
+ { id: "docker", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
27
29
  { id: "nginx", version: "ubuntu-26.04", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
28
30
  { id: "arangodb", version: "3.11.14", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
29
31
  { id: "cloudflared", version: "2026.7.3", status: "active", os: "ubuntu", osVersion: "26.04", architecture: "x64", evidence: "reviewed-strategy-and-tests" },
@@ -33,6 +35,7 @@ var SOFTWARE_CATALOG = [
33
35
  ];
34
36
  var UBUNTU_2604_X64 = [
35
37
  { requirement: { id: "bun", version: "1.3.14" } },
38
+ { requirement: { id: "docker", version: "ubuntu-26.04" } },
36
39
  { requirement: { id: "nginx", version: "ubuntu-26.04" } },
37
40
  { requirement: { id: "arangodb", version: "3.11.14" } },
38
41
  { requirement: { id: "cloudflared", version: "2026.7.3" } },
@@ -41,6 +44,15 @@ var UBUNTU_2604_X64 = [
41
44
  { requirement: { id: "openssh-client", version: "ubuntu-26.04" } }
42
45
  ];
43
46
  var path = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin";
47
+ var DOCKER_DAEMON_PATH = "/etc/docker/daemon.json";
48
+ var DOCKER_DAEMON_CONFIG = `${JSON.stringify({
49
+ "data-root": "/var/lib/docker",
50
+ "storage-driver": "overlay2",
51
+ "live-restore": true,
52
+ "log-driver": "local",
53
+ "log-opts": { "max-size": "10m", "max-file": "3" }
54
+ }, null, 2)}
55
+ `;
44
56
  var softwareSpawnFailure = (cause, argv) => cause.code === "ENOENT" ? { exitCode: 127, output: `executable is absent: ${argv[0]}` } : undefined;
45
57
  var runSoftwareCommand = async (argv, env = {}) => {
46
58
  let child;
@@ -83,6 +95,15 @@ async function executeSoftwareOperation(operation) {
83
95
  if (operation.kind === "check") {
84
96
  if (software === "bun")
85
97
  return run(["/usr/local/bin/bun", "--version"]).then((r) => ({ ...r, exitCode: successful(r, /^1\.3\.14\s*$/m) ? 0 : 1 }));
98
+ if (software === "docker") {
99
+ const binary = await run(["/usr/bin/docker", "--version"]);
100
+ if (!successful(binary, /Docker version/))
101
+ return { ...binary, exitCode: 1 };
102
+ if (!existsSync(DOCKER_DAEMON_PATH) || readFileSync(DOCKER_DAEMON_PATH, "utf8") !== DOCKER_DAEMON_CONFIG)
103
+ return { exitCode: 1, output: "Docker daemon policy is absent or differs from the reviewed ForgeZero policy" };
104
+ const active = await run(["/usr/bin/systemctl", "is-active", "--quiet", "docker.service"]);
105
+ return active.exitCode === 0 ? { exitCode: 0, output: binary.output } : active;
106
+ }
86
107
  if (software === "nginx") {
87
108
  const binary = await run(["/usr/sbin/nginx", "-v"]);
88
109
  return binary.exitCode === 0 ? run(["/usr/bin/systemctl", "is-active", "--quiet", "nginx.service"]) : binary;
@@ -115,11 +136,22 @@ async function executeSoftwareOperation(operation) {
115
136
  return { exitCode: 1, output: cause instanceof Error ? cause.message : String(cause) };
116
137
  }
117
138
  }
118
- if (software === "nginx" || software === "ufw" || software === "openssh-client") {
119
- const installed = await aptInstall(software === "openssh-client" ? "openssh-client" : software);
120
- if (installed.exitCode !== 0 || software !== "nginx")
139
+ if (software === "docker" || software === "nginx" || software === "ufw" || software === "openssh-client") {
140
+ const packageName = software === "openssh-client" ? "openssh-client" : software === "docker" ? "docker.io" : software;
141
+ const installed = await aptInstall(packageName);
142
+ if (installed.exitCode !== 0 || software !== "nginx" && software !== "docker")
121
143
  return installed;
122
- return run(["/usr/bin/systemctl", "enable", "--now", "nginx.service"]);
144
+ if (software === "docker") {
145
+ mkdirSync("/etc/docker", { recursive: true, mode: 493 });
146
+ if (existsSync(DOCKER_DAEMON_PATH) && readFileSync(DOCKER_DAEMON_PATH, "utf8") !== DOCKER_DAEMON_CONFIG) {
147
+ return { exitCode: 2, output: "refusing to overwrite an existing Docker daemon configuration that differs from the reviewed ForgeZero policy" };
148
+ }
149
+ if (!existsSync(DOCKER_DAEMON_PATH))
150
+ writeFileSync(DOCKER_DAEMON_PATH, DOCKER_DAEMON_CONFIG, { mode: 420, flag: "wx" });
151
+ const enabled = await run(["/usr/bin/systemctl", "enable", "docker.service"]);
152
+ return enabled.exitCode === 0 ? run(["/usr/bin/systemctl", "restart", "docker.service"]) : enabled;
153
+ }
154
+ return run(["/usr/bin/systemctl", "enable", "--now", `${software}.service`]);
123
155
  }
124
156
  const directory = mkdtempSync(join(tmpdir(), "forgezero-software-"));
125
157
  try {
@@ -204,7 +236,7 @@ function validateSoftwareRequirements(value, _options = {}) {
204
236
  if (Object.keys(row).some((key) => key !== "id" && key !== "version")) {
205
237
  throw new Error("software requirement contains an unknown field");
206
238
  }
207
- if (!["bun", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
239
+ if (!["bun", "docker", "nginx", "arangodb", "cloudflared", "cloudflare-warp", "ufw", "openssh-client"].includes(String(row.id)) || typeof row.version !== "string" || !/^[A-Za-z0-9][A-Za-z0-9.-]{0,31}$/.test(row.version)) {
208
240
  throw new Error("software requirement coordinate is invalid");
209
241
  }
210
242
  const requirement = { id: row.id, version: row.version };
@@ -0,0 +1,87 @@
1
+ import { type ComponentDefinition, type Condition, type CredentialDefinition, type JsonObject, type RequirementDefinition, type RetryDefinition, type StepScope, type WorkflowStepDefinition } from './deploy';
2
+ interface StepOptions {
3
+ scope: StepScope;
4
+ if?: Condition;
5
+ timeoutMs?: number;
6
+ retry?: RetryDefinition;
7
+ failure?: WorkflowStepDefinition['failure'];
8
+ compensate?: WorkflowStepDefinition['compensate'];
9
+ }
10
+ export declare const actions: {
11
+ readonly software: {
12
+ readonly ensure: (withValue: {
13
+ requirements: readonly string[];
14
+ }, options: StepOptions) => WorkflowStepDefinition<{
15
+ requirements: readonly string[];
16
+ }>;
17
+ };
18
+ readonly exec: {
19
+ readonly argv: (withValue: {
20
+ component: string;
21
+ argv: readonly string[];
22
+ credentials?: Readonly<Record<string, string>>;
23
+ }, options: StepOptions) => WorkflowStepDefinition<{
24
+ component: string;
25
+ argv: readonly string[];
26
+ credentials?: Readonly<Record<string, string>>;
27
+ }>;
28
+ };
29
+ readonly container: {
30
+ readonly build: (withValue: {
31
+ component: string;
32
+ noCache?: boolean;
33
+ }, options: StepOptions) => WorkflowStepDefinition<{
34
+ component: string;
35
+ noCache?: boolean;
36
+ }>;
37
+ readonly pull: (withValue: {
38
+ component: string;
39
+ }, options: StepOptions) => WorkflowStepDefinition<{
40
+ component: string;
41
+ }>;
42
+ };
43
+ readonly service: {
44
+ readonly deploy: (withValue: {
45
+ component: string;
46
+ imageDigest?: string | {
47
+ $ref: `steps.${string}.outputs.${string}`;
48
+ };
49
+ }, options: StepOptions) => WorkflowStepDefinition<{
50
+ component: string;
51
+ imageDigest?: string | {
52
+ $ref: `steps.${string}.outputs.${string}`;
53
+ };
54
+ }>;
55
+ readonly health: (withValue: {
56
+ component: string;
57
+ }, options: StepOptions) => WorkflowStepDefinition<{
58
+ component: string;
59
+ }>;
60
+ readonly promote: (withValue: {
61
+ component: string;
62
+ imageDigest?: string | {
63
+ $ref: `steps.${string}.outputs.${string}`;
64
+ };
65
+ }, options: StepOptions) => WorkflowStepDefinition<{
66
+ component: string;
67
+ imageDigest?: string | {
68
+ $ref: `steps.${string}.outputs.${string}`;
69
+ };
70
+ }>;
71
+ };
72
+ readonly storage: {
73
+ readonly verify: (withValue: {
74
+ component: string;
75
+ }, options: StepOptions) => WorkflowStepDefinition<{
76
+ component: string;
77
+ }>;
78
+ };
79
+ readonly extension: <T extends JsonObject>(uses: `${string}@${number}`, withValue: T, options: StepOptions) => WorkflowStepDefinition<T>;
80
+ };
81
+ /** Close package-owned action inputs at runtime. Third-party actions stay namespaced and are closed by their installed handler contract. */
82
+ export declare function validateBuiltInAction(definition: WorkflowStepDefinition, context: {
83
+ components: Readonly<Record<string, ComponentDefinition>>;
84
+ requirements: Readonly<Record<string, RequirementDefinition>>;
85
+ credentials: Readonly<Record<string, CredentialDefinition>>;
86
+ }, where: string): void;
87
+ export {};
@@ -0,0 +1,26 @@
1
+ import { type DeploymentPlan } from './deploy-plan';
2
+ export declare const DEPLOY_SOURCE_FILE = "forgezero.deploy.ts";
3
+ export declare const DEPLOY_PLAN_FILE = ".fz/deploy.plan.json";
4
+ export interface DeploymentCompilation {
5
+ source: string;
6
+ output: string;
7
+ plan: DeploymentPlan;
8
+ digest: `sha256:${string}`;
9
+ changed: boolean;
10
+ }
11
+ export declare function defaultTypeScriptDeployment(name: string): string;
12
+ export declare function initializeTypeScriptDeployment(rootValue: string, options: {
13
+ name: string;
14
+ force?: boolean;
15
+ }): string;
16
+ export declare function loadDeploymentSource(root: string, sourceFile?: string): Promise<unknown>;
17
+ export declare function compileDeploymentProject(rootValue: string, options?: {
18
+ sourceFile?: string;
19
+ outputFile?: string;
20
+ write?: boolean;
21
+ }): Promise<DeploymentCompilation>;
22
+ export declare function inspectCompiledDeployment(rootValue: string, outputFile?: string): {
23
+ path: string;
24
+ plan: DeploymentPlan;
25
+ digest: `sha256:${string}`;
26
+ };