diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index d717d4ad40..bcdbf594e9 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -56,6 +56,14 @@ jobs: - name: test examples run: make test-examples + - name: setup regal + uses: StyraInc/setup-regal@v0.2.0 + with: + version: v0.11.0 + + - name: lint examples + run: regal lint --format github examples + - name: acceptance run: make test-acceptance diff --git a/.regal/config.yaml b/.regal/config.yaml new file mode 100644 index 0000000000..b032831b0d --- /dev/null +++ b/.regal/config.yaml @@ -0,0 +1,19 @@ +rules: + idiomatic: + no-defined-entrypoint: + level: ignore + imports: + prefer-package-imports: + level: error + ignore-import-paths: + - data.services + style: + line-length: + non-breakable-word-threshold: 80 + opa-fmt: + level: ignore + prefer-some-in-iteration: + level: ignore + testing: + test-outside-test-package: + level: ignore diff --git a/acceptance.bats b/acceptance.bats index 19368d5f54..2f52af4e17 100755 --- a/acceptance.bats +++ b/acceptance.bats @@ -176,7 +176,7 @@ @test "Supports print() output" { run ./conftest test -p examples/report/policy_print/labels.rego examples/kubernetes/deployment.yaml --no-color [ "$status" -eq 1 ] - [[ "${lines[0]}" == "PRNT examples/report/policy_print/labels.rego:12: hello-kubernetes" ]] + [[ "${lines[0]}" == "PRNT examples/report/policy_print/labels.rego:13: hello-kubernetes" ]] } @test "Can parse hcl1 files" { @@ -282,7 +282,7 @@ } @test "Can parse newly introduced keywords for docker" { - run bash -c "cat < 1 msg = sprintf("Error duplicate name : %s", [name]) } @@ -13,8 +13,10 @@ deny[msg] { name := input[_].contents.metadata.name kind == "team" + some i, j + # list all existing users - existing_users = {email | input[i].contents.kind == "user"; email := input[i].contents.metadata.email} + existing_users = {email | some i; input[i].contents.kind == "user"; email := input[i].contents.metadata.email} # gather all configured users in teams configured_owner_users_array = [user | input[i].contents.kind == "team"; user := input[i].contents.spec.owner] @@ -31,5 +33,8 @@ deny[msg] { # missing users are the ones configured in teams but not in Github count(missing_users) > 0 - msg = sprintf("Existing users %s | Configured users %s | Missing users %s", [sort(existing_users), sort(configured_users), sort(missing_users)]) + msg = sprintf( + "Existing users %s | Configured users %s | Missing users %s", + [sort(existing_users), sort(configured_users), sort(missing_users)], + ) } diff --git a/examples/cyclonedx/policy/policy.rego b/examples/cyclonedx/policy/policy.rego index 891f02d999..153b987625 100644 --- a/examples/cyclonedx/policy/policy.rego +++ b/examples/cyclonedx/policy/policy.rego @@ -1,7 +1,9 @@ package main deny[msg] { - expectedSHAS256 := "sha256:d7ec60cf8390612b360c857688b383068b580d9a6ab78417c9493170ad3f1616" - input.metadata.component.version != expectedSHAS256 - msg := sprintf("current SHA256 %s is not equal to expected SHA256 %s", [input.metadata.component.version, expectedSHAS256]) + expected_shas256 := "sha256:d7ec60cf8390612b360c857688b383068b580d9a6ab78417c9493170ad3f1616" + input.metadata.component.version != expected_shas256 + msg := sprintf( + "current SHA256 %s is not equal to expected SHA256 %s", [input.metadata.component.version, expected_shas256] + ) } \ No newline at end of file diff --git a/examples/docker/policy/commands.rego b/examples/docker/policy/commands.rego index 33c509ecde..70b5c21182 100644 --- a/examples/docker/policy/commands.rego +++ b/examples/docker/policy/commands.rego @@ -1,6 +1,6 @@ package commands -denylist = [ +denylist := [ "apk", "apt", "pip", @@ -9,9 +9,10 @@ denylist = [ ] deny[msg] { + some i input[i].Cmd == "run" val := input[i].Value contains(val[_], denylist[_]) - msg = sprintf("unallowed commands found %s", [val]) + msg := sprintf("unallowed commands found %s", [val]) } diff --git a/examples/docker/policy/images.rego b/examples/docker/policy/images.rego index ab5291891f..53c495accd 100644 --- a/examples/docker/policy/images.rego +++ b/examples/docker/policy/images.rego @@ -1,8 +1,9 @@ package main -denylist = ["openjdk"] +denylist := ["openjdk"] deny[msg] { + some i input[i].Cmd == "from" val := input[i].Value contains(val[i], denylist[_]) diff --git a/examples/hcl1/policy/base.rego b/examples/hcl1/policy/base.rego index 702d9abbb5..958faf790d 100644 --- a/examples/hcl1/policy/base.rego +++ b/examples/hcl1/policy/base.rego @@ -1,6 +1,6 @@ package main -denylist = [ +denylist := [ "google_iam", "google_container", ] @@ -8,7 +8,7 @@ denylist = [ deny[msg] { check_resources(input.resource_changes, denylist) banned := concat(", ", denylist) - msg = sprintf("Terraform plan will change prohibited resources in the following namespaces: %v", [banned]) + msg := sprintf("Terraform plan will change prohibited resources in the following namespaces: %v", [banned]) } # Checks whether the plan will cause resources with certain prefixes to change diff --git a/examples/hcl2/policy/deny.rego b/examples/hcl2/policy/deny.rego index d3796f7ecb..57f52fe94e 100644 --- a/examples/hcl2/policy/deny.rego +++ b/examples/hcl2/policy/deny.rego @@ -5,12 +5,14 @@ has_field(obj, field) { } deny[msg] { + some lb proto := input.resource.aws_alb_listener[lb].protocol proto == "HTTP" msg = sprintf("ALB `%v` is using HTTP rather than HTTPS", [lb]) } deny[msg] { + some name rule := input.resource.aws_security_group_rule[name] rule.type == "ingress" contains(rule.cidr_blocks[_], "0.0.0.0/0") @@ -18,6 +20,7 @@ deny[msg] { } deny[msg] { + some name disk = input.resource.azurerm_managed_disk[name] has_field(disk, "encryption_settings") disk.encryption_settings.enabled != true diff --git a/examples/hcl2/policy/deny_test.rego b/examples/hcl2/policy/deny_test.rego index ce015b727b..da87e89dd0 100644 --- a/examples/hcl2/policy/deny_test.rego +++ b/examples/hcl2/policy/deny_test.rego @@ -13,7 +13,9 @@ test_blank_input { } test_correctly_encrypted_azure_disk { - no_violations with input as {"resource": {"azurerm_managed_disk": {"sample": {"encryption_settings": {"enabled": true}}}}} + no_violations with input as { + "resource": {"azurerm_managed_disk": {"sample": {"encryption_settings": {"enabled": true}}}} + } } test_unencrypted_azure_disk { diff --git a/examples/ignore/dockerignore/policy/deny.rego b/examples/ignore/dockerignore/policy/deny.rego index 28055b36d3..b1fd68f843 100644 --- a/examples/ignore/dockerignore/policy/deny.rego +++ b/examples/ignore/dockerignore/policy/deny.rego @@ -1,7 +1,7 @@ package main any_git_ignored { - entry := input[o] + entry := input[_] entry.Kind == "Path" entry.Value == ".git" @@ -9,5 +9,5 @@ any_git_ignored { deny[msg] { not any_git_ignored - msg = ".git directories should be ignored" + msg := ".git directories should be ignored" } diff --git a/examples/ignore/gitignore/policy/deny.rego b/examples/ignore/gitignore/policy/deny.rego index 05f0cc4232..e1d01bc531 100644 --- a/examples/ignore/gitignore/policy/deny.rego +++ b/examples/ignore/gitignore/policy/deny.rego @@ -1,7 +1,7 @@ package main any_id_rsa_ignored { - entry := input[i] + entry := input[_] entry.Kind == "Path" entry.Value == "id_rsa" diff --git a/examples/kubernetes/combine/combine.rego b/examples/kubernetes/combine/combine.rego index 3954b952fb..86eb1b9f62 100644 --- a/examples/kubernetes/combine/combine.rego +++ b/examples/kubernetes/combine/combine.rego @@ -1,6 +1,7 @@ package main violation[msg] { + some i input[i].contents.kind == "Deployment" deployment := input[i].contents not service_selects_app(deployment.spec.selector.matchLabels.app) @@ -8,6 +9,7 @@ violation[msg] { } service_selects_app(app) { + some i input[i].contents.kind == "Service" service := input[i].contents service.spec.selector.app == app diff --git a/examples/kubernetes/policy/base_test.rego b/examples/kubernetes/policy/base_test.rego index b0689ec2c9..de0a9c3327 100644 --- a/examples/kubernetes/policy/base_test.rego +++ b/examples/kubernetes/policy/base_test.rego @@ -13,7 +13,10 @@ no_warnings { } test_deployment_without_security_context { - deny["Containers must not run as root in Deployment sample"] with input as {"kind": "Deployment", "metadata": {"name": "sample"}} + deny["Containers must not run as root in Deployment sample"] with input as { + "kind": "Deployment", + "metadata": {"name": "sample"} + } } test_deployment_with_security_context { @@ -47,5 +50,10 @@ test_services_not_denied { } test_services_issue_warning { - warn["Found service sample but services are not allowed"] with input as {"kind": "Service", "metadata": {"name": "sample"}} + warn["Found service sample but services are not allowed"] with input as { + "kind": "Service", + "metadata": { + "name": "sample" + } + } } diff --git a/examples/kubernetes/policy/deny.rego b/examples/kubernetes/policy/deny.rego index 8054693d76..4d49af9d89 100644 --- a/examples/kubernetes/policy/deny.rego +++ b/examples/kubernetes/policy/deny.rego @@ -2,7 +2,7 @@ package main import data.kubernetes -name = input.metadata.name +name := input.metadata.name deny[msg] { kubernetes.is_deployment diff --git a/examples/kubernetes/policy/labels.rego b/examples/kubernetes/policy/labels.rego index eb61790b9b..3dca213f22 100644 --- a/examples/kubernetes/policy/labels.rego +++ b/examples/kubernetes/policy/labels.rego @@ -2,7 +2,7 @@ package main import data.kubernetes -name = input.metadata.name +name := input.metadata.name required_deployment_labels { input.metadata.labels["app.kubernetes.io/name"] diff --git a/examples/kubernetes/policy/violation.rego b/examples/kubernetes/policy/violation.rego index d8be4b1789..2c1b8a4429 100644 --- a/examples/kubernetes/policy/violation.rego +++ b/examples/kubernetes/policy/violation.rego @@ -2,9 +2,9 @@ package main import data.kubernetes -name = input.metadata.name +name := input.metadata.name violation[{"msg": msg, "details": {}}] { kubernetes.is_deployment - msg = sprintf("Found deployment %s but deployments are not allowed", [name]) + msg := sprintf("Found deployment %s but deployments are not allowed", [name]) } diff --git a/examples/kubernetes/policy/warn.rego b/examples/kubernetes/policy/warn.rego index b2a5d5c4ce..8caeab2435 100644 --- a/examples/kubernetes/policy/warn.rego +++ b/examples/kubernetes/policy/warn.rego @@ -2,7 +2,7 @@ package main import data.kubernetes -name = input.metadata.name +name := input.metadata.name warn[msg] { kubernetes.is_service diff --git a/examples/properties/policy/test.rego b/examples/properties/policy/test.rego index 0d227cd508..f40f3ab0e4 100644 --- a/examples/properties/policy/test.rego +++ b/examples/properties/policy/test.rego @@ -1,17 +1,19 @@ package main deny_valid_uri[msg] { + some name value := input[name] contains(lower(name), "url") not contains(lower(value), "http") msg := sprintf("Must have a valid uri defined '%s'", [value]) } -secret_exceptions = { +secret_exceptions := { "secret.value.exception" } deny_no_secrets[msg] { + some name value := input[name] not secret_exceptions[name] contains(lower(name), "secret") diff --git a/examples/report/policy/labels.rego b/examples/report/policy/labels.rego index e50b8dc49d..a6ffba095d 100644 --- a/examples/report/policy/labels.rego +++ b/examples/report/policy/labels.rego @@ -1,6 +1,6 @@ package main -name = input.metadata.name +name := input.metadata.name required_deployment_labels { input.metadata.labels["app.kubernetes.io/name"] @@ -10,6 +10,7 @@ required_deployment_labels { deny[msg] { input.kind = "Deployment" not required_deployment_labels + # regal ignore:print-or-trace-call trace("just testing notes flag") msg := sprintf("%s must include Kubernetes recommended labels: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/#labels", [name]) } diff --git a/examples/report/policy_print/labels.rego b/examples/report/policy_print/labels.rego index d5663a59e1..3dc484486c 100644 --- a/examples/report/policy_print/labels.rego +++ b/examples/report/policy_print/labels.rego @@ -1,6 +1,6 @@ package main -name = input.metadata.name +name := input.metadata.name required_deployment_labels { input.metadata.labels["app.kubernetes.io/name"] @@ -8,7 +8,8 @@ required_deployment_labels { } deny[msg] { - input.kind = "Deployment" + input.kind == "Deployment" + # regal ignore:print-or-trace-call print(name) not required_deployment_labels msg := sprintf("%s must include Kubernetes recommended labels: https://kubernetes.io/docs/concepts/overview/working-with-objects/common-labels/#labels", [name]) diff --git a/examples/serverless/policy/base.rego b/examples/serverless/policy/base.rego index df85f00146..100c8c7454 100644 --- a/examples/serverless/policy/base.rego +++ b/examples/serverless/policy/base.rego @@ -6,6 +6,7 @@ deny[msg] { } runtime[name] { + some i input.functions[i].runtime = name } diff --git a/examples/serverless/policy/util.rego b/examples/serverless/policy/util.rego index 632ad6a69c..333ffa3797 100644 --- a/examples/serverless/policy/util.rego +++ b/examples/serverless/policy/util.rego @@ -11,7 +11,7 @@ has_field(object, field) { object[field] == false } -has_field(object, field) = false { +has_field(object, field) := false { not object[field] not object[field] == false } diff --git a/examples/spdx/policy/policy.rego b/examples/spdx/policy/policy.rego index b87cc2a492..87b83ce4af 100644 --- a/examples/spdx/policy/policy.rego +++ b/examples/spdx/policy/policy.rego @@ -1,7 +1,7 @@ package main deny[msg] { - expectedDataLicense := "conftest-demo" - input.CreationInfo.DataLicense != expectedDataLicense - msg := sprintf("DataLicense should be %d, but found %d", [expectedDataLicense, input.CreationInfo.DataLicense]) + expected_data_license := "conftest-demo" + input.CreationInfo.DataLicense != expected_data_license + msg := sprintf("DataLicense should be %d, but found %d", [expected_data_license, input.CreationInfo.DataLicense]) } diff --git a/examples/traefik/policy/base.rego b/examples/traefik/policy/base.rego index 66db014819..1380cfafdc 100644 --- a/examples/traefik/policy/base.rego +++ b/examples/traefik/policy/base.rego @@ -1,10 +1,10 @@ package main -disallowed_ciphers = ["TLS_RSA_WITH_AES_256_GCM_SHA384"] +disallowed_ciphers := ["TLS_RSA_WITH_AES_256_GCM_SHA384"] deny[msg] { check_trusted_ips(input.entryPoints.http.tls.cipherSuites, disallowed_ciphers) - msg = sprintf("Following ciphers are not allowed: %v", [disallowed_ciphers]) + msg := sprintf("Following ciphers are not allowed: %v", [disallowed_ciphers]) } check_trusted_ips(ciphers, denylist) { diff --git a/examples/traefik/policy/base_test.rego b/examples/traefik/policy/base_test.rego index a936aa6409..c7591f1996 100644 --- a/examples/traefik/policy/base_test.rego +++ b/examples/traefik/policy/base_test.rego @@ -1,5 +1,7 @@ package main test_ip_with_disallowed_ciphers { - deny["IPs should not use disallowed ciphers"] with input as {"entryPoints": {"http": {"tls": {"cipherSuites": ["TLS_RSA_WITH_AES_256_GCM_SHA384"]}}}} + deny["IPs should not use disallowed ciphers"] with input as { + "entryPoints": {"http": {"tls": {"cipherSuites": ["TLS_RSA_WITH_AES_256_GCM_SHA384"]}}} + } } diff --git a/examples/xml/policy/deny.rego b/examples/xml/policy/deny.rego index a0adf341db..cc8e73ca43 100644 --- a/examples/xml/policy/deny.rego +++ b/examples/xml/policy/deny.rego @@ -1,24 +1,29 @@ package main -plugin_list = input.project.build.plugins.plugin +plugin_list := input.project.build.plugins.plugin deny[msg] { expected_version := "3.6.1" + some i plugin_list[i].artifactId == "maven-compiler-plugin" not plugin_list[i].version = expected_version msg = sprintf("in %s \n--- maven-plugin must have the version: %s \n", [plugin_list[i], expected_version]) } deny[msg] { + some i plugin_list[i].artifactId == "activejdbc-instrumentation" not plugin_list[i].executions.execution.goals.goal = "instrument" - msg = sprintf("in %s \n--- There must be defined 'instrument goal' for activejdbc-instrumentation \n", [plugin_list[i]]) + msg = sprintf( + "in %s \n--- There must be defined 'instrument goal' for activejdbc-instrumentation \n", [plugin_list[i]] + ) } deny[msg] { expected_version := "2.18.1" + some i plugin_list[i].artifactId == "maven-surefire-plugin" not plugin_list[i].version = expected_version msg = sprintf("in %s \n--- Version must be %s for maven-surefire-plugin \n", [plugin_list[i], expected_version])