GitHub
Connect GitHub to Team Server, place the Runtime Sensor on the runner, and instrument each protected GitHub Actions job with Endura commands.
Object Mapping
| GitHub | Team Server |
|---|---|
| Organization | Discovery scope |
| Repository | Pipeline |
| Workflow run | Build |
| Job | Part of the workflow-run build |
Discover the repository before instrumenting it. All its workflows and jobs share one policy.
Prerequisites
- Operator or Administrator access to Team Server
- GitHub organization access that can create an integration token
- Permission to edit protected workflows
- For self-hosted runners, root access to every Linux x86-64 runner host
- For GitHub-hosted runners, an Endura license and Runtime Sensor token stored as Actions secrets
Configure the Integration
Credentials and Permissions
Use a dedicated service account. Team Server supports both classic and fine-grained personal access tokens.
For a classic personal access token, use these scopes:
| Scope | When it is required |
|---|---|
read:org | Always. Team Server uses it to list the organizations available to the token owner. |
repo | When Team Server must discover private repositories or read their GitHub Actions workflow-run history. Selecting the parent repo checkbox also selects its child scopes, which is expected. |
The repo scope does not include read:org, so select both when private repositories are required. GitHub does not provide a read-only classic PAT scope for private repositories. The repo scope therefore grants more access than Team Server uses, and the token must be protected accordingly.
For organizations that contain only public repositories, read:org is sufficient. The token owner must be a member of every organization Team Server should discover and must have access to the required repositories. If an organization uses SAML single sign-on, authorize the classic token for that organization.
For a fine-grained personal access token, configure:
| Setting | Value |
|---|---|
| Resource owner | The GitHub organization Team Server should discover. The token can discover only the organization selected as its resource owner, so use a separate token and integration for each organization. |
| Repository access | All repositories, or Only select repositories containing the workflows Team Server should monitor. |
| Repository permissions | Metadata: Read-only and Actions: Read-only. |
The organization may need to approve the fine-grained token before it can access organization resources. If repository access is limited to selected repositories, Team Server discovers only those repositories.
Set an expiration and rotation owner, then copy the token into your secrets manager.
Add GitHub to Team Server
- Open Integrations, then GitHub under Discover.
- Select Get Started or Create.
- Enter
https://github.comor the base URL of GitHub Enterprise Server. - Paste the token and select Test.
- Select the organizations to discover.
- Select Save.
Repositories from the selected organizations appear under Pipelines. Create a separate integration for each GitHub Enterprise Server or credential boundary.
For a private GitHub Enterprise Server address or internal CA, configure Team Server outbound HTTP policy.
Schedule Discovery
Add these jobs to Team Server’s scheduler.jobs:
github_pipelines:
run: "github_sync mode:pipelines trigger:scheduled"
schedule: "0 2 * * * * *"
github_builds:
run: "github_sync mode:builds trigger:scheduled"
schedule: "0 3,18,33,48 * * * * *"Keep the required statistics_calculate and status_reconcile jobs enabled. Restart Team Server after changing its configuration; see Scheduler.
Manage Sync and Deletion
Use Start Sync for an immediate run. See sync controls and deletion.
Choose the Runner Pattern
Self-hosted Runners
Install the Runtime Sensor once on every host that can run a protected workflow. Include installation in images or provisioning for ephemeral self-hosted runners. See Runtime Sensor deployment.
Use runner labels to keep protected jobs on Sensor-enabled Linux x86-64 hosts. Instrument every protected job:
jobs:
build:
runs-on: [self-hosted, linux, x64, endura]
steps:
# Start protection before source checkout.
- name: Start Endura Job
run: |
ENDURA_JOB_ID=$(endura job start)
echo "started endura job with id ${ENDURA_JOB_ID}"
# Check out and build protected sources.
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build
run: make build
# Stop protection after every job outcome.
- name: Stop Endura Job
if: always()
run: endura job stopif: always() schedules cleanup after failure or cancellation. Forced cancellation, deadlines, or runner loss can still prevent cleanup and artifact collection. Keep Sensor credentials in the root-only host configuration.
GitHub-hosted Runners
GitHub-hosted runners are ephemeral, so install and start the Runtime Sensor within the job. Store ENDURA_LICENSE_KEY and ENDURA_SENSOR_TOKEN as repository or organization secrets.
name: CI
on:
push:
workflow_dispatch:
env:
ENDURA_TEAM_SERVER: https://team-server.example.com
ENDURA_ENV_VARS: ENDURA_TEAM_SERVER,ENDURA_LICENSE_KEY,ENDURA_SENSOR_TOKEN,ENDURA_LOG_FILE
jobs:
build:
runs-on: ubuntu-26.04
permissions:
contents: read
steps:
- name: Start Endura Sensor
run: |
# Install the Runtime Sensor package.
curl -sSf https://repo.endurasecurity.com/install/endura-sensor/testing.sh | sudo sh
# Start and verify the ephemeral Sensor.
export ENDURA_LOG_FILE="${RUNNER_TEMP}/endura.log"
sudo --preserve-env="${ENDURA_ENV_VARS}" endura sensor start -d
echo "started endura sensor: $(endura sensor status)"
sudo endura sensor hooks
# Start protection for subsequent workflow steps.
ENDURA_JOB_ID=$(endura job start)
echo "started endura job with id ${ENDURA_JOB_ID}"
# Expose credentials only during Sensor startup.
env:
ENDURA_LICENSE_KEY: "${{ secrets.ENDURA_LICENSE_KEY }}"
ENDURA_SENSOR_TOKEN: "${{ secrets.ENDURA_SENSOR_TOKEN }}"
# Check out and build protected sources.
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: Build
run: make build
# Stop and flush the ephemeral Sensor.
- name: Stop Endura Sensor
if: always()
run: sudo endura sensor stop
# Make the root-owned log uploadable.
- name: Prepare Endura Sensor Log
if: always()
run: |
if test -f "${RUNNER_TEMP}/endura.log"; then
sudo chown "$(id -u):$(id -g)" "${RUNNER_TEMP}/endura.log"
fi
# Retain Sensor logs after every outcome.
- name: Upload Endura Sensor Log
if: always()
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: endura-sensor-log-${{ github.job }}-${{ github.run_attempt }}
path: ${{ runner.temp }}/endura.log
if-no-files-found: warnKeep ENDURA_TEAM_SERVER and the named sudo allowlist at workflow scope. Expose license and token only to Sensor startup; add any optional startup variable to that allowlist. Build and cleanup steps need no Sensor credentials.
The example checks status unprivileged and uses root for installation, startup, hooks, shutdown, and log ownership. After shutdown, it transfers the RUNNER_TEMP log to the runner for upload. Both cleanup and upload use if: always().
Sensor shutdown stops active jobs, prints derived policies, and attempts telemetry delivery. No preceding job stop or autoflush setting is needed. Keep cleanup failures visible and restrict GITHUB_TOKEN to build requirements.
Container Jobs on Self-hosted Runners
The Runtime Sensor remains on the runner host. Mount its socket and install the CLI inside the job container:
jobs:
build:
runs-on: [self-hosted, linux, x64, endura]
container:
image: node:24.21.0-bookworm
options: --volume /run/endura/sensor.sock:/run/endura/sensor.sock
steps:
- name: Start Endura Job
run: |
# Install the CLI inside the container.
curl -sSf https://repo.endurasecurity.com/install/endura-sensor/testing.sh | sh
# Start protection through the host Sensor.
ENDURA_JOB_ID=$(endura job start)
echo "started endura job with id ${ENDURA_JOB_ID}"
# Check out and test protected sources.
- name: Checkout Code
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- run: npm test
# Stop protection after every job outcome.
- name: Stop Endura Job
if: always()
run: endura job stopWithout the socket mount, the CLI cannot reach the Runtime Sensor on the host.
Multi-job Workflows
Instrument each job that performs protected work. Jobs run in separate runner contexts, but all instrumented jobs in one workflow run report to the same Team Server build. Every job and workflow in the repository shares the repository policy.
Run all jobs and workflow variants while deriving the policy.
Standardize Instrumentation
- Put start and stop logic in centrally maintained composite actions.
- Wrap common build behavior in reusable workflows.
- Publish workflow templates to simplify adoption in new repositories.
Pin reused actions to a full commit SHA. These mechanisms reduce duplication but still require repositories or workflows to adopt the Endura wrapper. GitHub ruleset workflows gate pull-request merges; they do not transparently wrap every job in a repository and are not presented as universal Runtime Sensor instrumentation.
Verify
- Run an instrumented workflow.
- Open the repository under Pipelines in Team Server.
- Open Builds and confirm the workflow run appears.
- Confirm
endura sensor statusreports the expected Team Server connection and root-onlyendura sensor hooksreports the expected hook coverage. - If the run does not appear, confirm repository discovery, runner placement, and the start-step log.
Troubleshooting
| Symptom | Check |
|---|---|
| No organizations or repositories appear | For a fine-grained PAT, confirm the target organization is the resource owner and the organization approved the token. For a classic PAT, confirm read:org. Then verify repository access and both GitHub discovery jobs. |
| A workflow run does not appear | Confirm the repository was discovered first, the Runtime Sensor was online on the selected runner, and the start step ran. |
| A GitHub-hosted runner cannot start the Runtime Sensor | Review the installer output and confirm the runner provides the required root access, BTF, and eBPF capabilities. Use endura sensor hooks to distinguish hook attachment from Team Server connectivity. |
| A container job cannot reach the Runtime Sensor | Confirm the host socket is mounted at /run/endura/sensor.sock inside the job container. |
| A job remains active | On a self-hosted runner, confirm the job-stop step uses if: always(). On a GitHub-hosted runner, confirm the Sensor-stop step uses if: always(). Review the cleanup log and retained Sensor artifact for errors. |
Create and Assign a Policy
Derive across representative workflows and jobs and capture the policy printed by endura job stop (persistent runners) or endura sensor stop (ephemeral runners). Refine and test it in observe mode, then assign it to the repository pipeline before enforcement.
Configure notifications after violations reach Team Server.