When users have HTTP_PROXY/HTTPS_PROXY set in their shell (e.g. corporate
proxy), PMG's upstream transport routes all traffic through that external
proxy — including requests to localhost/127.0.0.1. The external proxy
cannot reach the user's loopback, causing EFAULT/ConnectionRefused errors.
This adds loopback bypass in two places:
- Proxy upstream transport skips external proxy for localhost/127.0.0.1/::1
- Child process env gets NO_PROXY so proxy-aware libs (axios) skip PMG's
proxy for loopback addresses
Fixes#193
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The spinner goroutine was writing carriage-return + status text to
os.Stdout every 100ms. In the non-interactive TTY path, the child
process also writes directly to os.Stdout, causing both writers to
race on the same file descriptor. The \r emitted by the spinner
resets the cursor to column 0 mid-line, corrupting and truncating
the child process output.
Fix by writing all spinner/status output to os.Stderr, which is the
standard Unix convention for diagnostic and status messages. This is
also consistent with how progress.go and ShowWarning already behave.
https://claude.ai/code/session_012jMiRSS4Jx9Bs7a2F4S6KN
Co-authored-by: Claude <noreply@anthropic.com>
* add support to merge system CA with PMG CA
* Keep CA cert immutable; merge system bundle only when writing proxy CA file
* Update proxy/certmanager/generator.go
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
* Update internal/flows/proxy_flow.go
Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
* update config field name
* Use integer-only guard when sizing merged CA bundle
* Use int64-only guard when sizing merged CA bundle
* add tests for firstReadablePath
* Update proxy/certmanager/generator.go
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
* fix linter
* refactor system CA merge API
* add max limit to 2MB for certificates
* update max limit to 2MB for certificate merging
* remove python specific env var for CAs
---------
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
* provide package blocked feedback in proxy mode
* update test case & clear status on block
* refactor reporting
* clearStatus on `continueExecution`
* set spinnerChan to nil
* add sync for spinner
* introduce enforce_always sandbox config & hooks for flows
* fix sandbox failing for unsupported commands
* add hooks for pypi package managers
* add tests for sandbox hook
* introduce enforce_always flag for ease use & CI
* make comments descriptive
* remove hooks & update config to add API to configure sandbox
* add comments
* rm unused function
* define contract for package executors
* introduce npx executor
* add npx and pnpx cmd support
* fix typo
* rm PackageExecutor and depend on PackageManager interface
* add support for PTY to handle parent-child process interaction
* refactor PTY handling in proxy flow
* enforce interactiveSession interface check
* close reader explicitly and clean npm version for pkg executors
* rm interaction from interceptors
* add docs and wait for outputRouter before exit
* add support for non interactive TTY for proxy mode
* add support for CI env var check for non interactive tty proxy mode
* update readme to include npx, pnpx support
* Update internal/flows/proxy_flow.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
* update ptyx lib
* fix docs typo
---------
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* feat: Add experimental proxy based npm interceptor
* refactor: Analysis cache
* ci: Add E2E for npm proxy
* fix: Handle dry-run in proxy flow
* fix: Handle special case for scope package name
* fix: Misc fixes
* fix: Code review fixes
* fix: Code review fixes
* refactor: Reusable code into base registry interceptor
* Pause npm process during user confirmation (#90)
* pause npm process when prompting user for confirmation
* disable progress bar
* fix logging and close chan on return
* update use of deprecated field
* refactor: Separation of concerns for handling process state
* fix: Safe permission for cert file
* fix: Handle nil check for interaction hook
* fix: Add test for base registry
* Fix goreleaser for windows build (#93)
* introduce platform specific process control
* rename common.go to common_flow.go
* feat: Add support for pause resume on windows
* fix: Code review fixes
* test: Add confirmation handler tests
---------
Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
* introduce a persistent config
* add tests and refactor config creation
* update config handling and add support for removing config
* add support to skip suspicious pkgs marked as trusted
* add support for config dir Env & unexport functions
* small fixes
* add assert for dir
* fix tests
* fix shell source line & trusted pkgs parsing
* fix flag inconsistency
* update config to read on each invocation and create if does not exist
* fix flags value being overridden
* remove redundant func call
* modify trusted pkg check to be config bound
* modify RemoveConfig to rm files & not dir. add tests for paths.go
* add versions for package for e2e
* modify tests to reset config
* fix: Simplify config persistence
* fix: Misc comments
* fix: Misc fix
* fix: Do not overwrite config file if exists
* fix: Do not overwrite config file if exists
* fix: Config cobra command should override and not replace
* fix: Create dir before writing config template
* fix: Create dir before writing config template
* fix: Misc refactoring
* test: Add test for is trusted package version
* Update cmd/setup/setup.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
* Update config/config.go
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
* Apply suggestion from @Copilot
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
* fix: Remove unused constant in config
* fix: Resolve conflict with event logger
* docs: Add doc for eventlogger.Logger interface
* test: Add E2E for config file creation
* fix: Code review fixes
---------
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Sahilb315 <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Add comprehensive event logging system with OS-specific location and rotation
Features:
- Event logging for security-relevant events (malware detection, installations)
- OS-specific default log locations (~/.pmg/logs/ on macOS/Linux, %LOCALAPPDATA%\pmg\logs\ on Windows)
- Automatic 7-day log rotation with daily log files (YYYYMMDD-pmg.log format)
- Support for custom log files via --log flag
- Thread-safe JSON logging with zero external dependencies
Implementation:
- New internal/eventlog package with comprehensive logging functionality
- Integration with guard.go to log malware detections and blocks
- Integration with main.go for initialization and cleanup
- Log file naming: YYYYMMDD-pmg.log (e.g., 20251216-pmg.log)
- Fail-safe design - PMG continues if logging fails
Event Types:
- malware_blocked: Malicious package blocked from installation
- malware_confirmed: User proceeded with flagged package
- install_allowed: Clean package installation allowed
- install_started: Package manager command initiated
- error: Error events
Testing:
- Comprehensive test suite with 6 passing tests
- Verified with real malware detection (e.g., @postman/tunnel-agent)
- Works with all package managers (npm, pip, etc.)
Technical Details:
- Thread-safe with mutex protection
- JSON format for easy parsing
- Automatic cleanup of logs >7 days old
- Background cleanup goroutine
- Uses only Go standard library (encoding/json, os, path/filepath, sync, time)
* Add update command support and improve event logging robustness
Features:
- Add support for npm/pnpm/bun/yarn update/upgrade/ci commands
- These commands now scan packages for malware before updating
- Closes security gap where update commands bypassed PMG protection
Improvements:
- Make event logging more defensive (graceful failure when not initialized)
- Add nil check for packageManager in guard to prevent test failures
- Add comprehensive tests for update commands
Testing:
- All 33+ unit tests passing
- Integration tests verified with real malware detection
- Tested with npm update, npm ci, npm upgrade, pnpm update, yarn upgrade
Files changed:
- packagemanager/npm.go: Added update/upgrade/ci to InstallCommands
- packagemanager/npm_test.go: Added 4 new test cases for update commands
- guard/guard.go: Added nil check for packageManager
- internal/eventlog/eventlog.go: Made logging more defensive
* Address review feedback: use log.Warnf instead of silently failing
Replace silent error handling in cleanupOldLogs with log.Warnf
to avoid completely swallowing errors when reading log directory.
Fixes reviewer feedback from abhisek.
* Remove update/upgrade command support, keep logging improvements
- Remove update/upgrade/ci commands from InstallCommands for npm, pnpm, bun, yarn
- Remove special handling for update/upgrade/ci commands in ParseCommand
- Remove update command test cases and restore original test
- Preserve logging improvements (nil check in guard.go, defensive check in eventlog.go)
All tests passing.
* Add support for yarn package manager
- Added yarn command handler in cmd/npm/yarn.go
- Added DefaultYarnPackageManagerConfig() in packagemanager/npm.go
- Added yarn dev flag support (--dev/-D) in ParseCommand()
- Added yarn analytics tracking in internal/analytics/event.go
- Registered yarn command in main.go
- Added yarn to alias setup in internal/alias/alias.go
- Added comprehensive test suite in packagemanager/yarn_test.go
- All tests passing (12 yarn tests + existing tests)
Resolves#30
Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
* docs: update README with yarn package manager support
Updated documentation to reflect yarn support addition:
- Changed yarn status from '🚧 Planned' to '✅ Active' in package managers table
- Added 'pmg yarn add <package>' command example
- Added 'yarn add <package-name>' to command list
- Added 'yarn install # Uses yarn.lock' to lockfile examples
This documentation update corresponds to the yarn implementation in the previous commit.
Related to #30
Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
* fix: address review feedback for yarn support
- Add support for bare 'yarn' command as manifest install
- Validate yarn install does not accept package names
- Add YarnExtractor for yarn.lock file support
Changes:
- packagemanager/npm.go: Added bare yarn command handling and validation
- packagemanager/yarn_test.go: Added test for bare yarn command
- extractor/ecosystems.go: Added Yarn PackageManagerName and extractor
- extractor/npm.go: Added YarnExtractor implementation
- go.mod, go.sum: Updated dependencies
Addresses review feedback from @Sahilb315
- Bare yarn command now triggers manifest install per docs
- yarn install <package> is now properly rejected
- yarn.lock extraction support added
Related to #30
Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
* chore: tidy go.mod and go.sum to remove unused dependencies
Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
* fix: add yarn.lock extractor mapping
- Add yarn.lock case in getExtractorForFile switch
- Import yarnlock extractor from osv-scalibr
- Enables lockfile parsing for manifest-based installations
Tested both package-based and manifest-based installations successfully.
Addresses review feedback from @Sahilb315
Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
* test: add validation test for yarn install with package name
- Add test case to verify 'yarn install <package>' is rejected
- Ensures invalid syntax returns no install targets
- Confirms IsManifestInstall is false for invalid commands
Addresses review feedback from @Sahilb315
Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
---------
Signed-off-by: shrvansudhakara <shrvansudhakara@gmail.com>
* follow proper consistent naming in pypi packagemanager
* follow proper consistent naming in pypi packagemanager - 2
* feat: add specialized command parsers to handle pip and uv command formats
* add uv support & modify extractor to be more robust
* add uv alias
* refactor var name & add error handling
* update readme & add support for `uv pip sync` cmd