Documentation Index
Fetch the complete documentation index at: https://docs.ctrlplane.dev/llms.txt
Use this file to discover all available pages before exploring further.
The GitHub Actions job agent triggers workflow dispatch events to execute your
deployments. This is ideal for teams already using GitHub Actions for CI/CD.
How It Works
- Ctrlplane creates a job and dispatches it to GitHub
- GitHub triggers your workflow with
workflow_dispatch
- Your workflow fetches job context (version, environment, resource)
- Your workflow executes the deployment
- GitHub sends a
workflow_run webhook event to Ctrlplane as the run progresses
- Ctrlplane automatically updates the job status (in progress, successful, failure, etc.)
Prerequisites
- A GitHub App registered in your organization (see GitHub App Setup)
- The GitHub App installed on the repositories you want to dispatch workflows to
- A workflow file with
workflow_dispatch trigger in each target repository
- Ctrlplane’s workspace engine configured with the GitHub App credentials (see Server Configuration)
GitHub App Setup
Ctrlplane authenticates with GitHub using a GitHub App. The workspace engine
generates a JWT from the App’s private key and exchanges it for a short-lived
installation token to dispatch workflows.
Creating a GitHub App
- Go to GitHub → Settings → Developer settings → GitHub Apps → New GitHub App
- Fill in the required fields:
- GitHub App name: e.g.
ctrlplane-bot
- Homepage URL: your Ctrlplane instance URL
- Under Webhook:
- Webhook URL:
https://<your-ctrlplane-domain>/api/github/webhook
- Webhook secret: generate a strong secret (e.g.
openssl rand -hex 32)
- Subscribe to the Workflow runs event
- Under Permissions, grant the following Repository permissions:
- Actions: Read and write (required to dispatch workflow events)
- Contents: Read-only (required to access workflow files)
- Metadata: Read-only (granted by default)
- Click Create GitHub App
Gathering Credentials
After creating the App, collect the following values:
| Credential | Where to find it |
|---|
| App ID | GitHub App settings page → App ID (numeric) |
| Private Key | GitHub App settings page → Private keys → Generate a private key (PEM file) |
| Client ID | GitHub App settings page → Client ID |
| Client Secret | GitHub App settings page → Generate a new client secret |
| Webhook Secret | The secret you entered when creating the App (step 3 above) |
Installing the App
- From the GitHub App settings page, click Install App in the left sidebar
- Choose the organization or account to install on
- Select the repositories the App should have access to
- Note the Installation ID — you can find it in the URL after installation:
https://github.com/settings/installations/INSTALLATION_ID
You can also retrieve it via the GitHub API:
curl -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/orgs/YOUR_ORG/installations
Server Configuration
The workspace engine (and the API server) need the GitHub App credentials to
authenticate with the GitHub API. These are provided via environment variables.
Environment Variables
| Variable | Service | Required | Description |
|---|
GITHUB_BOT_APP_ID | Workspace Engine | Yes | The numeric App ID from your GitHub App settings |
GITHUB_BOT_PRIVATE_KEY | Workspace Engine | Yes | The PEM-encoded private key generated for the GitHub App |
GITHUB_WEBHOOK_SECRET | API Server | Yes | The webhook secret used to verify incoming GitHub webhook payloads |
The workspace engine uses GITHUB_BOT_APP_ID and GITHUB_BOT_PRIVATE_KEY
to generate JWTs for authenticating with the GitHub API and dispatching
workflows. If either is missing, dispatching will fail with a
GitHub bot not configured error.
The API server uses GITHUB_WEBHOOK_SECRET to verify incoming
workflow_run webhook events from GitHub. When configured, Ctrlplane
automatically updates job status as workflows progress — no manual status
reporting is needed in your workflow.
Helm Chart Configuration
When deploying with the Ctrlplane Helm chart, configure the GitHub App
credentials in your values.yaml under global.integrations.github.bot:
global:
integrations:
github:
url: "https://github.com"
bot:
appId: "123456"
privateKey: |
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
webhookSecret: "your-webhook-secret"
All bot values support either inline strings or Kubernetes valueFrom
references for secrets:
global:
integrations:
github:
url: "https://github.com"
bot:
appId:
valueFrom:
secretKeyRef:
name: github-bot-secret
key: app-id
privateKey:
valueFrom:
secretKeyRef:
name: github-bot-secret
key: private-key
webhookSecret:
valueFrom:
secretKeyRef:
name: github-bot-secret
key: webhook-secret
The full set of Helm values for the GitHub bot:
| Helm Value | Env Variable | Required for Actions | Description |
|---|
global.integrations.github.bot.appId | GITHUB_BOT_APP_ID | Yes | GitHub App numeric ID |
global.integrations.github.bot.privateKey | GITHUB_BOT_PRIVATE_KEY | Yes | PEM private key |
global.integrations.github.bot.name | GITHUB_BOT_NAME | No | Display name for the bot |
global.integrations.github.bot.clientId | GITHUB_BOT_CLIENT_ID | No | GitHub App client ID |
global.integrations.github.bot.clientSecret | GITHUB_BOT_CLIENT_SECRET | No | GitHub App client secret |
global.integrations.github.bot.webhookSecret | GITHUB_WEBHOOK_SECRET | Yes | Webhook secret for verifying incoming GitHub events |
Docker / Manual Deployment
When running the workspace engine directly, pass the environment variables:
docker run -d \
--name ctrlplane-workspace-engine \
-e GITHUB_BOT_APP_ID=123456 \
-e GITHUB_BOT_PRIVATE_KEY="$(cat private-key.pem)" \
# ... other env vars ...
ctrlplane/workspace-engine:latest
Configuration
Job Agent Setup
Create a job agent with type github-app:
type: JobAgent
name: github-actions
agentType: github-app
Deployment Configuration
Configure the deployment to use GitHub Actions:
type: Deployment
name: api-service
jobAgent: github-actions
jobAgentConfig:
installationId: 12345678
owner: your-org
repo: your-repo
workflowId: 12345678
ref: main # optional, defaults to main
| Field | Required | Description |
|---|
installationId | Yes | GitHub App installation ID |
owner | Yes | Repository owner (org or user) |
repo | Yes | Repository name |
workflowId | Yes | Workflow ID (numeric) |
ref | No | Git ref to run workflow on (default: main) |
Finding Your Installation ID
The installation ID is the numeric ID assigned when the GitHub App is installed
on an organization or user account. You can find it:
- From the URL: after installing the App, the URL will be
https://github.com/settings/installations/INSTALLATION_ID
- From the API:
curl -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/orgs/YOUR_ORG/installations
Look for the id field in the response.
Finding Your Workflow ID
Use the GitHub API to find your workflow ID:
curl -H "Authorization: Bearer $GITHUB_TOKEN" \
https://api.github.com/repos/OWNER/REPO/actions/workflows
The id field in each workflow object is the numeric workflow ID you need.
Workflow Setup
Create a workflow file in your repository:
# .github/workflows/deploy.yml
name: Deploy
on:
workflow_dispatch:
inputs:
job_id:
description: "Ctrlplane Job ID"
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get job context
uses: ctrlplanedev/get-job-inputs@v1
id: job
with:
base_url: ${{ secrets.CTRLPLANE_BASE_URL }}
job_id: ${{ inputs.job_id }}
api_key: ${{ secrets.CTRLPLANE_API_KEY }}
- name: Deploy
run: |
echo "Deploying ${{ steps.job.outputs.version_tag }}"
echo "Environment: ${{ steps.job.outputs.environment_name }}"
echo "Resource: ${{ steps.job.outputs.resource_identifier }}"
# Your deployment commands here
Available Job Context
The get-job-inputs action provides these outputs:
| Output | Description |
|---|
job_id | The Ctrlplane job ID |
version_tag | Version tag being deployed |
version_name | Version name |
environment_name | Target environment name |
environment_id | Target environment ID |
resource_identifier | Target resource identifier |
resource_name | Target resource name |
resource_kind | Target resource kind |
resource_config | Resource config (JSON) |
deployment_name | Deployment name |
deployment_variables | Deployment variables (JSON) |
Templating
You can use Go templates in your job agent config to dynamically configure
workflows:
jobAgentConfig:
installationId: "{{.variables.github_installation_id}}"
owner: "{{.variables.github_org}}"
repo: "{{.deployment.slug}}"
workflowId: "{{.variables.workflow_id}}"
ref: "{{.version.tag}}"
Status Reporting
Automatic via Webhooks (Recommended)
When the GitHub App webhook is configured (see GitHub App Setup),
Ctrlplane automatically receives workflow_run events from GitHub and updates
job status without any extra steps in your workflow.
The API server listens at /api/github/webhook and maps GitHub workflow run
states to Ctrlplane job statuses:
| GitHub Conclusion | Ctrlplane Status |
|---|
| (in progress) | in_progress |
success | successful |
failure | failure |
cancelled | cancelled |
action_required | action_required |
skipped | skipped |
neutral | skipped |
Ctrlplane matches the workflow run to a job by extracting the job ID from the
workflow run name. The get-job-inputs action includes the job ID in the run
name automatically.
For automatic status reporting to work, ensure:
- The GitHub App webhook URL is set to
https://<your-ctrlplane-domain>/api/github/webhook
- The
GITHUB_WEBHOOK_SECRET env var matches the secret configured in the GitHub App
- The App is subscribed to Workflow runs events
Manual via API (Fallback)
If you are not using webhooks, you can manually report status from the workflow
using the Ctrlplane API:
- name: Mark job successful
if: success()
run: |
curl -X PATCH "https://your-ctrlplane-instance.com/api/v1/jobs/${{ inputs.job_id }}" \
-H "Authorization: Bearer ${{ secrets.CTRLPLANE_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"status": "successful"}'
- name: Mark job failed
if: failure()
run: |
curl -X PATCH "https://your-ctrlplane-instance.com/api/v1/jobs/${{ inputs.job_id }}" \
-H "Authorization: Bearer ${{ secrets.CTRLPLANE_API_KEY }}" \
-H "Content-Type: application/json" \
-d '{"status": "failure"}'
Example: Kubernetes Deployment
name: Deploy to Kubernetes
on:
workflow_dispatch:
inputs:
job_id:
required: true
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Get job context
uses: ctrlplanedev/get-job-inputs@v1
id: job
with:
base_url: ${{ secrets.CTRLPLANE_BASE_URL }}
job_id: ${{ inputs.job_id }}
api_key: ${{ secrets.CTRLPLANE_API_KEY }}
- name: Configure kubectl
uses: azure/k8s-set-context@v3
with:
kubeconfig: ${{ secrets.KUBECONFIG }}
- name: Deploy
run: |
kubectl set image deployment/${{ steps.job.outputs.deployment_name }} \
app=${{ steps.job.outputs.version_tag }} \
-n ${{ fromJson(steps.job.outputs.resource_config).namespace }}
Troubleshooting
The workspace engine cannot find the App credentials. Verify:
GITHUB_BOT_APP_ID is set and is a valid numeric ID
GITHUB_BOT_PRIVATE_KEY is set and contains the full PEM-encoded private key
- If using Helm, check that
global.integrations.github.bot.appId and
global.integrations.github.bot.privateKey are set in your values
failed to get installation token error
The App credentials are set but the token exchange failed. Check:
- The App ID matches the GitHub App you created
- The private key has not been revoked or regenerated
- The installation ID in your deployment config is correct
- The GitHub App is still installed on the target organization/account
Workflow not triggered
- Verify the workflow file has
workflow_dispatch as a trigger
- Ensure the
ref in your config points to a branch where the workflow file exists
- Check that the GitHub App has Actions: Read and write permission on the repository
- Confirm the workflow ID is correct (use the API to verify)
Job status not updating automatically
- Verify the GitHub App webhook URL is set to
https://<your-ctrlplane-domain>/api/github/webhook
- Ensure
GITHUB_WEBHOOK_SECRET is set on the API server and matches the secret in GitHub App settings
- Check that the App is subscribed to Workflow runs events
- Confirm the API server is reachable from GitHub (not behind a firewall)
Authentication errors in the workflow
- Ensure
CTRLPLANE_API_KEY is set as a repository or organization secret in GitHub
- Verify the API key has permissions to read jobs in your Ctrlplane workspace