* feat: Show cooldown report for pinned version installs
When a user installs a package with an explicit version (e.g.
npm install foo@1.2.3) and that version falls within the dependency
cooldown window, the cooldown block is now recorded and shown in the
report. Previously, the report only appeared when ALL versions of a
package were in cooldown (remaining == 0), causing pinned version
installs to fail with a confusing "version not found" error from the
package manager instead of a clear cooldown explanation.
Introduces InterceptorContext to carry per-execution data (pinned
versions) from the CLI command through the interceptor layer, keeping
it separate from long-lived dependencies like the analyzer and cache.
* fix: Normalize PyPI pinned version keys for cooldown lookup
CLI-provided package names (e.g. Flask_Cors) don't match the
URL-parsed form (flask-cors). Normalize keys once at construction
time so cooldown lookups match correctly.
* fix: Handle dots in PyPI package name normalization per PEP 503
denormalizePyPIPackageName already documented [-_.] replacement but
only handled underscores. Now also replaces dots with hyphens so
names like zope.interface match the URL-parsed form zope-interface.
* refactor: Extract shared cooldown stats recording into helper
Deduplicate identical stats-recording blocks from npm_cooldown.go
and pypi_cooldown.go into recordCooldownStats in cooldown.go.
* fix: Distinguish explicit version pins from auto-resolved versions
PyPI parsers resolve all packages to concrete versions (even without
a user-specified constraint), so HasVersion() was always true. Add
IsExplicitVersion to PackageInstallTarget, set it only when the user
provided an explicit constraint. Use it in proxy_flow.go to avoid
false pinned-version cooldown reports.
* refactor: Extract shared cooldown helpers to package-level functions
* feat: Add PyPI cooldown handler with PEP 691 file parsing
* feat: Add PyPI cooldown file stripping logic
* feat: Implement PyPI cooldown HandleMetadataRequest with PEP 691 filtering
* feat: Wire PyPI cooldown into pypi_registry interceptor
* update headers for no cache
* fix: Strip conditional GET headers to prevent 304 bypass in cooldown handlers
pip and npm clients cache Simple API / registry responses with ETags. On
subsequent requests they send If-None-Match, which causes the server to
return 304 Not Modified with no body. The cooldown response modifier
received an empty body, failed to parse it, and failed-open — letting
the client use its stale cached (unfiltered) response.
Fix: delete If-None-Match and If-Modified-Since from the request before
forwarding, forcing a full 200 response so the modifier always has a
body to filter.
Also removes the Content-Type guard from the PyPI modifier (the empty
Content-Type on 304 responses was a symptom of the same root cause) and
replaces Cache-Control: no-cache with the more targeted header deletion.
* docs: Add PyPI cooldown limitation for pip < 22.3 to dependency-cooldown docs
* 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>
* fix proxy mode failing for GH private packages
* skip analysis for private packages for proxy mode
* introduce npmRegistryConfig and support for handling multiple parsers in future
* refactor name and unexport npm config functions
* rm unused function
* rename & unexport npmRegistryURLParser
* add e2e for malicious pkg blocked using proxy mode
* 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>