javi-forge 1.15.1 → 1.16.0

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.
@@ -50,7 +50,8 @@ export async function handleCi(cli, ctx) {
50
50
  if (gates.length > 0) {
51
51
  console.log(` ${gates.length} gate(s):`);
52
52
  for (const gate of gates) {
53
- console.log(` - ${gate.id} (${gate.mode}, scope: ${gate.scope})`);
53
+ const image = gate.image !== undefined ? `, image: ${gate.image}` : "";
54
+ console.log(` - ${gate.id} (${gate.mode}, scope: ${gate.scope}${image})`);
54
55
  }
55
56
  }
56
57
  }
@@ -17,6 +17,8 @@ export interface CIValidateGateSummary {
17
17
  id: string;
18
18
  mode: string;
19
19
  scope: string;
20
+ /** Container image ref, present ONLY when the gate declares one. */
21
+ image?: string;
20
22
  }
21
23
  export interface CIValidateOk {
22
24
  ok: true;
@@ -59,6 +59,9 @@ export async function validateCIConfig(projectDir, config) {
59
59
  id: g.id,
60
60
  mode: g.mode,
61
61
  scope: g.scope,
62
+ // Surface `image` ONLY when declared, so an image-less gate summary
63
+ // stays byte-identical to today (no `image` key).
64
+ ...(g.image !== undefined ? { image: g.image } : {}),
62
65
  })),
63
66
  };
64
67
  }
@@ -60,6 +60,13 @@ export interface CIGateConfig {
60
60
  baseline?: string;
61
61
  /** Optional env injected via the child-process env map (slice 4). */
62
62
  env?: Record<string, string>;
63
+ /**
64
+ * Optional container image ref (containerized-gates). A plain,
65
+ * digest-pinnable image ref; when present the gate runs inside this image
66
+ * instead of host-native. Omitted → host-native (unchanged). Execution
67
+ * routing lands in a later slice; this slice validates the schema only.
68
+ */
69
+ image?: string;
63
70
  /**
64
71
  * Optional per-command wall-clock timeout in seconds (GATE-2). When set, a
65
72
  * command exceeding it is killed and the gate FAILS (non-zero). Omitted →
@@ -221,6 +221,7 @@ const GATE_FIELDS = new Set([
221
221
  "scope",
222
222
  "baseline",
223
223
  "env",
224
+ "image",
224
225
  "timeout",
225
226
  ]);
226
227
  function validateGate(raw, index, errors) {
@@ -318,6 +319,28 @@ function validateGate(raw, index, errors) {
318
319
  env = raw.env;
319
320
  }
320
321
  }
322
+ let image;
323
+ if (raw.image !== undefined) {
324
+ if (typeof raw.image !== "string" || !raw.image.trim()) {
325
+ errors.push({
326
+ path: `${base}.image`,
327
+ message: "image must be a non-empty string",
328
+ });
329
+ }
330
+ else if (raw.image.trim().startsWith("-")) {
331
+ // Harden against docker-flag injection: an image ref like "--privileged"
332
+ // or "-v /:/host" would be parsed by `docker run` as a FLAG, not an
333
+ // image argument, if it reached argv. Reject leading-dash refs at
334
+ // validation with a named error (JDB-004).
335
+ errors.push({
336
+ path: `${base}.image`,
337
+ message: "image must not start with '-' (would be parsed as a docker flag)",
338
+ });
339
+ }
340
+ else {
341
+ image = raw.image;
342
+ }
343
+ }
321
344
  let timeout;
322
345
  if (raw.timeout !== undefined) {
323
346
  if (typeof raw.timeout !== "number" ||
@@ -339,6 +362,7 @@ function validateGate(raw, index, errors) {
339
362
  scope,
340
363
  baseline,
341
364
  env,
365
+ image,
342
366
  timeout,
343
367
  };
344
368
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "javi-forge",
3
- "version": "1.15.1",
3
+ "version": "1.16.0",
4
4
  "description": "Project scaffolding and AI-ready CI bootstrap",
5
5
  "type": "module",
6
6
  "bin": {