Show CI pipeline error when Secrets Manager access is denied by entitlement

What does this MR do and why?

Implements https://gitlab.com/gitlab-org/gitlab/-/work_items/613392.

Previously, when a CI job requested GitLab Secrets Manager (GSM) secrets but the namespace entitlement denied direct reads, gitlab_secrets_manager_payload in the build runner presenter returned {} and the runner failed the job with a generic secret-resolution error. The only signals of the denial were internal telemetry events. Users had no indication of why the job failed or how to fix it.

This MR fails the job at scheduling time with a dedicated, actionable failure reason instead:

  • Adds a new failure reason secrets_manager_access_denied (enum value 1018 in Enums::Ci::CommitStatus). It covers all entitlement denial reasons — trial expired, credits exhausted, on-demand disabled, subscription grace period expired, and beta program ended for non-opted-in namespaces — not just the beta cutoff.
  • Adds a check to pre_assign_runner_checks in EE::Ci::RegisterJobService, following the same pattern as secrets_provider_not_found: if the build requests gitlab_secrets_manager secrets and Entitlement#permits_direct_read? is false, the build is dropped with the new failure reason before runner assignment.
  • Fails open so job pickup never blocks on or fails because of CustomersDot: entitlement resolution uses Entitlement.for! with a 0.25 s HTTP timeout and rescues all errors to permit scheduling. The check exits early for builds without GSM secrets, when the native_secrets_management license is absent, or when the secrets_manager_paid_experience feature flag is disabled (the flag guard is required because the resolver returns ineligible when the flag is off). Per-request memoization in the entitlement resolver caps CustomersDot calls at one per namespace.
  • Shows a user-facing message on the job page/log via CommitStatusPresenter: "This job could not retrieve secrets because the namespace does not have access to GitLab Secrets Manager. To restore access, start a trial or purchase GitLab Secrets Manager for the top-level group." with a "How do I fix it?" link to a new troubleshooting docs section. A short status text is added in Gitlab::Ci::Status::Build::Failed.
  • Keeps emitting the existing DenialTelemetry internal event, with a new job_scheduling surface so dashboards can distinguish it from the existing ci_runner_payload surface.
  • The GraphQL CiJobFailureReason enum picks up the new value automatically; doc/api/graphql/reference/_index.md is regenerated.
  • Adds a troubleshooting section to doc/ci/secrets/secrets_manager/_index.md.

Notes on scope:

  • The grace window (blocked_reason: grace) still permits direct reads, so those builds are not dropped. This matches the presenter behavior.
  • The scheduling check does not replicate the presenter's NamespaceEnrollment check. Entitlement is the GA-era gate, and a denied-but-unenrolled namespace now gets an actionable message instead of a generic runner error.

References

Screenshots or screen recordings

Tested locally:

Before After
image image

How to set up and validate locally

  1. Enable the feature flags in a rails console:

    Feature.enable(:secrets_manager_paid_experience)
    Feature.enable(:secrets_manager) # if not already enabled
  2. On a project in a group with GSM provisioned, add a CI job that requests a GSM secret:

    test_job:
      script: echo "test"
      secrets:
        DATABASE_PASSWORD:
          gitlab_secrets_manager:
            name: password
  3. Simulate a denied entitlement in a rails console. Entitlement is resolved from CustomersDot, so the easiest way locally is a temporary monkey-patch (or point your GDK at CustomersDot staging), for example:

    SecretsManagement::Entitlement.define_singleton_method(:for!) do |*|
      SecretsManagement::Entitlement.new(state: :blocked, blocked_reason: :trial_expired)
    end
  4. Run a pipeline with a runner available. The job should fail immediately with failure reason secrets_manager_access_denied, and the message should be visible on the job page.

  5. Run the specs:

    bundle exec rspec ee/spec/services/ci/register_job_service_spec.rb -e 'GitLab Secrets Manager secrets defined'

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Dmytro Biryukov

Merge request reports

Loading
Loading