Files
pmg/docs/proxy.md
T
Sahil BansalandGitHub d1dd2560a4 feat: consolidate proxy config into structured section and add support for custom commands to skip proxy (#240)
* feat: add ProxyConfig struct with per-PM skip_commands and legacy fallback

* feat: consolidate proxy config into structured section with backward compat

Replaces flat proxy_mode/proxy_install_only keys with a structured proxy
section supporting per-package-manager skip_commands. Legacy keys are
respected via fallback when user's config lacks the new proxy section.
Removes deprecated experimental_proxy_mode config and flag.

* fix: env var resolution for nested config keys and deduplicate skip command matching

- Add "." to "_" in Viper env key replacer so nested keys like
  sandbox.enabled resolve from PMG_SANDBOX_ENABLED (was silently broken)
- Export IsFirstNonFlagArgInList and remove duplicate from proxy_flow.go
- Add table-driven tests for skip command matching with real-world cases
- Remove redundant env var test

* docs: update proxy configuration and env var documentation

Update config.md env var table to reflect new proxy.enabled and
proxy.install_only keys. Add proxy configuration section to proxy.md
covering config structure, per-PM skip commands, CLI flags, and env vars.

* fix: legacy fallback precedence
2026-05-06 18:27:23 +05:30

3.7 KiB

PMG Proxy

A generic, extensible HTTP/HTTPS proxy server with man-in-the-middle (MITM) capabilities for intercepting and analyzing package manager traffic. Built with goproxy library.

Configuration

Proxy behavior is configured under the proxy: section in config.yml:

proxy:
  enabled: true
  install_only: false
  policies:
    npm:
      skip_commands: ["my-script"]
Key Default Description
enabled true Enable proxy-based interception. When false, PMG falls back to guard-based analysis.
install_only false When true, only install commands are proxied. Other commands (e.g., npm ls, pip list) bypass the proxy and execute directly.
policies {} Per-package-manager policies. Each entry maps a package manager name to a policy with skip_commands.

Per-package-manager skip commands

The policies section lets you define additional commands that should bypass the proxy for specific package managers:

proxy:
  policies:
    npm:
      skip_commands: ["dev", "my-script"]
    pip:
      skip_commands: ["list", "show"]

Commands in skip_commands are matched against the first non-flag argument. For example, npm dev would match dev, but npm install dev would not since install is the first non-flag argument.

CLI flags

Flag Description
--proxy-mode Override proxy.enabled

Environment variables

Variable Description
PMG_PROXY_ENABLED Override proxy.enabled
PMG_PROXY_INSTALL_ONLY Override proxy.install_only

Legacy variables PMG_PROXY_MODE and PMG_PROXY_INSTALL_ONLY (for the old flat config keys) are still supported when the proxy: section does not exist in the config file.

Features

  • Selective interception of HTTPS traffic
  • Pluggable interceptors for different use cases
  • Certificate generation and management for HTTPS interception (MITM)

Architecture

flowchart TD
    A[Package Manager]
    A -- HTTPS_PROXY --> B[Proxy Server]
    B --> C{Match?}
    C -- Yes --> D[MITM]
    D --> E[Inspect]
    C -- No --> F[TCP Tunnel]
    subgraph inside_proxy [ ]
        G[Interceptor<br/>Chain]
    end
    B --> inside_proxy

Example

See examples/proxy for a complete example.

Quick Start

package main

import (
    "github.com/safedep/pmg/proxy"
    "github.com/safedep/pmg/proxy/certmanager"
)

func main() {
    // Generate CA certificate
    caCert, _ := certmanager.GenerateCA(certmanager.DefaultCertManagerConfig())

    // Create certificate manager
    certMgr, _ := certmanager.NewCertificateManagerWithCA(caCert, certmanager.DefaultCertManagerConfig())

    // Create proxy
    proxyServer, _ := proxy.NewProxyServer(&proxy.ProxyConfig{
        ListenAddr:   "127.0.0.1:8888",
        CertManager:  certMgr,
        EnableMITM:   true,
        Interceptors: []proxy.Interceptor{NewMyInterceptor()},
    })

    // Start proxy
    proxyServer.Start()

    // ... wait for shutdown signal ...

    proxyServer.Stop(context.Background())
}

Certificate Manager

The certmanager package provides certificate generation and caching.

Usage

import "github.com/safedep/pmg/proxy/certmanager"

// Generate a new CA certificate
config := certmanager.DefaultCertManagerConfig()
caCert, err := certmanager.GenerateCA(config)

// Handle persistence (example)
os.WriteFile("ca-cert.pem", caCert.Certificate, 0644)

// Create certificate manager with CA
certMgr, err := certmanager.NewCertificateManagerWithCA(caCert, config)

// Generate host certificates (automatically cached)
hostCert, err := certMgr.GenerateCertForHost("registry.npmjs.org")