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

Copy link
Copy Markdown
Contributor

Phase 3, lane 3 of the install-gate restart — the org guarantee

Top of the stack, on #114 (Phase 3 lane 2). Base: install-gate-phase-3-json. This is the lane that makes the gate an enforcement guarantee rather than a best-effort warning: with a token, nothing unverifiable gets through.

Scope (per the PRD)

  • Authenticated fail-closed 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 now shared with utils/api.rs) and fails closed: unverifiable verdicts and resolution errors block instead of warning.
  • 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 enforcement. (A user-configured host must never silently receive a Corgea credential.)
  • 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 names what login adds.
  • Yanked-release handling shipped with the registry resolver back in Phase 1 (non-exact resolution skips yanked releases; exact pins still match, like pip).

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:

  • tokenless → warns and proceeds (exit 0, fail-open);
  • with token + opt-in → refuses (exit 1, fail-closed).

Also verified via OSV cross-check: event-stream@3.3.6 (the unpublished 2018 malware version) resolves to a registry error → passes in public mode (npm itself can't install it either), blocks in authenticated mode. ./harness check green.

Closes the series

With this lane merged, all four PRD phases are complete. Remaining PRD open questions (recency default validation, telemetry, production-worker handoff, org policy config) are explicitly future work.

🤖 Generated with Claude Code

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
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