Closed general

pkg publish lint: check install.sh path references against the tarball file set - a moved file published green and broke every fresh install for 5 days

Colby Knox · 1mo ago ·closed by Colby Knox

The gap (bit adom/altium-bridge on 2026-09-02, found by the Hydrogen pre-production test 5 days later, #10 there)

The pkg publish lint made me move a dev skill out of the shipping tarball (correct), but nothing checked that install.sh still referenced the removed path. set -e plus the failed cp killed the whole install script on every fresh workspace, which took the dock's altium-dashboard command with it. The package published green and stayed broken for five days until a fresh-box test tripped over it.

Ask

At publish time, statically scan install.sh (and uninstall.sh) for path references into the package tree ($HERE/... and relative cp/source targets) and fail the lint when a referenced path is not in the tarball's file set. The same scan can warn when files[] lists a path that does not exist locally (that half already silently drops the entry today). A dry-run in a scratch dir would be even stronger, but the static check alone would have caught this exact regression.

1 Reply

Colby Knox · 1mo ago

Shipped (git-wiki be1f682, on prod).

At publish, install.sh is scanned statically for package-relative READ operands and each one is matched against the tarball's file set. Counted as "into the package": ./x, $(dirname "$0")/x, and $VAR/x where the script itself sets VAR from dirname $0 / BASH_SOURCE / $PWD (HERE, DIR, SCRIPT_DIR, PKG_DIR, whatever it is called, including a variable copied from one of those); a bare relative path (skills/x/SKILL.md) counts only after a cd into that root. Operands checked: sources of cp/install/ln/rsync/mv (never the destination), and the arguments of source, ., cat, chmod, chown, bash, sh, node, python*, tar, unzip, cd. Not judged: anything with a variable, glob or brace in the path, and any path the script tests for first (if [ -d "$HERE/x" ], [ -f x ] && cp x): that is the author saying it is optional.

A reference the tarball ships neither as a file nor as a directory is 400 INSTALL_PATH_MISSING with errors[] like install.sh line 6: cp reads dev-skills/tool-dev/SKILL.md, which the tarball does not ship and data.references[] {script, level, line, command, path}. The same finding in uninstall.sh is a warning on the success response (same code), since an uninstall that dies leaves the install behind but blocks nobody.

Before turning it on I ran the scanner over every app, skill and bootstrap tarball on prod except Ray's (261 packages). After honouring existence guards and dir/. spellings it has no false positives, and it found two packages that are broken for fresh installs TODAY, both John's: adom/adom-video-post 1.0.8 copies bin/adom-video-post but ships no bin/ at all (source + build.sh only), and adom/chip-fetcher 1.0.5 installs bin/adom-chip-fetcher while the tarball ships bin/chip-fetcher. Filed as adom-video-post#1 and chip-fetcher#3; their next publish is refused until fixed. altium-bridge 0.2.12 passes (its dashboard/ui/assets copy is guarded).

The other half of the ask, warning when files[] names a path that does not exist locally, is client-side (the tarball is built by the CLI, the server never sees the working tree), so that one is the CLI thread's. A dry-run in a scratch dir stays open for later; the static check is what would have caught #10.

Tests: test/packages/install-path-findings.test.mjs (pure, 14 checks incl. the altium-bridge shape, guards, bare paths after cd, uninstall as warning) and route cases in test/packages/brand-slug-per-owner.test.mjs. Docs: api reference under POST /api/packages/:slug/publish, hint-codes row.

Log in to reply.