Fix ansible-galaxy collection metadata/file system location discrepancy (#86402)

* Fix discrepancy between ansible-galaxy and ansible runtime when identifying usable collections

When enumerating usable collections, ansible-galaxy validates the galaxy metadata in the MANIFEST.json/galaxy.yml matches the collection path.

When the metadata is incorrect ansible-galaxy emits a warning and falls back to using no metadata since it is not required for usable collections.

* ansible-galaxy collection verify now evaluates the collection that will be used at runtime, even if a collection inaccurately documents the same namespace and name earlier in the search path

* Add integration tests for ansible-galaxy collection verify, list, and install
This commit is contained in:
Patrick Kingston 2026-02-02 17:17:36 -05:00 committed by GitHub
parent 20ce7d60bd
commit 1e31c7c819
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 168 additions and 0 deletions

View file

@ -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)

View file

@ -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))

View file

@ -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'

View file

@ -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"

View file

@ -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"