mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
Install shared shims, managed configuration, and login-shell PATH integration so golden images and multi-user hosts can protect package installs for every user. Co-authored-by: Cursor <cursoragent@cursor.com>
165 lines
7.6 KiB
Markdown
165 lines
7.6 KiB
Markdown
---
|
||
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
|
||
|