diff --git a/.cursor/plans/system_install_design_98a8f15f.plan.md b/.cursor/plans/system_install_design_98a8f15f.plan.md deleted file mode 100644 index 0973fb0..0000000 --- a/.cursor/plans/system_install_design_98a8f15f.plan.md +++ /dev/null @@ -1,164 +0,0 @@ ---- -name: System install design -overview: "Design for `pmg setup install --system` (Linux): general system-wide shims + config + `/etc/profile.d`, motivated by Docker golden images but not Docker-specific. Venv-after-activate remains a documented limitation." -todos: - - id: spec - content: Write design spec to docs/specs/ after user approves design - status: completed - - id: eventlog-root - content: Eventlog soft-fail + root-without--system warning - status: completed - - id: system-artifacts - content: System shim manager, profile.d writer, WriteSystemTemplateConfig - status: completed - - id: cli-flags - content: Wire --system on install/remove with uid checks - status: completed - - id: info-doctor - content: Update setup info and doctor for system scope - status: completed - - id: docs-tests - content: Docs (golden image, venv limit) + unit tests - status: completed -isProject: false ---- - -# PMG System Install (`--system`) — Design - -Re-evaluation of [issue #317](https://github.com/safedep/pmg/issues/317) against current codebase. Prerequisite [PR #323](https://github.com/safedep/pmg/pull/323) (`PMG_SHIM_PATH`) is already merged. - -## Goal - -Root can install PMG once for **all users** on a Linux host (golden Docker image, shared VM). Later `USER appuser` / non-root logins get interception without per-user `pmg setup install`. - -Primary motivator: package installs inside `docker build` (host GHA PMG cannot see them). Feature itself is a **general Linux system install**, not a Docker mode. - -## Non-goals (v1) - -- macOS / Windows `--system` -- Persistent proxy baked into images -- In-place wrap of `/usr/local/bin` binaries -- Shell **function** wrappers (venv interactive fix) -- Making host PMG intercept `docker build` from outside the image -- Closing the venv-after-`activate` PATH race via shims - -## Locked decisions - - -| Topic | Choice | -| -------------------------- | -------------------------------------------------------------------------------------------- | -| Scope | Linux only | -| Shim location | `/usr/local/lib/pmg/bin` (not `/usr/local/bin`) | -| Config | Write `/etc/safedep/pmg/config.yml` (read path already exists) | -| PATH on VMs / login shells | `/etc/profile.d/pmg.sh` prepends shim dir | -| PATH in Docker builds | Image author sets `ENV PATH="/usr/local/lib/pmg/bin:$PATH"` (documented; required for `RUN`) | -| Venv after `activate` | Documented limitation → use `pmg pip …` | -| Proxy-in-image | Rejected for this use case | -| Layers | System and per-user installs independent | - - -## User flows - -### Golden Docker base - -```dockerfile -RUN curl -fsSL … | sh && pmg setup install --system -ENV PATH="/usr/local/lib/pmg/bin:$PATH" -``` - -Child images: - -```dockerfile -FROM company/golden:latest -USER appuser -RUN npm ci # intercepted -RUN pip install pkg # intercepted (system pip) -# RUN .venv/bin/activate && pip install x # NOT intercepted — use pmg pip -``` - -### Multi-user Linux VM - -```bash -sudo pmg setup install --system -# new login shells get PATH via /etc/profile.d/pmg.sh -``` - -### CLI UX - -```bash -sudo pmg setup install --system # root-only; fail fast otherwise -sudo pmg setup remove --system -pmg setup info # reports system / user / both -pmg setup doctor # checks system shim dir + on PATH -``` - -- Root without `--system` → warn (other users not covered; point to `--system`), then proceed with per-user install into root’s HOME. -- Non-root `--system` → `usefulerror` + sudo guidance. - -## Architecture - -```mermaid -flowchart TB - subgraph install [pmg setup install --system] - Cfg["/etc/safedep/pmg/config.yml"] - Shims["/usr/local/lib/pmg/bin/*"] - Profile["/etc/profile.d/pmg.sh"] - end - subgraph path [How PATH gets shims] - Env["Docker ENV PATH"] - Prof["profile.d on login shells"] - end - Shims --> Env - Shims --> Prof - Env --> Run["Dockerfile RUN / any process with ENV"] - Prof --> Login["VM interactive/login shells"] -``` - - - -### Components to add/change - -- `[cmd/setup/setup.go](cmd/setup/setup.go)` — `--system` flag, uid-0 preflight, branch install/remove; root warning without flag -- `[config/config.go](config/config.go)` — `WriteSystemTemplateConfig()` → `globalConfigDir()`; remove only with `--system` -- `[internal/shim/shim.go](internal/shim/shim.go)` — `NewSystemShimManager()` with `BinDir=/usr/local/lib/pmg/bin`, no per-user rc edits -- New system profile writer — `/etc/profile.d/pmg.sh` (marker-gated, PATH prepend only) -- `[cmd/setup/info.go](cmd/setup/info.go)` / `[cmd/setup/doctor.go](cmd/setup/doctor.go)` — system scope reporting + PATH check -- `[main.go](main.go)` / eventlog — soft-fail when log init fails (unusable HOME); do not `Fatalf` - -Reuse existing `PMG_SHIM_PATH` filtering in `[internal/shim/path.go](internal/shim/path.go)`; no recursion work needed for the new shim dir. - -## Corner cases (handled or documented) - - -| Case | Handling | -| --------------------------------------------------- | ------------------------------------------------------------------------------------------------- | -| Docker `RUN` does not source profile.d | Document `ENV PATH=…` in golden image | -| Login shell resets PATH via `/etc/profile` | profile.d restores shim dir | -| Child Dockerfile overwrites `PATH` without shim dir | Document; doctor can detect when run | -| Venv `activate` then `pip` | Documented limitation → `pmg pip` | -| System + per-user both present | Independent; remove is scoped | -| `PMG_SHIM_PATH` unset + direct `pmg npm` | Legacy `/.pmg/bin` only; system dir not stripped — prefer shim invocation or ensure env from shim | -| Unwritable HOME | Eventlog soft-fail | -| Windows | `--system` → not supported | - - -## Testing - -- Unit tests with path overrides (same pattern as `globalConfigDirOverride`) -- Install/remove idempotence for system shims + profile.d -- Doctor/info system detection -- Document a minimal Dockerfile golden-image smoke example in docs (not necessarily CI matrix in v1) - -## Docs - -- Setup / config docs: `--system`, golden-image snippet, VM vs Docker PATH, venv limitation -- Clarify host GHA PMG does not protect in-image `docker build` installs — bake PMG into the image - -## Implementation order (after spec approval) - -1. Soft-fail eventlog + root warn (small, unblocks containers) -2. System shim manager + profile.d writer + config write -3. Wire `--system` on install/remove -4. info/doctor -5. Docs + tests - diff --git a/docs/specs/2026-07-10-system-install-spec.md b/docs/specs/2026-07-10-system-install-spec.md deleted file mode 100644 index 997ed60..0000000 --- a/docs/specs/2026-07-10-system-install-spec.md +++ /dev/null @@ -1,68 +0,0 @@ -# System Install (`pmg setup install --system`) Spec - -Date: 2026-07-10 -Issue: [#317](https://github.com/safedep/pmg/issues/317) -Prerequisite: [#323](https://github.com/safedep/pmg/pull/323) (`PMG_SHIM_PATH`) - -## Problem - -`pmg setup install` writes shims and shell integration relative to the invoking user's HOME. When root installs PMG in a golden Docker image (or shared VM) and a later `USER` / non-root account runs package managers, those users do not get interception. - -Host-side PMG (e.g. GitHub Actions) also cannot see package installs that happen inside `docker build`. - -## Goal - -Root can install PMG once for all users on a Linux host. Feature is a **general Linux system install**, motivated by Docker golden images but not Docker-specific. - -## Non-goals (v1) - -- macOS / Windows `--system` -- Persistent proxy baked into images -- In-place wrap of binaries under `/usr/local/bin` -- Shell function wrappers for venv PATH races -- Host PMG intercepting `docker build` from outside the image - -## Behaviour - -### Artifacts - -| Artifact | Path | -|----------|------| -| Config | `/etc/safedep/pmg/config.yml` | -| Shims | `/usr/local/lib/pmg/bin/` | -| Login PATH | `/etc/profile.d/pmg.sh` (prepends shim dir) | - -Per-user cache and event logs stay per-user. - -### CLI - -```bash -sudo pmg setup install --system -sudo pmg setup remove --system -sudo pmg setup remove --system --config-file # also remove system config -``` - -- Non-root `--system` → fail with `PermissionDenied` and sudo guidance -- Non-Linux `--system` → fail with `UnsupportedPlatform` -- Root without `--system` → warn, then per-user install into root's HOME -- System and per-user layers are independent - -### PATH - -- **VMs / login shells:** `/etc/profile.d/pmg.sh` prepends the shim dir -- **Docker `RUN`:** image must set `ENV PATH="/usr/local/lib/pmg/bin:$PATH"` (profile.d is not sourced) - -### Limitations - -- After `venv/bin/activate`, `pip` resolves to the venv binary and bypasses shims. Use `pmg pip …`. -- Child Dockerfiles that rewrite `PATH` without the shim dir lose interception. - -### Event logging - -If event log initialization fails (e.g. unusable HOME), PMG warns and continues instead of exiting. - -## Testing - -- Unit tests with overridden system paths -- Install/remove idempotence for system shims and profile.d -- Doctor/info report system scope