deb822_repository: validate name parameter instead of over-normalizing (#86494)

* deb822_repository: validate name parameter instead of over-normalizing

The deb822_repository module was silently mangling the name parameter by converting to lowercase, replacing underscores with hyphens, and removing other characters. This caused filename collisions where distinct repository names produced identical filenames.

This change validates that the name parameter contains only valid APT sources.list filename characters (a-zA-Z0-9_.-) and preserves the name as-is. Invalid characters now result in a clear error message.

Fixes: #86243

* fix: update install.yml test to use valid name without spaces

* deb822_repository: add backward compatibility for legacy filenames

Check if a file with the old normalized naming convention already exists before using the new naming. If a legacy file exists, reuse that slug to avoid creating duplicate files for the same repository.

This addresses feedback from #86343 to maintain backward compatibility.

* deb822_repository: adopt PR #86343 approach for backward compatibility

Based on maintainer feedback, removed strict validation that hard-failed on invalid characters. Instead:

- Convert spaces to hyphens (backward compatible with existing playbooks)

- Preserve case, underscores, and periods

- Check for legacy-normalized files and reuse them if they exist

This maintains backward compatibility while still avoiding over-normalization.

Addresses feedback from https://github.com/ansible/ansible/pull/86494#discussion_r1975816493

* Replicate PR #86343 structure and fix trailing whitespace

- Created name_handling.yml with exact tests from #86343

- Import name_handling.yml in main.yml

- Removed conflicting tests from test.yml

- Updated changelog to match #86343 format

- Fixed trailing whitespace on line 584 (pep8/pylint fix)

* Apply suggested change: inline name.replace() directly
This commit is contained in:
Mohammed Saalim K 2026-02-03 09:21:45 -06:00 committed by GitHub
parent 1e31c7c819
commit 2f621c95fd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 83 additions and 19 deletions

View file

@ -0,0 +1,4 @@
bugfixes:
- deb822_repository no longer over-normalizes repository names when generating
sources list filenames, preventing collisions for names that differ by case,
underscores, or dots (https://github.com/ansible/ansible/issues/86243)

View file

@ -572,15 +572,20 @@ def main():
params.pop('install_python_debian')
name = params['name']
slug = re.sub(
# Generate legacy-normalized slug for backward compatibility check
legacy_slug = re.sub(
r'[^a-z0-9-]+',
'',
re.sub(
r'[_\s]+',
'-',
name.lower(),
),
re.sub(r'[_\s]+', '-', name.lower()),
)
legacy_sources = make_sources_filename(legacy_slug)
if os.path.exists(legacy_sources):
# Legacy file exists, reuse the old naming to maintain consistency
slug = legacy_slug
else:
# No legacy file, use the new naming convention
slug = name.replace(' ', '-')
sources_filename = make_sources_filename(slug)
if state == 'absent':

View file

@ -1,6 +1,6 @@
- name: Create repo to install from
deb822_repository:
name: ansible-test local
name: ansible-test-local
uris: file:{{ repodir }}
suites:
- stable
@ -31,7 +31,7 @@
- name: remove repo
deb822_repository:
name: ansible-test local
name: ansible-test-local
state: absent
- block:

View file

@ -183,7 +183,7 @@
state: absent
- import_tasks: test.yml
- import_tasks: name_handling.yml
- import_tasks: install.yml
always:
- name: uninstall python3-debian

View file

@ -0,0 +1,55 @@
---
- name: Add repositories with distinct valid names
ansible.builtin.deb822_repository:
state: present
name: "{{ item }}"
types: [deb]
uris: ["http://example.invalid/repo"]
suites: ["stable"]
components: [main]
loop:
- foo-1.2.3
- foo_123
- FOO_1.23
- name: Verify each sources file exists
stat:
path: "/etc/apt/sources.list.d/{{ item }}.sources"
loop:
- foo-1.2.3
- foo_123
- FOO_1.23
register: repo_files
- name: Assert all sources files exist
assert:
that:
- repo_files.results | map(attribute='stat.exists') | min
- name: Add repository with space in name
ansible.builtin.deb822_repository:
state: present
name: "foo 12.3"
types: [deb]
uris: ["http://example.invalid/repo"]
suites: ["stable"]
components: [main]
register: spaced_name_result
- name: Assert repo creation succeeded
assert:
that:
- spaced_name_result is changed
- name: Verify sources file normalized with dash
stat:
path: /etc/apt/sources.list.d/foo-12.3.sources
register: spaced_name_stat
- name: Assert normalized sources file exists
assert:
that:
- spaced_name_stat.stat.exists
- name: Clean up test repositories
ansible.builtin.deb822_repository:
name: "{{ item }}"
state: absent
loop:
- foo-1.2.3
- foo_123
- FOO_1.23
- foo 12.3

View file

@ -1,6 +1,6 @@
- name: Create deb822 repo - check_mode
deb822_repository:
name: ansible-test focal archive
name: ansible-test-focal-archive
uris: http://us.archive.ubuntu.com/ubuntu
suites:
- focal
@ -13,7 +13,7 @@
- name: Create deb822 repo
deb822_repository:
name: ansible-test focal archive
name: ansible-test-focal-archive
uris: http://us.archive.ubuntu.com/ubuntu
suites:
- focal
@ -31,7 +31,7 @@
- name: Create another deb822 repo
deb822_repository:
name: ansible-test focal security
name: ansible-test-focal-security
uris: http://security.ubuntu.com/ubuntu
suites:
- focal-security
@ -42,7 +42,7 @@
- name: Create deb822 repo idempotency
deb822_repository:
name: ansible-test focal archive
name: ansible-test-focal-archive
uris: http://us.archive.ubuntu.com/ubuntu
suites:
- focal
@ -56,7 +56,7 @@
- name: Create deb822 repo (changed order of parameters) idempotency
deb822_repository:
uris: http://us.archive.ubuntu.com/ubuntu
name: ansible-test focal archive
name: ansible-test-focal-archive
date_max_future: 10
components:
- main
@ -68,7 +68,7 @@
- name: Create deb822 repo - check_mode
deb822_repository:
name: ansible-test focal archive
name: ansible-test-focal-archive
uris: http://us.archive.ubuntu.com/ubuntu
suites:
- focal
@ -82,7 +82,7 @@
- name: Change deb822 repo mode
deb822_repository:
name: ansible-test focal archive
name: ansible-test-focal-archive
uris: http://us.archive.ubuntu.com/ubuntu
suites:
- focal
@ -119,7 +119,7 @@
focal_archive_expected: |-
Components: main restricted
Date-Max-Future: 10
X-Repolib-Name: ansible-test focal archive
X-Repolib-Name: ansible-test-focal-archive
Suites: focal focal-updates
Types: deb
URIs: http://us.archive.ubuntu.com/ubuntu
@ -130,8 +130,8 @@
state: absent
register: remove_repos_1
loop:
- ansible-test focal archive
- ansible-test focal security
- ansible-test-focal-archive
- ansible-test-focal-security
- name: Check for repo files
stat: