Skip to main content
PMG runs as a persistent proxy in CI/CD. It starts once per job, intercepts installs from every supported package manager through standard proxy environment variables, and auto-blocks any package flagged as malicious.
In CI, PMG is non-interactive: flagged packages are always blocked, never prompted. For local development use the wrapped commands (pmg npm install) covered in the PMG quickstart.

Use the SafeDep PMG action

Run the safedep/pmg action in server-mode, then add a final pmg proxy stop step to enforce the result.
- uses: safedep/pmg@v1
  with:
    server-mode: true
    api-key: ${{ secrets.SAFEDEP_API_KEY }}
    tenant-id: ${{ secrets.SAFEDEP_TENANT_ID }}

- run: npm ci   # intercepted automatically

- name: Enforce PMG policy
  if: always()
  run: pmg proxy stop --fail-on-violation
The pmg proxy stop --fail-on-violation step is what fails the job on a block and flushes the final events to the cloud. Without it the proxy keeps running and events still sync in the background, but the job won’t fail on a violation and the most recent events may be missed. The if: always() ensures it runs even when an earlier step fails. PMG blocks malicious packages using SafeDep’s free community intelligence with or without credentials. Add the optional api-key and tenant-id to connect the run to SafeDep Cloud, so block events sync to Endpoint Hub before the runner is destroyed.

Example workflow

A full workflow that installs dependencies through PMG on every pull request:
install-dependencies.yml
name: Install Dependencies
on:
  pull_request:
    branches: [main]

permissions:
  contents: read

jobs:
  install-deps:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6

      # Start PMG in server mode
      - uses: safedep/pmg@v1
        with:
          server-mode: true
          api-key: ${{ secrets.SAFEDEP_API_KEY }}
          tenant-id: ${{ secrets.SAFEDEP_TENANT_ID }}

      # Your usual language setup and install
      - uses: actions/setup-node@v6
        with:
          node-version: "24"

      - run: npm ci

      # Enforce the result and flush events
      - name: Stop proxy
        if: always()
        run: pmg proxy stop --fail-on-violation

Use raw commands

To wire the proxy up directly without the action:
- run: pmg proxy start --daemon
- run: pmg proxy env >> "$GITHUB_ENV"
- run: npm ci
- run: pmg proxy stop --fail-on-violation
  if: always()
For the proxy lifecycle, certificate trust, bind address, and cloud event sync, see the persistent proxy server docs.

PMG

How PMG blocks malicious packages at install time.

Malicious Package

How SafeDep detects malicious packages.