diff --git a/antora/docs/modules/ROOT/pages/authoring.adoc b/antora/docs/modules/ROOT/pages/authoring.adoc index f4c550805..eb9881a5e 100644 --- a/antora/docs/modules/ROOT/pages/authoring.adoc +++ b/antora/docs/modules/ROOT/pages/authoring.adoc @@ -59,6 +59,16 @@ The https://conforma.dev/docs/cli/index.html[cli] is reponsible for gathering the information to be validated which is made available to policies via the `input` object. Its structure is defined https://conforma.dev/docs/cli/policy_input.html[here]. +== Regex pattern anchoring + +When writing regex patterns for rule data (e.g. `allowed_package_sources`, `allowed_external_references`, +`allowed_target_branch_patterns`, `disallowed_platform_patterns`), always anchor patterns with `^` and +where appropriate `$` to prevent unintended substring matches. + +For example, use `^https://console\.redhat\.com/.*` instead of `console\.redhat\.com`. + +Conforma will emit a warning when it detects unanchored patterns in rule data. + == Pitfalls Today, EC takes the https://www.conftest.dev/[conftest] approach for asserting violations and diff --git a/antora/docs/modules/ROOT/pages/packages/release_git_branch.adoc b/antora/docs/modules/ROOT/pages/packages/release_git_branch.adoc index a465d6ad2..39e7a6a1d 100644 --- a/antora/docs/modules/ROOT/pages/packages/release_git_branch.adoc +++ b/antora/docs/modules/ROOT/pages/packages/release_git_branch.adoc @@ -18,3 +18,13 @@ Build must target a configured branch pattern (e.g., 'c10s') * Code: `git_branch.git_branch` * Effective from: `2025-07-01T00:00:00Z` * https://github.com/conforma/policy/blob/{page-origin-refhash}/policy/release/git_branch/git_branch.rego#L16[Source, window="_blank"] + +[#git_branch__allowed_target_branch_patterns_format] +=== link:#git_branch__allowed_target_branch_patterns_format[allowed_target_branch_patterns format] + +Confirm the `allowed_target_branch_patterns` rule data uses anchored regex patterns. + +* Rule type: [rule-type-indicator failure]#FAILURE# +* FAILURE message: `%s` +* Code: `git_branch.allowed_target_branch_patterns_format` +* https://github.com/conforma/policy/blob/{page-origin-refhash}/policy/release/git_branch/git_branch.rego#L36[Source, window="_blank"] diff --git a/antora/docs/modules/ROOT/pages/packages/release_rpm_build_deps.adoc b/antora/docs/modules/ROOT/pages/packages/release_rpm_build_deps.adoc index c50967986..0b7e0658a 100644 --- a/antora/docs/modules/ROOT/pages/packages/release_rpm_build_deps.adoc +++ b/antora/docs/modules/ROOT/pages/packages/release_rpm_build_deps.adoc @@ -17,3 +17,13 @@ Builds have valid download locations for RPM build dependencies * WARNING message: `RPM build dependency source %s is not in the allowed list %v.` * Code: `rpm_build_deps.download_location_valid` * https://github.com/conforma/policy/blob/{page-origin-refhash}/policy/release/rpm_build_deps/rpm_build_deps.rego#L15[Source, window="_blank"] + +[#rpm_build_deps__allowed_rpm_build_dependency_sources_format] +=== link:#rpm_build_deps__allowed_rpm_build_dependency_sources_format[allowed_rpm_build_dependency_sources format] + +Confirm the `allowed_rpm_build_dependency_sources` rule data uses anchored regex patterns. + +* Rule type: [rule-type-indicator failure]#FAILURE# +* FAILURE message: `%s` +* Code: `rpm_build_deps.allowed_rpm_build_dependency_sources_format` +* https://github.com/conforma/policy/blob/{page-origin-refhash}/policy/release/rpm_build_deps/rpm_build_deps.rego#L40[Source, window="_blank"] diff --git a/antora/docs/modules/ROOT/pages/release_policy.adoc b/antora/docs/modules/ROOT/pages/release_policy.adoc index af50c437d..b2c2ec249 100644 --- a/antora/docs/modules/ROOT/pages/release_policy.adoc +++ b/antora/docs/modules/ROOT/pages/release_policy.adoc @@ -79,9 +79,11 @@ Rules included: * xref:packages/release_buildah_build_task.adoc#buildah_build_task__disallowed_platform_patterns_pattern[Buildah build task: disallowed_platform_patterns format] * xref:packages/release_cve.adoc#cve__rule_data_provided[CVE checks: Rule data provided] * xref:packages/release_external_parameters.adoc#external_parameters__pipeline_run_params_provided[External parameters: PipelineRun params provided] +* xref:packages/release_git_branch.adoc#git_branch__allowed_target_branch_patterns_format[Git branch checks: allowed_target_branch_patterns format] * xref:packages/release_github_certificate.adoc#github_certificate__rule_data_provided[GitHub Certificate Checks: Rule data provided] * xref:packages/release_labels.adoc#labels__rule_data_provided[Labels: Rule data provided] * xref:packages/release_olm.adoc#olm__required_olm_features_annotations_provided[OLM: Required OLM feature annotations list provided] +* xref:packages/release_rpm_build_deps.adoc#rpm_build_deps__allowed_rpm_build_dependency_sources_format[RPM Build Dependencies: allowed_rpm_build_dependency_sources format] * xref:packages/release_rpm_repos.adoc#rpm_repos__rule_data_provided[RPM Repos: Known repo id list provided] * xref:packages/release_rpm_signature.adoc#rpm_signature__rule_data_provided[RPM Signature: Rule data provided] * xref:packages/release_sbom_cyclonedx.adoc#sbom_cyclonedx__allowed_package_external_references[SBOM CycloneDX: Allowed package external references] @@ -276,9 +278,11 @@ Rules included: * xref:packages/release_attestation_type.adoc#attestation_type__known_attestation_types_provided[Attestation type: Known attestation types provided] * xref:packages/release_attestation_type.adoc#attestation_type__pipelinerun_attestation_found[Attestation type: PipelineRun attestation found] * xref:packages/release_git_branch.adoc#git_branch__git_branch[Git branch checks: Builds have a trusted target branch] +* xref:packages/release_git_branch.adoc#git_branch__allowed_target_branch_patterns_format[Git branch checks: allowed_target_branch_patterns format] * xref:packages/release_provenance_materials.adoc#provenance_materials__git_clone_source_matches_provenance[Provenance Materials: Git clone source matches materials provenance] * xref:packages/release_provenance_materials.adoc#provenance_materials__git_clone_task_found[Provenance Materials: Git clone task found] * xref:packages/release_rpm_build_deps.adoc#rpm_build_deps__download_location_valid[RPM Build Dependencies: Builds have valid download locations] +* xref:packages/release_rpm_build_deps.adoc#rpm_build_deps__allowed_rpm_build_dependency_sources_format[RPM Build Dependencies: allowed_rpm_build_dependency_sources format] * xref:packages/release_rpm_pipeline.adoc#rpm_pipeline__invalid_pipeline[RPM Pipeline: Task version invalid_pipeline] * xref:packages/release_rpm_repos.adoc#rpm_repos__ids_known[RPM Repos: All rpms have known repo ids] * xref:packages/release_rpm_repos.adoc#rpm_repos__rule_data_provided[RPM Repos: Known repo id list provided] diff --git a/antora/docs/modules/ROOT/partials/release_policy_nav.adoc b/antora/docs/modules/ROOT/partials/release_policy_nav.adoc index deeb5b14e..3ac28558e 100644 --- a/antora/docs/modules/ROOT/partials/release_policy_nav.adoc +++ b/antora/docs/modules/ROOT/partials/release_policy_nav.adoc @@ -41,6 +41,7 @@ **** xref:packages/release_external_parameters.adoc#external_parameters__restrict_shared_volumes[Restrict shared volumes] *** xref:packages/release_git_branch.adoc[Git branch checks] **** xref:packages/release_git_branch.adoc#git_branch__git_branch[Builds have a trusted target branch] +**** xref:packages/release_git_branch.adoc#git_branch__allowed_target_branch_patterns_format[allowed_target_branch_patterns format] *** xref:packages/release_github_certificate.adoc[GitHub Certificate Checks] **** xref:packages/release_github_certificate.adoc#github_certificate__gh_workflow_extensions[GitHub Workflow Certificate Extensions] **** xref:packages/release_github_certificate.adoc#github_certificate__gh_workflow_name[GitHub Workflow Name] @@ -93,6 +94,7 @@ **** xref:packages/release_rhtap_multi_ci.adoc#rhtap_multi_ci__attestation_found[SLSA Provenance Attestation Found] *** xref:packages/release_rpm_build_deps.adoc[RPM Build Dependencies] **** xref:packages/release_rpm_build_deps.adoc#rpm_build_deps__download_location_valid[Builds have valid download locations] +**** xref:packages/release_rpm_build_deps.adoc#rpm_build_deps__allowed_rpm_build_dependency_sources_format[allowed_rpm_build_dependency_sources format] *** xref:packages/release_rpm_packages.adoc[RPM Packages] **** xref:packages/release_rpm_packages.adoc#rpm_packages__unique_version[Unique Version] *** xref:packages/release_rpm_pipeline.adoc[RPM Pipeline] diff --git a/policy/lib/rule_data/rule_data.rego b/policy/lib/rule_data/rule_data.rego index 857d95575..380daab50 100644 --- a/policy/lib/rule_data/rule_data.rego +++ b/policy/lib/rule_data/rule_data.rego @@ -200,3 +200,14 @@ get(key_name) := value if { # If the key is not found, default to an empty list value := [] } + +# Returns warnings for patterns in the given rule data key that lack ^ anchoring. +anchoring_errors(key) := {error | + some pattern in get(key) + is_string(pattern) + not startswith(pattern, "^") + error := { + "message": sprintf("Pattern %q in %s is not anchored with ^", [pattern, key]), + "severity": "warning", + } +} diff --git a/policy/lib/sbom/sbom.rego b/policy/lib/sbom/sbom.rego index 0b9112611..851b63b69 100644 --- a/policy/lib/sbom/sbom.rego +++ b/policy/lib/sbom/sbom.rego @@ -422,6 +422,65 @@ rule_data_errors contains error if { } } +# Warn when external_references URL patterns lack ^ anchoring. +rule_data_errors contains error if { + some key in {rule_data_allowed_external_references_key, rule_data_disallowed_external_references_key} + some index, ref in rule_data.get(key) + pattern := object.get(ref, "url", "") + pattern != "" + not startswith(pattern, "^") + error := { + "message": sprintf("Pattern %q at index %d in %s is not anchored with ^", [pattern, index, key]), + "severity": "warning", + } +} + +# Warn when allowed_package_sources patterns lack ^ anchoring. +rule_data_errors contains error if { + some index, source in rule_data.get(rule_data_allowed_package_sources_key) + some pattern in source.patterns + is_string(pattern) + not startswith(pattern, "^") + error := { + "message": sprintf( + "Pattern %q at index %d in %s is not anchored with ^", + [pattern, index, rule_data_allowed_package_sources_key], + ), + "severity": "warning", + } +} + +# Warn when allowed_proxy_url_patterns lack ^ anchoring. +rule_data_errors contains error if { + some purl_type, patterns in rule_data.get("allowed_proxy_url_patterns") + some pattern in patterns + is_string(pattern) + not startswith(pattern, "^") + error := { + "message": sprintf( + "Pattern %q for PURL type %q in %s is not anchored with ^", + [pattern, purl_type, "allowed_proxy_url_patterns"], + ), + "severity": "warning", + } +} + +# Warn when disallowed_attributes except_when patterns lack ^ anchoring. +rule_data_errors contains error if { + some attr_index, attr in rule_data.get(rule_data_attributes_key) + some ew in object.get(attr, "except_when", []) + some pattern in ew.patterns + is_string(pattern) + not startswith(pattern, "^") + error := { + "message": sprintf( + "Pattern %q at index %d in %s except_when is not anchored with ^", + [pattern, attr_index, rule_data_attributes_key], + ), + "severity": "warning", + } +} + # disallowed_attribute_excepted checks if the package's PURL has a qualifier # matching an except_when condition, meaning the violation should be suppressed. disallowed_attribute_excepted(disallowed, purl_string) if { diff --git a/policy/release/buildah_build_task/buildah_build_task.rego b/policy/release/buildah_build_task/buildah_build_task.rego index 481c1c132..0138085e5 100644 --- a/policy/release/buildah_build_task/buildah_build_task.rego +++ b/policy/release/buildah_build_task/buildah_build_task.rego @@ -182,4 +182,8 @@ _rule_data_errors contains error if { } } +_rule_data_errors contains error if { + some error in rule_data.anchoring_errors(_plat_patterns_rule_data_key) +} + _plat_patterns_rule_data_key := "disallowed_platform_patterns" diff --git a/policy/release/buildah_build_task/buildah_build_task_test.rego b/policy/release/buildah_build_task/buildah_build_task_test.rego index bf5c9a72a..15b0ad80e 100644 --- a/policy/release/buildah_build_task/buildah_build_task_test.rego +++ b/policy/release/buildah_build_task/buildah_build_task_test.rego @@ -247,11 +247,20 @@ test_add_capabilities_param if { } test_platform_param_disallowed if { - # Test v1.0 attestation with disallowed platform pattern - expected := {{ - "code": "buildah_build_task.platform_param", - "msg": "PLATFORM parameter value \"linux-root/arm64\" is disallowed by regex \".*root.*\"", - }} + _anchoring_warning := { + "code": "buildah_build_task.disallowed_platform_patterns_pattern", + # regal ignore:line-length + "msg": "Pattern \".*root.*\" in disallowed_platform_patterns is not anchored with ^", + "severity": "warning", + } + + expected := { + { + "code": "buildah_build_task.platform_param", + "msg": "PLATFORM parameter value \"linux-root/arm64\" is disallowed by regex \".*root.*\"", + }, + _anchoring_warning, + } _task1_base := tekton_test.slsav1_task("buildah") _task1_w_params = tekton_test.with_params( @@ -297,7 +306,7 @@ test_platform_param_disallowed if { assertions.assert_equal_results(expected, buildah_build_task.deny) with input.attestations as [tekton_test.slsav1_attestation([task1])] with data.rule_data.disallowed_platform_patterns as [".*root.*"] - assertions.assert_empty(buildah_build_task.deny) with input.attestations as [tekton_test.slsav1_attestation([task2])] + assertions.assert_equal_results({_anchoring_warning}, buildah_build_task.deny) with input.attestations as [tekton_test.slsav1_attestation([task2])] with data.rule_data.disallowed_platform_patterns as [".*root.*"] } @@ -334,11 +343,37 @@ test_plat_patterns_rule_data_validation if { "msg": "\"(?=a)?b\" is not a valid regular expression in rego", "severity": "failure", }, + { + "code": "buildah_build_task.disallowed_platform_patterns_pattern", + # regal ignore:line-length + "msg": "Pattern \".*foo\" in disallowed_platform_patterns is not anchored with ^", + "severity": "warning", + }, + { + "code": "buildah_build_task.disallowed_platform_patterns_pattern", + # regal ignore:line-length + "msg": "Pattern \"(?=a)?b\" in disallowed_platform_patterns is not anchored with ^", + "severity": "warning", + }, } assertions.assert_equal_results(buildah_build_task.deny, expected) with data.rule_data as d } +test_plat_patterns_anchoring_warning if { + d_unanchored := {"disallowed_platform_patterns": ["linux/amd64"]} + expected_warn := {{ + "code": "buildah_build_task.disallowed_platform_patterns_pattern", + # regal ignore:line-length + "msg": "Pattern \"linux/amd64\" in disallowed_platform_patterns is not anchored with ^", + "severity": "warning", + }} + assertions.assert_equal_results(buildah_build_task.deny, expected_warn) with data.rule_data as d_unanchored + + d_anchored := {"disallowed_platform_patterns": ["^linux/amd64$"]} + assertions.assert_empty(buildah_build_task.deny) with data.rule_data as d_anchored +} + test_privileged_nested_param if { expected := {{ "code": "buildah_build_task.privileged_nested_param", diff --git a/policy/release/git_branch/git_branch.rego b/policy/release/git_branch/git_branch.rego index 97e0edc7d..8ddf1fd84 100644 --- a/policy/release/git_branch/git_branch.rego +++ b/policy/release/git_branch/git_branch.rego @@ -33,7 +33,27 @@ deny contains result if { result := metadata.result_helper(rego.metadata.chain(), [branch]) } +# METADATA +# title: allowed_target_branch_patterns format +# description: >- +# Confirm the `allowed_target_branch_patterns` rule data uses anchored regex patterns. +# custom: +# short_name: allowed_target_branch_patterns_format +# failure_msg: "%s" +# collections: +# - redhat_rpms +# - policy_data +# +deny contains result if { + some error in _rule_data_errors + result := metadata.result_helper_with_severity(rego.metadata.chain(), [error.message], error.severity) +} + matches_any(branch) if { some pattern in rule_data.get("allowed_target_branch_patterns") regex.match(pattern, branch) } + +_rule_data_errors contains error if { + some error in rule_data.anchoring_errors("allowed_target_branch_patterns") +} diff --git a/policy/release/git_branch/git_branch_test.rego b/policy/release/git_branch/git_branch_test.rego index 017869c3f..c5095b54e 100644 --- a/policy/release/git_branch/git_branch_test.rego +++ b/policy/release/git_branch/git_branch_test.rego @@ -17,7 +17,7 @@ single_test_case(branch, expected_results) if { "^rhel-10\\.[0-9]+$", "^rhel-[0-9]+\\.[0-9]\\.0$", "^rhel-[0-9]+-main$", - "branch[0-9]+-rhel-[0-9]+.[0-9]+.[0-9]+$", + "^.*branch[0-9]+-rhel-[0-9]+.[0-9]+.[0-9]+$", ] mock_tasks := mock_input.attestations[0].statement.predicate.buildConfig.tasks @@ -271,3 +271,17 @@ test_hotfix_branch_with_extra_suffix_denied if { }} single_test_case("kernel-5.14.0-570.42.1.el9_6-branch1-rhel-9.6.0-extra", expected) } + +test_anchoring_warning_unanchored_pattern if { + expected := {{ + "code": "git_branch.allowed_target_branch_patterns_format", + # regal ignore:line-length + "msg": "Pattern \"main\" in allowed_target_branch_patterns is not anchored with ^", + "severity": "warning", + }} + assertions.assert_equal_results(expected, git_branch.deny) with data.rule_data.allowed_target_branch_patterns as ["main"] +} + +test_anchoring_warning_anchored_pattern if { + assertions.assert_empty(git_branch.deny) with data.rule_data.allowed_target_branch_patterns as ["^main$"] +} diff --git a/policy/release/rpm_build_deps/rpm_build_deps.rego b/policy/release/rpm_build_deps/rpm_build_deps.rego index 1cb4d9276..8bcb454af 100644 --- a/policy/release/rpm_build_deps/rpm_build_deps.rego +++ b/policy/release/rpm_build_deps/rpm_build_deps.rego @@ -36,3 +36,23 @@ matches_any(branch, valid_locations) if { some pattern in valid_locations regex.match(pattern, branch) } + +# METADATA +# title: allowed_rpm_build_dependency_sources format +# description: >- +# Confirm the `allowed_rpm_build_dependency_sources` rule data uses anchored regex patterns. +# custom: +# short_name: allowed_rpm_build_dependency_sources_format +# failure_msg: "%s" +# collections: +# - redhat_rpms +# - policy_data +# +deny contains result if { + some error in _rule_data_errors + result := metadata.result_helper_with_severity(rego.metadata.chain(), [error.message], error.severity) +} + +_rule_data_errors contains error if { + some error in rule_data.anchoring_errors("allowed_rpm_build_dependency_sources") +} diff --git a/policy/release/rpm_build_deps/rpm_build_deps_test.rego b/policy/release/rpm_build_deps/rpm_build_deps_test.rego index 466cafc31..ff3a60a6c 100644 --- a/policy/release/rpm_build_deps/rpm_build_deps_test.rego +++ b/policy/release/rpm_build_deps/rpm_build_deps_test.rego @@ -160,6 +160,22 @@ test_matches_any_multiple_patterns if { rpm_build_deps.matches_any("https://codeload.github.com/user/repo/tar.gz/v1.0", patterns) } +test_anchoring_warning_unanchored_pattern if { + expected := {{ + "code": "rpm_build_deps.allowed_rpm_build_dependency_sources_format", + # regal ignore:line-length + "msg": "Pattern \"download.example.com\" in allowed_rpm_build_dependency_sources is not anchored with ^", + "severity": "warning", + }} + assertions.assert_equal_results(expected, rpm_build_deps.deny) with input.attestations as [_sbom_attestation_with_download_location("NOASSERTION")] + with data.rule_data.allowed_rpm_build_dependency_sources as ["download.example.com"] +} + +test_anchoring_warning_anchored_pattern if { + assertions.assert_empty(rpm_build_deps.deny) with input.attestations as [_sbom_attestation_with_download_location("NOASSERTION")] + with data.rule_data.allowed_rpm_build_dependency_sources as ["^https://download\\.example\\.com/.*"] +} + # Helper function to create SBOM attestation with specific download location _sbom_attestation_with_download_location(location) := {"statement": { "predicateType": "https://spdx.dev/Document", diff --git a/policy/release/sbom/sbom_test.rego b/policy/release/sbom/sbom_test.rego index 90d064ef4..5e4835541 100644 --- a/policy/release/sbom/sbom_test.rego +++ b/policy/release/sbom/sbom_test.rego @@ -261,6 +261,30 @@ test_rule_data_validation if { "msg": "Rule data disallowed_packages has unexpected format: 2.exceptions.0.subpath: Invalid type. Expected: string, given: integer", "severity": "failure", }, + { + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"example.com\" at index 0 in allowed_external_references is not anchored with ^", + "severity": "warning", + }, + { + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"badurl\" at index 0 in disallowed_external_references is not anchored with ^", + "severity": "warning", + }, + { + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"[\" at index 0 in allowed_package_sources is not anchored with ^", + "severity": "warning", + }, + { + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"[\" at index 8 in disallowed_attributes except_when is not anchored with ^", + "severity": "warning", + }, } assertions.assert_equal_results(sbom.deny, expected) with input.attestations as _sbom_attestation @@ -340,15 +364,123 @@ test_proxy_rule_data_validation if { "proxy_enabled_purl_types": [], "allowed_proxy_url_patterns": {"maven": ["(?=a)?b"]}, } - expected_bad_regex := {{ - "code": "sbom.disallowed_packages_provided", - "msg": "\"(?=a)?b\" is not a valid regular expression for PURL type \"maven\"", - "severity": "failure", - }} + expected_bad_regex := { + { + "code": "sbom.disallowed_packages_provided", + "msg": "\"(?=a)?b\" is not a valid regular expression for PURL type \"maven\"", + "severity": "failure", + }, + { + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"(?=a)?b\" for PURL type \"maven\" in allowed_proxy_url_patterns is not anchored with ^", + "severity": "warning", + }, + } assertions.assert_equal_results(expected_bad_regex, sbom.deny) with input.attestations as _sbom_attestation with data.rule_data as d_bad_regex } +test_anchoring_warnings_external_references if { + d := { + lib.sbom.rule_data_allowed_external_references_key: [ + {"type": "distribution", "url": "^https://example\\.com/.*"}, + {"type": "distribution", "url": "example.com"}, + ], + lib.sbom.rule_data_disallowed_external_references_key: [ + {"type": "vcs", "url": "^https://evil\\.com/.*"}, + {"type": "vcs", "url": "evil.com"}, + ], + } + + expected := { + { + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"example.com\" at index 1 in allowed_external_references is not anchored with ^", + "severity": "warning", + }, + { + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"evil.com\" at index 1 in disallowed_external_references is not anchored with ^", + "severity": "warning", + }, + } + + assertions.assert_equal_results(expected, sbom.deny) with input.attestations as _sbom_attestation + with data.rule_data as d +} + +test_anchoring_warnings_package_sources if { + d := {lib.sbom.rule_data_allowed_package_sources_key: [ + {"type": "generic", "patterns": ["^https://registry\\.example\\.com/.*"]}, + {"type": "generic", "patterns": ["registry.example.com"]}, + ]} + + expected := {{ + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"registry.example.com\" at index 1 in allowed_package_sources is not anchored with ^", + "severity": "warning", + }} + + assertions.assert_equal_results(expected, sbom.deny) with input.attestations as _sbom_attestation + with data.rule_data as d +} + +test_anchoring_warnings_proxy_url_patterns if { + d := {"allowed_proxy_url_patterns": { + "maven": ["^https://proxy\\.example\\.com/.*"], + "npm": ["proxy.example.com"], + }} + + expected := {{ + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"proxy.example.com\" for PURL type \"npm\" in allowed_proxy_url_patterns is not anchored with ^", + "severity": "warning", + }} + + assertions.assert_equal_results(expected, sbom.deny) with input.attestations as _sbom_attestation + with data.rule_data as d +} + +test_anchoring_warnings_except_when if { + d := {lib.sbom.rule_data_attributes_key: [{ + "name": "test_attr", + "value": "true", + "except_when": [{"purl_qualifier": "repo", "patterns": ["console\\.redhat\\.com"]}], + }]} + + expected := {{ + "code": "sbom.disallowed_packages_provided", + # regal ignore:line-length + "msg": "Pattern \"console\\\\.redhat\\\\.com\" at index 0 in disallowed_attributes except_when is not anchored with ^", + "severity": "warning", + }} + + assertions.assert_equal_results(expected, sbom.deny) with input.attestations as _sbom_attestation + with data.rule_data as d +} + +test_no_anchoring_warnings_when_anchored if { + d := { + lib.sbom.rule_data_allowed_external_references_key: [{"type": "distribution", "url": "^https://example\\.com/.*"}], + lib.sbom.rule_data_disallowed_external_references_key: [{"type": "vcs", "url": "^https://evil\\.com/.*"}], + lib.sbom.rule_data_allowed_package_sources_key: [{"type": "generic", "patterns": ["^https://registry\\.example\\.com/.*"]}], + "allowed_proxy_url_patterns": {"maven": ["^https://proxy\\.example\\.com/.*"]}, + lib.sbom.rule_data_attributes_key: [{ + "name": "test_attr", + "value": "true", + "except_when": [{"purl_qualifier": "repo", "patterns": ["^https://console\\.redhat\\.com/.*"]}], + }], + } + + assertions.assert_empty(sbom.deny) with input.attestations as _sbom_attestation + with data.rule_data as d +} + _sbom_attestation := [_spdx_sbom_attestation, _cyclonedx_sbom_attestation] _spdx_sbom_attestation := {"statement": {