GitLab Example Queries#

Projects and languages#

List the programming languages detected across GitLab projects:

MATCH (project:GitLabProject)
WHERE project.languages IS NOT NULL
WITH apoc.convert.fromJsonMap(project.languages) AS languages
UNWIND keys(languages) AS language
RETURN DISTINCT language
ORDER BY language

Find projects that report a specific language without requiring APOC:

MATCH (project:GitLabProject)
WHERE project.languages CONTAINS '"Python"'
RETURN project.name, project.languages

The second query performs a string search. Parse languages with apoc.convert.fromJsonMap() when exact percentages are needed.

CI/CD security#

Find runners that accept untagged jobs from unprotected refs:

MATCH (runner:GitLabRunner)
WHERE runner.run_untagged = true
  AND runner.access_level = 'not_protected'
RETURN runner.id, runner.description, runner.runner_type

Find unmasked, unprotected CI/CD variables:

MATCH (variable:GitLabCIVariable)
WHERE variable.protected = false
  AND variable.masked = false
RETURN variable.scope_type, variable.key, variable.environment_scope

Find environments that use unprotected variables:

MATCH (environment:GitLabEnvironment)-[:HAS_CI_VARIABLE]->(variable:GitLabCIVariable)
WHERE variable.protected = false
RETURN environment.name, variable.key, variable.environment_scope

Find project includes that are not pinned to an immutable commit:

MATCH (config:GitLabCIConfig)-[:USES_INCLUDE]->(include:GitLabCIInclude)
WHERE include.include_type = 'project'
  AND include.is_pinned = false
RETURN config.project_id, include.location, include.ref

Find manually triggerable pipelines that reference protected variables:

MATCH (config:GitLabCIConfig)
WHERE 'manual' IN config.trigger_rules
  AND size(config.referenced_protected_variables) > 0
RETURN config.project_id,
       config.referenced_protected_variables,
       config.trigger_rules

Container registry#

List container images and their tags:

MATCH (repository:GitLabContainerRepository)
      -[:REPO_IMAGE]->(tag:GitLabContainerRepositoryTag)
      -[:IMAGE]->(image:GitLabContainerImage)
RETURN repository.name,
       tag.name,
       image.digest,
       image.architecture,
       image.os

Find multi-architecture images and their platform-specific images:

MATCH (manifest:GitLabContainerImage {type: 'manifest_list'})
      -[:CONTAINS_IMAGE]->(image:GitLabContainerImage)
RETURN manifest.digest, image.digest, image.architecture, image.os

Find images with signatures or provenance attestations:

MATCH (attestation:GitLabContainerImageAttestation)
      -[:ATTESTS]->(image:GitLabContainerImage)
RETURN image.digest,
       attestation.attestation_type,
       attestation.predicate_type

Find layers shared by multiple GitLab images:

MATCH (image:GitLabContainerImage)-[:HAS_LAYER]->(layer:GitLabContainerImageLayer)
WITH layer, count(DISTINCT image) AS image_count
WHERE image_count > 1
RETURN layer.diff_id, layer.size, image_count
ORDER BY image_count DESC

Find layers shared between GitLab Container Registry and Amazon ECR:

MATCH (layer:ImageLayer)
MATCH (gitlab_image:GitLabContainerImage)-[:HAS_LAYER]->(layer)
MATCH (ecr_image:AWSECRImage)-[:HAS_LAYER]->(layer)
RETURN layer.diff_id,
       count(DISTINCT gitlab_image) AS gitlab_images,
       count(DISTINCT ecr_image) AS ecr_images

Trivy integration#

Find Trivy vulnerabilities that affect GitLab container images:

MATCH (finding:TrivyImageFinding)-[:AFFECTS]->(image:GitLabContainerImage)
RETURN finding.name, finding.severity, image.uri, image.digest
ORDER BY finding.severity DESC

Find critical image vulnerabilities and available package fixes:

MATCH (finding:TrivyImageFinding {severity: 'CRITICAL'})
      -[:AFFECTS]->(image:GitLabContainerImage)
MATCH (finding)-[:AFFECTS]->(package:PackageVersion)
OPTIONAL MATCH (package)-[:SHOULD_UPDATE_TO]->(fix:TrivyFix)
RETURN finding.name,
       image.uri,
       package.name,
       package.version,
       fix.version AS fixed_version