mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
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:
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user