diff --git a/.github/workflows/pull-request.yaml b/.github/workflows/pull-request.yaml index 868d129123..abe6d5dfb5 100644 --- a/.github/workflows/pull-request.yaml +++ b/.github/workflows/pull-request.yaml @@ -287,11 +287,11 @@ jobs: uses: infracost/setup-opa@v1 - name: Test policies - run: opa test .github/policy + run: opa test build/policy - name: Run policy checks on changed files run: | curl --silent --fail --header 'Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}' \ https://api.github.com/repos/${{ github.repository }}/pulls/${{ github.event.pull_request.number }}/files \ - | opa eval --data .github/policy/files.rego --format values --stdin-input --fail-defined 'data.files.deny[message]' + | opa eval --bundle build/policy/ --format values --stdin-input --fail-defined 'data.files.deny[message]' diff --git a/.github/policy/files.rego b/build/policy/files.rego similarity index 60% rename from .github/policy/files.rego rename to build/policy/files.rego index 5ab9a3cbab..9aa6dc2fdf 100644 --- a/.github/policy/files.rego +++ b/build/policy/files.rego @@ -9,14 +9,19 @@ package files import future.keywords.in -filenames := [f | f := input[_].filename] +import data.helpers.endswith_any +import data.helpers.last_indexof + +filenames := {f.filename | some f in input} changes := {filename: attributes | - c := input[_] - filename := c.filename - attributes := object.remove(c, ["filename"]) + some change in input + filename := change.filename + attributes := object.remove(change, ["filename"]) } +get_file_in_pr(filename) = http.send({"url": changes[filename].raw_url, "method": "GET"}).raw_body + deny["Logo must be placed in docs/website/static/img/logos/integrations"] { "docs/website/data/integrations.yaml" in filenames @@ -37,10 +42,14 @@ deny["Logo must be a .png file"] { not endswith(filename, ".png") } -last_indexof(string, search) = i { - all := [i | chars := split(string, ""); chars[i] == search] - count(all) > 0 - i := all[count(all) - 1] -} else = -1 { - true +# Helper rule to work around not being able to mock functions yet +yaml_file_contents := {filename: get_file_in_pr(filename) | + some filename in filenames + endswith_any(filename, [".yml", ".yaml"]) +} + +deny[sprintf("%s is an invalid YAML file", [filename])] { + some filename, content in yaml_file_contents + changes[filename].status in {"added", "modified"} + not yaml.is_valid(content) } diff --git a/.github/policy/files_test.rego b/build/policy/files_test.rego similarity index 69% rename from .github/policy/files_test.rego rename to build/policy/files_test.rego index 266813fe3b..65e596dccf 100644 --- a/.github/policy/files_test.rego +++ b/build/policy/files_test.rego @@ -42,3 +42,14 @@ test_deny_logo_if_not_png_file { }, ] } + +test_deny_invalid_yaml_file { + expected := "invalid.yaml is an invalid YAML file" + deny[expected] with data.files.yaml_file_contents as {"invalid.yaml": "{null{}}"} + with data.files.changes as {"invalid.yaml": {"status": "modified"}} +} + +test_allow_valid_yaml_file { + count(deny) == 0 with data.files.yaml_file_contents as {"valid.yaml": "foo: bar"} + with data.files.changes as {"valid.yaml": {"status": "modified"}} +} diff --git a/build/policy/helpers.rego b/build/policy/helpers.rego new file mode 100644 index 0000000000..f7bc945191 --- /dev/null +++ b/build/policy/helpers.rego @@ -0,0 +1,16 @@ +package helpers + +import future.keywords.in + +last_indexof(string, search) = i { + all := [i | chars := split(string, ""); chars[i] == search] + count(all) > 0 + i := all[count(all) - 1] +} else = -1 { + true +} + +endswith_any(string, suffixes) { + some suffix in suffixes + endswith(string, suffix) +} diff --git a/docs/website/data/integrations.yaml b/docs/website/data/integrations.yaml index 4ff65e5fa8..8fc5ad358e 100644 --- a/docs/website/data/integrations.yaml +++ b/docs/website/data/integrations.yaml @@ -108,7 +108,6 @@ integrations: - name: Joe Beda organization: VMware link: https://www.youtube.com/watch?v=QU9BGPf0hBw - blogs: - https://medium.com/@sbueringer/kubernetes-authorization-via-open-policy-agent-a9455d9d5ceb - https://medium.com/@jimmy.ray/policy-enabled-kubernetes-with-open-policy-agent-3b612b3f0203 @@ -123,9 +122,14 @@ integrations: Kubernetes Authorization is a pluggable mechanism that lets administrators control which users can run which APIs and is often handled by builtin RBAC. OPA's policy language is more flexible than the RBAC, for example, writing policy using a prohibited list of APIs instead of the usual RBAC style of listing the permitted APIs. + code: + - https://github.com/open-policy-agent/contrib/tree/main/k8s_authorization blogs: + - https://blog.styra.com/blog/kubernetes-authorization-webhook - https://itnext.io/kubernetes-authorization-via-open-policy-agent-a9455d9d5ceb - https://itnext.io/optimizing-open-policy-agent-based-kubernetes-authorization-via-go-execution-tracer-7b439bb5dc5b + inventors: + - styra kubernetes-provisioning: title: Kubernetes Provisioning @@ -314,7 +318,6 @@ integrations: venue: Kubecon Austin 2017 link: https://www.youtube.com/watch?v=R6tUNpRpdnY - istio-authorization-edge: title: Container Network Authorization with Istio (at the Edge) description: Istio is a networking abstraction for cloud-native applications that uses Envoy at the edge. OPA hooks into Envoy’s external authorization filter to provide fine-grained, context-aware authorization for network or HTTP requests. @@ -470,6 +473,19 @@ integrations: inventors: - styra + open-service-mesh: + title: Open Service Mesh (OSM) + description: Open Service Mesh is a lightweight and extensible cloud native service mesh. + software: + - osm + labels: + category: servicemesh + layer: network + code: + - https://github.com/openservicemesh/osm/blob/main/docs/example/manifests/opa/deploy-opa-envoy.yaml + tutorials: + - https://release-v0-11.docs.openservicemesh.io/docs/guides/integrations/external_auth_opa/#osm-with-opa-plugin-external-authorization-walkthrough + minio: title: Minio API Authorization description: Minio is an open source, on-premise object database compatible with the Amazon S3 API. This integration lets OPA enforce policies on Minio's API. @@ -931,6 +947,8 @@ integrations: software: - SPIFFE - SPIRE + blogs: + - https://blog.styra.com/blog/zero-trust-with-envoy-spire-and-open-policy-agent-opa code: - https://github.com/spiffe/spire/blob/v1.0.2/doc/authorization_policy_engine.md tutorials: @@ -1199,6 +1217,9 @@ software: javaspringsecurity: name: Spring Security link: https://spring.io/projects/spring-security + osm: + name: Open Service Mesh + link: https://openservicemesh.io/ spinnaker: name: Spinnaker link: https://www.spinnaker.io/ diff --git a/docs/website/static/img/logos/integrations/open-service-mesh.png b/docs/website/static/img/logos/integrations/open-service-mesh.png new file mode 100644 index 0000000000..9d9e306617 Binary files /dev/null and b/docs/website/static/img/logos/integrations/open-service-mesh.png differ