From ba50e6a9197cdcd90185ad541525d98cbf308bdc Mon Sep 17 00:00:00 2001 From: Nikita Pivkin Date: Mon, 27 Jan 2025 14:13:08 +0600 Subject: [PATCH] ci: add lint for checks metadata Signed-off-by: Nikita Pivkin --- .regal/config.yaml | 2 + .../invalid-metadata/invalid_metadata.rego | 136 ++++++++++++++++++ .../invalid_metadata_test.rego | 40 ++++++ Makefile | 2 +- checks/cloud/aws/iam/no_policy_wildcards.rego | 2 +- ...apt_get_missing_no_install_recommends.rego | 1 - ...issing_yes_flag_to_avoid_manual_input.rego | 1 - .../general/manage_namespace_secrets.rego | 2 +- .../manage_webhook_configurations.rego | 2 +- .../baseline/6_apparmor_policy_disabled.rego | 2 +- 10 files changed, 183 insertions(+), 7 deletions(-) create mode 100644 .regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata.rego create mode 100644 .regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata_test.rego diff --git a/.regal/config.yaml b/.regal/config.yaml index 9d0f446d..126e3d2c 100644 --- a/.regal/config.yaml +++ b/.regal/config.yaml @@ -8,6 +8,8 @@ rules: - pattern: '^builtin|lib|defsec|appshield' targets: - package + invalid-metadata: + level: error naming: deny-rule: level: error diff --git a/.regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata.rego b/.regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata.rego new file mode 100644 index 00000000..60d8124d --- /dev/null +++ b/.regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata.rego @@ -0,0 +1,136 @@ +# METADATA +# description: | +# Ensures that metadata definitions adhere to the required schema by validating the following: +# - Ensure all necessary fields are present in metadata. +# - Detect and report any unexpected or forbidden fields. +# - Validate that field values are compliant with the expected format or constraints. +# schemas: +# - input: schema.regal.ast +package custom.regal.rules.custom["invalid-metadata"] + +import rego.v1 + +import data.regal.ast +import data.regal.result + +report contains _violation_check(lib_metadata_schema) if _is_lib_package + +report contains _violation_check(check_metadata_schema) if not _is_lib_package + +_is_lib_package if input["package"].path[1].value == "lib" + +_violation_check(schema) := violation if { + some annot in input["package"].annotations + annot.scope == "package" + + [match, errors] := json.match_schema(annot.custom, schema) + not match + + error_messages := [err.error | some err in errors] + + violation := result.fail( + rego.metadata.chain(), + object.union( + result.location(annot), + {"description": concat("\n", error_messages)}, + ), + ) +} + +lib_metadata_schema := { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "library": {"type": "boolean"}, + "input": input_schema, + }, + "required": ["library"], + "additionalProperties": false, +} + +check_metadata_schema := { + "$schema": "http://json-schema.org/draft-07/schema#", + "type": "object", + "properties": { + "id": {"type": "string"}, + "avd_id": {"type": "string"}, + "provider": {"type": "string"}, + "service": {"type": "string"}, + "short_code": {"type": "string"}, + "severity": { + "type": "string", + "enum": ["LOW", "MEDIUM", "HIGH", "CRITICAL"], + }, + "input": input_schema, + "frameworks": {"type": "object"}, + "deprecated": {"type": "boolean"}, + "examples": {"type": "string"}, + "aliases": { + "type": "array", + "items": {"type": "string"}, + }, + "cloud_formation": {"$ref": "#/$defs/engine_metadata"}, + "terraform": {"$ref": "#/$defs/engine_metadata"}, + "recommended_actions": {"type": "string"}, + "recommended_action": {"type": "string"}, + }, + "required": ["id", "avd_id"], + "additionalProperties": false, + "anyOf": [ + {"required": ["recommended_actions"]}, + {"required": ["recommended_action"]}, + {"not": {"required": ["recommended_actions", "recommended_action"]}}, + ], + "$defs": {"engine_metadata": { + "type": "object", + "properties": { + "good_examples": {"type": "string"}, + "bad_examples": {"type": "string"}, + "links": { + "type": "array", + "items": { + "type": "string", + "format": "uri", + }, + }, + }, + "additionalProperties": false, + }}, +} + +input_schema := { + "type": "object", + "properties": {"selector": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": {"type": "string"}, + "subtypes": { + "type": "array", + "items": { + "type": "object", + "oneOf": [ + { + "properties": {"kind": {"type": "string"}}, + "required": ["kind"], + "additionalProperties": false, + }, + { + "properties": { + "provider": {"type": "string"}, + "service": {"type": "string"}, + }, + "required": ["service", "provider"], + "additionalProperties": false, + }, + ], + }, + }, + }, + "required": ["type"], + "additionalProperties": false, + }, + }}, + "additionalProperties": false, +} diff --git a/.regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata_test.rego b/.regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata_test.rego new file mode 100644 index 00000000..06c9e5f2 --- /dev/null +++ b/.regal/rules/custom/regal/rules/custom/invalid-metadata/invalid_metadata_test.rego @@ -0,0 +1,40 @@ +package custom.regal.rules.custom["invalid-metadata_test"] + +import rego.v1 + +import data.custom.regal.rules.custom["invalid-metadata"] as rule + +test_invalid_metadata if { + module := regal.parse_module("example.rego", ` +# METADATA +# title: test title +# description: test description +# schemas: +# - input: schema["kubernetes"] +# custom: +# id: TEST-001 +# avdid: AVD-TEST-001 +# examples: test/ff.json +package policy + +foo := true`) + + r := rule.report with input as module + + r == {{ + "category": "custom", + "description": "(Root): avd_id is required\n(Root): Additional property avdid is not allowed", + "level": "error", + "location": { + "col": 1, + "end": { + "col": 27, + "row": 10, + }, + "file": "example.rego", + "row": 2, + "text": "# METADATA", + }, + "title": "invalid-metadata", + }} +} diff --git a/Makefile b/Makefile index 087b8980..590e6f85 100644 --- a/Makefile +++ b/Makefile @@ -23,7 +23,7 @@ test-rego: .PHONY: check-rego check-rego: - go run ./cmd/opa check lib checks --v0-v1 --strict + @go run ./cmd/opa check lib checks --v0-v1 --strict .PHONY: lint-rego lint-rego: check-rego diff --git a/checks/cloud/aws/iam/no_policy_wildcards.rego b/checks/cloud/aws/iam/no_policy_wildcards.rego index dff4b918..71b97f08 100644 --- a/checks/cloud/aws/iam/no_policy_wildcards.rego +++ b/checks/cloud/aws/iam/no_policy_wildcards.rego @@ -32,7 +32,7 @@ # - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document # good_examples: checks/cloud/aws/iam/no_policy_wildcards.yaml # bad_examples: checks/cloud/aws/iam/no_policy_wildcards.yaml -# cloudformation: +# cloud_formation: # good_examples: checks/cloud/aws/iam/no_policy_wildcards.yaml # bad_examples: checks/cloud/aws/iam/no_policy_wildcards.yaml package builtin.aws.iam.aws0057 diff --git a/checks/docker/apt_get_missing_no_install_recommends.rego b/checks/docker/apt_get_missing_no_install_recommends.rego index 19dc36c6..9e224452 100644 --- a/checks/docker/apt_get_missing_no_install_recommends.rego +++ b/checks/docker/apt_get_missing_no_install_recommends.rego @@ -7,7 +7,6 @@ # schemas: # - input: schema["dockerfile"] # custom: -# schema_version: 1 # id: DS029 # avd_id: AVD-DS-0029 # severity: HIGH diff --git a/checks/docker/apt_get_missing_yes_flag_to_avoid_manual_input.rego b/checks/docker/apt_get_missing_yes_flag_to_avoid_manual_input.rego index 9309caca..40e3d7b7 100644 --- a/checks/docker/apt_get_missing_yes_flag_to_avoid_manual_input.rego +++ b/checks/docker/apt_get_missing_yes_flag_to_avoid_manual_input.rego @@ -7,7 +7,6 @@ # schemas: # - input: schema["dockerfile"] # custom: -# schema_version: 1 # id: DS021 # avd_id: AVD-DS-0021 # severity: HIGH diff --git a/checks/kubernetes/general/manage_namespace_secrets.rego b/checks/kubernetes/general/manage_namespace_secrets.rego index 477357b5..b8af95d7 100644 --- a/checks/kubernetes/general/manage_namespace_secrets.rego +++ b/checks/kubernetes/general/manage_namespace_secrets.rego @@ -9,7 +9,7 @@ # custom: # id: KSV113 # avd_id: AVD-KSV-0113 -# severity: Medium +# severity: MEDIUM # short_code: no-manage-ns-secrets # recommended_actions: "Manage namespace secrets are not allowed. Remove resource 'secrets' from role" # input: diff --git a/checks/kubernetes/general/manage_webhook_configurations.rego b/checks/kubernetes/general/manage_webhook_configurations.rego index ec164049..8fcee4b0 100644 --- a/checks/kubernetes/general/manage_webhook_configurations.rego +++ b/checks/kubernetes/general/manage_webhook_configurations.rego @@ -9,7 +9,7 @@ # custom: # id: KSV114 # avd_id: AVD-KSV-0114 -# severity: Critical +# severity: CRITICAL # short_code: no-manage-webhook # recommended_actions: "Remove webhook configuration resouces/verbs, acceptable values for verbs ['get', 'list', 'watch']" # input: diff --git a/checks/kubernetes/pss/baseline/6_apparmor_policy_disabled.rego b/checks/kubernetes/pss/baseline/6_apparmor_policy_disabled.rego index 19dc5fb4..cf18833d 100644 --- a/checks/kubernetes/pss/baseline/6_apparmor_policy_disabled.rego +++ b/checks/kubernetes/pss/baseline/6_apparmor_policy_disabled.rego @@ -9,7 +9,7 @@ # custom: # id: KSV002 # avd_id: AVD-KSV-0002 -# severity: Low +# severity: LOW # short_code: use-default-apparmor-profile # recommended_action: "set the 'runtime/default' value from 'container.apparmor.security.beta.kubernetes.io'." # input: