✨ gitlab: add 12 supply-chain security checks for push rules, CI/CD, and webhooks#2976
✨ gitlab: add 12 supply-chain security checks for push rules, CI/CD, and webhooks#2976tas50 wants to merge 1 commit into
Conversation
…and webhooks Adds Tier 1 hardening checks across three previously-uncovered GitLab subsystems, each with GitLab runtime + Terraform HCL/plan/state variants and verified compliance tags: Push rules (Premium+): - push-rule-prevent-secrets reject files matching secret patterns - push-rule-reject-unsigned-commits - push-rule-committer-check committer is a verified GitLab user - push-rule-member-check author is a GitLab user Secret detection: - secret-push-protection pre-receive secret detection (Ultimate) CI/CD security: - ci-variables-masked variables hidden in job logs - ci-variables-protected variables scoped to protected refs - job-token-scope-enabled restrict inbound job-token access - webhook-ssl-verification enforce TLS verification on webhooks - no-public-jobs job logs not public to non-members Merge controls: - no-merge-on-skipped-pipeline block merge when pipeline is skipped - discussions-resolved all threads resolved before merge Registered under new "Push Rules" and "CI/CD Security" groups plus the existing Merge Request Security and Security Scanning groups. Bumps the policy to 1.9.0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| ### Audit via Console | ||
|
|
||
| 1. In GitLab, navigate to your project. | ||
| 2. Go to **Settings** > **Repository**. |
There was a problem hiding this comment.
🔵 suggestion — The Terraform HCL/Plan/State variants for secret-push-protection filter on gitlab_project (a broad resource), whereas the other new checks that have dedicated resource types (e.g., gitlab_project_push_rules, gitlab_project_variable, gitlab_project_hook) correctly filter on those specific types. This means the secret-push-protection Terraform checks will match any gitlab_project resource and assert pre_receive_secret_detection_enabled == true on all of them — which may be intentional since this is a project-level attribute, but it could cause false positives for projects where this Ultimate-only feature doesn't apply. Consider whether the Terraform variants should also gate on the plan (like the GitLab variant gates on gitlab.namespace.plan == "ultimate").
|
|
||
| A passing project returns `false`. A failing project returns `true`. | ||
| remediation: | ||
| - id: gitlab |
There was a problem hiding this comment.
🟡 warning — The no-public-jobs Terraform HCL check uses arguments["public_jobs"] == false, but Terraform treats an omitted attribute as its default value (which for public_jobs in the GitLab provider is true). If a user doesn't set public_jobs at all, the attribute won't appear in arguments and the check could pass vacuously via .all() on an empty match. The same pattern affects no-merge-on-skipped-pipeline HCL variant with allow_merge_on_skipped_pipeline. Consider whether omitted attributes should be treated as a failure.
| This check ensures that the project requires all merge request discussions to be resolved before a merge request can be merged. This guarantees that review comments, including those raising security concerns, are addressed rather than merged past. | ||
|
|
||
| **Why this matters** | ||
|
|
There was a problem hiding this comment.
🔵 suggestion — The no-merge-on-skipped-pipeline Terraform variants use != true while the GitLab variant uses == false. The != true pattern is more permissive (also passes for null/absent). This is likely intentional for Terraform where the field may be absent, but it's worth confirming this asymmetry is deliberate, as == false would be more strict and consistent with the GitLab variant's intent.
Summary
Adds 12 Tier 1 security checks to
mondoo-gitlab-securitycovering three GitLab subsystems the policy did not previously touch: push rules, CI/CD variables/tokens, and webhooks/merge controls. Every check ships with a GitLab runtime variant plus Terraform HCL/plan/state variants and verified compliance tags. Policy bumped to1.9.0.Checks added
Push Rules (Premium+,
gitlab_project_push_rules)push-rule-prevent-secrets(impact 90) — reject files matching secret patternspush-rule-reject-unsigned-commits(80) — require signed commitspush-rule-committer-check(70) — committer must be a verified GitLab userpush-rule-member-check(70) — commit author must be a GitLab userSecret detection
secret-push-protection(85, Ultimate) — pre-receive secret detection (pre_receive_secret_detection_enabled)CI/CD Security
ci-variables-masked(80) — variables masked in job logsci-variables-protected(70) — variables scoped to protected refsjob-token-scope-enabled(80) — restrict inbound CI/CD job-token access (lateral-movement prevention)webhook-ssl-verification(70) — enforce TLS verification on webhook deliveryno-public-jobs(70) — job logs/artifacts not public to non-membersMerge Request Security
no-merge-on-skipped-pipeline(80) — block merge when the pipeline is skippeddiscussions-resolved(60) — all threads resolved before mergeCompliance tags
Mapped across the 13 frameworks the policy already tags, by control objective (each verified against the framework control text,
falsewhere no strict fit):Validation
cnspec policy lint content/mondoo-gitlab-security.mql.yaml→ validpython3 content/validation/validate_remediation_commands.py gitlab→ allglabcommands PASSjobTokenScope,publicJobs,preReceiveSecretDetectionEnabled) required a local gitlab provider rebuild from~/dev/mql; they are present in the provider source and Go implementation.🤖 Generated with Claude Code