mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* docs(specs): add custom block messages and package blocklist spec * docs(specs): add custom block messages and package blocklist implementation plan * feat(config): add blocked_packages list and custom block messages * feat(audit): add package_blocklist_blocked event and blocklist model * feat(proxy): block blocklisted packages in the policy gate before analysis * feat(guard): block blocklisted packages before trust skip and analysis * feat(ui): render blocklist blocks and custom messages, fix silent-mode block output * feat(proxy): append custom messages to malware and go-cooldown block bodies * test(proxye2e): cover blocklist enforcement and custom block messages * docs(specs): remove spec and plan documents * refactor: drop guard-flow blocklist enforcement and trim docs Guard mode is being deprecated; the blocklist is enforced in proxy mode only. Remove the trusted_packages mirroring references outside the docs. * refactor(config): consolidate blocklist and block message under top-level block section Replace dependency_cooldown.message, malware.message and blocked_packages with a single block section: block.message is appended to every block output regardless of which control blocked, and block.packages is the package blocklist. * fix(ui): render block.message as info note with clean spacing * fix(ui): indent wrapped continuation lines in block reasons and messages * update config template * refactor(config): replace block section with top-level advisory_message Remove the package blocklist (will be implemented as part of policies in the future) and replace block.message with an optional top-level advisory_message appended to every block output. * chore(config): move advisory_message near top-level scalar configs in template
267 lines
10 KiB
YAML
267 lines
10 KiB
YAML
# PMG configuration template. Customize this file as needed.
|
|
# https://github.com/safedep/pmg
|
|
|
|
# Enable transitive dependency resolution. Default is true.
|
|
transitive: true
|
|
|
|
# Maximum depth of transitive dependencies to resolve. Default is 5.
|
|
transitive_depth: 5
|
|
|
|
# Include dev dependencies in the dependency graph. Default is false.
|
|
include_dev_dependencies: false
|
|
|
|
# UI verbosity level. Valid values: silent, normal, verbose. Default is normal.
|
|
# silent: PMG is hidden from the user except for errors and malicious package detection
|
|
# normal: Show minimal status updates
|
|
# verbose: Show verbose status updates and detailed information
|
|
verbosity: normal
|
|
|
|
# Enable paranoid mode. In paranoid mode, PMG will treat suspicious packages
|
|
# as malicious packages
|
|
paranoid: false
|
|
|
|
# Disable anonymous telemetry. Default is false.
|
|
disable_telemetry: false
|
|
|
|
# Skip event logging. Default is false.
|
|
# When skip_event_logging is false, all events will be logged to file. These events are useful for audit
|
|
# trail and incident response on systems using PMG. Set this config to true to disable event logging.
|
|
skip_event_logging: false
|
|
|
|
# Event log retention days. Default is 7.
|
|
# This is the number of days to retain event logs.
|
|
event_log_retention_days: 7
|
|
|
|
# Optional message appended to every block output, regardless of which control
|
|
# blocked the installation (malware analysis, dependency cooldown, etc.).
|
|
# Useful for org deployments to point developers at internal policy docs or a
|
|
# security contact. Example:
|
|
# advisory_message: "Blocked by ACME security policy. Questions? #security-help"
|
|
advisory_message: ""
|
|
|
|
# Proxy configuration.
|
|
# When enabled, PMG uses a proxy-based interception approach instead of the
|
|
# default guard-based analysis. The proxy intercepts package manager requests in real-time
|
|
# and analyzes packages as they are downloaded. Proxy mode may not work in all environments,
|
|
# and can be disabled to fall back to the guard-based analysis.
|
|
proxy:
|
|
enabled: true
|
|
|
|
# When true, only install commands are proxied. Other commands
|
|
# (e.g., npm ls, pip list) bypass the proxy and execute directly.
|
|
install_only: false
|
|
|
|
# Per-package-manager commands to skip proxying (only applies when install_only is true).
|
|
# Example:
|
|
# skip_commands:
|
|
# pip: ["list", "show"]
|
|
skip_commands:
|
|
npm: []
|
|
|
|
# Persistent proxy server (`pmg proxy start`) settings.
|
|
server:
|
|
# Host the persistent proxy binds to. Defaults to 127.0.0.1 (loopback),
|
|
# which keeps the MITM proxy private to the host (the right choice for CI
|
|
# and local use). Set to 0.0.0.0 or a specific interface ONLY for a
|
|
# deliberately hosted deployment: a non-loopback bind exposes the proxy,
|
|
# and every client must trust the PMG CA. The --host flag overrides this.
|
|
listen_host: 127.0.0.1
|
|
|
|
# Port the persistent proxy binds to. 0 means a random free port. The
|
|
# --port flag overrides this.
|
|
listen_port: 0
|
|
|
|
# Trusted packages are packages that are trusted by the user and will be ignored by the security guardrails.
|
|
# This is useful for packages that are known to be safe and are used in the application.
|
|
# Example:
|
|
# - purl: pkg:npm/@safedep/pmg
|
|
# reason: "PMG is a trusted package for PMG"
|
|
#
|
|
# When a package is specified without an explicit version, all versions of the package will be trusted.
|
|
# This feature should be used with caution and should be used for minimal set of packages.
|
|
#
|
|
# When a package is specified with an explicit version, only that version will be trusted.
|
|
#
|
|
# The purl is the package identifier and the reason is the reason for trusting the package.
|
|
# PURL specification: https://github.com/package-url/purl-spec
|
|
trusted_packages:
|
|
- purl: pkg:npm/@safedep/pmg
|
|
reason: "PMG is a trusted package for PMG"
|
|
|
|
# Sandbox configuration (EXPERIMENTAL)
|
|
# When enabled, package managers run in sandbox environments with restricted
|
|
# filesystem, network, and process execution access. This provides defense-in-depth
|
|
# protection against malicious install scripts and supply chain attacks.
|
|
#
|
|
# When sandboxing is enabled for a package manager, policy violations will block execution
|
|
# (no "warn-only" mode). Sandboxing itself can be disabled globally or per package manager.
|
|
#
|
|
# Currently supported platforms:
|
|
# - macOS (using Seatbelt sandbox-exec)
|
|
# - Linux (using Bubblewrap with namespace isolation)
|
|
# - Windows (planned)
|
|
#
|
|
# Platform-specific limitations:
|
|
# - Linux: Filesystem permissions use coarse-grained bind mounts. Glob patterns (e.g., *.txt)
|
|
# are expanded at policy translation time, but entire directories may be mounted rather than
|
|
# individual matching files. This is less precise than macOS regex-based filtering.
|
|
# - macOS: Network filtering is limited (all-or-nothing for most policies).
|
|
sandbox:
|
|
# Enable sandbox mode (opt-in, default: false for backward compatibility)
|
|
enabled: false
|
|
|
|
# Controls scope of sandbox enforcement:
|
|
# - true: sandbox applies to all package manager commands
|
|
# - false (default): sandbox only applies to install commands, others run unrestricted
|
|
# Requires 'enabled: true' and per-PM policies to be active. May break workflows expecting unrestricted commands.
|
|
enforce_always: false
|
|
|
|
# Policy templates define policy profiles by name and path.
|
|
# They can be used to override a built-in profile or create a custom profile.
|
|
# Note: Custom profiles loaded via policy_templates can inherit from built-in
|
|
# profiles using the 'inherits' field in the YAML (e.g., inherits: npm-restrictive).
|
|
# Inheritance allows you to extend a base profile with additional permissions.
|
|
policy_templates:
|
|
# Name for the template. Can be used to override a built-in profile or create a custom profile.
|
|
# Path is the path to the template file.
|
|
# Relative path can be used to reference a template file in the config directory (example: ./npm-restrictive.yml)
|
|
npm-restrictive-override:
|
|
path: ./profiles/npm-restrictive.yml
|
|
|
|
# Per-package-manager sandbox policies
|
|
# Each package manager can have its own policy to account for unique security characteristics
|
|
policies:
|
|
# npm ecosystem. npm-restrictive is the shared base profile; each package
|
|
# manager maps to a leaf profile that re-allows only its own environment
|
|
# variables.
|
|
npm:
|
|
enabled: true
|
|
profile: npm # Built-in profile, template name, or path to custom YAML
|
|
|
|
pnpm:
|
|
enabled: true
|
|
profile: pnpm
|
|
|
|
npx:
|
|
enabled: true
|
|
profile: npx
|
|
|
|
pnpx:
|
|
enabled: true
|
|
profile: npx
|
|
|
|
yarn:
|
|
enabled: true
|
|
profile: yarn
|
|
|
|
bun:
|
|
enabled: true
|
|
profile: bun
|
|
|
|
# PyPI ecosystem. pypi-restrictive is the shared base profile; each
|
|
# package manager maps to a leaf profile that re-allows only its own
|
|
# environment variables.
|
|
pip:
|
|
enabled: true
|
|
profile: pip
|
|
|
|
pip3:
|
|
enabled: true
|
|
profile: pip
|
|
|
|
pipx:
|
|
enabled: true
|
|
profile: pipx
|
|
|
|
poetry:
|
|
enabled: true
|
|
profile: poetry
|
|
|
|
uv:
|
|
enabled: true
|
|
profile: uv
|
|
|
|
uvx:
|
|
enabled: true
|
|
profile: uvx
|
|
|
|
# Go ecosystem (experimental). The go command is opt-in: it runs only when
|
|
# invoked explicitly as `pmg go ...`.
|
|
go:
|
|
enabled: true
|
|
profile: go
|
|
|
|
# Dependency cooldown blocks installation of package versions published within
|
|
# a configurable time window.
|
|
dependency_cooldown:
|
|
enabled: true
|
|
days: 5
|
|
|
|
# Per-control skip list of packages exempt from the cooldown window.
|
|
# Packages here are STILL malware-scanned — only the cooldown wait is waived.
|
|
# Use it for first-party / internal packages that must be installed immediately
|
|
# on release (e.g. to sanity-test a freshly published version).
|
|
#
|
|
# To bypass every PMG control (malware analysis, cooldown, and any future
|
|
# controls) for a package, add it to the top-level trusted_packages list
|
|
# above instead. Trusted packages are automatically cooldown-exempt; you do
|
|
# not need to repeat them here.
|
|
#
|
|
# A PURL without a version skips cooldown for ALL versions of the package; a
|
|
# PURL with a version skips cooldown for that version only. Example:
|
|
# skip:
|
|
# - purl: pkg:npm/my-internal-sdk # all versions
|
|
# reason: "First-party SDK; sanity-tested immediately on release"
|
|
# - purl: pkg:npm/another-internal-pkg@1.2.3 # only 1.2.3
|
|
# reason: "Pin a specific just-published build"
|
|
skip: []
|
|
|
|
# Persistent analysis cache (opt-in). Caching is analyzer-specific, so config is
|
|
# nested per analyzer; today only the Malysis (malware) analyzer has a cache.
|
|
#
|
|
# By default PMG re-screens the whole resolved graph against the analysis
|
|
# backend on every install. When enabled, clean (ALLOW) verdicts are cached on
|
|
# disk and reused across runs, so repeat installs of an unchanged graph are
|
|
# fast. Only ALLOW verdicts are cached — suspicious, malicious, and
|
|
# tenant-excluded verdicts are always re-evaluated.
|
|
#
|
|
# Trade-off: a version that was clean when first screened but is later flagged
|
|
# malicious is served from cache until its entry expires; `ttl` bounds that
|
|
# window. Keep `ttl` short if you prefer freshness over speed.
|
|
analysis_cache:
|
|
# Malysis is SafeDep's threat intelligence feed.
|
|
# Set cache TTL to be lower than dependency cooldown period to have a compensating
|
|
# control in place for newly published packages whose verdict is cached.
|
|
malysis:
|
|
enabled: false
|
|
ttl: 24h
|
|
|
|
# Cloud sync configuration.
|
|
# When enabled, PMG audit events are synced to SafeDep Cloud for centralized visibility.
|
|
# Requires SAFEDEP_API_KEY and SAFEDEP_TENANT_ID environment variables for authentication.
|
|
cloud:
|
|
enabled: false
|
|
# Endpoint ID is not required. By default, it falls back to the machine's hostname.
|
|
# Set it only if you want to explicitly override the identifier for this endpoint.
|
|
endpoint_id: ""
|
|
|
|
# Auto sync drains the local cloud-sync WAL to SafeDep Cloud opportunistically
|
|
# at the end of each PMG invocation, gated by a per-host cooldown so it does
|
|
# not fire on every command. The drain runs as a short-lived detached child
|
|
# so the user-facing CLI returns immediately.
|
|
#
|
|
# Disable this in ephemeral environments (CI runners, throwaway VMs) where
|
|
# the detached child may be torn down before it finishes draining; in those
|
|
# environments, prefer an explicit `pmg cloud sync` at job-end.
|
|
auto_sync:
|
|
enabled: true
|
|
|
|
# Minimum gap between sync attempts. The lastrun timestamp is updated on
|
|
# every attempt (success or failure), so a failing cloud endpoint will not
|
|
# cause every PMG invocation to retry. Reduce this if you want a more
|
|
# aggressive retry cadence.
|
|
min_interval: 15m
|
|
|
|
# Hard timeout applied to a single background sync attempt.
|
|
timeout: 5m
|