r/ManjaroLinux • u/doug445 • 3d ago
Tech Support I kept finding AUR packages that had been silently broken for weeks after Manjaro caught up to Arch, so I wrote guards for it
Every few months I'd find something on my system that had been quietly broken — not crashed, just wrong — and it always traced back to an AUR package built against a library version that no longer existed.
It isn't random. It's two specific failures at opposite ends of the same window, and both are detectable.
While Manjaro is behind Arch. Third-party binary repos (BlackArch, chaotic-aur) build against current Arch. So they ship packages whose dependencies our repos won't have for another week or two. You get a refused transaction, or you force it and now you have a partial upgrade.
When Manjaro catches up. libfoo goes 1.0 → 2.0. Every AUR package built against 1.0 still shows as installed, still has all its files, checksums fine — and can no longer resolve its DT_NEEDED. pacman will never tell you, because from pacman's view nothing is wrong. This is the one that kept getting me.
Separately: an AUR PKGBUILD can point source= at a git repo with no commit, so what you reviewed last week isn't necessarily what builds today.
First, the obvious objection: "this automates pacman --ignore"
Yes. And --ignore is listed on the Arch wiki as a way to cause partial upgrades, so this deserves a real answer rather than hand-waving.
**--ignore does not disable dependency resolution.** I checked rather than assumed — built a throwaway pacman root, installed consumer 1.0 depending on libX=1.0, offered upgrades to both, then ignored libX so that consumer 2.0 would need a libX 2.0 that isn't there:
$ pacman -Syu --noconfirm --ignore libX
warning: ignoring package libX-2.0-1
warning: cannot resolve "libX=2.0", a dependency of "consumer"
error: failed to prepare transaction (could not satisfy dependencies)
:: unable to satisfy dependency 'libX=2.0' required by consumer
exit 1
$ pacman -Q # nothing moved
consumer 1.0-1
libX 1.0-1
$ pacman -Dk # pacman's own consistency audit
No database errors have been found!
pacman resolved the whole transaction, saw the hole, refused, and changed nothing. It is not possible to --ignore your way into an unsatisfied dependency; pacman is the backstop, not the script.
That's section 19 of the test suite and runs in CI on every push, against real pacman transactions. It's deliberately a test of pacman's behaviour rather than of my code — the safety argument for the whole thing rests on that property, nothing in my repo would notice if a future pacman changed it, and the failure would be silent.
Beyond that guarantee, what gets held matters:
- It only holds a package whose version-constrained dependency is already unsatisfiable — something that cannot install correctly at that moment regardless of what I do.
- It holds the new version back, so the package keeps the dependencies it already had and stays in the state it was already working in. The classic dangerous pattern is pinning a library while upgrading its dependents; this is the opposite direction.
- The realistic alternative isn't a clean full upgrade. It's a failed transaction, or someone reaching for
--ignoreby hand with worse aim. - Every hold is printed and written to
/var/log/safeup.log, so it's a deferred upgrade you can chase — not a package that silently stops updating forever, which is the actual long-term hazard.
The limit, stated plainly: it does not pre-check whether a package it holds is itself required by something else in the transaction. It relies on pacman refusing, then isolating the break. That's the behaviour above, and it's why that's acceptable — but you should know it works that way rather than by its own cleverness.
What the three checks do
- **
safeup** wrapspacman -Syu. Works out which pending third-party upgrades have dependencies that can't be satisfied yet,--ignores only those, and logs every hold. Also recovers frominstalling X breaks dependency … required by Yby isolating X so one broken package doesn't block your whole upgrade. - **
aur-rebuild-check** runslddover every file owned by every foreign package and reports unresolved sonames. This is the one nothing else does. It filters the false positives that make-binpackages flag forever (libs bundled privately and loaded through an$ORIGINRPATH). - **
aur-pin-check** refuses PKGBUILDs whose git source isn't pinned to a commit.#tag=is refused too — a tag can be moved. There's an allowlist, but it re-resolves the tag every run and refuses the package if the SHA changed.
aurinstall / aurupdate run the pin check before yay. If a check refuses something and you disagree, plain yay -S still works and the message says so — a gate you can't bypass just gets uninstalled the first time it's annoying.
aurinstall --chroot (gated default) hands the actual build to chrootbuild, from Manjaro's own manjaro-chrootbuild package. This is a gated check building in a isolated chroot (not for security reasons). If unable to use chroot, it automatically passes to yay.
Testing
65 assertions, in CI. The main suite builds a file-backed loop device, formats it, and constructs a whole throwaway pacman root inside — its own database, its own file:// repos built with the real repo-add, real packages — then drives actual pacman through the real scenarios and checks installed versions afterwards. Nothing on your system is touched. The ldd tests compile real .so files with a real unresolvable DT_NEEDED, so no output is faked. The allowlist test makes a real git repo, vets a tag, moves the tag, and asserts the next run refuses it.
Writing those tests found three real bugs in code I'd been running for months — including one where a verification step exited non-zero after a successful kernel removal, on every machine whose ESP isn't laid out like mine. CI caught that one; my own machine couldn't. That's the argument for the tests.
What it doesn't do: it doesn't make the AUR safe, doesn't tell you a PKGBUILD isn't malicious (pinning proves you build what you reviewed, that's all), doesn't sandbox makepkg, and can't fix a package that genuinely needs a newer lib — holding it is the right answer there. Not a substitute for snapshots.
MIT, pure bash, no runtime deps beyond pacman and coreutils, nothing phones home.
https://github.com/doug445/manjaro-safeaur-updater
Genuinely interested if the dependency logic has a case I haven't hit.
1
u/kaptnblackbeard 1d ago
I've been thinking about this project, and one big question for me is why Manjaro and not all distros that use the AUR?
1
u/lyidaValkris 12h ago
Watching this with interest. I haven't noted any packages break by this method (and I use the AUR sparingly, as one is supposed to, but I guess that's not an option for some).
While this looks great - have you thought of contacting the pamac maintainers and suggesting these sort of improvements, or contributing this to it? It would be neat if this functionality was baked into Manjaro's meta-package manager.
2
u/NixNicks 3d ago
Instead of doing all this just
sudo pacman-mirrors --api --set-branch unstable
and
sudo pacman-mirrors --fasttrack 5 && sudo pacman -Syu
You're not lagging behind anymore