GitHub Collector
Automatically collect GitHub repository settings, branch protection rules, and access permissions. Enforce VCS standards across your organization.
github to your lunar-config.yml:uses: github://earthly/lunar-lib/collectors/github@v1.0.5
What This Integration Collects
This integration includes 5 collectors that gather metadata from your systems.
pull-request
Fetches pull-request metadata from the GitHub API for the PR being evaluated and writes it under .vcs.pr — title, description, source and target branch, author, labels, draft flag, state, URL, number and head SHA, plus the reviews submitted so far (reviewer, state, time, and the commit each was made on) and the PR's commits with GitHub's signature verification. This is the GitHub source of .vcs.pr.* that the ticket collectors (jira, linear) read via their after-json variants, so ticket and change-management checks work without each ticket collector calling the GitHub API itself. Runs only in PR context.
repository
Fetches basic repository settings from the GitHub API including visibility (public/private/internal), default branch name, topics, and allowed merge strategies (merge commit, squash, rebase). Writes to .vcs.provider, .vcs.visibility, .vcs.default_branch, .vcs.topics, and .vcs.merge_strategies.
branch-protection
Fetches branch protection rules for the default branch from the GitHub API. Detects both classic branch protection and the newer rulesets, normalizing the wire formats into a single .vcs.branch_protection shape with a .source field of "classic", "ruleset", or "none". Collects required approvals, code owner review, dismiss stale reviews, required status checks, force push/deletion restrictions, linear history requirements, signed commit requirements, and (classic only) push restrictions (users, teams, apps). Also lists every ruleset with an active rule on the branch, with its bypass actors when the token can see them, and (classic only) whether administrators can bypass and who may bypass the pull-request requirement.
access-permissions
Fetches repository access permissions from the GitHub API with pagination support. Collects direct collaborators (login, permission level, type) and teams with access (slug, name, permission). Does not expand team memberships for performance. Writes to .vcs.access.collaborators and .vcs.access.teams.
release-range
Opt-in: does nothing until release_tag_pattern is set. On the default
branch, lists the commits since the previous release tag (the tag
matching the pattern with the fewest commits ahead of it) and records
each one's signature verification and the merged pull request that
brought it in, with that PR's approvals, under .vcs.release_range.
Feeds the vcs policy's release-commits-merged-via-pr check, which
lunar policy ok-release can gate on.
How Collectors Fit into Lunar
Lunar watches your code and CI/CD systems to collect SDLC data from config files, test results, IaC, deployment configurations, security scans, and more.
Collectors are the automatic data-gathering layer. They extract structured metadata from your repositories and pipelines, feeding it into Lunar's centralized database where guardrails evaluate it to enforce your engineering standards.
Learn How Lunar Works →Example Collected Data
This collector writes structured metadata to the Component JSON. Here's an example of the data it produces:
{
"vcs": {
"provider": "github",
"default_branch": "main",
"visibility": "private",
"topics": ["backend", "api", "microservice"],
"merge_strategies": {
"allow_merge_commit": true,
"allow_squash_merge": true,
"allow_rebase_merge": false
},
"pr": {
"number": 123,
"title": "[ABC-456] Add payment validation",
"description": "Implements server-side validation. Closes ABC-456.",
"url": "https://github.com/acme/payments/pull/123",
"source_branch": "abc-456-payment-validation",
"target_branch": "main",
"author": "jdoe",
"labels": ["enhancement", "payments"],
"draft": false,
"state": "open",
"head_sha": "9f1c2e7d4b8a6f3e0c5d2b1a7e4f8c3d6b9a0e21",
"reviews": [
{
"reviewer": "alice",
"state": "CHANGES_REQUESTED",
"submitted_at": "2024-05-02T09:14:07Z",
"commit_sha": "4b7e1d9c2a5f8e3b6d0c9a1f7e2d5b8c4a3f6e19"
},
{
"reviewer": "alice",
"state": "APPROVED",
"submitted_at": "2024-05-02T15:40:51Z",
"commit_sha": "9f1c2e7d4b8a6f3e0c5d2b1a7e4f8c3d6b9a0e21"
}
],
"commits": [
{
"sha": "4b7e1d9c2a5f8e3b6d0c9a1f7e2d5b8c4a3f6e19",
"author": "jdoe",
"signature": {"verified": true, "reason": "valid"}
},
{
"sha": "9f1c2e7d4b8a6f3e0c5d2b1a7e4f8c3d6b9a0e21",
"author": "jdoe",
"signature": {"verified": false, "reason": "unsigned"}
}
]
},
"branch_protection": {
"enabled": true,
"source": "classic",
"branch": "main",
"require_pr": true,
"required_approvals": 2,
"require_codeowner_review": true,
"dismiss_stale_reviews": true,
"require_status_checks": true,
"required_checks": ["ci/build", "ci/test", "security/scan"],
"require_branches_up_to_date": true,
"allow_force_push": false,
"allow_deletions": false,
"require_linear_history": false,
"require_signed_commits": true,
"restrictions": {
"users": ["deployment-bot"],
"teams": ["platform-team"],
"apps": ["github-actions"]
},
"enforce_admins": false,
"bypass_pull_request_allowances": {
"users": [],
"teams": [],
"apps": ["release-bot"]
},
"rulesets": [
{
"id": 1234567,
"name": "main",
"source_type": "Repository",
"source": "acme/payments",
"bypass_actors": [
{"actor_type": "OrganizationAdmin", "bypass_mode": "always"},
{"actor_type": "Integration", "actor_id": 98765, "bypass_mode": "always"}
]
},
{
"id": 7654321,
"name": "org-baseline",
"source_type": "Organization",
"source": "acme"
}
]
},
"release_range": {
"tag_pattern": "^v[0-9]+\\.[0-9]+\\.[0-9]+$",
"head_sha": "c3e8a1f6d9b2e5a7c0f4d8b1e6a3c9f2d5b7e0a4",
"default_branch": "main",
"base": {"tag": "v2.3.0", "sha": "e1d4b7a0c3f6e9d2b5a8c1f4e7d0b3a6c9f2e5d8"},
"total_commits": 2,
"truncated": false,
"commits": [
{
"sha": "a7c0f3e6d9b2a5c8f1e4d7b0a3c6f9e2d5b8a1c4",
"author": "jdoe",
"signature": {"verified": true, "reason": "valid"},
"pull_request": {
"number": 123,
"base_branch": "main",
"head_branch": "abc-456-payment-validation",
"merged_at": "2024-05-02T16:02:13Z",
"merged_by": "jdoe",
"head_sha": "9f1c2e7d4b8a6f3e0c5d2b1a7e4f8c3d6b9a0e21",
"approvals": [
{
"reviewer": "alice",
"submitted_at": "2024-05-02T15:40:51Z",
"commit_sha": "9f1c2e7d4b8a6f3e0c5d2b1a7e4f8c3d6b9a0e21"
}
]
}
},
{
"sha": "c3e8a1f6d9b2e5a7c0f4d8b1e6a3c9f2d5b7e0a4",
"author": "github-actions[bot]",
"signature": {"verified": false, "reason": "unsigned"}
}
]
},
"access": {
"collaborators": [
{
"login": "alice",
"permission": "admin",
"type": "User"
},
{
"login": "deployment-bot",
"permission": "write",
"type": "Bot"
}
],
"teams": [
{"slug": "backend-team", "name": "Backend Team", "permission": "write"},
{"slug": "platform-team", "name": "Platform Team", "permission": "admin"}
]
}
}
}
Configuration
Configure this collector in your lunar-config.yml.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
release_tag_pattern
|
Required | — | Regular expression matching the tags that mark a release, e.g. `^v[0-9]+\.[0-9]+\.[0-9]+$`. The release-range sub-collector does nothing while this is empty. |
release_range_max_commits
|
Optional |
250
|
Most commits the release-range sub-collector records, up to the 1000 GitHub lists for a comparison; a longer range is recorded with `truncated` set. |
Secrets
This collector requires the following secrets to be configured in Lunar:
| Secret | Description |
|---|---|
GH_TOKEN
|
GitHub personal access token with `repo` scope for API authentication |
Documentation
View on GitHubGitHub Collector
Collects GitHub repository settings and branch protection rules via the GitHub API.
Overview
This collector queries the GitHub API to gather version control system (VCS) configuration data including repository visibility, default branch, topics, merge strategies, branch protection rules and rulesets with their bypass actors, and access permissions for direct collaborators and teams. In PR context it also collects pull-request metadata, reviews and commit signatures (.vcs.pr). The opt-in release-range collector records, on the default branch, the commits since the previous release tag and the merged pull request behind each one. It requires the LUNAR_SECRET_GH_TOKEN environment variable for API authentication.
Collected Data
This collector writes to the following Component JSON paths:
| Path | Type | Description |
|---|---|---|
.vcs.provider |
string | VCS provider name (always "github") |
.vcs.default_branch |
string | Default branch name (e.g., "main", "master") |
.vcs.visibility |
string | Repository visibility (public, private, internal) |
.vcs.topics |
array | Repository topics/tags |
.vcs.merge_strategies |
object | Allowed merge strategies for pull requests |
.vcs.branch_protection |
object | Branch protection rules and restrictions |
.vcs.access |
object | Repository access permissions for users and teams |
.vcs.pr |
object | Pull-request metadata (populated only in PR context) |
.vcs.release_range |
object | Commits since the previous release tag (opt-in, default branch only) |
Pull-request fields (.vcs.pr)
| Path | Type | Description |
|---|---|---|
.vcs.pr.number |
number | Pull-request number |
.vcs.pr.title |
string | PR title (source for ticket-ID extraction) |
.vcs.pr.description |
string | PR body |
.vcs.pr.url |
string | Web URL of the pull request |
.vcs.pr.source_branch |
string | Head branch name |
.vcs.pr.target_branch |
string | Base branch name |
.vcs.pr.author |
string | Author login |
.vcs.pr.labels |
array | PR label names |
.vcs.pr.draft |
boolean | Whether the PR is a draft |
.vcs.pr.state |
string | PR state (open, closed, merged) |
.vcs.pr.head_sha |
string | Head commit of the PR |
.vcs.pr.reviews[] |
array | Submitted reviews, oldest first: reviewer, state (APPROVED, CHANGES_REQUESTED, COMMENTED, DISMISSED), submitted_at, commit_sha |
.vcs.pr.commits[] |
array | The PR's commits: sha, author, signature.verified, signature.reason (GitHub's verification reason, e.g. valid, unsigned) |
Collection runs on pushes to the PR, not on review events, so .vcs.pr.reviews holds the reviews submitted before the last push. The approvals a PR had when it merged are recorded on the default-branch commit by release-range. .vcs.pr.commits is omitted for a PR with more than 250 commits, the most GitHub lists.
Bypass fields (.vcs.branch_protection)
| Path | Type | Description |
|---|---|---|
.vcs.branch_protection.rulesets[] |
array | Every ruleset with an active rule on the default branch: id, name, source_type, source, bypass_actors[] (actor_type, actor_id, bypass_mode) |
.vcs.branch_protection.enforce_admins |
boolean | Classic only: administrators are held to the rules ("Do not allow bypassing the above settings") |
.vcs.branch_protection.bypass_pull_request_allowances |
object | Classic only: users, teams and apps allowed to bypass the pull-request requirement |
GitHub returns a ruleset's bypass_actors only to a caller with write access to that ruleset, so the key is omitted when the token cannot see it and is [] only when the list is empty. actor_id is absent for OrganizationAdmin and DeployKey.
Release range (.vcs.release_range)
Written only when release_tag_pattern is set. The previous release is the tag matching the pattern that leaves the fewest commits ahead of it, so release tags cut on a release branch work.
| Path | Type | Description |
|---|---|---|
.vcs.release_range.tag_pattern |
string | The pattern used |
.vcs.release_range.head_sha |
string | The commit being evaluated |
.vcs.release_range.base |
object | The previous release: tag, sha. Absent when no matching tag precedes the commit |
.vcs.release_range.default_branch |
string | The repository's default branch |
.vcs.release_range.total_commits |
number | Commits in the range |
.vcs.release_range.truncated |
boolean | Not every commit was recorded: the range is longer than release_range_max_commits, or than the 1000 commits GitHub lists for a comparison |
.vcs.release_range.commits[] |
array | Oldest first (for a range over 1000 commits, the oldest of the newest 1000): sha, author, signature, and pull_request (number, base_branch, head_branch, merged_at, merged_by, head_sha, approvals[]) when GitHub associates the commit with a merged PR. A PR into the default branch is preferred; a gitflow feature commit is linked only to its PR into develop |
Collectors
This plugin provides the following collectors (use include to select a subset):
| Collector | Description |
|---|---|
pull-request |
Collects pull-request metadata (.vcs.pr) in PR context — title, description, branches, author, labels, draft, state, URL, head SHA, reviews, and the PR's commits with signature verification. This is the GitHub source of .vcs.pr.* that the ticket collectors read via their after-json variants. |
repository |
Collects basic repository settings including visibility, default branch, topics, and allowed merge strategies |
branch-protection |
Collects branch protection rules from classic branch protection or rulesets (whichever is configured), including required approvals, status checks, force push restrictions, commit signing requirements, and push access restrictions. The source field on .vcs.branch_protection records which mechanism was detected ("classic", "ruleset", or "none"). Also lists the rulesets on the branch with their bypass actors. |
access-permissions |
Collects repository access permissions including direct collaborators and teams (does not expand team memberships) |
release-range |
Opt-in (release_tag_pattern). On the default branch, records the commits since the previous release tag, each with its signature verification and the merged pull request that brought it in, with that PR's approvals. |
Installation
Add to your lunar-config.yml:
collectors:
- uses: github://earthly/lunar-lib/collectors/github@v1.0.0
on: ["domain:your-domain"] # Or use tags like [backend, kubernetes]
include:
- pull-request # PR metadata
- repository # Repository settings
- branch-protection # Branch protection rules
- access-permissions # Collaborators and teams
- release-range # Commits since the last release (needs release_tag_pattern)
# with:
# release_tag_pattern: '^v[0-9]+\.[0-9]+\.[0-9]+$' # enables release-range
Open Source
This collector is open source and available on GitHub. Contribute improvements, report issues, or fork it for your own use.
Common Use Cases
Explore guardrails that use data from GitHub Collector.
Ready to Automate Your Standards?
See how Lunar can turn your AGENTS.md, engineering wiki, compliance docs, or postmortem action items into automated guardrails with our 300+ built-in guardrails.