@crewhaus/docker-images 0.1.1 → 0.1.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crewhaus/docker-images",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "type": "module",
5
5
  "description": "Per-target-shape Docker images (multi-stage, non-root, healthchecked) + crewhaus build-image CLI wrapper (Section 32)",
6
6
  "main": "src/index.ts",
@@ -12,13 +12,13 @@
12
12
  "test": "bun test src"
13
13
  },
14
14
  "dependencies": {
15
- "@crewhaus/errors": "0.1.1"
15
+ "@crewhaus/errors": "0.1.3"
16
16
  },
17
17
  "license": "Apache-2.0",
18
18
  "author": {
19
19
  "name": "Max Meier",
20
- "email": "max@studiomax.io",
21
- "url": "https://studiomax.io"
20
+ "email": "max@crewhaus.ai",
21
+ "url": "https://crewhaus.ai"
22
22
  },
23
23
  "repository": {
24
24
  "type": "git",
@@ -30,12 +30,7 @@
30
30
  "url": "https://github.com/crewhaus/factory/issues"
31
31
  },
32
32
  "publishConfig": {
33
- "access": "restricted"
33
+ "access": "public"
34
34
  },
35
- "files": [
36
- "src",
37
- "README.md",
38
- "LICENSE",
39
- "NOTICE"
40
- ]
35
+ "files": ["src", "README.md", "LICENSE", "NOTICE"]
41
36
  }
package/src/index.test.ts CHANGED
@@ -8,6 +8,8 @@ import {
8
8
  DockerImagesError,
9
9
  TARGET_SHAPES,
10
10
  buildImage,
11
+ defaultRunner,
12
+ digestsPath,
11
13
  dockerRoot,
12
14
  dockerfilePath,
13
15
  dockerfileSize,
@@ -61,6 +63,11 @@ describe("Dockerfiles on disk", () => {
61
63
  test("dockerRoot points inside the package", () => {
62
64
  expect(dockerRoot()).toMatch(/packages\/docker-images\/docker$/);
63
65
  });
66
+
67
+ test("digestsPath resolves to docker/digests.json inside the package", () => {
68
+ expect(digestsPath()).toMatch(/packages\/docker-images\/docker\/digests\.json$/);
69
+ expect(digestsPath()).toBe(join(dockerRoot(), "digests.json"));
70
+ });
64
71
  });
65
72
 
66
73
  describe("Dockerfile structural contract (T2)", () => {
@@ -252,3 +259,49 @@ CMD ["--help"]
252
259
  expect(fp.exposedPorts).toEqual([]);
253
260
  });
254
261
  });
262
+
263
+ describe("defaultRunner (spawn integration, deterministic)", () => {
264
+ // We drive the real spawn-based runner using the running JS binary
265
+ // (`process.execPath`) with `-e` — no docker, no network, no external
266
+ // service. argv[0] is the program; the rest are passed verbatim.
267
+ const exe = process.execPath;
268
+
269
+ test("captures stdout, stderr, and a zero exit code", async () => {
270
+ const result = await defaultRunner(
271
+ [exe, "-e", 'process.stdout.write("hello-out");process.stderr.write("hello-err")'],
272
+ process.cwd(),
273
+ );
274
+ expect(result.exitCode).toBe(0);
275
+ expect(result.stdout).toBe("hello-out");
276
+ expect(result.stderr).toBe("hello-err");
277
+ });
278
+
279
+ test("propagates a non-zero exit code", async () => {
280
+ const result = await defaultRunner(
281
+ [exe, "-e", 'process.stderr.write("boom");process.exit(7)'],
282
+ process.cwd(),
283
+ );
284
+ expect(result.exitCode).toBe(7);
285
+ expect(result.stderr).toBe("boom");
286
+ });
287
+
288
+ test("resolves with exitCode 1 when the program cannot be spawned (error event)", async () => {
289
+ const result = await defaultRunner(
290
+ ["./crewhaus-nonexistent-binary-9f3a2c", "--version"],
291
+ process.cwd(),
292
+ );
293
+ expect(result.exitCode).toBe(1);
294
+ expect(result.stdout).toBe("");
295
+ expect(result.stderr.length).toBeGreaterThan(0);
296
+ });
297
+
298
+ test("falls back to exitCode 1 when the child is killed by a signal (null code)", async () => {
299
+ // A child that SIGKILLs itself terminates via signal, so `close` fires with
300
+ // code === null — exercising the `code ?? 1` fallback deterministically.
301
+ const result = await defaultRunner(
302
+ [exe, "-e", "process.kill(process.pid, 'SIGKILL')"],
303
+ process.cwd(),
304
+ );
305
+ expect(result.exitCode).toBe(1);
306
+ });
307
+ });
package/src/index.ts CHANGED
@@ -152,7 +152,7 @@ export async function buildImage(opts: BuildImageOptions): Promise<BuildImageRes
152
152
  return { tag: opts.tag, target: opts.target, buildArgv: argv };
153
153
  }
154
154
 
155
- const defaultRunner: BuildRunner = async (argv, cwd) => {
155
+ export const defaultRunner: BuildRunner = async (argv, cwd) => {
156
156
  const { spawn } = await import("node:child_process");
157
157
  return new Promise((resolve_) => {
158
158
  const head = argv[0] ?? "docker";