Bot that automates GitHub operations with Okta integration and Slack notifications. Deploy as AWS Lambda, standard HTTP server, or container.
- Okta group sync - Automatically sync Okta groups to GitHub teams
- Orphaned user detection - Identify org members not in any synced teams
- PR compliance monitoring - Detect and notify when PRs bypass branch protection
- Automatic reconciliation - Detects external team changes and triggers sync
- Flexible configuration - Enable only what you need via environment variables
- Slack notifications - Rich messages for violations and sync reports
- Go ≥ 1.24
- GitHub App (setup guide)
- Optional: Okta API Service app (setup guide)
- Optional: Slack app (setup guide)
The bot can be deployed in multiple ways:
Run as a long-lived HTTP server on any VPS, VM, or container platform:
# build
make build-server
# run (or use systemd, Docker, Kubernetes, etc.)
./dist/server
# server listens on APP_PORT (default: 8080)
# endpoints:
# POST /webhooks - GitHub webhook receiver
# POST /scheduled/okta-sync - Trigger Okta sync (call via cron)
# POST /scheduled/slack-test - Send test notification to Slack
# GET /server/status - Health check
# GET /server/config - Config (secrets redacted)Scheduling Okta Sync: Use any cron service or scheduler to POST to
/scheduled/okta-sync periodically. No EventBridge required.
Deploy as serverless function with automatic scaling:
# build for Lambda
make build-lambda # creates dist/bootstrapSee cmd/lambda/README.md for complete Lambda deployment instructions including API Gateway and EventBridge configuration.
See .env.example for a complete configuration reference.
All configuration values support direct values or AWS SSM parameter references. For sensitive values like secrets and private keys, use SSM parameters with automatic decryption:
# Direct value
APP_GITHUB_WEBHOOK_SECRET=my-secret
# SSM parameter (automatically decrypted if SecureString)
APP_GITHUB_WEBHOOK_SECRET=arn:aws:ssm:us-east-1:123456789012:parameter/github-bot/webhook-secretRequirements for SSM parameters:
- Valid AWS credentials with
ssm:GetParameterpermission - Full SSM parameter ARN in format:
arn:aws:ssm:REGION:ACCOUNT:parameter/path/to/param - SecureString parameters are automatically decrypted
| Variable | Description |
|---|---|
APP_GITHUB_APP_ID |
GitHub App ID |
APP_GITHUB_APP_PRIVATE_KEY |
Private key (PEM) |
APP_GITHUB_APP_PRIVATE_KEY_PATH |
Path to private key file |
APP_GITHUB_INSTALLATION_ID |
Installation ID |
APP_GITHUB_ORG |
Organization name |
APP_GITHUB_WEBHOOK_SECRET |
Webhook signature secret |
| Variable | Description |
|---|---|
APP_OKTA_DOMAIN |
Okta domain |
APP_OKTA_CLIENT_ID |
OAuth 2.0 client ID |
APP_OKTA_PRIVATE_KEY |
Private key (PEM) or use |
APP_OKTA_PRIVATE_KEY_PATH |
Path to private key file |
APP_OKTA_GITHUB_USER_FIELD |
User profile field for username |
APP_OKTA_SYNC_RULES |
JSON array (see examples) |
APP_OKTA_SYNC_SAFETY_THRESHOLD |
Max removal ratio (default: 0.5 = 50%) |
APP_OKTA_ORPHANED_USER_NOTIFICATIONS |
Notify about orphaned users |
| Variable | Description |
|---|---|
APP_PR_COMPLIANCE_ENABLED |
Enable monitoring (true) |
APP_PR_MONITORED_BRANCHES |
Branches to monitor (e.g., main,master) |
| Variable | Description |
|---|---|
APP_SLACK_TOKEN |
Bot token (xoxb-...) |
APP_SLACK_CHANNEL |
Default channel ID |
APP_SLACK_CHANNEL_PR_BYPASS |
Channel for PR bypass alerts (optional) |
APP_SLACK_CHANNEL_OKTA_SYNC |
Channel for sync reports (optional) |
APP_SLACK_CHANNEL_ORPHANED_USERS |
Channel for orphan alerts (optional) |
| Variable | Description |
|---|---|
APP_PORT |
Server port (default: 8080) |
APP_DEBUG_ENABLED |
Verbose logging (default: false) |
APP_BASE_PATH |
URL prefix to strip (e.g., /api/v1) |
Map Okta groups to GitHub teams using JSON rules:
[
{
"name": "sync-engineering-teams",
"enabled": true,
"okta_group_pattern": "^github-eng-.*",
"github_team_prefix": "eng-",
"strip_prefix": "github-eng-",
"sync_members": true,
"create_team_if_missing": true
},
{
"name": "sync-platform-team",
"enabled": true,
"okta_group_name": "platform-team",
"github_team_name": "platform",
"sync_members": true,
"team_privacy": "closed"
}
]See Okta Setup - Sync Rules for detailed rule field documentation.
Sync Safety Features:
- Only syncs
ACTIVEOkta users; never removes outside collaborators - Safety threshold (default 50%) aborts sync if too many removals detected
- Orphaned user detection alerts when org members aren't in any synced teams
Detailed setup guides for each integration:
- GitHub App Setup - Create and install the GitHub App with required permissions
- Okta Setup - Configure API Services app for group sync
- Slack Setup - Create Slack app for notifications
# run server locally
make server
# run all tests
make test
# integration tests (offline, uses mock servers)
make test-verify
# specific package
go test -race -count=1 ./internal/github
# specific test
go test -race -count=1 ./internal/okta -run TestGroupSyncFROM golang:1.24-alpine AS builder
WORKDIR /app
COPY . .
RUN apk add --no-cache make && make build-server
FROM alpine:latest
RUN apk --no-cache add ca-certificates
COPY --from=builder /app/dist/server /server
EXPOSE 8080
CMD ["/server"]+------------+ +------------------------------------+ +-----------+
| GitHub | ---> | github-ops-app | ---> | Slack |
| webhooks | | | | alerts |
+------------+ | +------------------------------+ | +-----------+
| | PR Compliance Check | |
+------------+ | | - verify branch protection | | +-----------+
| Okta | ---> | | - detect bypasses | | ---> | GitHub |
| groups | | +------------------------------+ | | Teams API |
+------------+ | | +-----------+
| +------------------------------+ |
| | Okta Sync Engine | |
| | - map groups to teams | |
| | - sync membership | |
| +------------------------------+ |
+------------------------------------+
- Trigger: Scheduled cron/EventBridge or team membership webhook
- Fetch: Query Okta groups matching configured rules
- Match: Apply sync rules to map Okta groups → GitHub teams
- Sync: Add/remove GitHub team members (ACTIVE Okta users only)
- Safety: Abort if removal ratio exceeds threshold (default 50%)
- Report: Send Slack notification with changes and orphaned users
- Receive: GitHub webhook on PR merge to monitored branch
- Verify: Validate webhook signature (HMAC-SHA256)
- Check: Query branch protection rules and required status checks
- Detect: Identify bypasses (admin override, missing reviews, failed checks)
- Notify: Send Slack alert with violation details
Common issues:
- Unauthorized from GitHub: Check app installation and permissions
- Group not found from Okta: Verify domain and scopes
- Webhook signature fails: Verify
APP_GITHUB_WEBHOOK_SECRETmatches - No Slack notifications: Verify token has
chat:writeand bot is in channel
MIT