# GitHub

{% hint style="info" %}
Cortex connects to many third-party vendors whose system interfaces frequently change. As a result, integration behavior or configuration steps may shift without notice. If you encounter unexpected issues, check with your system administrator or refer to the vendor's documentation for the most current information. Additionally, integration sync times vary and are subject to scheduling overrides and timing variance.
{% endhint %}

## Why use the integration for GitHub

GitHub is a Git-based source code management platform that helps teams share code, track changes over time, and collaborate on projects across an organization.

Integrating GitHub with Cortex allows you to:

* Automatically discover GitHub repositories and track ownership of the entities they represent in Cortex
* Manage your Cortex workspace through a GitOps workflow, using GitHub as the source of truth for entity definitions
* View repository context directly on an entity's details page, including the associated repo, recent commits and releases in the event timeline, the most-used language, and top contributors with their contribution counts
  * In an entity's **Code & Security** section, surface vulnerabilities from [GitHub Advanced Security](https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security), including code scanning, Dependabot alerts, CodeQL, and secret scanning
* Track pull requests and work items from the [engineering homepage](#engineering-homepage) to keep delivery work visible alongside the rest of your catalog
* Use GitHub metrics in [Eng Intelligence](/improve/eng-intelligence.md) to understand service health, incident response patterns, and other key engineering signals
* Create [Scorecards](#scorecards-and-cql) that drive alignment and measure progress on initiatives involving your repositories

You can also optionally integrate GitHub Copilot with Cortex to:

* Track Copilot adoption and measure its impact on engineering productivity within Eng Intelligence

{% hint style="info" %}
**GitHub Copilot integration**

If you installed the GitHub app prior to October 14, 2025, you must accept new permissions in order to access Copilot metrics in Cortex.

In your email, locate the message with subject line "\[GitHub] Cortex App is requesting updated permissions" from `noreply@github.com` and click the link to review and accept the change. As a security best practice, always verify that the email was sent from a trusted domain. In GitHub, click **Accept new permissions**.

Alternately, you can remove your GitHub integration in Cortex and re-configure it. The GitHub app is preconfigured to include the permissions necessary for the Copilot integration.
{% endhint %}

## Configuring GitHub

### Prerequisites

If you connect Cortex via a [custom GitHub app](#custom-app), it must be configured with a [fine-grained personal access](https://docs.github.com/en/rest/authentication/permissions-required-for-fine-grained-personal-access-tokens) token containing the minimum permissions listed below. Note that the [Cortex GitHub app](#cortex-github-app) is preconfigured with these permissions.

#### Repository permissions

<table><thead><tr><th width="204.0703125">Permission</th><th width="181.1875">Requirement</th><th>Purpose in Cortex</th></tr></thead><tbody><tr><td><strong>Actions</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read workflow run information for Git-based CQL rules</li><li>Artifact information for actions</li></ul></td></tr><tr><td><strong>Administration</strong></td><td><code>Read &#x26; write</code></td><td>Create repositories</td></tr><tr><td><strong>Checks</strong></td><td><code>Read &#x26; write</code></td><td>Create and update check runs for linting and validation workflows, such as the <code>cortex.yaml</code> linter on pull requests</td></tr><tr><td><strong>Code scanning alerts</strong></td><td><code>Read-only</code></td><td>Get vulnerability information for Git-based CQL rules</td></tr><tr><td><strong>Commit statuses</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read commits for an entity's Git metadata</li><li>Read commits for Git-based CQL rules</li><li>Show pending status messages on the OpenAPI incompatibility check</li></ul></td></tr><tr><td><strong>Contents</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read <code>cortex.yaml</code>, <code>cortex-properties.yaml</code>, and package/OpenAPI files</li><li>Read Git rules</li><li>Create file contents</li></ul></td></tr><tr><td><strong>Custom properties</strong></td><td><code>Read &#x26; write</code></td><td>Used in <a href="/pages/E4BndAJAkJ3sjXz3SAer">Workflows</a></td></tr><tr><td><strong>Dependabot alerts</strong></td><td><code>Read-only</code></td><td>Read vulnerability information for Git CQL rules (only relevant if using Dependabot)</td></tr><tr><td><strong>Deployments</strong></td><td><code>Read &#x26; write</code></td><td>Used in <a href="/pages/E4BndAJAkJ3sjXz3SAer">Workflows</a></td></tr><tr><td><strong>Issues</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read associated issues with repositories for populating entity Git integration and for Git CQL rules</li><li>Create new issues based on <a href="/pages/tdFcgLBakpb4SUx5Lotc">Initiatives</a></li></ul></td></tr><tr><td><strong>Metadata</strong></td><td><code>Read-only</code></td><td>Read associated data with repositories for populating entity Git integration and for Git CQL rules</td></tr><tr><td><strong>Pull requests</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read pull request data for Git CQL rules and developer homepage "My PRs" tab</li><li>Comment if there are breaking OpenAPI changes on a PR</li></ul></td></tr><tr><td><strong>Secret scanning alerts</strong></td><td><code>Read-only</code></td><td>Read vulnerability information for secret scanning</td></tr><tr><td><strong>Secrets</strong></td><td><code>Read &#x26; write</code></td><td>Optionally write repo secrets after creating new repo</td></tr><tr><td><strong>Single file</strong></td><td><code>Read &#x26; write</code> (path to cortex.yaml)</td><td><ul><li>Read <code>cortex.yaml</code> files</li><li>Create <code>cortex.yaml</code> files</li></ul></td></tr><tr><td><strong>Workflows</strong></td><td><code>Read &#x26; write</code></td><td>Write in GitHub actions files</td></tr></tbody></table>

#### Organization-level permissions

<table><thead><tr><th width="215.28515625">Permission</th><th width="173.73828125">Requirement</th><th>Purpose in Cortex</th></tr></thead><tbody><tr><td><strong>Administration</strong></td><td><code>Read-only</code></td><td><ul><li>Create repositories</li><li>Pull in Copilot data for <a href="/pages/nZOyOBWYHpwwuH9q8HVF">Eng Intelligence</a></li></ul></td></tr><tr><td><strong>Members</strong></td><td><code>Read &#x26; write</code></td><td><ul><li>Read membership information for ownership and team composition</li><li>Write permission used in <a href="/pages/E4BndAJAkJ3sjXz3SAer">Workflows</a></li></ul></td></tr><tr><td><strong>GitHub copilot business</strong></td><td><code>Read-only</code></td><td>Read copilot-related metrics for AI Impact Dashboard</td></tr></tbody></table>

#### Enabling PR webhooks (optional but recommended)

Cortex currently ingests pull request (PR) data via the GitHub API. By subscribing to GitHub's PR webhooks, you provide real-time data that Cortex uses to cross-reference against existing data. This is the most efficient way to ensure every PR and event is captured without gaps.

**To enable PR webhooks**:

1. Open your custom GitHub App settings.
2. From the left menu, select **Permissions & events**.\
   \> **Tip**: If you don't see this tab, check that you have admin access to the GitHub App organization.
3. Scroll to the Subscribe to events section.
4. Locate and select the checkboxes for the following events:
   * Pull request
   * Pull request review
   * Pull request review comment
   * Pull request review thread
5. Click **Save**.

Cortex begins receiving PR webhook events immediately and automatically cross-references them against standard API ingestion to validate the data.

### Choosing a configuration option

There are multiple options for connecting Cortex to your GitHub instance:

* Through Cortex's official GitHub app
  * This option is supported for use with a single organization in GitHub.
* Through a custom GitHub app
  * By using Cortex's official GitHub app or a custom GitHub app, users can tag entities with Git details and enable GitOps-style configuration of data in Cortex.
* Using a personal access token
* Using Cortex Axon Relay, a relay broker that allows you to securely connect your on-premises GitHub data.

If your GitHub setup involves multiple organizations, you can add multiple GitHub apps, use a [personal access token](#configuration---personal-access-token) that has access to all orgs, or create multiple configurations with corresponding aliases.

See the tabs below for instructions on each of the GitHub integration options.

{% hint style="info" %}
If you're using a self-hosted instance of GitHub, you'll need to verify that your Cortex instance is able to reach the GitHub instance. Requests are routed through a static IP address.

Contact 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 GitHub instance.
{% endhint %}

{% tabs %}
{% tab title="Cortex GitHub app" %}
**Configure GitHub with the Cortex GitHub app**

[Cortex's official GitHub app](https://github.com/apps/cortex-app) is the easiest way to connect your GitHub instance. It is preconfigured with the [permissions](#prerequisites) needed to use this integration. Note that it is not available for Cortex Server.

To set up the app:

1. In Cortex, navigate to the [GitHub settings page](https://app.getcortexapp.com/admin/integrations/github):
   1. Click **Integrations** from the main nav. Search for and select **GitHub**.
2. On the GitHub settings page, next to `cortex`, click **Install**.\
   ![](/files/2YjpsIRrU7NaEMpCr9kT)
3. Follow the prompts, then click **Install & Authorize**.

Cortex's GitHub app is preconfigured with:

* Permissions for [catalogs](/ingesting-data-into-cortex/catalogs.md), [Scorecards](/standardize/scorecards.md), and the [Scaffolder](/streamline/workflows.md#scaffolder).
* Webhooks to enable [GitOps](/configure/gitops.md).
* Support for using [GitHub teams](https://docs.github.com/en/organizations/organizing-members-into-teams/about-teams) as an ownership provider.

The app comes with a built-in linter, which validates the format of a given `cortex.yaml` file and checks Cortex-specific items. **However, the linter DOES NOT validate data correctness.** For example, the linter will confirm that the format of a group block is correct, but will not check that the group exists.
{% endtab %}

{% tab title="Custom app" %}
**Configure GitHub with a custom app**

If you're using Cortex Server, or if you don't want to use the official Cortex app, you can connect a custom GitHub app.

Make sure you have configured the permissions listed above under [Prerequisites](#prerequisites).

**Step 1: Register the custom app in GitHub**

1. [Register the app](https://docs.github.com/en/apps/creating-github-apps/registering-a-github-app/registering-a-github-app). When you're creating the app, make sure to follow these steps:
   * **Disable** "Expire user authorization tokens." (Cortex does not support this OAuth workflow yet.)
   * **Select** "Request user authorization (OAuth) during installation."
   * **Callback URL:** `https://app.getcortexapp.com/github/redirect/{alias}`
     * Make sure to use the GitHub configuration alias and not the tenant name in the URL.
   * **Webhook URL:** `https://api.getcortexapp.com/api/internal/v1/github/webhook`
   * **Add** a webhook secret of your choosing that will be identical to the webhook secret token configured later in Cortex settings.
   * **Set** the repository and organization [permissions](#api-permissions) outlined in the configuration modal.
   * **Check** `Push` and `Check suite` under **Subscribe to events**.
2. After the app has been created, generate a client secret and private key.

**Step 2: Configure the custom app in Cortex**

1. In Cortex, navigate to the [GitHub settings page](https://app.getcortexapp.com/admin/integrations/github):
   * Click **Integrations** from the main nav. Search for and select **GitHub**.
2. Click **Add configuration**, then for the type, select **GitHub app**.
3. Fill in the form:
   * **Alias:** Enter the name Cortex will associate with a given configuration.
   * **Application ID:** Enter the ID for your custom GitHub ap.
   * **Client ID:** Enter the unique [client ID](https://docs.github.com/en/apps/oauth-apps/building-oauth-apps/authenticating-to-the-rest-api-with-an-oauth-app#registering-your-app) assigned to your app during registration.
   * **Client secret:** Enter the unique client secret assigned to your app during registration.
   * **Private key:** Enter the [private key](https://docs.github.com/en/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps#generating-private-keys) to authenticate with your GitHub app.
   * **Public link:** Enter the public URL of your GitHub app.
   * **API endpoint (for GitHub enterprise):** Enter the endpoint root URL for self-managed GitHub setups.
4. Click **Save**.
5. On the GitHub Settings page in Cortex, under **Webhook**, choose your new configuration alias and enter the same **Secret token** that was entered in GitHub during the app configuration.
6. On the GitHub Settings page in Cortex, next to your custom app configuration's name, click **Install**.
   {% endtab %}

{% tab title="Personal access token" %}
**Configure GitHub with a personal access token**

**Prerequisites**

Before getting started, make sure your [personal access token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens) has, at minimum, the `repo` and `read:org` permissions.

Note: Beyond the minimum permissions indicated above, many scenarios will require that the user who generated the personal access token have organization ownership permissions within GitHub.

**Configuration**

1. In Cortex, navigate to the [GitHub settings page](https://app.getcortexapp.com/admin/integrations/github):
   * Click **Integrations** from the main nav. Search for and select **GitHub**.
2. Click **Add configuration**.
3. In the upper right corner of the modal, click the dropdown and select **Personal access token**.

   <figure><img src="/files/ZmKO27g2EwJnihbtyTU4" alt=""><figcaption></figcaption></figure>
4. Fill in the form:
   * **Alias:** Enter a name that Cortex will associate with a given configuration.
   * **Token:** Enter the Personal access token generated in GitHub.
   * **API endpoint (for GitHub enterprise):** Enter the endpoint root URL for self-managed GitHub setups.
5. Click **Save**.
   {% endtab %}

{% tab title="Relay broker" %}
**Configure GitHub with Cortex Axon Relay**

See [Internally hosted integrations](/ingesting-data-into-cortex/integrations/axon-relay.md) for instructions. Make sure to follow the GitHub-specific instructions for the docker-compose.yml file.
{% endtab %}
{% endtabs %}

#### **Configuring the integration for multiple GitHub accounts**[**​**](https://docs.cortex.io/docs/reference/integrations/github#configure-the-integration-for-multiple-propsintegration-accounts)

The GitHub integration has multi-account support. You can add a configuration for each additional organization, instance, or account by repeating the process above.

Each configuration requires an alias, which Cortex uses to correlate the designated organization, instance, or account 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 GitHub page in your Cortex settings.

**To set the default configuration**:

1. From the main sidebar, select **Integrations**.
2. Locate GitHub, then click **Settings**.
3. Locate the configuration, then click the **pencil icon**.
4. From the **Category** drop-down menu, select a category. You must select at least one category before you can set the configuration as default.
5. Toggle on **Set as default**.\
   \> **Tip**: If you only have one configuration, it's automatically set as the default.

Cortex supports mapping multiple identities for a single user if you have multiple configurations of GitHub. See [Configuring identity mappings](/configure/settings/managing-users/identity-mapping.md) for more information.

{% hint style="info" %}
To write rules related to Dependabot alerts, you must verify the necessary permissions are set for repositories you'd like to see vulnerabilities reported on.

To verify, navigate to a GitHub repo and click **Settings > Code security and analysis**. Ensure you are a member of a team under **Access to alerts**.
{% endhint %}

## Registration

See the [Create services documentation](/ingesting-data-into-cortex/entities-overview/entities/adding-entities/add-services.md#creating-services) for instructions on importing entities.

### Entity descriptor

**Repository**

You can define a GitHub repository for a given entity by adding the `x-cortex-git` block to the entity's descriptor. When you define a repository, Cortex checks for Security Advisory vulnerabilities from the GraphQL API and Advanced Security vulnerabilities from the Rest API.

```yaml
x-cortex-git:
  github:
    repository: cortex/docs
    basepath: myService
    alias: myApp
```

<table><thead><tr><th width="137.26953125">Field</th><th width="504.16796875">Description</th><th align="center">Required</th></tr></thead><tbody><tr><td><code>repository</code></td><td>GitHub repository in the form <code>/</code></td><td align="center"><strong>✓</strong></td></tr><tr><td><code>basepath</code></td><td>Subdirectory for the entity if it is in a monorepo. Note that setting a <code>basepath</code> filters the vulnerabilities that appear in Cortex; Advanced Security vulnerabilities will not appear.</td><td align="center"></td></tr><tr><td><code>alias</code></td><td>Alias for the configuration in Cortex (only needed if you have opted into multi-account support)</td><td align="center"></td></tr></tbody></table>

Only one repository can be defined for in a given entity's YAML in the `x-cortex-git` block. Users looking to list additional repositories without the full functionality of GitOps can define the repos as custom data.

```yaml
x-cortex-custom-metadata:
  second-git-repo:
    - `/`
  third-git-repo:
    - `/`
```

**Ownership**

You can define the following block in your Cortex entity descriptor to add your GitHub teams. Be sure to include both your GitHub organization name and the team name in the `name` field.

```yaml
x-cortex-owners:
  - type: group
    name: cortex/engineering
    provider: GITHUB
    description: This is a description for this GitHub team that owns this entity.
```

| Field         | Description                                                                                                                                                                                                 | Required |
| ------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :------: |
| `type`        | Ownership type; must be defined as `group` for GitHub teams                                                                                                                                                 |   **✓**  |
| `name`        | GitHub team name in the form `/`Team names are generally converted to lowercase with `-` separators (`Team Name` would be `cortex/team-name`), but you can verify your exact name from the GitHub permalink |   **✓**  |
| `provider`    | Name of integration (in this case, `GITHUB`)                                                                                                                                                                |   **✓**  |
| `description` | Description for the GitHub team                                                                                                                                                                             |          |

{% hint style="warning" %}
Multiple GitHub organizations are not supported for ownership, and Cortex will use the default configuration when fetching teams.
{% endhint %}

### Identity mappings

Cortex maps users' email addresses to discovered GitHub accounts, so you never need to define email ownership in an entity descriptor. Users must be members of GitHub teams to be pulled in to Cortex.

You can confirm users' GitHub accounts are connected from [GitHub identity mappings in settings](https://app.getcortexapp.com/admin/settings/github-mappings).

## Using the GitHub integration

### View GitHub data on entity pages in Cortex

The GitHub integration will populate the **Repo** and **Language** detail blocks on an [entity's details page](/ingesting-data-into-cortex/entities-overview/entities/details.md). If a GitHub team has been [defined as the owner](#ownership) for an entity, it will also appear in the **Owners** block.

#### Code & security

Vulnerabilities appear in the **Vulnerabilities** block under **Code & security** on an entity page overview.

Click **Code & security** in an entity's sidebar to view the full list of vulnerabilities for an entity. Cortex checks for:

* Security Advisory vulnerabilities from the GraphQL API
* [GitHub Advanced Security](https://docs.github.com/en/get-started/learning-about-github/about-github-advanced-security) vulnerabilities
  * Cortex pulls data from code scanning, Dependabot alerts, CodeQL, and Secret scanning.
  * Dependency reviews are not supported.

GitHub Advanced Security vulnerabilities are not surfaced for monorepos.

{% hint style="success" %}
You can query for vulnerabilities with CQL and create Scorecard rules based on security metrics. See [Scorecards and CQL](#scorecards-and-cql) below.
{% endhint %}

#### **Events**

Recent commits appear at the top of an entity's overview page.

You can also click **Events** in the entity's sidebar to see all commits and releases associated with that entity. Each is hyperlinked to the commit or release page in GitHub and includes a timestamp.

#### **Repository**

You can access more detailed information pulled from GitHub in the **Repository** page in the sidebar. At the top of the 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.

#### **Issue tracking**

From the **Issue tracking** page in the entity's sidebar, you can find a list of open [GitHub issues](https://docs.github.com/en/issues). Each issue will show the number, title, assignees, and date created.

#### **Packages**

Packages are automatically scraped from your Git repos or they can be submitted via the [packages API](/api/readme/packages.md). The package file must be in the root of your repository — or, if you're using `basepath`, in the root of the subdirectory — to be scraped by Cortex. You can query an entity's packages in [CQL explorer](https://app.getcortexapp.com/admin/cql-explorer) using `packages()`.

To view packages, click **Packages** in the entity's sidebar.

The following package types are automatically scraped from repositories:

* JavaScript / Node.js: `package.json`, `package-lock.json`, `yarn.lock`, `pnpm-lock.yaml`
* Python: `requirements.txt`, `pipfile.lock`
* .NET (C#): `packages.lock.json`
* Java: `pom.xml`
* Go: `go.sum`

All other files of these types can be added via the [packages API](/api/readme/packages.md).

#### **CI/CD - GitHub workflows**

From the **CI/CD > GitHub workflows** page in the entity's sidebar, you can find a history of [GitHub workflow](https://docs.github.com/en/actions/using-workflows/about-workflows) runs for the past week. Each run is tagged with its status: `IN_PROGRESS`, `COMPLETED`, `SUCCESS`, `CANCELLED`, `FAILURE`, `PAUSED`.

The **GitHub workflows** page displays data about workflows in GitHub, **not** Workflows initiated via [Cortex's Workflows tool](/streamline/workflows.md).

### Team entity pages

When a [GitHub team is registered](#ownership) with a team entity, Cortex will pull GitHub users in to the **Members** tab. When available, Cortex will pull in the profile picture and email address for each user.

### Engineering homepage

The GitHub integration enables Cortex to pull information about pull requests and issues into the [homepage](/streamline/homepage.md). You can find your open pull requests, any pull requests assigned to you for review, and any issues assigned to you.

Pull requests and issues from GitHub are refreshed every 2 minutes.

### Eng Intelligence

The [Eng Intelligence tool](/improve/eng-intelligence.md) uses pull request data from GitHub to generate metrics:

* Average PR open to close time
* Avg time to first review
* Avg time to approval
* PRs opened
* Weekly PRs merged
* Avg PRs reviewed/week
* Avg commits per PR
* Ave lines of code changed per PR

Eng Intelligence also pulls in data from Copilot to show AI impact in the [Copilot Dashboard](/improve/eng-intelligence/dashboards/ai-impact.md).

You can read more about how Eng Intelligence tracks metrics for teams and users in the [Eng Intelligence documentation](/improve/eng-intelligence.md).

To add deployments for your Github related entity, you can send a deployment event to the [Cortex API.](/api/readme/deploys.md)

### Scorecards and CQL

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

See more examples in the [CQL Explorer](https://app.getcortexapp.com/admin/cql-explorer) in Cortex.

<details>

<summary>Approvals required to merge</summary>

Number of approvals required to merge a pull/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 to merge a pull/merge request:

```
git.numOfRequiredApprovals() > 0
```

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
```

</details>

<details>

<summary>Git repository set</summary>

Check if an entity has a registered Git repository.

**Definition:** `git (==/!=) null: Boolean`

**Example**

In a Scorecard, you can write a rule that detects whether an entity has a Git repository set:

```
git != null
```

</details>

<details>

<summary>Branches</summary>

List all live branches with some basic metadata.

* Head
* Is protected
* Name

**Definition**: `git.branches()`

**Example**

For a 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-.*)"))
```

</details>

<details>

<summary>Branch protection details</summary>

{% hint style="info" %}
`git.branchProtection()` now returns the **effective** branch protection for a branch by merging policies from both classic branch protection and GitHub rulesets into a unified view. This means it reflects what GitHub actually enforces, regardless of whether a repo uses classic rules, rulesets, or a combination of both.
{% endhint %}

Find details for specified branch, or default branch if none is specified.

* Branch name
* Code owner reviews required
* Dismiss stale reviews
* Required status checks
* Restrictions apply to admin
* Review required

**Definition:** `git.branchProtection()`

**Examples**

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

```
git.branchProtection() != null
```

Because vulnerabilities in the default branch are critical, this rule should be in one of the first couple levels.

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

```
git.branchProtection() = null
```

</details>

<details>

<summary>Branch rulesets</summary>

{% hint style="info" %}
Support for branch rulesets is in private beta. To request access, reach out to your account team.
{% endhint %}

GitHub [branch rulesets](https://docs.github.com/en/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets) are a newer, more flexible alternative to classic branch protection. Rulesets are layered (organization + repository), composed of typed rules, and can target multiple branches by pattern. Cortex exposes them in CQL through `git.branchRulesets(...)`.

`git.branchRulesets(branchName?)` returns the effective ruleset for a branch, i.e. the rules from every active ruleset that targets that branch, merged together. Pass a branch name to target a specific branch; omit it to use the repo's default branch. Returns `null` if no ruleset applies.

```
git.branchRulesets().rules.any((rule) =>
    rule.type == "pull_request" && rule.requiredApprovingReviewCount >= 2
)
```

```
// Require Copilot code review on push for the default branch
git.branchRulesets().rules.any((rule) =>
    rule.type == "copilot_code_review" && rule.reviewOnPush == true
)
```

```
// Forbid pushes that match a banned commit-message pattern
git.branchRulesets().rules.any((rule) =>
    rule.type == "commit_message_pattern" && rule.patternOperator == "regex"
)
```

`GitBranchRulesets` **fields**

<table><thead><tr><th width="159.0234375">Field</th><th width="230.125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>branchName</code></td><td><code>String</code></td><td>Branch the rules apply to.</td></tr><tr><td><code>rules</code></td><td><code>List&#x3C;GitBranchRule></code></td><td>All effective rules for the branch.</td></tr></tbody></table>

`GitBranchRule` **common fields**

Present on every rule regardless of `type` .

<table><thead><tr><th width="184.2734375">Field</th><th width="106.6484375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>type</code></td><td><code>String</code></td><td>Rule type. See sections below for the full list.</td></tr><tr><td><code>rulesetSourceType</code></td><td><code>String</code></td><td>Source level: <code>Repository</code>, <code>Organization</code>, or <code>Enterprise</code>.</td></tr><tr><td><code>rulesetSource</code></td><td><code>String</code></td><td>Owner (for org), repo full name (for repository), or enterprise slug.</td></tr><tr><td><code>rulesetId</code></td><td><code>Long</code></td><td>GitHub ID of the ruleset this rule came from.</td></tr></tbody></table>

All remaining fields below are nullable; only the fields associated with a rule's `type` are populated, and the rest are `null`.

Rule type: `pull_request`

| Field                            | Type                                   | Description                                                             |
| -------------------------------- | -------------------------------------- | ----------------------------------------------------------------------- |
| `requiredApprovingReviewCount`   | `Int?`                                 | Minimum approvals required.                                             |
| `dismissStaleReviewsOnPush`      | `Boolean?`                             | Dismiss prior approvals when new commits land.                          |
| `requireCodeOwnerReview`         | `Boolean?`                             | Require code-owner approval.                                            |
| `requireLastPushApproval`        | `Boolean?`                             | The most-recent push must be approved by someone other than the pusher. |
| `requiredReviewThreadResolution` | `Boolean?`                             | All review threads must be resolved before merging.                     |
| `allowedMergeMethods`            | `List<String>?`                        | One or several of `merge`, `squash`, `rebase`.                          |
| `requiredReviewers`              | `List<RequiredReviewerConfiguration>?` | (Beta) Reviewers required for changes matching specific file patterns.  |

Rule type: `required_status_checks`

<table><thead><tr><th width="256.515625">Field</th><th width="150.2890625">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>requiredStatusCheckContexts</code></td><td><code>List&#x3C;String>?</code></td><td>Required check names.</td></tr><tr><td><code>strictRequiredStatusChecksPolicy</code></td><td><code>Boolean?</code></td><td>Branch must be up-to-date before merging.</td></tr><tr><td><code>doNotEnforceOnCreate</code></td><td><code>Boolean?</code></td><td>Allow repos/branches to be created even if a check would prohibit it. (Also populated for <code>workflows</code>.)</td></tr></tbody></table>

Rule type: `required_deployments`

<table><thead><tr><th>Field</th><th width="159.62890625">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>requiredDeploymentEnvironments</code></td><td><code>List&#x3C;String>?</code></td><td>Required environment deployments.</td></tr></tbody></table>

Rule type: `update`

<table><thead><tr><th width="251.28515625">Field</th><th width="97.77734375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>updateAllowsFetchAndMerge</code></td><td><code>Boolean?</code></td><td>Branch can pull changes from its upstream repository.</td></tr></tbody></table>

Rule type: `merge_queue`

<table><thead><tr><th width="256.828125"></th><th width="99.140625"></th><th></th></tr></thead><tbody><tr><td><code>mergeQueueCheckResponseTimeoutMinutes</code></td><td><code>Int?</code></td><td>Max time a required check has to report a conclusion before being considered failed.</td></tr><tr><td><code>mergeQueueGroupingStrategy</code></td><td><code>String?</code></td><td><code>ALLGREEN</code> or <code>HEADGREEN</code>.</td></tr><tr><td><code>mergeQueueMaxEntriesToBuild</code></td><td><code>Int?</code></td><td>Maximum queued PRs being checked/built simultaneously.</td></tr><tr><td><code>mergeQueueMaxEntriesToMerge</code></td><td><code>Int?</code></td><td>Maximum PRs merged together in one group.</td></tr><tr><td><code>mergeQueueMergeMethod</code></td><td><code>String?</code></td><td><code>MERGE</code>, <code>SQUASH</code>, or <code>REBASE</code>. (Uppercase here; lowercase on <code>allowedMergeMethods</code>.)</td></tr><tr><td><code>mergeQueueMinEntriesToMerge</code></td><td><code>Int?</code></td><td>Minimum PRs in a merge group.</td></tr><tr><td><code>mergeQueueMinEntriesToMergeWaitMinutes</code></td><td><code>Int?</code></td><td>Minutes to wait before merging a smaller-than-minimum group.</td></tr></tbody></table>

**Pattern rule types**

Shared by `commit_message_pattern`, `commit_author_email_pattern`, `committer_email_pattern`, `branch_name_pattern`, `tag_name_pattern`. The same four fields are populated for any of these.

<table><thead><tr><th width="169.78515625">Field</th><th width="126.8984375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>patternName</code></td><td><code>String?</code></td><td>Display name for the pattern rule.</td></tr><tr><td><code>patternNegate</code></td><td><code>Boolean?</code></td><td>If <code>true</code>, the rule fails when the pattern matches.</td></tr><tr><td><code>patternOperator</code></td><td><code>String?</code></td><td><code>starts_with</code>, <code>ends_with</code>, <code>contains</code>, or <code>regex</code>.</td></tr><tr><td><code>pattern</code></td><td><code>String?</code></td><td>The pattern to match against.</td></tr></tbody></table>

Rule type: `workflows`

| Field                  | Type                           | Description                                       |
| ---------------------- | ------------------------------ | ------------------------------------------------- |
| `requiredWorkflows`    | `List<WorkflowFileReference>?` | Workflows that must pass for the rule to pass.    |
| `doNotEnforceOnCreate` | `Boolean?`                     | Shared with `required_status_checks` . See above. |

Rule type: `code_scanning`

| Field               | Type                      | Description                                    |
| ------------------- | ------------------------- | ---------------------------------------------- |
| `codeScanningTools` | `List<CodeScanningTool>?` | Tools that must provide code-scanning results. |

Rule type: `copilot_code_review`

<table><thead><tr><th>Field</th><th width="137.58203125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>reviewDraftPullRequests</code></td><td><code>Boolean?</code></td><td>Copilot reviews draft PRs before they're marked ready.</td></tr><tr><td><code>reviewOnPush</code></td><td><code>Boolean?</code></td><td>Copilot reviews every new push.</td></tr></tbody></table>

Rule type: `file_path_restriction`

<table><thead><tr><th width="215.7109375">Field</th><th width="171.08203125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>restrictedFilePaths</code></td><td><code>List&#x3C;String>?</code></td><td>File paths restricted from being pushed.</td></tr></tbody></table>

Rule type: `max_file_path_length`

<table><thead><tr><th width="202.15625">Field</th><th width="108.203125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>maxFilePathLength</code></td><td><code>Int?</code></td><td>Maximum number of characters allowed in file paths.</td></tr></tbody></table>

Rule type: `file_extension_restriction`

<table><thead><tr><th width="239.515625">Field</th><th width="142.22265625">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>restrictedFileExtensions</code></td><td><code>List&#x3C;String>?</code></td><td>File extensions restricted from being pushed.</td></tr></tbody></table>

Rule type: `max_file_size`

<table><thead><tr><th width="142.94140625">Field</th><th width="122.71484375">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>maxFileSize</code></td><td><code>Int?</code></td><td>Maximum file size in megabytes (excluding Git LFS).</td></tr></tbody></table>

**Rule types without parameters**

`creation`, `deletion`, `required_linear_history`, `non_fast_forward`, and `required_signatures` present in the rules list with only the common fields populated.

**Nested types**

`RequiredReviewerConfiguration` - each element of `pull_request.requiredReviewers`:

<table><thead><tr><th width="171.296875">Field</th><th width="165.046875">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>filePatterns</code></td><td><code>List&#x3C;String></code></td><td>fnmatch patterns — PRs that change matching files require this reviewer.</td></tr><tr><td><code>minimumApprovals</code></td><td><code>Int</code></td><td>Required approvals from this reviewer. Zero makes approval optional but still adds the reviewer.</td></tr><tr><td><code>reviewer</code></td><td><code>RulesetReviewer</code></td><td>The reviewing team.</td></tr></tbody></table>

`RulesetReviewer` - nested in `RequiredReviewerConfiguration.reviewer`:

<table><thead><tr><th width="175.43359375">Field</th><th width="168.36328125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>id</code></td><td><code>Long</code></td><td>Reviewer ID.</td></tr><tr><td><code>type</code></td><td><code>String</code></td><td>Reviewer kind. Currently always <code>Team</code>.</td></tr></tbody></table>

`WorkflowFileReference` - each element of `workflows.requiredWorkflows`:

<table><thead><tr><th width="154.12109375">Field</th><th width="124.828125">Type</th><th>Description</th></tr></thead><tbody><tr><td><code>path</code></td><td><code>String</code></td><td>Path to the workflow file in the repository.</td></tr><tr><td><code>ref</code></td><td><code>String?</code></td><td>Branch or tag ref of the workflow file to use.</td></tr><tr><td><code>repositoryId</code></td><td><code>Long</code></td><td>ID of the repository where the workflow is defined.</td></tr><tr><td><code>sha</code></td><td><code>String?</code></td><td>Commit SHA of the workflow file to use.</td></tr></tbody></table>

`CodeScanningTool` - each element of `code_scanning.codeScanningTools`:

<table><thead><tr><th width="240.10546875"></th><th width="127.66015625"></th><th></th></tr></thead><tbody><tr><td><code>alertsThreshold</code></td><td><code>String</code></td><td>Severity at which alerts block a push: <code>none</code>, <code>errors</code>, <code>errors_and_warnings</code>, <code>all</code>.</td></tr><tr><td><code>securityAlertsThreshold</code></td><td><code>String</code></td><td>Severity at which security alerts block: <code>none</code>, <code>critical</code>, <code>high_or_higher</code>, <code>medium_or_higher</code>, <code>all</code>.</td></tr><tr><td><code>tool</code></td><td><code>String</code></td><td>Name of the code-scanning tool.</td></tr></tbody></table>

**Relationship with** `git.branchProtection()`

`git.branchProtection()` returns the **effective** branch protection for a branch, merging policies from both classic branch protection and GitHub rulesets into a unified result. `git.branchRulesets()` remains available if you need granular access to individual ruleset rules (e.g. filtering by type, source, or ruleset ID).

</details>

<details>

<summary>Commits</summary>

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(branchName="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.

</details>

<details>

<summary>Default branch</summary>

Default branch for the repository, or `main` when null.

**Definition:** `git.defaultBranch()`

**Example**

If default branches should always be named "main," you can write a rule to make sure entities follow this practice:

```
git.defaultBranch().matches("main")
```

</details>

<details>

<summary>File contents</summary>

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()`

**Example**

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.*")
```

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")))
  ```

</details>

<details>

<summary>File exists</summary>

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

**Definition:** `git.fileExists()`

**Examples**

For a Scorecard focused on best practices, you can make sure that repositories contain a README.md file:

```
git.fileExists("README.md")
```

This rule would make sense in the first level because it's so essential.

A higher-level rule in a best practices Scorecard might confirm that developers are checking in lockfiles to ensure consistency in package installs:

```
git.fileExists("yarn.lock") OR git.fileExists("package-lock.json")
```

And/or a rule that makes sure there are unit tests enabled:

```
git.fileExists("*Test.java")
```

Finally, you could write a rule to make sure projects have a standard linter:

```
git.fileExists(".prettierrc.json") OR git.fileExists(".eslintrc.js")
```

</details>

<details>

<summary>Number of Git vulnerabilities</summary>

Check the number of vulnerabilities for an entity's associated repository.

You can filter by severity (by default searches by all severities) or source (by default only searches GitHub security advisories).

**When using the GitHub Advanced Security source, severities displayed in the UI may not match severities returned by the API.**

**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
```

</details>

<details>

<summary>List of Git vulnerabilities</summary>

Lists the vulnerabilities for an entity's associated repository. You can filter by severity (by default searches by all severities) or source (by default only searches GitHub security advisories). Note when using the GitHub Advanced Security source, severities displayed in the UI may not match severities returned by the API.

**Definition**: `git.vulnerabilities()`

**Examples**

You could write a Scorecard rule that verifies an entity has fewer than 5 Git vulnerabilities:

```
git.vulnerabilities().length < 5
```

You could write a rule that verifies the entity has no vulnerabilities with "High" or "Critical" severity sourced from GitHub Advanced Security:

```
git.vulnerabilities(severity=["CRITICAL", "HIGH"], source=["GITHUB_ADVANCED_SECURITY"]).length < 1
```

</details>

<details>

<summary>Has Cortex YAML</summary>

Check if a repository has a valid `cortex.yaml` file checked in at the root directory (when GitOps is enabled).

**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
```

</details>

<details>

<summary>Last commit details</summary>

Provides last commit details.

* Date
* Message
* SHA
* URL
* Username

**Definition:** `git.lastCommit()`

**Examples**

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.

Depending on best practices at your organization, you may want to confirm entities are updated within a week:

```
git.lastCommit().freshness < duration("P7D")
```

Confirming whether a service was updated within the last week 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.

</details>

<details>

<summary>Pull requests</summary>

Lists pull 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 pull 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.

</details>

<details>

<summary>Reviews</summary>

List reviews left during a defined lookback period.

* Organization
* Repository
* Review date
* Reviewer

**Definition:** `git.reviews()`

**Examples**

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.

</details>

<details>

<summary>Workflow runs</summary>

Get workflow runs meeting given filter criteria, including conclusions, statuses, and a lookback period.

* Conclusion
* Name
* Run started at
* Run time
* Run updated at
* Status

Conclusions: `FAILURE`, `SUCCESS`, `TIMED_OUT`

Statuses: `QUEUED`, `IN_PROGRESS`, `COMPLETED`

The lookback period specifies a duration for which returned runs should be created within, defaulting to a period of 3 days.

* The `runTime` of the `WorkflowRun` object represents the difference between `runStartedAt` and `runUpdatedAt` times in seconds.

**Definition:** `git.workflowRuns()`

**Example**

To make sure an entity has had a successful workflow run within the last two weeks, you can write a rule like:

```
git.workflowRuns(conclusions=["SUCCESS"], statuses=["COMPLETED"], lookback=duration("P14D")).length > 0
```

This rule is checking for GitHub workflow runs with a `SUCCESS` conclusion and `COMPLETED` status during a 14-day lookback window.\\

To find the percentage of successes in workflow runs, you could write a query similar to:

```
(git.workflowRuns(conclusions=["SUCCESS"], lookback=duration("P1D")).length) / (git.workflowRuns(lookback=duration("P1D")).length) * 100
```

</details>

**Ownership CQL**

<details>

<summary>All ownership details</summary>

A special built-in type that supports a null check or a count check, used to enforce ownership of entities.

**Definition:** `ownership: Ownership | Null`

**Example**

An initial level in a security Scorecard might include a rule to ensure an entity has at least one team as an owner:

```
ownership.teams().length > 0
```

</details>

<details>

<summary>All owner details</summary>

List of owners, including team members and individual users, for each entity

**Definition:** `ownership.allOwners()`

**Example**

The Scorecard might include a rule to ensure that entity owners all have an email set:

```
ownership.allOwners().all((member) => member.email != null)
```

</details>

<details>

<summary>Team details</summary>

List of teams for each entity

**Definition:** `ownership.teams(): List<Team>`

**Example**

The Scorecard might include a rule to ensure that an entity owners all have a description and are not archived:

```
ownership.teams().all(team => team.description != null and team.isArchived == false)
```

</details>

**Copilot CQL**

<details>

<summary>AI adoption</summary>

The ratio of licensed seats that were active users of AI coding tools in a given time period. Returns a value between 0 and 1, where 1 represents 100% adoption. Note: This metric is only available for Team entities.

**Definition**: `aiTools.analysis(lookback: Duration).aiAdoptionRate`

**Example**

You could create a Scorecard rule to make sure AI adoption rate is at least 50% over the previous 30 days:

```
aiTools.analysis(lookback = duration("P30D")).aiAdoptionRate >= 0.5
```

</details>

<details>

<summary>Active AI users</summary>

The number of users who used AI coding tools in a given time period. Note: This metric is only available for Team entities.

**Definition**: `aiTools.analysis(lookback: Duration).activeAiUsers`

**Example**

You could create a Scorecard rule to verify you had at least 5 active AI users in the last 7 days:

```
aiTools.analysis(lookback = duration("P7D")).activeAiUsers >= 5
```

</details>

**External repositories**

By default, each GitHub rule is evaluated on the repository defined in a given entity descriptor. If the base path parameter has been set, CQL rules will automatically scope to the base path subdirectory.

To evaluate the rule for a service for an external repository, pass the repo identifier in the `git(repoIdentifier: Text)` command (e.g. `git("github:org/repositoryName")`).

This can be combined with other CQL rules. For example, a rule based on a dynamic external repository with custom data would be `git("github:" + custom("my-custom-repo")).fileExists("README.md")`.

### View integration logs <a href="#still-need-help" id="still-need-help"></a>

{% hint style="info" %}
This feature is available in Cortex cloud.
{% endhint %}

While viewing an integration's settings page, select the **Logs** tab to view error logs from the last 7 days. You can filter the logs list by configuration and by operation (for example, you could filter to view errors surfaced only via Scorecards).

<div align="left" data-with-frame="true"><figure><img src="/files/x8JmoPqXZTJ7YHeFJpOA" alt="The &#x27;Logs&#x27; tab on an integration&#x27;s settings page shows error information over the past 7 days."><figcaption></figcaption></figure></div>

Click into a row to get more information, including time stamp, status code, full error, and request path.

## Background sync

Cortex conducts a background sync of GitHub identities every day at 10 a.m. UTC. Pull requests and issues are refreshed about every 10 minutes.

## FAQs and troubleshooting

**I'm getting this error: `"{"message":"Not Found", "documentation_url":"https://docs.github.com/rest/repos#get-a-repository"}"`.**

If you've set up multiple GitHub accounts/organizations, Cortex will not be able to identify the correct one unless the `alias` variable is defined.

**What if I have multiple email addresses set in my GitHub account?**

Cortex will only detect the primary email address associated with your GitHub account **if it is public**.

If Cortex is not correctly pulling in user emails, ensure the given user(s) have allowed their email address to be public. Make sure the **"Keep my email address private"** setting is **unchecked** in the user's personal GitHub settings.

**My ownership isn't being automatically mapped through GitHub.**

If the email address associated with your Cortex account is not the same as your GitHub email address, you need to add your Cortex email address to the **Public email** dropdown in GitHub settings.

Github OAuth, which you can configure in Cortex user settings, allows you to link your GitHub username with your Cortex account, even if you don't have a public email set up on GitHub.

## Still need help?[​](https://docs.cortex.io/docs/reference/integrations/aws#still-need-help) <a href="#still-need-help" id="still-need-help"></a>

The following options are available to get assistance from the Cortex Customer Engineering team:

* **Email**: <help@cortex.io>, or open a support ticket in the in app 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.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.cortex.io/ingesting-data-into-cortex/integrations/github.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
