首页
/ uv 对接 Azure Artifacts:从索引配置、PAT/keyring 认证到 uv publish 发布的完整实践

uv 对接 Azure Artifacts:从索引配置、PAT/keyring 认证到 uv publish 发布的完整实践

2026-09-04 19:46:45作者:房伟宁

uv 不仅可以从公共 PyPI 安装依赖,也支持将 Azure Artifacts 这类企业私有制品库作为包索引源,并可直接向其中发布包。本文基于 uv 官方集成文档 Azure Artifacts 指南,完整讲解:如何在 pyproject.toml 中注册 Azure Artifacts 索引、如何用 Personal Access Token(PAT)或 keyring + artifacts-keyring 插件完成认证、如何通过 uv publish 把自有包发布回 Artifacts,并深入 uv-auth 凭据服务 的源码,说明子进程 keyring 与发布凭据收集的真实实现路径。

读完本文,你可以在 Azure DevOps 流水线或本地开发环境中,让 uv 安全地读取私有制品库,并完成“配置索引 → 选择认证方式 → 发布包”的全流程。

在 pyproject.toml 中注册 Azure Artifacts 索引

使用 Azure Artifacts 的第一步,是在项目配置中声明索引。索引通过 [[tool.uv.index]] 数组定义,每个索引需要一个唯一的 name(供环境变量与 --index 参数引用)和 Artifacts 的 PEP 503 格式 url

[[tool.uv.index]]
name = "private-registry"
url = "https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/simple/"

其中 <ORGANIZATION><PROJECT><FEED> 分别替换为你的 Azure DevOps 组织、项目与制品库(Feed)名称。索引 name 是后文所有认证配置的关键:uv 用 UV_INDEX_<NAME>_USERNAME / UV_INDEX_<NAME>_PASSWORD 这类环境变量按索引名定位凭据,因此 name 必须与环境变量中的 PRIVATE_REGISTRY(即名称的大写形式)一致,凭据才能被正确匹配。

认证方式一:Personal Access Token(PAT)

当环境中已有 PAT 时(例如 Azure 流水线中可直接使用系统变量 $(System.AccessToken)),可以通过 HTTP "Basic" 认证方案提供凭据:把 PAT 填入 URL 凭据的密码字段。用户名是必填项,但可以是任意字符串(Azure Artifacts 侧并不校验其具体内容,常用 dummy 占位)。

以 token 存放在 $AZURE_ARTIFACTS_TOKEN 环境变量为例:

export UV_INDEX_PRIVATE_REGISTRY_USERNAME=dummy
export UV_INDEX_PRIVATE_REGISTRY_PASSWORD="$AZURE_ARTIFACTS_TOKEN"

注意两点:

  1. PRIVATE_REGISTRY 必须与 pyproject.toml[[tool.uv.index]]name 字段对应(名称会做规范化大写处理);
  2. 凭据只通过环境变量注入,不写入 pyproject.tomluv.lock —— uv 在 uv add 等操作中同样不会把索引凭据持久化进这些会进入版本控制的文件,这是 uv 的通用安全行为,见 HTTP 凭据概念文档 中“Persistence of credentials”一节。

从 uv 的凭据优先级看,HTTP 认证来源依次为:URL 内嵌的 user:password.netrc 文件、uv 凭据存储、keyring provider(默认关闭)。环境变量注入的索引凭据在命令执行期间按索引 URL / 网络位置(scheme、host、port)缓存复用,但不跨命令持久化(来源见 docs/concepts/authentication/http.md)。

认证方式二:keyring 与 artifacts-keyring 插件

另一种无需管理 token 字符串的方式,是使用 Python 的 keyring 包配合 Microsoft 的 artifacts-keyring 插件。artifacts-keyring 插件封装了 Azure Artifacts Credential Provider 工具,支持交互式登录等多种认证模式(具体配置参见该工具自身文档)。

有两个前置约束值得注意:

  • 这两个包必须从 Artifacts 之外的来源(如公共 PyPI)预安装,因为它们本身就是认证 Artifacts 的依赖,若从 Artifacts 拉取会形成先有鸡还是先有蛋的循环;
  • uv 目前仅支持 keyring 的 subprocess(子进程)模式keyring 可执行文件必须在 PATH 中(全局安装或处于激活环境内),并且 keyring CLI 要求 URL 中提供用户名,该用户名必须为 VssSessionToken

完整操作流程如下:

# 从公共 PyPI 预装 keyring 与 Artifacts 插件
uv tool install keyring --with artifacts-keyring

# 启用 keyring 子进程认证
export UV_KEYRING_PROVIDER=subprocess

# 为该索引设置用户名(必须为 VssSessionToken)
export UV_INDEX_PRIVATE_REGISTRY_USERNAME=VssSessionToken

同样的配置也可以通过项目文件固化:在 uv.tomlpyproject.toml 中设置 tool.uv.keyring-provider = "subprocess"(见 keyring providers 说明),并把 VssSessionToken 用户名直接写进索引 URL,避免每个环境重复导出环境变量。

源码视角:uv 如何调用 keyring 子进程

crates/uv-auth/src/keyring.rs 中,KeyringProvider 定义了 Native(系统原生密钥环)与 Subprocess(外部 keyring 命令)两种后端,KeyringProviderBackend::Subprocess 对应本文使用的模式。其 fetch_subprocess 方法(约 L266–L355)展示了实际行为:

// fetch_subprocess:拼出 keyring get <service> [<username>] 命令
let mut command = Command::new("keyring");
command.arg("get").arg(service_name);

if let Some(username) = username {
    command.arg(username);
} else {
    command.arg("--mode").arg("creds");
}

即 uv 会先以完整 URL 作为 service_name 查询一次 keyring,未命中再回退到 host(含端口)级别查询,非 HTTPS 场景还会尝试 scheme://host:port 形式的服务名,以避免跨协议泄露凭据。若 keyring 版本过低不支持 --mode creds,uv 会给出明确的升级提示(要求 keyring>=v25.2.1 或提供用户名)。这也解释了前文“必须提供 VssSessionToken 用户名”的原因:带用户名时 uv 只向 keyring 索要密码,行为更简单可靠。

发布包到 Azure Artifacts

如果还要把自己的包发布到 Artifacts,使用 uv 的 uv publish 命令(通用流程见 构建与发布指南)。

第一步,给目标索引增加 publish-url,指向 Artifacts 的 upload 端点:

[[tool.uv.index]]
name = "private-registry"
url = "https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/simple/"
publish-url = "https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/upload/"

第二步,若未走 keyring 方案,配置发布凭据(PAT 场景与安装时相同,用户名任意):

$ export UV_PUBLISH_USERNAME=dummy
$ export UV_PUBLISH_PASSWORD="$AZURE_ARTIFACTS_TOKEN"

第三步,用 --index 指定要发布的索引名:

$ uv publish --index private-registry

也可以在项目配置中不写 publish-url,改用 UV_PUBLISH_URL 环境变量临时指定上传地址:

$ export UV_PUBLISH_URL=https://pkgs.dev.azure.com/<ORGANIZATION>/<PROJECT>/_packaging/<FEED>/pypi/upload/
$ uv publish

官方文档特别提醒:这种方式不推荐。原因在 crates/uv/src/commands/publish.rs 的源码中可以印证——发布时 uv 会根据索引配置解析出 (publish_url, check_url) 二元组:

let (publish_url, check_url) = if let Some(index_name) = index {
    // 按索引名查找,publish_url 来自索引的 publish-url
    // check_url 用于上传前检查包是否已发布
}

只有当能从项目索引配置中解析出该索引时,check_url 才有值,uv 才会在上传前“Checking N files against ...”检查包是否已发布,避免重复发布冲突。直接给 UV_PUBLISH_URL 时没有关联的 simple 索引 URL,uv 无法执行这项预检,只能直接“Publishing N files to ...”。因此,只要发布目标是固定的 Azure Artifacts 仓库,把 publish-url 写进 pyproject.toml 是更稳妥的做法。

发布时的凭据收集逻辑(gather_credentials,约 L349 起)同样遵循通用优先级:先读取 UV_PUBLISH_USERNAME / UV_PUBLISH_PASSWORD 环境变量,再看 URL 内嵌用户名/密码,最后才会查询 keyring(keyring.rs 中的 fetch),并在使用 keyring 且无密码时报出 “Keyring has no password for URL ...” 的明确错误,便于排查认证配置。

小结与适用前提

把本文要点归纳为一张对照表:

场景 关键配置 / 命令 备注
声明索引 [[tool.uv.index]] + url.../pypi/simple/ name 须与 UV_INDEX_<NAME>_* 环境变量匹配
PAT 认证 UV_INDEX_<NAME>_USERNAME / UV_INDEX_<NAME>_PASSWORD 用户名任意字符串即可
keyring 认证 uv tool install keyring --with artifacts-keyring + UV_KEYRING_PROVIDER=subprocess 用户名必须为 VssSessionToken;keyring 需在 PATH 中
发布包 索引增加 publish-url + UV_PUBLISH_USERNAME/PASSWORD + uv publish --index <name> 建议写 publish-url 以启用已发布检查
临时发布地址 UV_PUBLISH_URL 无法执行“是否已发布”预检,非首选

适用前提与限制:

  • 本文配置基于当前仓库中 docs/guides/integration/azure.md 描述的 uv 行为;tool.uv.keyring-provider 仅支持 subprocess 一种值,原生系统密钥环存储(Keychain / Credential Manager / Secret Service)目前处于 preview 阶段,需通过 UV_PREVIEW_FEATURES=native-auth 开启,且只能读取 uv 自己写入的条目,与 artifacts-keyring 插件写入的条目不互通;
  • 环境变量按索引名匹配,多索引项目请为每个索引使用不同的 name,避免凭据串号;
  • 凭据不会被写入 pyproject.tomluv.lock 等可能入库的文件,流水线中建议用受保护变量或 $(System.AccessToken) 注入。

如需进一步了解认证机制的完整优先级、.netrc 支持与凭据持久化规则,可继续阅读 HTTP 凭据索引认证 相关文档;索引与索引 URL 的概念见 索引文档

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
903
1.82 K
docsdocs
暂无描述
Markdown
888
5.78 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.51 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.17 K
341