Enforce branch protection rules with scorecards
Branch protection rules are powerful ways to ensure critical branches in your repositories like main
or release
follow security and governance best practices. By tracking these rules with Port's scorecards, platform and security teams can monitor organizational compliance, enforce DevSecOps policies, and ensure consistent engineering standards across all teams.
This guide demonstrates how to track GitHub branch protection settings using Port's scorecards, providing visibility and automation around repository health and security posture.
Common use casesโ
- Drive engineering compliance: Spot missing branch protections and guide teams to fix them.
- Make sure production is safe: Check that every service meets the right rules before it goes live.
Prerequisitesโ
- Install Port's GitHub app in your GitHub organization.
Set up data modelโ
Follow the steps below to create the branch blueprint:
-
Go to your Builder page.
-
Click on
+ Blueprint
. -
Click on the
{...}
button in the top right corner, and chooseEdit JSON
. -
Add this JSON schema:
GitHub Branch Blueprint (Click to expand)
{
"identifier": "branch_protection",
"title": "Branch",
"icon": "Microservice",
"schema": {
"properties": {
"require_approval_count": {
"title": "Require approvals",
"type": "number",
"icon": "DefaultProperty",
"description": "The number of approvals required before merging a pull request"
},
"is_protected": {
"title": "Is branch protected",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Indicates whether certain rules must be met before changes can be merged"
},
"require_code_owner_review": {
"title": "Require code owner review",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Requires review from code owners before a pull request can be merged"
},
"allow_deletions": {
"title": "Allow deletions",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Allows users with bypass permissions to delete matching references in the branch"
},
"allow_force_pushes": {
"title": "Allow force pushes",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Permits users with push access to force push changes to the branch"
},
"url": {
"title": "Branch url",
"type": "string",
"format": "url",
"description": "URL of the branch in the repository"
},
"require_signed_commits": {
"title": "Require signed commits",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Ensures that commits pushed to the branch are signed"
},
"require_linear_history": {
"title": "Require linear history",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Enforces a linear history in the branch by preventing merge commits"
},
"restrict_creations": {
"title": "Restrict creations",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Restricts the creation of matching references in the branch, allowing only users with bypass permissions"
},
"restrict_updates": {
"title": "Restrict updates",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Prevents updates to matching references in the branch, limiting changes to users with bypass permissions"
},
"require_conversation_resolution": {
"title": "Require conversation resolution",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Ensures that all comments and conversations are resolved before merging a pull request"
},
"lock_branch": {
"title": "Lock branch",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Locks the branch, preventing any changes from being made unless explicitly unlocked"
},
"block_force_pushes": {
"title": "Block force pushes",
"type": "boolean",
"icon": "DefaultProperty",
"description": "Prevent users with push access from force pushing to refs"
}
},
"required": []
},
"mirrorProperties": {},
"calculationProperties": {},
"aggregationProperties": {},
"relations": {
"repository": {
"title": "Repository",
"target": "service",
"required": false,
"many": false
}
}
} -
Click
Save
to create the blueprint.
Update GitHub integration configuration
-
Go to your Data Source page.
-
Select the GitHub integration.
-
Add the following YAML block into the
Mapping
editor to ingest the branch protection rules data:GitHub Branch Protection Rules Configuration (Click to expand)
supported branch protection rulesCurrently only default branch protection rules are supported
- kind: branch
selector:
query: '.repository.default_branch == .branch.name'
port:
entity:
mappings:
identifier: .repository.name + "_" + .branch.name
title: .repository.name + " " + .branch.name
blueprint: '"branch_protection"'
properties:
is_protected: .branch.protected
url: .branch._links.html
require_approval_count: >-
.branch.protectionRules.required_pull_request_reviews.required_approving_review_count
require_code_owner_review: >-
.branch.protectionRules.required_pull_request_reviews.require_code_owner_reviews
allow_force_pushes: .branch.protectionRules.allow_force_pushes.enabled
allow_deletions: .branch.protectionRules.allow_deletions.enabled
require_signed_commits: .branch.protectionRules.required_signatures.enabled
require_linear_history: .branch.protectionRules.required_linear_history.enabled
restrict_creations: .branch.protectionRules.block_creations.enabled
restrict_updates: .branch.protectionRules.restrict_updates.enabled
require_conversation_resolution: >-
.branch.protectionRules.required_conversation_resolution.enabled
lock_branch: .branch.protectionRules.lock_branch.enabled
block_force_pushes: .branch.protectionRules.allow_force_pushes.enabled == false
relations:
repository: .repository.name -
Click
Save & Resync
to apply the mapping.
Set up scorecardโ
Let's create a scorecard that will evaluate the health of each repo based on its protection configuration:
-
Go to your Builder page.
-
Search for the Branch blueprint and select it.
-
Click on the
Scorecards
tab. -
Click on
+ New Scorecard
to create a new scorecard. -
Add this JSON configuration:
Protection Metrics Scorecard (click to expand)
[
{
"identifier": "branch_protection",
"title": "Protection Metrics",
"levels": [
{
"color": "paleBlue",
"title": "Basic"
},
{
"color": "darkGray",
"title": "Low"
},
{
"color": "orange",
"title": "Medium"
},
{
"color": "red",
"title": "High"
}
],
"rules": [
{
"identifier": "restrict_create",
"title": "Restrict Creations",
"description": "Prevents unauthorized creation of release branches. Low unless automated CI/CD pipelines are used, then Medium due to a potential software supply chain risk.",
"level": "Low",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "restrict_creations",
"value": true
}
]
}
},
{
"identifier": "restrict_update",
"title": "Restrict Updates",
"description": "Prevents unauthorized changes to important tags or refs. Medium security level as changes could introduce vulnerabilities.",
"level": "Medium",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "restrict_updates",
"value": true
}
]
}
},
{
"identifier": "restrict_delete",
"title": "Restrict Deletions",
"description": "Prevents unauthorized deletions, reducing risks of accidental or malicious data loss. Low security value.",
"level": "Low",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "allow_deletions",
"value": false
}
]
}
},
{
"identifier": "linear_history",
"title": "Require Linear History",
"description": "Enforces a simpler, more auditable code history. Low security value.",
"level": "Low",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "require_linear_history",
"value": true
}
]
}
},
{
"identifier": "signed_commits",
"title": "Require Signed Commits",
"description": "Validates the author of the code with verified signatures to prevent spoofing. Medium security level but with a high effort required.",
"level": "Medium",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "require_signed_commits",
"value": true
}
]
}
},
{
"identifier": "pr_approval",
"title": "Require PR Approval",
"description": "Requires at least 1 approver on a PR before merging, ensuring a minimum change control in place. High security level.",
"level": "High",
"query": {
"combinator": "and",
"conditions": [
{
"operator": ">=",
"property": "require_approval_count",
"value": 1
}
]
}
},
{
"identifier": "code_owner_rev",
"title": "Require Code Owner Review",
"description": "Requires code owner review for PR merges, ensuring only authorized personnel can approve changes. High security level.",
"level": "High",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "require_code_owner_review",
"value": true
}
]
}
},
{
"identifier": "conv_resolution",
"title": "Require Conversation Resolution",
"description": "Ensures all conversations are resolved before merging a PR. Medium security level.",
"level": "Medium",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "require_conversation_resolution",
"value": true
}
]
}
},
{
"identifier": "allow_force_push",
"title": "Allow Force Pushes",
"description": "Allows force pushing, which can overwrite history. High security risk.",
"level": "High",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "allow_force_pushes",
"value": true
}
]
}
},
{
"identifier": "block_force_push",
"title": "Block Force Pushes",
"description": "Prevents force pushing to branches, mitigating the risk of history overwrites. High security level.",
"level": "High",
"query": {
"combinator": "and",
"conditions": [
{
"operator": "=",
"property": "block_force_pushes",
"value": true
}
]
}
}
]
}
] -
Click on
Save
to create the scorecard.
After setting up the scorecard metrics on a branch, it should look like this:
