From 72b5bd337baf235ee65881ae21638cb2a6b04f21 Mon Sep 17 00:00:00 2001 From: Anders Eknert Date: Tue, 31 Oct 2023 14:31:16 +0100 Subject: [PATCH] policy: Add Regal for linting Rego (#257) This PR introduces [Regal](https://github.com/styrainc/regal) for linting the Rego files of the project. The Rego found here is generally in a good shape, so only a few rules have been either ignored or fixed. The few rules fixed include: * [rule-shadows-builtin](https://docs.styra.com/regal/rules/bugs/rule-shadows-builtin) as there is already an `is_null` function in the standard lib * [custom-has-key-construct](https://docs.styra.com/regal/rules/idiomatic/custom-has-key-construct) as this is handled by `object.keys` and `in` in modern Rego * [use-assignment-operator](https://docs.styra.com/regal/rules/style/use-assignment-operator) as `:=` is preferred over `=` for rule assignment, and using this does not change the semantics of the code in any way. Included is also a new job for checking/linting Rego code as part of CI. Signed-off-by: Anders Eknert --- .github/workflows/build_and_test.yaml | 13 +++ .regal/config.yaml | 23 +++++ policies/github/actions.rego | 16 ++-- policies/github/common/webhooks.rego | 10 +- policies/github/enterprise.rego | 46 ++++----- policies/github/member.rego | 8 +- policies/github/organization.rego | 22 ++--- policies/github/repository.rego | 133 +++++++++++++------------- policies/github/runner_group.rego | 8 +- policies/gitlab/enterprise.rego | 44 ++++----- policies/gitlab/member.rego | 20 ++-- policies/gitlab/organization.rego | 16 ++-- policies/gitlab/repository.rego | 70 +++++++------- 13 files changed, 228 insertions(+), 201 deletions(-) create mode 100644 .regal/config.yaml diff --git a/.github/workflows/build_and_test.yaml b/.github/workflows/build_and_test.yaml index 7c6fc7d0..2176f0c2 100644 --- a/.github/workflows/build_and_test.yaml +++ b/.github/workflows/build_and_test.yaml @@ -27,3 +27,16 @@ jobs: run: go test -count=1 -shuffle=on -timeout=10m -race $(go list ./... | grep -vE '^github.com/Legit-Labs/legitify/e2e') - name: Vet run: go vet -v ./... + check_rego: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: open-policy-agent/setup-opa@9501844990f7dcfd09b17a8d97c794d294620f37 # v2.1.0 + with: + version: v0.55.0 + - uses: styrainc/setup-regal@94ad2891f53efdb7ebe7c6836bc25ecc9504aec1 # v0.2.0 + with: + version: v0.11.0 + - run: opa check --strict policies/github + - run: opa check --strict policies/gitlab + - run: regal lint --format=github policies diff --git a/.regal/config.yaml b/.regal/config.yaml new file mode 100644 index 00000000..a8633f90 --- /dev/null +++ b/.regal/config.yaml @@ -0,0 +1,23 @@ +rules: + idiomatic: + no-defined-entrypoint: + # OK to ignore for libraries + level: ignore + style: + file-length: + # Override default of 500 as one file has 515 lines + max-file-length: 550 + line-length: + # Violations here mostly from metadata annotation values. + # These could be fixed by using |> and newlines, but we'll + # ignore this for now. + level: ignore + opa-fmt: + # Would mostly changes spaces -> tabs. Safe to ignore. + level: ignore + prefer-snake-case: + # Only a few violations here, so this would be easy to fix. + level: ignore + prefer-some-in-iteration: + # This is mostly a style preference, so safe to ignore. + level: ignore diff --git a/policies/github/actions.rego b/policies/github/actions.rego index dd10fd98..0ad7cf42 100644 --- a/policies/github/actions.rego +++ b/policies/github/actions.rego @@ -17,9 +17,9 @@ package actions # - "4. Attacker trigger the workflow" # - "5. Attacker receives all organization secrets and uses them maliciously" # requiredScopes: [admin:org] -default all_repositories_can_run_github_actions = true +default all_repositories_can_run_github_actions := true -all_repositories_can_run_github_actions = false { +all_repositories_can_run_github_actions := false { input.actions_permissions.enabled_repositories != "all" } @@ -37,9 +37,9 @@ all_repositories_can_run_github_actions = false { # - "1. Attacker creates a repository with a tempting but malicious custom GitHub Action" # - "2. An innocent developer / DevOps engineer uses this malicious action" # - "3. The malicious action has access to the developer repository and could steal its secrets or modify its content" -default all_github_actions_are_allowed = true +default all_github_actions_are_allowed := true -all_github_actions_are_allowed = false { +all_github_actions_are_allowed := false { input.actions_permissions.allowed_actions != "all" } @@ -59,9 +59,9 @@ all_github_actions_are_allowed = false { # severity: MEDIUM # requiredScopes: [admin:org] # threat: In case of token compromise (due to a vulnerability or malicious third-party GitHub actions), an attacker can use this token to sabotage various assets in your CI/CD pipeline, such as packages, pull-requests, deployments, and more. -default token_default_permissions_is_read_write = true +default token_default_permissions_is_read_write := true -token_default_permissions_is_read_write = false { +token_default_permissions_is_read_write := false { input.token_permissions.default_workflow_permissions == "read" } @@ -81,8 +81,8 @@ token_default_permissions_is_read_write = false { # severity: HIGH # requiredScopes: [admin:org] # threat: Attackers can exploit this misconfiguration to bypass code-review restrictions by creating a workflow that approves their own pull request and then merging the pull request without anyone noticing, introducing malicious code that would go straight ahead to production. -default actions_can_approve_pull_requests = true +default actions_can_approve_pull_requests := true -actions_can_approve_pull_requests = false { +actions_can_approve_pull_requests := false { not input.token_permissions.can_approve_pull_request_reviews } diff --git a/policies/github/common/webhooks.rego b/policies/github/common/webhooks.rego index ba2a7659..5c2192fc 100644 --- a/policies/github/common/webhooks.rego +++ b/policies/github/common/webhooks.rego @@ -1,14 +1,12 @@ package common.webhooks -has_key(x, k) { - _ = x[k] -} +import future.keywords.in ssl_enabled(hook) { - has_key(hook.config, "insecure_ssl") + "insecure_ssl" in object.keys(hook.config) hook.config.insecure_ssl == "0" } has_secret(hook) { - has_key(hook.config, "secret") -} \ No newline at end of file + "secret" in object.keys(hook.config) +} diff --git a/policies/github/enterprise.rego b/policies/github/enterprise.rego index 8edfb681..536da36b 100644 --- a/policies/github/enterprise.rego +++ b/policies/github/enterprise.rego @@ -10,9 +10,9 @@ package enterprise # requiredScopes: [admin:enterprise] # threat: # - "A member of the organization could inadvertently or maliciously make public an internal repository exposing confidential data." -default enterprise_not_using_visibility_change_disable_policy = true +default enterprise_not_using_visibility_change_disable_policy := true -enterprise_not_using_visibility_change_disable_policy = false { +enterprise_not_using_visibility_change_disable_policy := false { input.members_can_change_repository_visibility == "DISABLED" } @@ -27,9 +27,9 @@ enterprise_not_using_visibility_change_disable_policy = false { # requiredScopes: [admin:enterprise] # threat: # - Forking to external namespaces could result in loss of control over proprietary information and potentially expose the organization to security risks, such as data leaks. -default enterprise_allows_forking_repos = true +default enterprise_allows_forking_repos := true -enterprise_allows_forking_repos = false { +enterprise_allows_forking_repos := false { input.repositories_forking_policy == "DISABLED" } @@ -44,9 +44,9 @@ enterprise_allows_forking_repos = false { # requiredScopes: [admin:enterprise] # threat: # - Users can accidentaly create public repositories and expose source code. -default enterprise_allows_creating_public_repos = true +default enterprise_allows_creating_public_repos := true -enterprise_allows_creating_public_repos = false { +enterprise_allows_creating_public_repos := false { input.members_can_create_public_repositories == false } @@ -61,9 +61,9 @@ enterprise_allows_creating_public_repos = false { # requiredScopes: [admin:enterprise] # threat: # - Inviting external collaborators could result in a loss of control over proprietary information and potentially expose the organization to security risks, such as data leaks. -default enterprise_allows_inviting_externals_collaborators = true +default enterprise_allows_inviting_externals_collaborators := true -enterprise_allows_inviting_externals_collaborators = false { +enterprise_allows_inviting_externals_collaborators := false { input.external_collaborators_invite_policy == "DISABLED" } @@ -77,9 +77,9 @@ enterprise_allows_inviting_externals_collaborators = false { # requiredScopes: [admin:enterprise] # threat: # - If an attacker gets the valid credentials for one of the enterprise’s users they can authenticate to your GitHub enterprise. -default enterprise_enforce_two_factor_authentication = true +default enterprise_enforce_two_factor_authentication := true -enterprise_enforce_two_factor_authentication = false { +enterprise_enforce_two_factor_authentication := false { input.two_factor_required_setting == "ENABLED" } @@ -93,24 +93,24 @@ enterprise_enforce_two_factor_authentication = false { # remediationSteps: [Make sure you are an enterprise owner, Go to the Settings page, Go to the Authentication security tab, Toggle on "Enable SAML authentication", Fill in the remaining SSO configuration as instructed on the screen, Click "Save"] # requiredScopes: [admin:enterprise] # threat: Not using an SSO solution makes it more difficult to track a potentially compromised user's actions across different systems, prevents common password policy throughout the enterprise, and makes it challenging to audit different aspects of the user's behavior. -default enterprise_not_using_single_sign_on = true +default enterprise_not_using_single_sign_on := true -enterprise_not_using_single_sign_on = false { +enterprise_not_using_single_sign_on := false { input.saml_enabled } # METADATA # scope: rule -# title: Enterprise Should Define Base Permissions As “No Permission” For All Members +# title: Enterprise Should Define Base Permissions As “No Permission” For All Members # description: Collaborators in your organizations should receive access to specific organizations and repositories as necessary, and not have read and write access to all repositories across the enterprise. # custom: # severity: MEDIUM # remediationSteps: [Make sure you are an enterprise owner, Go to the Settings page, Under the ‘Policies’ tab, choose ‘Repositories’, Under ‘Base Permission’ choose ‘No Permission’] # requiredScopes: [admin:enterprise] # threat: An adversary will have access to all repositories in the enterprise, instead of just a part of them. -default repository_no_permission_enforced_by_default = true +default repository_no_permission_enforced_by_default := true -repository_no_permission_enforced_by_default = false { +repository_no_permission_enforced_by_default := false { input.default_repository_no_permission_enforced == "NONE" } @@ -123,9 +123,9 @@ repository_no_permission_enforced_by_default = false { # remediationSteps: [Make sure you are an enterprise owner, Go to the Enterprise Settings page, Under the ‘Policies’ tab choose ‘Repositories’, Go to the ‘Admin repository permissions' section, under ‘Repository deletion and transfer' and select 'Disabled'] # requiredScopes: [admin:enterprise] # threat: A member of the organization could inadvertently or maliciously transfer a repository to an external namespace and expose confidential data. -default memberes_allowed_repository_move_or_deletion = true +default memberes_allowed_repository_move_or_deletion := true -memberes_allowed_repository_move_or_deletion = false { +memberes_allowed_repository_move_or_deletion := false { input.member_can_delete_repository == "DISABLED" } @@ -138,9 +138,9 @@ memberes_allowed_repository_move_or_deletion = false { # custom: # remediationSteps: [Make sure you are an enterprise owner, Go to the Enterprise Settings page, Under the ‘Settings’ tab choose ‘Code security and analysis’, Check 'Automatically enable for new repositories'] # requiredScopes: [admin:enterprise] -default enable_ghas_for_new_orgs = true +default enable_ghas_for_new_orgs := true -enable_ghas_for_new_orgs = false { +enable_ghas_for_new_orgs := false { input.code_analysis_and_security_policies.advanced_security_enabled_for_new_repositories == true } @@ -152,9 +152,9 @@ enable_ghas_for_new_orgs = false { # severity: MEDIUM # remediationSteps: [Make sure you are an enterprise owner, Go to the Enterprise Settings page, Under the ‘Settings’ tab choose ‘Code security and analysis’, Check 'Automatically enable for new repositories with Advanced Security enabled'] # requiredScopes: [admin:enterprise] -default enable_secret_scanning_for_new_orgs = true +default enable_secret_scanning_for_new_orgs := true -enable_secret_scanning_for_new_orgs = false { +enable_secret_scanning_for_new_orgs := false { input.code_analysis_and_security_policies.secret_scanning_enabled_for_new_repositories == true } @@ -166,8 +166,8 @@ enable_secret_scanning_for_new_orgs = false { # severity: MEDIUM # remediationSteps: [Make sure you are an enterprise owner, Go to the Enterprise Settings page, Under the ‘Settings’ tab choose ‘Code security and analysis’, Check 'Automatically enable for repositories added to secret scanning'] # requiredScopes: [admin:enterprise] -default enable_push_protection_secret_scanning = true +default enable_push_protection_secret_scanning := true -enable_push_protection_secret_scanning = false { +enable_push_protection_secret_scanning := false { input.code_analysis_and_security_policies.secret_scanning_push_protection_enabled_for_new_repositories == true } \ No newline at end of file diff --git a/policies/github/member.rego b/policies/github/member.rego index 21e642de..09deffd5 100644 --- a/policies/github/member.rego +++ b/policies/github/member.rego @@ -12,9 +12,9 @@ package member # - "1. An organization has a permissive attitude and provides an owner role to all developers." # - "2. One of the developers has decided to collaborate with an evil ransomware gang, and uses his high privileges to add a malicious external collaborator" # - "3. The malicious collaborator, being an owner, has a wide range of destructive operations he can do (e.g. remove security settings)" -default organization_has_too_many_admins = true +default organization_has_too_many_admins := true -organization_has_too_many_admins = false { +organization_has_too_many_admins := false { admins := count({member | member := input.members[_]; member.is_admin == true}) admins <= 3 } @@ -31,7 +31,7 @@ organization_has_too_many_admins = false { # prerequisites: [premium] # threat: # - "Stale members are most likely not managed and monitored, increasing the possibility of being compromised." -stale_member_found[mem] = true { +stale_member_found[mem] := true { some member mem := input.members[member] mem.is_admin == false @@ -51,7 +51,7 @@ stale_member_found[mem] = true { # prerequisites: [premium] # threat: # - "Stale admins are most likely not managed and monitored, increasing the possibility of being compromised." -stale_admin_found[mem] = true { +stale_admin_found[mem] := true { some member mem := input.members[member] mem.is_admin == true diff --git a/policies/github/organization.rego b/policies/github/organization.rego index 8ce0e0b4..5029e804 100644 --- a/policies/github/organization.rego +++ b/policies/github/organization.rego @@ -11,10 +11,10 @@ import data.common.webhooks as webhookUtils # severity: LOW # remediationSteps: [Make sure you have admin permissions, Go to the organization settings page, Select "Webhooks", Press on the insecure webhook, Configure a secret , Click "Update webhook"] # requiredScopes: [admin:org_hook] -# threat: +# threat: # - "Not using a webhook secret makes the service receiving the webhook unable to determine the authenticity of the request." # - "This allows attackers to masquerade as your organization, potentially creating an unstable or insecure state in other systems." -organization_webhook_no_secret[violated] = true { +organization_webhook_no_secret[violated] := true { some index hook := input.hooks[index] not webhookUtils.has_secret(hook) @@ -36,7 +36,7 @@ organization_webhook_no_secret[violated] = true { # threat: # - "If SSL verification is disabled, any party with access to the target DNS domain can masquerade as your designated payload URL, allowing it freely read and affect the response of any webhook request." # - "In the case of GitHub Enterprise Server instances, it may be sufficient only to control the DNS configuration of the network where the instance is deployed, as an attacker can redirect traffic to the target domain in your internal network directly to them, and this is often much easier than compromising an internet-facing domain." -organization_webhook_doesnt_require_ssl[violated] = true { +organization_webhook_doesnt_require_ssl[violated] := true { some index hook := input.hooks[index] not webhookUtils.ssl_enabled(hook) @@ -56,9 +56,9 @@ organization_webhook_doesnt_require_ssl[violated] = true { # requiredScopes: [admin:org] # threat: # - If an attacker gets the valid credentials for one of the organization’s users they can authenticate to your GitHub organization. -default two_factor_authentication_not_required_for_org = true +default two_factor_authentication_not_required_for_org := true -two_factor_authentication_not_required_for_org = false { +two_factor_authentication_not_required_for_org := false { input.organization.two_factor_requirement_enabled } @@ -73,9 +73,9 @@ two_factor_authentication_not_required_for_org = false { # requiredScopes: [read:org] # threat: # - "A member of the organization could inadvertently or maliciously make public an internal repository exposing confidential data." -default non_admins_can_create_public_repositories = true +default non_admins_can_create_public_repositories := true -non_admins_can_create_public_repositories = false { +non_admins_can_create_public_repositories := false { not input.organization.members_can_create_public_repositories } @@ -89,9 +89,9 @@ non_admins_can_create_public_repositories = false { # requiredScopes: [read:enterprise] # threat: # - "Organization members can see the content of freshly created repositories, even if they should be restricted." -default default_repository_permission_is_not_none = true +default default_repository_permission_is_not_none := true -default_repository_permission_is_not_none = false { +default_repository_permission_is_not_none := false { input.organization.default_repository_permission == "none" } @@ -105,8 +105,8 @@ default_repository_permission_is_not_none = false { # remediationSteps: [Make sure you have admin permissions, Go to the organization settings page, Enter "Authentication security" tab, Toggle on "Enable SAML authentication", Fill in the remaining SSO configuration as instructed on the screen, Click "Save"] # requiredScopes: [admin:org] # threat: Not using an SSO solution makes it more difficult to track a potentially compromised user's actions accross different systems, prevents the organization from defining a common password policy, and makes it challenging to audit different aspects of the user's behavior. -default organization_not_using_single_sign_on = true +default organization_not_using_single_sign_on := true -organization_not_using_single_sign_on = false { +organization_not_using_single_sign_on := false { input.saml_enabled } diff --git a/policies/github/repository.rego b/policies/github/repository.rego index 5920e6a5..cf9bef84 100644 --- a/policies/github/repository.rego +++ b/policies/github/repository.rego @@ -11,9 +11,9 @@ import data.common.webhooks as webhookUtils # severity: HIGH # requiredScopes: [repo] # threat: As new vulnerabilities are found over time, unmaintained repositories are more likely to point to dependencies that have known vulnerabilities, exposing these repositories to 1-day attacks. -default repository_not_maintained = true +default repository_not_maintained := true -repository_not_maintained = false { +repository_not_maintained := false { not input.repository.is_archived not is_null(input.repository.pushed_at) ns := time.parse_rfc3339_ns(input.repository.pushed_at) @@ -33,12 +33,12 @@ repository_not_maintained = false { # severity: LOW # remediationSteps: [Make sure you have admin permissions, Go to the repository settings page, Press "Collaborators and teams", Select the unwanted admin users, Select "Change Role"] # requiredScopes: [read:org,repo] -# threat: +# threat: # - "A compromised user with admin permissions can initiate a supply chain attack in a plethora of ways." # - "Having many admin users increases the overall risk of user compromise, and makes it more likely to lose track of unused admin permissions given to users in the past." -default repository_has_too_many_admins = true +default repository_has_too_many_admins := true -repository_has_too_many_admins = false { +repository_has_too_many_admins := false { admins := [admin | admin := input.collaborators[_]; admin.permissions.admin] count(admins) <= 3 } @@ -52,10 +52,10 @@ repository_has_too_many_admins = false { # severity: LOW # remediationSteps: [Make sure you can manage webhooks for the repository, Go to the repository settings page, Select "Webhooks", Press on the insecure webhook, Confiure a secret, Click "Update webhook"] # requiredScopes: [read:repo_hook, repo] -# threat: +# threat: # - "Not using a webhook secret makes the service receiving the webhook unable to determine the authenticity of the request." # - "This allows attackers to masquerade as your repository, potentially creating an unstable or insecure state in other systems." -repository_webhook_no_secret[violated] = true { +repository_webhook_no_secret[violated] := true { some index hook := input.hooks[index] not webhookUtils.has_secret(hook) @@ -77,7 +77,7 @@ repository_webhook_no_secret[violated] = true { # threat: # - "If SSL verification is disabled, any party with access to the target DNS domain can masquerade as your designated payload URL, allowing it freely read and affect the response of any webhook request." # - "In the case of GitHub Enterprise Server instances, it may be sufficient only to control the DNS configuration of the network where the instance is deployed, as an attacker can redirect traffic to the target domain in your internal network directly to them, and this is often much easier than compromising an internet-facing domain." -repository_webhook_doesnt_require_ssl[violated] = true { +repository_webhook_doesnt_require_ssl[violated] := true { some index hook := input.hooks[index] not webhookUtils.ssl_enabled(hook) @@ -96,17 +96,13 @@ repository_webhook_doesnt_require_ssl[violated] = true { # severity: LOW # requiredScopes: [read:org] # threat: Forked repositories cause more code and secret sprawl in the organization as forks are independent copies of the repository and need to be tracked separately, making it more difficult to keep track of sensitive assets and contain potential incidents. -default forking_allowed_for_repository = true +default forking_allowed_for_repository := true -forking_allowed_for_repository = false { +forking_allowed_for_repository := false { input.repository.is_private == true input.repository.allow_forking == false } -is_null(x) { - x == null -} - # METADATA # scope: rule # title: Default Branch Should Be Protected @@ -117,13 +113,13 @@ is_null(x) { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Any contributor with write access may push potentially dangerous code to this repository, making it easier to compromise and difficult to audit. -default missing_default_branch_protection = true +default missing_default_branch_protection := true -missing_default_branch_protection = false { +missing_default_branch_protection := false { not is_null(input.repository.default_branch.branch_protection_rule) } -missing_default_branch_protection = false { +missing_default_branch_protection := false { some index rule := input.rules_set[index] rule.type == "pull_request" @@ -146,12 +142,13 @@ missing_default_branch_protection = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Rewriting project history can make it difficult to trace back when bugs or security issues were introduced, making them more difficult to remediate. -default missing_default_branch_protection_deletion = true -missing_default_branch_protection_deletion = false { +default missing_default_branch_protection_deletion := true + +missing_default_branch_protection_deletion := false { not input.repository.default_branch.branch_protection_rule.allows_deletions } -missing_default_branch_protection_deletion = false { +missing_default_branch_protection_deletion := false { some index rule := input.rules_set[index] rule.type == "deletions" @@ -167,13 +164,13 @@ missing_default_branch_protection_deletion = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Rewriting project history can make it difficult to trace back when bugs or security issues were introduced, making them more difficult to remediate. -default missing_default_branch_protection_force_push = true +default missing_default_branch_protection_force_push := true -missing_default_branch_protection_force_push = false { +missing_default_branch_protection_force_push := false { not input.repository.default_branch.branch_protection_rule.allows_force_pushes } -missing_default_branch_protection_force_push = false { +missing_default_branch_protection_force_push := false { some index rule := input.rules_set[index] rule.type == "non_fast_forward" @@ -189,13 +186,13 @@ missing_default_branch_protection_force_push = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Not defining a set of required status checks can make it easy for contributors to introduce buggy or insecure code as manual review, whether mandated or optional, is the only line of defense. -default requires_status_checks = true +default requires_status_checks := true -requires_status_checks = false { +requires_status_checks := false { input.repository.default_branch.branch_protection_rule.requires_status_checks } -requires_status_checks = false { +requires_status_checks := false { some index rule := input.rules_set[index] rule.type == "required_status_checks" @@ -212,14 +209,14 @@ requires_status_checks = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Required status checks may be failing on the latest version after passing on an earlier version of the code, making it easy to commit buggy or otherwise insecure code. -default requires_branches_up_to_date_before_merge = true +default requires_branches_up_to_date_before_merge := true -requires_branches_up_to_date_before_merge = false { +requires_branches_up_to_date_before_merge := false { input.repository.default_branch.branch_protection_rule.requires_status_checks input.repository.default_branch.branch_protection_rule.requires_strict_status_checks } -requires_branches_up_to_date_before_merge = false { +requires_branches_up_to_date_before_merge := false { some index rule := input.rules_set[index] rule.type == "required_status_checks" @@ -237,13 +234,13 @@ requires_branches_up_to_date_before_merge = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Buggy or insecure code may be committed after approval and will reach the main branch without review. Alternatively, an attacker can attempt a just-in-time attack to introduce dangerous code just before merge. -default dismisses_stale_reviews = true +default dismisses_stale_reviews := true -dismisses_stale_reviews = false { +dismisses_stale_reviews := false { input.repository.default_branch.branch_protection_rule.dismisses_stale_reviews } -dismisses_stale_reviews = false { +dismisses_stale_reviews := false { some index rule := input.rules_set[index] rule.type == "pull_request" @@ -260,13 +257,13 @@ dismisses_stale_reviews = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Users can merge code without being reviewed, which can lead to insecure code reaching the main branch and production. -default code_review_not_required = true +default code_review_not_required := true -code_review_not_required = false { +code_review_not_required := false { input.repository.default_branch.branch_protection_rule.required_approving_review_count >= 1 } -code_review_not_required = false { +code_review_not_required := false { some index rule := input.rules_set[index] rule.type == "pull_request" @@ -286,13 +283,13 @@ code_review_not_required = false { # threat: # - "Users can merge code without being reviewed, which can lead to insecure code reaching the main branch and production." # - "Requiring code review by at least two reviewers further decreases the risk of an insider threat (as merging code requires compromising at least 2 identities with write permissions), and decreases the likelihood of human error in the review process." -default code_review_by_two_members_not_required = true +default code_review_by_two_members_not_required := true -code_review_by_two_members_not_required = false { +code_review_by_two_members_not_required := false { input.repository.default_branch.branch_protection_rule.required_approving_review_count >= 2 } -code_review_by_two_members_not_required = false { +code_review_by_two_members_not_required := false { some index rule := input.rules_set[index] rule.type == "pull_request" @@ -309,13 +306,13 @@ code_review_by_two_members_not_required = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: A pull request may be approved by any contributor with write access. Specifying specific code owners can ensure review is only done by individuals with the correct expertise required for the review of the changed files, potentially preventing bugs and security risks. -default code_review_not_limited_to_code_owners = true +default code_review_not_limited_to_code_owners := true -code_review_not_limited_to_code_owners = false { +code_review_not_limited_to_code_owners := false { input.repository.default_branch.branch_protection_rule.requires_code_owner_reviews } -code_review_not_limited_to_code_owners = false { +code_review_not_limited_to_code_owners := false { some index rule := input.rules_set[index] rule.type == "pull_request" @@ -332,13 +329,13 @@ code_review_not_limited_to_code_owners = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Having a non-linear history makes it harder to reverse changes, making recovery from bugs and security risks slower and more difficult. -default non_linear_history = true +default non_linear_history := true -non_linear_history = false { +non_linear_history := false { input.repository.default_branch.branch_protection_rule.requires_linear_history } -non_linear_history = false { +non_linear_history := false { some index rule := input.rules_set[index] rule.type == "required_linear_history" @@ -354,13 +351,13 @@ non_linear_history = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Allowing the merging of code without resolving all conversations can promote poor and vulnerable code, as important comments may be forgotten or deliberately ignored when the code is merged. -default no_conversation_resolution = true +default no_conversation_resolution := true -no_conversation_resolution = false { +no_conversation_resolution := false { input.repository.default_branch.branch_protection_rule.requires_conversation_resolution } -no_conversation_resolution = false { +no_conversation_resolution := false { some index rule := input.rules_set[index] rule.type == "pull_request" @@ -377,13 +374,13 @@ no_conversation_resolution = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: A commit containing malicious code may be crafted by a malicious actor that has acquired write access to the repository to initiate a supply chain attack. Commit signing provides another layer of defense that can prevent this type of compromise. -default no_signed_commits = true +default no_signed_commits := true -no_signed_commits = false { +no_signed_commits := false { input.repository.default_branch.branch_protection_rule.requires_commit_signatures } -no_signed_commits = false { +no_signed_commits := false { some index rule := input.rules_set[index] rule.type == "required_signatures" @@ -399,10 +396,10 @@ no_signed_commits = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: Allowing the dismissal of reviews can promote poor and vulnerable code, as important comments may be forgotten and ignored during the review process. -default review_dismissal_allowed = true +default review_dismissal_allowed := true -review_dismissal_allowed = false { - input.repository.default_branch.branch_protection_rule.restricts_review_dismissals +review_dismissal_allowed := false { + input.repository.default_branch.branch_protection_rule.restricts_review_dismissals } # METADATA @@ -415,14 +412,14 @@ review_dismissal_allowed = false { # requiredScopes: [repo] # prerequisites: [has_branch_protection_permission] # threat: An attacker with write credentials may introduce vulnerabilities to your code without your knowledge. Alternatively, contributors may commit unsafe code that is buggy or easy to exploit that could have been caught using a review process. -default pushes_are_not_restricted = true +default pushes_are_not_restricted := true -pushes_are_not_restricted = false { +pushes_are_not_restricted := false { not code_review_not_required } -pushes_are_not_restricted = false { - input.repository.default_branch.branch_protection_rule.restricts_pushes +pushes_are_not_restricted := false { + input.repository.default_branch.branch_protection_rule.restricts_pushes } # METADATA @@ -434,11 +431,11 @@ pushes_are_not_restricted = false { # severity: MEDIUM # requiredScopes: [repo] # threat: An open source vulnerability may be affecting your code without your knowledge, making it vulnerable to exploitation. -default vulnerability_alerts_not_enabled = true +default vulnerability_alerts_not_enabled := true -vulnerability_alerts_not_enabled = false { +vulnerability_alerts_not_enabled := false { # deliberately ignoring nil value (in case this data is unavailable) - input.vulnerability_alerts_enabled + input.vulnerability_alerts_enabled } # METADATA @@ -450,9 +447,9 @@ vulnerability_alerts_not_enabled = false { # severity: MEDIUM # requiredScopes: [repo] # threat: A contributor may add vulnerable third-party dependencies to the repository, introducing vulnerabilities to your application that will only be detected after merge. -default ghas_dependency_review_not_enabled = true +default ghas_dependency_review_not_enabled := true -ghas_dependency_review_not_enabled = false { +ghas_dependency_review_not_enabled := false { input.dependency_graph_manifests.total_count > 0 } @@ -467,9 +464,9 @@ ghas_dependency_review_not_enabled = false { # requiredScopes: [repo, read:repo_hook] # prerequisites: [scorecard_enabled] # threat: A low Scorecard score can indicate that the repository is more vulnerable to attack than others, making it a prime attack target. -default scorecard_score_too_low = true +default scorecard_score_too_low := true -scorecard_score_too_low = false { +scorecard_score_too_low := false { input.scorecard.score > 7.0 } @@ -489,9 +486,9 @@ scorecard_score_too_low = false { # severity: MEDIUM # requiredScopes: [admin:org] # threat: In case of token compromise (due to a vulnerability or malicious third-party GitHub actions), an attacker can use this token to sabotage various assets in your CI/CD pipeline, such as packages, pull-requests, deployments, and more. -default token_default_permissions_is_read_write = true +default token_default_permissions_is_read_write := true -token_default_permissions_is_read_write = false { +token_default_permissions_is_read_write := false { input.actions_token_permissions.default_workflow_permissions == "read" } @@ -511,8 +508,8 @@ token_default_permissions_is_read_write = false { # severity: HIGH # requiredScopes: [admin:org] # threat: Attackers can exploit this misconfiguration to bypass code-review restrictions by creating a workflow that approves their own pull request and then merging the pull request without anyone noticing, introducing malicious code that would go straight ahead to production. -default actions_can_approve_pull_requests = true +default actions_can_approve_pull_requests := true -actions_can_approve_pull_requests = false{ +actions_can_approve_pull_requests := false{ not input.actions_token_permissions.can_approve_pull_request_reviews } diff --git a/policies/github/runner_group.rego b/policies/github/runner_group.rego index 8960086a..ee177280 100644 --- a/policies/github/runner_group.rego +++ b/policies/github/runner_group.rego @@ -25,9 +25,9 @@ package runner_group # - "If the hosted runner is insecurely configured, any GitHub user could:" # - "1. Create a workflow that runs on the public hosted runner" # - "2. Exploit the misconfigurations to execute code inside the private network" -default runner_group_can_be_used_by_public_repositories = true +default runner_group_can_be_used_by_public_repositories := true -runner_group_can_be_used_by_public_repositories = false { +runner_group_can_be_used_by_public_repositories := false { not input.runner_group.allows_public_repositories } @@ -52,8 +52,8 @@ runner_group_can_be_used_by_public_repositories = false { # - "If the hosted runner is insecurely configured, any user in the organization could:" # - "1. Create a workflow that runs on the hosted runner" # - "2. Exploit the runner misconfigurations/known CVE's to execute code inside the private network" -default runner_group_not_limited_to_selected_repositories = true +default runner_group_not_limited_to_selected_repositories := true -runner_group_not_limited_to_selected_repositories = false { +runner_group_not_limited_to_selected_repositories := false { input.runner_group.visibility == "selected" } diff --git a/policies/gitlab/enterprise.rego b/policies/gitlab/enterprise.rego index 14e81a3a..6c7f8831 100644 --- a/policies/gitlab/enterprise.rego +++ b/policies/gitlab/enterprise.rego @@ -15,9 +15,9 @@ package enterprise # - Expand "Sign-in restrictions" section # - Toggle "Two-factor authentication" # - Press "Save Changes" -default require_two_factor_authentication_not_globally_enforced = true +default require_two_factor_authentication_not_globally_enforced := true -require_two_factor_authentication_not_globally_enforced = false { +require_two_factor_authentication_not_globally_enforced := false { input.require_two_factor_authentication } @@ -35,9 +35,9 @@ require_two_factor_authentication_not_globally_enforced = false { # - Expand "Sign-in restrictions" section # - Un toggle "Allow password authentication for Git over HTTP(S)" # - Press "Save Changes" -default password_authentication_enabled_for_git_is_enabled = true +default password_authentication_enabled_for_git_is_enabled := true -password_authentication_enabled_for_git_is_enabled = false { +password_authentication_enabled_for_git_is_enabled := false { not input.password_authentication_enabled_for_git } @@ -55,9 +55,9 @@ password_authentication_enabled_for_git_is_enabled = false { # - Expand "User and IP rate limit" section # - Toggle "Enable authenticated API request rate limit # - Press "Save Changes" -default throttle_authenticated_api_not_enabled = true +default throttle_authenticated_api_not_enabled := true -throttle_authenticated_api_not_enabled = false { +throttle_authenticated_api_not_enabled := false { input.throttle_authenticated_api_enabled } @@ -75,9 +75,9 @@ throttle_authenticated_api_not_enabled = false { # - Expand "Default Branch" section # - Toggle "Fully protected" # - Press "Save Changes" -default default_branch_protection_not_globally_enforced = true +default default_branch_protection_not_globally_enforced := true -default_branch_protection_not_globally_enforced = false { +default_branch_protection_not_globally_enforced := false { input.default_branch_protection > 0 } @@ -96,9 +96,9 @@ default_branch_protection_not_globally_enforced = false { # - Expand "Visibility and access controls" section # - Under "Restricted visibility levels" toggle "Public" # - Press "Save Changes" -default all_users_are_allowed_to_create_public_projects = true +default all_users_are_allowed_to_create_public_projects := true -all_users_are_allowed_to_create_public_projects = false { +all_users_are_allowed_to_create_public_projects := false { public := [rule | rule := input.restricted_visibility_levels[_]; rule == "public"] count(public) > 0 } @@ -117,9 +117,9 @@ all_users_are_allowed_to_create_public_projects = false { # - Expand "Visibility and access controls" section # - Under "Default group visibility" toggle "Private" # - Press "Save Changes" -default default_group_visibility_is_public = true +default default_group_visibility_is_public := true -default_group_visibility_is_public = false { +default_group_visibility_is_public := false { not input.default_group_visibility == "public" } @@ -137,9 +137,9 @@ default_group_visibility_is_public = false { # - Expand "Visibility and access controls" section # - Under "Default project visibility" toggle "Private" # - Press "Save Changes" -default default_project_visibility_is_public = true +default default_project_visibility_is_public := true -default_project_visibility_is_public = false { +default_project_visibility_is_public := false { not input.default_project_visibility == "public" } @@ -157,9 +157,9 @@ default_project_visibility_is_public = false { # - Expand "Sign-up restrictions" section # - Toggle "Send confirmation email on sign-up" # - Press "Save Changes" -default send_user_confirmation_email_not_enabled = true +default send_user_confirmation_email_not_enabled := true -send_user_confirmation_email_not_enabled = false { +send_user_confirmation_email_not_enabled := false { input.send_user_confirmation_email } @@ -177,9 +177,9 @@ send_user_confirmation_email_not_enabled = false { # - Expand "User and IP rate limit" section # - Toggle "Enable unauthenticated API request rate limit" and "Enable unauthenticated web request rate limit" # - Press "Save Changes" -default throttle_unauthenticated_request_not_enabled = true +default throttle_unauthenticated_request_not_enabled := true -throttle_unauthenticated_request_not_enabled = false { +throttle_unauthenticated_request_not_enabled := false { input.throttle_unauthenticated_api_enabled input.throttle_unauthenticated_web_enabled } @@ -199,9 +199,9 @@ throttle_unauthenticated_request_not_enabled = false { # - Expand "Outbound requests" section # - Un toggle "Allow requests to the local network from web hooks and services" # - Press "Save Changes" -default webhooks_are_allowed_to_be_sent_to_local_network = true +default webhooks_are_allowed_to_be_sent_to_local_network := true -webhooks_are_allowed_to_be_sent_to_local_network = false { +webhooks_are_allowed_to_be_sent_to_local_network := false { not input.allow_local_requests_from_web_hooks_and_services } @@ -217,8 +217,8 @@ webhooks_are_allowed_to_be_sent_to_local_network = false { # - Expand "Sign-up restrictions" section # - Un toggle "Sign-up enabled" # - Press "Save Changes" -default unauthenticated_signup_enabled = true +default unauthenticated_signup_enabled := true -unauthenticated_signup_enabled = false { +unauthenticated_signup_enabled := false { not input.signup_enabled } diff --git a/policies/gitlab/member.rego b/policies/gitlab/member.rego index a1487ea1..728728f1 100644 --- a/policies/gitlab/member.rego +++ b/policies/gitlab/member.rego @@ -13,9 +13,9 @@ package member # - Select "Account" on the left navigation bar # - Press "Enable two-factor authentication" # threat: Collaborators without two-factor authentication are prime targets for phising and social engineering attacks, as compromise only requires acquiring the collaborator's password. -default two_factor_authentication_is_disabled_for_a_collaborator = true +default two_factor_authentication_is_disabled_for_a_collaborator := true -two_factor_authentication_is_disabled_for_a_collaborator = false { +two_factor_authentication_is_disabled_for_a_collaborator := false { input.two_factor_enabled } @@ -31,13 +31,13 @@ two_factor_authentication_is_disabled_for_a_collaborator = false { # - Go to the user settings page # - Select "Account" on the left navigation bar # - Press "Enable two-factor authentication" -# threat: +# threat: # - "Collaborators without two-factor authentication are prime targets for phising and social engineering attacks, as compromise only requires acquiring the collaborator's password." # - "This is doubly important for external collaborators, as these are identities that aren't likely managed by you or your organization and may be easier to compromise." -default two_factor_authentication_is_disabled_for_an_external_collaborator = true +default two_factor_authentication_is_disabled_for_an_external_collaborator := true -two_factor_authentication_is_disabled_for_an_external_collaborator = false { - input.external +two_factor_authentication_is_disabled_for_an_external_collaborator := false { + input.external input.two_factor_enabled } @@ -53,9 +53,9 @@ two_factor_authentication_is_disabled_for_an_external_collaborator = false { # - Find the stale admin and either delete of block it # threat: # - "Stale admins are most likely not managed and monitored, increasing the possibility of being compromised." -default stale_admin_found = true +default stale_admin_found := true -stale_admin_found = false { +stale_admin_found := false { input.is_admin == true not is_null(input.last_sign_in_at) ns := time.parse_rfc3339_ns(input.last_sign_in_at) @@ -69,7 +69,3 @@ isStale(target_last_active, count_months) { # diff[1] the months index diff[1] >= count_months } - -is_null(x) { - x == null -} diff --git a/policies/gitlab/organization.rego b/policies/gitlab/organization.rego index c908d3d4..7af9b7fe 100644 --- a/policies/gitlab/organization.rego +++ b/policies/gitlab/organization.rego @@ -14,16 +14,16 @@ package organization # - Press "Save Changes" # threat: # - If an attacker gets the valid credentials for one of the organization’s users they can authenticate to your GitHub organization. -default two_factor_authentication_not_required_for_group = true +default two_factor_authentication_not_required_for_group := true -two_factor_authentication_not_required_for_group = false { +two_factor_authentication_not_required_for_group := false { input.require_two_factor_authentication } # METADATA # scope: rule # title: Forking of Repositories to External Namespaces Should Be Disabled. -# description: The ability to fork project to external namespaces is turned on. Forking a repository can lead to loss of control and potential exposure of source code. If you do not need forking, it is recommended to turn it off in the project's configuration. The option to fork should be enabled only by owners deliberately when opting to create a fork. +# description: The ability to fork project to external namespaces is turned on. Forking a repository can lead to loss of control and potential exposure of source code. If you do not need forking, it is recommended to turn it off in the project's configuration. The option to fork should be enabled only by owners deliberately when opting to create a fork. # custom: # severity: MEDIUM # remediationSteps: @@ -33,9 +33,9 @@ two_factor_authentication_not_required_for_group = false { # - "Select Save changes" # threat: # - Forking to external namespaces could result in loss of control over proprietary information and potentially expose the organization to security risks, such as data leaks. -default collaborators_can_fork_repositories_to_external_namespaces = true +default collaborators_can_fork_repositories_to_external_namespaces := true -collaborators_can_fork_repositories_to_external_namespaces = false { +collaborators_can_fork_repositories_to_external_namespaces := false { input.prevent_forking_outside_group } @@ -54,7 +54,7 @@ collaborators_can_fork_repositories_to_external_namespaces = false { # threat: # - "If SSL verification is disabled, any party with access to the target DNS domain can masquerade as your designated payload URL, allowing it freely read and affect the response of any webhook request." # - "In the case of GitLab Self-Managed, it may be sufficient only to control the DNS configuration of the network where the instance is deployed." -organization_webhook_doesnt_require_ssl[violation] = true { +organization_webhook_doesnt_require_ssl[violation] := true { some index hook := input.hooks[index] hook.enable_ssl_verification == false @@ -76,8 +76,8 @@ organization_webhook_doesnt_require_ssl[violation] = true { # threat: # - A developer creates a repository without any branch protection rules # - Attacker that get access to the repository can modify its main branch without any restrictions -default group_does_not_enforce_branch_protection_by_default = true +default group_does_not_enforce_branch_protection_by_default := true -group_does_not_enforce_branch_protection_by_default = false { +group_does_not_enforce_branch_protection_by_default := false { input.default_branch_protection > 0 } diff --git a/policies/gitlab/repository.rego b/policies/gitlab/repository.rego index d54a089d..e05522d7 100644 --- a/policies/gitlab/repository.rego +++ b/policies/gitlab/repository.rego @@ -8,9 +8,9 @@ package repository # remediationSteps: [Make sure you have admin permissions, Either Delete or Archive the project] # severity: HIGH # threat: As new vulnerabilities are found over time, unmaintained repositories are more likely to point to dependencies that have known vulnerabilities, exposing these repositories to 1-day attacks. -default project_not_maintained = true +default project_not_maintained := true -project_not_maintained = false { +project_not_maintained := false { input.archived == false ns := time.parse_rfc3339_ns(input.last_activity_at) now := time.now_ns() @@ -32,9 +32,9 @@ project_not_maintained = false { # threat: # - "A compromised user with owner permissions can initiate a supply chain attack in a plethora of ways." # - "Having many admin users increases the overall risk of user compromise, and makes it more likely to lose track of unused admin permissions given to users in the past." -default project_has_too_many_admins = true +default project_has_too_many_admins := true -project_has_too_many_admins = false { +project_has_too_many_admins := false { admins := [admin | admin := input.members[_]; admin.access_level == 50] count(admins) <= 3 } @@ -47,13 +47,13 @@ project_has_too_many_admins = false { # remediationSteps: [Make sure you have owner permissions, Go to the project's settings page, Enter "General" tab, Under "Visibility, project features, permissions", Toggle off "Forks"] # severity: LOW # threat: Forked repositories may leak important code assets or sensitive secrets embedded in the code to anyone outside your organization, as the code becomes publicy-accessible -default forking_allowed_for_repository = true +default forking_allowed_for_repository := true -forking_allowed_for_repository = false { +forking_allowed_for_repository := false { input.public } -forking_allowed_for_repository = false { +forking_allowed_for_repository := false { not input.public input.forking_access_level != "enabled" } @@ -67,9 +67,9 @@ forking_allowed_for_repository = false { # severity: MEDIUM # prerequisites: [premium] # threat: Any contributor with write access may push potentially dangerous code to this repository, making it easier to compromise and difficult to audit. -default missing_default_branch_protection = true +default missing_default_branch_protection := true -missing_default_branch_protection = false { +missing_default_branch_protection := false { default_protected_branches := [protected_branch | protected_branch := input.protected_branches[_]; protected_branch.name == input.default_branch] count(default_protected_branches) > 0 } @@ -83,10 +83,10 @@ missing_default_branch_protection = false { # severity: MEDIUM # prerequisites: [premium] # threat: Rewriting project history can make it difficult to trace back when bugs or security issues were introduced, making them more difficult to remediate. -default missing_default_branch_protection_force_push = true +default missing_default_branch_protection_force_push := true + +missing_default_branch_protection_force_push := false { -missing_default_branch_protection_force_push = false { - default_protected_branches := [protected_branch | protected_branch := input.protected_branches[_]; protected_branch.name == input.default_branch] count(default_protected_branches) > 0 rules_allow_force_push := [rule_allow_force_push | rule_allow_force_push := default_protected_branches[_]; rule_allow_force_push.allow_force_push == true] @@ -102,9 +102,9 @@ missing_default_branch_protection_force_push = false { # severity: LOW # prerequisites: [premium] # threat: A pull request may be approved by any contributor with write access. Specifying specific code owners can ensure review is only done by individuals with the correct expertise required for the review of the changed files, potentially preventing bugs and security risks. -default repository_require_code_owner_reviews_policy = true +default repository_require_code_owner_reviews_policy := true -repository_require_code_owner_reviews_policy = false { +repository_require_code_owner_reviews_policy := false { default_protected_branches := [protected_branch | protected_branch := input.protected_branches[_]; protected_branch.name == input.default_branch] rules_allow_force_push := [ rule_require_code_owner_review | rule_require_code_owner_review := default_protected_branches[_]; rule_require_code_owner_review.code_owner_approval_required ] count(rules_allow_force_push) > 0 @@ -120,9 +120,9 @@ repository_require_code_owner_reviews_policy = false { # threat: # - "If SSL verification is disabled, any party with access to the target DNS domain can masquerade as your designated payload URL, allowing it freely read and affect the response of any webhook request." # - "In the case of GitLab Self-Managed, it may be sufficient only to control the DNS configuration of the network where the instance is deployed, as an attacker can redirect traffic to the target domain in your internal network directly to them, and this is often much easier than compromising an internet-facing domain." -default project_webhook_doesnt_require_ssl = true +default project_webhook_doesnt_require_ssl := true -project_webhook_doesnt_require_ssl = false{ +project_webhook_doesnt_require_ssl := false{ webhooks_without_ssl_verification := [webhook_without_verification | webhook_without_verification := input.webhooks[_]; webhook_without_verification.enable_ssl_verification == false] count(webhooks_without_ssl_verification) == 0 } @@ -135,9 +135,9 @@ project_webhook_doesnt_require_ssl = false{ # severity: MEDIUM # remediationSteps: [Make sure you can manage project merge requests permissions, Go to the project's settings page, Select "Merge Requests", Press on the "Pipelines must succeed", Click "Save changes"] # threat: Not defining a set of required status checks can make it easy for contributors to introduce buggy or insecure code as manual review, whether mandated or optional, is the only line of defense. -default requires_status_checks = true +default requires_status_checks := true -requires_status_checks = false { +requires_status_checks := false { input.only_allow_merge_if_pipeline_succeeds } @@ -149,9 +149,9 @@ requires_status_checks = false { # severity: LOW # remediationSteps: [Make sure you can manage project merge requests permissions, Go to the project's settings page, Select "Merge Requests", Press on the "All threads must be resolved", Click "Save changes"] # threat: Allowing the merging of code without resolving all conversations can promote poor and vulnerable code, as important comments may be forgotten or deliberately ignored when the code is merged. -default no_conversation_resolution = true +default no_conversation_resolution := true -no_conversation_resolution = false { +no_conversation_resolution := false { input.only_allow_merge_if_all_discussions_are_resolved } @@ -164,9 +164,9 @@ no_conversation_resolution = false { # severity: LOW # prerequisites: [premium] # threat: A commit containing malicious code may be crafted by a malicious actor that has acquired write access to the repository to initiate a supply chain attack. Commit signing provides another layer of defense that can prevent this type of compromise. -default no_signed_commits = true +default no_signed_commits := true -no_signed_commits = false { +no_signed_commits := false { input.push_rules.reject_unsigned_commits } @@ -181,9 +181,9 @@ no_signed_commits = false { # prerequisites: [premium] # threat: # - "Users can merge code without being reviewed which can lead to insecure code reaching the main branch and production." -default code_review_not_required = true +default code_review_not_required := true -code_review_not_required = false { +code_review_not_required := false { input.minimum_required_approvals >= 1 } @@ -197,9 +197,9 @@ code_review_not_required = false { # prerequisites: [premium] # threat: # - "Users can merge code without being reviewed which can lead to insecure code reaching the main branch and production." -default code_review_by_two_members_not_required = true +default code_review_by_two_members_not_required := true -code_review_by_two_members_not_required = false { +code_review_by_two_members_not_required := false { input.minimum_required_approvals >= 2 } @@ -212,9 +212,9 @@ code_review_by_two_members_not_required = false { # severity: MEDIUM # threat: # - "Users can merge code without being reviewed which can lead to insecure code reaching the main branch and production." -default repository_allows_review_requester_to_approve_their_own_request = true +default repository_allows_review_requester_to_approve_their_own_request := true -repository_allows_review_requester_to_approve_their_own_request = false { +repository_allows_review_requester_to_approve_their_own_request := false { not input.approval_configuration.merge_requests_author_approval } @@ -228,10 +228,10 @@ repository_allows_review_requester_to_approve_their_own_request = false { # prerequisites: [premium] # threat: # - "Users can merge code without being reviewed which can lead to insecure code reaching the main branch and production." -default repository_allows_overriding_approvers = true +default repository_allows_overriding_approvers := true -repository_allows_overriding_approvers = false { - input.approval_configuration.disable_overriding_approvers_per_merge_request +repository_allows_overriding_approvers := false { + input.approval_configuration.disable_overriding_approvers_per_merge_request } # METADATA @@ -244,9 +244,9 @@ repository_allows_overriding_approvers = false { # prerequisites: [premium] # threat: # - "Users can merge code without being reviewed which can lead to insecure code reaching the main branch and production." -default repository_allows_committer_approvals_policy = true +default repository_allows_committer_approvals_policy := true -repository_allows_committer_approvals_policy = false { +repository_allows_committer_approvals_policy := false { input.approval_configuration.merge_requests_disable_committers_approval } @@ -259,8 +259,8 @@ repository_allows_committer_approvals_policy = false { # severity: LOW # prerequisites: [premium] # threat: Buggy or insecure code may be committed after approval and will reach the main branch without review. Alternatively, an attacker can attempt a just-in-time attack to introduce dangerous code just before merge. -default repository_dismiss_stale_reviews = true +default repository_dismiss_stale_reviews := true -repository_dismiss_stale_reviews = false { +repository_dismiss_stale_reviews := false { input.approval_configuration.reset_approvals_on_push }