Install gate, Phase 2: gate the full would-install set (tree pass)#112
Open
juangaitanv wants to merge 3 commits into
Open
Install gate, Phase 2: gate the full would-install set (tree pass)#112juangaitanv wants to merge 3 commits into
juangaitanv wants to merge 3 commits into
Conversation
68dbba9 to
5a99db0
Compare
juangaitanv
added a commit
that referenced
this pull request
Jun 12, 2026
…hrinkwrap, lockfile v1, workspace stanzas Addresses Cursor review on #112. - SECURITY: the pip resolver's `--only-binary :all:` guard is now appended AFTER the user's args. pip format-control is last-wins, so a user `--no-binary :all:` could previously re-enable sdist builds and execute package code during the report step. e2e test pins the arg order. - a bare `npm install --prefix <other>` (and `npm ci --prefix/-C`) now fails closed unless --force: it installs a redirected project's tree the gate can't resolve from the CWD, so it would otherwise install wholly unchecked. (Named installs still verify their targets + degrade the tree pass to the named-only warning.) - npm lockfile reads now prefer npm-shrinkwrap.json (npm's precedence) over package-lock.json, in both the tree resolver and `npm ci`. - parse_npm_lockfile supports lockfileVersion 1 (`dependencies` tree, recursing nested deps) so a v1 project's `npm ci` isn't forced to bypass the gate with --force. - parse_npm_lockfile restricts the verdict set to `node_modules/` entries, excluding workspace SOURCE stanzas (`packages/foo`) — local packages with no registry identity that would otherwise be sent to the public vuln-api and could falsely block a monorepo install.
936d69a to
dd4b575
Compare
5a99db0 to
ddd215b
Compare
juangaitanv
added a commit
that referenced
this pull request
Jun 12, 2026
…hrinkwrap, lockfile v1, workspace stanzas Addresses Cursor review on #112. - SECURITY: the pip resolver's `--only-binary :all:` guard is now appended AFTER the user's args. pip format-control is last-wins, so a user `--no-binary :all:` could previously re-enable sdist builds and execute package code during the report step. e2e test pins the arg order. - a bare `npm install --prefix <other>` (and `npm ci --prefix/-C`) now fails closed unless --force: it installs a redirected project's tree the gate can't resolve from the CWD, so it would otherwise install wholly unchecked. (Named installs still verify their targets + degrade the tree pass to the named-only warning.) - npm lockfile reads now prefer npm-shrinkwrap.json (npm's precedence) over package-lock.json, in both the tree resolver and `npm ci`. - parse_npm_lockfile supports lockfileVersion 1 (`dependencies` tree, recursing nested deps) so a v1 project's `npm ci` isn't forced to bypass the gate with --force. - parse_npm_lockfile restricts the verdict set to `node_modules/` entries, excluding workspace SOURCE stanzas (`packages/foo`) — local packages with no registry identity that would otherwise be sent to the public vuln-api and could falsely block a monorepo install.
dd4b575 to
c86aa2d
Compare
Harvested from the install-vuln-gate spike (dfac68e), trimmed to pip/npm (no uv, no --json, public mode only). - pip tree via `pip install --dry-run --report -` (--only-binary :all: so resolution never builds sdists); npm tree via an isolated `npm install --package-lock-only --ignore-scripts` in a throwaway dir that never touches the project lockfile - bare `npm install` gated from the nearest-ancestor package.json (like npm finds it); `npm ci` and aliases gated from the lockfile directly, with an unparsable-lockfile refusal (--force escape) - transitive findings labeled by provenance: (transitive), (from requirements), (already in package.json) — with a "fix with: corgea npm install <pkg>@<fix>" hint — and (locked) - honest named-only fallback: a failed dry-run or an npm root-redirect flag (--prefix, -g) degrades loudly, and pip -r requirements.txt entries are still parsed and verified in the fallback - bare installs that block blame the existing tree explicitly when no finding was added by the command - bounded verdict pool (fixed at 8) with a progress line above 8 jobs; repeated outage errors collapse into one line above 3 findings Also de-flakes the config test: vuln_api_url resolution is tested as a pure function instead of mutating process env, which raced concurrent getenv calls under the parallel test harness.
…hrinkwrap, lockfile v1, workspace stanzas Addresses Cursor review on #112. - SECURITY: the pip resolver's `--only-binary :all:` guard is now appended AFTER the user's args. pip format-control is last-wins, so a user `--no-binary :all:` could previously re-enable sdist builds and execute package code during the report step. e2e test pins the arg order. - a bare `npm install --prefix <other>` (and `npm ci --prefix/-C`) now fails closed unless --force: it installs a redirected project's tree the gate can't resolve from the CWD, so it would otherwise install wholly unchecked. (Named installs still verify their targets + degrade the tree pass to the named-only warning.) - npm lockfile reads now prefer npm-shrinkwrap.json (npm's precedence) over package-lock.json, in both the tree resolver and `npm ci`. - parse_npm_lockfile supports lockfileVersion 1 (`dependencies` tree, recursing nested deps) so a v1 project's `npm ci` isn't forced to bypass the gate with --force. - parse_npm_lockfile restricts the verdict set to `node_modules/` entries, excluding workspace SOURCE stanzas (`packages/foo`) — local packages with no registry identity that would otherwise be sent to the public vuln-api and could falsely block a monorepo install.
… .npmrc rationale - SECURITY: pip applies format-control directives found INSIDE a -r file AFTER command-line parsing, so a '--no-binary :all:' line in a requirements file overrode the tree pass's trailing '--only-binary :all:' guard and built sdists — executing package code — during the dry-run. The tree pass now pre-scans -r files (transitively, following nested includes) and refuses to dry-run any file carrying a format-control directive, degrading to the named-only fallback whose parser skips option lines. The scan is best-effort on unreadable files (same uid — pip can't read them either and fails loudly itself). Unit + e2e tests prove the dry-run never executes against such a file while the file's entries still verdict. - collect_v1_dependencies carries an explicit depth cap (serde_json's recursion limit fires first today; the cap is the backstop), with a depth-bomb test. - Documented why the .npmrc copy is safe (CLI flags win; package-lock=false degrades to named-only by design). - Adapted the phase-1 alternate-spelling test to the tree-aware fake pip.
ddd215b to
5fb3e5d
Compare
c86aa2d to
33da96b
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 2 of the install-gate restart — SHIP
Stacked on #111 (Phase 1). Base:
install-gate-phase-1— retargets up the stack automatically as parents merge.Extends the gate from named targets to the full would-install set.
Scope (per the PRD)
pip install --dry-run --report -(--only-binary :all:so resolution never builds sdists / runs package code).npm install --package-lock-only --ignore-scriptsin a throwaway temp dir — never touches the project lockfile.npm installgated from the nearest-ancestorpackage.json(found the way npm finds it, incl. from a subdirectory).npm ci(and aliases) gated from the lockfile directly, with an unparsable-lockfile refusal (--forceescape).(transitive),(from requirements),(already in package.json)— with afix with: corgea npm install <pkg>@<fix>hint — and(locked).--prefix,-g) degrades loudly; pip-r requirements.txtentries are still parsed and verified in that fallback.--concurrencyflag — a deliberate dead end from the spike), progress line above 8 jobs, repeated-outage error collapsing above 3.Out of scope (later phases): uv/yarn/pnpm,
--json, auth.Exit criteria — met
All three covered by hermetic e2e tests (
tests/cli_tree.rs,cli_bare_install.rs,cli_npm_ci.rs,cli_provenance.rs) and confirmed against real npm/pip resolution on thetest-clifixtures (monorepo ancestor-walk,-r requirements.txttrees)../harness checkgreen.Also de-flakes the config test:
vuln_api_urlresolution is now tested as a pure function instead of mutating process env (which raced concurrentgetenvunder the parallel harness).🤖 Generated with Claude Code