* ci: reject AI tooling artifacts in pull requests
The project's public face carries no AI tooling attribution, but nothing
enforced it: a session trailer reached a merged commit message and a pull
request body before anyone noticed.
Add a check that runs on pull requests and inspects only what the PR
changes — commit messages, PR title and body, added lines, and any
attempt to track the local-only guidance and review-export files that
are meant to stay gitignored. History is untouched and unrelated files
are not scanned. The clean-room audit records are exempt: they must
describe their own methodology to serve as compliance evidence.
Also drop the tooling credits from README and CHANGELOG.
* ci: fix base-ref fetch in the artifact check
`--depth=0` is rejected by git, and the extra fetch was redundant with
the full-history checkout. Fetch the base branch plainly and diff against
FETCH_HEAD.
Releases carried no binaries (v0.2.1 shipped zero assets). Add dist
(formerly cargo-dist) 0.32.0 to build and upload them on tag push.
Scope: only the workspace root package is distributed, producing the
single shadow-rs multicall binary that provides all 14 tools via argv[0]
— the same layout as `make install-multicall`. The 14 per-tool crates
carry `dist = false` so a release is one archive per target rather than
fifteen. `[dist.binaries]` pins the archive to `shadow-rs`, keeping the
feature-gated `shadow-rs-completions` helper out of it.
Targets are glibc-only for now: shadow-core::crypt links crypt(3) via
`#[link(name = "crypt")]`, and the self-contained musl target provides
no libcrypt, so an x86_64-unknown-linux-musl cross-build fails at link
time. (Alpine CI passes only because it installs a system libcrypt.)
`[dist.dependencies.apt]` installs libcrypt-dev on the runner for the
same reason.
`[profile.dist]` inherits the hardened release profile, so published
binaries keep LTO, stripped symbols and panic = "abort".
README documents deploying the archive (symlinks + setuid) and why musl
is not published yet.
Verified locally: `dist plan` and `dist build --artifacts=local` produce
uu_shadow-x86_64-unknown-linux-gnu.tar.gz containing shadow-rs plus
README/CHANGELOG/LICENSE and a .sha256; the extracted binary reports
`shadow-rs (uutils shadow-rs) 0.2.1`.
Closes#207.
Claude-Session: https://claude.ai/code/session_011f42R6SMAfQXufTgdjSuhU
Address review feedback on #173:
- Don't sleep after the final build attempt (no retry follows it).
- Forward the workflow-wide CARGO_NET_RETRY into the container with a
bare '-e CARGO_NET_RETRY' instead of re-hardcoding the value, keeping
a single source of truth.
The Test (debian/alpine/fedora) matrix failed four times in a row on
2026-06-10, each on a transient network error (Docker Hub base-image
pull i/o timeout; crates.io download broken pipe) unrelated to the code.
- fail-fast: false so one distro's flake no longer cancels the others.
- Retry 'docker compose build <target>' (the Docker Hub pull) with backoff.
- Pass CARGO_NET_RETRY into the container and set it for runner-native
jobs so cargo retries crate downloads; real test failures still fail
fast (no step-level retry around the test run).
No new third-party actions — a shell retry loop keeps the supply-chain
surface unchanged.
Closes#172.
#154: Reject setuid multicall invocations where argv[0] doesn't match
AT_EXECFN from the ELF auxiliary vector. Prevents an attacker from
spoofing argv[0] to route the multicall binary to a different tool
in setuid context. Only enforced when euid != uid.
#155: Add daily cargo-audit workflow matching uutils/coreutils pattern.
Also triggers on Cargo.toml/Cargo.lock changes.
Fixes#154. Fixes#155.
- Add homepage.workspace to root package (missing vs subcrates)
- Gate Docker test-docker job to push only (seccomp:unconfined
and SYS_ADMIN are unsafe for untrusted PR contexts)
- Add Docker test matrix (debian/alpine/fedora) to GitHub Actions CI
- Add renovate.json for automated dependency updates
- Add rust-toolchain.toml for contributor convenience