Skip to content

Commit eef13a1

Browse files
authored
feat: add more policies for better compliance posture for SOC2 (#9)
* feat: add more policies for better compliance posture for SOC2 fix: support new format for dependabot and secret scanning policies Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: forgot to add files after rename Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> * fix: copilot issues Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com> --------- Signed-off-by: Gustavo Carvalho <gustavo.carvalho@container-solutions.com>
1 parent 779f129 commit eef13a1

20 files changed

Lines changed: 985 additions & 45 deletions

example-data/testorg-unremediated.json

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,32 @@
5959
"secret_scanning_push_protection_custom_link_enabled": false,
6060
"secret_scanning_push_protection_custom_link": null,
6161
"secret_scanning_validity_checks_enabled": false
62-
}
62+
},
63+
"owners": [
64+
{"login": "admin-user-1", "id": 1001},
65+
{"login": "admin-user-2", "id": 1002},
66+
{"login": "admin-user-3", "id": 1003},
67+
{"login": "admin-user-4", "id": 1004},
68+
{"login": "admin-user-5", "id": 1005},
69+
{"login": "admin-user-6", "id": 1006},
70+
{"login": "admin-user-7", "id": 1007}
71+
],
72+
"teams": [],
73+
"sso": {
74+
"enabled": false,
75+
"enforced": false,
76+
"sso_url": "",
77+
"idp_issuer": ""
78+
},
79+
"default_security_configs": [
80+
{
81+
"default_for_new_repos": "all",
82+
"configuration": {
83+
"name": "Legacy Security Profile",
84+
"secret_scanning": "disabled",
85+
"dependabot_alerts": "not_set"
86+
}
87+
}
88+
],
89+
"ip_allow_list": []
6390
}

example-data/testorg.json

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@
3131
"collaborators": 0,
3232
"billing_email": "test@example.com",
3333
"default_repository_permission": "read",
34-
"members_can_create_repositories": true,
34+
"members_can_create_repositories": false,
3535
"two_factor_requirement_enabled": true,
36-
"members_allowed_repository_creation_type": "all",
36+
"members_allowed_repository_creation_type": "none",
3737
"members_can_create_public_repositories": false,
38-
"members_can_create_private_repositories": true,
39-
"members_can_create_internal_repositories": true,
38+
"members_can_create_private_repositories": false,
39+
"members_can_create_internal_repositories": false,
4040
"members_can_create_pages": false,
4141
"members_can_fork_private_repositories": false,
4242
"web_commit_signoff_required": true,
@@ -59,5 +59,33 @@
5959
"secret_scanning_push_protection_custom_link_enabled": true,
6060
"secret_scanning_push_protection_custom_link": null,
6161
"secret_scanning_validity_checks_enabled": true
62-
}
62+
},
63+
"owners": [
64+
{"login": "admin-user-1", "id": 1001},
65+
{"login": "admin-user-2", "id": 1002}
66+
],
67+
"teams": [
68+
{"name": "developers", "privacy": "closed", "description": "Application development team"},
69+
{"name": "security", "privacy": "closed", "description": "Security operations team"}
70+
],
71+
"sso": {
72+
"enabled": true,
73+
"enforced": true,
74+
"sso_url": "https://sso.example.com/saml/github",
75+
"idp_issuer": "https://sso.example.com"
76+
},
77+
"default_security_configs": [
78+
{
79+
"default_for_new_repos": "all",
80+
"configuration": {
81+
"name": "Baseline Security Profile",
82+
"secret_scanning": "enabled",
83+
"dependabot_alerts": "enabled"
84+
}
85+
}
86+
],
87+
"ip_allow_list": [
88+
{"allow_list_value": "203.0.113.0/24", "is_active": true, "name": "Office Network"},
89+
{"allow_list_value": "198.51.100.0/24", "is_active": true, "name": "VPN"}
90+
]
6391
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
package compliance_framework.default_repo_permission
2+
3+
risk_templates := [
4+
{
5+
"name": "Default repository permission is too permissive",
6+
"title": "Overly Permissive Default Repository Access Grants Excessive Privileges to All Members",
7+
"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.",
8+
"likelihood_hint": "moderate",
9+
"impact_hint": "high",
10+
"violation_ids": ["default_permission_too_permissive"],
11+
"threat_refs": [
12+
{
13+
"system": "https://cwe.mitre.org",
14+
"external_id": "CWE-269",
15+
"title": "Improper Privilege Management",
16+
"url": "https://cwe.mitre.org/data/definitions/269.html"
17+
},
18+
{
19+
"system": "https://cwe.mitre.org",
20+
"external_id": "CWE-284",
21+
"title": "Improper Access Control",
22+
"url": "https://cwe.mitre.org/data/definitions/284.html"
23+
},
24+
{
25+
"system": "https://cwe.mitre.org",
26+
"external_id": "CWE-732",
27+
"title": "Incorrect Permission Assignment for Critical Resource",
28+
"url": "https://cwe.mitre.org/data/definitions/732.html"
29+
}
30+
],
31+
"remediation": {
32+
"title": "Set the default repository permission to 'read' or 'none'",
33+
"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.",
34+
"tasks": [
35+
{ "title": "Navigate to Organization Settings > Member privileges > Base permissions" },
36+
{ "title": "Change the base permission to 'Read' or 'No permission'" },
37+
{ "title": "Review all repositories to ensure teams have explicit access grants where write access is required" },
38+
{ "title": "Communicate the change to all members and update onboarding documentation" },
39+
{ "title": "Audit existing repositories for any direct-user write grants that should be team-based" }
40+
]
41+
}
42+
}
43+
]
44+
45+
_settings := object.get(input, "settings", {})
46+
47+
_default_repository_permission := object.get(_settings, "default_repository_permission", "")
48+
49+
_allowed_permissions := {"read", "none"}
50+
51+
violation[{"id": "default_permission_too_permissive"}] if {
52+
not _allowed_permissions[_default_repository_permission]
53+
}
54+
55+
title := "Default repository permission is set to 'read' or 'none'"
56+
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."
57+
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"
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package compliance_framework.default_repo_permission
2+
3+
test_default_permission_read if {
4+
count(violation) == 0 with input as {
5+
"settings": {
6+
"default_repository_permission": "read"
7+
}
8+
}
9+
}
10+
11+
test_default_permission_none if {
12+
count(violation) == 0 with input as {
13+
"settings": {
14+
"default_repository_permission": "none"
15+
}
16+
}
17+
}
18+
19+
test_default_permission_write if {
20+
count(violation) > 0 with input as {
21+
"settings": {
22+
"default_repository_permission": "write"
23+
}
24+
}
25+
}
26+
27+
test_default_permission_admin if {
28+
count(violation) > 0 with input as {
29+
"settings": {
30+
"default_repository_permission": "admin"
31+
}
32+
}
33+
}
34+
35+
test_default_permission_missing if {
36+
count(violation) > 0 with input as {}
37+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package compliance_framework.ip_allowlist_enabled
2+
3+
risk_templates := [
4+
{
5+
"name": "No IP allow-list configured for the organization",
6+
"title": "Absence of IP Allow-List Exposes GitHub Resources to Access from Untrusted Networks",
7+
"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.",
8+
"likelihood_hint": "moderate",
9+
"impact_hint": "high",
10+
"violation_ids": ["ip_allowlist_not_configured"],
11+
"threat_refs": [
12+
{
13+
"system": "https://cwe.mitre.org",
14+
"external_id": "CWE-284",
15+
"title": "Improper Access Control",
16+
"url": "https://cwe.mitre.org/data/definitions/284.html"
17+
},
18+
{
19+
"system": "https://cwe.mitre.org",
20+
"external_id": "CWE-923",
21+
"title": "Improper Restriction of Communication Channel to Intended Endpoints",
22+
"url": "https://cwe.mitre.org/data/definitions/923.html"
23+
}
24+
],
25+
"remediation": {
26+
"title": "Configure an IP allow-list for the GitHub organization",
27+
"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.",
28+
"tasks": [
29+
{ "title": "Navigate to Organization Settings > Security > IP allow list" },
30+
{ "title": "Enable 'IP allow list'" },
31+
{ "title": "Add approved IP ranges for corporate offices, VPNs, and CI/CD infrastructure" },
32+
{ "title": "Test that members can still access GitHub from approved networks before fully enforcing" },
33+
{ "title": "Document the process for requesting additions to the IP allow-list" },
34+
{ "title": "Schedule periodic review of the IP allow-list to remove stale entries" }
35+
]
36+
}
37+
}
38+
]
39+
40+
_ip_allow_list := object.get(input, "ip_allow_list", [])
41+
42+
_has_active_entry if {
43+
some entry in _ip_allow_list
44+
entry.is_active == true
45+
}
46+
47+
violation[{"id": "ip_allowlist_not_configured"}] if {
48+
not _has_active_entry
49+
}
50+
51+
title := "Organization has an active IP allow-list configured"
52+
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."
53+
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"
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package compliance_framework.ip_allowlist_enabled
2+
3+
test_ip_allowlist_configured if {
4+
count(violation) == 0 with input as {
5+
"ip_allow_list": [
6+
{"allow_list_value": "203.0.113.0/24", "is_active": true, "name": "Office"},
7+
{"allow_list_value": "198.51.100.0/24", "is_active": false, "name": "Old VPN"}
8+
]
9+
}
10+
}
11+
12+
test_ip_allowlist_all_inactive if {
13+
count(violation) > 0 with input as {
14+
"ip_allow_list": [
15+
{"allow_list_value": "203.0.113.0/24", "is_active": false, "name": "Disabled"},
16+
{"allow_list_value": "198.51.100.0/24", "is_active": false, "name": "Also Disabled"}
17+
]
18+
}
19+
}
20+
21+
test_ip_allowlist_empty if {
22+
count(violation) > 0 with input as {
23+
"ip_allow_list": []
24+
}
25+
}
26+
27+
test_ip_allowlist_missing if {
28+
count(violation) > 0 with input as {}
29+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package compliance_framework.members_can_create_repos
2+
3+
risk_templates := [
4+
{
5+
"name": "Organization members can create repositories without restriction",
6+
"title": "Unrestricted Repository Creation Undermines Access Governance",
7+
"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.",
8+
"likelihood_hint": "moderate",
9+
"impact_hint": "high",
10+
"violation_ids": ["members_can_create_repos"],
11+
"threat_refs": [
12+
{
13+
"system": "https://cwe.mitre.org",
14+
"external_id": "CWE-284",
15+
"title": "Improper Access Control",
16+
"url": "https://cwe.mitre.org/data/definitions/284.html"
17+
},
18+
{
19+
"system": "https://cwe.mitre.org",
20+
"external_id": "CWE-200",
21+
"title": "Exposure of Sensitive Information to an Unauthorized Actor",
22+
"url": "https://cwe.mitre.org/data/definitions/200.html"
23+
}
24+
],
25+
"remediation": {
26+
"title": "Restrict repository creation to organization administrators",
27+
"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.",
28+
"tasks": [
29+
{ "title": "Navigate to Organization Settings > Member privileges" },
30+
{ "title": "Review the Repository creation section for member repository creation settings" },
31+
{ "title": "Disable 'Allow members to create repositories' or restrict repository creation to administrators" },
32+
{ "title": "Review and archive any repositories created without administrative approval" },
33+
{ "title": "Document a repository provisioning process that routes requests through an administrator" }
34+
]
35+
}
36+
}
37+
]
38+
39+
_settings := object.get(input, "settings", {})
40+
41+
_members_can_create_repositories := object.get(_settings, "members_can_create_repositories", true)
42+
43+
violation[{"id": "members_can_create_repos"}] if {
44+
_members_can_create_repositories
45+
}
46+
47+
title := "Organization members cannot create repositories"
48+
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."
49+
remarks := "More information: https://docs.github.com/en/organizations/managing-organization-settings/restricting-repository-creation-in-your-organization"
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package compliance_framework.members_can_create_repos
2+
3+
test_members_cannot_create_repos if {
4+
count(violation) == 0 with input as {
5+
"settings": {
6+
"members_can_create_repositories": false
7+
}
8+
}
9+
}
10+
11+
test_members_can_create_repos if {
12+
count(violation) > 0 with input as {
13+
"settings": {
14+
"members_can_create_repositories": true
15+
}
16+
}
17+
}
18+
19+
test_members_create_repos_missing if {
20+
count(violation) > 0 with input as {}
21+
}

0 commit comments

Comments
 (0)