mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
main
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
327c9c7068 |
feat(cooldown): respect trusted_packages in dependency cooldown (#342)
* feat(cooldown): respect trusted_packages in dependency cooldown Trusted packages are now treated as a superset waiver that bypasses every PMG control (malware analysis, cooldown, and any future controls). A globally trusted package is automatically exempt from the cooldown window and no longer needs a duplicate entry in dependency_cooldown.skip. The skip list remains the narrower, cooldown-only waiver for packages that must bypass the cooldown wait but still be malware-scanned. * refactor(cooldown): tag skip reason and audit-log skipped packages Address review feedback on #342: - Restore cooldownSkip to a pure single-list function (SRP); the merge into trusted_packages now happens in a separate mergeCooldownSkip step, driven by the exported CooldownSkip wrapper. - Extend CooldownSkipInfo with a CooldownSkipReason (TrustedPackage / CooldownSkipList) on both SkipAll and per-version entries, so callers can tell apart the broad waiver from the cooldown-only one. When both lists match the same package, trusted_packages wins. - Add audit.LogCooldownSkipped and emit it from the npm and PyPI interceptors on the SkipAll path, alongside the existing info log, carrying the source list as the reason. * refactor(cooldown): inline list merge, audit per-version exemptions Address further review feedback: - Drop the separate mergeCooldownSkip helper; cooldownSkip now writes into a shared *CooldownSkipInfo and is called twice from CooldownSkip (cooldown skip list first, trusted_packages on top so trusted entries override the reason on overlap). - Audit log every exemption, not just SkipAll: a new auditCooldownSkip helper in proxy/interceptors/cooldown.go emits one event per match (package-wide or per-version), each tagged with its source list. LogCooldownSkipped gains a version argument for the per-version case. - Cover the trusted_packages reason path in TestCooldownSkip. * fix(cooldown): avoid double-auditing trusted package exemptions auditCooldownSkip now only emits EventTypeCooldownSkipped for entries that came from dependency_cooldown.skip. Trusted-package exemptions already get an EventTypeInstallTrustedAllowed event at tarball-download time (proxy/interceptors/base_registry.go), so emitting a cooldown event for them too would double-count the same waiver. * emit trusted and cooldown skip events to cloud * fix tests * refactor(cooldown): return value from collectCooldownSkip, short-circuit on trusted SkipAll Address PR review feedback: - Rename cooldownSkip to collectCooldownSkip and return CooldownSkipInfo instead of mutating an input pointer. - Add mergeCooldownSkip to combine per-list results with trusted_packages taking precedence on overlap. - CooldownSkip now consults trusted_packages first and returns immediately on a package-wide trusted exemption (DC skip list cannot add anything). - Extend tests to cover disjoint pinned entries across both lists and the case where DC version-less subsumes a trusted pinned entry. * fix(audit): address cooldown review feedback * fix(cooldown): audit cooldown skips at download time with concrete version Backend rejects PackageVersion messages without a version, and audit logs should reflect the runtime fact (a specific version was skipped) rather than the config rule. Move the audit emission from metadata-request handling to download-request handling, where the concrete version is known, and require version in LogCooldownSkipped. * chore(audit): drop dead scope assignment in LogCooldownSkipped * refactor(cooldown): move skip-list logic into cooldown handlers Registry interceptors no longer compute CooldownSkip or branch on SkipAll; they just call HandleMetadataRequest. The npm and pypi cooldown handlers own the skip lookup, the package-wide exemption short-circuit, and (for pypi) the canonical-name denormalization. Also align LogCooldownSkipped with other LogXxx signatures by taking *packagev1.PackageVersion. * fix: Simplify audit logging for dependency cooldown skip * refactor: Simplify cooldown handling and maintain separation of concepts for trusted and DC skip packages * fix: Code review fixes * fix: Emit cooldown skipped audit event ONLY when an in-window version is skipped --------- Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com> |
||
|
|
61230fbcd7 |
feat(cooldown): add dependency_cooldown.skip list (per-control exemption) (#328)
Let dependency cooldown respect an explicit skip list so first-party / internal packages that must be installed the moment they are published (e.g. to sanity-test a freshly released version) are not held back by the cooldown window. Per review, this is a per-control skip list — NOT a second definition of "trusted package". There remains a single top-level `trusted_packages` (which waives malware analysis); `dependency_cooldown.skip` waives ONLY the cooldown wait, so a fast-tracked package is still malware-scanned. Matching: - a PURL without a version skips cooldown for all versions of the package (package-level) — the metadata passes through unmodified; - a PURL with a version skips cooldown for that version only — that version is preserved during stripping while other recent versions are still held. - config: DependencyCooldownConfig.Skip + CooldownSkip()/CooldownSkipInfo. - npm/pypi interceptors: bypass on package-level skip; thread per-version exemptions into the cooldown stripper so pinned versions survive. - docs + config template; unit tests for the matcher (package/version level, precedence, mismatches) and the skip-vs-trusted independence. Signed-off-by: dmdhrumilmistry <56185972+dmdhrumilmistry@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
8cb7b7d1c0 |
fix: npm Dependency Cooldown Select Stable Version (#291)
* fix: npm Dependency Cooldown Select Stable Version * fix: Code review fixes |
||
|
|
c3a3518c36 |
feat: Show cooldown report for pinned version installs (#225)
* 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. |
||
|
|
544b38b278 |
feat: Add PyPI dependency cooldown support (#221)
* 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 |
||
|
|
987bda5d6a |
feat: Add dependency cooldown for npm packages (#200)
* 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> |