Admission Controller scoping

Admission Controller Scoping - First Iteration

Goal

Define the scoping model for Runner Admission Controllers in the first iteration, establishing a flexible database structure that supports instance-level scoping while enabling future expansion to group and project levels.

Current State

Runner (Admission) Controllers are currently implemented at the instance level in Rails (see #578037 (closed) and #578797 (closed)).

Problem Statement

The current instance-level scoping is too broad for organizations that need fine-grained control. For example, a macOS runner team should be able to enforce admission controllers only on their specific runners without affecting other runners on the instance.

Proposed Solution

Database Schema: Postgres Inheritance Pattern

We will implement a parent-child table structure using Postgres inheritance to support multiple scoping types:

Parent Table: ci_runner_controller_scopings

Child Tables (via Postgres Inheritance):

  1. ci_runner_controller_scopings_instance - Instance-level scoping
    • runner_controller_id → references ci_runner_controllers
    • type = 'instance'
    • target_id = NULL (applies to entire instance)
  2. ci_runner_controller_scopings_group - Group-level scoping (maybe future iteration)
    • runner_controller_id → references ci_runner_controllers
    • type = 'group'
    • target_id → references namespaces (group)
  3. ci_runner_controller_scopings_project - Project-level scoping (maybe future iteration)
    • runner_controller_id → references ci_runner_controllers
    • type = 'project'
    • target_id → references projects
  4. ci_runner_controller_scopings_runners - Runner-level scoping (future iteration)
    • runner_controller_id → references ci_runner_controllers
    • type = 'runner'
    • target_id → references runners

Behavior Model

When a job is dequeued for execution on a runner:

  1. Query all applicable admission controllers from ci_runner_controller_scopings:
    • Instance-level controllers (always included)
    • Group-level controllers (if job's project belongs to a scoped group)
    • Project-level controllers (if job's project is scoped)
    • Runner-specific controllers (if runner has scoped controllers)
  2. Return controller list to the Job Router/Runner with the job response
  3. All returned controllers MUST pass before the job can be executed

Cells Consideration

This design is compatible with GitLab's Cells architecture:

  • Each cell maintains its own ci_runner_controller_scopings table
  • Instance-level scoping applies within a cell's scope
  • Group, project and runner scoping are naturally cell-aware (groups/projects/runners belong to specific cells)
  • No cross-cell coordination required for admission control decisions

First Iteration Scope

In this iteration, we will:

  • Implement the parent table structure with instance-level scoping
  • Add enabled flag to Runner Controllers (prevents chicken-and-egg problem) (WIP: Implement `enabled` field in runner controller (!215485))
  • Support querying applicable controllers during job dequeue
  • Establish the inheritance pattern for future scoping types
Edited by Timo Furrer