Answer to Your Questions
1. Is the production branch or tag actually configured as protected? – You need to check Settings > Repository > Protected Branches / Tags and confirm that the ref (e.g., main, production, or a pattern like release/*) is listed and marked as protected.
2. Do any protected variables violate masking constraints? – Masking only hides the value in job logs; the variable is still passed to the environment. Verify by printing the variable inside a job script with env | grep ^MY_PROTECTED_VAR= and observe whether it appears.
3. Could the runner used for production be a different executor or scope? – Check the runner’s Scope (project vs. group) and Executor type in Settings > CI/CD > Runners. A Docker executor will start from a clean environment, while a shell executor may inherit host variables; both should receive protected variables if the runner is allowed to run on protected refs.
Likely Explanations
- The production ref is not marked as protected, so protected variables are omitted.
- A variable is marked as protected but the ref is a tag that isn’t protected.
- The runner is configured with
Only run on protected branches enabled but is not registered to the project, so it skips the job.
- Masking rules may hide the value in logs, giving the impression that it is missing; the variable is actually present in the environment.
Confirmed Facts (GitLab 16.x behavior)
| Fact | Description |
|---|
| Protected variables are injected only when the pipeline runs on a ref that is explicitly protected. | Unprotected variables are available to all refs. |
| Masking is log‑only; the variable exists in the job environment. | Use env | grep to confirm presence. |
| Runner scope and tags determine whether a job is picked up. | A runner not allowed to run on protected refs will not execute the job. |
Steps to Resolve
- Verify the production ref is protected:
# Go to Settings → Repository → Protected Branches / Tags
# Ensure your production branch/tag is listed and marked as protected
- Check each protected variable’s settings:
# Settings → CI/CD → Variables
# Expand each variable and confirm the "Protect variable" checkbox is checked
- Run a diagnostic job on the production ref:
debug-vars:
script:
- echo "=== Debug Vars ==="
- env | grep ^MY_PROTECTED_VAR= || echo "VAR NOT FOUND"
only:
- main
Trigger this job on the production branch and inspect the job log. The variable should appear if the ref is protected.
- Confirm runner configuration:
# Settings → CI/CD → Runners
# Verify the runner assigned to production jobs has
# • Scope: Project (or Group if the variable is group‑level)
# • Executor: Docker or Shell (both support protected vars)
# • "Only run on protected branches" is enabled if you want to restrict
- Check for scheduler or API triggers:
# Scheduled pipelines run on detached refs and may not honor protected
# If you use API or schedule, ensure the target ref is protected
Ask for One Missing Diagnostic Detail
To fine‑tune the recommendation, could you confirm whether the production branch (e.g., main) is listed in the Protected Branches/Tags section of your project settings?