GitLab CI Pipeline Control via Web-Based Triggers

The architecture of modern continuous integration and continuous deployment (CI/CD) often requires a surgical approach to job execution. While the primary goal of most pipelines is full automation—triggering on every single git push—there are critical scenarios where automation becomes a liability. Specifically, when dealing with production environments or expensive resource allocations, engineers require a mechanism to ensure that certain stages only execute when a human operator explicitly initiates them via the user interface. This is the functional core of the web-based pipeline trigger in GitLab CI, a configuration that separates automated testing from manual administrative intervention.

By leveraging the .gitlab-ci.yml configuration file, developers can define precise rules that dictate whether a job should be eligible for execution based on the source of the pipeline. The distinction between a pipeline triggered by a git push and one triggered by the "Run Pipeline" button in the GitLab UI is managed through the CI_PIPELINE_SOURCE variable. When this variable is set to web, it signals that the pipeline was initiated manually through the project's Build > Pipelines section. This capability allows for the creation of "administrative" pipelines that do not clutter the standard development cycle but remain available for on-demand execution.

The Anatomy of GitLab CI/CD Pipeline Components

To understand how to isolate jobs to the web interface, one must first understand the structural hierarchy of a GitLab pipeline. A pipeline is not a single entity but a collection of coordinated elements that execute in a specific sequence.

Pipelines are fundamentally composed of three layers:

  • Global YAML keywords: These provide the overarching control for the project's pipelines, defining the environment and behavior that apply across all jobs.
  • Stages: These act as logical groupings for jobs. Stages run in a strict sequence. For example, a pipeline may have a build stage, followed by a test stage, and finally a deploy stage. Within a single stage, all jobs run in parallel. A pipeline only moves to the next stage if all jobs in the current stage complete successfully.
  • Jobs: These are the smallest units of execution. A job is a set of instructions executed by a GitLab Runner, often within a Docker container. Each job produces a unique execution log that provides a full audit trail of the commands run.

The interaction between these components determines the flow of execution. For instance, in a standard three-stage pipeline, a compile job in the build stage must succeed before test1 and test2 in the test stage can begin. Subsequently, a deploy-to-production job in the deploy stage will only execute if all preceding test jobs have successfully concluded. This sequential dependency is what makes the web trigger so powerful, as it allows an operator to stop a pipeline in a "blocked" state before the final, high-risk deployment stage occurs.

Implementing Web-Only Triggers via CIPIPELINESOURCE

The most effective way to ensure a job runs only when triggered via the GitLab UI is by using the rules keyword combined with the CI_PIPELINE_SOURCE predefined variable.

The CI_PIPELINE_SOURCE variable identifies the event that triggered the pipeline. When a user navigates to CI/CD -> Pipelines and clicks the "Run Pipeline" button, GitLab assigns the value web to this variable.

To implement this, the .gitlab-ci.yml must be configured as follows:

yaml plan_prod: stage: plan prod rules: - if: '$CI_PIPELINE_SOURCE == "web"' script: - TS_ENV=prod terraspace plan demo

In this configuration, the plan_prod job will be completely ignored by the pipeline if the trigger was a git push, a merge request, or a schedule. It only becomes part of the pipeline graph when the "web" source is detected. This prevents production planning jobs from running and consuming runner resources on every minor commit.

Manual Approvals and the Blocked State

While the web trigger controls whether a job enters the pipeline, the when: manual keyword controls whether that job starts automatically once it is in the pipeline. These two concepts are often confused but serve different purposes in a production workflow.

The when: manual attribute is used to create a "manual approval" gate. When a job is marked as manual, the pipeline does not execute that job automatically. Instead, the pipeline enters a "blocked" status. The user must then manually interact with the GitLab UI to trigger the job.

A comprehensive example of combining web-only triggers with manual approvals is seen in the following configuration:

yaml up_prod: stage: up prod rules: - if: '$CI_PIPELINE_SOURCE == "web"' when: manual script: - TS_ENV=prod terraspace up demo -y

In this scenario, two layers of security are applied:
1. The job only exists in the pipeline if the pipeline was started via the Web UI.
2. Even after the pipeline starts, the job will not execute until a user clicks the "Play" button or selects "Run" from the job panel.

The real-world impact of this setup is a secure deployment gate. A lead engineer can start a pipeline via the web interface, review the logs of the preceding plan stage to ensure the infrastructure changes are correct, and only then click the play button to apply the changes to the production environment.

Navigating the GitLab UI for Manual Execution

To execute a pipeline configured for web-only triggers, the operator must follow a specific sequence within the GitLab interface:

  • Navigate to the left-side menu and select CI/CD -> Pipelines.
  • Locate the "Run Pipeline" button in the upper right-hand corner.
  • If required, specify any custom variables; otherwise, leave the defaults as is.
  • Click "Run Pipeline" to initiate the build.

Once the pipeline is active, the behavior is as follows:

  • Jobs without when: manual (but with the web rule) will execute immediately.
  • The operator can click on each stage to view the logs and verify the output (such as a terraspace plan preview).
  • When the pipeline reaches a job marked as when: manual, the overall pipeline status changes to "blocked".
  • To resume the pipeline, the operator clicks the "Play" button associated with the blocked job, which transitions the pipeline back into a "running" state.

Distinguishing Web Triggers from Other Pipeline Sources

It is critical for DevOps engineers to understand that web is just one of many possible pipeline sources. Misconfiguring these can lead to "pipeline flooding," where the pipelines list is overwhelmed by unintended runs.

The following table details the various CI_PIPELINE_SOURCE values and their triggers:

Source Value Triggering Event
web Created by selecting "New pipeline" in the GitLab UI (Build > Pipelines)
push Triggered by a Git push event, including branches and tags
merge_request_event Created when a merge request is updated or created
schedule Triggered by a pre-defined pipeline schedule
trigger Created via a trigger token (API)
parent_pipeline Triggered by a parent pipeline in a child pipeline setup
pipeline Used for multi-project pipelines
webide Created via the GitLab Web IDE
external Triggered by services other than GitLab
external_pull_request_event Triggered by an external GitHub pull request
ondemand_dast_scan Specific to on-demand DAST scans
ondemand_dast_validation Specific to on-demand DAST validation
security_orchestration_policy Triggered by scheduled scan execution policies

By exclusively using if: $CI_PIPELINE_SOURCE == "web", the developer ensures that the job is isolated from all other event types, effectively turning the job into a tool that can only be wielded by a human operator via the browser.

Advanced Filtering and Instance-Specific Execution

In complex enterprise environments, a single repository may be mirrored across multiple GitLab instances (e.g., a public GitLab.com instance and a private self-managed instance). In such cases, simply restricting a job to the web trigger may not be enough, as a user might trigger a web pipeline on the wrong instance.

To restrict job execution to a specific GitLab instance, engineers can use the CI_SERVER_HOST variable. This variable identifies the hostname of the GitLab instance running the pipeline.

For example, if a release stage should only run on a specific internal instance for tags following a PEP-440 versioning pattern, the configuration would look like this:

yaml release_job: only: refs: - /^v\d+\.\d+\.\d+([abc]\d*)?$/ variables: - $CI_SERVER_HOST == "gitlab.example.org" script: - echo "Releasing on the authorized instance"

This dual-layer filtering (checking both the Git ref and the server host) prevents accidental releases from unauthorized or secondary GitLab instances, ensuring that the deployment logic is only executed where it is intended.

Pipeline Types and Dependency Management

The use of web triggers often intersects with different pipeline architectures. Depending on the complexity of the project, a "web" pipeline might be a basic pipeline or a more advanced structure.

  • Basic Pipelines: These run everything in each stage concurrently, moving to the next stage only after all jobs in the current stage succeed.
  • Needs-Based Pipelines: By using the needs keyword, jobs can run based on specific dependencies rather than waiting for an entire stage to finish. This allows a web triggered job to start as soon as its specific prerequisite is met, regardless of other jobs in the same stage.
  • Parent-Child Pipelines: Large projects may use a parent pipeline to trigger multiple child sub-pipelines. In this architecture, a web trigger at the parent level can cascade down to child pipelines, which must also be configured to handle the parent_pipeline source if they are to be triggered this way.
  • Merge Request Pipelines: These are specifically for merge requests. Using a web trigger allows an operator to run a "manual" version of a merge request pipeline for testing before the actual MR pipeline is triggered by a commit.

Analysis of Manual Triggering Strategies

The distinction between rules: - if: $CI_PIPELINE_SOURCE == "web" and when: manual is a common point of contention in GitLab CI configuration.

If a user only uses when: manual, the job will appear in every single pipeline (including every single push). While the job won't run automatically, it still exists in the pipeline graph. For many teams, this leads to "pipeline clutter," where the pipeline view is filled with manual jobs that are irrelevant to the current commit.

By contrast, using the web source check removes the job from the pipeline entirely unless the pipeline is started via the UI. This results in a cleaner pipeline graph for developers while maintaining a powerful "administrative" interface for operators.

The most robust architecture for production deployment follows this logic:
1. Use rules: if $CI_PIPELINE_SOURCE == "web" to ensure the job only exists during manual UI-triggered runs.
2. Use when: manual to ensure that even within that UI-triggered run, the final "apply" or "deploy" step requires a second, explicit confirmation.

This creates a two-factor authorization process for infrastructure changes: first, the decision to start the administrative pipeline, and second, the decision to execute the final deployment job after reviewing the logs of the preceding plan stage.

Sources

  1. Terraspace GitLab CI Manual
  2. GitLab Forum: Trigger pipeline manually only
  3. GitLab Forum: Run pipeline only on a specific GitLab instance
  4. GitLab Documentation: CI/CD Pipelines
  5. GitLab Documentation: CI/CD Jobs
  6. GitLab Documentation: Job Rules

Related Posts