Commit Graph
63 Commits
Author SHA1 Message Date
Sahil BansalandGitHub bafd3c0654 Update README to include GHCR installation detail (#383) 2026-07-16 18:08:29 +05:30
dc0e3202cc feat: Linux system-wide setup (pmg setup install --system) (#377)
* feat: add Linux system-wide setup

Install shared shims, managed configuration, and login-shell PATH integration so golden images and multi-user hosts can protect package installs for every user.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: keep local design documents untracked

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: harden and simplify Linux system install

Tighten shim detection, profile repair, and install ordering while
trimming over-specific doctor/info hints from the system-install path.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: clarify system-install doctor alias and shim path checks

Use UserBinDir for PATH checks and pass aliases as not required under
system install without treating that as active interception.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: tighten event-log soft-fail warning prefix

Prefix the warning with [pmg] and drop the redundant continuing clause.

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: add Linux system-install e2e and pin pnpm for add flake

Cover root system setup, PATH/profile.d, managed config, non-root
interception, and remove. Pin pnpm 11.10.0 on the package-manager e2e
job after an integrity crash on pnpm add.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: bump packageManager to pnpm 11.10.0 for e2e

Align package.json with the pnpm version we want in CI so action-setup
stops erroring on a version mismatch after the e2e integrity flake.

Co-authored-by: Cursor <cursoragent@cursor.com>

* ci: use npm init for pnpm e2e to avoid integrity crash

pnpm 11.x `pnpm init` still writes onFail:download; `pnpm add` then
fails after PMG analysis even on 11.10.0. Seed the temp package with
npm init instead.

Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: revert packageManager pin to pnpm 11.1.3

The e2e integrity crash is avoided by npm init; the 11.10.0 bump is
no longer needed.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: harden system-install review findings

Require root-owned, non-group/other-writable pmg for --system install;
allow remove without that validation. Doctor checks npm resolution for
PATH precedence, uses ImpliesInterception instead of message matching,
and documents version-manager shadowing. Pass profile bin dir from the
shim manager and note that system config ignores per-user files.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: harden doctor PATH checks and attribute cloud events by OS user

Doctor now verifies every installed package manager against the shim
directory, and system-install validation only requires a safe parent
directory. Cloud sync records username/uid on invocation context for
multi-user hosts sharing one endpoint.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: address system-install review findings

- shim: make system executable resolution injectable so tests pass under
  umask 002; skip the root-owner test when running as root
- doctor: treat resolution into either the system or per-user shim dir as
  intercepted, and collapse the shim-in-PATH check to a single call site
- setup: make remove (both --system and per-user) best-effort with
  errors.Join so one failed step no longer strands the other artifact
- shim: allow a group-writable install parent dir (Debian/Ubuntu ship
  /usr/local/bin as root:staff 2775) while still rejecting world-writable
  and non-root-owned parents
- audit: attribute cloud events to SUDO_USER when running under sudo
- docs: drop the soft-fail event-logging claim (hard-fail is retained)

* ci: normalize /usr/local/bin perms before system-install e2e

The GitHub ubuntu-latest runner ships /usr/local/bin world-writable so
tooling can install without sudo. System install correctly refuses a
world-writable dir for the shared binary (any local user could replace
it and hijack every user's npm/pip). No FHS-compliant distro or Docker
image ships it world-writable — it is always root:root 0755 or
root:staff 2775 — so this normalizes only the anomalous CI runner back
to standard perms and still exercises the real /usr/local/bin path.

* fix: actionable remedy for root-created per-user config dir

A pmg run as root with a preserved HOME (GitHub runners, sudo -E, su
without -) creates the invoking user's ~/.config/safedep as root-owned,
and event-log init then fail-closes every later non-root command.
Make that state self-solvable:

- event-log init permission errors exit with a usefulerror naming the
  likely cause and the chown fix instead of a bare fatal
- pmg setup doctor probes event-log dir writability and reports the
  same fix via a new per-result Fix override
- document the mechanism and remedy in system-install.md, along with
  the binary ownership requirements for --system
- consolidate this branch's doctor tests into doctor_test.go

* fix: resolve per-user paths from root's own home when running as root

Path resolution trusted HOME (and XDG_*), which sudo and su can preserve
from the invoking user (GitHub runners, sudo -E, su without -). Any pmg
run as root then created root-owned ~/.config/safedep inside that user's
home, and event-log init fail-closed every later non-root pmg/npm/pip
run for them. System install made sudo pmg the documented flow, turning
this latent bug into the happy path.

When euid is 0, configDir and cacheDir now resolve from root's passwd
home instead of the environment, so root state lands under /root and
user homes are never touched. PMG_CONFIG_DIR/PMG_CACHE_DIR still win,
non-root resolution is unchanged, and Windows is unaffected (no euid).
Event-log init stays fatal on failure; sudo-run package events are
attributed via SUDO_USER and synced by the exit auto-sync as usual.

E2E: GitHub runners preserve HOME under sudo, so assert that no sudo
pmg run leaks state into the runner's home, and that the managed-config
refusal fails for the documented reason rather than a permission brick.

* fix: triage the unwritable config dir remedy by cause

The chown hint is only correct when another account created files
inside the current user's own home. When a leaked HOME or
XDG_CONFIG_HOME points at another user's home (e.g. sudo -u on GitHub
runners), following it would chown that user's directory and brick
their pmg instead. Classify the failure against the passwd home,
which the leaked environment cannot influence, and prescribe:

- dir inside own home: restore ownership with chown
- dir outside own home: fix the leaked environment, never chown
- explicit PMG_CONFIG_DIR: make it writable

Used by both the fatal event-log error and the doctor check, and the
docs troubleshooting now carries the same two-case triage.

* ci: pin XDG_CONFIG_HOME for the cross-user e2e step; terse doctor fix

GitHub runners export XDG_CONFIG_HOME=/home/runner/.config and it leaks
through sudo -u, so the pmgtest pmg resolved the runner user's config
dir and fail-closed on its runner-owned log file (run 29289868727 shows
the triaged error catching exactly this). Set it inside the login shell
so it wins regardless of how the leak is delivered.

The remedy now returns a full-help and doctor-table pair from a single
triage, and drops the do-not-chown tail from the leak message.

* fix: adapt event-log error to the two-value remedy signature

Belongs with the previous commit; it was left unstaged and e0580b1
does not compile without it.

* fix: fall back to env path resolution when root has no passwd entry

Running as uid 0 without a resolvable root passwd entry (scratch
containers, minimal chroots) panicked at startup on every command,
because the euid-based path resolution had no fallback. Fall back to
env-derived resolution there: without a passwd database there is no
user switching, so the cross-user poisoning that branch prevents
cannot occur.

Also restore the underlying cause in the generic event-log init error
(minimal output hid it after the usefulerror change), and document
that root's per-user data lives under /root regardless of a preserved
HOME.

* fix: gate SUDO_USER trust and root path diversion; add doctor binary check

Address review findings on the system-install PR:

- cloud_sink: honor SUDO_USER for audit attribution only when euid==0.
  Without the gate any user could set SUDO_USER and spoof cloud-audit
  attribution to another account. Matches the guard in cmd/setup/cert.go.

- config: divert per-user paths to root's passwd home only on an actual
  sudo elevation (euid==0 && SUDO_USER set), not for every root euid.
  The blanket root diversion ignored HOME/XDG_CONFIG_HOME and silently
  stopped reading genuine root users' config (golden Docker images),
  regressing two tests that only fail when the suite runs as root.
  Genuine root honors the environment as before; su without - leaves no
  marker and stays a documented, loud-failing residual.

- doctor: add a system-only check re-validating that the binary the
  installed shims exec is still root-owned and non-writable, catching
  permission/ownership drift after install.

- shim: fold the duplicated shim-scan loop into firstShimContent.

* fix: harden system dirs at install; keep sudo attribution without passwd

Address remaining review comments:

- shim: force root:root 0755 on the managed system dirs (shim tree and
  profile.d) after MkdirAll. A pre-created dir with weaker ownership,
  possible under Debian's group-writable /usr/local/lib, would let a
  non-root user replace the shims every account executes.

- audit: when SUDO_USER has no passwd entry (minimal containers),
  attribute cloud events from sudo's recorded SUDO_USER/SUDO_UID env
  instead of falling back to root. Still gated on euid 0.

- setup: reword the root-without---system warning; alias/shim install
  follows HOME, so claiming it configures only root's home was wrong.

- shim: skip the non-root-owner validation test on Windows, where file
  ownership is not resolvable.

* fix: reject system binaries unreachable by other users; consistent info

The system-install validation checked the binary's own permissions and
the parent's tamper-safety but never reachability: a 0755 root-owned
binary under a 0700 directory (e.g. /root/pmg) passed every check while
every non-root user's shim failed with exit 127. Walk the directory
chain to / and require the search bit for others; doctor's system
binary check inherits this. E2E gains a reject case for a binary under
a non-searchable directory.

setup info: render alias/user-shim/system-shim rows through one
installed-state formatter (location when installed, "not installed"
otherwise) instead of a mix of booleans, paths, and prose.

* fix: stop reowning /etc/profile.d; document group-writable and su gaps

writeSystemProfile chowned/chmod'd /etc/profile.d itself, a shared
system directory pmg does not own, silently overriding any perms a
sysadmin set on it. Secure only the file pmg writes (pmg.sh) via
secureSystemFile, which also forces 0644 explicitly so a restrictive
root umask cannot leave the snippet non-world-readable (which would
drop the shim dir from other users' login-shell PATH).

Docs: add Limitations entries for the group-writable install dir
bypass (validation is defeatable on non-sticky group-writable dirs
like Debian's /usr/local/bin) and the elevation-only scope (su without
- can still poison the caller's home; sudo -u cannot poison another
account). Trim the requireSafeParentDir comment to a pointer.

* refactor: separate unwritable-dir diagnosis from remedy rendering

Address the open review threads on #376:
- rename realUserHomeDir to currentUserHomeDir and fail when the passwd
  entry has no home directory
- split UnwritableConfigDirRemedy into classifyUnwritableDir (cause
  diagnosis) and pure message rendering so each function has one job
- replace cmd/setup's duplicate pathIsUnderDir with the shared
  config.PathWithinDir, now guarding empty inputs

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011rWmR6NS47FpedJsrTWk8A

* fix: repair umask-clamped modes on system shims and managed config

os.WriteFile and os.MkdirAll honor the process umask, so a hardened root
umask (e.g. 077) produced 0700 shims other users cannot execute and a
0600/0700 managed config non-root pmg runs cannot read - silently
disabling the system-wide policy. Chmod/chown the artifacts explicitly
after writing, with unix regression tests running under umask 077.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011rWmR6NS47FpedJsrTWk8A

* refactor: address system-install maintainability review

- move PathWithinDir and the root-owned mkdir/chmod helpers into a new
  internal/fsutil package; config no longer exports a generic fs util
- create managed-config directories with MkdirAllRootOwned, which only
  sets ownership and mode on directories it creates - drops the
  hardcoded safedep parent-dir heuristic and never touches pre-existing
  directories
- collapse NewSystemShimManagerForRemove into NewSystemShimManager and
  validate the executable in Install, where the action needs it; Remove
  works regardless of binary state
- rename ShimConfig.ManageProfile to SystemProfile and document it
- name the Linux-only system paths linuxSystemBinDir/ProfilePath and
  document the Unix-only validation semantics
- share the PMG_BIN shim variable name between writeShimScript and
  parseShimPMGBin via the shimPMGBinVar constant
- cloud attribution falls back to the effective uid when SUDO_UID is
  absent, so sudo-invoked commands are not misattributed to root

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011rWmR6NS47FpedJsrTWk8A

---------

Co-authored-by: Sahilb315 <bansalsahil315@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude <noreply@anthropic.com>
2026-07-14 21:34:22 +05:30
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
Kunal SinghandGitHub f9ca26d112 Add Trendshift badge to README (#355)
Signed-off-by: Kunal Singh <kunalsin9h@gmail.com>
2026-06-30 13:25:10 +05:30
Abhisek DattaandGitHub 7b13b6bfb3 docs: Update README GHA example (#353) 2026-06-26 09:47:14 +00:00
c47776db27 feat(proxy): persistent proxy server mode (#351)
* refactor(flows): extract SetupCACertificate for reuse

Move the CA load/generate/merge logic out of proxyFlow into an exported
flows.SetupCACertificate so the persistent proxy server can reuse it.

* feat(proxy): add persistent proxy server with start/stop/env/status

Introduces 'pmg proxy' commands backed by internal/proxyserver: a long-lived
MITM proxy that intercepts package managers via env vars (no shims). Supports
--daemon (Unix), --state, --port; generic 'env' output that skips cert vars
when the CA is OS-trusted; opt-in 'stop --fail-on-violation' (fail-closed on
crash) with a synchronous cloud event flush; and the malysis analysis cache.

* feat(action): add server-mode for persistent proxy

When server-mode=true the action starts the proxy daemon and injects proxy
env vars into the job instead of installing shims.

* test(proxy): add persistent proxy server E2E workflow

* docs(readme): document persistent proxy server mode

* fix(proxy): create cache dir before writing state file and daemon log

On a fresh CI runner the cache directory does not exist yet; os.OpenFile and
os.WriteFile do not create parent dirs, so 'pmg proxy start --daemon' failed
with 'no such file or directory'. MkdirAll the parent before writing.

* docs: add persistent proxy server architecture doc

* refactor proxyserver

* fix(proxy): always emit cert env vars instead of skipping on OS-trust status

npm/pip/yarn/requests trust the MITM CA inconsistently across tools, versions,
and configs; many still use bundled CA stores. Always emitting the cert-path
env vars is the conservative choice that works regardless, and is harmless for
tools that read the OS store (they ignore the vars). Skipping them when a
system CA exists would silently break any tool still on a bundled store.

* refactor(proxy): drop redundant audit init in daemon; rely on main.go

main.go's PersistentPreRun already initializes the audit pipeline for every
command (including the daemon's re-exec'd child) and closes it at process exit.
Re-initializing in proxyserver.Run created a second auditor and a second
cloud-sync WAL connection, orphaning the first. Removing it makes the daemon
consistent with the normal proxy flow, which never self-initializes audit.

* fix(proxy): bypass proxy env when flushing events to cloud on stop

pmg proxy stop inherits HTTP(S)_PROXY (injected by 'pmg proxy env') pointing at
the PMG proxy it just shut down. The cloud sync gRPC client honored those vars
and routed api.safedep.io through the dead proxy, failing with 'connection
refused' so no events were delivered. Clear the proxy env vars before the sync
so PMG's own cloud traffic goes direct.

* chore(proxy): address review feedback

- configurable bind host via proxy.server.listen_host (default loopback)
- proxy commands use ui.ErrorExit instead of returning errors to cobra
- rename errcode to ProxyPolicyViolation (covers malware + cooldown)
- share cloud sync via audit.DrainToCloud (de-dup with cmd/cloud/sync)
- centralize proxy CA bundle path in certmanager
- docs: persistent proxy cert trust + bind address

* fix(proxy): show real message on fail-on-violation error

stopExitError set only WithMsg, but ui.ErrorExit renders HumanError, so the
framed error showed 'no human-readable message available'. Set both from one
string, and emit the framed error before the stdout summary so the blocked
count is stated once.

* fix(proxy): flush cloud events from the daemon, not stop

The stop process inherits HTTP_PROXY (from 'pmg proxy env'), so its cloud
client routed api.safedep.io through the already-stopped proxy and failed with
connection refused. Move the flush into the daemon's shutdown, which has no
proxy env (it started before env injection) and dials SafeDep directly.

- daemon flushes on shutdown via audit.DrainToCloud and records the result in
  the state file; stop surfaces it (on both success and fail-on-violation
  paths) since the daemon's own logs aren't visible to stop
- coordinate stop's wait with the daemon shutdown budget; on timeout, error
  out without reading stale state or deleting the file (fail-closed)
- persist blocked count before the flush so the gate stays correct if the
  flush hangs or the daemon is killed mid-flush
- remove now-redundant cloud_flush.go

* disable auto-sync for proxy cmds

* feat(proxy): periodic cloud sync + move proxy env vars to packagemanager

- daemon runs a periodic cloud-sync ticker so the shutdown flush stays small;
  the run total is reported by stop, and shutdown timeouts are coordinated
- move EnvVarForProxy from config to packagemanager (it is package-manager
  knowledge); the shared function now builds the proxy URL and NO_PROXY itself,
  removing the duplicated construction in the per-command and persistent paths
- relocate the #319 yarn and #339 IPv6 regression tests alongside the function
- enable cloud sync in the persistent-proxy E2E workflow and fix the stale
  internal/proxystate path filter

* refactor(proxy): rename cloudFlushLockTimeout to cloudFlushLockWait

Consistent timeout naming: *LockWait is the lock-acquire bound, *Timeout is
the sync-RPC bound. Previously the final-flush pair was cloudFlushLockTimeout
vs cloudFlushTimeout — two lookalike names for different operations.

* refactor(proxy): extract cloudFlush and trim duplicate shutdown comments

The shutdown's final-flush block is now a cloudFlush helper, symmetric with
startCloudSyncLoop (one-shot vs loop). Removed the triplicated ticker/lock
contention comments, keeping the contract on the function doc and one-line
pointers at the call sites.

* docs: update persistent proxy cloud sync to daemon-owned model

The daemon now owns cloud delivery (periodic sync while serving + final flush
on shutdown); stop signals it, waits, and reports the result. Rewrite the Cloud
event sync section, fix stop attributions, add the cloud_sync state field, and
update the sequence diagram.

* docs: move Usage section up below How it works

Put the copy-paste recipes near the top so users find them before the internals.

* refactor(proxy): address PR review feedback

- configurable bind host/port via --host/--port flags + config (listen_host,
  listen_port), bound directly to config fields per PMG's flag pattern
- daemon log path via --log-file and readiness timeout in ProxyDaemonConfig;
  Daemonize no longer owns path policy (caller validates, fails fast)
- gate periodic cloud sync on auto_sync; suppress detached background sync for
  proxy commands instead of flipping the flag
- pmg proxy env --export emits shell-quoted lines for eval (spaces survive)
- extract shared flows.BuildCachedMalysisAnalyzer, dropping the analyzer+cache
  duplication between proxy flow and proxy server
- add internal/proxyserver/doc.go documenting the package + boundary vs flows
- E2E: assert malicious installs are blocked (drop continue-on-error)
- docs: trim Commands/State-file to user contracts; refresh bind address

* refactor(proxy): proactive alignment fixes from whole-PR review

- gate the shutdown cloud flush on auto_sync too, matching the periodic ticker
  (auto_sync consistently controls all daemon-driven cloud delivery)
- ResolveStatePath takes cacheDir instead of *RuntimeConfig, keeping state.go
  free of config dependency
- drop the empty-host comment in listenAddr; keep the loopback guard so a blank
  host never silently binds all interfaces

* fix: Decouple localdb with malysis analyser construction

* fix: Persist global args before proxy server daemon exec

* fix: GitHub Action for cloud auto-sync in server mode

---------

Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
2026-06-26 11:19:28 +05:30
Abhisek DattaandGitHub d360e75897 feat: Add malysis cache implementation with proxy flow integration (#346)
* feat: Add malysis cache implementation with proxy flow integration

* fix: Code review fixes
2026-06-22 10:12:02 +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
Abhisek DattaandGitHub 4f0db15ede feat: Add opt-in support for proxy CA cert installation (#318)
* feat: Add opt-in support for proxy CA cert installation

* fix: Code review fixes

* fix: Code review fixes

* fix: Code review fixes

* fix: Code review fixes

* fix: Code review fixes

* docs: Add limitation for MacOS MDM script
2026-06-03 23:15:02 +05:30
Sahil BansalandGitHub 0f084931c6 docs: add safe-chain to comparison table (#316) 2026-06-01 17:28:25 +05:30
37958f4441 docs: mark Socket as supporting no account or API key (#299)
Co-authored-by: Claude <noreply@anthropic.com>
2026-05-27 12:12:11 +05:30
a651761636 docs: Update README (#296)
* docs: Update README

* docs: Add diagram for how PMG works

* docs: Updated featured docs

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

* Update README.md

Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
2026-05-26 16:45:14 +00:00
Sahil BansalandGitHub 321896996f fix: skip PyPI dependency cooldown for clients without PEP 691 support (#295)
PMG was forcing Accept: application/vnd.pypi.simple.v1+json on all
Simple API requests regardless of client capability. Older pip versions
(< 22.3) that only understand text/html would reject the JSON response,
breaking installs entirely.

Now checks the client's original Accept header before applying cooldown.
If PEP 691 is not supported, the request passes through unchanged with
a warning log recommending pip upgrade.
2026-05-26 20:50:10 +05:30
Sahil BansalandGitHub 083f82dd79 feat: Add pmg setup doctor command (#290)
* feat: add doctor check runner core types and logic

* feat: add doctor checks for config, binary, directory, and aliases

* feat: add doctor checks for sandbox and security features

* feat: add protection verification check using test malicious packages

* feat: add summarized package manager availability check

* feat: add pmg setup doctor command with compact output

* feat: add PATH shim verification to doctor command

* fix: improve doctor command UX and alias detection

- Capitalize all check messages for consistent output
- Dim passing checks, color warn/fail for visual clarity
- Silence empty Cobra error output on doctor failure
- Remove redundant pmg binary check (self-evident)
- Fix alias IsInstalled to skip commented-out source lines
- Improve protection failure message

* refactor: remove package manager availability check from doctor

* fix: handle os.RemoveAll error in doctor protection check

* refactor: use table layout for setup doctor, extract shared table renderer

Move renderTable, truncate, and visibleWidth helpers from cmd/sandbox
to internal/ui so both sandbox and setup doctor share them. Rewrite
setup doctor output to use the same table structure as sandbox doctor.
Fix VisibleWidth to count runes instead of bytes for correct alignment
with multi-byte UTF-8 characters.

* docs: add pmg setup doctor to README, remove manual verification step

* refactor: use constants for check names, rename and inline doctor helpers

Address PR review comments: extract check name constants, rename
CheckConfigFile to CheckFileExists and CheckDirectoryWritable to
CheckDirectoryExists for reusability, inline trivial wrappers
(CheckSandbox, CheckSecurityFeature, CheckProxyMode), and add
fix hints for all checks with correct config keys.

* refactor: inline simple doctor checks into command layer

* fix: skip protection check when aliases and shims are inactive

Protection checks now fail immediately when shell aliases and shims
are both inactive, instead of falsely passing by running through the
pmg binary directly. Also clean up summary messages to remove
redundant fix hints and truncated paths.
2026-05-26 12:21:39 +05:30
Abhisek DattaandGitHub 9b0e12f130 feat: Add Support for Optimistic Cloud Sync (#273)
* feat: Add support for background sync

* refactor: Maintain single source of truth for command defn

* fix: Code review fixes

* fix: Code review fixes

* docs: Add corner case inline doc
2026-05-20 13:56:50 +05:30
Abhisek DattaandGitHub 5872f5281f docs: refresh README for clarity and conversion (#270)
- Remove top banner and add a tagline under the H1 so the value
  proposition sits above the fold; move the demo GIF above the badges.
- Reframe "How PMG Works" as defense in depth with three explicit
  layers (Threat Intelligence, Policy/Cooldown, Sandbox) and promote
  Dependency Cooldown out of the Features table.
- De-duplicate install instructions between Quick Start and Installation,
  and drop the all-"Yes" Status column from the supported package
  managers table.
- Update GitHub Actions snippet to actions/setup-node@v6 and add a
  comment recommending SHA pinning for third-party Actions.
- Add Mini Shai-Hulud (300+ npm packages compromised) to the recent
  malicious-package examples.
- Tighten prose: remove filler adverbs, passive voice, em-dashes, and
  marketing fluff; split semicolon-joined clauses into separate
  sentences.
2026-05-19 09:48:03 +00:00
46cc70db53 feat: add GitHub Action for one-step PMG setup in CI (#263)
* feat: add GitHub Action for one-step PMG setup in CI

Composite action at repo root that downloads PMG (with SHA-256 verification
against the upstream checksums.txt), runs `pmg setup install`, and wires
shims onto $GITHUB_PATH so subsequent `npm install` / `pip install` calls
are transparently analyzed.

Defaults are conservative: malware blocking + dependency cooldown + proxy
mode (matching PMG's own defaults). Sandbox is opt-in because enabling
Landlock/Bubblewrap on ubuntu-latest requires relaxing AppArmor
user-namespace restrictions.

Cloud sync uses the documented SAFEDEP_API_KEY / SAFEDEP_TENANT_ID env-var
fallback so we skip the keychain codepath that has no usable backend in
headless CI. When cloud is enabled and no endpoint-id is supplied, the
action sets PMG_CLOUD_ENDPOINT_ID=github-actions/${GITHUB_REPOSITORY} so
events aggregate per repository instead of per ephemeral runner hostname.

Closes #248.

https://claude.ai/code/session_01ARb8ZiBiJjvhWjchBXraAh

* fix(action): drop github.repository template from input description

Action manifest validation rejected the action.yml because the endpoint-id
input description contained ${{ github.repository }} — template expressions
aren't evaluated in input description text and trip the validator with
"Unrecognized named-value: 'github'". This caused every job using uses: ./
to fail before any step ran.

Also switch the config-file e2e job to verify the staged file directly
instead of calling `pmg config get`, which is not in the v0.13.0 release
that "latest" resolves to today.

https://claude.ai/code/session_01ARb8ZiBiJjvhWjchBXraAh

* fix(action): address review comments on PR #263

- Drop opinionated defaults on PMG_* toggle inputs. All defaults are now
  empty strings, and the action only exports PMG_* env vars when the
  caller explicitly sets the input. Without this, defaults like
  PMG_PARANOID=false silently shadowed config-file overrides because env
  vars beat config.yml in Viper precedence.
- Verify cached PMG against upstream checksums.txt on every cache hit.
  The cached tarball is stored alongside the binary and re-hashed against
  the freshly-fetched checksums.txt; on drift, the cache entry is evicted
  and re-downloaded.
- Export PMG_* env vars BEFORE running `pmg setup install` so settings
  like disable-telemetry actually apply during setup, not just to
  subsequent package-manager calls.
- Add `|| true` to the grep that extracts the expected checksum so
  set -e doesn't kill the script before the friendly error message fires
  when no checksum entry is found.
- Pin third-party actions (actions/checkout, actions/setup-node) to
  commit SHAs to match the repo's supply-chain hardening convention.
- Fix the malicious-package E2E test capturing tee's exit code instead
  of npm's; redirect to a file and check the actual command exit code.
- Add an E2E job that asserts PMG_PARANOID is unset when only
  config-file is provided — regression guard for the precedence fix.

https://claude.ai/code/session_01ARb8ZiBiJjvhWjchBXraAh

* ci(action-e2e): scope sandbox tests to action setup, not PMG runtime

The landlock job was running `npm install express` with no explicit
sandbox profile and the default profile blocks something npm needs
(PMG's own e2e uses `--sandbox-profile npm-restrictive` to make this
viable). Bubblewrap happened to pass, but verifying the default sandbox
profile is permissive enough for arbitrary package installs is PMG's
e2e responsibility — this workflow's job is to assert the action wires
sandbox config correctly.

Switch both drivers to a matrix and verify only what the action owns:
PMG_SANDBOX_* env vars propagated, pmg binary runs, bwrap is installed
when requested, AppArmor user-ns restriction relaxed.

https://claude.ai/code/session_01ARb8ZiBiJjvhWjchBXraAh

* ci(action-e2e): bump setup-node to 24

Node 20 reached end-of-life and setup-node now warns on it. Match the
version pinned by publish-npm.yml (the repo's newest workflow). Updated
the README and docs/github-action.md quick-start examples to match.

https://claude.ai/code/session_01ARb8ZiBiJjvhWjchBXraAh

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-05-18 00:44:06 +05:30
Abhisek DattaandGitHub 8b94b860a7 chore: Add install.sh based installation option (#234) 2026-05-04 16:16:58 +00:00
Sahil BansalGitHubdevin-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>
996d9aeca0 Add config support for disabling telemetry (#226)
* Add config-driven telemetry disable and surface telemetry status

* Update config/config_template_test.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>

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: devin-ai-integration[bot] <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-04-22 22:04:56 +05:30
365deb1897 feat: Add proxy_install_only config to restrict proxy to download commands (#222)
* feat: Add proxy_install_only config to restrict proxy to download commands

Introduces proxy_install_only (default: false) which, when enabled,
skips the proxy for package manager commands that do not download
packages (e.g. npm ls, pip list), avoiding unnecessary MITM overhead.

- Add ProxyInstallOnly to Config and config template
- Add IsKnownDownloadCommand / MayDownloadPackages to ParsedCommand
- Add DownloadCommands to npm and pypi PM configs covering update,
  ci, audit, dlx, exec, x, download, run and equivalents per PM
- Extract shared runner.Execute used by both proxy flow and guard
- Proxy flow short-circuits to runner.Execute for non-download commands
  when proxy_install_only=true

* refactor: Inject CommandExecutor into guard to fix dependency direction

guard depended on internal/runner, which inverted the intended layer
hierarchy. Now guard defines a CommandExecutor function type and accepts
it as a constructor argument. internal/flows (the composition root)
creates the executor closure wrapping runner.Execute and injects it,
keeping guard free of internal/ dependencies.

* refactor: Invert proxy_install_only logic to use known non-download commands

Replace the DownloadCommands allowlist (opt-in, fail-open) with a
NonDownloadCommands denylist (opt-out, fail-safe). The proxy now runs
for all commands except those explicitly known to not download packages.
Unknown or future package manager subcommands default to running with
the proxy.

Includes script runners (run, start, test, stop, restart) that can spin
up local servers — setting proxy env vars on these breaks them without
providing any security benefit. Also covers removal commands and local
operations that never contact the registry.

* fix: Support PMG_* env vars regardless of config file state

AutomaticEnv only resolves env vars for keys Viper already knows about
via AllKeys(). When a key is absent from the config file (commented out,
new key added after last setup, or no config file at all), Viper had no
knowledge of it and silently skipped the env var.

Fix by registering all Config struct fields as Viper defaults via
reflection (using mapstructure tags) before reading the config file.
This ensures PMG_* env vars work in all cases.

Precedence: cobra flags > env vars > config file > defaults.
SetDefault is used (not Set) so env vars and config file can still
override the Go defaults freely.

Tests added covering all precedence levels including the key-absent-
from-config-file case that was the original bug report.

* fix: Only check first non-flag arg against NonDownloadCommands

Scanning all args caused false proxy bypasses when package names or
script arguments matched a NonDownloadCommands entry. For example:
- npm exec test → "test" matched, proxy incorrectly skipped
- npm update config → "config" matched, proxy skipped
- npm publish --tag version → "version" matched, proxy skipped

Fix by checking only the first non-flag argument (the subcommand).
If it is not in NonDownloadCommands we break immediately, so trailing
args never influence the classification. Applied to all four parsers:
npm, pip/pip3, uv, and poetry.

Regression tests added for the false positive cases.

* refactor: Replace reflection-based Viper defaults with embedded template

Load the embedded config template as the Viper base so all keys are
registered upfront, enabling PMG_* env vars to work regardless of
whether a key exists in the user's config file.

* fix: Restore trusted_packages template entry and revert DefaultConfig change

* docs: Document environment variable overrides for config keys

* update npm test cmd

* refactor: extract shared non-download command detection helper

Replaces duplicated first-non-flag-arg detection loops in npm.go and
pypi.go (pip + poetry parsers) with a shared isFirstNonFlagArgInList
helper in packagemanager.go.

https://claude.ai/code/session_01AHaKF3vc2Haj9tK3jgUBAs

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-04-17 01:13:30 +05:30
a128a60982 docs: Add dependency cooldown docs (#209)
* docs: Add dependency cooldown docs

* fix: Remove unnecessary params

* Update docs/dependency-cooldown.md

Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

* fix: Cooldown guarantees

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
2026-04-08 17:19:30 +00:00
Abhisek DattaandGitHub 64b95b3ad0 docs: README Update (#199)
* docs: Update README

* docs: Update README

* docs: Update README

* fix: Uninstallation instructions
2026-04-07 00:56:21 +05:30
5fdc3a03ae update README.md & workflows (#192)
* update README.md

* ci: Remove paths-ignore filters from all workflows

Removes docs/ and *.md path exclusions so required checks always run,
preventing PRs from being blocked when only documentation files change.

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

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 19:54:25 +05:30
d112ded3da feat: Merge template config into existing user config during setup install (#189)
* docs: Add config merging design spec for #114

Defines the merge-during-setup-install approach for keeping user
configs up to date with new template keys while preserving all
existing values, comments, and formatting.

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

* docs: Add implementation plan for config merging

TDD-based plan with 6 tasks: dependency setup, failing tests,
core merge implementation, integration test, WriteTemplateConfig
integration, and full verification.

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

* feat: Merge template config into existing user config during setup install

Instead of skipping when a config file exists, WriteTemplateConfig() now
merges missing keys from the embedded template into the user's config
using YAML AST manipulation. Preserves all user values, comments, and
formatting. Only adds keys present in the template but absent in the
user's config.

Closes #114

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

* fix: Graceful error handling for config loading and setup commands

Replace panics in loadViperConfig with error returns so the app falls
back to defaults instead of crashing on malformed config files. Add
SilenceUsage to setup install/remove commands so runtime errors don't
dump the full usage text.

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

* add test cmd in readme

* update copy text

* refactor: Address review feedback on config merging

- Rename existing/template to dest/source for generic util naming
- Remove unnecessary code comments (Rule N references, obvious comments)
- Add AGENTS.md with dev guide and code style rules, symlink CLAUDE.md
- Add BenchmarkMergeYAML (~46μs/op on M4 Pro)
- Remove stale design spec

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

* update `MergeYAML` to use from dry/utils

* update AGENTS.md

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-31 19:21:01 +05:30
Abhisek DattaandGitHub e31a11e8e2 docs: Update README (#182)
* docs: Update README

* docs: Update README
2026-03-11 11:04:05 +05:30
d3cb15a3ea docs: Update README (#163)
* docs: Update README

* docs: Misc fixes

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

* Update README.md

Co-authored-by: Copilot <175728472+Copilot@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: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-16 13:35:58 +05:30
Sahil BansalandGitHub a6cb60a757 Treat suspicious as malicious in paranoid mode (#156)
* paranoid mode blocks suspicious packages

* enable sandbox for paranoid flag

* rm sandbox enabling for paranoid mode

* update docs
2026-02-10 22:22:40 +05:30
41e3b9b22e Deprecate malysis active scanner (#155)
* deprecate malysis active scanner

* Update config/config.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* copilot fixes

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-10 20:38:55 +05:30
28c7b6c843 Make proxy mode default for npm based managers (#148)
* update npm pkg managers to use proxy mode as default

* update config template for default to true for proxy_mode

* update e2e for proxy mode

* update info cmd for correct proxy mode status

* Update config/config.template.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* Update config/config.template.yml

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* Update config/config.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-02-02 14:30:00 +05:30
Abhisek DattaandGitHub be63fdd6ea fix: Remove Emoji from Setup (#142)
* fix: Remove emoji from setup

* fix: Update README demo
2026-01-27 20:08:23 +05:30
Sahil BansalandGitHub 224658e6d2 Update PMG banner (#138)
* update pmg banner

* rm width

* trial: rm lines

* trial: add line above demo

* trial: add thin line above demo

* trial: add thin line above demo

* trial: add thin line below demo

* trial: rm lines

* trial: add br

* trial: replace images with badges

* trial: replace h1 with h3

* trial: increase pmg height

* revert back to h1

* trial: change theme for demo

* trial: use lighter bg for demo

* trial: use lighter bg for demo

* trial: use lighter bg for demo & rm extra div

* revert demo back to original

* add private package limitation in non-proxy mode

* update demos
2026-01-27 19:39:36 +05:30
aa5c528a9d docs: Update README (#133)
* docs: Update README

* docs: Update README

* docs: Update README

* docs: Update README

* docs: Update README

* Apply suggestion from @Sahilb315

Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
2026-01-21 20:29:15 +05:30
edfdd543e0 chore: README update demo and Error Fix (#126)
* docs: Update README with demo gif

* fix: Proxy remove dependency on interaction

* fix: Update demo gif width

* Update docs/demo/pmg-intro.tape

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

* fix: PMG demo

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-18 16:00:37 +05:30
Abhisek DattaandGitHub 80a1747e3e feat: Add support for Linux Sandbox using Bubblewrap (#120)
* feat: Add support for bubblewrap sandbox

* fix: Glob pattern expansion limit for linux

* fix: Bug in glob pattern expansion for bwrap

* fix: README on trust

* fix: Multiple bubblewrap translator fix

* test: Add E2E for linux sandbox

* fix: Refactor bwrap sandbox to use common dangerous files

* fix: Path test case

* fix: Non-existent path handling bug

* refactor: Misc cleanup

* fix: Avoid bind mount for non-existentent deny protection

* fix: Off by one bug in path depth handling

* ci: Disable AppArmor on GHA runner

* fix: Disable apparmor userns restrictions
2026-01-15 20:12:12 +05:30
b97a4c2ee5 docs: Add trust doc (#118)
* docs: Add trust doc

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@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: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 15:02:08 +05:30
9693428171 feat: Experimental Sandbox Support (#101)
* feat: Sandbox implementation with seatbelt

* refactor: Remove concept of PM_CACHE

* fix: Misc fixes

* refactor: Sandbox for separation of boundaries

* fix: Apply API

* fix: Add support for sandbox cleanup

* test: Add variable interpolation test

* fix: Misc cleanup fixes

* chore: Cleanup sandbox registry

* chore: Cleanup sandbox policy

* chore: Cleanup sandbox

* fix: Misc cleanup fixes

* fix: Remove violation mode

* fix: Update config template

* chore: Go mod cleanup

* fix: Handle the case when package manager policy is explicitly disabled

* fix: Sandbox executor

* Apply suggestions from code review

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>

* test: Remove unused var

* test: Add test for seatbelt sandbox driver

* fix: Sandbox profile loader from file should use path for caching

* test: Add policy test

* feat: Add support for config templates

* fix: Seatbelt translator handle glob

* fix: Merge conflicts

* fix: Fix sandbox policy generator for MacOS min permissions

* fix: Sandbox path handling bugs

* fix: Deny read to dangerous directories

* fix: Deny read to dangerous directories

* add sandbox e2e (#112)

* fix: Sandbox E2E test

* fix: Code review fixes

* fix: Code review fixes

* doc: Add sandbox debugging guide

* doc: Update sandbox doc

* docs: Add sandbox usage doc

* fix: Use better error for sandbox without policy

* fix: Add sandbox for npx

* fix: Enable PTY for npm

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
2026-01-13 14:52:02 +05:30
Sahil BansalandGitHub 11481c3f4c remove windows proxy limitation (#107)
* remove windows proxy limitation

* move setup cmd details to a single place
2026-01-11 10:05:19 +05:30
31f23fd065 Add support for package executors and support for PTY handling (#100)
* 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>
2026-01-09 22:03:42 +05:30
Abhisek DattaandGitHub a373b5b243 docs: Add doc for trusted packages and proxy mode (#102) 2026-01-09 13:56:48 +00:00
Abhisek DattaandGitHub 0603df8c25 docs: Update README (#97)
* docs: Update README

* docs: Update README
2026-01-07 18:54:18 +00:00
779deeb23d feat: Add Support for Proxy Based Npm Interceptor (#87)
* 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>
2026-01-07 13:22:08 +05:30
Shrvan SudhakaraandGitHub 03bd697ae0 Add support for yarn package manager (#72)
* 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>
2025-11-05 13:49:19 +05:30
Sahil BansalandGitHub 12aaba8a05 add poetry command (#67)
* add poetry command

* add poetry.lock extractor & define cmd parser for poetry

* feat: support Poetry caret/tilde version syntax

* add wildcard constraint support & test cases

* readme update

* chore: small fixes
2025-08-29 00:21:09 +05:30
Sahil BansalandGitHub 099dc45958 update docs (#71) 2025-08-28 20:53:24 +05:30
Sahil BansalandGitHub fd7d83704f feat/#28 uv support (#62)
* 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
2025-08-06 21:10:51 +05:30
Sahil BansalandGitHub 2cbb24b3b1 docs/improve readme and alias text (#60)
* fix readme TOC links

* add note for removing aliases

* give a clear msg for removing aliases
2025-07-30 16:42:02 +05:30
Sahil BansalandGitHub c486834c2e feat/#55 bun support (#56)
* add support for bun package manager

* update readme
2025-07-28 17:23:32 +05:30
Sahil BansalandGitHub ca752edf79 feat: add suppport for bypassing the blocking behavior of malicious packages (#53)
* feat: add suppport for bypassing the blocking behavior of malicious packages

* feat: add InsecureInstallation config to bypass malware scanning with tests

* ui: introduce ShowWarning interaction method

* guard test fix
2025-07-02 19:09:27 +05:30
0e17378d3e feat: add posthog analytics support (#52)
* feat: add posthog analytics events

* Update internal/analytics/analytics.go

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-06-30 09:47:14 +05:30
Sahil BansalandGitHub 0a62473e9a Docs/add instructions for setup cmds (#45)
* docs: add instructions for installing & removing aliases

* refactor: fix cmd name

* add diff sections for usage

* add section in index
2025-06-24 18:17:06 +05:30