Commit Graph
48 Commits
Author SHA1 Message Date
e6b5157a2a ci: add macOS test job (#366)
* ci: add macOS test job

Darwin-tagged tests (Seatbelt translator, diagnostics, upcoming network
lockdown tests) never ran in CI: the test matrix covered ubuntu and
windows only. The M0 sandbox lockdown milestone is macOS-first, so macOS
coverage must exist before enforcement work lands.

Also establishes the convention that darwin integration tests requiring
sandbox-exec must fail (not skip) when running in CI, so missing tooling
cannot silently hide security tests.

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

* test(sandbox): make Seatbelt render golden test machine-independent

The golden file baked the authoring machine's HOME, CWD and TMPDIR parent
into the expected profile, so TestRenderSeatbelt_Golden could only pass on
that machine. It never ran in CI before the macOS job exposed it.

Normalize CWD, home and TMPDIR parents (raw and query-escaped forms) to
stable placeholders before comparison, longest path first so prefix
overlaps survive, and rewrite the golden accordingly.

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

* ci: make setup-go cache explicit in macOS job

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

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-07-10 19:07:15 +05:30
Abhisek DattaandGitHub c601e17cdc fix: Sandbox profile for Go ecosystem (#361)
* fix: Sandbox profile for Go ecosystem

* fix: Sandbox violations for network bind
2026-07-06 23:38:38 +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
Sahil BansalandGitHub 2a7ecdb556 ci: add E2E for pmg action server-mode (#354)
* ci: add E2E for pmg action server-mode

Exercises the safedep/pmg action with server-mode enabled: the action
starts the proxy daemon and injects HTTP_PROXY + CA env vars, then bare
npm/pip installs are intercepted. Asserts benign installs pass, malicious
npm/pip installs are blocked, and 'pmg proxy stop --fail-on-violation'
fails the job on the blocks.

Scoped via paths to action.yml and the proxy server sources so it only
runs when relevant. Complements persistent-proxy-e2e.yml, which covers
the branch's proxy internals via raw pmg proxy commands.

* ci: extract shared proxy E2E assertions into composite action

Both the action server-mode E2E and the persistent-proxy E2E run the same
benign/malicious install assertions. Factor them into a local composite
action (.github/actions/proxy-e2e-assertions) so the assertions live in one
place and both workflows exercise the composite itself.

Proxy teardown (pmg proxy stop --fail-on-violation) stays inline in each
workflow since the setup/teardown differs per binary-under-test (released
binary via the action vs. branch build via make).
2026-06-26 16:33:37 +05:30
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 26d5c0ad71 test(e2e): verify proxy-mode NO_PROXY does not crash Python httpx (#341) 2026-06-15 15:40:02 +05:30
Abhisek DattaandGitHub c7244f921a feat: Add support for environment protection (scrubbing) (#327)
* feat: Add support for environment variable protection for sandbox

* chore: Update dangerous env var list

* fix: Split profiles for improved environment protection

* fix: pipx sandbox profile separation

* chore: Show sandbox scrub info on error exit

* fix: Code review fixes

* test: Add e2e for sandbox environment scrubbing
2026-06-11 11:40:33 +05:30
Abhisek DattaandGitHub f3e00a7f6e fix: yarn proxy mode proxy environment injection (#320) 2026-06-05 18:39:37 +05:30
Arunanshu BiswasandGitHub 1c25395d74 feat: migrate pmg to nx based release automation (#293)
* feat: Migrate release system to Nx with platform-specific npm packages

* add go.work.sum

* fix: CI deprecations, stale action pins, and signal propagation

* fix: update e2e workflows to pnpm 11 and latest action SHAs

* fix: update pmg-e2e.yml to Node 24 with Go and pnpm caching

* fix: resolve E2E failures, remove goreleaser-test, update action SHAs

* fix: restore goreleaser-test (required check)

* fix: escape pnpm workspace detection for yarn/pnpx tests, update action versions
2026-05-28 17:22:11 +05:30
DivyanshuandGitHub 88d8a566bc ci: pin codeql-action to commit SHA for Node 24 support (#289) 2026-05-25 07:39:19 +05:30
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
Diego Ramil ÁlvarezandGitHub 6249d0781d feat(install): add support for clean installation (#259)
Signed-off-by: DiegoRamil <nxquumodding@gmail.com>
2026-05-13 20:52:41 +05:30
6546116e28 feat: migrate PMG to use PATH shims for package manager wrapper (#246)
* feat: add FilterPMGFromPath utility for PATH shim recursion prevention

* feat: add FilterPMGFromEnv to filter PATH from env slices

* feat: filter ~/.pmg/bin from PATH in proxy subprocess env

* feat: add PathExport method to Shell interface for shim PATH integration

* feat: add ShimManager for PATH shim install/remove lifecycle

* feat: wire ShimManager into setup commands with --use-aliases fallback

* refactor: add DefaultShimConfig helper to reduce setup boilerplate

* fix: resolve real binary path to prevent shim double-invocation

exec.CommandContext resolves the binary using the current process PATH,
which still contains ~/.pmg/bin. This caused pmg to launch the shim
instead of the real package manager, resulting in a second pmg instance
with its own proxy — producing duplicate error messages and wasted work.

ResolveRealBinary searches a filtered PATH (without ~/.pmg/bin) to find
the real package manager binary before execution.

* fix: resolve real binary in runner.Execute and expand path resolution tests

Ensure guard mode and proxy skip paths also resolve through
ResolveRealBinary to prevent infinite shim recursion. Add table-driven
tests covering error cases, multi-binary PATH, and PATH restoration.

* fix: handle error return values from os.Setenv and file Close calls

Address errcheck lint failures: check os.Setenv returns in
ResolveRealBinary, and check f.Close/tempFile.Close in ShimManager.

* feat: auto-migrate shell aliases to PATH shims on setup install

When running `pmg setup install`, detect existing shell aliases and
automatically remove them before installing shims. Existing users
get a seamless migration with no extra flags or commands needed.

* fix: update E2E test to verify shim installation instead of alias RC file

Replace the .pmg.rc file check with assertions that ~/.pmg/bin/ exists
and contains executable shim scripts for npm and pip.

* feat: add FilterPMGFromPath utility for PATH shim recursion prevention

* feat: add FilterPMGFromEnv to filter PATH from env slices

* feat: filter ~/.pmg/bin from PATH in proxy subprocess env

* feat: add PathExport method to Shell interface for shim PATH integration

* feat: add ShimManager for PATH shim install/remove lifecycle

* feat: wire ShimManager into setup commands with --use-aliases fallback

* refactor: add DefaultShimConfig helper to reduce setup boilerplate

* fix: resolve real binary path to prevent shim double-invocation

exec.CommandContext resolves the binary using the current process PATH,
which still contains ~/.pmg/bin. This caused pmg to launch the shim
instead of the real package manager, resulting in a second pmg instance
with its own proxy — producing duplicate error messages and wasted work.

ResolveRealBinary searches a filtered PATH (without ~/.pmg/bin) to find
the real package manager binary before execution.

* fix: resolve real binary in runner.Execute and expand path resolution tests

Ensure guard mode and proxy skip paths also resolve through
ResolveRealBinary to prevent infinite shim recursion. Add table-driven
tests covering error cases, multi-binary PATH, and PATH restoration.

* fix: handle error return values from os.Setenv and file Close calls

Address errcheck lint failures: check os.Setenv returns in
ResolveRealBinary, and check f.Close/tempFile.Close in ShimManager.

* feat: auto-migrate shell aliases to PATH shims on setup install

When running `pmg setup install`, detect existing shell aliases and
automatically remove them before installing shims. Existing users
get a seamless migration with no extra flags or commands needed.

* fix: update E2E test to verify shim installation instead of alias RC file

Replace the .pmg.rc file check with assertions that ~/.pmg/bin/ exists
and contains executable shim scripts for npm and pip.

* feat: install both aliases and shims for full coverage

Aliases win in interactive shells (including venvs), shims catch
non-interactive contexts (IDEs, CI, subprocesses). Remove --use-aliases
flag and migration logic since both are always installed together.
Update E2E to verify all shim scripts and alias RC file.

* feat: address review feedback for shim implementation

- Install both aliases and shims together for full coverage
- Move homeDir resolution into NewDefaultShimManager (internal concern)
- Add mutex to ResolveRealBinary to guard against concurrent PATH mutation
- Use filepath.SplitList for platform-correct PATH splitting
- Add ResolveRealBinary to runner.Execute and proxy flow to prevent
  shim recursion in all execution paths
- Remove print side-effects from ShimManager.Remove
- Update E2E to verify all shim scripts and alias RC file
- Expand ResolveRealBinary tests with table-driven cases

* fix: restore errcheck handling and add concurrency test for ResolveRealBinary

- Restore proper defer with log.Warnf for PATH restoration in ResolveRealBinary
- Restore errcheck handling for f.Close() and tempFile.Close() in ShimManager
- Add explanatory comment for ResolveRealBinary call in proxy_flow
- Add TestResolveRealBinaryConcurrent to verify mutex guards concurrent access

* feat: skip shell integration on Windows with informative warning

On Windows, pmg setup install now writes only the config file and
prints a warning that shell aliases and PATH shims require WSL.

* fix: PMG use pre-resolved binary path (#253)

---------

Co-authored-by: Abhisek Datta <abhisek.datta@gmail.com>
2026-05-12 22:27:05 +05:30
Abhisek DattaandGitHub 4c42ceca0e feat: Add support for Landlock based Sandbox for Linux (#238)
* feat: Initial implementation of landlock based sandbox driver

* fix: Handle seccom probe failure

* fix: Remove unnecessary seccomp probe

* fix: Use file based policy load

* fix: Keep bpf filter in memory

* fix: Use TSYNC for seccom filter

* fix: Use TSYNC for seccom filter

* fix: Update landlock translator

* fix: Landlock sandbox implementation

* fix: Landlock + seccomp based sandboxing on Linux

* fix: Misc fixes

* fix: Cleanup sandbox files

* fix: Handle mandatory deny API change post merge

* fix: Landlock write access translation

* chore: Fix linter issues

* ci: Use /tmp for npm cache for landlock
2026-05-07 12:42:28 +05:30
d6755d3f44 feat/sandbox allow explicit dangerous pattern override (#239)
* feat(sandbox): allow opt-out of mandatory deny via explicit allow rules

Mandatory deny patterns (.env, .aws, .ssh, .gcloud, .kube, .gnupg,
.docker/config.json, .git/config) can now be opted out by listing the
exact literal post-expansion path in policy filesystem.allow_read /
allow_write, OR via --sandbox-allow read=... / write=... at runtime.
Both channels are treated at par.

Suppression is exact-match. Listing the CWD-absolute or HOME-absolute
form of a dangerous file additionally suppresses its **/<file> glob
sibling on the same direction so a single opt-out is sufficient.
Broad globs (${CWD}/**) and relative paths in user allow lists do not
suppress. The unnamed absolute form remains denied. .git/hooks is
unconditional and never suppressible (arbitrary code execution risk).

GetMandatoryDenyPatterns now returns split DenyRead / DenyWrite
slices and reports SuppressedRead / SuppressedWrite for audit. Both
translators emit per-direction deny rules and log.Warnf each
suppression. On Linux/bubblewrap, the tmpfs hide is restricted to the
intersection of DenyRead and DenyWrite; one-sided suppression falls
back to /dev/null (write) or the user's allow_read --ro-bind (read).
bwrap has no primitive that allows writes while denying reads, so
write-only opt-outs warn that the read-side mandatory deny is
unenforceable.

Updates docs/sandbox.md to document the opt-out, exact-match
semantics, and the Linux platform limitation. Updates pmg-e2e.yml to
create ./.env so the sandbox e2e test exercises the BLOCK case.

Closes #232

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: Code review fixes

---------

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-06 12:45:36 +05:30
Sahil BansalandGitHub 296d5e52e1 chore: Update GHA actions to Node.js 24 (#231)
* update gha to use node24

* add environment approval for PMG release
2026-04-30 07:52:44 +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
601ba315c2 ci: Add GHA for issue triage (#171)
* ci: Add GHA for issue triage

* Update .github/workflows/issue-triage.yml

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

* Update .github/workflows/issue-triage.yml

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-20 07:12:39 +00:00
Sahil BansalandGitHub b0305cb54d Add concurrency cancel and ignore docs/markdown changes across CI workflows (#168)
* Add concurrency cancel and ignore docs/markdown changes across CI workflows

* Clarify PR-only concurrency (no push queuing)
2026-02-16 21:33:27 +05:30
Sahil BansalandGitHub b161d34f9e fix proxy stuck on blocking malicious package (#153)
* fix proxy stuck on blocking malicious package

* update pmg e2e
2026-02-06 22:41:56 +05:30
Sahil BansalandGitHub f1891271c1 Add proxy support for pypi package managers (#150)
* initial pypi registry implementation

* support proxy mode for pypi package managers

* support proxy mode for pypi package managers - 2

* rm default mode as proxy for pip3

* update goproxy version & fix pypi proxy failing on 304

* add PIP_RETRIES=0 env

* update pmg e2e & add proxy mode e2e for pypi

* rm safedep-test-pkg for pypi proxy e2e
2026-02-05 13:30:27 +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
4600ab0245 fix: Sandbox policy tuning for tmp write access (#145)
* fix: Sandbox policy tuning for tmp write access

* fix: Remove numbers from test

* Update sandbox/profiles/pnpm-restrictive.yml

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

* fix: Sandbox E2E test to consider Linux bubblewrap tmpfs mount

* Update sandbox/profiles/pnpm-restrictive.yml

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

* fix: Migrate deny rules from pnpm to npm policy

---------

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-02-01 15:20:17 +05:30
Sahil BansalandGitHub 0aa82033a5 fix proxy mode failing for GH private packages (#137)
* 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
2026-01-23 18:38:54 +05:30
Sahil BansalandGitHub 736c63a7b6 Sandbox fails for unsupported cmds (#129)
* introduce enforce_always sandbox config & hooks for flows

* fix sandbox failing for unsupported commands

* add hooks for pypi package managers

* add tests for sandbox hook

* introduce enforce_always flag for ease use & CI

* make comments descriptive

* remove hooks & update config to add API to configure sandbox

* add comments

* rm unused function
2026-01-19 22:24:59 +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
Sahil BansalandGitHub f1b7e3f403 fix download artifact path (#117) 2026-01-14 06:43:08 +00:00
Abhisek DattaandGitHub cf12914ab3 ci: Add support for build provenance (#116)
* ci: Add support for build provenance

* fix: Fix provenance job
2026-01-14 11:45:54 +05:30
2e1f5b1a36 feat: Add support for policy inheritence (#113)
* feat: Add support for policy inheritence

* fix: Linter fixes

* Update docs/sandbox.md

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

* fix: Handle boolean inheritence

* ci: Add linter

* Update sandbox/policy_test.go

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

* fix: Linter fixes

* fix: Linter fixes

* fix: Sandbox rule regex format

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-14 10:50:39 +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
f50d296935 add e2e and alias for npx, pnpx (#105)
* add e2e and alias for npx, pnpx

* Update .github/workflows/pmg-e2e.yml

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-01-10 16:47:43 +05:30
Sahil BansalandGitHub 6e830c4c3d update node to use v24 (#99) 2026-01-08 06:48:57 +05:30
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
20c854e473 feat: Config Persistence & API (#83)
* introduce a persistent config

* add tests and refactor config creation

* update config handling and add support for removing config

* add support to skip suspicious pkgs marked as trusted

* add support for config dir Env & unexport functions

* small fixes

* add assert for dir

* fix tests

* fix shell source line & trusted pkgs parsing

* fix flag inconsistency

* update config to read on each invocation and create if does not exist

* fix flags value being overridden

* remove redundant func call

* modify trusted pkg check to be config bound

* modify RemoveConfig to rm files & not dir. add tests for paths.go

* add versions for package for e2e

* modify tests to reset config

* fix: Simplify config persistence

* fix: Misc comments

* fix: Misc fix

* fix: Do not overwrite config file if exists

* fix: Do not overwrite config file if exists

* fix: Config cobra command should override and not replace

* fix: Create dir before writing config template

* fix: Create dir before writing config template

* fix: Misc refactoring

* test: Add test for is trusted package version

* Update cmd/setup/setup.go

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

* Update config/config.go

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

* Apply suggestion from @Copilot

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

* fix: Remove unused constant in config

* fix: Resolve conflict with event logger

* docs: Add doc for eventlogger.Logger interface

* test: Add E2E for config file creation

* fix: Code review fixes

---------

Signed-off-by: Abhisek Datta <abhisek.datta@gmail.com>
Co-authored-by: Sahilb315 <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2026-01-01 12:33:52 +05:30
Sahil BansalandGitHub 2bc500f817 replace token based auth with OIDC auth (#80) 2025-12-16 12:58:45 +00:00
2be1e5f009 Update go version to 1.25 & Add steps for introducing new package manager (#78)
* upgrade go version to 1.25.1

* introduce doc for steps for creating a new pkg manager

* Update docs/package-manager.md

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

* Update docs/package-manager.md

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

* Update docs/package-manager.md

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-12-08 09:36:32 +05:30
Sahil BansalandGitHub 50d7b55445 Add Pip3 support (#75)
* add pip3 support

* add pip3 e2e

* chore: rename var
2025-12-03 20:28:45 +05:30
Sahil BansalandGitHub c47cb30de0 Add pmg E2E Tests (#73)
* add pmg e2e tests

* pin sha version

* pin python sha version

* add pmg to path

* fix pnpm init

* fix pnpm init

* rm poerty verification

* fix poetry verification

* comment poetry verification

* fix poetry error

* add poetry verification back

* fix poetry error

* add yarn e2e

* fix yarn installation

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
2025-12-01 12:13:24 +05:30
Sahil BansalandGitHub cd306884e3 add trufflehog secret scan CI (#63) 2025-08-13 15:49:12 +05:30
Sahil BansalandGitHub 6d39fc0dde fix publish npm test installations (#59) 2025-07-29 21:54:58 +05:30
Sahil BansalandGitHub 49b2371cc3 fix: invalid cross-device link (#54)
* fix: invalid cross-device link

* version flag fix in workflow

* remove version from package.json
2025-07-04 20:56:31 +05:30
74248cd74a Publish pmg to npm (#50)
* feat: pmg publish to npm

* feat: add github action for publishing to npm

* Update publish/npm/install.js

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

* Update .github/workflows/publish-npm.yml

Co-authored-by: Omkar Phansopkar <omkarphansopkar@gmail.com>
Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* refactor: define constants

* refactor: improve npm package reliability with removing dynamic handlers and better error handling and validation

* fix: publish-npm workflow

* Update publish/npm/test.js

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

* refactor(npm-workflow): use a more portable loop construct

* refactor: remove version field from package.json

* feat: use os.tmpdir() with mkdtempSync for cleaner temp directory handling

* fix: add redirect limit and cleanup to prevent infinite redirects and resource leaks

* remove test.js for npm publisher pack

* chore: test cmd cleanup

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Omkar Phansopkar <omkarphansopkar@gmail.com>
2025-07-04 12:42:37 +05:30
4031219375 fix: Show error messages on fatal failures #32 (#34)
* fix: Show error messages on fatal failures #32

* test: Add E2E test

* test: fix E2E scripts

* test: fix E2E scripts

* fix: Race condition in concurrent analyzer

* fix: update formatting to ensure docs URL is clickable

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>

* fix: E2E test

---------

Signed-off-by: Sahil Bansal <bansalsahil315@gmail.com>
Co-authored-by: Sahil Bansal <bansalsahil315@gmail.com>
2025-05-17 21:54:47 +05:30
Abhisek DattaandGitHub cfde1d7632 ci: Add CodeQL and OpenSSF Scorecard action (#21) 2025-05-15 16:59:13 +05:30
Abhisek DattaandGitHub e86b6ef056 feat: Refactor PMG to Maintain Separation of Concerns and Clean Architecture (#19)
* feat: Add separate package manager and resolver

* fix: Npm dependency resolver

* feat: Add analyzer for malysis query

* feat: Add package manager guard as the orchestrator

* feat: Add PMG to orchestrate installation

* Add concurrent scan execution

* Introduce package manager interaction abstraction

* feat: Add UI port for guard

* Remove refactored source files

* Update README

* fix: CI script for multi-arch build

* ci: goreleaser CI fix

* fix: npm command parser to extract package names

* feat: Introduce global config primitive

* fix: Close results channel for clean goroutine exit

* ci: Add container image releaser

* test: Improve test for npm resolver

* refactor: Analyzer to generalise

* Improve UI with additional info

* fix: Goreleaser config

* fix: npm resolver bug

* fix: Fail when command exec workflow fails

* fix: Bug with transitive dependency resolution

* fix: Synchronize common data update in dependency resolver

* chore: Improve log handling

* docs: Update README

* fix: UI text wrapping

* fix: UI handling bugs

* feat: Use concurrent dependency resolver
2025-05-15 16:50:59 +05:30
Sahil BansalandGitHub 5a6b842360 add goreleaser & goreleaser workflow (#8) 2025-05-02 12:37:27 +05:30
Sahilb315 4f13dfbb40 chore: clean unused deps 2025-04-29 01:52:35 +05:30
Sahilb315 d4a31b14c0 ci: add vet ci 2025-04-29 01:41:50 +05:30