Skip to main content

GitHub Team Management

Overview

Repository access is controlled through GitHub Teams, which are automatically synced from Keycloak groups via SCIM.

Principle: Keycloak is the source of truth, GitHub teams mirror Keycloak groups.

Team Structure

@company-org/
├── @all-engineering (all engineers, read-all)
├── @backend-team (backend repos, write)
├── @frontend-team (frontend repos, write)
├── @devops-team (infrastructure repos, write + admin)
├── @mobile-team (mobile app repos, write)
├── @security-team (security reviews)
└── @admins (org-level admins)

Repository Access Model

Public vs Private Repositories

  • Private repos (default): Require team membership for access
  • Internal repos: Visible to all org members, write access requires team membership
  • Public repos: Only for open-source projects, strict review required

Default: All company repos are private.

Access Levels

RolePermissionsUse Case
ReadClone, pull, view issues/PRsDefault for all engineers
TriageManage issues, no code changesProduct managers, support
WritePush, create branches, merge PRsTeam members
MaintainManage repo settings (no danger)Tech leads
AdminFull control including deletionDevOps, CTO only

Team-to-Repository Mapping

Backend Team

Keycloak Group: engineering-backend GitHub Team: @backend-team

Repositories (Write Access):

  • api-server
  • auth-service
  • notification-worker
  • shared-backend-libs

Repositories (Admin Access):

  • None (DevOps manages repo settings)

Frontend Team

Keycloak Group: engineering-frontend GitHub Team: @frontend-team

Repositories (Write Access):

  • web-app
  • admin-dashboard
  • shared-ui-components
  • design-system

DevOps Team

Keycloak Group: engineering-devops GitHub Team: @devops-team

Repositories (Write Access):

  • infrastructure (Ansible playbooks)
  • terraform-configs
  • docker-images
  • .github (org-level workflows)

Repositories (Admin Access):

  • All repositories (for settings management, branch protection)

Cross-Team Repositories

Some repos need access from multiple teams:

Example: shared-libraries

  • @backend-team → Write
  • @frontend-team → Write
  • @mobile-team → Write

Managed via: Repository settings → Collaborators and teams

Branch Protection Rules

All production code repositories must have branch protection on main:

Standard Protection (All Repos)

Branch: main
Protections:
- Require pull request before merging
- Require 1 approval
- Dismiss stale reviews when new commits pushed
- Require status checks to pass
- CI build
- Unit tests
- Linting
- Security scan
- Require conversation resolution before merging
- Include administrators (yes - no one bypasses)
- Require linear history
- Allow force pushes: No
- Allow deletions: No

Infrastructure Repos (Extra Protection)

Branch: main
Additional protections:
- Require 2 approvals (peer + DevOps lead)
- Require code owner review
- Restrict who can push:
- @devops-team only

CODEOWNERS file:

# Infrastructure changes require DevOps approval
/ansible/ @devops-team
/terraform/ @devops-team
*.tf @devops-team

Required Status Checks

Every PR must pass these automated checks before merge:

Standard Checks (All Repos)

  • Build: Code compiles/builds successfully
  • Tests: All unit tests pass
  • Lint: Code style checks pass
  • Security: No high/critical vulnerabilities found

Defined in: .github/workflows/ci.yml

Additional Checks (By Repo Type)

Backend APIs:

  • API contract tests
  • Database migration tests
  • Integration tests

Frontend:

  • Visual regression tests (Chromatic/Percy)
  • Accessibility tests
  • Bundle size check

Infrastructure:

  • Ansible syntax check
  • Terraform plan validation
  • Cost estimation (Infracost)

Code Review Requirements

Who Can Approve

Any team member can approve PRs for their team's repositories.

Special cases:

  • Infrastructure changes → Require DevOps team member approval
  • Security-sensitive code → Auto-tag @security-team for review (async, non-blocking)
  • Breaking API changes → Require tech lead approval

Automated tagging based on file changes:

# .github/CODEOWNERS
/ansible/ @devops-team
/terraform/ @devops-team
**/auth* @security-team
**/secrets* @security-team

Review Expectations

Reviewers should check:

  • ✅ Code quality and readability
  • ✅ Tests included for new features
  • ✅ No obvious security issues
  • ✅ Documentation updated if needed
  • ✅ No secrets committed

Not required:

  • ❌ Perfection (we iterate)
  • ❌ Complete rewrite suggestions
  • ❌ Nitpicking formatting (linters handle that)

Timeline: Aim to review PRs within 24 hours (4 hours for urgent).

Automated Workflows

PR Auto-Labeling

PRs are automatically labeled based on changes:

# .github/workflows/labeler.yml
frontend:
- web-app/**/*
- admin-dashboard/**/*

backend:
- api-server/**/*
- auth-service/**/*

infrastructure:
- ansible/**/*
- terraform/**/*

security-review:
- "**/*auth*"
- "**/*secret*"
- "**/*password*"

Auto-Assign Reviewers

# .github/workflows/auto-assign.yml
# PRs automatically assigned to team members based on files changed

Dependency Updates (Dependabot)

# .github/dependabot.yml
version: 2
updates:
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "frontend-team"
labels:
- "dependencies"

- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "weekly"
reviewers:
- "backend-team"

Auto-merge minor updates if CI passes (via Dependabot auto-merge).

GitHub Actions Secrets

Secrets for CI/CD workflows are managed at different scopes:

Organization Secrets

Available to all repos:

  • DIGITALOCEAN_TOKEN - For deployments
  • DOCKER_REGISTRY_TOKEN - For pushing images
  • SLACK_WEBHOOK (if using) - For notifications

Who can manage: @devops-team only

Repository Secrets

Specific to one repo:

  • API_KEY_FOR_SERVICE_X
  • DATABASE_URL_STAGING

Who can manage: Repo admins (@devops-team)

Environment Secrets

Tied to deployment environments:

Production environment:

  • Requires approval from @devops-team
  • Secrets: PROD_DB_URL, PROD_API_KEY, etc.

Staging environment:

  • No approval required
  • Secrets: STAGING_DB_URL, etc.

Common Tasks

Request Access to a Repository

Self-service (if you're in the right Keycloak group):

# Access granted automatically within 15 minutes via SCIM sync
# Just wait for the GitHub invitation email

Manual request (for special access):

# In Rocket.Chat
/access request github-repo=infrastructure-repo justification="Need to review Ansible playbook for bug fix"

Create a New Repository

  1. Create repo in GitHub
  2. Configure teams:
    • Add @all-engineering with Read
    • Add relevant team(s) with Write
    • Add @devops-team with Admin
  3. Set up branch protection (required)
  4. Add required status checks (CI workflow)
  5. Announce in Rocket.Chat #engineering

Template checklist: docs/06-self-service/new-service-checklist.md

Transfer Repository Ownership

When: Moving repo between teams

Process:

  1. Update team permissions in GitHub
  2. Update CODEOWNERS file
  3. Announce in both team channels
  4. Update documentation

Remove Someone's Access

Automatic when removed from Keycloak group:

  • SCIM sync removes from GitHub team within 15 min
  • GitHub automatically revokes repo access

Manual (immediate removal needed):

  1. Go to GitHub org → People
  2. Find user → Remove from organization
  3. Document reason in #security channel

Security Best Practices

Personal Access Tokens (PATs)

When to use: For local Git operations, API access

How to create:

  1. GitHub Settings → Developer settings → Personal access tokens → Fine-grained tokens
  2. Set expiration (max 90 days)
  3. Scope to specific repos only
  4. Minimum permissions needed

Do NOT:

  • ❌ Use classic tokens (use fine-grained)
  • ❌ Set no expiration
  • ❌ Grant full org access
  • ❌ Commit tokens to code

SSH Keys

Recommended over HTTPS for Git operations.

Setup:

# Generate key
ssh-keygen -t ed25519 -C "your.email@company.com"

# Add to GitHub
cat ~/.ssh/id_ed25519.pub
# Copy and paste into GitHub Settings → SSH Keys

Best practice: Different SSH keys for different machines.

Commit Signing

Recommended for all commits (not enforced yet).

Setup GPG signing:

# Generate GPG key
gpg --gen-key

# Configure Git
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true

# Add public key to GitHub
gpg --armor --export YOUR_KEY_ID
# Paste into GitHub Settings → SSH and GPG keys

Monitoring & Auditing

GitHub audit log tracks:

  • Repository access changes
  • Team membership changes
  • Branch protection modifications
  • Secret access
  • Failed auth attempts

Reviewed by: @devops-team weekly Alerts on:

  • Org admin additions
  • Repo deletions
  • Branch protection removals

Audit export: Monthly backup to DigitalOcean Spaces

Troubleshooting

I can't access a repository:

  1. Check if you're in the right Keycloak group
  2. Wait 15 min for SCIM sync
  3. Check GitHub email for team invitation (accept it)
  4. If still blocked, post in #it-support

PR checks failing:

  1. Click "Details" on failing check
  2. Review error logs
  3. Fix locally and push again
  4. If CI is broken, post in #devops

Can't push to branch:

  • Check if branch is protected (you need a PR)
  • Check if you have write access to the repo
  • Check if you need to update your local branch

Need urgent merge but reviewer unavailable:

  • Tag another team member for review
  • For emergencies: Tag @devops-team (can merge with override)
  • Document why it was urgent in PR description