Skip to content

Install gate, Phase 3 (lane 3): org guarantee — authenticated fail-closed mode#115

Open
juangaitanv wants to merge 3 commits into
install-gate-phase-3-jsonfrom
install-gate-phase-3-auth
Open

Install gate, Phase 3 (lane 3): org guarantee — authenticated fail-closed mode#115
juangaitanv wants to merge 3 commits into
install-gate-phase-3-jsonfrom
install-gate-phase-3-auth

Conversation

@juangaitanv

@juangaitanv juangaitanv commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Overview

This PR is Phase 3, lane 3 of the install-gate feature for the Corgea CLI.

Lane 3 turns the gate from public best-effort checks into an authenticated org guarantee. With a Corgea token on the default vuln-api, unverifiable packages, resolution failures, vuln-api outages, and degraded tree coverage block the install instead of warning and proceeding.

Tokenless mode remains public and fail-open. A custom vuln-api URL never receives a Corgea token unless explicitly opted in.

Stacked on #114. Base branch: install-gate-phase-3-json. Review this PR's diff in isolation; it contains the Phase 3 lane 3 slice.

What Phase 3 Lane 3 Includes

  • Authenticated fail-closed mode using CORGEA_TOKEN or corgea login on the default vuln-api endpoint.
  • Shared auth-header construction between the vuln-api client and utils/api.rs: JWT tokens use Bearer; opaque tokens use CORGEA-TOKEN.
  • Credential safety for custom URLs: a custom CORGEA_VULN_API_URL stays public even when a token exists. CORGEA_VULN_API_SEND_TOKEN_TO_CUSTOM_URL=1 is required to send the token and enable enforcement there.
  • Fail-closed enforcement for unverifiable vuln-api verdicts, resolution errors, vuln-api outages, and degraded named-only tree coverage for managers that normally have tree resolvers.
  • Expected named-only behavior for yarn and pnpm, which do not have a tree resolver in this series and therefore continue with the named-only warning rather than fail-closing every authenticated install.
  • Transient-failure retries in the vuln-api client: idempotent GETs retry twice with 500ms and 1500ms backoff on send errors; HTTP 429 honors Retry-After, clamped to 1-10s, once.
  • Scripted stub retry/drop modes so retries and dropped connections are tested hermetically.
  • PEP 668 refusal for pip installs into externally managed environments before registry checks run, with a virtualenv hint. --break-system-packages, --target, --prefix, --root, and --force bypass.
  • Public-mode disclosure telling tokenless users that authenticated enforcement is available through login.
  • Mode-aware docs and debug traces for fail-open versus fail-closed decisions.

Deliberately Out Of Scope

Future work after this series includes:

  • recency default validation
  • telemetry
  • production-worker handoff
  • org policy config

Exit Criteria - Met

With a token, an unverifiable package or a vuln-api outage blocks the install.

Demonstrated live with the real binary against the same dead vuln-api endpoint:

Mode Result
tokenless public mode warns and proceeds, exit 0
token + custom-URL opt-in refuses, exit 1

Also verified with event-stream@3.3.6: the unpublished malware version resolves to a registry error, so npm cannot install it; public mode proceeds with disclosure, while authenticated mode blocks. ./harness check passes.

Comment thread src/precheck/verdict.rs Outdated
@juangaitanv juangaitanv force-pushed the install-gate-phase-3-json branch from 0e07df6 to c5715f9 Compare June 12, 2026 14:52
juangaitanv added a commit that referenced this pull request Jun 12, 2026
…ree pass

Addresses Cursor review on #115.

When a manager with a tree resolver (pip/npm/uv) degrades to a NamedOnly
tree — pip --dry-run, npm lockfile resolution, or uv pip compile failed —
the whole transitive set goes unverified. In public mode that warns and
proceeds (fail-open), but in authenticated mode it now BLOCKS unless
--force: the unchecked transitives can hide the vulnerable package the org
guarantee exists to catch.

yarn/pnpm have no resolver, so their NamedOnly is inherent and expected —
the new `has_tree_resolver()` predicate keeps them on the named-only warning
rather than fail-closing every authenticated yarn/pnpm install. e2e tests
pin the pip fail-closed block, the public fail-open, and the yarn proceed;
an existing token-forwarding test now reflects the authenticated block.

(Also fixes the Phase 0 harness_smoke test's check_package_version call for
the token parameter added in this phase.)
@juangaitanv juangaitanv force-pushed the install-gate-phase-3-auth branch from 7bf5651 to 023419f Compare June 12, 2026 14:52
@juangaitanv juangaitanv force-pushed the install-gate-phase-3-json branch from c5715f9 to c79d501 Compare June 12, 2026 16:42
juangaitanv added a commit that referenced this pull request Jun 12, 2026
…ree pass

Addresses Cursor review on #115.

When a manager with a tree resolver (pip/npm/uv) degrades to a NamedOnly
tree — pip --dry-run, npm lockfile resolution, or uv pip compile failed —
the whole transitive set goes unverified. In public mode that warns and
proceeds (fail-open), but in authenticated mode it now BLOCKS unless
--force: the unchecked transitives can hide the vulnerable package the org
guarantee exists to catch.

yarn/pnpm have no resolver, so their NamedOnly is inherent and expected —
the new `has_tree_resolver()` predicate keeps them on the named-only warning
rather than fail-closing every authenticated yarn/pnpm install. e2e tests
pin the pip fail-closed block, the public fail-open, and the yarn proceed;
an existing token-forwarding test now reflects the authenticated block.

(Also fixes the Phase 0 harness_smoke test's check_package_version call for
the token parameter added in this phase.)
@juangaitanv juangaitanv force-pushed the install-gate-phase-3-auth branch from 023419f to fb1fbb3 Compare June 12, 2026 16:42
Harvested from the install-vuln-gate spike (dfac68e). With a token,
nothing unverifiable gets through.

- authenticated mode: a Corgea token (CORGEA_TOKEN or corgea login)
  on the default vuln-api sends the auth header (JWT → Bearer,
  opaque → CORGEA-TOKEN; one definition shared with utils/api.rs) and
  fails closed — unverifiable verdicts and resolution errors block
- custom-URL token opt-in: a custom CORGEA_VULN_API_URL stays public
  even with a token; CORGEA_VULN_API_SEND_TOKEN_TO_CUSTOM_URL=1 sends
  the token there and enables fail-closed enforcement
- transient-failure retries in the vuln-api client: idempotent GETs
  retry twice (500ms/1500ms backoff) on send errors; HTTP 429 honors
  Retry-After (clamped 1-10s) once; stub gains scripted retry/drop
  modes to exercise both paths hermetically
- PEP 668 refusal: pip installs into an externally managed environment
  are refused before any registry check, with a virtualenv hint;
  --break-system-packages/--target/--prefix/--root and --force bypass
- tokenless public mode now discloses itself and what login adds
- yanked-release handling shipped with the registry resolver in
  Phase 1 (non-exact resolution skips yanked releases; exact pins
  still match, like pip)
…ree pass

Addresses Cursor review on #115.

When a manager with a tree resolver (pip/npm/uv) degrades to a NamedOnly
tree — pip --dry-run, npm lockfile resolution, or uv pip compile failed —
the whole transitive set goes unverified. In public mode that warns and
proceeds (fail-open), but in authenticated mode it now BLOCKS unless
--force: the unchecked transitives can hide the vulnerable package the org
guarantee exists to catch.

yarn/pnpm have no resolver, so their NamedOnly is inherent and expected —
the new `has_tree_resolver()` predicate keeps them on the named-only warning
rather than fail-closing every authenticated yarn/pnpm install. e2e tests
pin the pip fail-closed block, the public fail-open, and the yarn proceed;
an existing token-forwarding test now reflects the authenticated block.

(Also fixes the Phase 0 harness_smoke test's check_package_version call for
the token parameter added in this phase.)
…aware docs, PEP 668 traces

- run_locked_install now prints the same public-login hint as
  run_parsed_install: a tokenless 'npm ci'/'uv sync' runs public checks
  and should disclose that authenticated enforcement exists.
- Module header and run_verdict_pass docs no longer describe only the
  public fail-open behavior — both modes and their decision point
  (verdict::block_reason) are named.
- PEP 668 detection error arms are debug-traced (the deliberate
  fail-open stays; a silent miss is now diagnosable).
@juangaitanv juangaitanv force-pushed the install-gate-phase-3-json branch from c79d501 to 07bb21d Compare June 12, 2026 18:28
@juangaitanv juangaitanv force-pushed the install-gate-phase-3-auth branch from fb1fbb3 to 5d1d30a Compare June 12, 2026 18:28
@leenk7991

Copy link
Copy Markdown

is this the last phase? should we update PRD.md? or just remove it entirely?

Comment thread skills/corgea/SKILL.md
custom URL and make lookup failures fail closed. Overrides for testing:
`CORGEA_PYPI_REGISTRY`, `CORGEA_NPM_REGISTRY`, `CORGEA_VULN_API_URL`.

#### Limitations

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add a line in limitations to mention something like: "git/URL/path specs are skipped (noted unverifiable), the skip never blocks, even in authenticated mode."

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.

2 participants