From f4e2e206b3356c9b9fa94e8cbead1cdb88cede54 Mon Sep 17 00:00:00 2001 From: Felix Fontein Date: Tue, 24 Sep 2024 18:15:43 +0300 Subject: [PATCH] Add basic validation for action_groups (#83965) Co-authored-by: Sloane Hertel <19572925+s-hertel@users.noreply.github.com> --- .../fragments/83965-action-groups-schema.yml | 2 ++ .../ns/no_version/meta/runtime.yml | 21 ++++++++++++++ .../ns/version/meta/runtime.yml | 2 ++ .../expected-no_version.txt | 7 +++++ .../expected-version.txt | 1 + .../sanity/code-smell/runtime-metadata.py | 28 ++++++++++++++++++- 6 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 changelogs/fragments/83965-action-groups-schema.yml diff --git a/changelogs/fragments/83965-action-groups-schema.yml b/changelogs/fragments/83965-action-groups-schema.yml new file mode 100644 index 00000000000..cd4a439044d --- /dev/null +++ b/changelogs/fragments/83965-action-groups-schema.yml @@ -0,0 +1,2 @@ +minor_changes: + - "runtime-metadata sanity test - improve validation of ``action_groups`` (https://github.com/ansible/ansible/pull/83965)." diff --git a/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/no_version/meta/runtime.yml b/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/no_version/meta/runtime.yml index c27820e4afb..5db2a5b5aea 100644 --- a/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/no_version/meta/runtime.yml +++ b/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/no_version/meta/runtime.yml @@ -9,3 +9,24 @@ plugin_routing: tombstone: removal_version: 1.0.0 warning_text: Is no longer there. +action_groups: + foo: + - metadata: {} + - metadata: {} + bar: foo + baz: + bam: bar + bam: + - foo + - foo.bar + - foo.bar.bam + foobar: + - metadata: + extend_group: + - foo + - bar.baz + - foo.bar.baz + extra: indeed + foobarbam: + - metadata: + extend_group: 23 diff --git a/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/version/meta/runtime.yml b/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/version/meta/runtime.yml index 1c002e17dfb..3adbc20d84d 100644 --- a/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/version/meta/runtime.yml +++ b/test/integration/targets/ansible-test-sanity-runtime-metadata/ansible_collections/ns/version/meta/runtime.yml @@ -16,3 +16,5 @@ plugin_routing: tombstone: removal_version: 3.0.0 warning_text: Is no longer there. +action_groups: + - foo diff --git a/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-no_version.txt b/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-no_version.txt index ffe48a35cb9..ff7732f0fdd 100644 --- a/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-no_version.txt +++ b/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-no_version.txt @@ -1 +1,8 @@ +meta/runtime.yml:0:0: List must contain at most one dictionary for dictionary value @ data['action_groups']['foo']. Got [{'metadata': {}}, {'metadata': {}}] +meta/runtime.yml:0:0: Must be a FQCR or a short name @ data['action_groups']['bam'][1]. Got 'foo.bar' +meta/runtime.yml:0:0: Must be a FQCR or a short name @ data['action_groups']['foobar'][0]['metadata']['extend_group'][1]. Got 'bar.baz' +meta/runtime.yml:0:0: expected a list for dictionary value @ data['action_groups']['bar']. Got 'foo' +meta/runtime.yml:0:0: expected a list for dictionary value @ data['action_groups']['baz']. Got {'bam': 'bar'} +meta/runtime.yml:0:0: expected a list for dictionary value @ data['action_groups']['foobarbam'][0]['metadata']['extend_group']. Got 23 +meta/runtime.yml:0:0: extra keys not allowed @ data['action_groups']['foobar'][0]['metadata']['extra']. Got 'indeed' meta/runtime.yml:0:0: extra keys not allowed @ data['extra_key']. Got True diff --git a/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-version.txt b/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-version.txt index c3de212a642..9cab3f86c38 100644 --- a/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-version.txt +++ b/test/integration/targets/ansible-test-sanity-runtime-metadata/expected-version.txt @@ -1,2 +1,3 @@ meta/runtime.yml:0:0: The deprecation removal_version ('2.0.0') must be after the current version (SemanticVersion('2.3.4')) for dictionary value @ data['plugin_routing']['modules']['deprecated_module_wrong_version']['deprecation']['removal_version']. Got '2.0.0' meta/runtime.yml:0:0: The tombstone removal_version ('3.0.0') must not be after the current version (SemanticVersion('2.3.4')) for dictionary value @ data['plugin_routing']['modules']['tombstoned_module_wrong_version']['tombstone']['removal_version']. Got '3.0.0' +meta/runtime.yml:0:0: expected a dictionary for dictionary value @ data['action_groups']. Got ['foo'] diff --git a/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py b/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py index ad7d017767e..a3cfca0a97e 100644 --- a/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py +++ b/test/lib/ansible_test/_util/controller/sanity/code-smell/runtime-metadata.py @@ -6,6 +6,7 @@ import os import re import sys +from collections.abc import Sequence, Mapping from functools import partial import yaml @@ -29,6 +30,15 @@ def fqcr(value): return value +def fqcr_or_shortname(value): + """Validate a FQCR or a shortname.""" + if not isinstance(value, string_types): + raise Invalid('Must be a string that is a FQCR or a short name') + if '.' in value and not AnsibleCollectionRef.is_valid_fqcr(value): + raise Invalid('Must be a FQCR or a short name') + return value + + def isodate(value, check_deprecation_date=False, is_tombstone=False): """Validate a datetime.date or ISO 8601 date string.""" # datetime.date objects come from YAML dates, these are ok @@ -264,6 +274,22 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): list_dict_import_redirection_schema = [{str_type: import_redirection_schema} for str_type in string_types] + # action_groups schema + + def at_most_one_dict(value): + if isinstance(value, Sequence): + if sum(1 for v in value if isinstance(v, Mapping)) > 1: + raise Invalid('List must contain at most one dictionary') + return value + + metadata_dict = Schema({ + Required('metadata'): Schema({ + 'extend_group': [fqcr_or_shortname], + }, extra=PREVENT_EXTRA) + }, extra=PREVENT_EXTRA) + action_group_schema = All([metadata_dict, fqcr_or_shortname], at_most_one_dict) + list_dict_action_groups_schema = [{str_type: action_group_schema} for str_type in string_types] + # top level schema schema = Schema({ @@ -272,7 +298,7 @@ def validate_metadata_file(path, is_ansible, check_deprecation_dates=False): ('import_redirection'): Any(None, *list_dict_import_redirection_schema), # requires_ansible: In the future we should validate this with SpecifierSet ('requires_ansible'): Any(*string_types), - ('action_groups'): dict, + ('action_groups'): Any(*list_dict_action_groups_schema), }, extra=PREVENT_EXTRA) # Ensure schema is valid