GitHub Integration Setup Guide
This guide walks you through connecting Lathe Studio to GitHub for CI/CD pipeline integration.
Prerequisites#
- GitHub account (personal or organization)
- GitHub repository with Actions workflows
- Project admin access in Lathe Studio
Overview#
The GitHub integration enables:
- CI/CD Webhooks: Automatically create builds when GitHub Actions workflows complete
Connecting GitHub#
Step 1: Create a GitHub Connection in Lathe Studio
- In Lathe Studio, open your project and go to Project Settings → Integrations
- Find GitHub and click Connect
- Lathe Studio generates a webhook URL containing a unique token and a webhook secret — copy both
Step 2: Configure the GitHub Webhook
- In GitHub, go to your repository
- Navigate to Settings > Webhooks
- Click Add webhook
- Configure:
- Payload URL: the webhook URL from Lathe Studio (includes
?token=...) - Content type:
application/json - Secret: the webhook secret from Lathe Studio (enables
X-Hub-Signature-256verification) - SSL verification: Enable
- Payload URL: the webhook URL from Lathe Studio (includes
- Events: Select "Let me select individual events", check "Workflow runs" (or "Send me everything")
- Click Add webhook
Step 3: Test the Integration
- Trigger a workflow run in GitHub Actions
- Open the GitHub connection panel in Lathe Studio to see recent events
- If the workflow name matches a pipeline with auto-create enabled, a build appears on the Releases page
Authentication#
GitHub webhooks are authenticated by the unique token in the webhook URL
(?token=...), which identifies your project's connection. When a webhook
secret is configured on the connection, Lathe Studio also requires a valid
X-Hub-Signature-256 HMAC-SHA256 signature on every request.
How It Works#
- Workflow Completes → GitHub sends the
workflow_runevent to your webhook URL (/api/webhooks/github?token=...) - Authentication → The token identifies your project's connection; if a secret is configured, the
X-Hub-Signature-256signature must also be valid - Pipeline Matching → The workflow name is matched against the pipelines configured on the connection
- Build Creation → When the matching pipeline has auto-create enabled (the default), a build is created in your project as soon as the workflow completes
- Review → Every event is recorded in the connection's recent events list, so you can confirm delivery and troubleshoot
Build Queue UI#
The Build Queue on the Releases page holds builds that arrived without a project or release assignment (for example, from the Bitbucket webhook). From the queue you can:
- Assign to Release: Select an active release for the project
- Select Project: Navigate to projects if the project was not auto-detected
- Reject: Remove the build from the queue (no build created)
GitHub Actions Example#
To report test results back to Lathe Studio, create an API key (Settings > Organization > API Keys) with the results:submit scope, store it as the LATHE_STUDIO_API_KEY repository secret, then add this step to your existing .github/workflows/test.yml after your test runner finishes. The if: always() ensures results are sent even if tests fail.
name: Test and Report
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Tests
run: npm test -- --reporter=json --outputFile=test-results.json
- name: Upload Results to Lathe Studio
if: always()
env:
LATHE_API_KEY: ${{ secrets.LATHE_STUDIO_API_KEY }}
run: |
# Parse your test framework's JSON output into the Lathe Studio format.
# Below is an example for Jest — adapt the jq filter to your framework.
RESULTS=$(jq -c '
[.testResults[] | .assertionResults[] | select(.status != "pending") | {
test_identifier: .ancestorTitles + [.title] | join(" > "),
name: .title,
status: (if .status == "passed" then "passed" elif .status == "failed" then "failed" else "skipped" end),
duration_ms: .duration,
error: (if .failureMessages | length > 0 then .failureMessages[0] else null end)
}]
' test-results.json)
curl -X POST https://lathe.studio/api/v1/results/ingest \
-H "Authorization: Bearer $LATHE_API_KEY" \
-H "Content-Type: application/json" \
-d "{
\"build\": {
\"identifier\": \"${{ github.ref_name }}-${{ github.run_number }}\",
\"branch\": \"${{ github.ref_name }}\",
\"commit_sha\": \"${{ github.sha }}\",
\"url\": \"${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}\"
},
\"source\": {
\"pipeline\": \"github_actions\",
\"run_id\": \"${{ github.run_id }}\",
\"run_url\": \"${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}\"
},
\"results\": $RESULTS
}"
What this does:
- Runs your tests and outputs JSON (Jest example shown)
- Parses the JSON into Lathe Studio's
IngestResultformat - Sends everything to
POST /api/v1/results/ingest - Lathe Studio automatically:
- Creates a Build (or re-uses an existing one by
identifier) - Creates a completed Test Run linked to that Build
- Matches results to existing Test Cases by
test_identifier - Auto-creates new Test Cases for unknown identifiers
- Creates a Build (or re-uses an existing one by
If your API key is org-scoped (not tied to one project), also include "project_key": "YOUR-PROJECT-CODE" at the top level of the payload.
Response:
{
"build_id": "uuid",
"build_display_id": "main-1042",
"test_run_id": "uuid",
"test_run_display_id": "RUN-MOB-0123",
"test_run_url": "/projects/.../runs/...",
"test_cases_created": 3,
"test_cases_linked": 47,
"results_imported": 50
}
Adapting to other test frameworks:
For result files, lathe report <file> --project <code> reads JUnit XML, TestNG XML
(testng-results.xml), NUnit 3 XML, xUnit.net v2 XML, and Cucumber JSON. It
detects the format from the file or accepts --format to specify one. The
direct POST /api/v1/results/ingest endpoint shown above accepts JSON payloads,
not raw report files.
| Framework | Approach |
|---|---|
| Jest | Use --json --outputFile= then jq to map fields |
| Pytest | Use pytest-json-report plugin, map nodeid → test_identifier |
| JUnit XML | Send the file with lathe report |
| Cypress, Playwright, Postman (Newman), pytest, Appium-based suites | Configure their JUnit XML output, then use lathe report |
The only requirement is that each result has a stable test_identifier string. Use your existing display codes (TC-MOB-0042) or any unique ID — Lathe Studio will match them automatically.
Troubleshooting#
Builds not appearing
- Check webhook delivery in GitHub (Settings > Webhooks > Recent Deliveries)
- Verify the webhook URL includes the
?token=query parameter - Ensure the "Workflow runs" event is selected
- Check the connection's recent events in Lathe Studio — if the event arrived but no build was created, the workflow name may not match any configured pipeline
Webhook signature verification fails
If using webhook secrets:
- Verify the secret in GitHub matches the one shown in the Lathe Studio connection panel
- Check that GitHub is sending the
X-Hub-Signature-256header - Ensure the payload hasn't been modified
Security#
- The webhook URL token identifies your project's connection — treat it as a secret
- Webhook secrets are stored encrypted and used for HMAC-SHA256 signature verification
- Results-ingest API keys are hashed using SHA-256 before storage; only the first 12 characters are kept for identification
- Keys can be revoked at any time
- All webhook communications use HTTPS
Unlinking GitHub#
To disconnect:
- Go to your GitHub repository
- Navigate to Settings > Webhooks
- Find the Lathe Studio webhook
- Click Delete
Note: Previously created builds remain in Lathe Studio. New builds will not be created until reconnected.
Advanced Configuration#
Pipeline Auto-Create
Each pipeline configured on the connection matches events by workflow name and can toggle automatic build creation. When auto-create is off, events are still recorded in the connection's recent events list without creating builds.
For additional help, contact support.