From 9b5a1923ec1a91178f798c322c859f25a3318a9f Mon Sep 17 00:00:00 2001 From: zjhe Date: Fri, 24 Jan 2025 10:20:56 +0800 Subject: [PATCH] copy common.utils.rego file instead of using git submodule --- policy/common/common.utils.rego | 215 +++++++++++++++++- .../aws-infra-policy-as-code-with-terraform | 1 - 2 files changed, 214 insertions(+), 2 deletions(-) mode change 120000 => 100644 policy/common/common.utils.rego delete mode 160000 submodule/aws-infra-policy-as-code-with-terraform diff --git a/policy/common/common.utils.rego b/policy/common/common.utils.rego deleted file mode 120000 index 41704c9..0000000 --- a/policy/common/common.utils.rego +++ /dev/null @@ -1 +0,0 @@ -../../submodule/aws-infra-policy-as-code-with-terraform/policy-as-code/OPA/policy/common.utils.rego \ No newline at end of file diff --git a/policy/common/common.utils.rego b/policy/common/common.utils.rego new file mode 100644 index 0000000..f637eb8 --- /dev/null +++ b/policy/common/common.utils.rego @@ -0,0 +1,214 @@ +# Copy from https://github.com/aws-samples/aws-infra-policy-as-code-with-terraform/blob/main/policy-as-code/OPA/policy/common.utils.rego +package utils + +# Checks if action is create or update +# Common path: resource.change.actions +is_create_or_update(change_actions) { + change_actions[count(change_actions) - 1] == ["create", "update"][_] +} + +# Checks of resource is being created or updated +is_resource_create_or_update(resource) { + is_create_or_update(resource.change.actions) +} + +# Creates an array with all falsey values removed. +# The values false, null, 0, "", {} and [] are considered falsey. +compact(array) = output { + output := [value | + value := array[_] + not is_null(value) + not value == false + not value == "" + not value == 0 + not value == [] + not value == {} + ] +} + +# Checks if `match` value matches to all items in array. +every(array, match) { + count([value | + value := array[_] + value == match + ]) == count(array) +} else = false { + true +} + +# Gets the value at path of object. +get(object, path) = output { + [obj_path, value] = walk(object) + path_array := to_path(path) + obj_path == path_array + output := value +} + +# Gets the value at path of object. +# If the resolved value is undefined, +# the default_value is returned in its place. +get_or_default(object, path, default_value) = output { + output := get(object, path) +} else = output { + output := default_value +} + +# Checks if path exists on object +has(object, path) { + [obj_path, value] = walk(object) + obj_path == to_path(path) +} else = false { + true +} + +# Checks if value exists in array +includes(array, value) { + value == array[_] +} else = false { + true +} + +# Gets index of object in array that matches provided fraction object +index_by(array, fraction) = output { + some i + item = array[i] + is_fraction(item, fraction) + output := i +} else = output { + output := -1 +} + +# Gets index of value in array +index_of(array, value) = output { + some i + item = array[i] + item == value + output := i +} else = output { + output := -1 +} + +# Checks if value is null or false +is_null_or_false(value) { + is_null(value) +} else { + value == false +} else = false { + true +} + +# Checks if object matches fraction +is_fraction(object, fraction) { + search_keys = keys(fraction) + count({key | + key = search_keys[_] + object[key] == fraction[key] + }) == count(search_keys) +} else = false { + true +} + +# Gets the keys of object +keys(object) = output { + output := {key | + [path, value] = walk(object) + key := path[0] + } +} + +# Gets the size of collection +size(collection) = output { + is_string(collection) + output := count(collection) +} else = output { + output := count(keys(collection)) +} + +# Converts set to an array +to_array(set) = output { + output := [value | + value := set[_] + ] +} + +# Converts array to a set +to_set(array) = output { + output := {value | + value := array[_] + } +} + +_parse_array_index(value) = output { + contains(value, "[") + number_string := substring(value, 1, count(value) - 2) + output = try_to_number(number_string) +} else = output { + output = value +} + +# Converts string path to a path array +to_path(path) = output_array { + output_array := [value | + part := split(path, ".")[_] + value := _parse_array_index(part) + ] +} + +# Attempts to converts string to a number +try_to_number(string) = out { + out := to_number(string) +} else = out { + out := string +} + +is_resource_of_type(resource, service) { + resource.mode == "managed" + contains(resource.type, service) + resource.change.actions[count(resource.change.actions) - 1] != "delete" +} + +# Checks if service resource exists in the plan +find_service_resource(plan, service) = result { + result := [ x.address | x := plan.resource_changes[_]; is_resource_of_type(x, service)] +} + +# Checks if arrays is null or empty +is_array_null_or_empty(value) { + is_null(value) +} else { + size(value) = 0 +} else = false { + true +} + +# Check if an array contains specified value +contains_element(array, value) { + array[_] = value +} else = false { + true +} + +# find configuration entries for resource +find_configuration_resource(plan, resource) = cfgresource{ + # case where there is no module + not resource.module_address + some ssm_resource + plan.configuration.root_module.resources[ssm_resource].address == resource.address + cfgresource := plan.configuration.root_module.resources[ssm_resource] +} else = cfgresource{ + some ssm_resource + # case with module (or nested modules) + base_path := "configuration.root_module" + # get module_address and split with "." + module_address_list := split(resource.module_address, ".") + # list comprehention to keep only modules names not "module." entries + nested_module_path := [ path | module_address_list[i] != "module"; path := module_address_list[i] ] + # rebuild path for configuration section + temp_path := concat(".", [ path2 | nested_module_path[i] ; path2 := sprintf("module_calls.%s.module",[nested_module_path[i]])]) + temp_path2 := concat(".", [base_path, temp_path]) + + # search input object starting at root_module + myobj := data.utils.get(plan, temp_path2) + concat(".", [resource.module_address, myobj.resources[ssm_resource].address]) == resource.address + cfgresource := myobj.resources[ssm_resource] +} \ No newline at end of file diff --git a/submodule/aws-infra-policy-as-code-with-terraform b/submodule/aws-infra-policy-as-code-with-terraform deleted file mode 160000 index cffa57e..0000000 --- a/submodule/aws-infra-policy-as-code-with-terraform +++ /dev/null @@ -1 +0,0 @@ -Subproject commit cffa57e515d54dec65acba1d88ef0facd160c49b