feat(npm): slug/repository resolver (S11 Step 6, 2/4)

What

Part 2 of 4 splitting !425 (closed) (S11 Step 6). The slug/repository resolver.

  • Resolver walks {slug}namespace_id{repo}repository_id, composed from two small finder interfaces (NamespaceFinder, RepositoryFinder) injected at the wire boundary in Step 8.
  • Mirrors OCI's internal/namespace resolver: two-sentinel pattern (ErrNamespaceNotFound / ErrRepositoryNotFound), nil-finder panic-at-construction, %w wrapping, short-circuit on a namespace miss.
  • Resolution.Slug carries the resolved row's canonical namespaces.slug, not the raw {slug} request segment, so the downstream tarball / dist.tarball URL construction never embeds caller-supplied path bytes (per the AppSec review note below).

The npm repository row is resolved by (namespace_id, {repo}, format=npm, kind=local), excluding soft-deleted rows. The private-repo collapse to namespace_not_found for anonymous reads (AC 33) is deferred by design to the S08/S09 auth layer.

Stack

Targets dm/npm-step6-transport (part 1). Merge order: transport → resolver → middleware → integration.

Tests

resolver_test.go (unit): resolver happy / namespace-miss / repo-miss / underlying-error-at-each-tier, nil-dependency panics, canonical-slug sourcing. Integration coverage lands in part 4.

Spec / plan

Edited by Dzmitry (Dima) Meshcharakou

Merge request reports

Loading
Loading