As GitHub repositories grow across teams and organizations, maintaining consistent repository governance becomes increasingly difficult. Branch protection, pull request requirements, status checks, code review policies, and other controls help teams enforce engineering standards, but simply configuring these policies does not tell you whether they are working effectively.
GitHub rulesets provide a centralized way to define repository governance policies. The next challenge is measuring how those policies are applied, identifying repositories with weaker controls, and detecting situations where expected governance is not being enforced.
This article explains how to approach GitHub ruleset analysis programmatically, build a repository governance inventory with C#, and identify potential policy gaps without relying on manual repository-by-repository inspection.
What Are GitHub Rulesets?
A ruleset defines rules that control how users can interact with selected Git references or repository resources.
For example, an organization might require:
Pull requests before changes reach a protected branch
A minimum number of approvals
Successful status checks
Restrictions on force pushes
Restrictions on branch deletion
Specific repository or team access
Commit or branch naming requirements
A simplified governance model looks like this:
Organization
|
+---- Repository A
| |
| +---- Ruleset
|
+---- Repository B
| |
| +---- Ruleset
|
+---- Repository C
|
+---- RulesetThe important point is that repository governance is not only about creating rules. Security and engineering teams also need to know whether the intended controls are consistently applied.
Why Ruleset Insights Matter
Consider an organization with 200 repositories.
The security team expects every production repository to require:
Pull Request
+
Code Review
+
Required Status ChecksIf one repository has weaker protection, developers may unknowingly bypass an important part of the organization's engineering process.
A governance dashboard can instead provide:
Repositories Checked: 200
Repositories With Rules: 187
Repositories Missing Rules: 13
Repositories With Gaps: 8This turns repository governance into something that can be measured rather than manually assumed.
Understanding Enforcement Status
A ruleset can have an enforcement state that determines whether its rules actively restrict operations.
For governance reporting, distinguish between:
Active
Evaluate
DisabledThe exact states available depend on the GitHub ruleset configuration and API surface being used.
An evaluation-oriented ruleset can be particularly useful during rollout because teams can observe potential impact before enforcing a policy.
This gives organizations a safer migration path:
Create Ruleset
↓
Evaluate
↓
Review Results
↓
Fix Repository Issues
↓
EnforceDesigning a Repository Governance Inventory
The first step in an analytics system is collecting repository metadata and ruleset information.
A C# model can represent the information required by the governance system:
public sealed record RepositoryGovernance(
string Repository,
string Owner,
bool HasRuleset,
string? Enforcement,
int RequiredApprovals,
bool RequiresPullRequest,
bool AllowsForcePush);A collection of these records can then be analyzed.
For example:
var repositories = new List<RepositoryGovernance>
{
new(
"Orders",
"Engineering",
true,
"Active",
2,
true,
false),
new(
"LegacyPortal",
"Engineering",
false,
null,
0,
false,
true)
};The second repository immediately deserves investigation because it has no corresponding governance configuration in this simplified example.
Defining Governance Policies
Do not hard-code every governance requirement directly into reporting code.
Instead, define a policy model:
public sealed record GovernancePolicy(
bool RequirePullRequest,
int MinimumApprovals,
bool RequireStatusChecks,
bool PreventForcePush);For example:
var productionPolicy = new GovernancePolicy(
RequirePullRequest: true,
MinimumApprovals: 2,
RequireStatusChecks: true,
PreventForcePush: true);This makes the analysis reusable.
Different repository categories can have different policies:
Production
↓
Strict Policy
Development
↓
Standard Policy
Experimental
↓
Relaxed PolicyGovernance should reflect risk rather than treating every repository identically.
Detecting Policy Gaps
Once repository configuration has been collected, compare it against the expected policy.
public static List<string> FindGaps(
RepositoryGovernance repository,
GovernancePolicy policy)
{
var gaps = new List<string>();
if (policy.RequirePullRequest &&
!repository.RequiresPullRequest)
{
gaps.Add("Pull request requirement is missing.");
}
if (repository.RequiredApprovals <
policy.MinimumApprovals)
{
gaps.Add("Required approval count is below policy.");
}
if (policy.PreventForcePush &&
repository.AllowsForcePush)
{
gaps.Add("Force pushes are not sufficiently restricted.");
}
return gaps;
}The important design principle is that the application compares actual configuration against an explicit policy.
Without a defined baseline, an analytics system can report configuration but cannot reliably determine whether that configuration is appropriate.
Measuring Governance Coverage
One useful metric is ruleset coverage.
For example:
public static double CalculateCoverage(
IEnumerable<RepositoryGovernance> repositories)
{
var items = repositories.ToList();
if (items.Count == 0)
{
return 0;
}
var protectedCount =
items.Count(repository => repository.HasRuleset);
return (double)protectedCount /
items.Count *
100;
}The result can be displayed as:
Repository Governance Coverage: 93.5%However, coverage alone can be misleading.
A repository having a ruleset does not necessarily mean it satisfies the organization's security requirements.
Therefore, track both:
Ruleset Coverage
+
Policy ComplianceMeasuring Policy Compliance
A better model calculates compliance based on individual requirements.
public sealed record ComplianceResult(
string Repository,
bool Compliant,
IReadOnlyList<string> Gaps);Then:
public static ComplianceResult Evaluate(
RepositoryGovernance repository,
GovernancePolicy policy)
{
var gaps = FindGaps(repository, policy);
return new ComplianceResult(
repository.Repository,
gaps.Count == 0,
gaps);
}This produces more actionable information:
Repository Status Gaps
---------------------------------------------
Orders Compliant None
Payments Non-compliant 1
LegacyPortal Non-compliant 3
Reporting Compliant NoneIdentifying High-Risk Repositories
Not every policy gap represents the same level of risk.
A missing pull-request requirement on a production repository should generally receive more attention than a less critical configuration difference in an experimental repository.
Introduce repository classification:
public enum RepositoryRisk
{
Low,
Medium,
High,
Critical
}Then assign a policy based on repository context:
public static GovernancePolicy GetPolicy(
RepositoryRisk risk)
{
return risk switch
{
RepositoryRisk.Critical =>
new GovernancePolicy(true, 2, true, true),
RepositoryRisk.High =>
new GovernancePolicy(true, 2, true, true),
RepositoryRisk.Medium =>
new GovernancePolicy(true, 1, true, true),
_ =>
new GovernancePolicy(true, 1, false, true)
};
}
Join the conversation! Your thoughts help the community grow.