Skip to content

vlt lock inventory and hosted restore resolve a node's registry differently #562

Description

[agent] Filed by the scheduled architecture audit routine (ecosystems and formats). Register: #560 (comment).

Kind: bug. Source: review §1 #7; Part 4.4; register E03. It also absorbs the duplicate-helper half of E02.

Problem

Two private registry_base functions turn a vlt-lock.json DepID registry segment plus the lock's options into a registry URL. Their precedence and their fallback differ:

vendor/lock_inventory/vlt.rs#L100-L122 (inventory: vendored fetch, VEX) patch/redirect/upstream/vlt.rs#L52-L72 (hosted rollback/remove restore)
default alias options.registry → registries.npm → npmjs registries.<alias> → options.registry → npmjs
unmapped alias None (no location) options.registry, else npmjs
URL test starts_with("https://"|"http://") Url::parse + scheme

Reproduced on d63ae5f (the same inputs fed to both functions in unit tests, run twice):

seg=""     opts={"registry":"https://a.example/","registries":{"npm":"https://b.example/"}}
  inventory -> Some("https://a.example/")   restore -> "https://b.example/"
seg="npm"  same opts
  inventory -> Some("https://a.example/")   restore -> "https://b.example/"
seg="corp" opts={"registry":"https://a.example/"}
  inventory -> None                         restore -> "https://a.example/"
seg="corp" opts={}
  inventory -> None                         restore -> "https://registry.npmjs.org/"

As a result, one lock resolves to one registry when vex and vendoring inventory it, and to a different registry when rollback and remove rebuild slot [3] (upstream/vlt.rs#L280-L286) and evaluate `under_configured_registry` ([`#L109-L119`](https://github.com/SocketDev/socket-patch/blob/d63ae5f2804595ab20c4ab33f31af70b51ec950f/crates/socket-patch-core/src/patch/redirect/upstream/vlt.rs#L109-L119)).`` For an alias the lock doesn't map, restore writes a URL on a registry the alias never named, instead of refusing.

The conventional tarball path is also spelled three times:

  • lock_inventory/vlt.rs#L141 uses an inline format!("{base}{name}/-/{bare}-{version}.tgz");
  • upstream/vlt.rs#L75 goes through registry_fetch::npm_tarball_url;
  • vendor/bun_lockb.rs#L233-L235 uses an inline format!.

Separately, upstream/vlt.rs#L33 defines its own NPM_REGISTRY beside registry_fetch::DEFAULT_NPM_REGISTRY (registry_fetch.rs#L18), and only the latter honors SOCKET_NPM_REGISTRY.

Symptoms

Related: #521 (vlt rollback synthesizes slot [3] instead of using dist.tarball). That is the same restore code, but a different defect. Fixing #521 removes one of the three tarball spellings, not the registry_base drift.

Impact: a vlt project with both registry and registries.npm set, or with a custom alias that isn't in registries, gets inconsistent answers across modes. Restore can write a lock pointing at the wrong registry, and VEX/vendoring can locate a different artifact than hosted restore. Size: small.

Proposed change

  • Add one pub(crate) fn registry_base(segment, options) -> Option<String> beside is_default_registry in vendor/vlt_lock_text.rs (it moves to formats/ with E20). Its precedence must be checked against vlt's own config resolution, and the PR must state which spelling vlt uses and cite the source.
  • On None, restore refuses that node (fail closed) instead of falling back to npmjs.
  • Delete both private registry_base functions, with_slash if it is unused, the inline tarball format! in lock_inventory/vlt.rs, and upstream/vlt.rs's NPM_REGISTRY. Use registry_fetch::npm_tarball_url and DEFAULT_NPM_REGISTRY.
  • Out of scope: the bun.lockb format-1 synthesized URL (bun_lockb.rs#L235) describes what Bun resolves, not what socket-patch fetches. Leave it to the E18/E20 helper moves. Also out of scope: vlt hosted rollback and remove rewrite slot [3] to a synthesized /<name>/-/<leaf>-<ver>.tgz URL instead of the registry's dist.tarball, so the next cold vlt ci 404s #521's dist.tarball change.

Size and scope

vendor/vlt_lock_text.rs, vendor/lock_inventory/vlt.rs and patch/redirect/upstream/vlt.rs. About −50 / +30 production lines.

Acceptance criteria

  • One registry_base; neither private copy remains.
  • A table test covers default alias, explicit npm, a custom mapped alias, a custom unmapped alias, a URL segment, and registry with and without registries.npm. The inventory and restore call sites both assert against it.
  • Restore of a node on an unmapped alias refuses with a code. Document the code in CLI_CONTRACT.md if it is new.
  • The existing vlt tests stay green: upstream/vlt.rs tests, lock_inventory vlt tests, and vex/discover/vlt.rs.

Dependencies

Blocked by nothing. Coordinate with #521, since both touch upstream/vlt.rs#L280.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent:claimedagent:triagedarch-auditFiled by a scheduled architecture audit routine (see the architecture review discussion)bugSomething isn't workingpm:vltvltpriority:p1

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions