Skip to main content

GitLab

This page covers the GitLab CI/CD particulars of the Plumber CLI: how to authenticate, the controls that ship for GitLab, the issues they emit, a complete gitlab.controls: configuration block, and the merge-request / badge integration. For installation and the provider-agnostic command reference, see the main CLI page.

On GitLab, Plumber flags issues like:

  • Container images using mutable tags (latest, dev) or from untrusted registries
  • Unprotected branches, missing approval rules, non-compliant MR settings
  • Hardcoded jobs / outdated includes / forbidden version patterns (main, HEAD)
  • Missing required catalog components or shared templates
  • Security jobs weakened via allow_failure, rules: overrides, when: manual
  • Controlled CI/CD variables overridden in the pipeline YAML
  • Unverified remote script execution patterns (curl | bash, wget | sh)
  • Docker-in-Docker (dind) services enabling container escape on shared runners

Quick Start

  1. Install Plumber (Installation below): Homebrew, mise, a prebuilt binary, Docker, or from source.

  2. Authenticate: create a GITLAB_TOKEN with read_api + read_repository scopes (see Authentication below).

  3. Run the scan from inside your project, or against a remote one (see Running a scan):

    Terminal window
    plumber analyze
  4. Read the report: a per-control compliance breakdown and a letter grade, plus an optional JSON report, PBOM, and CycloneDX SBOM (see Example Output).

Installation

Info

Trying a beta? Homebrew, mise, and Docker Hub follow stable releases only. Beta binaries and checksums live on the GitHub Releases page; each beta’s release notes carry the verified download + checksum steps for that specific build.

Authentication

In GitLab, go to User Settings → Access Tokens (direct link) and create a Personal Access Token with read_api + read_repository scopes. Project Access Tokens also work: create one inside your project under Settings → Access Tokens with the same scopes and at least Maintainer role.

Caution

The token must belong to a user (or project bot) with Maintainer role (or higher) on the project to access branch protection settings and other project configurations.

Terminal window
export GITLAB_TOKEN=glpat-xxxx

Use api scope instead of read_api if you plan to enable --mr-comment or --badge (see GitLab Integration below).

Running a scan

Terminal window
# Auto-detected from git remote
plumber analyze
# Explicit project
plumber analyze --gitlab-url https://gitlab.com --project mygroup/myproject

Self-Hosted GitLab

Terminal window
plumber analyze --gitlab-url https://gitlab.example.com --project mygroup/myproject

Custom CI Configuration Path

By default Plumber reads the project’s configured CI config path (usually .gitlab-ci.yml). Override it when your pipeline file lives elsewhere:

Terminal window
plumber analyze --ci-config-path .gitlab/ci/main.yml

Command Reference

plumber analyze

The main command for analyzing GitLab CI/CD pipelines.

Terminal window
plumber analyze [flags]

Flags

FlagRequiredDefaultDescription
--gitlab-urlNo*auto-detectGitLab instance URL (e.g., https://gitlab.com). Mutually exclusive with --github-url.
--github-urlNo*auto-detectGitHub host (e.g., github.com or ghes.example.com). Mutually exclusive with --gitlab-url.
--projectNo*auto-detectProject / repo path. GitLab: group/project. GitHub: owner/repo.
--configNo.plumber.yamlPath to configuration file
--thresholdNo100Minimum compliance % to pass (0-100)
--branchNoProject defaultBranch to analyze
--outputNo-Write JSON results to file
--pbomNo-Write PBOM (Pipeline Bill of Materials) to file
--pbom-cyclonedxNo-Write PBOM in CycloneDX SBOM format
--printNotruePrint text output to stdout
--mr-commentNofalsePost/update a compliance comment on the merge request (MR pipelines only; requires api scope)
--badgeNofalseCreate/update a Plumber compliance badge on the project (requires api scope; only runs on default branch)
--controlsNo-Run only listed controls (comma-separated). Cannot be used with --skip-controls
--skip-controlsNo-Skip listed controls (comma-separated). Cannot be used with --controls
--fail-warningsNofalseTreat configuration warnings (unknown keys) as errors (exit 2)
--ci-config-pathNoauto-detectOverride CI configuration file path. Defaults to project CI config path from GitLab settings (usually .gitlab-ci.yml)
--verbose, -vNofalseEnable verbose/debug output

Info

* Auto-detected from git remote (requires origin) if not specified. Supports both SSH and HTTPS remote URLs.
* You can always override with --gitlab-url and --project

Environment Variables

VariableRequiredDescription
GITLAB_TOKENGitLab onlyGitLab API token with read_api + read_repository scopes (from a Maintainer or higher). Use api scope instead if --mr-comment or --badge is enabled.
PLUMBER_NO_UPDATE_CHECKNoSet to any value (e.g., 1) to disable the automatic version check.

For the configuration commands (plumber config init / generate / migrate / view / validate), plumber explain, and exit codes, see the main CLI page. They behave identically for both providers.

Usage Examples

Save JSON Output

Terminal window
docker run --rm \
-e GITLAB_TOKEN=glpat-xxxx \
-v $(pwd):/output \
getplumber/plumber:latest analyze \
--gitlab-url https://gitlab.com \
--project mygroup/myproject \
--branch main \
--config /.plumber.yaml \
--threshold 100 \
--output /output/results.json

Silent Mode (JSON Only)

Terminal window
plumber analyze \
--gitlab-url https://gitlab.com \
--project mygroup/myproject \
--config .plumber.yaml \
--threshold 100 \
--output results.json \
--print false

Example Output

The CLI output is color-coded in your terminal for easy scanning: green for passing controls, red for failures.

Tip

When using --output, results are saved as JSON for programmatic access and CI/CD integration.

Plumber CLI output showing compliance results

Available Controls

Plumber ships 14 GitLab controls. Each can be enabled / disabled and customized in .plumber.yaml. When a control detects a violation, it creates an Issue (e.g., ISSUE-101) with a direct link to its documentation page.

ControlIssuesDescription
Container images must come from authorized sourcesISSUE-101Ensures images come from trusted registries
Container images must not use forbidden tagsISSUE-102Flags latest, dev, and other mutable tags. Can enforce digest pinning for all images
Container images must be pinned by digestISSUE-103Ensures images use SHA256 digest pinning
Pipeline must not enable debug traceISSUE-203Detects CI_DEBUG_TRACE/CI_DEBUG_SERVICES leaking secrets in job logs
Pipeline must not use unsafe variable expansionISSUE-204Detects user-controlled variables in shell re-interpretation contexts (OWASP CICD-SEC-1)
Pipeline must not override job variablesISSUE-205Detects controlled CI/CD variables redefined in .gitlab-ci.yml that should only be set in GitLab CI/CD Settings
Pipeline must not include hardcoded jobsISSUE-401Detects jobs defined directly instead of from includes
Includes must be up to dateISSUE-403Checks if included templates have newer versions
Includes must not use forbidden versionsISSUE-404Prevents mutable version references like main, HEAD
Pipeline must include templateISSUE-405 ISSUE-406Ensures required templates are included; detects overridden jobs
Pipeline must include componentISSUE-408 ISSUE-409Ensures required CI/CD components are included; detects overridden jobs
Security jobs must not be weakenedISSUE-410Detects security scanning jobs neutralized by allow_failure, rules: overrides, or when: manual (OWASP CICD-SEC-4)
Pipeline must not execute unverified scriptsISSUE-411Detects curl | bash, wget | sh, and download-then-execute patterns without integrity verification (OWASP CICD-SEC-3)
Pipeline must not use Docker-in-DockerISSUE-412 ISSUE-413Detects docker:dind services and insecure Docker daemon configuration (for example TLS disabled)
Branch must be protectedISSUE-501 ISSUE-505Verifies critical branches have proper protection
Unsafe Variable Expansion Detection

Detects user-controlled CI variables (MR title, commit message, branch name) passed to commands that re-interpret their input as shell code. This is OWASP CICD-SEC-1.

GitLab sets CI variables as environment variables. The shell does not re-parse expanded values for command substitution, so normal usage is safe. Only commands that re-interpret their arguments as code are flagged:

Flagged (re-interpretation contexts):

Terminal window
eval "$CI_COMMIT_BRANCH"
sh -c "$CI_MERGE_REQUEST_TITLE"
bash -c "$CI_COMMIT_MESSAGE"
source <(echo "$CI_COMMIT_REF_NAME")
echo "$CI_COMMIT_BRANCH" | xargs sh

Not flagged (safe, the shell doesn’t re-parse env var values):

Terminal window
echo $CI_COMMIT_BRANCH
curl -d "$CI_MERGE_REQUEST_TITLE" https://...
git checkout $CI_COMMIT_REF_NAME
printf '%s' "$CI_COMMIT_MESSAGE"

Allowing specific patterns

Some sh -c or bash -c usages are legitimate (e.g., Helm deploys, Terraform workspaces). Use allowedPatterns (regex) to suppress those findings. Each pattern is matched against the full script line.

pipelineMustNotUseUnsafeVariableExpansion:
enabled: true
dangerousVariables:
- CI_MERGE_REQUEST_TITLE
- CI_COMMIT_MESSAGE
- CI_COMMIT_REF_NAME
- CI_COMMIT_REF_SLUG
- CI_COMMIT_BRANCH
allowedPatterns:
- "helm.*--set.*\\$CI_"
- "terraform workspace select.*\\$CI_"
- "docker build.*--build-arg.*\\$CI_"
- "aws s3 sync.*\\$CI_"
- "make deploy.*\\$CI_"

For example, the script line sh -c "helm upgrade myapp . --set image.tag=$CI_COMMIT_SHA" would normally be flagged, but the pattern helm.*--set.*\\$CI_ allows it.

Info

Escape $ as \\$ and {/} as \\{/\\} in patterns. Only direct variable names are detected. Indirect aliasing (variables: { B: $CI_COMMIT_BRANCH } then sh -c $B) is not tracked.

Security Job Weakening Detection

GitLab lets you override any property of an included job. This means someone can include a security template (SAST, Secret Detection, Container Scanning, Dependency Scanning, DAST, License Scanning) but silently neutralize it. The pipeline still looks compliant, but the scanning is disabled. Maps to OWASP CICD-SEC-4 (Poisoned Pipeline Execution).

This control detects three weakening patterns, each a separate sub-control you can toggle independently:

  • allowFailureMustBeFalse (default: off, opt-in): Detects allow_failure: true. Off by default because GitLab templates ship with this setting.
  • rulesMustNotBeRedefined (default: on): Detects rules: overrides with when: never or when: manual.
  • whenMustNotBeManual (default: on): Detects when: manual set at job level.

Flagged: security jobs weakened

include:
- template: Security/SAST.gitlab-ci.yml
semgrep-sast:
allow_failure: true # failures silently ignored
secret_detection:
rules:
- when: never # job will never run
container_scanning:
when: manual # requires manual trigger

Plumber identifies a job as a security job when its name (the job id as it appears in .gitlab-ci.yml, for example semgrep-sast) matches one of the globs in securityJobPatterns. Wildcards (*) match any substring.

gitlab:
controls:
securityJobsMustNotBeWeakened:
enabled: true
securityJobPatterns:
- "*-sast"
- "secret_detection"
- "container_scanning"
- "*_dependency_scanning"
- "gemnasium-*"
- "dast"
- "dast_*"
- "license_scanning"
allowFailureMustBeFalse:
enabled: false
rulesMustNotBeRedefined:
enabled: true
whenMustNotBeManual:
enabled: true
Unverified Script Execution Detection

Detects CI/CD jobs that download and immediately execute scripts from the internet without integrity verification. This is a well-documented supply chain attack vector: an attacker who compromises the remote URL can serve a modified script that exfiltrates secrets. Maps to OWASP CICD-SEC-3 (Dependency Chain Abuse) and CICD-SEC-8 (Ungoverned Usage of 3rd Party Services).

Detected patterns:

  • Direct pipe to shell: curl ... | bash, wget ... | sh, curl ... | python, etc.
  • Download-and-execute: curl -o script.sh ... && bash script.sh
  • Download-redirect-execute: curl ... > install.sh; sh install.sh

Lines that include checksum verification (e.g., sha256sum, gpg --verify) between the download and execution are automatically excluded.

pipelineMustNotExecuteUnverifiedScripts:
enabled: true
trustedUrls: []
# - https://internal-artifacts.example.com/*

Add trusted URL patterns to trustedUrls (supports wildcards) to suppress findings for known-good sources.

Job Variable Override Detection

Detects CI/CD variables that are redefined in .gitlab-ci.yml when they should only be set in GitLab CI/CD Settings > Variables. An attacker who can modify .gitlab-ci.yml could override variables like SECURE_ANALYZERS_PREFIX to point to a fake registry, or set SAST_DISABLED: "true" to silently disable security scanners.

The control inspects only the raw user-authored YAML. Variables defined by included templates or components are not flagged.

pipelineMustNotOverrideJobVariables:
enabled: true
variables:
- SECURE_ANALYZERS_PREFIX
- SAST_DISABLED
- SAST_EXCLUDED_PATHS
- SAST_EXCLUDED_ANALYZERS
- SECRET_DETECTION_DISABLED
- SECRET_DETECTION_EXCLUDED_PATHS
- CONTAINER_SCANNING_DISABLED
- DAST_DISABLED
- DEPENDENCY_SCANNING_DISABLED
- LICENSE_SCANNING_DISABLED

Add any variable name your organization considers controlled. Matching is case-insensitive and any value triggers the issue (even "false").

Docker-in-Docker Detection

Detects CI/CD jobs that use Docker-in-Docker (dind) services. Running a Docker daemon inside a CI container on shared runners in privileged mode enables container escape, lateral movement, and access to secrets from other jobs on the same runner.

When detectInsecureDaemon is enabled (default: true), the control also flags jobs where TLS is disabled (DOCKER_TLS_CERTDIR="") or the Docker host uses the plaintext port (tcp://docker:2375).

pipelineMustNotUseDockerInDocker:
enabled: true
detectInsecureDaemon: true

Consider using Kaniko or Buildah for building container images in CI/CD as safer alternatives.

Issues

The CLI reports Issues using identifiers like ISSUE-XXX. Each links to a documentation page with a description, the impact, and before/after fix examples. You can also inspect a code locally:

Terminal window
plumber explain ISSUE-412
# shorthand:
plumber explain 412

Codes shipping today for GitLab:

IssueTitle
ISSUE-101Untrusted image source
ISSUE-102Forbidden container image tag
ISSUE-103Container image not pinned by digest
ISSUE-203Pipeline enables CI debug trace
ISSUE-204Unsafe variable expansion
ISSUE-205Job variable overrides controlled variable
ISSUE-401Hardcoded job
ISSUE-403Outdated template
ISSUE-404Forbidden include version
ISSUE-405Missing required template
ISSUE-406Forbidden override of required template
ISSUE-408Missing required component
ISSUE-409Forbidden override of required component
ISSUE-410Security job weakened
ISSUE-411Unverified script execution
ISSUE-412Docker-in-Docker service detected
ISSUE-413Docker-in-Docker with insecure daemon configuration
ISSUE-501Branch protection missing
ISSUE-505Branch protection configuration not compliant

Example Configuration

The gitlab.controls: section of a schema v2 .plumber.yaml:

version: "2.0"
gitlab:
controls:
containerImageMustNotUseForbiddenTags:
enabled: true
tags:
- latest
- dev
- main
# When true, ALL images must be pinned by digest. Takes precedence
# over the tags list, so even version tags like alpine:3.19 fail.
containerImagesMustBePinnedByDigest: false
containerImageMustComeFromAuthorizedSources:
enabled: true
trustDockerHubOfficialImages: true
trustedUrls:
- $CI_REGISTRY_IMAGE:*
- registry.gitlab.com/security-products/*
branchMustBeProtected:
enabled: true
defaultMustBeProtected: true
namePatterns:
- main
- release/*
allowForcePush: false
minMergeAccessLevel: 30 # Developer
minPushAccessLevel: 40 # Maintainer
pipelineMustNotIncludeHardcodedJobs:
enabled: true
includesMustBeUpToDate:
enabled: true
includesMustNotUseForbiddenVersions:
enabled: true
forbiddenVersions:
- latest
- "~latest"
- main
- master
- HEAD
defaultBranchIsForbiddenVersion: false
pipelineMustIncludeComponent:
enabled: false # Disabled by default. Enable and configure for your org.
# Expression syntax (use one, not both):
# required: components/sast/sast AND components/secret-detection/secret-detection
# Array syntax (OR of ANDs):
# requiredGroups:
# - ["components/sast/sast", "components/secret-detection/secret-detection"]
# - ["your-org/full-security/full-security"]
pipelineMustIncludeTemplate:
enabled: false # Disabled by default. Enable and configure for your org.
# Expression syntax (use one, not both):
# required: templates/go/go AND templates/trivy/trivy
# Array syntax (OR of ANDs):
# requiredGroups:
# - ["templates/go/go", "templates/trivy/trivy"]
# - ["templates/full-go-pipeline"]
# Detect debug trace variables that leak secrets in job logs.
pipelineMustNotEnableDebugTrace:
enabled: true
forbiddenVariables:
- CI_DEBUG_TRACE
- CI_DEBUG_SERVICES
# Detect user-controlled variables in shell re-interpretation contexts
# (eval, sh -c, etc.). Safe: echo $CI_COMMIT_BRANCH. Dangerous: eval
# "deploy $CI_COMMIT_BRANCH".
pipelineMustNotUseUnsafeVariableExpansion:
enabled: true
dangerousVariables:
- CI_MERGE_REQUEST_TITLE
- CI_MERGE_REQUEST_DESCRIPTION
- CI_COMMIT_MESSAGE
- CI_COMMIT_TITLE
- CI_COMMIT_TAG_MESSAGE
- CI_COMMIT_REF_NAME
- CI_COMMIT_REF_SLUG
- CI_COMMIT_BRANCH
- CI_MERGE_REQUEST_SOURCE_BRANCH_NAME
- CI_EXTERNAL_PULL_REQUEST_SOURCE_BRANCH_NAME
# Regex patterns to allow specific script lines (escape $ as \\$).
allowedPatterns:
- "helm.*--set.*\\$CI_"
- "terraform workspace select.*\\$CI_"
- "docker build.*--build-arg.*\\$CI_"
# Detect security scanning jobs that have been silently weakened.
securityJobsMustNotBeWeakened:
enabled: true
securityJobPatterns:
- "*-sast"
- "secret_detection"
- "container_scanning"
- "*_dependency_scanning"
- "gemnasium-*"
- "dast"
- "dast_*"
- "license_scanning"
allowFailureMustBeFalse:
enabled: false # opt-in: GitLab templates ship with allow_failure: true
rulesMustNotBeRedefined:
enabled: true
whenMustNotBeManual:
enabled: true
# Detect controlled variables overridden in .gitlab-ci.yml.
pipelineMustNotOverrideJobVariables:
enabled: true
variables:
- SECURE_ANALYZERS_PREFIX
- SAST_DISABLED
- SAST_EXCLUDED_PATHS
- SECRET_DETECTION_DISABLED
- CONTAINER_SCANNING_DISABLED
- DAST_DISABLED
# Detect unverified script downloads and execution (curl|bash, wget|sh).
pipelineMustNotExecuteUnverifiedScripts:
enabled: true
trustedUrls: []
# - https://internal-artifacts.example.com/*
# Detect Docker-in-Docker services and insecure daemon configuration.
pipelineMustNotUseDockerInDocker:
enabled: true
detectInsecureDaemon: true

Info

pipelineMustIncludeComponent and pipelineMustIncludeTemplate support two syntax options for defining requirements (use one, not both):

  • Expression syntax (required): A natural boolean expression using AND, OR, and parentheses. AND binds tighter than OR.
  • Array syntax (requiredGroups): A list of groups using “OR of ANDs” logic. Outer array = OR, inner array = AND.

GitLab Integration

Plumber integrates directly with GitLab to provide visual compliance feedback where your team works.

Merge Request Comments

Automatically post compliance summaries on merge requests to catch issues before they’re merged.

Terminal window
plumber analyze --mr-comment

Or via the GitLab CI component:

include:
- component: gitlab.com/getplumber/plumber/plumber@v0.2.2
inputs:
mr_comment: true # Requires api scope on token

Merge request comment showing compliance results

Features:

  • Shows compliance badge with pass/fail status
  • Lists all controls with individual compliance percentages
  • Details specific issues found with job names and image references
  • Automatically updates on each pipeline run (no duplicate comments)

Caution

Token requirement: The api scope is required (not read_api) to create/update MR comments. The --mr-comment flag only works in merge request pipelines (CI_MERGE_REQUEST_IID must be set).

Project Badges

Display a live compliance badge on your project’s overview page.

Terminal window
plumber analyze --badge

Or via the GitLab CI component:

include:
- component: gitlab.com/getplumber/plumber/plumber@v0.2.2
inputs:
badge: true # Requires api scope on token

Project badge showing Plumber compliance percentage

Features:

  • Shows current compliance percentage
  • Green when compliance meets threshold, red when below
  • Only updates on default branch pipelines (not on MRs or feature branches)
  • Badge appears in GitLab’s “Project information” section

Caution

Token requirement: The api scope is required (not read_api) and Maintainer role to manage project badges.

The Plumber GitLab CI/CD component (drop-in pipeline integration) is documented in the GitLab CI Component section below. For installation and the provider-agnostic commands, see the main CLI page.

Selective Control Execution

You can run or skip specific controls using their YAML key names from .plumber.yaml. This is useful for iterative debugging or targeted CI checks.

Terminal window
# Only check image tags and branch protection
plumber analyze --controls containerImageMustNotUseForbiddenTags,branchMustBeProtected
# Run everything except branch protection
plumber analyze --skip-controls branchMustBeProtected

Controls not selected are reported as skipped in the output. The --controls and --skip-controls flags are mutually exclusive.

Valid GitLab control names
Control Name
branchMustBeProtected
containerImageMustComeFromAuthorizedSources
containerImageMustNotUseForbiddenTags
includesMustBeUpToDate
includesMustNotUseForbiddenVersions
pipelineMustIncludeComponent
pipelineMustIncludeTemplate
pipelineMustNotEnableDebugTrace
pipelineMustNotExecuteUnverifiedScripts
pipelineMustNotIncludeHardcodedJobs
pipelineMustNotOverrideJobVariables
pipelineMustNotUseDockerInDocker
pipelineMustNotUseUnsafeVariableExpansion
securityJobsMustNotBeWeakened

GitLab CI Component

Beyond running the CLI yourself, Plumber ships as a GitLab CI/CD component: a drop-in include: that runs compliance scanning on every pipeline with no binary to install. It uses the same engine, the same .plumber.yaml, and the same controls and issues documented above. It produces the same output and supports the same MR comments and badges.

Quick Start (GitLab.com)

Info

For self-hosted GitLab instances, see Hosting on self-hosted GitLab below.

  1. Create a GitLab token

    Use a token with read_api + read_repository scopes (or api if you enable mr_comment / badge), as described under Authentication above.

  2. Add the token to your project

    Go to Settings → CI/CD → Variables and add it as GITLAB_TOKEN (masked recommended).

  3. Add the component to your .gitlab-ci.yml

    workflow:
    rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS # prevents duplicate pipelines
    when: never
    - if: $CI_COMMIT_BRANCH
    - if: $CI_COMMIT_TAG
    include:
    - component: gitlab.com/getplumber/plumber/plumber@v0.2.2
    # inputs:
    # stage: .pre | by default runs in .pre which only runs if there is at least another CI job in another stage

    Get the latest version from the CI/CD Catalog.

    Info

    Why workflow:rules? Without it, pushing to a branch with an open merge request creates two pipelines (a branch pipeline and an MR pipeline), splitting your jobs between them. The block above ensures a single pipeline per push: MR pipeline when an MR exists, branch pipeline otherwise. This is the recommended GitLab pattern. If you already have workflow:rules, keep yours and just add the include.

  4. Run your pipeline

    Plumber now runs on every pipeline (default branch, tags, and open merge requests) and reports compliance issues.

Hosting on self-hosted GitLab

If you run a self-hosted GitLab instance, you need your own copy of the component since gitlab.com components can’t be accessed from your instance. There are two ways:

Customizing the component

Override any input to fit your needs:

include:
- component: gitlab.com/getplumber/plumber/plumber@v0.2.2
inputs:
# Target (defaults to current project)
server_url: https://gitlab.example.com # Self-hosted GitLab
project_path: other-group/other-project # Analyze a different project
branch: develop # Analyze a specific branch
ci_config_path: $CI_CONFIG_PATH # CI config path (GitLab predefined variable)
# Compliance
threshold: 80 # Minimum % to pass (default: 100)
config_file: configs/my-plumber.yaml # Custom config path
# Output
output_file: plumber-report.json # Export JSON report
pbom_file: plumber-pbom.json # PBOM artifact
pbom_cyclonedx_file: plumber-cyclonedx-sbom.json # CycloneDX SBOM (auto-uploaded as a GitLab report)
print_output: true
# Job behavior
stage: test # Run in a different stage
allow_failure: true # Don't block the pipeline on failure
gitlab_token: $MY_CUSTOM_TOKEN # Different variable name
verbose: true
# Selective execution (mutually exclusive)
controls: containerImageMustNotUseForbiddenTags,branchMustBeProtected
# skip_controls: branchMustBeProtected
# MR feedback (require `api` scope, see GitLab Integration above)
mr_comment: true
badge: true

The controls / skip_controls inputs map to the CLI --controls / --skip-controls flags (valid names). mr_comment and badge are the component equivalents of the CLI --mr-comment / --badge flags shown under GitLab Integration.

All inputs

InputDefaultDescription
server_url$CI_SERVER_URLGitLab instance URL
project_path$CI_PROJECT_PATHProject to analyze
branch$CI_COMMIT_REF_NAMEBranch to analyze
ci_config_path$CI_CONFIG_PATHCI configuration file path to analyze. Defaults to the GitLab predefined variable (.gitlab-ci.yml unless customized in project settings)
gitlab_token$GITLAB_TOKENGitLab API token (read_api + read_repository, or api if mr_comment / badge is enabled)
threshold100Minimum compliance % to pass
config_file(auto-detect)Path to config file (relative to repo root). Auto-detects .plumber.yaml, falls back to default
output_fileplumber-report.jsonPath to write JSON results
pbom_fileplumber-pbom.jsonPath to write the PBOM
pbom_cyclonedx_fileplumber-cyclonedx-sbom.jsonPath to write the CycloneDX SBOM (auto-uploaded as a GitLab report)
print_outputtruePrint text output to stdout
stage.prePipeline stage for the job. .pre runs before all other stages but requires at least one job in a regular stage. If Plumber is the only job, set this to test or another stage
imagegetplumber/plumber:0.1Docker image to use
allow_failurefalseAllow the job to fail without blocking
verbosefalseEnable debug output
mr_commentfalsePost/update a compliance comment on the merge request (requires api scope)
badgefalseCreate/update a compliance badge (requires api scope; default branch only)
controls-Run only listed controls (comma-separated). Cannot be used with skip_controls
skip_controls-Skip listed controls (comma-separated). Cannot be used with controls
fail_warningsfalseTreat configuration warnings (unknown keys) as errors (exit 2)

Component configuration resolution

The component resolves your configuration in priority order:

  1. config_file input set uses your specified path (relative to repo root).
  2. .plumber.yaml in repo root uses your repo’s config file.
  3. No config found uses the default embedded in the container.

To author one, run plumber config generate (see the main CLI page) or create it manually from the default config. The CycloneDX SBOM the component writes is automatically uploaded as a GitLab CycloneDX report.

Troubleshooting

IssueSolution
GITLAB_TOKEN environment variable is requiredSet the GITLAB_TOKEN environment variable with a valid GitLab token
401 UnauthorizedToken needs read_api + read_repository scopes, from a Maintainer or higher
403 Forbidden on MR settingsExpected on non-Premium GitLab; continues without that data
403 Forbidden on MR commentToken needs api scope (not read_api) when --mr-comment is enabled
403 Forbidden on badgeToken needs api scope (not read_api) when --badge is enabled
404 Not FoundVerify the project path and GitLab URL are correct
MR comment not posted--mr-comment only works in merge request pipelines (CI_MERGE_REQUEST_IID must be set)
Badge not created/updatedToken needs api scope and Maintainer role (or higher) on the project
Configuration file not foundEnsure --config points at the real file (use an absolute path in Docker). Create one with plumber config generate or plumber config init
Component not found (self-hosted)You must import or mirror the component to your instance (Hosting on self-hosted GitLab)
Plumber component job not runningThe component’s default stage is .pre, which requires at least one other job in a regular stage. Override with inputs: { stage: test }
Two pipelines on the same pushAdd workflow:rules to prevent duplicate branch + MR pipelines (see Quick Start)
Component job skipped on branchThe component runs only on merge request events, the default branch, and tags

Info

Need help? Open an issue on GitHub or join our Discord.