8000 Stop usr/** packages shipping the sandbox's usr/lib64 symlink (gnupg test collision, unblocks #1242) by bryan-minimal · Pull Request #1341 · gominimal/pkgs · GitHub
[go: up one dir, main page]

Skip to content

Stop usr/** packages shipping the sandbox's usr/lib64 symlink (gnupg test collision, unblocks #1242) - #1341

Merged
bryan-minimal merged 1 commit into
mainfrom
fix/usr-lib64-collision
Nov 6, 2026
Merged

bryan-minimal merged 1 commit into
mainfrom
fix/usr-lib64-collision

Conversation

@bryan-minimal
Copy link
Copy Markdown
Member

Unblocks #1242: gnupg's smoke test fails there with a sandbox path collision on usr/lib64.

What collides

The sandbox seeds $OUTPUT_DIR/usr/lib64 -> lib before every build so that installs targeting lib64 land in usr/lib. Nine packages use a catch-all usr/** output glob, and that glob picks the symlink up. The artifacts on cache.minimal.dev for current main show two shapes:

package what the artifact ships at usr/lib64
libgpg-error, libgcrypt, libassuan, libksba, npth, lsof, stow a real directory: the symlink was followed, so every library is shipped twice (usr/lib/ and usr/lib64/)
gnupg, iputils the dangling symlink usr/lib64 -> lib (they install nothing in usr/lib)

gnupg's smoke-test sandbox (test_deps = [base] plus gnupg's runtime closure) holds gnupg's symlink and the five gpg libraries' directories. The sandbox lays them down in spec-hash order:

  • main (run 42107730006): the directories go first. gnupg's symlink is skipped with WARN … Not symlinking …/dd/e362e0a7…/usr/lib64 => …/rootfs/usr/lib64, already exists. (dde362e0… is gnupg's own spec hash.)
  • bootstrap pins -> gen-13: every root, ladder top and userland cycle breaker from one generation #1242 (run 42112308631): the gen-13 pins change the hashes, the symlink goes first, and creating the directory fails with create directory I/O error at path …/rootfs/usr/lib64: File exists → failed setup for test smoke.

Fix

Each of the nine build.sh files now runs rm -f "$OUTPUT_DIR/usr/lib64" after installing. The libraries, .pc files and everything else stay in usr/lib, which is the only path any consumer uses (the .pc copies under lib64 were duplicates). If usr/lib64 is ever a real directory, rm -f fails the build, so nothing gets dropped silently. libffi already removes it the same way.

Rebuild blast radius (mip dump --arch amd64, before vs after): exactly these nine packages, all leaves.

Fleet check

  • usr/** is the only output glob in the fleet that captures the seeded symlink, and all nine packages using it are fixed here. Packages using usr/**/* (acl, attr, gmp, mpfr, libcap, pcre2, …) don't ship it; I checked their artifacts.
  • Every other lib64 mention in a build.sh already redirects to lib (--libdir/CMAKE_INSTALL_LIBDIR=lib, gcc's t-linux64 sed, libffi's merge).
  • I did not scan the prebuilt tarballs fleet-wide. A prebuilt ships its tarball as-is, without output globs.

Verification

  • A local min session can't fetch sources (build egress), so this depends on the build-bot and CI.
  • Check: gnupg's standalone test in this PR's minimal-check log no longer prints the usr/lib64 WARN.

🤖 Generated with Claude Code

The sandbox seeds $OUTPUT_DIR/usr/lib64 -> lib so libtool/cmake installs
that target lib64 land in usr/lib. Nine packages use a catch-all `usr/**`
output glob, which picks that symlink up. Where usr/lib exists the symlink
is followed, so the artifact also carries a full duplicate of every library
as a real usr/lib64/ directory (libgpg-error, libgcrypt, libassuan, libksba,
npth, lsof, stow); where it doesn't, the artifact ships the dangling
symlink itself (gnupg, iputils).

gnupg's smoke-test sandbox holds both shapes: gnupg's usr/lib64 symlink and
the gpg libraries' usr/lib64 directories. They are laid down in spec-hash
order. On main the directories go first and the symlink is skipped with a
WARN ("Not symlinking .../usr/lib64 ... already exists"). With the gen-13
pins in #1242 the hashes flip, the symlink goes first, and creating the
directory fails: "create directory I/O error at path .../rootfs/usr/lib64:
File exists", so the test setup fails.

Remove the symlink at the end of each build.sh. The libraries, .pc files
and everything else stay in usr/lib, which is the only path any consumer
uses. `rm -f` fails the build if usr/lib64 is ever a real directory.

Rebuild blast radius (mip dump, amd64): exactly these nine leaves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bryan-minimal
bryan-minimal requested a review from a team as a code owner November 5, 2026 21:48
@coderabbitai
coderabbitai Bot commented Nov 5, 2026
Copy link
Copy Markdown
Contributor

Warning

Review limit reached

  • Run on-demand review

This review includes 9 billable files and costs up to $2.25.

  • Ask an admin to make reviews automatic

Open in CodeRabbit

Reviews can continue after your included limit without a manual trigger. An admin must approve usage-based billing.

Or wait 3 minutes for your next included review.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available. Your 65 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Learn how review limits work.

Review configuration:

Run configuration

Commits

Reviewing files that changed from the base of the PR and between b79dd65 and 7a2cfc1.

Files selected for processing: 9

  • packages/gnupg/build.sh
  • packages/iputils/build.sh
  • packages/libassuan/build.sh
  • packages/libgcrypt/build.sh
  • packages/libgpg-error/build.sh
  • packages/libksba/build.sh
  • packages/lsof/build.sh
  • packages/npth/build.sh
  • packages/stow/build.sh
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

@norrietaylor norrietaylor left a comment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scope matches the title. All nine hunks add the same comment and the same rm -f line. Clobber none: the diff only adds lines, and git log shows no recent fix on these files. Correctness the fix is sound for the stated collision. All nine scripts run set -eu, and the rm -f is the last command, so a real usr/lib64 directory fails the build as the PR says. The nine packages are the only usr/** globs in packages/. No .ncl file names lib64, and no consumer of these nine packages reads usr/lib64. The findings are one missing guard and one comment nit. Not checked: the artifact tables and the claim that usr/**/* does not capture the symlink, because both need cache.minimal.dev. The result of gnupg's standalone test also needs CI. gitleaks and trivy did not run because the shell was restricted. I read the whole diff instead: it holds only comments and rm -f, and no dependency file changed. The PR body says libffi removes the path "the same way". libffi actually merges with cp -a and then runs rm -rf, which does not fail on a real directory.

Comment thread packages/gnupg/build.sh
# usr/lib64 as a symlink and another as a directory is a path collision in any
# sandbox holding both; the order is spec-hash-dependent, and the wrong order is
# a hard "File exists" (gnupg's smoke test, pkgs#1242). Libraries live in usr/lib.
rm -f "$OUTPUT_DIR/usr/lib64"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

low · Nothing fails if a package ships usr/lib64 again. gnupg's smoke test cannot serve as the regression test, because the PR says it passes on main and fails only in one spec-hash order. The next pkgmgr import wolfi package can bring the defect back, because the importer emits usr/** as a "Discovery catch-all" (packages/gnupg/build.ncl:88). That package will collide only when a later pin change flips the order. rg finds no lib64 check in .github/ or tests/. Add a small guard next to .github/scripts/llvm_collision_guard.py. It can fail any package with a usr/** glob whose build.sh does not remove usr/lib64. The same shape is in all nine packages, so one guard covers them.

Comment thread packages/iputils/build.sh
# duplicates every library under a real usr/lib64/). One package shipping
# usr/lib64 as a symlink and another as a directory is a path collision in any
# sandbox holding both; the order is spec-hash-dependent, and the wrong order is
# a hard "File exists" (gnupg's smoke test, pkgs#1242). Libraries live in usr/lib.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit · This six-line comment is copied into all nine scripts, and it does not fit every one. iputils and gnupg have no libraries in usr/lib according to the PR table, so "duplicates every library" and "Libraries live in usr/lib" say nothing true about them. lsof, stow and iputils are not in gnupg's closure, so the reference to gnupg's smoke test and pkgs#1242 only records this incident. A two-line comment can state the rule: the sandbox seeds this symlink, and the usr/** glob must not ship it.

@bryan-minimal
bryan-minimal added this pull request to the merge queue Nov 6, 2026
Merged via the queue into main with commit bcd45e1 Nov 6, 2026
15 checks passed
@bryan-minimal
bryan-minimal deleted the fix/usr-lib64-collision branch November 6, 2026 16:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0