Skip to main content

Module config

Module config 

Source
Expand description

NuGet.Config <packageSources>/<packageSourceMapping> discovery and resolution — private/custom feed support (issue #523).

§Security model (read before touching this module)

A repository’s NuGet.Config is attacker-controlled the moment a hostile repository is cloned and opened — this LSP parses on file open, before any build ever runs.

  • No credential is ever parsed. <packageSourceCredentials> is walked for child element names only (each names a source key) into a set — no Username/ ClearTextPassword/Password value is ever deserialized into a field, so no code path in this module can hold a credential (NFR-001 is then structurally provable). A source named there becomes NuGetFeedUrlError::HasCredentials and is dropped, fail-closed.
  • <clear/> is merged root→leaf, not “nearest file wins”. A root NuGet.Config <clear/> that removes the implicit nuget.org hop must stay removed for every descendant project, even one whose own NuGet.Config adds a feed without repeating the <clear/> — otherwise a leaf file would silently resurrect the public hop the root explicitly cleared (the #248 bug class). See resolve_with_context’s accumulation loop.
  • <packageSourceMapping> is merged across every level too, not “nearest file wins”: a root mapping {CorpFeed: ["MyCompany.*"], nuget.org: ["*"]} combined with a leaf mapping {nuget.org: ["*"]} must still route MyCompany.Internal to CorpFeed — taking only the leaf’s * entire would leak the private package name to nuget.org, exactly the dependency-confusion attack this feature exists to close. See PackageSourceMapping::resolve_keys_for.
  • A packageSourceMapping key resolving to more than one distinct declared source is treated as unresolvable, not fanned out to every match. Source-key matching is deliberately case/XML-name-insensitive (union of the raw and decoded forms — FR-009), and growing an exclusion set (disabled/credentialed) that way is fail-closed, but growing an inclusion set (which feed a mapped package routes to) the same way is fail-open — see resolve_mapping_source_key.
  • The public nuget.org source is identified by normalized URL, never by a source’s configured key. A hostile config can name a private feed "nuget.org"; only an exact match against crate::registry::NUGET_ORG_INDEX_URL restores the OSV/deps.dev/hover trust signal a genuine public-registry dependency gets — see crate::registry::is_public_registry_url.
  • A config chain that clears every source down to zero, with nothing re-added, is an explicit fail-closed state, never a silent fallback to nuget.org — see NO_SOURCES_CONFIGURED_SENTINEL.

See specs/035-nuget-private-feed-support/spec.md for the full requirements.

Structs§

InvalidEntry
A present-but-unusable <add> entry — an invalid URL, a policy-blocked host, a disabled/credentialed source, or an unsupported protocol/local-feed value.
NuGetAuth
A pre-formatted Basic base64(username:password) Authorization header value (issue #561).
NuGetConfig
Resolved NuGet.Config view for one manifest’s directory — the merged result of every in-repo ancestor NuGet.Config (root-to-leaf accumulation, see this module’s doc).
NuGetConfigCache
NuGetFeedUrl
A validated, normalized, https-only NuGet V3 service index URL with no embedded userinfo.
NuGetParseContext
Owned by NuGetEcosystem, shared across every document it parses.
NuGetSourceChain
One fully-resolved routing chain, produced by NuGetConfig::resolved_chains, consumed by NuGetRegistry::register_chain. Mirrors deps_pypi::config::ResolvedChain exactly.
PackageSourceEntry
One resolved <packageSources> entry, keyed by its declared key (case preserved, but every comparison against it goes through key_candidates).
ResolvedHop
One resolved hop in a NuGetSourceChain (issue #561, FR-016).

Enums§

ConfigTier
Which tier a parsed NuGet.Config file came from (issue #561, FR-001).
NuGetFeedUrlError
Why a candidate <add value="..."> failed validation, or why it was dropped as disabled/credentialed/unsupported.

Functions§

resolve_with_context
Resolves manifest_dir’s in-repo NuGet.Config ancestor chain, plus the user-profile tier (issue #561), into a merged NuGetConfig (FR-001/FR-002, C1’s root-to-leaf accumulation).