@crewhaus/sandbox-image-java 0.1.3 → 0.1.5

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.
@@ -0,0 +1,22 @@
1
+ import { type SandboxImageEntry } from "@crewhaus/sandbox-image-registry";
2
+ /**
3
+ * Catalog R8 `sandbox-image-java` — Section 36 polyglot Java sandbox image.
4
+ *
5
+ * Java 11+ supports running .java source files directly via `java <File>.java`,
6
+ * so snippet mode skips the explicit javac step. Default entrypoint is
7
+ * `["java"]`; tool-code-execution callers extend with the source file path.
8
+ *
9
+ * Cold-start budget: ≤2s for the compiled-language warm pool. The JVM's
10
+ * `java -version` boot is ~250ms on warm hosts and stays well under
11
+ * budget; full compile+run round-trips can take longer (1-3s) and
12
+ * should be invoked with a per-call timeoutMs override.
13
+ *
14
+ * Layer R8.
15
+ */
16
+ export declare const JAVA_IMAGE_ID = "java";
17
+ export declare const JAVA_IMAGE_REF = "eclipse-temurin:21-alpine";
18
+ export declare const JAVA_DEFAULT_ENTRYPOINT: ReadonlyArray<string>;
19
+ export declare const JAVA_HEALTHCHECK_ARGV: ReadonlyArray<string>;
20
+ /** Cold-start budget for the warm pool (ms). T7 layer asserts this. */
21
+ export declare const JAVA_COLD_START_BUDGET_MS = 2000;
22
+ export declare function registerJavaSandboxImage(): SandboxImageEntry;
@@ -1,5 +1,4 @@
1
- import { type SandboxImageEntry, registerSandboxImage } from "@crewhaus/sandbox-image-registry";
2
-
1
+ import { registerSandboxImage } from "@crewhaus/sandbox-image-registry";
3
2
  /**
4
3
  * Catalog R8 `sandbox-image-java` — Section 36 polyglot Java sandbox image.
5
4
  *
@@ -14,26 +13,22 @@ import { type SandboxImageEntry, registerSandboxImage } from "@crewhaus/sandbox-
14
13
  *
15
14
  * Layer R8.
16
15
  */
17
-
18
16
  export const JAVA_IMAGE_ID = "java";
19
17
  export const JAVA_IMAGE_REF = "eclipse-temurin:21-alpine";
20
- export const JAVA_DEFAULT_ENTRYPOINT: ReadonlyArray<string> = ["java"];
21
- export const JAVA_HEALTHCHECK_ARGV: ReadonlyArray<string> = ["java", "-version"];
22
-
18
+ export const JAVA_DEFAULT_ENTRYPOINT = ["java"];
19
+ export const JAVA_HEALTHCHECK_ARGV = ["java", "-version"];
23
20
  /** Cold-start budget for the warm pool (ms). T7 layer asserts this. */
24
21
  export const JAVA_COLD_START_BUDGET_MS = 2_000;
25
-
26
- export function registerJavaSandboxImage(): SandboxImageEntry {
27
- return registerSandboxImage({
28
- id: JAVA_IMAGE_ID,
29
- image: JAVA_IMAGE_REF,
30
- defaultEntrypoint: JAVA_DEFAULT_ENTRYPOINT,
31
- healthcheck: {
32
- command: JAVA_HEALTHCHECK_ARGV,
33
- expectedExitCode: 0,
34
- timeoutMs: JAVA_COLD_START_BUDGET_MS,
35
- },
36
- description:
37
- "JDK 21 (Eclipse Temurin alpine) — snippet mode via `java <File>.java` (Java 11+); compiled-class mode for mounted projects.",
38
- });
22
+ export function registerJavaSandboxImage() {
23
+ return registerSandboxImage({
24
+ id: JAVA_IMAGE_ID,
25
+ image: JAVA_IMAGE_REF,
26
+ defaultEntrypoint: JAVA_DEFAULT_ENTRYPOINT,
27
+ healthcheck: {
28
+ command: JAVA_HEALTHCHECK_ARGV,
29
+ expectedExitCode: 0,
30
+ timeoutMs: JAVA_COLD_START_BUDGET_MS,
31
+ },
32
+ description: "JDK 21 (Eclipse Temurin alpine) — snippet mode via `java <File>.java` (Java 11+); compiled-class mode for mounted projects.",
33
+ });
39
34
  }
package/package.json CHANGED
@@ -1,20 +1,23 @@
1
1
  {
2
2
  "name": "@crewhaus/sandbox-image-java",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "JDK 21 polyglot sandbox image: registry registration + multi-stage Dockerfile + T2/T7/T8 contract tests (Section 36)",
6
- "main": "src/index.ts",
7
- "types": "src/index.ts",
6
+ "main": "dist/index.js",
7
+ "types": "dist/index.d.ts",
8
8
  "exports": {
9
- ".": "./src/index.ts"
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
10
13
  },
11
14
  "scripts": {
12
15
  "test": "bun test src"
13
16
  },
14
17
  "dependencies": {
15
- "@crewhaus/errors": "0.1.3",
16
- "@crewhaus/sandbox": "0.1.3",
17
- "@crewhaus/sandbox-image-registry": "0.1.3"
18
+ "@crewhaus/errors": "0.1.5",
19
+ "@crewhaus/sandbox": "0.1.5",
20
+ "@crewhaus/sandbox-image-registry": "0.1.5"
18
21
  },
19
22
  "license": "Apache-2.0",
20
23
  "author": {
@@ -34,5 +37,5 @@
34
37
  "publishConfig": {
35
38
  "access": "public"
36
39
  },
37
- "files": ["src", "README.md", "LICENSE", "NOTICE"]
40
+ "files": ["dist", "README.md", "LICENSE", "NOTICE"]
38
41
  }
package/src/index.test.ts DELETED
@@ -1,157 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from "bun:test";
2
- import { createSandbox } from "@crewhaus/sandbox";
3
- import {
4
- ImageRegistrationError,
5
- _resetSandboxImageRegistry,
6
- hasSandboxImage,
7
- listAllowedImageRefs,
8
- lookupSandboxImage,
9
- registerSandboxImage,
10
- } from "@crewhaus/sandbox-image-registry";
11
- import {
12
- JAVA_COLD_START_BUDGET_MS,
13
- JAVA_DEFAULT_ENTRYPOINT,
14
- JAVA_HEALTHCHECK_ARGV,
15
- JAVA_IMAGE_ID,
16
- JAVA_IMAGE_REF,
17
- registerJavaSandboxImage,
18
- } from "./index";
19
-
20
- describe("registerJavaSandboxImage (T1 + T2)", () => {
21
- beforeEach(() => _resetSandboxImageRegistry());
22
- afterEach(() => _resetSandboxImageRegistry());
23
-
24
- test("constants match the kickoff prompt's spec", () => {
25
- expect(JAVA_IMAGE_ID).toBe("java");
26
- expect(JAVA_IMAGE_REF).toBe("eclipse-temurin:21-alpine");
27
- expect(JAVA_DEFAULT_ENTRYPOINT).toEqual(["java"]);
28
- expect(JAVA_HEALTHCHECK_ARGV).toEqual(["java", "-version"]);
29
- });
30
-
31
- test("registerJavaSandboxImage() registers an image with the right shape", () => {
32
- const entry = registerJavaSandboxImage();
33
- expect(entry.id).toBe("java");
34
- expect(entry.image).toBe("eclipse-temurin:21-alpine");
35
- expect(entry.defaultEntrypoint).toEqual(["java"]);
36
- expect(entry.healthcheck.command).toEqual(["java", "-version"]);
37
- expect(entry.healthcheck.expectedExitCode).toBe(0);
38
- expect(entry.healthcheck.timeoutMs).toBe(JAVA_COLD_START_BUDGET_MS);
39
- expect(entry.description).toMatch(/JDK 21/);
40
- });
41
-
42
- test("lookupSandboxImage('java') returns the registered entry", () => {
43
- registerJavaSandboxImage();
44
- expect(hasSandboxImage("java")).toBe(true);
45
- expect(lookupSandboxImage("java").image).toBe("eclipse-temurin:21-alpine");
46
- });
47
-
48
- test("listAllowedImageRefs includes eclipse-temurin:21-alpine", () => {
49
- registerJavaSandboxImage();
50
- const refs = listAllowedImageRefs();
51
- expect(refs).toContain("eclipse-temurin:21-alpine");
52
- expect(refs).toContain("python:3.13-slim");
53
- });
54
- });
55
-
56
- describe("Java-shape T2 contract — round-trip via noop sandbox", () => {
57
- beforeEach(() => _resetSandboxImageRegistry());
58
- afterEach(() => _resetSandboxImageRegistry());
59
-
60
- test("noop sandbox accepts eclipse-temurin:21-alpine when registered", async () => {
61
- registerJavaSandboxImage();
62
- const sandbox = createSandbox({
63
- backend: "noop",
64
- allowedImages: listAllowedImageRefs(),
65
- });
66
- const result = await sandbox.exec({
67
- image: JAVA_IMAGE_REF,
68
- argv: ["printf", "hello-from-java"],
69
- });
70
- expect(result.exitCode).toBe(0);
71
- expect(result.stdout).toBe("hello-from-java");
72
- await sandbox.close();
73
- });
74
-
75
- test("noop sandbox refuses eclipse-temurin:21-alpine when NOT registered", async () => {
76
- const trioRefs = ["python:3.13-slim", "node:22-alpine", "alpine:3.19"];
77
- const sandbox = createSandbox({ backend: "noop", allowedImages: trioRefs });
78
- await expect(sandbox.exec({ image: JAVA_IMAGE_REF, argv: ["printf", "x"] })).rejects.toThrow(
79
- /not on the allowlist/,
80
- );
81
- await sandbox.close();
82
- });
83
- });
84
-
85
- describe("Java-shape T7 — cold-start budget", () => {
86
- beforeEach(() => _resetSandboxImageRegistry());
87
- afterEach(() => _resetSandboxImageRegistry());
88
-
89
- test("healthcheck timeoutMs is within the compiled-language budget (≤2s)", () => {
90
- const entry = registerJavaSandboxImage();
91
- expect(entry.healthcheck.timeoutMs).toBeLessThanOrEqual(2_000);
92
- expect(entry.healthcheck.timeoutMs).toBeGreaterThan(0);
93
- });
94
- });
95
-
96
- describe("Java-shape T8 — escape-attempt suite (reuses §18 corpus shape)", () => {
97
- beforeEach(() => _resetSandboxImageRegistry());
98
- afterEach(() => _resetSandboxImageRegistry());
99
-
100
- test("Java image registration is idempotent-then-rejected", () => {
101
- registerJavaSandboxImage();
102
- expect(() => registerJavaSandboxImage()).toThrow(/already registered/);
103
- });
104
-
105
- test("Java entry's image string passes registry validation", () => {
106
- expect(JAVA_IMAGE_REF.startsWith("-")).toBe(false);
107
- expect(/\s/.test(JAVA_IMAGE_REF)).toBe(false);
108
- expect(JAVA_IMAGE_REF.includes("\n")).toBe(false);
109
- });
110
-
111
- test("Java defaultEntrypoint contains no shell-meta", () => {
112
- for (const arg of JAVA_DEFAULT_ENTRYPOINT) {
113
- expect(/[;&|<>$`(){}]/.test(arg)).toBe(false);
114
- expect(arg.includes("\n")).toBe(false);
115
- }
116
- });
117
-
118
- test("Java healthcheck argv contains no shell-meta", () => {
119
- for (const arg of JAVA_HEALTHCHECK_ARGV) {
120
- expect(/[;&|<>$`(){}]/.test(arg)).toBe(false);
121
- expect(arg.includes("\n")).toBe(false);
122
- }
123
- });
124
-
125
- test("CLI-flag-injection registration via Java id is refused", () => {
126
- expect(() =>
127
- registerSandboxImage({
128
- id: "java",
129
- image: "--privileged",
130
- defaultEntrypoint: ["java"],
131
- healthcheck: { command: ["java", "-version"], expectedExitCode: 0 },
132
- }),
133
- ).toThrow(ImageRegistrationError);
134
- });
135
-
136
- test("whitespace-tampered Java image is refused", () => {
137
- expect(() =>
138
- registerSandboxImage({
139
- id: "java",
140
- image: "eclipse-temurin:21-alpine --privileged",
141
- defaultEntrypoint: ["java"],
142
- healthcheck: { command: ["java", "-version"], expectedExitCode: 0 },
143
- }),
144
- ).toThrow(/whitespace/);
145
- });
146
-
147
- test("shell-meta-tagged Java image is refused", () => {
148
- expect(() =>
149
- registerSandboxImage({
150
- id: "java",
151
- image: "eclipse-temurin:$(id)",
152
- defaultEntrypoint: ["java"],
153
- healthcheck: { command: ["java", "-version"], expectedExitCode: 0 },
154
- }),
155
- ).toThrow(/valid registry/);
156
- });
157
- });