Debian packages conventionally target 'unstable' in their
debian/changelog distribution field, but the series data (the
distro-info CSVs) only knows codenames: the suite is the alias
'unstable' of the series 'sid', a mapping the debian-distro-info tool
resolves internally without exposing it in its data.
Add a per-dist suite_aliases reference-data key (debian: unstable ->
sid), with two helpers on top: resolve_suite_alias, identifying a
changelog suite name with its series codename and the dist that
codename belongs to, and series_suite_alias, the inverse direction.
The two names identify the same series.
--backport was Debian-only: ~bpo is backports.debian.org's scheme and
its number the Debian release, so Ubuntu targets were rejected outright.
Ubuntu backports have their own documented scheme (Ubuntu version-
strings): the development release's version with a per-release ~YY.MM.1
appended, sorting before it (3.1-1ubuntu2 backported to 22.04 becomes
3.1-1ubuntu2~22.04.1; native 3.1 becomes 3.1~22.04.1) and independent of
the version the target release carries. The .N increments for
subsequent per-release SRU uploads.
backport_series_number becomes backport_suffix_for_series: the release
number comes from the new generic get_series_release_number (version
column of the target series' own distro-info data, leading token kept —
"12" for bookworm, "26.04" out of resolute's "26.04 LTS"; empty column
as on sid/experimental means None), and the suffix is picked per vendor:
~bpoNN+ for Debian (plain integer releases only), ~YY.MM. for Ubuntu.
Unnumbered series still error before anything is written.
Also serialize the changelog tests that mutate the process-global
DEBFULLNAME/DEBEMAIL variables behind a tokio Mutex: run in parallel
they raced each other's identity reads, which started failing
intermittently as generate_entry tests accumulated.
Busy mirrors and CDNs routinely break bulk fetches: pooled keep-alive
connections get closed remotely ('error sending request'), downloads are
cut short (surfacing as bogus checksum mismatches), and index generations
momentarily drift from the Release file fetched moments before.
- shared client: short idle-pool timeout and TCP keepalive, and a
bounded-retry GET helper now used for index, Release, keyring and
Launchpad fetches (previously reqwest::get, which has no timeouts)
- downloads: retry the whole download, and check the content length so
truncation is reported as such instead of a checksum mismatch
- sources index: on a checksum mismatch against the Release file, retry
pinned to the exact listed generation via Debian's by-hash mechanism;
body-read errors are retried and reported per component instead of
aborting the whole lookup
Upload built source packages over SFTP with host-key verification
(Launchpad fingerprints pinned in host_keys.yml, ask-to-accept
otherwise), Launchpad account discovery (git config lp.user), and
pre-flight checks the upload queue itself never does: changes file
discovery/validation, PPA existence via the Launchpad API, target
series validity, and debian/control Section validity (sections
bundled in distro_info.yml). Upload log prevents duplicate uploads
unless --force.
- distro_info: malformed CSV rows are skipped with a warning, dates
that fail to parse become None, and all plain HTTP requests go
through a shared reqwest client with connect/total timeouts
- package_info: the Sources stanza iterator is iterative (a crafted
index with many blank stanzas overflowed the stack), stanzas missing
a Version are skipped, and failed series/pocket probes are summarized
in the final 'not found' error instead of being silently dropped
- pull: no double unwrap on the remote-derived artifact filename, an
empty series list is an error, and streaming downloads get a
per-request timeout
- deb/cross: dpkg-architecture output parsing skips unexpected lines
and its exit status is checked, as is dpkg --add-architecture
- changelog: version increments parse as u64 with checked arithmetic
(1.0-20250123123456 used to panic on the u32 parse)
Without an explicit --pocket, find_package stops at the first pocket
containing the package, but the search order listed '-proposed' first
and never included '-security': unreleased proposed packages won by
default and security-only updates were unreachable. Search the main
archive first, then updates, security, and proposed last.
The Sources index was downloaded with no authentication: per-artifact
checksums were verified, but against hashes taken from an index a MITM
could substitute along with the artifacts. Fetch each suite's InRelease
(or Release + Release.gpg), verify the signature with gpgv against the
archive keyring (or the PPA signing key) the same way apt does, and
checksum-check every Sources index against it before parsing.
Distro archives and PPAs verify strictly: an invalid or unverifiable
signature, or a missing gpgv binary, is a hard error. Flat repositories
keep working without a Release file or without a verifiable one (warned
as unauthenticated), but tampering evidence is a hard error there too.
Also switches all archive, PPA and keyring base URLs to https, and
reads suite components from the verified Release instead of fetching
them separately over an unauthenticated channel.