> 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-change-management/sources/github-actions.md).

# Configure GitHub Actions for Deploy Change Investigator

Configure GitHub Actions workflows to send build and deployment data to the [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md).

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

* **Deploy Change Investigator setup:** Create build and deploy webhook integrations in AI SRE. Go to [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) to set up the webhook endpoints.
* **GitHub repository access:** Permission to edit workflows and add secrets.
* **Webhook URLs:** Copy the build and deploy webhook URLs from your AI SRE integrations.

***

### Store webhook URLs as secrets <a href="#store-webhook-urls-as-secrets" id="store-webhook-urls-as-secrets"></a>

Store webhook URLs securely in GitHub:

1. In your repository, go to **Settings** > **Secrets and variables** > **Actions**.
2. Click **New repository secret**.
3. Create two secrets:
   * **Name:** `AISRE_BUILD_WEBHOOK_URL`
   * **Value:** Your build webhook URL from AI SRE
4. Click **Add secret**
5. Repeat for deploy webhook:
   * **Name:** `AISRE_DEPLOY_WEBHOOK_URL`
   * **Value:** Your deploy webhook URL from AI SRE

***

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

Add a webhook step to your build workflow **after** the artifact is published.

#### Example: Docker build workflow <a href="#example-docker-build-workflow" id="example-docker-build-workflow"></a>

```yaml
name: Build and Push

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GitHub Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=ref,event=branch
            type=ref,event=pr
            type=semver,pattern={{version}}
            type=sha,prefix={{branch}}-

      - name: Build and push Docker image
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}

      - name: Send build webhook to AI SRE
        if: success()
        run: |
          curl "${{ secrets.AISRE_BUILD_WEBHOOK_URL }}" \
            -s \
            -H "Content-Type: application/json" \
            -d '{
              "artifact": {
                "name": "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}",
                "version": "${{ github.sha }}"
              },
              "source": {
                "commitSha": "${{ github.sha }}",
                "kind": "branch",
                "value": "${{ github.ref_name }}",
                "repository_url": "${{ github.server_url }}/${{ github.repository }}"
              },
              "service": {
                "name": "${{ github.event.repository.name }}",
                "version": "${{ github.sha }}"
              },
              "buildId": "${{ github.run_id }}"
            }'
```

#### GitHub context variables <a href="#github-context-variables" id="github-context-variables"></a>

GitHub Actions provides these context variables automatically:

| Variable                       | Description                     | Example                                    |
| ------------------------------ | ------------------------------- | ------------------------------------------ |
| `github.sha`                   | Full commit SHA                 | `ffac537e6cbbf934b08745a378932722df287a53` |
| `github.ref_name`              | Branch or tag name              | `main`                                     |
| `github.repository`            | Repository name                 | `org/repo`                                 |
| `github.server_url`            | GitHub server URL               | `https://github.com`                       |
| `github.run_id`                | Unique workflow run ID          | `1234567890`                               |
| `github.actor`                 | User who triggered the workflow | `username`                                 |
| `github.event.repository.name` | Repository name without org     | `repo`                                     |

***

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

Add a webhook step to your deployment workflow **after** the deployment completes.

#### Example: Kubernetes deployment workflow <a href="#example-kubernetes-deployment-workflow" id="example-kubernetes-deployment-workflow"></a>

```yaml
name: Deploy to Production

on:
  workflow_run:
    workflows: ["Build and Push"]
    types: [completed]
    branches: [main]

env:
  KUBE_NAMESPACE: production
  SERVICE_NAME: myapp

jobs:
  deploy:
    runs-on: ubuntu-latest
    if: ${{ github.event.workflow_run.conclusion == 'success' }}

    steps:
      - name: Checkout code
        uses: actions/checkout@v4

      - name: Configure kubectl
        uses: azure/k8s-set-context@v3
        with:
          method: kubeconfig
          kubeconfig: ${{ secrets.KUBE_CONFIG }}

      - name: Deploy to Kubernetes
        run: |
          kubectl set image deployment/${{ env.SERVICE_NAME }} \
            ${{ env.SERVICE_NAME }}=ghcr.io/${{ github.repository }}:${{ github.sha }} \
            -n ${{ env.KUBE_NAMESPACE }}
          
          kubectl rollout status deployment/${{ env.SERVICE_NAME }} \
            -n ${{ env.KUBE_NAMESPACE }} \
            --timeout=5m

      - name: Send deploy webhook to AI SRE
        if: success()
        run: |
          curl "${{ secrets.AISRE_DEPLOY_WEBHOOK_URL }}" \
            -s \
            -H "Content-Type: application/json" \
            -d '{
              "services": [{
                "service": "${{ env.SERVICE_NAME }}",
                "version": "${{ github.sha }}"
              }],
              "environments": ["production"],
              "changeId": "${{ github.run_id }}",
              "status": "SUCCESS",
              "deployedBy": "${{ github.actor }}",
              "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
            }'

      - name: Send failure webhook to AI SRE
        if: failure()
        run: |
          curl "${{ secrets.AISRE_DEPLOY_WEBHOOK_URL }}" \
            -s \
            -H "Content-Type: application/json" \
            -d '{
              "services": [{
                "service": "${{ env.SERVICE_NAME }}",
                "version": "${{ github.sha }}"
              }],
              "environments": ["production"],
              "changeId": "${{ github.run_id }}",
              "status": "FAILURE",
              "deployedBy": "${{ github.actor }}",
              "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
            }'
```

{% hint style="info" %}
**DEPLOY STATUS IS RECORDED AS SUCCESS**

The stock Harness Deployment template records every deploy activity as `success`. Sending `"status": "FAILURE"` is accepted but does not create a failed-deployment record. Keep the failure webhook if you want the deploy event captured, but do not rely on the status value to distinguish failed deploys.
{% endhint %}

#### Multi-service deployments <a href="#multi-service-deployments" id="multi-service-deployments"></a>

For workflows that deploy multiple services:

```yaml
- name: Send deploy webhook to AI SRE
  if: success()
  run: |
    curl "${{ secrets.AISRE_DEPLOY_WEBHOOK_URL }}" \
      -s \
      -H "Content-Type: application/json" \
      -d '{
        "services": [
          {
            "service": "frontend",
            "version": "${{ needs.build-frontend.outputs.version }}"
          },
          {
            "service": "backend",
            "version": "${{ needs.build-backend.outputs.version }}"
          },
          {
            "service": "worker",
            "version": "${{ needs.build-worker.outputs.version }}"
          }
        ],
        "environments": ["production"],
        "changeId": "${{ github.run_id }}",
        "status": "SUCCESS",
        "deployedBy": "${{ github.actor }}",
        "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
      }'
```

***

### Use semantic versions <a href="#use-semantic-versions" id="use-semantic-versions"></a>

If you use semantic versioning instead of commit SHAs:

#### With Docker metadata action <a href="#with-docker-metadata-action" id="with-docker-metadata-action"></a>

```yaml
- name: Extract metadata
  id: meta
  uses: docker/metadata-action@v5
  with:
    images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
    tags: |
      type=semver,pattern={{version}}
      type=semver,pattern={{major}}.{{minor}}

- name: Send build webhook to AI SRE
  if: success()
  env:
    VERSION: ${{ steps.meta.outputs.version }}
  run: |
    curl "${{ secrets.AISRE_BUILD_WEBHOOK_URL }}" \
      -s \
      -H "Content-Type: application/json" \
      -d '{
        "artifact": {
          "name": "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}",
          "version": "'$VERSION'"
        },
        "source": {
          "commitSha": "${{ github.sha }}",
          "kind": "tag",
          "value": "${{ github.ref_name }}",
          "repository_url": "${{ github.server_url }}/${{ github.repository }}"
        },
        "service": {
          "name": "${{ github.event.repository.name }}",
          "version": "'$VERSION'"
        },
        "buildId": "${{ github.run_id }}"
      }'
```

***

### Critical mapping requirements <a href="#critical-mapping-requirements" id="critical-mapping-requirements"></a>

The Deploy Change Investigator requires exact matches between build and deploy data:

| Build webhook field                     | Deploy webhook field | Must match |
| --------------------------------------- | -------------------- | ---------- |
| `service.name`                          | `services[].service` | ✅ Yes      |
| `artifact.version` or `service.version` | `services[].version` | ✅ Yes      |

{% hint style="danger" %}
**COMMON MISTAKES**

* **Version mismatch:** Build sends commit SHA, deploy sends semantic version, so there is no match.
* **Service name mismatch:** Build sends full repository name `org/repo`, deploy sends just `repo`, so there is no match.
* Use `${{ github.sha }}` in **both** build and deploy webhooks for consistency.
  {% endhint %}

***

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

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

Trigger a build and confirm the webhook reaches AI SRE:

1. Push a commit or create a PR to trigger your build workflow.
2. Check the workflow run logs for the webhook curl command.
3. In the AI SRE left navigation, go to **Integrations**.
4. Click the **More** icon (**...**) on the BUILD integration.
5. Select **Debug** to view received webhook events.

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

Trigger a deployment and confirm the webhook reaches AI SRE:

1. Trigger a deployment workflow.
2. Check the workflow logs for webhook execution.
3. In the AI SRE left navigation, go to **Integrations** > DEPLOY > **Debug**.
4. Verify the deploy webhook appears with correct payload.

#### Verify the connection <a href="#verify-the-connection" id="verify-the-connection"></a>

After sending both build and deploy webhooks:

1. In the AI SRE left navigation, go to **Change Management**.
2. You should see deployment records linked to builds.
3. Click into a deployment to see:
   * Artifact versions
   * Commit SHAs
   * Linked PRs

***

### Reusable workflow example <a href="#reusable-workflow-example" id="reusable-workflow-example"></a>

Create a reusable workflow to standardize webhook notifications across repositories:

#### `.github/workflows/notify-aisre.yml` <a href="#githubworkflowsnotify-aisreyml" id="githubworkflowsnotify-aisreyml"></a>

```yaml
name: Notify AI SRE

on:
  workflow_call:
    inputs:
      webhook_type:
        required: true
        type: string
        description: 'build or deploy'
      service_name:
        required: true
        type: string
      service_version:
        required: true
        type: string
      environment:
        required: false
        type: string
        default: 'production'
    secrets:
      WEBHOOK_URL:
        required: true

jobs:
  notify:
    runs-on: ubuntu-latest
    steps:
      - name: Send build webhook
        if: inputs.webhook_type == 'build'
        run: |
          curl "${{ secrets.WEBHOOK_URL }}" \
            -s \
            -H "Content-Type: application/json" \
            -d '{
              "artifact": {
                "name": "ghcr.io/${{ github.repository }}",
                "version": "${{ inputs.service_version }}"
              },
              "source": {
                "commitSha": "${{ github.sha }}",
                "kind": "branch",
                "value": "${{ github.ref_name }}",
                "repository_url": "${{ github.server_url }}/${{ github.repository }}"
              },
              "service": {
                "name": "${{ inputs.service_name }}",
                "version": "${{ inputs.service_version }}"
              },
              "buildId": "${{ github.run_id }}"
            }'

      - name: Send deploy webhook
        if: inputs.webhook_type == 'deploy'
        run: |
          curl "${{ secrets.WEBHOOK_URL }}" \
            -s \
            -H "Content-Type: application/json" \
            -d '{
              "services": [{
                "service": "${{ inputs.service_name }}",
                "version": "${{ inputs.service_version }}"
              }],
              "environments": ["${{ inputs.environment }}"],
              "changeId": "${{ github.run_id }}",
              "status": "SUCCESS",
              "deployedBy": "${{ github.actor }}",
              "deployTimestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'"
            }'
```

#### Call the reusable workflow <a href="#call-the-reusable-workflow" id="call-the-reusable-workflow"></a>

```yaml
jobs:
  build:
    # ... build steps ...
    
  notify-build:
    needs: build
    uses: ./.github/workflows/notify-aisre.yml
    with:
      webhook_type: build
      service_name: myapp
      service_version: ${{ github.sha }}
    secrets:
      WEBHOOK_URL: ${{ secrets.AISRE_BUILD_WEBHOOK_URL }}
```

***

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

<details>

<summary>GitHub Actions build webhook not received in AI SRE</summary>

Confirm the webhook URL secret is configured correctly in repository settings, verify the curl command runs in the workflow logs, ensure GitHub Actions runners allow outbound HTTPS, and check the JSON payload for syntax errors.

</details>

<details>

<summary>GitHub Actions deploy webhook received but changes not showing in AI SRE</summary>

Ensure services\[].service in the deploy webhook exactly matches service.name in the build webhook, and services\[].version exactly matches artifact.version or service.version. Confirm both webhooks were sent by checking the Debug view for both integrations.

</details>

<details>

<summary>GitHub Actions workflow fails at the AI SRE webhook step</summary>

Check that the secret is configured and spelled correctly, fix any JSON syntax error in the curl payload, and confirm the date command is available using date -u +%Y-%m-%dT%H:%M:%SZ.

</details>

***

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

* Go to [Deploy Change Investigator](/ai-sre/ai-sre-for-administrators/set-up-change-management/deploy-change-investigator.md) for the complete setup guide.
* Go to [AI Agent RCA](/ai-sre/ai-sre-for-incident-responders/use-ai-agents/rca-change-agent.md) to learn how change detection works during incidents.
* Go to [Configure Jenkins](/ai-sre/ai-sre-for-administrators/set-up-change-management/sources/jenkins.md) for webhook setup in Jenkins pipelines.
