Commit Graph
3 Commits
Author SHA1 Message Date
Sahil BansalGitHubClaude Opus 4.6devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>Abhisek Dattadevin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
19d735cdd2 feat: emit cloud events for dependency cooldown and host observations (#243)
* feat: emit cloud events for dependency cooldown and host observations (#237)

Wire cooldown blocks and proxy host observations through the cloud sync
pipeline so they appear as telemetry in Control Tower.

- Cooldown blocks emit PACKAGE_DECISION with COOLDOWN_BLOCKED action and
  PmgDependencyCooldown context (publish date, cooldown days, days since
  publish, days remaining)
- Proxy host observations emit HOST_OBSERVATION with PmgHostObservation
  (hostname, method)
- Session summary now includes cooldown_blocked_count
- Updated buf API dependency for new proto schema

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* format file

* fix: add explicit eventlog mapping for EventTypeDependencyCooldown

Follow the existing pattern where every audit event type has an explicit
case in mapEventType and a corresponding constant in the eventlog package.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* Apply suggestion from @devin-ai-integration[bot]

Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-05-08 10:01:25 +05:30
Sahil BansalandGitHub 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.
2026-04-23 17:47:14 +05:30
Sahil BansalandGitHub 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
2026-04-20 21:10:05 +05:30