@invarn/cibuild 1.5.3 → 1.5.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.
@@ -1 +1 @@
1
- {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/run.ts"],"names":[],"mappings":"AAcA,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAuI3E"}
1
+ {"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../../src/commands/run.ts"],"names":[],"mappings":"AAeA,MAAM,WAAW,UAAU;IACzB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CA0I3E"}
@@ -6,7 +6,7 @@ import { PipelineRunner } from "../runner.js";
6
6
  import { loadConfig } from "../config.js";
7
7
  import { loadYAMLPipeline } from "../yaml/parser.js";
8
8
  import { convertYAMLWithSecrets } from "../yaml/pipeline-with-secrets.js";
9
- import { promptForWorkflow, promptForMissingVariables, } from "../shared/prompts.js";
9
+ import { promptForWorkflow, promptForMissingVariables, isInteractiveTTY, } from "../shared/prompts.js";
10
10
  /**
11
11
  * Run a pipeline locally. Mirrors `ci run <path>`.
12
12
  *
@@ -100,7 +100,10 @@ export async function handleRunCommand(opts = {}) {
100
100
  config,
101
101
  workflowName: selectedWorkflow,
102
102
  yamlFilePath: pipelinePath,
103
- interactive: true,
103
+ // Only prompt when stdin/stdout are real TTYs. Sandboxed runs
104
+ // (Tart guest, CI, `tart exec`, pipes) have no terminal and
105
+ // MUST fail with a clear message rather than hang on a prompt.
106
+ interactive: isInteractiveTTY(),
104
107
  });
105
108
  pipeline = conversionResult.pipeline;
106
109
  await runner.runPipeline(pipeline, conversionResult.warnings, conversionResult.skippedSteps);
@@ -1,5 +1,17 @@
1
1
  import type { YAMLPipeline } from "../yaml/types.js";
2
2
  import type { CIConfig } from "../types.js";
3
+ /**
4
+ * True only when stdin AND stdout are real TTYs AND the caller has not
5
+ * explicitly opted out of interactivity.
6
+ *
7
+ * `process.stdin.isTTY` is unreliable as a sole signal: Tart guest
8
+ * sessions opened via `tart exec` attach a pseudo-TTY, so the check
9
+ * passes and the prompt runs — only for nobody to ever answer it. The
10
+ * runner sets `CIBUILD_NON_INTERACTIVE=1` (and the generic `CI=1` env
11
+ * is also honored) to make the override unambiguous regardless of
12
+ * whether the shell looks interactive.
13
+ */
14
+ export declare function isInteractiveTTY(): boolean;
3
15
  /**
4
16
  * Shows an interactive workflow picker. If exactly one workflow exists,
5
17
  * returns it without prompting. Returns `undefined` when the user cancels
@@ -1 +1 @@
1
- {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/shared/prompts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0BxF;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,QAAQ,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAgFlB"}
1
+ {"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../src/shared/prompts.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAE5C;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAU1C;AAED;;;;GAIG;AACH,wBAAsB,iBAAiB,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CA0BxF;AAED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,YAAY,EAAE,YAAY,EAC1B,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,QAAQ,EAChB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAwFlB"}
@@ -2,6 +2,26 @@ import prompts from "prompts";
2
2
  import { StepValidator, formatValidationResult } from "../yaml/step-validator.js";
3
3
  import { MissingEnvHandler } from "../yaml/missing-env-handler.js";
4
4
  import { MissingEnvironmentVariableError } from "../yaml/env-resolver.js";
5
+ /**
6
+ * True only when stdin AND stdout are real TTYs AND the caller has not
7
+ * explicitly opted out of interactivity.
8
+ *
9
+ * `process.stdin.isTTY` is unreliable as a sole signal: Tart guest
10
+ * sessions opened via `tart exec` attach a pseudo-TTY, so the check
11
+ * passes and the prompt runs — only for nobody to ever answer it. The
12
+ * runner sets `CIBUILD_NON_INTERACTIVE=1` (and the generic `CI=1` env
13
+ * is also honored) to make the override unambiguous regardless of
14
+ * whether the shell looks interactive.
15
+ */
16
+ export function isInteractiveTTY() {
17
+ if (process.env.CIBUILD_NON_INTERACTIVE === '1' ||
18
+ process.env.CIBUILD_NON_INTERACTIVE === 'true' ||
19
+ process.env.CI === '1' ||
20
+ process.env.CI === 'true') {
21
+ return false;
22
+ }
23
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
24
+ }
5
25
  /**
6
26
  * Shows an interactive workflow picker. If exactly one workflow exists,
7
27
  * returns it without prompting. Returns `undefined` when the user cancels
@@ -66,6 +86,11 @@ export async function promptForMissingVariables(yamlPipeline, workflowName, conf
66
86
  console.log(` • ${issue.requirement.name.padEnd(30)}${stepInfo}`);
67
87
  }
68
88
  console.log();
89
+ if (!isInteractiveTTY()) {
90
+ console.error("\n❌ Cannot prompt for missing values: no interactive TTY available (running in a sandbox / CI).\n" +
91
+ " Define the required values as env vars, secrets, or app.envs before dispatch, then retry.");
92
+ return false;
93
+ }
69
94
  const handler = new MissingEnvHandler({
70
95
  interactive: true,
71
96
  workflow: workflowName,
@@ -34,12 +34,24 @@ export declare class StepValidator {
34
34
  private validateRequirement;
35
35
  /**
36
36
  * Extracts all $VAR and ${VAR} variable names referenced in an object recursively.
37
+ *
38
+ * `${{ secrets.X }}` / `${{ vars.X }}` references are deliberately ignored:
39
+ * those are resolved by the runner-side interpolator before cibuild sees
40
+ * the YAML (or by the dashboard's secrets-resolver on dispatch). Without
41
+ * this filter the inner regex would capture `{ secrets.X ` as if it were
42
+ * a `${VAR}` reference, producing garbled variable names in the
43
+ * missing-env error output.
37
44
  */
38
45
  private extractVariableReferences;
39
46
  /**
40
47
  * Replaces all unresolved $VAR and ${VAR} references with empty string.
41
48
  * Used as a lenient fallback when full interpolation fails, so that
42
49
  * getValidationRequirements can detect truly-missing variables correctly.
50
+ *
51
+ * `${{ ... }}` refs are left intact — they belong to the runner-side
52
+ * interpolator / dashboard secrets-resolver layer, not to shell-level
53
+ * variable substitution. Stripping them here would destroy the YAML for
54
+ * any downstream consumer that still expects to see them.
43
55
  */
44
56
  private stripUnresolvedVars;
45
57
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"step-validator.d.ts","sourceRoot":"","sources":["../../../src/yaml/step-validator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAGV,wBAAwB,EAGzB,MAAM,uBAAuB,CAAC;AAwB/B;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,YAAY,CAAC,CAAS;IAG9B,OAAO,CAAC,gBAAgB,CAAoE;IAG5F,OAAO,CAAC,mBAAmB,CAA6B;gBAGtD,QAAQ,EAAE,YAAY,EACtB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,QAAQ,EAChB,YAAY,CAAC,EAAE,MAAM;IAwBvB;;;OAGG;IACG,gBAAgB,IAAI,OAAO,CAAC,wBAAwB,CAAC;IAuM3D;;OAEG;YACW,mBAAmB;IAsDjC;;OAEG;IACH,OAAO,CAAC,yBAAyB;IAoBjC;;;;OAIG;IACH,OAAO,CAAC,mBAAmB;IAiB3B;;OAEG;IACH,OAAO,CAAC,SAAS;CA8BlB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CA4D/E"}
1
+ {"version":3,"file":"step-validator.d.ts","sourceRoot":"","sources":["../../../src/yaml/step-validator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,YAAY,EAA4B,MAAM,YAAY,CAAC;AACzE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,KAAK,EAGV,wBAAwB,EAGzB,MAAM,uBAAuB,CAAC;AAwB/B;;;;GAIG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,QAAQ,CAAe;IAC/B,OAAO,CAAC,YAAY,CAAS;IAC7B,OAAO,CAAC,MAAM,CAAW;IACzB,OAAO,CAAC,WAAW,CAAc;IACjC,OAAO,CAAC,YAAY,CAAC,CAAS;IAG9B,OAAO,CAAC,gBAAgB,CAAoE;IAG5F,OAAO,CAAC,mBAAmB,CAA6B;gBAGtD,QAAQ,EAAE,YAAY,EACtB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,QAAQ,EAChB,YAAY,CAAC,EAAE,MAAM;IAwBvB;;;OAGG;IACG,gBAAgB,IAAI,OAAO,CAAC,wBAAwB,CAAC;IA8M3D;;OAEG;YACW,mBAAmB;IAsDjC;;;;;;;;;OASG;IACH,OAAO,CAAC,yBAAyB;IAsBjC;;;;;;;;;OASG;IACH,OAAO,CAAC,mBAAmB;IAoB3B;;OAEG;IACH,OAAO,CAAC,SAAS;CA8BlB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CA4D/E"}
@@ -167,6 +167,14 @@ export class StepValidator {
167
167
  // values set by the YAML/secrets are still treated as "provided")
168
168
  if (Object.prototype.hasOwnProperty.call(resolvedEnv, varName))
169
169
  continue;
170
+ // Skip if the runner (or the surrounding shell) already exported
171
+ // the var into our process.env. The sandbox runner delivers
172
+ // dispatch-supplied `execution.env` / `execution.secrets` this
173
+ // way — without this fallback, bash-style `$VAR` refs in
174
+ // repo-hosted YAML (human CLI flow) would false-trigger the
175
+ // auto-discovery even though they resolve at shell runtime.
176
+ if (Object.prototype.hasOwnProperty.call(process.env, varName))
177
+ continue;
170
178
  // Skip if provided as output by an earlier step
171
179
  if (this.availableOutputs.has(varName))
172
180
  continue;
@@ -277,13 +285,22 @@ export class StepValidator {
277
285
  }
278
286
  /**
279
287
  * Extracts all $VAR and ${VAR} variable names referenced in an object recursively.
288
+ *
289
+ * `${{ secrets.X }}` / `${{ vars.X }}` references are deliberately ignored:
290
+ * those are resolved by the runner-side interpolator before cibuild sees
291
+ * the YAML (or by the dashboard's secrets-resolver on dispatch). Without
292
+ * this filter the inner regex would capture `{ secrets.X ` as if it were
293
+ * a `${VAR}` reference, producing garbled variable names in the
294
+ * missing-env error output.
280
295
  */
281
296
  extractVariableReferences(obj) {
282
297
  const vars = new Set();
283
298
  if (typeof obj === 'string') {
299
+ // Strip `${{ ... }}` refs first so they can't be mis-matched as `${VAR}`.
300
+ const sanitized = obj.replace(/\$\{\{[^}]*\}\}/g, '');
284
301
  const pattern = /\$\{([^}]+)\}|\$([A-Z_][A-Z_0-9]*)/g;
285
302
  let match;
286
- while ((match = pattern.exec(obj)) !== null) {
303
+ while ((match = pattern.exec(sanitized)) !== null) {
287
304
  vars.add(match[1] || match[2]);
288
305
  }
289
306
  }
@@ -305,10 +322,18 @@ export class StepValidator {
305
322
  * Replaces all unresolved $VAR and ${VAR} references with empty string.
306
323
  * Used as a lenient fallback when full interpolation fails, so that
307
324
  * getValidationRequirements can detect truly-missing variables correctly.
325
+ *
326
+ * `${{ ... }}` refs are left intact — they belong to the runner-side
327
+ * interpolator / dashboard secrets-resolver layer, not to shell-level
328
+ * variable substitution. Stripping them here would destroy the YAML for
329
+ * any downstream consumer that still expects to see them.
308
330
  */
309
331
  stripUnresolvedVars(obj) {
310
332
  if (typeof obj === 'string') {
311
- return obj.replace(/\$\{[^}]+\}|\$[A-Z_][A-Z_0-9]*/g, '');
333
+ // `(?!\{)` prevents `\$\{[^}]+\}` from matching a leading `${` of
334
+ // `${{ ... }}` and stripping the inner content. Plain `$VAR` and
335
+ // `${VAR}` are still stripped as before.
336
+ return obj.replace(/\$\{(?!\{)[^}]+\}|\$[A-Z_][A-Z_0-9]*/g, '');
312
337
  }
313
338
  if (Array.isArray(obj)) {
314
339
  return obj.map((item) => this.stripUnresolvedVars(item));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@invarn/cibuild",
3
- "version": "1.5.3",
3
+ "version": "1.5.5",
4
4
  "description": "CI Build CLI — local pipeline orchestration and validation",
5
5
  "type": "module",
6
6
  "main": "dist/cli.cjs",