Commit Graph
5 Commits
Author SHA1 Message Date
648adcbda4 feat: add uvx (uv tool run) package executor (#357)
* feat(uvx): add uvx (uv tool run) package executor

Adds support for `uvx`, implemented as a PyPI Executor alongside pipx.
uvx is an alias for `uv tool run`: it installs a tool into an ephemeral
environment and runs it, so it has no install/list subcommand and the
first positional argument (or --from) is the package to audit.

Parsing highlights:
- --from overrides the positional command as the package to audit
- --with packages are audited as additional environment dependencies
- name@version shorthand (ruff@0.3.0, ruff@latest) is normalized
- flag parsing stops at the tool name so the tool's own flags are not
  misread as uvx options; uvx's value/boolean flags are registered so
  none greedily consume the package positional
- VCS/URL/local-path specs are skipped for registry auditing

Wires up command registration, analytics, shell alias/shim, cloud audit
mapping, a dedicated `uvx` sandbox profile (UV_*/PIP_* env, uv cache and
tool dirs), config policy, docs, unit tests and an E2E workflow step.

Closes #326

https://claude.ai/code/session_011hyLxq7oWJX5Dp4tCEfG19

* chore(uvx): align docs and base profile with uvx support

Incorporates the low-risk, non-parser improvements from the community
PR #345 (author non-responsive) into our implementation:

- list uvx (and the previously-missing pipx) as PyPI managers in the
  pypi-restrictive base profile package_managers and its README, so the
  base profile applies directly when selected via --sandbox-profile
- document uvx in docs/github-action.md and docs/proxy-mode.md
- add version / IsExplicitVersion assertions to the uvx parser tests

Our pflag-based parser is kept as-is: unlike #345 it audits --with
packages and handles all uvx short flags (e.g. -w), both of which the
community PR misses.

* fix(uvx): skip interpreter requests; use require in tests

Addresses review feedback on PR #357:

- uvx interpreter requests (`uvx python`, `uvx python@3.12`, `uvx pypy`,
  ...) launch an isolated interpreter rather than installing a PyPI tool.
  Treating the positional as a package made the guard flow resolve/analyze
  pkg:pypi/python (and python==3.12), which could wrongly block or fail a
  valid invocation. Skip these for the positional; --with packages on the
  same command are still audited.
- Use require.NoError / require.Len for fatal assertions in the uvx tests,
  matching the repo's testing convention, so a failure stops the subtest
  before a nil dereference instead of panicking.

* docs(uvx): document fail-open and --with-requirements trade-offs

Record the two deliberate parsing decisions raised in review as in-code
trade-off comments (no behavior change):

- unknown flags are tolerated (fail open), consistent with the other
  executors; the residual gap only affects non-proxy guard mode since the
  default proxy flow intercepts every registry download.
- --with-requirements / --with-editable values are consumed but not
  expanded into audit targets; expanding them needs manifest-extractor and
  guard changes, tracked as follow-up. Proxy mode still covers them.

* docs(uvx): drop --with-requirements limitation note

Per maintainer review: guard mode is being deprecated and auditing the
contents of an existing requirements file is a scanner's responsibility,
not PMG's. Remove the "known limitation / follow-up" note; the flags stay
registered only so their values are not mistaken for the tool positional.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-02 18:49:31 +05:30
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>
2026-06-21 18:22:15 +05:30
7620097613 feat : adds pipx support to PMG (#292)
* adding the pipx support to project

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>

* create excutors for pipx

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>

* add pipx yml

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>

* chores

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>

* pipx to use standard executor pattern

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>

* Address PR feedback for pipx support

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>

* Update pipx flags comments

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>

---------

Signed-off-by: DivyanshuVortex <divyanshuchandra9027@gmail.com>
Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
2026-06-10 16:26:33 +05:30
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
Abhisek DattaGitHubdevin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
e67735c1c3 feat: Add cloud sync event emit (#212)
* feat: Add cloud sync event emit

* fix: Linter fixes

* fix: Include malysis metadata in confirmed event

* fix: Code review fixes

* fix: Emit session complet event

* fix: Code review fixes

* chore: Add comment

* chore: Add cloud info in setup info command

* fix: Proxy flow must call install started

* fix: Code review fixes

* fix: Code review fixes

* Update internal/audit/cloud_sink.go

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>

* fix: Code review fixes

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-11 12:33:27 +05:30