Skip to content

feat: support spec:inputs for root pipeline via --input and --inputs-file#1814

Open
gyanranjan wants to merge 3 commits intofirecow:masterfrom
gyanranjan:feat/spec-inputs-pipeline
Open

feat: support spec:inputs for root pipeline via --input and --inputs-file#1814
gyanranjan wants to merge 3 commits intofirecow:masterfrom
gyanranjan:feat/spec-inputs-pipeline

Conversation

@gyanranjan
Copy link
Copy Markdown

@gyanranjan gyanranjan commented Mar 24, 2026

Summary

Adds support for providing spec:inputs values to the root .gitlab-ci.yml pipeline file — not just included files. This closes #1720.

Problem

When the root .gitlab-ci.yml uses spec:inputs, there was no way to pass values for required inputs (those without a default). The root file was always loaded with an empty context:

// parser.ts — was:
const gitlabCiData = await Parser.loadYaml(`${cwd}/${file}`, {}, ...);

Inputs on included files worked fine because parser-includes.ts forwarded value.inputs from the include: block. But the root file had no equivalent mechanism.

Solution

New CLI options

  • --input KEY=value (repeatable) — provide global inputs
  • --input component:KEY=value — provide component-specific inputs
  • --inputs-file PATH — path to inputs YAML file (default: .gitlab-ci-local-inputs.yml)

Inputs file formats

Flat (all inputs are global):

environment: production
replicas: 5

Structured (global + component-specific):

_global:
  environment: production
deploy:
  replicas: 5
build:
  go_version: "1.21"

Priority order (highest to lowest)

  1. Component-specific CLI inputs (--input component:key=value)
  2. Global CLI inputs (--input key=value)
  3. Component-specific file inputs
  4. Global file inputs (_global: or flat format)
  5. Inline inputs in .gitlab-ci.yml (include: inputs:)
  6. Spec defaults

Changes

File Change
src/argv.ts inputsFile getter, input getter with key=value and component:key=value parsing
src/index.ts --inputs-file and --input yargs options
src/parser.ts loadInputs() method; root loadYaml() now passes {inputs: rootInputs} instead of {}; absolute path support for --inputs-file
src/parser-includes.ts inputs in opts type; merge logic for global/component-specific inputs across all include types
tests/test-cases/component-inputs-cli/ New test case: single component with CLI and file inputs
tests/test-cases/component-inputs-multiple/ New test case: multiple components with structured inputs
tests/test-cases/.gitignore Exceptions for .gitlab-ci-local-inputs.yml fixture files

Testing

  • 27 input-related tests pass (19 existing + 8 new)
  • 130 core unit tests pass
  • 88 non-Docker integration tests pass — zero regressions

Corner cases verified

  • Root required input via --input
  • Root defaults used when not overridden ✅
  • CLI overrides file inputs ✅
  • Structured file with _global:
  • Number/boolean type coercion ✅
  • Options validation (valid + invalid) ✅
  • Dynamic job names using inputs ✅
  • Inputs in include paths ✅
  • Type mismatch rejection ✅
  • Normal pipelines without spec:inputs unaffected ✅
  • Absolute --inputs-file path ✅

Example

# .gitlab-ci.yml
---
spec:
  inputs:
    environment:
      type: string
      default: dev
    build_type:
      type: string
---
stages:
  - build
build-job:
  stage: build
  script:
    - echo "env=$[[ inputs.environment ]] type=$[[ inputs.build_type ]]"
# Before: fails with "build_type input: required value has not been provided"
gitlab-ci-local --list

# After: works
gitlab-ci-local --input build_type=nightly --list
gitlab-ci-local --input build_type=nightly --input environment=prod --list

Fixes #1720


Summary by cubic

Add support for passing spec:inputs to the root .gitlab-ci.yml, so required root inputs can be provided. Inputs can be set globally or per component via CLI or an inputs file, and are applied across the root and all include types.

  • New Features

    • --input KEY=value (repeatable) and --input component:KEY=value for global and component inputs.
    • --inputs-file PATH (default: .gitlab-ci-local-inputs.yml) with flat or structured formats (_global + component sections).
    • Inputs are merged into the root pipeline and all include types (local, project, component, template, remote).
    • Precedence: component CLI > file component > global CLI > file global > inline include inputs > spec defaults.
  • Bug Fixes

    • Allowed / in component names (e.g. templates/deploy:KEY=value).
    • Guards against prototype pollution keys in --input parsing (__proto__, constructor, prototype).
    • Resolved ESLint errors; no functional changes.

Written for commit 8e761a1. Summary will update on new commits.

…file

Add support for providing spec:inputs values to the root .gitlab-ci.yml
pipeline file, not just included files. This closes firecow#1720.

Changes:
- Add --input KEY=value CLI flag (repeatable) for global inputs
- Add --input component:KEY=value syntax for component-specific inputs
- Add --inputs-file flag (default: .gitlab-ci-local-inputs.yml)
- Pass inputs to root loadYaml() call in parser.ts (was hardcoded {})
- Merge external inputs into all include types (local, project,
  component, template, remote)
- Support structured inputs file with _global and component sections
- Fix absolute path handling for --inputs-file

Priority order (highest to lowest):
1. Component-specific CLI inputs (--input component:key=value)
2. Global CLI inputs (--input key=value)
3. Component-specific file inputs
4. Global file inputs (_global or flat format)
5. Inline inputs in .gitlab-ci.yml (include: inputs:)
6. Spec defaults

Fixes: firecow#1720
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 15 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="src/parser-includes.ts">

<violation number="1" location="src/parser-includes.ts:177">
P1: Component input merge order is incorrect: trailing `cliGlobalInputs` overrides component-specific CLI inputs on key conflicts.</violation>
</file>

<file name="src/argv.ts">

<violation number="1" location="src/argv.ts:226">
P2: Component-specific `--input` parsing is too restrictive (`[\w-]+`) and can misparse valid component names containing `/`, causing inputs to be dropped or assigned to the wrong component.</violation>

<violation number="2" location="src/argv.ts:243">
P1: Global and component inputs share one object namespace, allowing key collisions that can cause runtime errors or overwrite component data.</violation>

<violation number="3" location="src/argv.ts:243">
P1: User-controlled `component`/`key` are assigned into a plain object, allowing `__proto__`-based prototype pollution via `--input` parsing.</violation>
</file>

Since this is your first cubic review, here's how it works:

  • cubic automatically reviews your code and comments on bugs and improvements
  • Teach cubic by replying to its comments. cubic learns from your replies and gets better over time
  • Add one-off context when rerunning by tagging @cubic-dev-ai with guidance or docs links (including llms.txt)
  • Ask questions if you need clarification on any suggestion

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

if (component) {
// Component-specific input: store under component namespace
if (!inputs[component]) inputs[component] = {};
inputs[component][key] = parsedValue;
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Global and component inputs share one object namespace, allowing key collisions that can cause runtime errors or overwrite component data.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At src/argv.ts, line 243:

<comment>Global and component inputs share one object namespace, allowing key collisions that can cause runtime errors or overwrite component data.</comment>

<file context>
@@ -212,6 +217,39 @@ export class Argv {
+                if (component) {
+                    // Component-specific input: store under component namespace
+                    if (!inputs[component]) inputs[component] = {};
+                    inputs[component][key] = parsedValue;
+                } else {
+                    // Global input
</file context>
Fix with Cubic

- Fix component input merge order: remove duplicate cliGlobalInputs
  spread that caused global CLI to override component-specific CLI
  inputs on key conflicts (P1)
- Broaden component name regex to allow '/' for paths like
  templates/deploy (P2)
- Add prototype pollution guard for __proto__, constructor,
  prototype keys in --input parsing (P1)
- Add 7 new tests covering edge cases
- Fix existing test that relied on buggy merge order
@gyanranjan
Copy link
Copy Markdown
Author

@firecow could you please review this PR when you get a chance?

This adds support for root spec:inputs via --input and --inputs-file. I’ve included tests as well. I don’t seem to have permission to assign reviewers from my side, so tagging here for visibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support spec::inputs for pipelines

1 participant