chore: Proxy mode without experimental tag (#147)

* chore: Proxy mode without experimental tag

* fix: Update proxy mode docs

* fix: Code review fixes
This commit is contained in:
Abhisek Datta
2026-02-02 12:58:28 +05:30
committed by GitHub
parent 4600ab0245
commit b5696f989f
10 changed files with 38 additions and 23 deletions
+1 -1
View File
@@ -51,7 +51,7 @@ func executeNpxFlow(ctx context.Context, args []string) error {
return fmt.Errorf("failed to create dependency resolver: %w", err) return fmt.Errorf("failed to create dependency resolver: %w", err)
} }
if config.Config.ExperimentalProxyMode { if config.IsProxyModeEnabled() {
return flows.ProxyFlow(packageExecutor, packageResolver).Run(ctx, args, parsedCommand) return flows.ProxyFlow(packageExecutor, packageResolver).Run(ctx, args, parsedCommand)
} }
+1 -1
View File
@@ -51,7 +51,7 @@ func executePnpxFlow(ctx context.Context, args []string) error {
return fmt.Errorf("failed to create dependency resolver: %w", err) return fmt.Errorf("failed to create dependency resolver: %w", err)
} }
if config.Config.ExperimentalProxyMode { if config.IsProxyModeEnabled() {
return flows.ProxyFlow(packageExecutor, packageResolver).Run(ctx, args, parsedCommand) return flows.ProxyFlow(packageExecutor, packageResolver).Run(ctx, args, parsedCommand)
} }
+1 -1
View File
@@ -51,7 +51,7 @@ func executeBunFlow(ctx context.Context, args []string) error {
return fmt.Errorf("failed to create dependency resolver: %w", err) return fmt.Errorf("failed to create dependency resolver: %w", err)
} }
if config.Config.ExperimentalProxyMode { if config.IsProxyModeEnabled() {
return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand) return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand)
} }
+1 -1
View File
@@ -51,7 +51,7 @@ func executeNpmFlow(ctx context.Context, args []string) error {
return fmt.Errorf("failed to create dependency resolver: %w", err) return fmt.Errorf("failed to create dependency resolver: %w", err)
} }
if config.Config.ExperimentalProxyMode { if config.IsProxyModeEnabled() {
return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand) return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand)
} }
+1 -1
View File
@@ -52,7 +52,7 @@ func executePnpmFlow(ctx context.Context, args []string) error {
return fmt.Errorf("failed to create dependency resolver: %w", err) return fmt.Errorf("failed to create dependency resolver: %w", err)
} }
if config.Config.ExperimentalProxyMode { if config.IsProxyModeEnabled() {
return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand) return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand)
} }
+1 -1
View File
@@ -51,7 +51,7 @@ func executeYarnFlow(ctx context.Context, args []string) error {
return fmt.Errorf("failed to create dependency resolver: %w", err) return fmt.Errorf("failed to create dependency resolver: %w", err)
} }
if config.Config.ExperimentalProxyMode { if config.IsProxyModeEnabled() {
return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand) return flows.ProxyFlow(packageManager, packageResolver).Run(ctx, args, parsedCommand)
} }
+5
View File
@@ -21,10 +21,15 @@ func ApplyCobraFlags(cmd *cobra.Command) {
globalConfig.Config.SkipEventLogging, "Skip event logging") globalConfig.Config.SkipEventLogging, "Skip event logging")
cmd.PersistentFlags().BoolVar(&globalConfig.Config.ExperimentalProxyMode, "experimental-proxy-mode", cmd.PersistentFlags().BoolVar(&globalConfig.Config.ExperimentalProxyMode, "experimental-proxy-mode",
globalConfig.Config.ExperimentalProxyMode, "Use experimental proxy-based interception (EXPERIMENTAL)") globalConfig.Config.ExperimentalProxyMode, "Use experimental proxy-based interception (EXPERIMENTAL)")
cmd.PersistentFlags().BoolVar(&globalConfig.Config.ProxyMode, "proxy-mode",
globalConfig.Config.ProxyMode, "Use proxy based interception")
cmd.PersistentFlags().BoolVar(&globalConfig.Config.Sandbox.Enabled, "sandbox", cmd.PersistentFlags().BoolVar(&globalConfig.Config.Sandbox.Enabled, "sandbox",
globalConfig.Config.Sandbox.Enabled, "Enable sandbox mode to isolate package manager processes (EXPERIMENTAL)") globalConfig.Config.Sandbox.Enabled, "Enable sandbox mode to isolate package manager processes (EXPERIMENTAL)")
cmd.PersistentFlags().BoolVar(&globalConfig.Config.Sandbox.EnforceAlways, "sandbox-enforce", cmd.PersistentFlags().BoolVar(&globalConfig.Config.Sandbox.EnforceAlways, "sandbox-enforce",
globalConfig.Config.Sandbox.EnforceAlways, "Apply sandbox to all commands, not just install commands (requires --sandbox)") globalConfig.Config.Sandbox.EnforceAlways, "Apply sandbox to all commands, not just install commands (requires --sandbox)")
cmd.PersistentFlags().StringVar(&globalConfig.SandboxProfileOverride, "sandbox-profile", cmd.PersistentFlags().StringVar(&globalConfig.SandboxProfileOverride, "sandbox-profile",
globalConfig.SandboxProfileOverride, "Override sandbox policy profile (built-in name or path to custom YAML)") globalConfig.SandboxProfileOverride, "Override sandbox policy profile (built-in name or path to custom YAML)")
// Hide the experimental proxy mode flag but keep it for backward compatibility
_ = cmd.PersistentFlags().MarkHidden("experimental-proxy-mode")
} }
+22 -12
View File
@@ -15,22 +15,22 @@ import (
const ( const (
// Environment variable key for the insecure installation flag // Environment variable key for the insecure installation flag
PMG_INSECURE_INSTALLATION_ENV_KEY = "PMG_INSECURE_INSTALLATION" pmgInsecureInstallationEnvKey = "PMG_INSECURE_INSTALLATION"
// Allow overriding the config path from the environment // Allow overriding the config path from the environment
CONFIG_DIR_ENV_KEY = "PMG_CONFIG_DIR" pmgConfigDirEnvKey = "PMG_CONFIG_DIR"
// Config path is computed as the user config directory + the default relative path // Config path is computed as the user config directory + the default relative path
// when not overridden by the environment variable // when not overridden by the environment variable
CONFIG_DEFAULT_HOME_RELATIVE_PATH = "safedep/pmg" pmgDefaultHomeRelativePath = "safedep/pmg"
// Default log directory is relative to the config directory. // Default log directory is relative to the config directory.
CONFIG_DEFAULT_LOG_DIR = "logs" pmgDefaultLogDir = "logs"
// Config file name. // Config file name.
// Important: The config file path and the schema should be backward compatible. In case of breaking config // Important: The config file path and the schema should be backward compatible. In case of breaking config
// changes, we must introduce a new file name and a migration path. // changes, we must introduce a new file name and a migration path.
CONFIG_FILE_NAME = "config.yml" pmgConfigFileName = "config.yml"
) )
//go:embed config.template.yml //go:embed config.template.yml
@@ -56,8 +56,12 @@ type Config struct {
// EventLogRetentionDays is the number of days to retain event logs. // EventLogRetentionDays is the number of days to retain event logs.
EventLogRetentionDays int `mapstructure:"event_log_retention_days"` EventLogRetentionDays int `mapstructure:"event_log_retention_days"`
// ExperimentalProxyMode enables experimental proxy-based package interception. // ProxyMode enables proxy-based package interception when supported by package managers.
// When enabled, PMG starts a proxy server and intercepts package manager requests in real-time. // When enabled, PMG starts a proxy server and intercepts package manager requests in real-time.
ProxyMode bool `mapstructure:"proxy_mode"`
// ExperimentalProxyMode is same as ProxyMode. Kept here for backward compatibility because
// we initially introduced it as an experimental feature.
ExperimentalProxyMode bool `mapstructure:"experimental_proxy_mode"` ExperimentalProxyMode bool `mapstructure:"experimental_proxy_mode"`
// Sandbox enables sandboxing of package manager processes with controlled filesystem, // Sandbox enables sandboxing of package manager processes with controlled filesystem,
@@ -151,12 +155,18 @@ func (r *RuntimeConfig) ConfigDir() string {
return r.configDir return r.configDir
} }
// IsProxyModeEnabled is a helper function to check for proxy mode with
// support for backward compatibility
func (r *RuntimeConfig) IsProxyModeEnabled() bool {
return (r.Config.ExperimentalProxyMode || r.Config.ProxyMode)
}
// DefaultConfig is a fail safe contract for the runtime configuration. // DefaultConfig is a fail safe contract for the runtime configuration.
// The config package return an appropriate RuntimeConfig based on the environment and the configuration. // The config package return an appropriate RuntimeConfig based on the environment and the configuration.
func DefaultConfig() RuntimeConfig { func DefaultConfig() RuntimeConfig {
// Backward compatibility for the insecure installation flag before config was introduced. // Backward compatibility for the insecure installation flag before config was introduced.
insecureInstallation := false insecureInstallation := false
if val := os.Getenv(PMG_INSECURE_INSTALLATION_ENV_KEY); val != "" { if val := os.Getenv(pmgInsecureInstallationEnvKey); val != "" {
if boolVal, err := strconv.ParseBool(val); err == nil { if boolVal, err := strconv.ParseBool(val); err == nil {
insecureInstallation = boolVal insecureInstallation = boolVal
} }
@@ -232,7 +242,7 @@ func loadConfig() {
// configDir computes the path to the config directory. // configDir computes the path to the config directory.
func configDir() (string, error) { func configDir() (string, error) {
dir := os.Getenv(CONFIG_DIR_ENV_KEY) dir := os.Getenv(pmgConfigDirEnvKey)
if dir != "" { if dir != "" {
return dir, nil return dir, nil
} }
@@ -242,7 +252,7 @@ func configDir() (string, error) {
return "", fmt.Errorf("failed to retrieve user config directory: %w", err) return "", fmt.Errorf("failed to retrieve user config directory: %w", err)
} }
return filepath.Join(userConfigDir, CONFIG_DEFAULT_HOME_RELATIVE_PATH), nil return filepath.Join(userConfigDir, pmgDefaultHomeRelativePath), nil
} }
// configFilePath computes the path to the config file. // configFilePath computes the path to the config file.
@@ -252,7 +262,7 @@ func configFilePath() (string, error) {
return "", fmt.Errorf("failed to get config directory: %w", err) return "", fmt.Errorf("failed to get config directory: %w", err)
} }
return filepath.Join(configDir, CONFIG_FILE_NAME), nil return filepath.Join(configDir, pmgConfigFileName), nil
} }
// eventLogDir computes the path to the event log directory. // eventLogDir computes the path to the event log directory.
@@ -270,14 +280,14 @@ func eventLogDir() (string, error) {
} }
} }
return filepath.Join(baseDir, CONFIG_DEFAULT_HOME_RELATIVE_PATH, CONFIG_DEFAULT_LOG_DIR), nil return filepath.Join(baseDir, pmgDefaultHomeRelativePath, pmgDefaultLogDir), nil
case "darwin", "linux": case "darwin", "linux":
configDir, err := configDir() configDir, err := configDir()
if err != nil { if err != nil {
return "", fmt.Errorf("failed to get config directory: %w", err) return "", fmt.Errorf("failed to get config directory: %w", err)
} }
return filepath.Join(configDir, CONFIG_DEFAULT_LOG_DIR), nil return filepath.Join(configDir, pmgDefaultLogDir), nil
default: default:
return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS) return "", fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
} }
+2 -2
View File
@@ -23,12 +23,12 @@ skip_event_logging: false
# This is the number of days to retain event logs. # This is the number of days to retain event logs.
event_log_retention_days: 7 event_log_retention_days: 7
# Experimental proxy mode. Default is false. # Proxy mode. Default is false.
# When enabled, PMG uses an experimental proxy-based interception approach instead of the # When enabled, PMG uses an experimental proxy-based interception approach instead of the
# default guard-based analysis. The proxy intercepts package manager requests in real-time # default guard-based analysis. The proxy intercepts package manager requests in real-time
# and analyzes packages as they are downloaded. This is an experimental feature and may not # and analyzes packages as they are downloaded. This is an experimental feature and may not
# work in all environments. # work in all environments.
experimental_proxy_mode: false proxy_mode: false
# Trusted packages are packages that are trusted by the user and will be ignored by the security guardrails. # 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. # This is useful for packages that are known to be safe and are used in the application.
+3 -3
View File
@@ -1,6 +1,6 @@
# Proxy Mode # Proxy Mode
PMG supports an experimental proxy based interception as an alternative to the current optimistic dependency resolution. When enabled via `--experimental-proxy-mode` flag: PMG supports proxy based interception as an alternative to the current optimistic dependency resolution. When enabled via `--proxy-mode` flag:
- PMG starts a micro-proxy server on a random localhost port - PMG starts a micro-proxy server on a random localhost port
- Runs `npm` and other supported package managers configured to use the proxy - Runs `npm` and other supported package managers configured to use the proxy
@@ -10,7 +10,7 @@ PMG supports an experimental proxy based interception as an alternative to the c
## Usage ## Usage
```bash ```bash
pmg --experimental-proxy-mode npm install lodash pmg --proxy-mode npm install lodash
``` ```
## Configuration ## Configuration
@@ -18,7 +18,7 @@ pmg --experimental-proxy-mode npm install lodash
To permanently enable proxy mode, add the following to your `config.yml` file: To permanently enable proxy mode, add the following to your `config.yml` file:
```yaml ```yaml
experimental_proxy_mode: true proxy_mode: true
``` ```
## Supported Package Managers ## Supported Package Managers