From 7821c40312b97475cdc3c3e0abc7aae48442fd76 Mon Sep 17 00:00:00 2001 From: Sahilb315 Date: Wed, 15 Apr 2026 02:11:24 +0530 Subject: [PATCH] fix: Only check first non-flag arg against NonDownloadCommands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Scanning all args caused false proxy bypasses when package names or script arguments matched a NonDownloadCommands entry. For example: - npm exec test → "test" matched, proxy incorrectly skipped - npm update config → "config" matched, proxy skipped - npm publish --tag version → "version" matched, proxy skipped Fix by checking only the first non-flag argument (the subcommand). If it is not in NonDownloadCommands we break immediately, so trailing args never influence the classification. Applied to all four parsers: npm, pip/pip3, uv, and poetry. Regression tests added for the false positive cases. --- packagemanager/npm.go | 10 ++++++++-- packagemanager/npm_test.go | 22 ++++++++++++++++++++++ packagemanager/pypi.go | 8 ++++++++ 3 files changed, 38 insertions(+), 2 deletions(-) diff --git a/packagemanager/npm.go b/packagemanager/npm.go index ff178a7..ad07339 100644 --- a/packagemanager/npm.go +++ b/packagemanager/npm.go @@ -134,12 +134,18 @@ func (npm *npmPackageManager) ParseCommand(args []string) (*ParsedCommand, error } if installCmdIndex == -1 { - // Check if this is a known non-download command (e.g., npm ls, npm outdated). - // Unknown commands are treated as potential downloads — fail safe. + // Check only the first non-flag arg (the subcommand) against NonDownloadCommands. + // Scanning all args would cause false positives when package names or script + // arguments happen to match a known non-download command (e.g. `npm exec test`, + // `npm update config`, `npm publish --tag version`). for _, arg := range args { + if strings.HasPrefix(arg, "-") { + continue + } if slices.Contains(npm.Config.NonDownloadCommands, arg) { return &ParsedCommand{Command: command, IsKnownNonDownloadCommand: true}, nil } + break } return &ParsedCommand{Command: command}, nil diff --git a/packagemanager/npm_test.go b/packagemanager/npm_test.go index 064c533..a9a4553 100644 --- a/packagemanager/npm_test.go +++ b/packagemanager/npm_test.go @@ -561,6 +561,28 @@ func TestNpmProxyBehavior(t *testing.T) { isKnownNonDownloadCmd: true, isInstallationCommand: false, }, + // False positive regression: package/script names matching NonDownloadCommands words + { + name: "npm exec test — proxy runs (test is package arg, not subcommand)", + pm: func() (*npmPackageManager, error) { return NewNpmPackageManager(DefaultNpmPackageManagerConfig()) }, + command: "npm exec test", + isKnownNonDownloadCmd: false, + isInstallationCommand: false, + }, + { + name: "npm update config — proxy runs (config is package name, not subcommand)", + pm: func() (*npmPackageManager, error) { return NewNpmPackageManager(DefaultNpmPackageManagerConfig()) }, + command: "npm update config", + isKnownNonDownloadCmd: false, + isInstallationCommand: false, + }, + { + name: "npm publish --tag version — proxy runs (version is flag value, not subcommand)", + pm: func() (*npmPackageManager, error) { return NewNpmPackageManager(DefaultNpmPackageManagerConfig()) }, + command: "npm publish --tag version", + isKnownNonDownloadCmd: false, + isInstallationCommand: false, + }, // Unknown commands default to proxy running (fail safe) { name: "unknown npm subcommand — proxy runs (fail safe)", diff --git a/packagemanager/pypi.go b/packagemanager/pypi.go index fa3fc85..aacdec4 100644 --- a/packagemanager/pypi.go +++ b/packagemanager/pypi.go @@ -149,9 +149,13 @@ func (p *pipCommandParser) ParseCommand(args []string) (*ParsedCommand, error) { if installCmdIndex == -1 { for _, arg := range args { + if strings.HasPrefix(arg, "-") { + continue + } if slices.Contains(p.config.NonDownloadCommands, arg) { return &ParsedCommand{Command: command, IsKnownNonDownloadCommand: true}, nil } + break } return &ParsedCommand{Command: command}, nil @@ -376,9 +380,13 @@ func (p *poetryCommandParser) ParseCommand(args []string) (*ParsedCommand, error if installCmdIndex == -1 { for _, arg := range args { + if strings.HasPrefix(arg, "-") { + continue + } if slices.Contains(p.config.NonDownloadCommands, arg) { return &ParsedCommand{Command: command, IsKnownNonDownloadCommand: true}, nil } + break } return &ParsedCommand{Command: command}, nil