- Package:
- python3-apt
- Source:
- python3-apt
- Description:
- Python 3 interface to libapt-pkg
- Submitter:
- zzaimeche
- Date:
- 2026-10-22 11:05:02 UTC
- Severity:
- normal
The current code does not handle sources which include the 'signed-by' option. These are interpreted as invalid, although signed-by is listed as a valid option for ubuntu source lists here: https://manpages.ubuntu.com/manpages/focal/en/man5/sources.list.5.html . I'm not sure whether it's supported for debian or not, but I couldn't find a better place to report the issue, so hopefully this is the right place! :) When 'signed-by' is not recognised, it causes knock-on effects, for example when using salt to add repos to /etc/apt/sources.list, there will be duplicate entries. This is where the 'signed-by' parameter would need to be added: https://salsa.debian.org/apt-team/python-apt/-/blob/main/aptsources/sourceslist.py#L240 And below is a patch that has fixed the issue for us (it's a little old so we may need to adjust the line numbers, but the rest should be the same). Best Wishes, Zara @@ -, +, @@ --- aptsources/sourceslist.py | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) --- a/aptsources/sourceslist.py +++ a/aptsources/sourceslist.py @@ -92,6 +92,7 @@ class SourceEntry(object): self.type = "" # what type (deb, deb-src) self.architectures = [] # architectures self.trusted = None # Trusted + self.signed_by = "" # gpg self.uri = "" # base-uri self.dist = "" # distribution (dapper, edgy, etc) self.comps = [] # list of available componetns (may empty) @@ -198,6 +199,8 @@ class SourceEntry(object): self.architectures = value.split(",") elif key == "trusted": self.trusted = apt_pkg.string_to_bool(value) + elif key == "signed-by": + self.signed_by = value else: self.invalid = True @@ -239,13 +242,23 @@ class SourceEntry(object): line += self.type - if self.architectures and self.trusted is not None: - line += " [arch=%s trusted=%s]" % ( - ",".join(self.architectures), "yes" if self.trusted else "no") - elif self.trusted is not None: - line += " [trusted=%s]" % ("yes" if self.trusted else "no") - elif self.architectures: - line += " [arch=%s]" % ",".join(self.architectures) + repo_opts = {} + + if self.architectures: + repo_opts["arch"] = ",".join(self.architectures) + + if self.trusted is not None: + repo_opts["trusted"] = "yes" if self.trusted else "no" + + if self.signed_by: + repo_opts["signed-by"] = self.signed_by + + if repo_opts: + _opts_str = "" + for key in repo_opts: + _opts_str += "%s=%s " % (key, repo_opts[key]) + line += " [%s]" % _opts_str.strip() + line += " %s %s" % (self.uri, self.dist) if len(self.comps) > 0: line += " " + " ".join(self.comps) --
Hi, A further consequence of this bug: Ubuntu's release upgrader uses aptsources.sourceslist.SourceEntry to migrate one-line .list sources to deb822 .sources. Because [signed-by=...] lines parse as invalid, it cannot convert them. It writes them, commented out, to foo.list.disabled and removes them from foo.list (deleting the file, or leaving only its comment lines). apt then has no source for those packages. The upgrader logs this only at DEBUG level, and apt update and apt upgrade report nothing. signed-by is the recommended way to configure third-party repositories, so it is the correctly configured ones that get disabled. Seen on this machine during two release upgrades (to 26.04 and then 26.10). Excerpt from the upgrader's log (/var/log/dist-upgrade/main.log) for the 26.10 upgrade, timestamps removed: DEBUG Could not migrate deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main from /etc/apt/sources.list.d/google-cloud-sdk.list, disabling instead. DEBUG Could not migrate deb [signed-by=/usr/share/keyrings/tailscale-archive-keyring.gpg] https://pkgs.tailscale.com/stable/ubuntu resolute main from /etc/apt/sources.list.d/tailscale.list, disabling instead. The earlier upgrade to 26.04 disabled a third repository the same way (its .list.disabled file has the same header). Before that upgrade, dpkg.log shows its package being upgraded every few days. The last upgrade was the day before the release upgrade, and the next was 11 weeks later, after I restored the source by hand. Reproducer, on Ubuntu 26.10 with python3-apt 3.1.0ubuntu2: $ /usr/bin/python3 -c ' from aptsources.sourceslist import SourceEntry print(SourceEntry("deb [signed-by=/usr/share/keyrings/x.gpg] https://example.com/apt stable main").invalid) print(SourceEntry("deb [arch=amd64] https://example.com/apt stable main").invalid) print(SourceEntry("deb https://example.com/apt stable main").invalid) ' True False False [arch=] parses, but [signed-by=] does not. The upgrader acknowledges the cause in a comment in DistUpgrade/DistUpgradeController.py, migrateToDeb822Sources(), in ubuntu-release-upgrader 1:26.10.11: # It's possible that the source is considered invalid because python-apt # does not support [signed-by=] or something. For anything that we # cannot migrate, move it instead to <filename>.disabled. These will not # be cleaned up at the end of the upgrade. Fixing signed-by parsing in SourceEntry, along the lines of the patch already attached to this report, should let these entries migrate normally. The upgrader's handling of entries it cannot parse (removing them from the original file, logging only at DEBUG) is a separate Ubuntu issue. Versions (current, after the 26.10 upgrade): Ubuntu 26.10 (stonking) python3-apt 3.1.0ubuntu2 ubuntu-release-upgrader-core 1:26.10.11 apt 3.3.3 The 26.04 upgrade ran release-upgrader 26.04.22. Thanks, Ove Brynestad