Skip to content

About

Bash scripts for GitHub org & enterprise administration — dual-auth (GITHUB_TOKEN or gh CLI), usable as GitHub Actions or standalone CLI tools

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Repository files navigation

GitHub API Scripts

AI Ready License Shell GitHub API

⭐ If you like this project, star it on GitHub — it helps a lot!

Overview • Getting started • Scripts • Shared Library • GitHub Actions • Resources

A collection of standalone bash scripts for GitHub organization administration. Automate common tasks like bulk permission management, repository creation, migration, and reporting using simple, self-contained utilities powered by the GitHub REST API.

Overview

This toolkit provides ready-to-use automation scripts for GitHub organization administrators. Each script is a complete, independent utility that can be run directly or integrated into your GitHub Actions workflows.

What you can do:

  • Grant team permissions across all repositories in bulk
  • Create repositories from templates with pre-configured access
  • Mirror repositories with full git history
  • Generate monthly issue reports with contributor statistics
  • Track license consumption for enterprise accounts
  • Archive old repositories
  • Discover Dockerfiles and base images across an enterprise
  • Organize your starred repositories
  • And much more!

Architecture: Scripts use a shared utility library (lib/github-common.sh) for common validation, error handling, and API helpers. Script directories are grouped by domain (org-admin/, enterprise/, reporting/, personal/) and each script remains a self-contained .sh utility.

Built with simplicity: All scripts use only curl for API requests and jq for JSON processing—no complex dependencies or installation required beyond standard Unix tools.

Note

Scripts follow a convention-over-configuration approach with built-in validation and error handling. Each can be run standalone or integrated into CI/CD pipelines and GitHub Actions workflows.

Getting started

Prerequisites

  • bash 4+
  • curl - HTTP client for API requests
  • jq - Command-line JSON processor
  • git - For repository operations (required by some scripts)
  • gh - GitHub CLI (required by github-organize-stars)
  • GitHub Personal Access Token with appropriate scopes

Installation

Clone the repository:

git clone https://github.com/locus313/github-api-scripts.git
cd github-api-scripts

Alternatively, download individual scripts as needed—each script is standalone and can be used independently.

Authentication

Create a GitHub Personal Access Token at github.com/settings/tokens with these scopes:

  • repo - Full control of repositories
  • admin:org - Organization administration
  • read:enterprise - Read enterprise data (for license scripts)

Export your token as an environment variable:

export GITHUB_TOKEN="ghp_your_token_here"

Tip

Add this export to your ~/.bashrc or ~/.zshrc to persist the token across terminal sessions.

Configuration

Scripts use environment variables for configuration. Common variables include:

Variable Description Required
GITHUB_TOKEN GitHub personal access token Yes
ORG Organization name Yes (most scripts)
API_URL_PREFIX GitHub API base URL (default: https://api.github.com) No
GIT_URL_PREFIX GitHub base URL (default: https://github.com). Must be a GitHub-family host (github.com, *.github.com, *.ghe.com, *.githubenterprise.com). No

Note

The *_PREFIX variables support GitHub Enterprise Server. Set them to your enterprise domain to use these scripts with GHES.

Pre-commit Hooks

The repository ships versioned pre-commit hooks in .githooks/. Run the installer once after cloning:

./install-hooks.sh

This sets core.hooksPath to .githooks/ so Git picks up the hooks automatically on every commit.

What the hook checks:

Check Tool Fallback
Secret scanning gitleaks Built-in regex patterns for GitHub tokens, AWS keys, private keys, and generic secrets
Shell script security shellcheck Skipped with a warning if not installed

Install the recommended tools for full coverage:

brew install gitleaks shellcheck

Tip

To bypass the hooks in an emergency: git commit --no-verify. Use sparingly — the hooks exist to prevent secrets from reaching the remote.

Unit Tests

The repository includes a bats unit-test suite in tests/. Install bats and run the full suite:

# macOS
brew install bats-core

# Ubuntu / Debian
sudo apt-get install -y bats

# Run all tests
bats tests/
File What it covers
tests/test_common.bats lib/github-common.sh functions (validate_slug, require_env_var, gh_api sentinels, gh_api_paginate, etc.)
tests/test_script_validation.bats Every script — missing required env vars, invalid CLI args, --help, and script-specific guards

CI runs bats tests/ on every pull request alongside shellcheck.

Scripts

Each script is a self-contained utility designed for a specific task. Navigate to the script's directory, set the required environment variables, and execute.

Folder Layout (Domain-Based)

  • org-admin/: github-add-repo-collaborators-by-pattern, github-add-repo-permissions, github-archive-old-repos, github-auto-repo-creation, github-close-archived-repo-security-alerts, github-enable-issues, github-get-repo-list, github-import-repo, github-migrate-internal-repos-to-private, github-repo-from-template
  • enterprise/: github-add-enterprise-team-read-permissions, github-dockerfile-discovery, github-get-consumed-licenses, github-get-public-repos, github-increase-copilot-user-budget, github-install-enterprise-app
  • reporting/: github-monthly-issues-report, github-repo-permissions-report, github-copilot-report, github-copilot-budget-advisor, github-enterprise-billing-report
  • personal/: github-organize-stars

Add Repository Permissions

Script: org-admin/github-add-repo-permissions/github-add-repo-permissions.sh

Grants team permissions across all repositories in an organization. Supports multiple permission levels (admin, maintain, push, triage, pull) and multiple teams per permission level.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"

# Set one or more permission levels (space-separated team slugs)
export REPO_ADMIN="platform-team ops-team"      # Admin permissions
export REPO_MAINTAIN="maintainers"              # Maintain permissions
export REPO_PUSH="developers contributors"      # Write/push permissions
export REPO_TRIAGE="support-team"               # Triage permissions
export REPO_PULL="external-auditors"            # Read/pull permissions

# Optional: restrict to repos whose names start with a given prefix
export REPO_NAME_FILTER="my-service-"

# Optional: skip specific repos for a given permission level (space-separated repo names)
export REPO_PULL_EXCLUDE="secret-repo internal-tools"   # These repos won't get pull access

# Optional: skip maintain/push/triage/pull on archived repos (admin is still applied)
export SKIP_ARCHIVED="true"

Usage:

cd org-admin/github-add-repo-permissions
./github-add-repo-permissions.sh

What it does:

  • Retrieves all repositories in the organization (paginated)
  • Filters to repositories whose names start with REPO_NAME_FILTER (all repos when unset)
  • Grants permissions to specified teams based on permission level
  • Supports multiple teams per permission level (space-separated)
  • Skips repos listed in the matching REPO_<LEVEL>_EXCLUDE variable for that permission level only
  • Optionally skips maintain/push/triage/pull permissions on archived repos when SKIP_ARCHIVED=true (admin permissions are still applied on archived repos)
  • Processes all five GitHub permission levels: admin, maintain, push, triage, pull
  • Includes 5-second delays between repos to avoid rate limits

Permission levels:

  • admin - Full repository access including settings and team management
  • maintain - Repository management without admin privileges
  • push - Read and write access to code
  • triage - Read access plus ability to manage issues and pull requests
  • pull - Read-only access to code

Note

At least one permission level must be set. Team slugs should be lowercase and hyphenated (e.g., "Platform Team" → platform-team).

Each permission level has an optional exclusion list: REPO_ADMIN_EXCLUDE, REPO_MAINTAIN_EXCLUDE, REPO_PUSH_EXCLUDE, REPO_TRIAGE_EXCLUDE, and REPO_PULL_EXCLUDE. Each holds space-separated exact repo names that are skipped for that level only.


Create Repository from Template

Script: org-admin/github-repo-from-template/github-repo-from-template.sh

Creates a new repository from a template with pre-configured team permissions and collaborator access.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"
export TEMPLATE_REPO="template-repo"
export REPO_ADMIN="admins platform-team"     # Space-separated team slugs
export REPO_WRITE="developers contributors"  # Space-separated team slugs
export CD_USERNAME="ci-bot"
export CD_GITHUB_TOKEN="bot_token"

Usage:

cd org-admin/github-repo-from-template
./github-repo-from-template.sh new-project-name

What it does:

  • Creates a private repository from the specified template
  • Includes all branches from the template
  • Assigns admin permissions to teams in REPO_ADMIN
  • Assigns write permissions to teams in REPO_WRITE
  • Invites CD user as collaborator and auto-accepts the invitation

Note

REPO_NAME (CLI argument), TEMPLATE_REPO, CD_USERNAME, and all team slugs in REPO_ADMIN and REPO_WRITE are validated as slugs before use. Only alphanumeric characters, hyphens, and underscores are accepted.


Import Repository

Script: org-admin/github-import-repo/github-import-repo.sh

Performs a full repository mirror—clones source repo and pushes all branches, tags, and history to a new destination repo.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"
export OWNER_USERNAME="admin-user"

Usage:

cd org-admin/github-import-repo
./github-import-repo.sh source-repo destination-repo

What it does:

  • Creates a new internal repository
  • Performs bare clone of source repository
  • Mirrors all git objects to destination
  • Grants admin permissions to specified owner
  • Cleans up local temporary clone

Warning

This creates a complete copy with full git history. Ensure you have sufficient disk space and network bandwidth for large repositories.

Note

GIT_URL_PREFIX is validated against a GitHub-host allowlist before any git operations run. Non-GitHub URLs are rejected to prevent credential leakage. Repository names and OWNER_USERNAME must be valid slugs (alphanumeric, hyphen, and underscore only).


Add Repository Collaborators by Pattern

Script: org-admin/github-add-repo-collaborators-by-pattern/github-add-repo-collaborators-by-pattern.sh

Adds one or more individual collaborators to all repositories in an organisation whose names match a given regex pattern.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"
export COLLABORATORS="alice,bob"
export REPO_NAME_REGEX='^service-'

Usage:

cd org-admin/github-add-repo-collaborators-by-pattern
./github-add-repo-collaborators-by-pattern.sh
Variable Description Default
PERMISSION Permission level: pull|triage|push|maintain|admin push
REPO_EXCLUDE_REGEX ERE regex to exclude matching repository names —

What it does:

  • Iterates all repositories in the organization (paginated)
  • Filters to repos matching REPO_NAME_REGEX
  • Optionally excludes repos matching REPO_EXCLUDE_REGEX
  • Adds each specified collaborator with the configured permission level

Archive Old Repositories

Script: org-admin/github-archive-old-repos/github-archive-old-repos.sh

Identifies and archives repositories that have not been updated within a configurable number of years. Generates a timestamped CSV report.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"

Usage:

cd org-admin/github-archive-old-repos
./github-archive-old-repos.sh

What it does:

  • Fetches all repositories in the organization (paginated)
  • Calculates a cutoff date based on YEARS_THRESHOLD
  • Generates a timestamped CSV report in the reports/ subdirectory
  • Displays a summary with the top 10 oldest repositories
  • Prompts for confirmation before archiving
  • Archives qualifying repositories via the GitHub API, skipping already-archived ones
Variable Description Default
YEARS_THRESHOLD Age threshold in years 5
REPORT_DIR Output directory for the CSV report ./reports

Auto Repository Creation

Script: org-admin/github-auto-repo-creation/github-auto-repo-creation.sh

Creates one or more private GitHub repositories in an organisation with standard configuration: branch protection on the default branch, a CODEOWNERS file, and optional team permissions.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"
export REPO_NAMES="repo1,repo2"
export REPO_OWNERS="platform-team"

Usage:

cd org-admin/github-auto-repo-creation
./github-auto-repo-creation.sh

What it does:

  • Creates each repository listed in REPO_NAMES as private
  • Configures branch protection on the default branch
  • Creates a CODEOWNERS file referencing the REPO_OWNERS teams
  • Grants admin access to teams listed in ADMIN_TEAMS
Variable Description Default
ADMIN_TEAMS Comma-separated team slugs for admin access —

Note

Requires base64 in addition to curl and jq (used to encode the CODEOWNERS file content for the API).

Note

All values in REPO_NAMES, ADMIN_TEAMS, and REPO_OWNERS are validated as slugs — only alphanumeric characters, hyphens, and underscores are allowed. The script exits with an error if any value fails this check.


Close Archived Repository Security Alerts

Script: org-admin/github-close-archived-repo-security-alerts/github-close-archived-repo-security-alerts.sh

Dismisses or resolves all open security alerts (Dependabot, code scanning, and secret scanning) across all repositories in a GitHub organisation. Generates a CSV report of dismissed alerts.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"

Usage:

cd org-admin/github-close-archived-repo-security-alerts

# Preview which alerts would be dismissed (no changes)
./github-close-archived-repo-security-alerts.sh --dry-run

# Dismiss only Dependabot alerts
./github-close-archived-repo-security-alerts.sh --type dependabot

# Dismiss all alert types
./github-close-archived-repo-security-alerts.sh

Options:

Flag Description Default
--type <type> Alert type: dependabot | code-scanning | secret-scanning | all all
--dry-run List alerts without dismissing them —
Variable Description Default
DEPENDABOT_REASON Dismiss reason for Dependabot alerts tolerable_risk
CODE_SCANNING_REASON Dismiss reason for code scanning alerts won't fix
SECRET_SCANNING_RESOLUTION Resolution for secret scanning alerts wont_fix
REPORT_DIR Output directory for the CSV report ./reports

What it does:

  • Enumerates all repositories in the organization
  • For each configured alert type, pages through all open alerts
  • Dismisses or resolves alerts with the configured reason
  • Generates a timestamped CSV report in the reports/ subdirectory

Important

Requires a token with security_events and repo scope. Use --dry-run first to preview the scope of changes.


Enable Issues

Script: org-admin/github-enable-issues/github-enable-issues.sh

Enables the Issues feature on every repository in a GitHub organisation that currently has it disabled. Skips archived repositories.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"

Usage:

cd org-admin/github-enable-issues
./github-enable-issues.sh --dry-run   # Preview only
./github-enable-issues.sh             # Apply changes
Flag Description
--dry-run List repositories that would be updated without making changes

What it does:

  • Iterates all non-archived repositories in the organization (paginated)
  • Identifies repositories with Issues disabled
  • Enables Issues on each matching repository via the PATCH API

Get Repository List

Script: org-admin/github-get-repo-list/github-get-repo-list.sh

Lists all repositories in a GitHub organisation and outputs their metadata to stdout in CSV format.

Required variables:

export GITHUB_TOKEN="your_token"
export ORG="your-org"

Usage:

cd org-admin/github-get-repo-list
./github-get-repo-list.sh
./github-get-repo-list.sh > repos.csv

What it does:

  • Fetches all repositories (paginated, 100 per page)
  • Outputs a CSV row per repository with: full name, owner, visibility, URL, description, fork flag, pushed/created/updated timestamps

Migrate Internal Repositories to Private