Send fully-resolved variable values to the runner
What does this MR do?
This MR does the following:
- Changes
Ci::BuildRunnerPresenter.variables
to leverageExpandVariables.expand_variables_collection
so that variables sent in the job response are expanded; - Documents the new nested variable value resolution feature and the
:variable_inside_variable
FF.
TODO
-
Add tests to seed/build_spec.rb
-
Create FF rollout issue
List of MRs
MR 1: MakeCollection::Sorted
class take and output aVariables::Collection
;MR 2: Add#sorted_collection
method and#errors
property toVariables::Collection
;MR 3: Add indexing/lookup of variables toVariables::Collection
;MR 4: Add support fordepends_on
property toVariables::Collection::Item
;MR 5: Add support forraw
property toVariables::Collection::Item
;MR 6: Add an#expand_variables_collection
function toExpandVariables
to perform a full expansion of aVariables::Collection
, gated by the new project-scoped:variable_inside_variable
feature flag. It will return the original object if a cyclic reference is detected;MR 7: Add error reporting toGitlab::Ci::Pipeline::Seed::Build
to let the user know when a problem occurs with variable expansion;- MR 7.5: Implement expression parser to be able to handle escaping in strings;
- MR 8: Change
Ci::BuildRunnerPresenter#variables
to leverageExpandVariables#expand_variables_collection
so that variables sent in the job response are expanded;
Screenshots (strongly suggested)
Job definition
variables:
VAR3: "test-$SECRET_VAR"
VAR2: "test-${VAR1}"
VAR1: "${PROTECTED_VAR}-${CI_PIPELINE_ID}"
start_evaluation:
script:
- printenv
- echo "VAR1=${VAR1}"
- echo "VAR2=${VAR2}"
- echo "VAR3=${VAR3}"
- echo "PROTECTED_VAR=${PROTECTED_VAR}"
- echo "SECRET_VAR=${SECRET_VAR}"
- echo Done
tags: [local-gdk, shell]
Here's a screenshot from a debugging session in GitLab Runner showing the received job response's variables. It shows that:
- the
VAR1
variable value is sent from GitLab already resolved, as opposed to what would be the result from the main branch (it would show as${PROTECTED_VAR}-${CI_PIPELINE_ID}
; - the protected variable is not expanded, since the job ran on an unprotected branch;
- the masked variable was expanded and is later masked by the UI.
Does this MR meet the acceptance criteria?
Conformity
-
Changelog entry -
Documentation (if required) -
Code review guidelines -
Merge request performance guidelines -
Style guides -
Database guides -
Separation of EE specific content
Availability and Testing
-
Review and add/update tests for this feature/bug. Consider all test levels. See the Test Planning Process. -
Tested in all supported browsers -
Informed Infrastructure department of a default or new setting change, if applicable per definition of done
Test suite executed by contributor
✅
1. Resolving/masking of referenced variables .gitlab-ci.yml
variables:
variable_1: build-dir-$CI_BUILD_DIR
A: var-$B
B: var-$C
C: var-$SECRET_VAR
start_evaluation:
script:
- printenv
- echo Done
tags: [local-gdk, shell]
✅
Feature flag disabled
Feature.disable(:variable_inside_variable)
A masked variable SECRET_VAR
is defined in CI / CD Settings
/ Variables
with value maskedvalue
:
Output
...
SECRET_VAR=[MASKED]
C=var-[MASKED]
B=var-var-$SECRET_VAR
A=var-var-$C
...
++ echo '$ echo Done'
$ echo Done
++ echo Done
Done
+ exit 0
Job succeeded
✅
Feature flag enabled
Feature.enable(:variable_inside_variable)
All dependent values get recursively masked:
Output
...
SECRET_VAR=[MASKED]
C=var-[MASKED]
B=var-var-[MASKED]
A=var-var-var-[MASKED]
...
++ echo '$ echo Done'
$ echo Done
++ echo Done
Done
+ exit 0
Job succeeded
✅
2. Resolving variables with cyclic reference Start a pipeline with a value override C: var-$A
to create a cyclic reference
✅
Feature flag disabled
Feature.disable(:variable_inside_variable)
The build succeeds.
Output
...
SECRET_VAR=[MASKED]
C=var-$B
B=var-$A
A=var-var-$C
...
++ echo '$ echo Done'
$ echo Done
++ echo Done
Done
+ exit 0
Job succeeded
✅
Feature flag enabled NOTE: If a job has already succeeded and the FF is then enabled, the build will be marked as non-retryable.
Feature.enable(:variable_inside_variable)
✅
3. Pass variable value unmodified to Runner The variable references that cannot be resolved should be passed as-is to the runner for expansion there (e.g. for variables that only exist on the runner).
.gitlab-ci.yml
variables:
variable_1: build-dir-$CI_BUILD_DIR
start_evaluation:
script:
- printenv
- echo Done
tags: [local-gdk]
✅
Feature flag disabled
Feature.disable(:variable_inside_variable)
Output
...
variable_1=build-dir-/Users/pedropombeiro/src/gitlab.com/gitlab-org/gitlab-runner/builds
...
++ echo '$ echo Done'
$ echo Done
++ echo Done
Done
+ exit 0
Job succeeded
✅
Feature flag enabled
Feature.enable(:variable_inside_variable)
Runner variable is still expanded:
Output
...
variable_1=build-dir-/Users/pedropombeiro/src/gitlab.com/gitlab-org/gitlab-runner/builds
...
++ echo '$ echo Done'
$ echo Done
++ echo Done
Done
+ exit 0
Job succeeded
Security
If this MR contains changes to processing or storing of credentials or tokens, authorization and authentication methods and other items described in the security review guidelines:
-
Label as security and @ mention @gitlab-com/gl-security/appsec
-
The MR includes necessary changes to maintain consistency between UI, API, email, or other methods -
Security reports checked/validated by a reviewer from the AppSec team
Closes gitlab-runner#26345 (closed)
Closes gitlab-runner#4319 (closed)