Reject YAML tags in CI/CD input values
What does this MR do and why?
A YAML tag such as !reference passed as a CI/CD input value (in include: inputs:) is never resolved. Tag resolution runs after input interpolation in Gitlab::Ci::Config#build_config, so the unresolved Tags::Reference object is stringified during interpolation and its internals are dumped into the configuration:
echo '[#<Gitlab::Ci::Config::Yaml::Tags::Reference:0x... @data={...}>, my-specific]'This MR rejects a YAML tag in an input value with a clear error instead:
`a` input: provided value cannot contain a YAML tagThe check covers a tag as the entire value, a tag nested in an array or hash, and a tag in an input default:. It runs before type coercion, because coercion would otherwise stringify the tag and hide it.
Reusing a value across configuration files does not need !reference: an array input defined in an external file already works, and its items are added to a surrounding array so the list can be extended with additional items. That behavior is documented in !249486 (merged).
Resolves #607053
Why reject instead of support
An earlier revision of this MR implemented resolution (deferring the tag through interpolation so the resolver could resolve it against the merged configuration). It was dropped after review:
- It added significant complexity to the inputs and interpolation code (deferred value wrappers, tag detection across both layers, key and size guards) for a need that existing input mechanics already cover.
- It could not produce the flat array the original reporter wanted, because supporting a tag as the entire input value means a shared list cannot be extended with extra items. Array input concatenation does exactly that, without new code.
Rejecting keeps the inputs code free of tag handling and replaces silent garbage output with an actionable error.
Feature flag
ci_reject_yaml_tags_in_inputs(gitlab_com_derisk, disabled by default).- Rollout issue: #607488
- The flag exists because a configuration that currently produces the dumped object would start failing, so the change needs a gradual rollout and an instant revert path.
How to set up and validate locally
# list.yml
.my-shared-list:
- value1
- value2
# template.yml
spec:
inputs:
a:
type: array
---
job:
script: $[[ inputs.a ]]
# .gitlab-ci.yml
include:
- local: /list.yml
- local: /template.yml
inputs:
a: !reference [.my-shared-list]With the flag enabled, this fails with `a` input: provided value cannot contain a YAML tag. With the flag disabled, the previous behavior is unchanged.
Test coverage
End-to-end Gitlab::Ci::Config spec with real local includes:
- a tag as the entire input value, for an array and a scalar input
- a tag used in a value that is interpolated into a string
- a tag nested in an array, and nested in a hash within an array
- a tag in an input
default: - flag disabled: previous behavior preserved
- no tag: normal interpolation unaffected
MR acceptance checklist
- Feature flag added, disabled by default; both states tested.
- End-to-end tests.
- RuboCop, markdownlint, and Vale passing.
- Technical Writer review of the documentation changes (can be post-merge).
Related
- !249486 (merged) documents array input concatenation, the supported way to reuse and extend a list.
- Supersedes !247355 (closed) and !247759 (closed) (closed in favor of this MR).