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 — noUsername/ClearTextPassword/Passwordvalue 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 becomesNuGetFeedUrlError::HasCredentialsand is dropped, fail-closed. <clear/>is merged root→leaf, not “nearest file wins”. A rootNuGet.Config<clear/>that removes the implicitnuget.orghop must stay removed for every descendant project, even one whose ownNuGet.Configadds a feed without repeating the<clear/>— otherwise a leaf file would silently resurrect the public hop the root explicitly cleared (the #248 bug class). Seeresolve_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 routeMyCompany.InternaltoCorpFeed— taking only the leaf’s*entire would leak the private package name tonuget.org, exactly the dependency-confusion attack this feature exists to close. SeePackageSourceMapping::resolve_keys_for.- A
packageSourceMappingkey 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 — seeresolve_mapping_source_key. - The public
nuget.orgsource is identified by normalized URL, never by a source’s configuredkey. A hostile config can name a private feed"nuget.org"; only an exact match againstcrate::registry::NUGET_ORG_INDEX_URLrestores the OSV/deps.dev/hover trust signal a genuine public-registry dependency gets — seecrate::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— seeNO_SOURCES_CONFIGURED_SENTINEL.
See specs/035-nuget-private-feed-support/spec.md for the full requirements.
Structs§
- Invalid
Entry - A present-but-unusable
<add>entry — an invalid URL, a policy-blocked host, a disabled/credentialed source, or an unsupported protocol/local-feed value. - NuGet
Auth - A pre-formatted
Basic base64(username:password)Authorizationheader value (issue #561). - NuGet
Config - Resolved
NuGet.Configview for one manifest’s directory — the merged result of every in-repo ancestorNuGet.Config(root-to-leaf accumulation, see this module’s doc). - NuGet
Config Cache - NuGet
Feed Url - A validated, normalized, https-only NuGet V3 service index URL with no embedded userinfo.
- NuGet
Parse Context - Owned by
NuGetEcosystem, shared across every document it parses. - NuGet
Source Chain - One fully-resolved routing chain, produced by
NuGetConfig::resolved_chains, consumed byNuGetRegistry::register_chain. Mirrorsdeps_pypi::config::ResolvedChainexactly. - Package
Source Entry - One resolved
<packageSources>entry, keyed by its declaredkey(case preserved, but every comparison against it goes throughkey_candidates). - Resolved
Hop - One resolved hop in a
NuGetSourceChain(issue #561, FR-016).
Enums§
- Config
Tier - Which tier a parsed
NuGet.Configfile came from (issue #561, FR-001). - NuGet
Feed UrlError - 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-repoNuGet.Configancestor chain, plus the user-profile tier (issue #561), into a mergedNuGetConfig(FR-001/FR-002, C1’s root-to-leaf accumulation).