> For the complete documentation index, see [llms.txt](https://developer.harness.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://developer.harness.io/ai-sre/ai-sre-for-administrators/set-up-alert-management/webhooks/integration-guides/cicd/github.md).

# GitHub Integration Guide

Configure GitHub repository webhooks to send event notifications to Harness AI SRE for deployments, releases, and security alerts.

### Before you begin <a href="#before-you-begin" id="before-you-begin"></a>

* **Harness webhook endpoint**: Create a GitHub webhook in Harness AI SRE using the [GitHub webhook template](/ai-sre/ai-sre-for-administrators/set-up-alert-management/webhooks/templates/cicd/github.md).
* **GitHub permissions**: Admin access to the repository or organization.
* **Webhook URL**: Copy the webhook URL from your Harness webhook configuration.
* **GitHub webhooks documentation**: Go to [Webhooks Documentation](https://docs.github.com/webhooks) to understand webhook configuration and event types.
* **Event payloads reference**: Go to [Webhook Events and Payloads](https://docs.github.com/webhooks/webhook-events-and-payloads) for event-specific payload structures.

***

### Create repository webhook <a href="#create-repository-webhook" id="create-repository-webhook"></a>

#### Navigate to webhook settings <a href="#navigate-to-webhook-settings" id="navigate-to-webhook-settings"></a>

{% tabs %}
{% tab title="Repository webhook" %}

1. Go to your GitHub repository
2. Click **Settings**, then click **Webhooks**
3. Click **Add webhook**
   {% endtab %}

{% tab title="Organization webhook" %}

1. Go to your GitHub organization
2. Click **Settings**, then click **Webhooks**
3. Click **Add webhook**

Organization webhooks receive events from all repositories in the organization.
{% endtab %}
{% endtabs %}

#### Configure webhook <a href="#configure-webhook" id="configure-webhook"></a>

{% tabs %}
{% tab title="Basic configuration" %}

* **Payload URL**: Your Harness webhook URL

  ```
  https://<your-harness-instance>/gateway/ai-sre/api/webhooks/<webhook-id>
  ```
* **Content type**: `application/json`
* **Secret**: (Optional) Webhook secret for signature verification
* **SSL verification**: Enable SSL verification
* **Which events**: Select events to trigger webhook
  {% endtab %}

{% tab title="With secret validation" %}

* **Payload URL**: Your Harness webhook URL
* **Content type**: `application/json`
* **Secret**: Enter a secure secret
  * GitHub signs payloads with HMAC-SHA256
  * Harness can verify the `X-Hub-Signature-256` header
* **SSL verification**: Enable SSL verification
* **Which events**: Select events

**Note**: Store the secret securely and configure it in your Harness webhook validation settings.
{% endtab %}

{% tab title="Custom event selection" %}

* **Payload URL**: Your Harness webhook URL
* **Content type**: `application/json`
* **Which events**: Select **Let me select individual events**

Common events for monitoring:

* ☑ Deployments
* ☑ Deployment statuses
* ☑ Releases
* ☑ Pull requests
* ☑ Pull request reviews
* ☑ Issues
* ☑ Issue comments
* ☑ Security and analysis (code scanning alerts, secret scanning alerts)
* ☑ Workflow runs
  {% endtab %}
  {% endtabs %}

#### Activate webhook <a href="#activate-webhook" id="activate-webhook"></a>

Enable the webhook so GitHub begins sending events:

* Check **Active** to enable the webhook
* Click **Add webhook**

***

### Select events to monitor <a href="#select-events-to-monitor" id="select-events-to-monitor"></a>

#### Deployment events <a href="#deployment-events" id="deployment-events"></a>

Monitor deployment activities:

**Events**:

* **Deployments**: Deployment created
* **Deployment statuses**: Deployment status changed (pending, success, failure, error)

**Use cases**:

* Track deployment failures
* Alert on production deployments
* Monitor deployment rollbacks

#### Release events <a href="#release-events" id="release-events"></a>

Monitor software releases:

**Events**:

* **Releases**: Release published, created, edited, deleted

**Use cases**:

* Notify on new releases
* Track release cadence
* Monitor hotfix releases

#### Pull request events <a href="#pull-request-events" id="pull-request-events"></a>

Monitor code changes:

**Events**:

* **Pull requests**: Opened, closed, merged, reopened
* **Pull request reviews**: Submitted, edited, dismissed
* **Pull request review comments**: Created, edited, deleted

**Use cases**:

* Track deployment-related PRs
* Monitor high-impact changes
* Alert on emergency merges

#### Security events <a href="#security-events" id="security-events"></a>

Monitor security findings:

**Events**:

* **Code scanning alerts**: Created, fixed, dismissed, reopened
* **Secret scanning alerts**: Created, resolved, reopened
* **Dependabot alerts**: Created, dismissed, fixed, reintroduced

**Use cases**:

* Alert on critical security vulnerabilities
* Track secret leaks
* Monitor dependency vulnerabilities

***

### Configure field mapping in Harness <a href="#configure-field-mapping-in-harness" id="configure-field-mapping-in-harness"></a>

In your Harness webhook configuration, map GitHub payload fields to alert properties.

#### GitHub webhook payload structure <a href="#github-webhook-payload-structure" id="github-webhook-payload-structure"></a>

Payload varies by event type. Common structure:

{% tabs %}
{% tab title="Deployment status" %}

```json
{
  "action": "created",
  "deployment_status": {
    "id": 123,
    "state": "failure",
    "description": "Deployment failed",
    "environment": "production",
    "target_url": "https://example.com/deployment/123",
    "created_at": "2025-07-01T10:30:00Z",
    "updated_at": "2025-07-01T10:35:00Z"
  },
  "deployment": {
    "id": 456,
    "sha": "abc123def456",
    "ref": "main",
    "task": "deploy",
    "payload": {},
    "environment": "production",
    "description": "Deploy to production",
    "creator": {
      "login": "deployer"
    }
  },
  "repository": {
    "name": "my-app",
    "full_name": "myorg/my-app",
    "html_url": "https://github.com/myorg/my-app"
  },
  "sender": {
    "login": "github-actions[bot]"
  }
}
```

{% endtab %}

{% tab title="Release" %}

```json
{
  "action": "published",
  "release": {
    "id": 789,
    "tag_name": "v1.2.3",
    "name": "Release v1.2.3",
    "body": "Release notes here",
    "draft": false,
    "prerelease": false,
    "created_at": "2025-07-01T10:00:00Z",
    "published_at": "2025-07-01T10:30:00Z",
    "html_url": "https://github.com/myorg/my-app/releases/tag/v1.2.3"
  },
  "repository": {
    "name": "my-app",
    "full_name": "myorg/my-app",
    "html_url": "https://github.com/myorg/my-app"
  },
  "sender": {
    "login": "release-bot"
  }
}
```

{% endtab %}

{% tab title="Code scanning alert" %}

```json
{
  "action": "created",
  "alert": {
    "number": 42,
    "created_at": "2025-07-01T10:30:00Z",
    "url": "https://api.github.com/repos/myorg/my-app/code-scanning/alerts/42",
    "html_url": "https://github.com/myorg/my-app/security/code-scanning/42",
    "state": "open",
    "dismissed_by": null,
    "dismissed_at": null,
    "dismissed_reason": null,
    "rule": {
      "id": "sql-injection",
      "severity": "error",
      "description": "SQL injection vulnerability",
      "name": "SQL injection"
    },
    "tool": {
      "name": "CodeQL",
      "version": "2.7.6"
    },
    "most_recent_instance": {
      "ref": "refs/heads/main",
      "analysis_key": ".github/workflows/codeql.yml:analyze",
      "category": ".github/workflows/codeql.yml:analyze/language:javascript",
      "environment": "",
      "state": "open",
      "location": {
        "path": "src/database.js",
        "start_line": 42,
        "end_line": 42
      }
    }
  },
  "repository": {
    "name": "my-app",
    "full_name": "myorg/my-app",
    "html_url": "https://github.com/myorg/my-app"
  },
  "sender": {
    "login": "security-bot"
  }
}
```

{% endtab %}
{% endtabs %}

#### Field mapping by event type <a href="#field-mapping-by-event-type" id="field-mapping-by-event-type"></a>

{% tabs %}
{% tab title="Deployment status" %}
**Basic mapping**:

```yaml
title: "Deployment {{webhook.deployment_status.state}}: {{webhook.repository.full_name}}"
message: |
  Deployment to {{webhook.deployment_status.environment}} {{webhook.deployment_status.state}}
  
  Description: {{webhook.deployment_status.description}}
  SHA: {{webhook.deployment.sha}}
  Ref: {{webhook.deployment.ref}}
  
  View: {{webhook.deployment_status.target_url}}
severity: "{{webhook.deployment_status.state}}"
source: "github"
link: "{{webhook.deployment_status.target_url}}"
tags:
  - "repository:{{webhook.repository.full_name}}"
  - "environment:{{webhook.deployment_status.environment}}"
  - "state:{{webhook.deployment_status.state}}"
  - "ref:{{webhook.deployment.ref}}"
```

**CEL mapping**:

```cel
title: "Deployment " + webhook.deployment_status.state + ": " + webhook.repository.full_name
message: "Deployment to " + webhook.deployment_status.environment + " " + 
         webhook.deployment_status.state + "\n\n" +
         webhook.deployment_status.description

// Map deployment state to severity
severity: webhook.deployment_status.state == "failure" ? "critical" :
          webhook.deployment_status.state == "error" ? "high" :
          webhook.deployment_status.state == "pending" ? "info" : "info"

source: "github"
link: webhook.deployment_status.target_url

// Filter: only failures and errors
filter: webhook.deployment_status.state in ["failure", "error"]
```

{% endtab %}

{% tab title="Release" %}
**Basic mapping**:

```yaml
title: "Release {{webhook.release.tag_name}}: {{webhook.repository.full_name}}"
message: |
  New release published: {{webhook.release.name}}
  
  {{webhook.release.body}}
  
  View: {{webhook.release.html_url}}
severity: "info"
source: "github"
link: "{{webhook.release.html_url}}"
tags:
  - "repository:{{webhook.repository.full_name}}"
  - "tag:{{webhook.release.tag_name}}"
  - "prerelease:{{webhook.release.prerelease}}"
```

**CEL mapping**:

```cel
title: "Release " + webhook.release.tag_name + ": " + webhook.repository.full_name
message: "New release published: " + webhook.release.name + "\n\n" + webhook.release.body
severity: webhook.release.prerelease ? "medium" : "info"
source: "github"
link: webhook.release.html_url

// Filter: only production releases (not prereleases or drafts)
filter: !webhook.release.prerelease && !webhook.release.draft
```

{% endtab %}

{% tab title="Code scanning alert" %}
**Basic mapping**:

```yaml
title: "Security Alert: {{webhook.alert.rule.name}} in {{webhook.repository.full_name}}"
message: |
  Code scanning alert: {{webhook.alert.rule.description}}
  
  Severity: {{webhook.alert.rule.severity}}
  Tool: {{webhook.alert.tool.name}}
  File: {{webhook.alert.most_recent_instance.location.path}}:{{webhook.alert.most_recent_instance.location.start_line}}
  
  View: {{webhook.alert.html_url}}
severity: "{{webhook.alert.rule.severity}}"
source: "github"
link: "{{webhook.alert.html_url}}"
tags:
  - "repository:{{webhook.repository.full_name}}"
  - "rule:{{webhook.alert.rule.id}}"
  - "tool:{{webhook.alert.tool.name}}"
  - "file:{{webhook.alert.most_recent_instance.location.path}}"
```

**CEL mapping**:

```cel
title: "Security: " + webhook.alert.rule.name + " in " + webhook.repository.full_name
message: webhook.alert.rule.description + "\n\n" +
         "File: " + webhook.alert.most_recent_instance.location.path + ":" + 
         string(webhook.alert.most_recent_instance.location.start_line) + "\n" +
         "Tool: " + webhook.alert.tool.name + " " + webhook.alert.tool.version

// Map GitHub severity to Harness severity
severity: webhook.alert.rule.severity == "error" ? "critical" :
          webhook.alert.rule.severity == "warning" ? "high" :
          webhook.alert.rule.severity == "note" ? "medium" : "low"

source: "github"
link: webhook.alert.html_url

// Filter: only critical and high severity
filter: webhook.alert.rule.severity in ["error", "warning"] && 
        webhook.alert.state == "open"
```

{% endtab %}
{% endtabs %}

***

### Test the integration <a href="#test-the-integration" id="test-the-integration"></a>

#### Test with webhook delivery <a href="#test-with-webhook-delivery" id="test-with-webhook-delivery"></a>

Redeliver a past webhook payload to test the integration:

1. Go to **Settings**, then click **Webhooks** in your repository
2. Click your webhook
3. Select the **Recent Deliveries** tab
4. Click **Redeliver** on any past delivery to test

#### Trigger real events <a href="#trigger-real-events" id="trigger-real-events"></a>

{% tabs %}
{% tab title="Test deployment" %}
Create a test deployment using GitHub API:

```bash
curl -X POST \
  -H "Authorization: token YOUR_GITHUB_TOKEN" \
  -H "Accept: application/vnd.github.v3+json" \
  https://api.github.com/repos/OWNER/REPO/deployments \
  -d '{
    "ref": "main",
    "environment": "staging",
    "description": "Test deployment for Harness integration"
  }'
```

{% endtab %}

{% tab title="Test release" %}
Create a test release:

1. Go to **Releases** in your repository
2. Click **Draft a new release**
3. Enter tag version (e.g., `v0.0.1-test`)
4. Enter release title and notes
5. Check **This is a pre-release**
6. Click **Publish release**
   {% endtab %}
   {% endtabs %}

#### Verify in Harness <a href="#verify-in-harness" id="verify-in-harness"></a>

Confirm the event arrived and mapped correctly:

1. Navigate to **Alerts** in Harness AI SRE
2. Check that the event appears
3. Verify field mapping is correct

***

### Available GitHub webhook headers <a href="#available-github-webhook-headers" id="available-github-webhook-headers"></a>

GitHub sends these headers with all webhooks:

| Header                                   | Description              | Example                                               |
| ---------------------------------------- | ------------------------ | ----------------------------------------------------- |
| `X-GitHub-Event`                         | Event type               | `deployment_status`, `release`, `code_scanning_alert` |
| `X-GitHub-Delivery`                      | Unique delivery ID       | `12345678-1234-1234-1234-123456789012`                |
| `X-Hub-Signature-256`                    | HMAC-SHA256 signature    | `sha256=...` (if secret configured)                   |
| `X-GitHub-Hook-ID`                       | Webhook configuration ID | `123456`                                              |
| `X-GitHub-Hook-Installation-Target-ID`   | Installation/org ID      | `456789`                                              |
| `X-GitHub-Hook-Installation-Target-Type` | Target type              | `repository`, `organization`                          |

***

### Advanced configuration <a href="#advanced-configuration" id="advanced-configuration"></a>

#### Filter by environment <a href="#filter-by-environment" id="filter-by-environment"></a>

Only process production deployments:

```cel
filter: has(webhook.deployment_status) && 
        webhook.deployment_status.environment == "production" &&
        webhook.deployment_status.state in ["failure", "error"]
```

#### Filter by branch <a href="#filter-by-branch" id="filter-by-branch"></a>

Only process events from main branch:

```cel
filter: (has(webhook.deployment) && webhook.deployment.ref == "refs/heads/main") ||
        (has(webhook.release) && webhook.release.target_commitish == "main")
```

#### Route by repository <a href="#route-by-repository" id="route-by-repository"></a>

Create separate webhooks for different repositories or use routing:

```cel
// Tag by repository for routing
tags: [
  "repository:" + webhook.repository.full_name,
  "repo_name:" + webhook.repository.name,
  "event:" + // Extract from X-GitHub-Event header if available
]
```

#### Security alert prioritization <a href="#security-alert-prioritization" id="security-alert-prioritization"></a>

Prioritize critical security alerts:

```cel
severity: has(webhook.alert) && webhook.alert.rule.severity == "error" 
  ? "critical" 
  : "high"

// Filter: only security errors
filter: has(webhook.alert) && 
        webhook.alert.rule.severity == "error" && 
        webhook.alert.state == "open"
```

***

### Troubleshooting <a href="#troubleshooting" id="troubleshooting"></a>

<details>

<summary>GitHub webhook is not sending events to Harness AI SRE</summary>

Check the webhook Recent Deliveries for errors, verify the webhook URL is publicly accessible, ensure the SSL certificate is valid, and review response codes (200 is success, 4xx/5xx is an error).

</details>

<details>

<summary>GitHub events are not triggering the webhook in Harness AI SRE</summary>

Edit the webhook in GitHub, select 'Let me select individual events', enable the required events, then click Update webhook.

</details>

<details>

<summary>GitHub webhook signature verification is failing in Harness AI SRE</summary>

Ensure the secret in GitHub matches the Harness configuration, verify Harness is checking the X-Hub-Signature-256 header, and note that GitHub uses HMAC-SHA256, not the legacy HMAC-SHA1.

</details>

<details>

<summary>GitHub webhook payload fields are missing in Harness AI SRE</summary>

Check the GitHub webhook documentation for the event-specific payload structure, and use the CEL has() function to check field existence before accessing it.

</details>

***

### Example: complete integration <a href="#example-complete-integration" id="example-complete-integration"></a>

#### GitHub webhook configuration <a href="#github-webhook-configuration" id="github-webhook-configuration"></a>

The following example shows an end-to-end GitHub webhook setup and its field mapping.

* **Payload URL**: `https://app.harness.io/gateway/ai-sre/api/webhooks/wh_abc123`
* **Content type**: `application/json`
* **Secret**: `your-secure-secret`
* **Events**:
  * Deployment statuses
  * Releases
  * Code scanning alerts
* **Active**: ✓

#### Harness webhook field mapping example <a href="#harness-webhook-field-mapping-example" id="harness-webhook-field-mapping-example"></a>

```yaml
# Deployment status events <a href="#deployment-status-events" id="deployment-status-events"></a>
title: |
  webhook.deployment_status ? 
    "Deployment " + webhook.deployment_status.state + ": " + webhook.repository.full_name :
  webhook.release ?
    "Release " + webhook.release.tag_name + ": " + webhook.repository.full_name :
  webhook.alert ?
    "Security: " + webhook.alert.rule.name + " in " + webhook.repository.full_name :
  "GitHub Event"

message: |
  webhook.deployment_status ?
    "Deployment to " + webhook.deployment_status.environment + " " + webhook.deployment_status.state :
  webhook.release ?
    "Release published: " + webhook.release.name :
  webhook.alert ?
    webhook.alert.rule.description + " (" + webhook.alert.most_recent_instance.location.path + ")" :
  "GitHub event received"

severity: |
  webhook.deployment_status && webhook.deployment_status.state == "failure" ? "critical" :
  webhook.deployment_status && webhook.deployment_status.state == "error" ? "high" :
  webhook.alert && webhook.alert.rule.severity == "error" ? "critical" :
  webhook.alert && webhook.alert.rule.severity == "warning" ? "high" :
  webhook.release ? "info" : "medium"

source: "github"

link: |
  webhook.deployment_status ? webhook.deployment_status.target_url :
  webhook.release ? webhook.release.html_url :
  webhook.alert ? webhook.alert.html_url :
  webhook.repository.html_url

tags:
  - "source:github"
  - "repository:{{webhook.repository.full_name}}"

filter: |
  (webhook.deployment_status && webhook.deployment_status.state in ["failure", "error"]) ||
  (webhook.release && !webhook.release.prerelease && !webhook.release.draft) ||
  (webhook.alert && webhook.alert.rule.severity in ["error", "warning"] && webhook.alert.state == "open")
```

***

### Next steps <a href="#next-steps" id="next-steps"></a>

* [Route alerts](/ai-sre/ai-sre-for-administrators/set-up-alert-management/alert-rules/overview.md): Route and deduplicate GitHub events.
* [Use CEL in webhooks](/ai-sre/ai-sre-for-administrators/set-up-alert-management/webhooks/use-cel-webhooks.md): Add advanced event filtering.
* [AI agent](/ai-sre/ai-sre-for-incident-responders/use-ai-agents/ai-agent.md): Enable automated incident investigation.
* [GitHub template](/ai-sre/ai-sre-for-administrators/set-up-alert-management/webhooks/templates/cicd/github.md): Use the pre-configured template.

***

### Related documentation <a href="#related-documentation" id="related-documentation"></a>

#### GitHub official documentation <a href="#github-official-documentation" id="github-official-documentation"></a>

* [Webhooks documentation](https://docs.github.com/webhooks): Complete guide to GitHub webhooks configuration and event types.
* [Webhook events and payloads](https://docs.github.com/webhooks/webhook-events-and-payloads): Event-specific payload structures (`deployment_status`, `release`, `code_scanning_alert`).
* [Validating webhook deliveries](https://docs.github.com/webhooks/using-webhooks/validating-webhook-deliveries): Signature validation (`X-Hub-Signature-256`) and secret configuration.
* [Deployments API](https://docs.github.com/rest/deployments/deployments): Deployment and deployment status payload structures.
