Skip to main content
Use a system-wide install when one machine or image should protect every user account: shared VMs, CI runners, and golden Docker images. It installs PATH shims for all users and an authoritative config under /etc, so any user’s npm install or pip install is checked before it runs.
For a single developer machine, use the per-user setup in the Quickstart instead. Per-user and system-wide installs can coexist.

Requirements

  • Linux and root. System install is Linux-only and must run as root.
  • PMG in a system path. Every user’s shim runs PMG by absolute path, so the binary must live in a root-owned system path such as /usr/local/bin, executable and reachable by all users.

What gets created

ItemPath
Configuration/etc/safedep/pmg/config.yml
Package-manager shims/usr/local/lib/pmg/bin
Shell PATH snippet/etc/profile.d/pmg.sh
System install uses PATH shims only. It does not create the ~/.pmg.rc alias layer that per-user setup installs.

Docker images

PMG must be installed inside the image: PMG on the Docker host cannot see installs that run during docker build. Compared to a Linux VM, a Dockerfile needs two adjustments:
  1. No sudo. RUN steps execute as root. If your base image switches to a non-root USER, add USER root before the install step and switch back after.
  2. Set PATH with ENV. RUN steps do not source /etc/profile.d, so add the shim directory to PATH explicitly.
Every RUN npm install or RUN pip install after the ENV PATH line now goes through PMG, and the running container inherits the protection, for any USER. Derived images inherit it too.
If a later stage sets ENV PATH again, keep /usr/local/lib/pmg/bin ahead of the real npm/pip directories. Dropping it, or ordering it behind the toolchain, turns interception off without any error.

Linux VMs

  1. Place PMG in a system path. Not installed yet? The install script places it in /usr/local/bin, prompting for sudo for the copy:
    Already installed in a user location? Copy it over:
    PMG rejects a binary in a user location (~/.local/bin, ~/go/bin), since any single user could modify it. The install script also picks ~/.local/bin when that is on your PATH; if it did, use the copy command above.
  2. Install system-wide:
  3. Activate the PATH. The install writes /etc/profile.d/pmg.sh, which prepends the shim directory for login shells. New login sessions pick it up; for an already-open shell:
On a multi-user host where you do not trust every member of the directory’s group, tighten the install directory: sudo chmod g-w /usr/local/bin. Debian and Ubuntu ship it group-writable for the staff group (empty by default).

Verify

Works for a VM shell and inside a container (docker run --rm -it <image> sh):
Then prove the protection end to end with a known test package. PMG must block it:

Configuration

The system config file is authoritative for every user. PMG ignores a per-user config.yml while /etc/safedep/pmg/config.yml exists. pmg config set and pmg config edit are disabled under a system config. Edit the file as root, or redeploy it through your image or configuration management.
Runtime data (event logs, cloud-sync state, cache) stays per user under ~/.config/safedep/pmg and ~/.cache/safedep/pmg. The invoking user must be able to write their own config directory. Relocate it with PMG_CONFIG_DIR / PMG_CACHE_DIR if needed.

Cloud sync

Cloud sync reports install events to your SafeDep Cloud tenant, where they appear in Package Guard. To set it up, enable cloud sync and provide your tenant ID and API key from SafeDep Cloud through the SAFEDEP_API_KEY and SAFEDEP_TENANT_ID environment variables.

In a Docker image

Enable sync and set a stable endpoint name before your install steps:
Containers report a generated hostname per run, so without PMG_CLOUD_ENDPOINT_ID every run registers as a new endpoint. A stable name is what you will recognize in Endpoint Hub. The credentials exist only where you run docker, as shell exports or CI secrets; they never go in the Dockerfile.
Never bake credentials into an image with ENV SAFEDEP_API_KEY=.... ENV values persist in the image metadata, and anyone who pulls the image can read them.
In the running container, pass them through at start:
Compose environment: entries and Kubernetes Secret references work the same way. If the container is short-lived, a CI job for example, run pmg cloud sync before it exits so buffered events are not destroyed with it. During docker build, sync in the same RUN step as the install, with the export covering both commands: PMG records events for the cloud only when credentials resolve. Mount the credentials as BuildKit secrets, which expose them to that step only (uid= makes them readable by the step’s non-root user):
Each --secret reads the variable exported where you run the build:
A blocked package fails its RUN step: later commands never run, including any sync at the end of the Dockerfile, and Docker discards the failed step’s changes. Syncing per step uploads every event up to the block; the block itself shows in the build output.
Build it with the credentials exported in your shell:

On a shared VM

Enable sync in /etc/safedep/pmg/config.yml as root:
Then put the credential values in a root-owned snippet such as /etc/profile.d/safedep-cloud.sh, so every login shell exports them:
Users who should sync with their own key can set the same variables in their own shell profile instead. One shared key does not blur the picture: every synced event records which OS user ran the install. It does mean every user on the host can read the key. Auto-sync cadence, manual sync, and viewing events are covered in Package Guard; the full set of cloud keys is in the PMG configuration reference.

Certificates

System install does not set up a MITM certificate authority. For npm and pip on Linux, PMG’s default ephemeral CA and environment-variable injection are sufficient. To install a persistent CA into the OS trust store, run pmg setup cert install --system as your normal user.

Uninstall

This leaves the PMG binary in place. To remove it too, run sudo rm /usr/local/bin/pmg, or uninstall it through your package manager if you installed it that way.

Troubleshooting

Try running pmg setup doctor first: it detects each of these states and prints the matching fix.
Version managers like nvm, pyenv, volta, and asdf prepend their own bin directories from rc files that run after /etc/profile.d, putting the real npm/pip ahead of the shims.
  • Keep /usr/local/lib/pmg/bin first in a durable ENV PATH or login PATH
  • Or call pmg npm / pmg pip directly
After source .venv/bin/activate, bare pip uses the venv binary and skips the shims. Call pmg pip inside the venv.
Another account created or owns your config directory. Check the path in the error message.If the path is inside your own home, a root run created it as root. This happens with su without - (prefer sudo or su -) and with images that set ENV HOME before dropping root. Restore ownership:
If the path is inside another user’s home, your environment leaked that user’s HOME or XDG_CONFIG_HOME (common with sudo -u on CI runners). Fix the environment; do not chown another user’s directory, that breaks PMG for them.

System Install Reference

Full reference in the PMG repo: binary validation rules, user data directories, and limitations.

PMG

How PMG blocks malicious packages at install time.