# Container-based e2e smoke
Local-only smoke harness that runs `pathlint` inside three Linux
distro containers (Ubuntu, Arch, Fedora) to confirm the binary
still works on PATH layouts the host CI matrix does not exercise.
This is intentionally **not wired into GitHub Actions** — pulling
three images per PR adds minutes of CI time for a check that
existing host-side `cargo test` already covers structurally. Run
it locally before a release that touches:
- the doctor R3 detectors (PATH layout sensitivity)
- the built-in catalog (distro-specific source paths)
- anything that reads `/etc/os-release` or `expand_env`
## Requirements
- `bash` (the orchestrator and inner smoke script)
- Either `podman` (preferred for rootless) or `docker`. The
orchestrator auto-detects.
- A way to produce the Linux release binary. Two modes:
- **Builder container (default on Windows / macOS).** The
orchestrator runs `cargo build --release --bin pathlint`
inside a `rust:1.85-slim` image and mounts the result into
each distro container. No Linux toolchain required on the
host. Set `PATHLINT_E2E_USE_BUILDER=0` to skip.
- **Host cargo (default on Linux).** Runs
`cargo build --release --target $PATHLINT_E2E_TARGET` on the
host. On non-Linux hosts this means installing the cross
target with `rustup target add x86_64-unknown-linux-gnu` and
a Linux linker (`mold`, `lld`, `gcc-multilib`); the builder
container exists to avoid that.
## Run
```bash
# All three distros
scripts/e2e/run.sh
# Just one
scripts/e2e/run.sh ubuntu
# Subset
scripts/e2e/run.sh ubuntu fedora
```
Exit codes:
- `0` — all selected distros passed
- `1` — at least one distro failed
- `2` — environment problem (no runtime, build failure, etc.)
## What is checked
`smoke.sh` runs inside each container and verifies, without pinning
exact human output:
1. `pathlint --version` mentions `pathlint`
2. `--help` works on every subcommand
3. `pathlint catalog list` produces non-trivial output
4. `pathlint doctor` exits 0 or 1 and `--json` output starts with `[`
5. `pathlint trace ls` resolves and emits a `kind` field in JSON
6. `pathlint check` (no rules) exits 0 and `--json` is a JSON array
7. `pathlint init` writes `pathlint.toml` to a tempdir
The aim is portability assertion (each distro's PATH does not
crash pathlint), not output drift detection. Output drift is
covered by the host-side integration tests.
## Adding a distro
Drop a new `Dockerfile.<name>` in this directory; `run.sh` picks it
up automatically when called as `run.sh <name>`. Keep the image
slim — `bash`, `coreutils`, `ca-certificates`, and whatever the
distro needs to install those.
## Troubleshooting
- **"neither podman nor docker is on PATH"**: install one. On
Windows, [Docker Desktop] or [Podman Desktop]; on macOS, the
same plus `brew install podman` works rootless.
- **"cargo build inside builder container failed"**: usually a
registry / network issue. Re-run after a moment; the cargo
registry cache is reused via the bind-mounted `target/` and
the home cargo dir.
- **"cargo build failed"** (host cargo mode): the host needs the
`x86_64-unknown-linux-gnu` target installed and a Linux linker.
Either install them (`rustup target add ...`) or just leave
`PATHLINT_E2E_USE_BUILDER=1` to use the builder container.
- **arch keyring failures during `pacman -Sy`**: stale base image,
`${runtime} pull archlinux:latest` to refresh and retry.
[Docker Desktop]: https://www.docker.com/products/docker-desktop
[Podman Desktop]: https://podman-desktop.io/