Skip to content
29 changes: 28 additions & 1 deletion example-data/testorg-unremediated.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,5 +59,32 @@
"secret_scanning_push_protection_custom_link_enabled": false,
"secret_scanning_push_protection_custom_link": null,
"secret_scanning_validity_checks_enabled": false
}
},
"owners": [
{"login": "admin-user-1", "id": 1001},
{"login": "admin-user-2", "id": 1002},
{"login": "admin-user-3", "id": 1003},
{"login": "admin-user-4", "id": 1004},
{"login": "admin-user-5", "id": 1005},
{"login": "admin-user-6", "id": 1006},
{"login": "admin-user-7", "id": 1007}
],
"teams": [],
"sso": {
"enabled": false,
"enforced": false,
"sso_url": "",
"idp_issuer": ""
},
Comment thread
gusfcarvalho marked this conversation as resolved.
"default_security_configs": [
{
"default_for_new_repos": "all",
"configuration": {
"name": "Legacy Security Profile",
"secret_scanning": "disabled",
"dependabot_alerts": "not_set"
}
}
],
"ip_allow_list": []
}
38 changes: 33 additions & 5 deletions example-data/testorg.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,12 @@
"collaborators": 0,
"billing_email": "test@example.com",
"default_repository_permission": "read",
"members_can_create_repositories": true,
"members_can_create_repositories": false,
"two_factor_requirement_enabled": true,
"members_allowed_repository_creation_type": "all",
"members_allowed_repository_creation_type": "none",
"members_can_create_public_repositories": false,
"members_can_create_private_repositories": true,
"members_can_create_internal_repositories": true,
"members_can_create_private_repositories": false,
"members_can_create_internal_repositories": false,
Comment thread
gusfcarvalho marked this conversation as resolved.
"members_can_create_pages": false,
"members_can_fork_private_repositories": false,
"web_commit_signoff_required": true,
Expand All @@ -59,5 +59,33 @@
"secret_scanning_push_protection_custom_link_enabled": true,
"secret_scanning_push_protection_custom_link": null,
"secret_scanning_validity_checks_enabled": true
}
},
"owners": [
{"login": "admin-user-1", "id": 1001},
{"login": "admin-user-2", "id": 1002}
],
"teams": [
{"name": "developers", "privacy": "closed", "description": "Application development team"},
{"name": "security", "privacy": "closed", "description": "Security operations team"}
],
Comment thread
gusfcarvalho marked this conversation as resolved.
Comment thread
gusfcarvalho marked this conversation as resolved.
"sso": {
"enabled": true,
"enforced": true,
"sso_url": "https://sso.example.com/saml/github",
"idp_issuer": "https://sso.example.com"
},
"default_security_configs": [
{
"default_for_new_repos": "all",
"configuration": {
"name": "Baseline Security Profile",
"secret_scanning": "enabled",
"dependabot_alerts": "enabled"
}
}
],
"ip_allow_list": [
{"allow_list_value": "203.0.113.0/24", "is_active": true, "name": "Office Network"},
{"allow_list_value": "198.51.100.0/24", "is_active": true, "name": "VPN"}
]
Comment thread
gusfcarvalho marked this conversation as resolved.
}
57 changes: 57 additions & 0 deletions policies/gh_org_default_repo_permission.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package compliance_framework.default_repo_permission

risk_templates := [
{
"name": "Default repository permission is too permissive",
"title": "Overly Permissive Default Repository Access Grants Excessive Privileges to All Members",
"statement": "The default repository permission setting determines the base access level automatically granted to every organization member on all repositories. Setting this to 'write' or 'admin' means that all organization members, including newly onboarded employees and contractors, receive write or administrative access to every repository by default. This violates the principle of least privilege and can lead to unauthorized modifications, accidental data loss, or privilege escalation if any member account is compromised. The default should be 'read' or 'none', with elevated access granted explicitly via team membership.",
"likelihood_hint": "moderate",
"impact_hint": "high",
"violation_ids": ["default_permission_too_permissive"],
"threat_refs": [
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-269",
"title": "Improper Privilege Management",
"url": "https://cwe.mitre.org/data/definitions/269.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-284",
"title": "Improper Access Control",
"url": "https://cwe.mitre.org/data/definitions/284.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-732",
"title": "Incorrect Permission Assignment for Critical Resource",
"url": "https://cwe.mitre.org/data/definitions/732.html"
}
],
"remediation": {
"title": "Set the default repository permission to 'read' or 'none'",
"description": "Configure the organization's default repository permission to 'read' or 'none'. Grant write and admin access explicitly via team membership to specific repositories, following the principle of least privilege.",
"tasks": [
{ "title": "Navigate to Organization Settings > Member privileges > Base permissions" },
{ "title": "Change the base permission to 'Read' or 'No permission'" },
{ "title": "Review all repositories to ensure teams have explicit access grants where write access is required" },
{ "title": "Communicate the change to all members and update onboarding documentation" },
{ "title": "Audit existing repositories for any direct-user write grants that should be team-based" }
]
}
}
]

_settings := object.get(input, "settings", {})

_default_repository_permission := object.get(_settings, "default_repository_permission", "")

_allowed_permissions := {"read", "none"}

violation[{"id": "default_permission_too_permissive"}] if {
not _allowed_permissions[_default_repository_permission]
}

title := "Default repository permission is set to 'read' or 'none'"
description := "The organization's default repository permission must not grant write or admin access to all members by default. Elevated access should be granted explicitly via team membership to follow the principle of least privilege."
remarks := "More information: https://docs.github.com/en/organizations/managing-user-access-to-your-organizations-repositories/managing-repository-roles/setting-base-permissions-for-an-organization"
37 changes: 37 additions & 0 deletions policies/gh_org_default_repo_permission_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package compliance_framework.default_repo_permission

test_default_permission_read if {
count(violation) == 0 with input as {
"settings": {
"default_repository_permission": "read"
}
}
}

test_default_permission_none if {
count(violation) == 0 with input as {
"settings": {
"default_repository_permission": "none"
}
}
}

test_default_permission_write if {
count(violation) > 0 with input as {
"settings": {
"default_repository_permission": "write"
}
}
}

test_default_permission_admin if {
count(violation) > 0 with input as {
"settings": {
"default_repository_permission": "admin"
}
}
}

test_default_permission_missing if {
count(violation) > 0 with input as {}
}
53 changes: 53 additions & 0 deletions policies/gh_org_ip_allowlist_enabled.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package compliance_framework.ip_allowlist_enabled

risk_templates := [
{
"name": "No IP allow-list configured for the organization",
"title": "Absence of IP Allow-List Exposes GitHub Resources to Access from Untrusted Networks",
"statement": "Without an IP allow-list, the GitHub organization's resources (repositories, API, settings) are accessible from any IP address on the internet, subject only to authentication. This means that even valid credentials used from untrusted networks (e.g., compromised endpoints, attacker infrastructure) can interact with the organization's assets. Configuring an IP allow-list restricts access to approved network ranges, adding a network-layer control that limits the blast radius of credential compromise.",
"likelihood_hint": "moderate",
"impact_hint": "high",
"violation_ids": ["ip_allowlist_not_configured"],
"threat_refs": [
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-284",
"title": "Improper Access Control",
"url": "https://cwe.mitre.org/data/definitions/284.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-923",
"title": "Improper Restriction of Communication Channel to Intended Endpoints",
"url": "https://cwe.mitre.org/data/definitions/923.html"
}
],
"remediation": {
"title": "Configure an IP allow-list for the GitHub organization",
"description": "Enable the IP allow-list feature for the organization and add the approved IP ranges from which members are permitted to access GitHub. This restricts access to known, trusted networks and reduces the risk of credential-based attacks from untrusted locations.",
"tasks": [
{ "title": "Navigate to Organization Settings > Security > IP allow list" },
{ "title": "Enable 'IP allow list'" },
{ "title": "Add approved IP ranges for corporate offices, VPNs, and CI/CD infrastructure" },
{ "title": "Test that members can still access GitHub from approved networks before fully enforcing" },
{ "title": "Document the process for requesting additions to the IP allow-list" },
{ "title": "Schedule periodic review of the IP allow-list to remove stale entries" }
]
}
}
]

_ip_allow_list := object.get(input, "ip_allow_list", [])

_has_active_entry if {
some entry in _ip_allow_list
entry.is_active == true
}

violation[{"id": "ip_allowlist_not_configured"}] if {
not _has_active_entry
}

title := "Organization has an active IP allow-list configured"
description := "The GitHub organization must have at least one active IP allow-list entry to restrict access to approved network ranges and reduce the risk of access from untrusted locations."
remarks := "More information: https://docs.github.com/en/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/managing-allowed-ip-addresses-for-your-organization"
29 changes: 29 additions & 0 deletions policies/gh_org_ip_allowlist_enabled_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package compliance_framework.ip_allowlist_enabled

test_ip_allowlist_configured if {
count(violation) == 0 with input as {
"ip_allow_list": [
{"allow_list_value": "203.0.113.0/24", "is_active": true, "name": "Office"},
{"allow_list_value": "198.51.100.0/24", "is_active": false, "name": "Old VPN"}
]
}
}

test_ip_allowlist_all_inactive if {
count(violation) > 0 with input as {
"ip_allow_list": [
{"allow_list_value": "203.0.113.0/24", "is_active": false, "name": "Disabled"},
{"allow_list_value": "198.51.100.0/24", "is_active": false, "name": "Also Disabled"}
]
}
}

test_ip_allowlist_empty if {
count(violation) > 0 with input as {
"ip_allow_list": []
}
}
Comment thread
gusfcarvalho marked this conversation as resolved.

test_ip_allowlist_missing if {
count(violation) > 0 with input as {}
}
49 changes: 49 additions & 0 deletions policies/gh_org_members_can_create_repos.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package compliance_framework.members_can_create_repos

risk_templates := [
{
"name": "Organization members can create repositories without restriction",
"title": "Unrestricted Repository Creation Undermines Access Governance",
"statement": "When all organization members are permitted to create repositories, the organization loses control over its asset inventory. Members may inadvertently expose internal code via public repositories, create repositories that bypass security baselines, or accumulate ungoverned codebases. Restricting repository creation to administrators ensures that new repositories are intentional, properly configured, and subject to security review before use.",
"likelihood_hint": "moderate",
"impact_hint": "high",
"violation_ids": ["members_can_create_repos"],
"threat_refs": [
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-284",
"title": "Improper Access Control",
"url": "https://cwe.mitre.org/data/definitions/284.html"
},
{
"system": "https://cwe.mitre.org",
"external_id": "CWE-200",
"title": "Exposure of Sensitive Information to an Unauthorized Actor",
"url": "https://cwe.mitre.org/data/definitions/200.html"
}
],
"remediation": {
"title": "Restrict repository creation to organization administrators",
"description": "Disable the ability for regular organization members to create new repositories. Only administrators should be permitted to create repositories, ensuring each new repository is intentionally provisioned and subject to organizational security baselines.",
"tasks": [
{ "title": "Navigate to Organization Settings > Member privileges" },
{ "title": "Review the Repository creation section for member repository creation settings" },
{ "title": "Disable 'Allow members to create repositories' or restrict repository creation to administrators" },
{ "title": "Review and archive any repositories created without administrative approval" },
{ "title": "Document a repository provisioning process that routes requests through an administrator" }
]
}
}
]

_settings := object.get(input, "settings", {})

_members_can_create_repositories := object.get(_settings, "members_can_create_repositories", true)

violation[{"id": "members_can_create_repos"}] if {
_members_can_create_repositories
}

title := "Organization members cannot create repositories"
description := "Repository creation should be restricted to administrators to maintain control over the organization's code asset inventory and prevent ungoverned or accidentally public repositories."
remarks := "More information: https://docs.github.com/en/organizations/managing-organization-settings/restricting-repository-creation-in-your-organization"
21 changes: 21 additions & 0 deletions policies/gh_org_members_can_create_repos_test.rego
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package compliance_framework.members_can_create_repos

test_members_cannot_create_repos if {
count(violation) == 0 with input as {
"settings": {
"members_can_create_repositories": false
}
}
}

test_members_can_create_repos if {
count(violation) > 0 with input as {
"settings": {
"members_can_create_repositories": true
}
}
}

test_members_create_repos_missing if {
count(violation) > 0 with input as {}
}
Loading
Loading