Skip to main content

GitLab

CatalogDiscoveryGitOpsScorecards

GitLab is a Git-based version control system with cloud and self-hosted options. By integrating GitLab into Cortex, you can easily import entities, view commits alongside other events, and monitor development maturity with Scorecards.

Setup and configuration

Getting started

In order to connect Cortex to your GitLab instance, you’ll first need to create a personal access token with the read_api scope.

If you're using the Scaffolder for entities in a given GitLab instance, that configuration needs the full api scope.

Configuration

Once you've created a GitLab token, you can configure the integration from GitLab settings in Cortex.

caution

If you do not see the settings page you're looking for, you likely don't have the proper permissions and need to contact your admin.

Select Add GitLab configuration and enter the following information in the modal:

  • Account alias: Used to tie entity registrations to different configuration accounts.
  • Token: Personal access token generated earlier.
  • Host (optional): URL for your custom GitLab instance (if applicable).
    • Enter the URL without the API path (e.g. https://gitlab.getcortexapp.com)

You can also choose to Hide personal projects. Toggle this setting off to allow Cortex to pull your personal projects.

Once you save your configuration, you'll see the last four characters of the token you entered. If you’ve set everything up correctly, you’ll see the option to Remove Integration in Settings.

You can also use the Test all configurations button to confirm that the configuration was successful. If your configuration is valid, you’ll see a banner that says “Configuration is valid. If you see issues, please see documentation or reach out to Cortex support.”

The GitLab integration has multi-account support so you can add a configuration for each additional by repeating the above process.

Each configuration requires an alias, which Cortex uses to correlate the designated with registrations for various entities. Registrations can also use a default configuration without a listed alias.

You can edit aliases and default configurations from the GitLab page in settings. Select the edit icon next to a given configuration and toggle "Set as default" on. If you only have one configuration, it will automatically be set as the default.

caution

If you're using a self-hosted instance of GitLab, you'll need to verify that your Cortex instance is able to reach the GitLab instance.

We route our requests through a static IP address. Reach out to support at help@cortex.io to receive details about our static IP. If you're unable to directly allowlist our static IP, you can route requests through a secondary proxy in your network that has this IP allowlisted and have that proxy route traffic to your GitLab instance.

Registration

Discovery

Cortex will discover entities for import from your GitLab configuration(s). These will appear in the import entities workflow.

Entity descriptor

Git

By specifying the x-cortex-git field in your Cortex entity descriptor, you'll be able to see Git information in the entity page, including the top language, recent commits, and top contributors.

x-cortex-git:
gitlab:
repository: cortex/docs
basepath: myService
alias: myApp
FieldDescriptionRequired
repositoryGitLab project ID or namespace/repo as defined in GitLab
basepathSubdirectory for the entity if it is in a monorepo
aliasAlias is optional and only relevant if you have opted into multi-account support

Ownership

You can define the following block in your Cortex entity descriptor to add your GitLab groups.

Team name should match the group name in GitLab.

x-cortex-owners:
- type: group
name: Team Name
provider: GITLAB
description: This is a description for this owner
FieldDescriptionRequired
typeOwnership type; must be defined as group for GitLab teams
nameGitLab team name
providerName of integration (in this case, GITLAB)
descriptionDescription for the GitLab team

Identity mapping

Cortex maps users' email addresses to discovered GitLab accounts, so you never need to define email ownership in an entity descriptor.

You can confirm users' GitLab accounts are connected from GitLab identity mappings in settings.

Expected results

Entity pages

Cortex uses the GitLab integration for a significant amount of data that appears on entities' detail pages.

The GitLab integration will populate the Repo and Language detail blocks on an entity's details page.

In the Recent activity preview, you'll find the recent commits and releases. These will also appear in the event timeline.

These data will appear for entities imported from a Git source or those that have a Git repo defined in their YAMLs.

Events

On an entity's Events page, you can find all of the commits and releases associated with that entity. Each is hyperlinked to the commit or release page in GitLab and includes a timestamp.

Integrations - Git

You can access more detailed information pulled from GitLab in the Git tab under Integrations in the sidebar. At the top of the Git page, you'll find the repo(s) associated with that entity and the most-used language in files for that entity. In the Top contributors block, you'll find the three users who have contributed the most code and the number of their contributions.

In the Commits section, you'll find the 10 most recent commits and metadata about each. Below Commits is the Recent releases section, which includes the 5 most recent releases.

Team pages

When a GitLab team is registered in a team entity descriptor, Cortex will pull GitLab users in to the Members tab. When available, Cortex will pull in the profile picture and email address for each user.

Scorecards and CQL

With the GitLab integration, you can create Scorecard rules and write CQL queries based on GitLab data.

Approvals required to merge

Total number of approval required to merge a merge request into a repository.

Defaults to 0 if no approvals are defined.

Definition: git.numOfRequiredApprovals()

Examples

For a security or development maturity Scorecard, you can write a rule to make sure at least one approval is required for a merge request:

git.numOfRequiredApprovals() >= 1

By having a rigorous PR process in place for a repo, you can make sure changes aren't made that create vulnerabilities. This kind of rule could also be used in a best practices or project standards Scorecard.

You can also use a similar expression in the Query Builder to find entities lacking approval:

git.numOfRequiredApprovals() < 1
Branches

List all live branches with some basic metadata:

  • Head

  • Is protected

  • Name

    Definition: git.branches(): List<GitBranch>

Example

For a development best practices Scorecard, you can make sure that branches associated with an entity match a standard naming convention:

git.branches().all((branch) => branch.name.matches("(main|master|feat-.*|bug-.*|task-.*)"))
Branch protection details

Find details for a specified branch or default branch if none is specified:

  • Branch name

  • Code owner reviews required

  • Disable overriding approvers per merge request (only supperted in GitLab Ultimate)

  • Merge requests author approval (only supperted in GitLab Ultimate)

  • Merge requests disable committers approval (only supperted in GitLab Ultimate)

  • Request approvals on push (only supperted in GitLab Ultimate)

  • Require password to approve (only supperted in GitLab Ultimate)

  • Reviews required

  • Selective code owner removals (only supperted in GitLab Ultimate)

    Definition: git.branchProtection(branchName: Text?): GitBranchProtection

Examples

For a security Scorecard, you can write a rule to make sure the default branch is protected:

git.branchProtection() != null

Or to make sure the main branch is protected:

git.branchProtection("main") != null

Because vulnerabilities in the default branch are critical, this rule should be in one of the first couple levels. A higher-level rule might make sure that branch protection checks are set:

git.branchProtection("main").requiredStatusChecks.length > 0

You can also use the Query Builder to find entities with unprotected default branches:

git.branchProtection() = null
Commits

Get the latest commits (to a maximum of 100) for a defined lookback period (defaulting to 7 days).

  • Date
  • Message
  • SHA
  • URL
  • Username

These results can be filtered based on branch name, using the default branch if no other branch is provided.

Definition: git.commits()

Example

You can use the git.commits() expression in a security Scorecard to make sure entities have fewer than three commits to a "security-fixes" branch in the last week:

git.commits(branch="security-fixes").length < 3

Entities passing this rule will include those that haven't needed three or more security fixes. This can indicate that there aren't vulnerabilities in a given entity's code, but could also suggest that fixes aren't being implemented.

Using this rule in conjunction with one focused on vulnerabilities could provide the extra context needed to gain a better understanding of what's happening.

Default branch

Default branch for the entity's repository or main when null.

Definition: git.defaultBranch()

Example

If default branches should always be named "main," you can write a rule in a best practices Scorecard to make sure entities are compliant:

git.defaultBranch().matches("main")
File contents

Load the contents of a file from the entity's associated repository.

The contents can be validated by using string comparison operations or parsed by the built-in jq function. The jq function will automatically coerce file contents of JSON or YAML formats.

Definition: git.fileContents(<filename: Text>)

Examples

For a Scorecard focused on development maturity, you could use the git.fileContents() rule to enforce that a CI pipeline exists, and that there is a testing step defined in the pipeline:

git.fileContents(“circleci/config.yml”).matches(“.*npm test.*”) - Enforce that a CI pipeline exists, and there is a testing step defined in the pipeline

A best practices Scorecard, meanwhile, could use this expression for a number of rules:

  • To make sure node engine version in specified in the package.json file:
    jq(git.fileContents("package.json"), ".engines.node") != null
  • To make sure TypeScript projects have a tsconfig.json file checked in:
    jq(git.fileContents("package.json"), ".devDependencies | with_entries(select(.key == \"typescript\")) | length") == 0 or git.fileExists("tsconfig.json")
  • To make sure projects using yarn do not allow NPM:
    jq(git.fileContents("package.json"), ".engines.yarn") == null or jq(git.fileContents("package.json"), ".engine.npm") = "please-use-yarn"
  • And to ensure the yarn version being used is not deprecated:
    jq(git.fileContents("package.json"), ".engines.yarn") == null or !(semver("1.2.0") ~= semverRange(jq(git.fileContents("package.json"), ".engines.yarn")))
File exists

Check if file exists from within the entity's associated repository.

Definition: git.fileExists(<filename: Text>)

Examples

For a development best practices Scorecard, this expression can be used for a rule that makes sure developers are checking in lockfiles to ensure repeatable builds:

git.fileExists(“package-lock.json”)

In the Query builder, you can use this expression with a wildcard to find entities with unit tests enabled:

git.fileExists(*Test.java”)

Or to find entities with an outdated Terraform version:

git.fileExists("terraform/versions.tf") and !git.fileContents("terraform/versions.tf").matchesIn("required_version =! \"[~>= ]{0,3}0\\.(12|13)")
Git vulnerabilities

Find all vulnerabilities within a repository.

Can filter by severity or scan type.

Definition: git.numOfVulnerabilities()

Examples

A security-focused Scorecard will likely include a rule making sure there are no Git vulnerabilities:

git.numOfVulnerabilities() == 0

You can use Scorecard levels to stratify vulnerabilities by risk. An initial level might make sure there are no critical vulnerabilities:

git.numOfVulnerabilities(severity=["CRITICAL"]) == 0

While a higher level might make sure there are no vulnerability warnings:

git.numOfVulnerabilities(severity=["WARNING"]) == 0

You can also use this expression in the Query builder to find critical vulnerabilities from different types of scans:

git.vulnerabilities(severity=["CRITICAL"], scan_types=["SAST"]) < 5
Has Cortex YAML (GitOps)

When enabling GitOps to manage entity descriptors, Cortex checks for a checked in file ./cortex.yaml at the root directory. This rule can help track migrations from UI editing to GitOps for entity descriptor management.

Definition: git.hasCortexYaml()

Example

If you're using a Scorecard to track a migration from Cortex UI to GitOps, you can use this rule to make sure entities are set up for GitOps management of entity descriptors:

git.hasCortexYaml() == true
Git repository set

Check if entity has a registered Git repository.

Definition: git (==/!=) null

Example

A Scorecard focused on best practices or standards will likely include a rule in its first level making sure a Git repository is set up:

git != null

If an entity is failing this rule, it can indicate broader issues with the integration or explain why an entity isn't functioning as expected.

Last commit details

Provides last commit details.

  • Date

  • Message

  • SHA

  • URL

  • Username

    Definition: git.lastCommit()

Examples

Depending on best practices at your organization, you may want to confirm the last commit for a given entity is no older than 3 days:

datetime(git.lastCommit().date).fromNow() > duration("P-3D")

Confirming whether a service was updated recently can help team members catch outdated code sooner. Plus, if there is a security issue, you can quickly determine which services have or have not been updated to patch the vulnerability.

For a best practices Scorecard, you can also use this expression to make sure the entity's last commit message follows conventional commit guidelines:

git.lastCommit().message.matches("^(feat|fix|docs|style|refactor|test|chore)(\\(.+\\))?:*")
Pipeline build success rate

Percentage of build pipelines that complete successfully.

This is calculated against builds on the default branch for commits in the last 30 days: # successful builds / (# successful + # failed).

Definition: git.percentBuildSuccess()

Example

This expression can be used in a development maturity Scorecard to write a rule making sure at least 95% of build runs are successful:

git.percentBuildSuccess() >= 0.95
Merge requests

List merge requests opened during a defined lookback period.

  • Approval date

  • Author

  • Date closed

  • Date opened

  • First review date

  • Last updated

  • Number of commits

  • Number of lines added

  • Number of lines deleted

  • Organization

  • Repository

  • Source

  • Status

  • URL

    Definition: git.pullRequests()

Example

You can use the git.pullRequests() query to find entities that have a small number of merge requests opened in the last two weeks:

git.pullRequests(lookback=duration("P14D")).length < 3

This can highlight entities that haven't been updated recently, which may be especially useful when entities have to be updated to address a vulnerability.

You can also use this expression to check that there are fewer than 500 lines added per merge request on average in the last 7 days:

git.pullRequests(lookback=duration("P7D")).filter((mr) => mr.numLinesAdded != null).map((mr) => mr.numLinesAdded).average() < 500

If an entity fails this rule, it can flag inefficiencies in the development process.

Recency of last commit

Calculates the duration of time between Scorecard evaluation and the date of the last commit from the entity's Git repository.

Definition: git.lastCommit().freshness

Example

One of the first rules you might write for a Scorecard focused on development maturity or security is one validating that the last commit was within the last month:

git.lastCommit().freshness < duration("P1M")

As counterintuitive as it may seem, services that are committed too infrequently are actually at more risk. People who are familiar with the service may leave a team, institutional knowledge accumulates, and from a technical standpoint, the service may be running outdated versions of your platform tooling.

Reviews

List reviews left during a defined lookback period.

  • Organization

  • Repository

  • Review date

  • Reviewer

    Definition: git.reviews()

Example

A development maturity Scorecard might use the git.reviews() expression to make sure that there is a rigorous review process in place before changes are implemented:

git.reviews(lookback=duration("P7D")).length > 25

This rule makes sure that there are more than 25 reviews left in the last week.

Search repository files

Find all instances of code search query from within a repository.

Can filter by path, file name (extension required in file name), or extension. Filters can use * for glob matching. Supplying a query is required.

Definition: git.codeSearch((query = <query: Text>) (, path = <path: Text>) (, fileName = <fileName: Text>) (, fileExtension = <fileExtension: Text>)): List<GitSearchResult>

Example

You can use the git.codeSearch() expression to query for entities that have certain components, like icons:

git.codeSearch(query = "icon", fileExtension = "css").length > 0
Top repository language

Find top used language for a repository, if available.

Definition: git.topLanguage()

Example

Let's say the primary language developers should be using is Kotlin. You can write a rule to make sure that the top language associated with entities is Kotlin:

git.topLanguage() == "kotlin"

You can also use this expression to query for entities that don't have Kotlin as the top language to identify those that need to be updated:

git.topLanguage() != "kotlin"

Dev homepage

The GitLab integration enables Cortex to pull information about merge requests into the Dev homepage. You can find your open merge requests under the My open PRs tab and any merge requests assigned to you for review under the Assigned reviews tab.

Merge requests from GitLab are refreshed every 2 minutes.

Eng Intelligence

The Eng Intelligence tool also uses merge request data from GitLab to generate metrics:

  • Average PR open to close time
  • Avg time to first review
  • Avg time to approval
  • Avg deploys/week
  • PRs opened
  • Weekly PRs merged
  • Avg PRs reviewed/week
  • Avg commits per PR

You can read more about how Eng Intelligence tracks metrics for teams and users in the Eng Intelligence walkthrough.

Enabling GitOps

In order to use GitOps with GitLab, a webhook must be created. Setup steps for webhooks can be found here.

Background sync

Cortex conducts a background sync of GitLab identities every day at 10 a.m. UTC. Merge requests are refreshed every 2 minutes.

Still need help?

The following are all the ways to get assistance from our customer engineering team. Please use the option that is best for your users:

  • Email: help@cortex.io, or open a support ticket in the in app Resource Center
  • Chat: Available in the Resource Center
  • Slack: Users with a connected Slack channel will have a workflow added to their account. From here, you can either @CortexTechnicalSupport or add a :ticket: reaction to a question in Slack, and the team will respond directly.

Don’t have a Slack channel? Talk with your customer success manager.