Collects GitHub organization security posture metrics
epack install collector github
Adds to epack.yaml, resolves dependencies, downloads binary.
Run all configured collectors and build a pack:
epack collect
Runs all collectors in epack.yaml and outputs an evidence pack.
Or add manually to epack.yaml:
collectors:
github:
source: https://github.com/locktivity/epack-collector-github
Then run epack install to lock and sync.
The GitHub Posture Collector gathers security posture metrics from your GitHub organization.
This collector queries your GitHub organization and aggregates security posture coverage metrics:
All metrics are expressed as coverage percentages (0-100) rather than raw counts, making it easy to track and compare security posture over time. The scope is included in the output so receivers can understand exactly what was covered.
GITHUB_TOKEN supplied by the runtimeGitHub App authentication is recommended for manual setups:
- Not tied to a user account
- Better audit logging
- Higher rate limits
- Recommended by GitHub for org-level integrations
When the collector runs under a managed or brokered runtime, GITHUB_TOKEN may be a short-lived installation token instead of a user PAT.
See Configuration for setup instructions.
The collector supports two authentication methods. GitHub App is recommended for manual setups because it provides better security and audit capabilities. For managed or brokered runtimes, the collector can also consume a short-lived GITHUB_TOKEN.
GitHub Apps provide the best security posture:
- Not tied to a user account
- Better audit logging
- Higher rate limits
- Recommended by GitHub for org-level integrations
collectors:
github:
source: locktivity/epack-collector-github@^0.1
config:
organization: myorg
app_id: 123456
installation_id: 78901234
secrets:
- GITHUB_APP_PRIVATE_KEY
epack-posture-collector (or your preferred name).pem filehttps://github.com/organizations/myorg/settings/installations/78901234)Set the GITHUB_APP_PRIVATE_KEY secret to the contents of the .pem file:
export GITHUB_APP_PRIVATE_KEY="$(cat /path/to/private-key.pem)"
epack collect
GITHUB_TOKEN (Brokered Token or PAT)The collector accepts a GITHUB_TOKEN for GitHub API access. In practice this can be:
- a short-lived GitHub installation token injected by a trusted runtime or broker
- a classic PAT for manual setups
Classic PATs still work, but they are not recommended when a short-lived or GitHub App-based flow is available.
collectors:
github:
source: locktivity/epack-collector-github@^0.1
config:
organization: myorg
secrets:
- GITHUB_TOKEN
Create a classic token with these scopes:
- repo - Repository access (or public_repo for public repos only)
- admin:org - (Optional) Read organization settings for 2FA status
Note: Without admin:org, the collector will still work but two_factor_required will be null (unknown) in the output.
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
organization |
string | Yes | - | GitHub organization name |
app_id |
int | No* | - | GitHub App ID |
installation_id |
int | No* | - | GitHub App installation ID |
include_patterns |
[]string | No | ["*"] |
Glob patterns for repositories to include |
exclude_patterns |
[]string | No | [] |
Glob patterns for repositories to exclude |
*Required if using GitHub App authentication
| Name | Required | Description |
|---|---|---|
GITHUB_APP_PRIVATE_KEY |
For App auth | GitHub App private key (PEM format) |
GITHUB_TOKEN |
For token auth | GitHub API token (short-lived installation token or classic PAT) |
The include and exclude patterns use glob syntax:
* matches any characters? matches a single characterArchived repositories are skipped automatically and are not assessed for security settings or code scanning status.
# Include all non-archived repos, but exclude deprecated repos by name
include_patterns: ["*"]
exclude_patterns: ["*-deprecated"]
# Only include production repos
include_patterns: ["prod-*", "platform-*"]
exclude_patterns: []
# Exclude test and experimental repos
include_patterns: ["*"]
exclude_patterns: ["test-*", "experiment-*", "sandbox-*"]
For GitHub App authentication, the app needs:
Repository permissions:
- Administration: Read-only (for security settings and security_and_analysis field)
- Contents: Read-only (for repository metadata)
- Metadata: Read-only (always required)
- Code scanning alerts: Read-only (for code scanning status)
- Secret scanning alerts: Read-only (for secret scanning status)
- Dependabot alerts: Read-only (for dependabot status)
Organization permissions:
- Administration: Read-only (for 2FA settings)
- Members: Read-only (for organization membership)
Secret scanning and push protection metrics require that these features are enabled for your organization. Some features may require GitHub Advanced Security for private repositories.
"organization is required"
The organization field must be set in your config:
config:
organization: myorg # Required
"authentication required"
You must provide either:
- GITHUB_TOKEN secret (for brokered token or PAT auth), or
- app_id in config + GITHUB_APP_PRIVATE_KEY secret (for App auth)
"401 Unauthorized"
Your credentials are invalid or expired. For GitHub Apps, ensure the private key matches the app and the app is installed on the organization.
"403 Forbidden"
This can occur for two reasons:
Missing permissions: The authenticated user or app doesn't have the required permissions. See Required GitHub App Permissions above.
GitHub Advanced Security not enabled: For code scanning checks, GitHub returns 403 if Advanced Security is not enabled on the repository. The error message will show: "Advanced Security must be enabled for this repository to use code scanning."
stream: myorg/github-posture
collectors:
github:
source: locktivity/epack-collector-github@^0.1
config:
organization: myorg
app_id: 123456
installation_id: 78901234
secrets:
- GITHUB_APP_PRIVATE_KEY
Then run:
export GITHUB_APP_PRIVATE_KEY="$(cat /path/to/private-key.pem)"
epack collect
See Configuration for GitHub App setup instructions.
GITHUB_TOKEN (Brokered Token or PAT)stream: myorg/github-posture
collectors:
github:
source: locktivity/epack-collector-github@^0.1
config:
organization: myorg
secrets:
- GITHUB_TOKEN
Then run:
export GITHUB_TOKEN=ghp_xxxx
epack collect
GITHUB_TOKEN can be a short-lived installation token injected by the runtime, or a classic PAT for manual use.
collectors:
github:
source: locktivity/epack-collector-github@^0.1
config:
organization: myorg
app_id: 123456
installation_id: 78901234
exclude_patterns:
- "*-archived"
- "*-deprecated"
- "*-old"
secrets:
- GITHUB_APP_PRIVATE_KEY
collectors:
github:
source: locktivity/epack-collector-github@^0.1
config:
organization: myorg
app_id: 123456
installation_id: 78901234
include_patterns:
- "prod-*"
- "platform-*"
- "service-*"
secrets:
- GITHUB_APP_PRIVATE_KEY
{
"protocol_version": 1,
"data": {
"schema_version": "1.0.0",
"collected_at": "2026-02-23T14:30:00Z",
"organization": "myorg",
"scope": {
"include_patterns": ["*"],
"exclude_patterns": ["*-archived", "test-*"],
"repositories_coverage": 79
},
"posture": {
"branch_protection_coverage": 93,
"security_features_coverage": 72
},
"access_control": {
"two_factor_required": true
},
"branch_protection_rules": {
"pull_request_required": 93,
"approving_reviews": 89,
"dismiss_stale_reviews": 84,
"code_owner_reviews": 33,
"status_checks": 87,
"signed_commits": 49,
"admin_enforcement": 78
},
"security_features": {
"vulnerability_alerts": 95,
"code_scanning": 78,
"secret_scanning": 82,
"secret_scanning_push_protection": 60,
"dependabot_security_updates": 51
}
}
}
All coverage values are percentages (0-100). The security_features_coverage is the average of all five security features.
The scope field records the filters applied during collection. The repositories_coverage percentage indicates what proportion of the organization's repositories were assessed (e.g., 79% means 79% of repos matched the include/exclude filters).
The access_control section provides organization-level security posture:
- two_factor_required: Whether 2FA is enforced for all org members
Note: two_factor_required may be null if the token lacks sufficient permissions (requires admin:org scope for PATs, or Organization Administration permission for GitHub Apps).
SSO Limitation: SSO status is not included in the output because GitHub does not provide a reliable API to detect SAML SSO configuration. The GraphQL samlIdentityProvider field has a known permission bug with GitHub Apps (discussion), and no REST API endpoint returns SSO status.
name: Collect Evidence
on:
schedule:
- cron: "0 0 * * 1" # Weekly on Monday
workflow_dispatch:
jobs:
collect:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install epack
run: |
curl -sSL https://github.com/locktivity/epack/releases/latest/download/epack-linux-amd64 -o epack
chmod +x epack
sudo mv epack /usr/local/bin/
- name: Collect evidence
run: epack collect --frozen
env:
GITHUB_APP_PRIVATE_KEY: ${{ secrets.GITHUB_APP_PRIVATE_KEY }}
- name: Upload pack
uses: actions/upload-artifact@v4
with:
name: evidence-pack
path: "*.pack"
Store the GitHub App private key as a repository secret named GITHUB_APP_PRIVATE_KEY.
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.8...v0.1.9
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.7...v0.1.8
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.6...v0.1.7
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.5...v0.1.6
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.4...v0.1.5
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.3...v0.1.4
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.2...v0.1.3
**Full Changelog**: https://github.com/locktivity/epack-collector-github/compare/v0.1.0...v0.1.1
**Full Changelog**: https://github.com/locktivity/epack-collector-github/commits/v0.1.0