diff --git a/changelogs/fragments/86402-galaxy-fix-metadata-foldername-mismatch.yml b/changelogs/fragments/86402-galaxy-fix-metadata-foldername-mismatch.yml new file mode 100644 index 00000000000..d4249d439c2 --- /dev/null +++ b/changelogs/fragments/86402-galaxy-fix-metadata-foldername-mismatch.yml @@ -0,0 +1,10 @@ +bugfixes: + - >- + ``ansible-galaxy collection list`` - issue a warning when a collection's namespace and name do not match its + filepath. (https://github.com/ansible/ansible/issues/69813) + - >- + ``ansible-galaxy collection list|install`` - list collections based on reference (the fqcn used to refer to them in a + playbook), not based on their documented name. (https://github.com/ansible/ansible/issues/69813) + - >- + ``ansible-galaxy collection verify`` - fail collection verification when a collection's namespace and name + do not match its filepath. (https://github.com/ansible/ansible/issues/69813) diff --git a/lib/ansible/galaxy/collection/__init__.py b/lib/ansible/galaxy/collection/__init__.py index 433af9f5efa..8a5a96e712e 100644 --- a/lib/ansible/galaxy/collection/__init__.py +++ b/lib/ansible/galaxy/collection/__init__.py @@ -863,6 +863,11 @@ def verify_collections( local_collection = Candidate.from_dir_path( b_search_path, artifacts_manager, ) + + if local_collection.fqcn != collection.fqcn: + default_err = f"Collection at '{to_text(local_collection.src)}' documents incorrect FQCN '{local_collection.fqcn}'" + continue + supplemental_signatures = [ get_signature_from_source(source, display) for source in collection.signature_sources or [] @@ -1467,6 +1472,10 @@ def find_existing_collections(path_filter, artifacts_manager, namespace_filter=N display.warning(f'{val_err}') continue + if req.fqcn != '.'.join(pathlib.Path(to_text(req.src)).parts[-2:]): + display.warning(f"Collection at {to_text(req.src)} documents incorrect FQCN '{req.fqcn}'. Ignoring metadata.") + req = Candidate.from_dir_path_implicit(b_collection_path) + display.vvv( u"Found installed collection {coll!s} at '{path!s}'". format(coll=to_text(req), path=to_text(req.src)) diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/install.yml b/test/integration/targets/ansible-galaxy-collection/tasks/install.yml index 2de0f11f447..c86ca87b1e3 100644 --- a/test/integration/targets/ansible-galaxy-collection/tasks/install.yml +++ b/test/integration/targets/ansible-galaxy-collection/tasks/install.yml @@ -1152,6 +1152,60 @@ path: '{{ galaxy_dir }}/scratch/trailing_dir' state: absent +- name: test collection FQCN mismatch warning + block: + - name: create test collection install directory for FQCN mismatch test + file: + path: '{{ galaxy_dir }}/ansible_collections' + state: directory + + - name: Install a collection for FQCN mismatch test + command: ansible-galaxy collection install namespace1.name1 + environment: + ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections' + + - name: Create wrong namespace directory + file: + path: '{{ galaxy_dir }}/ansible_collections/wrongnamespace' + state: directory + + - name: Move the installed collection to a mismatched path + command: mv {{ galaxy_dir }}/ansible_collections/namespace1/name1 {{ galaxy_dir }}/ansible_collections/wrongnamespace/wrongname + + - name: Re-install the same collection to trigger path scanning + command: ansible-galaxy collection install namespace1.name1 + environment: + ANSIBLE_COLLECTIONS_PATH: '{{ galaxy_dir }}/ansible_collections' + register: second_install + + - name: Assert second install succeeded and warning was displayed + assert: + that: + - second_install is success + - expected_warning in second_install.stderr + - correct_name in second_install.stdout + - incorrect_name not in second_install.stdout + vars: + mismatched_path: "{{ galaxy_dir }}/ansible_collections/wrongnamespace/wrongname" + expected_warning: "Collection at {{ mismatched_path }} documents incorrect FQCN 'namespace1.name1'" + correct_name: 'namespace1.name1' + incorrect_name: 'wrongnamespace.wrongname' + + - name: Stat for collection paths + stat: + path: "{{ item }}" + loop: + - '{{ galaxy_dir }}/ansible_collections/namespace1/name1' + - '{{ galaxy_dir }}/ansible_collections/wrongnamespace/wrongname' + register: collection_paths + + - name: Assert both correct and incorrect collection directories exist + assert: + that: + - collection_paths.results[0].stat.exists and collection_paths.results[0].stat.isdir + - collection_paths.results[1].stat.exists and collection_paths.results[1].stat.isdir + + - name: remove collection dir after round of testing - {{ test_id }} file: path: '{{ galaxy_dir }}/ansible_collections' diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/list.yml b/test/integration/targets/ansible-galaxy-collection/tasks/list.yml index 595323b7823..11f9c9a253c 100644 --- a/test/integration/targets/ansible-galaxy-collection/tasks/list.yml +++ b/test/integration/targets/ansible-galaxy-collection/tasks/list.yml @@ -15,6 +15,64 @@ - 'prod.collection2' - 'prod.collection3' +- name: Check that list warns on improperly named directories + vars: + wrong_name: nottherightname + doc_fqcn: dev.collection1 + dir_fqcn: dev.{{ wrong_name }} + srcdir: "{{ galaxy_dir }}/dev/ansible_collections/dev/collection1" + destdir: "{{ galaxy_dir }}/dev/ansible_collections/dev/{{ wrong_name }}" + block: + - name: move dev.collection1 somewhere + command: mv {{ srcdir }} {{ destdir }} + + - name: List dev collections + command: ansible-galaxy collection list + register: errant_directory_list + environment: + ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev" + + - debug: var=errant_directory_list + - assert: + that: + - errant_directory_list is success + - errant_directory_list.rc == 0 + - warning_text in errant_directory_list.stderr + - dir_fqcn in errant_directory_list.stdout + vars: + warning_text: Collection at {{ destdir }} documents incorrect FQCN '{{ doc_fqcn }}' + + - name: List incorrect collection by metadataname + command: ansible-galaxy collection list {{ doc_fqcn }} + environment: + ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev" + register: list_metadata_name + + - assert: + that: + - list_metadata_name is success + - list_metadata_name.rc == 0 + - doc_fqcn not in list_metadata_name.stdout + + - name: List incorrect collection by dirname + command: ansible-galaxy collection list {{ dir_fqcn }} + environment: + ANSIBLE_COLLECTIONS_PATH: "{{ galaxy_dir }}/dev" + register: list_dir_name + + - assert: + that: + - list_dir_name is success + - list_dir_name.rc == 0 + - doc_fqcn not in list_dir_name.stdout + - dir_fqcn in list_dir_name.stdout + - warning_text in list_dir_name.stderr + vars: + warning_text: Collection at {{ destdir }} documents incorrect FQCN '{{ doc_fqcn }}' + + - name: move {{ doc_fqcn }} back + command: mv {{ destdir }} {{ srcdir }} + - name: replace the default version of the collections lineinfile: path: "{{ galaxy_dir }}/dev/ansible_collections/dev/{{ item.name }}/galaxy.yml" diff --git a/test/integration/targets/ansible-galaxy-collection/tasks/verify.yml b/test/integration/targets/ansible-galaxy-collection/tasks/verify.yml index 96c2245696e..72d782bc092 100644 --- a/test/integration/targets/ansible-galaxy-collection/tasks/verify.yml +++ b/test/integration/targets/ansible-galaxy-collection/tasks/verify.yml @@ -482,6 +482,43 @@ - verify.rc == 1 - '"Signature verification failed for ''namespace1.name1'': no successful signatures" in verify.stdout' +- name: check ansible-galaxy verify is using folder names not collection names + vars: + wrong_namespace: notmynamespace + wrong_name: notmyname + block: + - name: Give namespace1.name1 an incorrect namespace dir + command: mv {{ galaxy_dir }}/ansible_collections/namespace1 {{ galaxy_dir }}/ansible_collections/{{ wrong_namespace }} + + - name: Give namespace1.name1 an incorrect collection name dir + command: mv {{ galaxy_dir }}/ansible_collections/{{ wrong_namespace }}/name1 {{ galaxy_dir }}/ansible_collections/{{ wrong_namespace }}/{{ wrong_name }} + + - name: Verify namespace1.name after moving the incorrect collection name + command: ansible-galaxy collection verify namespace1.name1 --offline + register: verify_metadata_name + ignore_errors: true + + - assert: + that: + - verify_metadata_name is failed + - verify_metadata_name.rc != 0 + - error_message in verify_metadata_name.stderr + vars: + error_message: Collection namespace1.name1 is not installed in any of the collection paths + + - name: Verify {{ wrong_namespace }}.{{ wrong_name }} after moving the incorrect collection name + command: ansible-galaxy collection verify {{ wrong_namespace }}.{{ wrong_name }} --offline + register: verify_folder_name + ignore_errors: true + + - assert: + that: + - verify_metadata_name is failed + - verify_metadata_name.rc != 0 + - error_message in verify_folder_name.stderr + vars: + error_message: Collection at '{{ galaxy_dir }}/ansible_collections/{{ wrong_namespace }}/{{ wrong_name }}' documents incorrect FQCN 'namespace1.name1' + - name: empty installed collections file: path: "{{ galaxy_dir }}/ansible_collections"