Skip to content

Install gate, Phase 1: core gate — corgea pip|npm install <named targets>#111

Open
juangaitanv wants to merge 3 commits into
install-gate-phase-0from
install-gate-phase-1
Open

Install gate, Phase 1: core gate — corgea pip|npm install <named targets>#111
juangaitanv wants to merge 3 commits into
install-gate-phase-0from
install-gate-phase-1

Conversation

@juangaitanv

Copy link
Copy Markdown
Contributor

Phase 1 of the install-gate restart — SHIP

Stacked on #110 (Phase 0). Base: install-gate-phase-0 — retargets to main automatically when Phase 0 merges. Review this PR's diff in isolation; it contains only the Phase 1 commit.

This is the first user-facing slice: corgea npm|pip install <named targets>.

Scope (per the PRD)

  • Install-verb detection behind global flags (npm --loglevel silent install x is still gated; the verb is found, not the flag value).
  • Named-spec parsing — exact pins and ranges, per ecosystem (npm semver/dist-tags, PEP 440 specifiers/wildcards/post-releases).
  • Registry resolution (PyPI, npm) → the concrete version that would install, plus its publish time. Yanked releases resolve only via an exact pin, matching pip.
  • Two independent blocks: recency (-t, default 2d) and the vuln-api verdict.
  • Refusal output built for agent self-correction: per-advisory fixed in <version> lines and a → safe version: <name>@<version> steer (the highest fix covering every advisory).
  • --force (override everything), --no-fail (demote recency only).
  • Git/URL/path specs (incl. pip install ., PEP 508 name @ url, npm user/repo shorthand) pass through with a note, never blocked. Non-install subcommands pass straight through.
  • Public mode only: no token; lookup outages warn and continue (fail-open).
  • skills/corgea/SKILL.md install-wrapper section, including the limitations doc (wrapper, not an enforcement boundary).

Out of scope (later phases): transitive/tree resolution, bare installs, npm ci, -r parsing, --json, token auth / fail-closed, yarn/pnpm/uv, retries.

Exit criteria — met

All deterministic staging targets block with exit 1; a real agent session self-corrects to the safe version.

Verified end-to-end against the live staging worker (registry + vuln-api via loopback proxy, real npm/pip resolution):

Target Result
axios@0.21.0 blocked, exit 1, → axios@0.21.2
minimist@0.0.8 blocked, exit 1, → minimist@1.2.2
node-fetch@2.6.0 blocked, exit 1, → node-fetch@2.6.7
mezzanine==6.0.0 blocked, exit 1, no fixed version known

Installing the steered axios@0.21.2 passes the gate — the self-correction loop closes. ./harness check green.

🤖 Generated with Claude Code

Comment thread src/config.rs
Comment thread src/main.rs
Comment thread src/precheck/parse.rs
Comment thread src/verify_deps/registry.rs Outdated
juangaitanv added a commit that referenced this pull request Jun 12, 2026
…gistry

Addresses Cursor review on #111.

- npm `--tag <value>` now resolves the named dist-tag for a bare spec
  (`npm install --tag beta pkg` gates the beta release, not latest), so a
  fresh/vulnerable beta/canary no longer bypasses both blocks. Explicit
  pins/tags still win.
- pip `--pre` makes prereleases eligible: PypiVersion now parses PEP 440
  prereleases (dev<a<b<rc, all below the plain release) and the resolver
  includes them only when `--pre` is set, so the gate verdicts the
  prerelease pip would install instead of the latest stable.
- a custom registry/index flag (`--registry`, `-i`, `--index-url`,
  `--extra-index-url`) now prints a loud warning that the gate resolves
  against the default registry and can't vouch the mirrored artifact —
  full mirror resolution / allow-listing stays out of scope (documented
  limitation, separate PRD).
@juangaitanv juangaitanv force-pushed the install-gate-phase-1 branch from 68dbba9 to 5a99db0 Compare June 12, 2026 14:51
juangaitanv added a commit that referenced this pull request Jun 12, 2026
…gistry

Addresses Cursor review on #111.

- npm `--tag <value>` now resolves the named dist-tag for a bare spec
  (`npm install --tag beta pkg` gates the beta release, not latest), so a
  fresh/vulnerable beta/canary no longer bypasses both blocks. Explicit
  pins/tags still win.
- pip `--pre` makes prereleases eligible: PypiVersion now parses PEP 440
  prereleases (dev<a<b<rc, all below the plain release) and the resolver
  includes them only when `--pre` is set, so the gate verdicts the
  prerelease pip would install instead of the latest stable.
- a custom registry/index flag (`--registry`, `-i`, `--index-url`,
  `--extra-index-url`) now prints a loud warning that the gate resolves
  against the default registry and can't vouch the mirrored artifact —
  full mirror resolution / allow-listing stays out of scope (documented
  limitation, separate PRD).
@juangaitanv juangaitanv force-pushed the install-gate-phase-1 branch from 5a99db0 to ddd215b Compare June 12, 2026 16:42
Harvested from the install-vuln-gate spike (dfac68e), trimmed to
named-target paths: no tree resolution, no uv/yarn/pnpm, no --json, no
token auth — public fail-open mode only.

- corgea npm|pip wrap their package manager: install verbs (found
  behind global flags) gate named targets; everything else passes
  through with the manager's own exit code
- two independent blocks: publish recency (-t, default 2d) and the
  vuln-api verdict on each resolved version
- refusal output built for agent self-correction: per-advisory
  "fixed in <version>" lines and a "→ safe version:" steer naming the
  highest fix covering every advisory
- --force overrides everything; --no-fail demotes recency only
- git/URL/path/editable specs are noted, never blocked; -r files and
  bare installs noted, not gated
- public mode fails open: vuln-api outages warn and continue
- pip→pip3 binary fallback; pip3/pip-add "did you mean" guidance
- SKILL.md: install-wrapper section with limitations + staging targets

Verified end-to-end: all four deterministic staging targets
(axios@0.21.0, minimist@0.0.8, node-fetch@2.6.0, mezzanine==6.0.0)
block with exit 1 and steer to the fixed version; installing the
steered version passes.
…gistry

Addresses Cursor review on #111.

- npm `--tag <value>` now resolves the named dist-tag for a bare spec
  (`npm install --tag beta pkg` gates the beta release, not latest), so a
  fresh/vulnerable beta/canary no longer bypasses both blocks. Explicit
  pins/tags still win.
- pip `--pre` makes prereleases eligible: PypiVersion now parses PEP 440
  prereleases (dev<a<b<rc, all below the plain release) and the resolver
  includes them only when `--pre` is set, so the gate verdicts the
  prerelease pip would install instead of the latest stable.
- a custom registry/index flag (`--registry`, `-i`, `--index-url`,
  `--extra-index-url`) now prints a loud warning that the gate resolves
  against the default registry and can't vouch the mirrored artifact —
  full mirror resolution / allow-listing stays out of scope (documented
  limitation, separate PRD).
…tag, no resolution guessing

- pypi resolution adopts the registry's canonical spelling (info.name,
  guarded to PEP 503-equivalent values so a hostile mirror can't redirect
  the verdict to another package's identity). The vuln-api keys advisories
  by lowercase(canonical), so checking a user-typed variant (Flask_Cors)
  would miss the flask-cors row and fail open.
- npm --tag is last-wins like npm's own config parser; gating the first
  of two --tag flags verdicts the wrong dist-tag.
- pick_latest_stable no longer guesses by upload time when nothing parses
  as PEP 440 (could pick a prerelease without --pre); a visible
  resolution error replaces the silent wrong pick.
- Resolution-error output now states the target is ungated.
@juangaitanv juangaitanv force-pushed the install-gate-phase-1 branch from ddd215b to 5fb3e5d Compare June 12, 2026 18:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant