Add a VCS dependency

nab resolves dependencies pulled from git URLs through [tool.nab.vcs] and [[tool.nab.vcs-sources]]. Only git is supported; hg, svn, and bzr are not. The default posture is fully restrictive: nothing VCS-shaped resolves without an explicit policy.

Default posture

[tool.nab.vcs]
policy = "block"
allowed-schemes = []
allowed-repos = []
require-pin = true

policy = "block" means every VCS URL is rejected. Switching to "allow" is necessary but not sufficient: you also have to declare allowlists.

Layered allowlist

[tool.nab.vcs]
policy = "allow"
allowed-schemes = ["git+https"]
allowed-repos = ["https://github.com/myorg/"]
require-pin = true

Three layers, each AND-checked:

  1. allowed-schemes: pip-style scheme prefixes. The supported set is git+https, git+ssh, git+http, git+file, git+git. Empty means “no scheme is allowed”. git+http and git+git are unauthenticated; prefer git+https or git+ssh.

  2. allowed-repos: prefix match against the URL after the git+ prefix is stripped, so the value includes the inner scheme. https://github.com/myorg/ matches every HTTPS repo under that org. Empty means “no repo is allowed”.

  3. require-pin: when true, the URL must include a 40-char hex commit SHA after @. Branch and tag references are rejected because they are mutable.

Everything after the final @ is the ref, so the URL has to name a repository ahead of it: git+https://github.com and git+https://github.com@<sha> are both refused; git+https://github.com/myorg/pkg@<sha> is not.

Pinned VCS sources

The supported entry point is [[tool.nab.vcs-sources]]:

[tool.nab.vcs]
policy = "allow"
allowed-schemes = ["git+https"]
allowed-repos = ["https://github.com/myorg/"]
require-pin = true

[[tool.nab.vcs-sources]]
name = "my-fork"
url  = "git+https://github.com/myorg/my-fork.git@<sha>"

The named package becomes a single-version source pinned to the commit you specified. nab clones the repo, reads the static metadata (Layer 2: clone + static metadata), and treats the result as a normal dependency for the rest of the resolve. The URL in each [[tool.nab.vcs-sources]] table is run through the same admission as project-root requirements, so it must pass allowed-schemes, allowed-repos, and require-pin.

Reading static dependencies from the cloned tree works at any build-policy level. Dynamic dependencies on a VCS clone require build-policy = "build-remote" (a clone is considered “remote” for build purposes because the source bytes are network-fetched, even though they end up on disk before the backend runs). See the build policy page.

pkg @ git+... at the project root

PEP 508 lets you write a direct-URL requirement under [project].dependencies:

[project]
dependencies = ["my-fork @ git+https://github.com/myorg/my-fork.git@<sha>"]

The admission check (allowed schemes, allowed repos, required pin) fires on this form too, but the resolver path is not implemented for the project-root case: nab raises NotImplementedError. Use a [[tool.nab.vcs-sources]] entry instead.

Lockfile shape

VCS pins land in the lockfile as VcsPin records carrying the repo URL, the resolved 40-char commit SHA, and an optional subdirectory. Annotated tags are dereferenced to their underlying commit so the lock never records a tag-object SHA. VcsPins do not carry a sha256 (pip does not hash-check VCS forms), so nab download skips them.