Dear Maintainer,
This is the underlying fix for Debian bug #1038747[1]. That bug is currently
filed against software-properties, but the actual defect lives in python3-apt:
aptsources.distro.Distribution.change_server() rewrites *every* child source's
URI onto the newly selected main mirror. On Debian that is wrong for the
security archive, which is a SEPARATE archive (deb.debian.org/debian-security)
rather than a pocket of the main archive (as it is on Ubuntu).
Root cause
----------
In aptsources/distro.py, change_server() does (for child sources):
if (source.template.base_uri is None
or source.template.base_uri != source.uri):
change_server_of_source(source, uri, seen_binary)
This replaces the whole child URI with the main mirror URI. For a Debian
security source the template's base_uri is security.debian.org while the
source URI is deb.debian.org/debian-security; the old guard only skips the
source when base_uri already equals the current URI, so the security source
is moved to <mirror>/debian/<suite>-security, which does not exist.
Result: after changing the download mirror in the "Software & Updates" GUI,
`apt update` fails with
E: The repository 'https://deb.debian.org/debian bookworm-security
Release' does not have a Release file.
and the entire security-update channel is disabled. The deb-src counterpart
is affected the same way via the source_code_sources loop.
Fix
---
Introduce an `_archive_root()` helper (host + first path segment) and a
`separate_archive()` predicate that compares the child source's template
base_uri against the main archive's base_uri. Child sources (and their
deb-src siblings) that live on a separate archive are left untouched when the
main download server is changed, while same-archive children such as
*-updates keep following the mirror. Ubuntu behaviour is unchanged because
its -security shares the main archive.
Verification
------------
I reproduced the bug and confirmed the fix on a current Debian sid container
(python3-apt 3.1.0). The attached hermetic test(AI generated) drives
change_server()
directly with an in-memory Debian sid source set (no /etc/apt access, no
network):
BEFORE (unpatched 3.1.0):
main -> http://ftp.hu.debian.org/debian/ (follows mirror, ok)
security -> http://ftp.hu.debian.org/debian/ (WRONG:
moved off debian-security)
security-src -> http://ftp.hu.debian.org/debian/ (WRONG)
RESULT: FAIL
AFTER (patched):
main -> http://ftp.hu.debian.org/debian/ (follows mirror, ok)
security -> http://deb.debian.org/debian-security (kept)
security-src -> http://deb.debian.org/debian-security (kept)
RESULT: PASS
The patch below applies cleanly to sid's 3.1.0.
Kind regards,
Emfox Zhou
[1] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1038747