Files
pmg/config/config.template.yml
T
987bda5d6a feat: Add dependency cooldown for npm packages (#200)
* feat: Add dependency cooldown for npm packages

Strip recently-published package versions from npm registry metadata
responses so npm's resolver naturally falls back to older versions.
Overrides the Accept header to force full packument responses (which
include the "time" field needed for publish-date checks).

Reports cooldown blocks only when all versions are stripped (remaining == 0),
matching npm's --min-release-age behavior for silent fallback.

* fix: Report oldest version in cooldown block (shortest wait)

When all versions are blocked by cooldown, report the oldest version
since it exits the cooldown window first — giving the user the
shortest wait time instead of the longest.

* fix: Handle resp.Body.Close error return for errcheck linter

* test: Add dependency cooldown assertions to template config tests

* fix: config template for dependency cooldown

* fix: Prevent npm from caching cooldown-stripped metadata responses

* fix: Restore body on ReadAll failure and log Close errors in response modifier

* fix: Close response body before replacing to prevent connection leak

* fix: Correct daysLeft ceiling math and update ContentLength on error recovery

* fix: Clear Status on status code change and update ContentLength in modifier error path

* refactor: address review comments on dependency cooldown PR

- Make NpmCooldownHandler and constructor package-private
- Pass cooldown days as parameter instead of reading config internally
- Convert standalone functions to methods on npmCooldownHandler
- Set Accept-Encoding: identity to prevent gzip responses breaking JSON parsing
- Return 503 with descriptive message when upstream body read fails

* fix: log errors in stripCooldownVersions instead of swallowing them

* fix: Config preserve fallback defaults

* fix: Code review fixes

* fix: correct cooldown tip to show wait time instead of incorrect trusted_packages advice

* fix: prevent integer overflow in cooldown duration calculation with large days values

* refactor: deduplicate CooldownBlock into internal/models, fix misleading variable names

- Move CooldownBlock struct to internal/models to eliminate duplication
  between proxy/interceptors and internal/ui packages
- Simplify proxy_flow.go by using direct assignment instead of field copy
- Rename latestStripped/latestDate to oldestVer/oldestDate for clarity

* fix: Dependency Cooldown Check Encapsulation (#207)

* fix: Encapsulate cooldown check

* feat: Add --skip-dependency-cooldown override

* fix: Code review fixes

---------

Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
2026-04-08 21:04:17 +05:30

146 lines
5.5 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
# 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
# Proxy mode. Default is true.
# 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_mode: true
# 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 a built-in profile.
npm:
enabled: true
profile: npm-restrictive # Built-in profile, template name, or path to custom YAML
pnpm:
enabled: true
profile: pnpm-restrictive
npx:
enabled: true
profile: npx
pnpx:
enabled: true
profile: npx
yarn:
enabled: true
profile: npm-restrictive
bun:
enabled: true
profile: npm-restrictive
# PyPI ecosystem. pypi-restrictive is a built-in profile.
pip:
enabled: true
profile: pypi-restrictive
pip3:
enabled: true
profile: pypi-restrictive
poetry:
enabled: true
profile: pypi-restrictive
uv:
enabled: true
profile: pypi-restrictive
# Dependency cooldown blocks installation of package versions published within
# a configurable time window.
dependency_cooldown:
enabled: true
days: 5