You type apt install nginx, watch some text scroll past, and have a web server. Between those two moments sit eight stages, two entirely different trust models, and one asymmetry that decides whether a failure leaves your machine untouched or half-modified.

This page goes underneath how packages and dependencies work, which covers what a repository is and why versions matter. This one follows a single install through the machinery, and it covers both families throughout — because the most useful facts in the whole subject are differences between them, and you cannot see any of them from inside one.

Scoped explicitly, because the versions matter here more than usual: apt and dpkg as they are on Debian 13 and Ubuntu 26.04 LTS, and dnf and rpm as they are on Fedora 44 and RHEL 10. Be warned that those last two are two generations apart — Fedora has dnf5 and RPM 6, RHEL 10 has dnf 4 and RPM 4 — so a command that works on one will sometimes not exist on the other. Where that happens it is called out.

Flatpak and Snap are not here. They are not a section of this article; they are a different spine, one that deliberately skips half the stages below — no solver worth the name, no maintainer scripts, no configuration-file negotiation, no shared filesystem to collide on. That is the point of them, and the mechanism belongs with the container article rather than this one.

The eight stages, and one command that tells you where you stand

  1. You name something, and a candidate version is chosen.
  2. Metadata is fetched, and its signature is checked — or, on one family, is not.
  3. Dependencies are solved. This is where “it wants to remove half the system” comes from.
  4. Packages are downloaded, and their own signature is checked — or, on the other family, does not exist.
  5. Files are unpacked, and conflicts are adjudicated.
  6. Maintainer scripts and triggers run.
  7. The record of what happened is written.
  8. Something is left behind: caches, your edited configuration files, and orphans.

Now the split, and it rests on a fact about which program owns which file. Only dpkg writes /var/lib/dpkg/status, and only rpm writes the package database under /usr/lib/sysimage/rpm. apt and dnf never touch either. They resolve, they fetch, and then they hand a list to the low-level tool. So the database is a complete and local record of whether that tool ran at all.

# Debian and Ubuntu
dpkg --audit

# Fedora and RHEL
dnf history list | head -3

On Debian or Ubuntu, no output from dpkg --audit means dpkg never got partway. Whatever failed, failed above it, and your installed system is exactly what it was before you typed the command — fix the cause and retry. Output means a transaction is open: finish it with dpkg --configure -a or unwind the package it names, but do not simply retry the apt command, because apt will re-solve against a state that is now inconsistent.

On Fedora or RHEL the mirror image applies, and the surprise is that the state dpkg --audit looks for does not exist. RPM has no half-configured condition: a package is in the database or it is not, and a failed script leaves it fully installed. So the question is not “is a transaction open” but “did the transaction run at all”, and dnf history list answers it. If your operation is not the top entry, rpm never started — and because rpm checks the entire transaction before writing a single file, nothing up to that point needs repairing.

Stage 1 — You name something, and a candidate is chosen

“Install nginx” is not a complete instruction. There may be several versions across several configured sources, with different priorities, and something has to pick one.

apt-cache policy nginx        # every candidate, with its priority and source
apt why nginx                 # why is this here at all
apt why-not nginx=1.2         # why can I not have that one

dnf repoquery --qf '%{name}-%{evr} %{reponame}' nginx
dnf repoquery --whatrequires nginx

apt why and apt why-not are recent — they arrived with apt 3.1 and generate a trace from the solver rather than a guess. apt why-not in particular answers the question people have actually been asking for twenty years, which is not “what depends on this” but “why can I not have the version I asked for”.

One behaviour change here that catches Red Hat users moving between releases: in dnf5, best defaults to true. Where dnf 4 would quietly fall back to an older version it could satisfy, dnf5 fails and tells you. That is better, and it means a command that “worked” on RHEL 10 may stop working on Fedora — not because anything is broken, but because the older behaviour was hiding something from you.

Stage 2 — Metadata is fetched, and its signature is checked

Before anything is solved, the machine needs the list of what exists. This is apt update, or dnf refreshing its cache. And it is where the two families make opposite choices that almost nobody states out loud.

Where the signature is, and what it is not on

Debian and Ubuntu sign the metadata. The InRelease file is signed; it contains hashes of the package lists; those contain hashes of the .deb files. Trust reaches your package through a chain, and apt-secure(8) says the consequence plainly: apt does not review signatures at a package level. There is a tool for that, debsig-verify, and effectively nobody uses it.

Fedora and RHEL sign the packages. Each .rpm carries its own signature, which is why rpm -K somefile.rpm is a meaningful question about a file a vendor emailed you. But repo_gpgcheck defaults to false, so the repository metadata itself is not signature-checked at all — its integrity rests on TLS.

So the two families anchor trust at opposite ends of the same chain, and each is unprotected exactly where the other is protected. The consequence you can act on: Ubuntu’s own security documentation states that apt install ./package.deb does not verify the integrity of the package. There is no .deb equivalent of rpm -K. If a vendor sends you a file, one family can answer “is this really from you” and the other cannot.

Where keys live now, and where they no longer do

Almost every instruction you will find for adding a third-party repository is wrong, and it is wrong in the same way. apt-key was not deprecated — it was removed, in apt 2.9.17 in December 2024. Worse, /etc/apt/trusted.gpg is no longer trusted at all, and /etc/apt/trusted.gpg.d is deprecated. A key placed the old way is not warned about. It is ignored.

# The current shape: a deb822 .sources file naming its own key
# /etc/apt/sources.list.d/vendor.sources
Types: deb
URIs: https://repo.example.com/apt
Suites: stable
Components: main
Signed-By: /etc/apt/keyrings/vendor.pgp

Three details in that small file. Keys belong in /etc/apt/keyrings when you put them there yourself, or /usr/share/keyrings when a package ships one. The extension changed: Debian 13’s release notes state that the .gpg pathnames are now backwards-compatibility symlinks to canonical .pgp names which will eventually be removed. And Signed-By: can take an ASCII-armoured key inline, with no separate file at all — which is documented and almost never mentioned.

Debian 13 and Ubuntu 24.04 and later both install with this format. If you are looking at a machine with a meaningful /etc/apt/sources.list, apt modernize-sources converts it.

One trap worth knowing because it fails silently: keyring filenames in those directories must be safe for run-parts — a dot or an unusual character in the name and the file is simply not loaded, with no message.

The first of February 2026

If a third-party repository stopped working this year and nobody could explain why, this is almost certainly it.

apt moved Release-file verification from GnuPG to Sequoia’s sqv in version 2.9.19, in December 2024, with a grandfathering clause permitting SHA-1 binding signatures until 2026. That clause expired on 1 February 2026, and apt now rejects them outright:

Policy rejected non-revocation signature (PositiveCertification) requiring
second pre-image resistance because: SHA1 is not considered secure since
2026-02-01T00:00:00Z

# The command that names the repository and the key fingerprint:
sudo apt --audit update

It broke NodeSource, Amazon Corretto, OpenResty and repositories hosted on OBS, among others. The policy lives in /usr/share/apt/default-sequoia.config and can be overridden at /etc/crypto-policies/back-ends/apt-sequoia.config — but overriding it is not the fix. The fix belongs to the vendor, and it is to rotate the key. We come back to what people did instead in the worked diagnosis at the end.

While in this stage, one small correction about expiry. A Release file’s Valid-Until prevents an attacker replaying expired metadata at you. It does not prevent them freezing you on a stale-but-still-valid snapshot inside the window, and it depends entirely on your clock being right. It is a narrower guarantee than it looks.

Stage 3 — Dependencies are solved

Now the machine has to decide what else must change. On the Red Hat side this is libsolv, underneath libdnf5, and has been for years. On the Debian side apt has always used its own, and now it has two.

The old one is pkgProblemResolver, and it is the reason for the single most alarming thing package management does: offering to remove two hundred packages because you asked for one. The new one, called solver3, is defined never to remove a manually installed package. It fails and explains instead.

Which gives you a clean test, and a fact worth knowing about your own machine:

# A mass-removal proposal proves you are on the classic resolver.
apt --solver 3.0 install thing      # ask for the new one explicitly
apt-config dump | grep -i solver

Solver3 became apt’s default in version 3.1.10, in October 2025; before that it was enabled on Ubuntu only. Debian 13 ships apt 3.0.3 and still uses the classic resolver, so on the largest single group of machines reading this you have to ask for the new one by name. Ubuntu 26.04 has apt 3.1 and already uses it.

There is a second-order effect worth expecting. Solver3 tracks only the strongest dependency chain, so apt autoremove proposes different things under it — a package that was being kept alive through a weak virtual dependency may now be offered for removal. Read the list before agreeing to it, which is good advice regardless.

On the Red Hat side the notable change is a subtraction: RHEL 10 removed modularity entirely. Red Hat states that no modular content is shipped, and dnf module is gone. Every instruction telling you to enable a module stream to pick a database version is now describing a system that does not exist there.

Stage 4 — Packages are downloaded, and their integrity checked

This looks like the dullest stage, and it is the one where the choice each family made back in stage 2 finally costs something.

On Debian and Ubuntu, what is checked is the hash — the one that came down the signed chain from InRelease. That is a real guarantee as long as the chain is intact, and it evaporates the moment you step outside it. A .deb you downloaded in a browser has no such chain, and installing it directly checks nothing.

On Fedora and RHEL, the package carries its own signature, so the same question has an answer:

rpm -K vendor-package.rpm            # is this signed, and by a key I trust?
rpmkeys -K vendor-package.rpm       # the supported spelling on RPM 6
rpmkeys --list                      # which keys this machine trusts

# There is no .deb equivalent of the above.
# The nearest honest thing:
sha256sum vendor-package.deb        # ...and compare it with what, exactly?

RPM 6 changed how those keys are handled, and it is worth a sentence because the old advice is now wrong: rpmkeys is the supported way to manage the keyring, replacing the practice of manipulating gpg-pubkey pseudo-packages, and keys are referenced by fingerprint or full key ID rather than by collision-prone short IDs. RPM 6.0 shipped in September 2025 and is in Fedora 43 and 44; RHEL 10 is still on RPM 4.

And a dated change to expect. RPM 6 upstream defaults to enforcing signature checking rather than merely verifying signatures that happen to be present. Fedora 43 and 44 override that back to digest-only, so it has not bitten anyone yet — but the change to enforce it has been accepted for Fedora 45. After that, installing an unsigned local package fails unless you ask for it explicitly, and the documented escape is a one-line macro file:

echo '%_pkgverify_level digest' | sudo tee /etc/rpm/macros.verify

On compression, one small thing that is stated wrongly everywhere. dpkg’s documented default is still xz at level 6. Zstandard is supported and Ubuntu has built its packages with it since 21.10, as a distribution decision. So the answer to “what compression do .deb files use” is a distribution, not a format. On the Red Hat side, delta RPMs are gone — dnf5 does not support them and never will.

Stage 5 — Files are unpacked, and conflicts are adjudicated

This is the largest difference between the two families, and it is the one that decides whether a failure leaves you with damage to repair.

rpm checks the whole transaction before it writes anything. Dependencies, file conflicts and disk space, for every package in the operation, up front. dnf prints this as Running transaction check and Running transaction test, and a conflict discovered there looks like this — with nothing on disk changed:

Transaction test error:
  file /usr/bin/foo from install of alpha-1.2 conflicts with file
  from package beta-0.9

dpkg has no such phase. It discovers a collision while unpacking the package that hits it:

dpkg: error processing archive /var/cache/apt/archives/alpha_1.2_amd64.deb
 trying to overwrite '/usr/bin/foo', which is also in package beta 0.9

By the time you read that, earlier packages in the same run have already been unpacked and their pre-install scripts have already run. The two messages describe the same underlying situation and mean opposite things about the state of your machine: on one family a file conflict is a pre-write check, on the other it is a mid-write discovery. That is exactly why one family needs dpkg --audit and the other has no equivalent command — and why the box at the top of this page splits the way it does.

One Debian-specific complication belongs here, because it has been quietly generating strange failures for several releases. The merged /usr transition/bin becoming a symlink to /usr/bin and so on — breaks an assumption dpkg was built on, that every filename uniquely identifies a file on disk. The project’s own design document enumerates the consequences; two matter to you. Triggers may fail to fire when a file moves across an aliased path, and diversions can silently break. Debian 13 is the first release where the mitigation work is largely finished, which is worth knowing if you are debugging something odd on an older machine.

Stage 6 — Maintainer scripts and triggers run

Packages carry code that runs at install and removal time: preinst, postinst, prerm, postrm on one side, and %pretrans, %pre, %post, %preun, %postun, %posttrans on the other. This is where a package creates its service user, generates a key, or reloads a daemon.

Triggers belong here too, because triggers are maintainer scripts — deferred ones. A package that installs a file into a directory somebody else watches causes that other package’s trigger to run later in the same operation. It is how the man-page index gets rebuilt without every package knowing about it. The mechanism has not changed in over a decade; the standing advice remains to prefer the noawait variants where you can, because they do not force ordering constraints on the rest of the transaction.

And here is where the families diverge again, in a way that invalidates a lot of transferred advice. RPM’s own documentation states it plainly: RPM cannot undo or roll back a transaction, and a non-zero exit from a script stops further processing for that package, not for the whole transaction. So there is no half-configured state on the Red Hat side. A failed %post leaves the package fully installed and recorded, with a warning. There is nothing to finish. There is no rpm --configure, and advice shaped like dpkg --configure -a has no meaning there.

On Debian, by contrast, a failed postinst leaves a package unpacked but not configured — a real state, visible in the database, and the thing dpkg --audit reports.

Two newer conveniences worth knowing. apt now takes a systemd inhibitor lock while dpkg runs, so a laptop is less likely to suspend in the middle of a transaction. And dnf5 has offline transactions, which stage everything and apply it in a minimal boot environment where nothing else is running:

dnf5 --offline upgrade          # stage it
dnf5 offline status             # what is staged
dnf5 offline reboot             # apply it during a controlled boot

That is the closest either family gets to making stage 6 safe by construction, and it is the right tool for upgrading something that is currently serving traffic.

Stage 7 — The record of what happened

Something now knows what you did, and there are more places than you would expect.

dpkg --audit                    # any package left in a bad state
dpkg-query -W -f='${Package} ${Status}\n' | grep -v 'install ok installed'
cat /var/lib/apt/extended_states | head   # who asked for what, auto vs manual

dnf history list
dnf history info 42
journalctl -t rpm               # RPM 6.1 and later

The package databases themselves have moved, and one of the moves has broken a great deal of writing. The RPM database is at /usr/lib/sysimage/rpm, and has been since Fedora 36 and RHEL 9; /var/lib/rpm is a symlink to it. The move was so that a snapshot of /usr captures package state along with the files. It has been sqlite, not Berkeley DB, since RPM 4.16 — which retires rpm --rebuilddb as a general-purpose remedy.

There is a genuinely confusing consequence of the dnf4-to-dnf5 transition here, and it is worth checking on any Fedora machine that has been upgraded through several releases: dnf4 and dnf5 do not share state. Transactions performed by one are not visible to the other, and packages installed as dependencies by one appear as user-installed to the other. On a long-lived machine, dnf history may simply be missing the first half of its own life, and “why is this installed” can have two different answers depending on which binary you ask.

Undo, and what it is not

Both families now offer something called rollback, and both are the same shape:

apt history-list                # apt 3.1 and later; not on Debian 13
apt history-info 7
apt history-undo 7

dnf history undo 42
dnf history rollback 40

Neither is a journal replay. Each composes a new forward transaction that attempts to reach the earlier state, subject to the same solving and the same availability. If the old versions have been removed from the repository, it cannot get there. And it cannot undo what a script did — a user that was created, a database that was migrated, a certificate that was regenerated. Red Hat documents that using history to downgrade is not supported, naming selinux, selinux-policy, kernel and glibc specifically.

Note also that apt’s history commands are recent. They landed during the 3.1 series in autumn 2025 and reached the current stable series with apt 3.2 in April 2026 — so Ubuntu 26.04 has them, and Debian 13, on apt 3.0.3, does not.

What the record does not contain

Reproducible builds deserve a mention here precisely because of where they are not. Debian’s figures are now remarkable — around 94.7% of packages in the current development series reproduce bit-for-bit — and since May 2026 reproducibility has been a release gate: Debian’s migration software blocks packages that cannot be reproduced, or that regress, from entering testing.

But nothing verifies reproducibility at install time, on either family. Verification happens on rebuild infrastructure that reconstructs packages from build metadata, and the user-facing tool, debian-repro-status, is something you install and run afterwards to ask which of your packages have been independently rebuilt. It is an archive-side gate plus a post-hoc audit. It is not a stage in this article, and it would be easy to come away thinking apt checks it. It does not.

Stage 8 — What is left behind

Three kinds of residue, and the interesting one is the middle.

Caches. apt clean, apt autoclean, and dnf’s keepcache setting, which defaults to false in dnf5. Unremarkable, and worth doing on a small root filesystem.

Your edited configuration files, and here the rules have not changed in years — which is itself the story, because the two families behave so differently that admins from each are surprised the other exists.

SituationDebian and UbuntuFedora and RHEL
You never edited itNew version installed silentlyNew version installed silently
You edited it, package unchangedLeft aloneLeft alone
You edited it, and the package changed it tooYou are prompted, interactively, with a diff on requestNothing is said. Plain %config: yours is renamed .rpmsave. %config(noreplace): theirs lands as .rpmnew
You deleted itdpkg will not put it backDepends on the directive
The asymmetry is the point: dpkg prompts and rpm does not. Nothing in a default Fedora or RHEL install tells you those files have appeared.
# Find the ones nobody told you about
sudo find /etc -name '*.rpmnew' -o -name '*.rpmsave'

# The Debian equivalent question: which conffiles have you modified?
dpkg-query -W -f='${Conffiles}\n' | grep -v ' obsolete$' | awk '$3=="newconffile"'

Which directive a file gets is decided when the package is built, not when it is installed. You cannot change it, which is why the behaviour feels arbitrary; it is a decision somebody else made about that specific file.

Orphans. apt autoremove and dnf autoremove are the supported answers, and old tools like deborphan are no longer needed. One difference: dnf5 sets clean_requirements_on_remove to true, so dnf remove already prunes dependencies that nothing else needs — the separate autoremove step is a Debian habit.

And the removal distinction people forget until it costs them: apt remove leaves your configuration files behind, apt purge takes them with it. Reinstalling after a remove gives you your old settings back, which is usually welcome and occasionally the reason a “clean reinstall” changes nothing.

Advice that has expired

Package management has an unusually stale corpus, and it is not stale randomly. Nearly all of it is wrong in one direction, which we will come to after the table.

What you will still readWhat is true now
sudo apt-key add key.gpg, or “put it in /etc/apt/trusted.gpg.d/apt-key was removed in December 2024, /etc/apt/trusted.gpg is no longer trusted, and badly-named files in trusted.gpg.d are silently ignored. Use Signed-By:
“An old repository key still works, it just warns”Since 1 February 2026 apt rejects SHA-1 binding signatures outright. apt --audit update names the repository
“apt verifies signatures with GnuPG”Sequoia’s sqv since apt 2.9.19, with a policy file at /usr/share/apt/default-sequoia.config
“The signature verifies the packages you install” (Debian)It verifies the metadata. apt install ./foo.deb checks nothing at all
“dnf verifies the repository’s signature”repo_gpgcheck defaults to false. RPM signs packages; metadata rests on TLS
“apt resolves dependencies better than apt-get”Same library. The real difference is that apt has no stable command-line interface and apt-get does — which is why scripts use apt-get
apt upgrade removes obsolete packages”It never removes anything. It installs new ones, which apt-get upgrade does not. That is the whole difference
dist-upgrade is the dangerous old name; full-upgrade is the safe new one”They are the same operation. The meaningful pair is upgrade versus full-upgrade
“apt has no rollback”apt history-list, history-undo and history-rollback landed in the apt 3.1 series and ship in 3.2 — present on Ubuntu 26.04, absent from Debian 13’s apt 3.0.3
dnf history rollback restores your system to that point”It composes a new forward transaction. Red Hat does not support using it to downgrade, naming kernel, glibc and the SELinux packages
apt-get install -y --force-yesSuperseded long ago by five separate flags, granted separately: --allow-downgrades, --allow-remove-essential, --allow-change-held-packages, --allow-unauthenticated, --allow-insecure-repositories
dnf install --skip-brokenRemoved in dnf5. Use --no-best (accept an older version) or --skip-unavailable (ignore names that do not exist) — two different things the old flag conflated
dpkg --configure -a is what you run when packages are broken”It finishes an interrupted dpkg run and does nothing for a solver failure, a 404 or a rejected key. Run dpkg --audit first
rpm -Uvh foo.rpm as the way to install somethingrpm resolves nothing and refuses on unmet dependencies. Use dnf install ./foo.rpm, which resolves and runs the transaction test
rpm --rebuilddb as a cure for transaction errorsBerkeley-DB-era advice. The backend has been sqlite since RPM 4.16, and this does nothing for a file conflict
“The RPM database is in /var/lib/rpmA symlink since Fedora 36 and RHEL 9. It is /usr/lib/sysimage/rpm
yum is gone”dnf5 ships /usr/bin/yum as a symlink. What is gone is yum 3
dnf module enable postgresql:15Modularity was removed from RHEL 10 entirely. No modular content is shipped
“Enable delta RPMs to save bandwidth”dnf5 does not support them and will not
“Edit /etc/apt/sources.listDebian 13 and Ubuntu 24.04+ install with a deb822 .sources file. Run apt modernize-sources
.deb files are zstd-compressed now”dpkg’s default is still xz. Ubuntu uses zstd; Debian does not. Name the distribution, not the format
“‘The following packages have been kept back’ means a broken dependency”On Ubuntu it is usually a phased update; on Debian it means apt upgrade would have to install a new package
“RPM packages must be signed”Historically false — RPM verified signatures when present and never required them. It becomes true on Fedora 45, and is not true on Fedora 44 or RHEL 10
Every row was correct when somebody first wrote it down.

Now the direction. Almost every wrong page on this subject makes the same mistake, on both families, for the same reason: it describes the trust model backwards. On Debian it tells you the key protects your packages — it protects the metadata. On Red Hat it tells you the key verifies the repository — metadata checking is off by default, and what is verified is the package.

Both come from one shortcut — I imported a GPG key for this repository, therefore what I install from it is signed — and both survive forever because the happy path never contradicts them. Every page in that corpus tells you how to import a key and none tells you what the key is checking.

Which gives you a one-question test for any page on this subject. Ask it what happens when you run apt install ./something.deb. If it does not tell you that no signature is checked, it was not written from Debian’s own documentation. The Red Hat equivalent: ask it what repo_gpgcheck defaults to. (If you prefer a keyword scan, grep for apt-key, trusted.gpg.d, --force-yes, --skip-broken, rpm --rebuilddb, /var/lib/rpm, dnf module and deltarpm — three hits and the page predates the machine you are sitting at.)

A worked diagnosis

A server has been running fine for years. Someone notices that a security scanner reports it is not receiving updates from one of its third-party repositories, and nobody can remember it ever failing.

$ grep -r 'trusted=yes' /etc/apt/
/etc/apt/sources.list.d/vendor.list:deb [trusted=yes] https://repo.example.com/apt stable main

There is the finding, and it is worse than it looks. [trusted=yes] does not mean “we checked and it is fine”. It means verification is switched off for that repository — apt will accept whatever that host returns, unsigned, indefinitely. The scanner is right.

The question is how it got there. The file’s modification time says February. Removing the flag and asking apt what it thinks:

$ sudo apt --audit update
...
E: Policy rejected non-revocation signature (PositiveCertification) requiring
   second pre-image resistance because: SHA1 is not considered secure since
   2026-02-01T00:00:00Z
N: Updating from such a repository can't be done securely: repo.example.com
N: Key fingerprint: 9A4C 2E1B ...

This is stage 2, and it is dated. The vendor’s signing key carries a SHA-1 binding signature; apt’s Sequoia policy grandfathered those until 2026 and the grandfathering expired on the first of February. Somebody hit a failing apt update that morning, searched for the error, found an answer that said to add [trusted=yes], and the alerts stopped. Six months later nobody remembers doing it.

The repair is not on this machine. The vendor has to rotate the key — they had eighteen months’ notice, and most of the affected vendors have now done it. The right sequence here is to fetch the current key, install it properly, and delete the flag rather than the symptom:

# 1. Get the vendor's current key and put it where apt looks
curl -fsSL https://repo.example.com/key.asc \
  | sudo tee /etc/apt/keyrings/vendor.pgp > /dev/null

# 2. Replace the one-line source with a deb822 file naming that key
#    (no [trusted=yes] anywhere)

# 3. Prove it verifies now
sudo apt --audit update

If the vendor has not rotated, the honest options are to pin the repository to a mirror you control, or to stop using it. Overriding the Sequoia policy is possible and is the wrong answer: it re-enables SHA-1 for every repository on the machine to fix one.

The moral is small and generalises well beyond apt. A signature that stopped being accepted is not a signature that stopped existing — and the workaround everybody reaches for deletes the difference between the two. The repository still had a key. It was still signing. The only thing that changed was that the machine stopped believing an algorithm, and [trusted=yes] answered a question nobody had asked.

What to hold on to

The two families do the same job in the opposite order, and the order is the entire answer. rpm checks the whole transaction and then writes; dpkg writes as it goes and discovers problems on the way. One signs the metadata and reaches the package by hash; the other signs the package and leaves the metadata to TLS. Almost every practical difference — including whether a failure leaves you with work to do — falls out of those two reversals.

Ask the database, not the console. dpkg --audit and dnf history list are local, need no network, and cannot be wrong about whether the low-level tool ran. Every other diagnosis in this article starts from one of them.

Find out what your machine actually has. Four programs move independently here, and no two of these distributions ship the same combination. Debian’s apt is a full minor series behind Ubuntu’s, and Fedora is two generations ahead of RHEL on both rpm and dnf. No table survives that; four commands do.

apt --version; dpkg --version
dnf --version; rpm --version

Related reading