From 613fe4b02957c7f3774e8a1444986a4ca6e2dd04 Mon Sep 17 00:00:00 2001 From: Avielle Wolfe Date: Mon, 21 Jul 2025 18:21:53 +0200 Subject: [PATCH] Fix mangled array input values Some array type inputs contain objects that get loaded as Ruby hashes. The YAML keys for those objects are loaded as symbols. When we cast those symbols to JSON during interpolation, the result gets mangled. To fix that, this commit adds logic to stringify the keys to ArrayInput. Changelog: fixed Issue: https://gitlab.com/gitlab-org/gitlab/-/issues/548328 --- .../pipeline_creation/inputs/array_input.rb | 14 +++++++++ .../inputs/array_input_spec.rb | 30 +++++++++++++++++++ .../ci/config/interpolation/inputs_spec.rb | 2 +- 3 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 spec/lib/ci/pipeline_creation/inputs/array_input_spec.rb diff --git a/lib/ci/pipeline_creation/inputs/array_input.rb b/lib/ci/pipeline_creation/inputs/array_input.rb index dff5043fc47721..50ca14f47a35aa 100644 --- a/lib/ci/pipeline_creation/inputs/array_input.rb +++ b/lib/ci/pipeline_creation/inputs/array_input.rb @@ -16,6 +16,20 @@ def validate_type(value, default) error("#{default ? 'default' : 'provided'} value is not an array") end + + # Some array type inputs contain objects that get loaded as Ruby hashes. The YAML keys for those objects are + # loaded as symbols. When we cast those symbols to JSON during interpolation, the result gets mangled. + # { :"array.input.item" => "value" } becomes { ":\"array.input.item\": "value" }. + # To fix that, we stringify the keys. + def actual_value(param) + super.map do |item| + if item.is_a?(Hash) + item.stringify_keys + else + item + end + end + end end end end diff --git a/spec/lib/ci/pipeline_creation/inputs/array_input_spec.rb b/spec/lib/ci/pipeline_creation/inputs/array_input_spec.rb new file mode 100644 index 00000000000000..ceb806e3329947 --- /dev/null +++ b/spec/lib/ci/pipeline_creation/inputs/array_input_spec.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +require 'fast_spec_helper' +require_relative Rails.root.join('lib/ci/pipeline_creation/inputs/base_input.rb') + +RSpec.describe Ci::PipelineCreation::Inputs::ArrayInput, feature_category: :pipeline_composition do + describe '#actual_value' do + it 'returns the array given to the input' do + input = described_class.new(name: 'test', spec: { test: { type: 'array' } }) + + value = input.actual_value('[1, 2]') + + expect(value).to eq([1, 2]) + end + + context 'when the array contains objects/hashes' do + # Some array type inputs contain objects that get loaded as Ruby hashes. The YAML keys for those objects are + # loaded as symbols. When we cast those symbols to JSON during interpolation, the result gets mangled. + # { :"array.input.item" => "value" } becomes { ":\"array.input.item\": "value" }. + # To fix that, we stringify the keys when we return them from ArrayInput. + it 'stringifies the keys so they do not contain extra characters when cast to JSON during interpolation' do + input = described_class.new(name: 'test', spec: { test: { type: 'array' } }) + + value = input.actual_value([{ 'array.input.item': 'value' }]) + + expect(value).to eq([{ 'array.input.item' => 'value' }]) + end + end + end +end diff --git a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb index c8dd2ad00a8220..55aff94a448595 100644 --- a/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb +++ b/spec/lib/gitlab/ci/config/interpolation/inputs_spec.rb @@ -337,7 +337,7 @@ end end - context 'when the default is not a boolean' do + context 'when the default is not an array' do let(:specs) { { array_input: { default: 'string', type: 'array' } } } let(:args) { {} } -- GitLab