Skip to content

Security Configuration: Define GraphQL API queries and mutations

Summary

To power the new configuration section, which will allow users to add and remove refs from being security tracked, we need to add some GraphQL queries and mutations.

This issue is the place to propose and agree on a schema, so it can be used as a contract between the frontend and backend.

Schema Proposal

# ============================================================================
# QUERIES
# ============================================================================

extend type Project {
  # Refs (branches or tags) being tracked for security vulnerabilities
  # Returns paginated list of currently tracked refs (max 4 total - including the default branch)
  # Supports cursor-based pagination
  securityTrackedRefs(
    first: Int
    after: String
    last: Int
    before: String
  ): SecurityTrackedRefConnection
}

# ============================================================================
# MUTATIONS
# ============================================================================

extend type Mutation {
  # Start tracking refs for security vulnerabilities ⁉️ Feedback on the naming would be appreciated
  securityTrackedRefsTrack(
    input: SecurityTrackedRefsTrackInput!
  ): SecurityTrackedRefsTrackPayload

  # Stop tracking refs for security vulnerabilities ⁉️ Feedback on the naming would be appreciated
  securityTrackedRefsUntrack(
    input: SecurityTrackedRefsUntrackInput!
  ): SecurityTrackedRefsUntrackPayload
}

# ============================================================================
# INPUT TYPES
# ============================================================================

# Input for tracking new refs
input SecurityTrackedRefsTrackInput {
  # Full path of the project
  # Example: "gitlab-org/gitlab", "my-group/my-project"
  projectPath: ID!

  # Names of the refs to start tracking (branches or tags)
  # Examples: ["main", "develop"], ["v1.0.0", "v2.0.0"], ["18-2-stable-ee"]
  refNames: [String!]!
}

# Input for untracking refs
input SecurityTrackedRefsUntrackInput {
  # Full path of the project
  # Example: "gitlab-org/gitlab", "my-group/my-project"
  projectPath: ID!

  # Global IDs of the tracked refs to stop tracking
  # Examples: ["gid://gitlab/Security::TrackedRef/123", "gid://gitlab/Security::TrackedRef/456"]
  refIds: [ID!]!

  # Whether to archive associated vulnerabilities instead of deleting them
  # Example: true (archive), false (delete permanently)
  # Default: true
  archiveVulnerabilities: Boolean! = true
}

# ============================================================================
# PAYLOAD TYPES
# ============================================================================

# Return type for tracking refs
type SecurityTrackedRefsTrackPayload {
  # Refs that were successfully tracked
  # Returns array of SecurityTrackedRef objects that were created
  trackedRefs: [SecurityTrackedRef!]

  # Errors encountered during the operation
  # Examples: [], ["Ref 'invalid-ref' does not exist"], ["Maximum of 16 refs can be tracked"]
  errors: [String!]!
}

# Return type for untracking refs
type SecurityTrackedRefsUntrackPayload {
  # Global IDs of refs that were successfully untracked
  # Examples: ["gid://gitlab/Security::TrackedRef/123"], []
  untrackedRefIds: [ID!]

  # Errors encountered during the operation
  # Examples: [], ["Cannot untrack default branch"], ["Ref not found"]
  errors: [String!]!
}

# ============================================================================
# CONNECTION TYPES (for pagination)
# ============================================================================

# The connection type for SecurityTrackedRef
type SecurityTrackedRefConnection {
  edges: [SecurityTrackedRefEdge]
  nodes: [SecurityTrackedRef]
  pageInfo: PageInfo!
  count: Int!
}

type SecurityTrackedRefEdge {
  cursor: String!
  node: SecurityTrackedRef
}

# ============================================================================
# OBJECT TYPES
# ============================================================================

# Represents a ref (branch or tag) tracked for security vulnerabilities
type SecurityTrackedRef {
  # Global ID of the tracked ref
  # Example: "gid://gitlab/Security::TrackedRef/123"
  id: ID!

  # Name of the ref (branch or tag name)
  # Examples: "main", "develop", "18-2-stable-ee", "v18.1.4", "release/2.0"
  name: String!

  # Type of the ref (branch or tag)
  # Values: HEADS (for branches), TAGS (for tags)
  refType: RefType!

  # Whether this is the default branch
  # Example: true (for main/master), false (for other refs)
  isDefault: Boolean!

  # Whether this ref is protected
  # Example: true (protected), false (not protected)
  isProtected: Boolean!

  # Latest commit on the ref
  # Returns standard GitLab Commit type with fields like sha, title, etc.
  commit: Commit

  # Count of open vulnerabilities on this ref
  # Example: 42, 0, 258
  vulnerabilitiesCount: Int!

  # When tracking was enabled for this ref
  # Example: "2025-10-29T14:30:00Z"
  trackedAt: Time!
}

Usage Examples

Query
query GetSecurityTrackedRefs($projectPath: ID!) {
  project(fullPath: $projectPath) {
    id
    securityTrackedRefs {     # Example Values:
      id                      # "gid://gitlab/Security::TrackedRef/1"
      name                    # "main"
      refType                 # HEADS
      isDefault               # true
      isProtected             # true
      vulnerabilitiesCount    # 258
      trackedAt               # "2025-01-15T10:30:00Z"
      commit {
        sha                   # "df210850abc123..."
        shortId               # "df21085"
        title                 # "Apply 1 suggestion(s) to 1 file(s)"
        authoredDate          # "2025-10-20T09:59:00Z"
        webPath               # "/gitlab-org/gitlab/-/commit/df21085"
      }
    }
  }
}
Mutations

Track new refs

# Variables:
# {
#   "projectPath": "gitlab-org/gitlab",
#   "refNames": ["18-2-stable-ee", "v18.1.4"]
# }
mutation TrackRefs($projectPath: ID!, $refNames: [String!]!) {
  securityTrackedRefsTrack(
    input: { projectPath: $projectPath, refNames: $refNames }
  ) {
    trackedRefs {             # Example Values:
      id                      # "gid://gitlab/Security::TrackedRef/42"
      name                    # "18-2-stable-ee"
      refType                 # HEADS
      vulnerabilitiesCount    # 0
    }
    errors                    # []
  }
}

Untrack Ref

# Variables:
# {
#   "projectPath": "gitlab-org/gitlab",
#   "refIds": ["gid://gitlab/Security::TrackedRef/42"],
#   "archiveVulnerabilities": true
# }
mutation UntrackRefs(
  $projectPath: ID!
  $refIds: [ID!]!
  $archiveVulnerabilities: Boolean!
) {
  securityTrackedRefsUntrack(
    input: {
      projectPath: $projectPath
      refIds: $refIds
      archiveVulnerabilities: $archiveVulnerabilities
    }
  ) {
    untrackedRefIds           # ["gid://gitlab/Security::TrackedRef/42"]
    errors                    # []
  }
}
Edited by David Pisek