Reference for every ecosystem pkgprobe scans: what config files exist at
each precedence level, what syntax declares a registry URL or credentials,
and what pkgprobe currently parses.
This document is the spec for implementing new languages/<lang>/registry.rs
modules and for verifying completeness of the existing ones.
Every ecosystem follows roughly the same four-level hierarchy, highest
precedence first:
| Level | Description | Typical location |
|---|
| Environment | Env vars and CLI flags at runtime | $PIP_INDEX_URL, $CARGO_REGISTRIES_X_TOKEN |
| Project | Config file adjacent to the manifest/lockfile | .npmrc, auth.json, .cargo/config.toml |
| User | Per-user config in the home directory | ~/.npmrc, ~/.m2/settings.xml, ~/.pypirc |
| Machine | System-wide config (rare) | /etc/pip/pip.conf, /etc/NuGet/NuGet.Config |
pkgprobe reads project and user levels for all implemented ecosystems.
Environment-level detection is implemented for Node, Python, and Rust.
Implementation: app/core/src/languages/node/registry.rs — Complete
| File | Fields |
|---|
.npmrc | registry=<url>, @scope:registry=<url>, _authToken, _password, _auth |
.yarnrc.yml | npmRegistryServer, npmAuthToken, npmScopes.<scope>.npmRegistryServer |
| File | Fields |
|---|
~/.npmrc | Same as project .npmrc |
~/.yarnrc.yml | Same as project .yarnrc.yml |
~/.config/pnpm/rc | Same as .npmrc |
| Variable | pkgprobe |
|---|
NPM_TOKEN | Detected: token hashed, auth_status set |
Implementation: app/core/src/languages/php/registry.rs — Complete
| File | Fields |
|---|
composer.json | repositories[].type, repositories[].url |
auth.json | http-basic, bearer, github-oauth, gitlab-token |
| File | Fields |
|---|
~/.composer/auth.json | Same as project auth.json |
Implementation: app/core/src/languages/dotnet/registry.rs — Complete
| File | Fields |
|---|
NuGet.Config (walks up directory tree) | <packageSources>, <packageSourceCredentials> |
| File | Fields |
|---|
~/.nuget/NuGet/NuGet.Config | Same |
| File | Fields |
|---|
/etc/NuGet/NuGet.Config (macOS/Linux) | Same |
Implementation: app/core/src/languages/python/registry.rs — Complete
| Level | File | Fields |
|---|
| Project | pyproject.toml | [tool.pip] index-url, extra-index-url |
| User | ~/.pip/pip.conf | [global] index-url, extra-index-url |
| User | ~/.pypirc | [distutils] index-servers, [<server>] repository, username, password |
| Env | $PIP_INDEX_URL, $PIP_EXTRA_INDEX_URL | Override index URLs |
| Level | File | Fields |
|---|
| Project | pyproject.toml | [[tool.poetry.source]] name, url |
| User | ~/Library/Caches/pypoetry/auth.toml | http-basic, http-bearer |
| Level | File | Fields |
|---|
| Project | pyproject.toml | [[tool.uv.index]] name, url |
| User | ~/.config/uv/uv.toml | Same |
| Env | $UV_INDEX_URL, $UV_EXTRA_INDEX_URL | Override |
Implementation: app/core/src/languages/rust_lang/registry.rs — Complete
| Level | File | Fields |
|---|
| Project | .cargo/config.toml | [registries.<name>] index, token |
| User | ~/.cargo/config.toml | Same |
| User | ~/.cargo/credentials.toml | [registries.<name>] token |
| Env | $CARGO_REGISTRIES_<NAME>_TOKEN | Per-registry token |
Implementation: app/core/src/languages/go/registry.rs — Complete
| Level | File | Fields |
|---|
| Project/User | ~/.netrc | machine <host> login <user> password <token> |
| Env | $GOPROXY | Module proxy list |
| Env | $GOPRIVATE | Module prefixes that bypass proxy |
Implementation: app/core/src/languages/ruby/registry.rs — Complete
| Level | File | Fields |
|---|
| Project | Gemfile | source "<url>" |
| Project | .bundle/config | BUNDLE_GEMS__<HOST> |
| User | ~/.gemrc | :sources: [...] |
| User | ~/.gem/credentials | <url>: <api-key> |
Implementation: app/core/src/languages/java/registry.rs — Complete
| Level | File | Fields |
|---|
| Project | pom.xml | <repositories>, <pluginRepositories> |
| User | ~/.m2/settings.xml | <servers>, <profiles> |
| Level | File | Fields |
|---|
| Project | gradle.properties | artifactory_user, artifactory_password |
| User | ~/.gradle/gradle.properties | Same |
Implementation: app/core/src/languages/swift/registry.rs — Complete
| Level | File | Fields |
|---|
| Project | Package.swift | .package(url: "https://...", from: "1.0.0") |
| User | ~/.netrc | Credentials matched by host |
Implementation: app/core/src/languages/dart/registry.rs — Complete
| Level | File | Fields |
|---|
| Project | pubspec.yaml | dependencies.<pkg>.hosted.url |
| User | ~/.pub-cache/pub-credentials.json | hosted[].url, hosted[].token |
Implementation: app/core/src/languages/cocoapods/registry.rs — Complete
| Level | File | Fields |
|---|
| Project | Podfile | source 'https://...' |
| User | ~/.cocoapods/repos/*/ | .git/config remote URLs |
| User | ~/.netrc | Credentials by host |
For each ecosystem, the registry parser should:
- Read project-level config adjacent to the manifest/lockfile.
- Read user-level config from the home directory.
- Read machine-level config from the system directory (when it exists).
- Hash all credential values via
utils::hash_secret before storing.
- Emit one
RegistryConfig per registry URL with level, config_file,
username, password_hash, and valid (always true until policy runs).
- Be callable from
attach_ecosystem_registries regardless of PM.
- Short-circuit quickly when the config file is absent.
- Include unit tests using
tempfile fixtures.