关于 jfrog-package-safety-and-download
指导使用 JFrog Platform 检查并下载软件包的安全与下载流程,适合管理包依赖的开发者和运维人员。流程先查公共目录与存储包,再检查平台存储及适用的策展策略。
主要功能
- 01搜索公共目录与存储包
- 02确定软件包最新版本
- 03检查平台中是否已有版本
- 04按仓库类型下载制品
- 05检查策展许可与策略
适用场景
- 01下载前检查软件包是否已存储
- 02依据策展策略判断是否允许下载
- 03从 JFrog 远程仓库获取制品
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jfrog/ jfrog-skills --skill jfrog-package-safety-and-download安装后在 Claude Code 中输入/jfrog-package-safety-and-download确认已加载。
详细介绍
JFrog 软件包安全性与下载
前提条件
- 阅读
../jfrog/SKILL.md了解 JFrog Platform 概念、领域模型、CLI 设置和 API 模式。 - OneModel 的结构会随服务器版本而变化。 在自行构造 GraphQL 字段或
where过滤器之前,请阅读../jfrog/references/onemodel-graphql.md(schema 获取工作流)和../jfrog/references/onemodel-query-examples.md(公共软件包、已存储软件包)。当示例无法通过验证时,请根据GET "$JFROG_URL/onemodel/api/v1/supergraph/schema"重新生成或验证查询。
工作流概览
flowchart TD
A[User requests package check / download] --> B{Package in Public Catalog?}
B -->|Yes| C[Get latest version from Catalog]
B -->|No| D{Package in JFrog Platform Stored Packages?}
D -->|Yes| E[Get latest version from Stored Packages]
D -->|No| F[Package not found — stop]
C --> G{Latest version in JFrog Platform?}
E --> G
G -->|Yes| H[Safe — download from JFrog Platform]
G -->|No| I{Curation entitled?}
I -->|Yes| J[Check curation policy via API]
I -->|No| K[Download via remote repo]
J -->|200 Allowed| K
J -->|403 Blocked| M[Report curation blocked — stop]
并行化机会
此工作流中的若干步骤相互独立,可以并行运行以减少总延迟:
- 步骤 1 + 步骤 1 回退:当软件包类型已知时,并行查询公共目录(
getPackage)和已存储软件包(getPackage)。使用返回数据的那个;如果公共目录返回命中结果,则优先将其latestVersion用于步骤 2。 - 步骤 3 + 步骤 5:确定版本后,并行查询已存储软件包版本(JFrog Platform 检查)和 curation 授权(
/api/system/version)。两者都是独立的读取操作 —— 如果 JFrog Platform 检查返回为空,则立即需要 curation 结果。
在发出并行 Shell 调用时,每个 jf api 调用都会针对当前活动的 jf config 服务器独立进行身份验证;调用之间无需传递任何 shell 状态。
步骤 1:查找软件包
首先通过 OneModel GraphQL 搜索公共目录,如果未找到,则回退到已存储软件包。
按照 ../jfrog/references/onemodel-graphql.md 中的说明通过 jf api 执行查询;具体查询形态请参考 ../jfrog/references/onemodel-query-examples.md。
当软件包类型已知时(例如 npm、maven、pypi),使用 publicPackages.getPackage(type:, name:)(参见 获取公共软件包)。包含 latestVersion { version } 选择集 —— latestVersion 是一个对象,不是标量。
当类型未知时,使用带 nameContains 的 publicPackages.searchPackages(参见 搜索公共软件包)。当用户缩小生态系统范围时,添加 type:。
- 找到 → 记下
type和latestVersion.version。继续步骤 2。 - 未找到 → 该软件包可能属于第一方/第二方。使用
storedPackages.searchPackages或storedPackages.getPackage搜索已存储软件包(参见onemodel-query-examples.md中的 已存储软件包领域)。已知时优先按type过滤;否则仅使用nameContains。- 找到 → 记下
type和latestVersionName(或从versionsConnection推导出版本)。继续步骤 2。 - 两者均未找到 → 报告“未找到软件包”并停止。
- 找到 → 记下
如果出现多个具有不同 type 值的结果,请询问用户指的是哪种软件包类型。
步骤 2:确定最新版本
| 来源 | 版本字段 |
|---|---|
| 公共目录 | latestVersion.version(需要对象选择集) |
| JFrog Platform 已存储软件包 | StoredPackage 上的 latestVersionName,或来自 versionsConnection 的最高条目 |
步骤 3:检查软件包 + 最新版本是否存在于 JFrog Platform 中
使用带 hasPackageWith 过滤器的 storedPackages.searchPackageVersions 查询已存储软件包版本(参见 ../jfrog/references/onemodel-query-examples.md → 搜索已存储软件包版本)。为步骤 2 中的特定版本添加 version 过滤器,并请求 locationsConnection 以获取仓库详情(repositoryKey、repositoryType、leadArtifactPath)。
通过 jf api 执行查询(调用模式参见 ../jfrog/references/onemodel-graphql.md)。
- 找到且带有位置信息 → 软件包位于 JFrog Platform 中。报告为可安全下载。继续步骤 4。
- 未找到 → 继续步骤 5。
步骤 4:从 JFrog Platform 下载
使用步骤 3 中的位置信息。二进制构件下载通过
jf rt dl 进行——而不是 jf api。jf api 是
JFrog REST API(元数据、管理、策展等)的统一入口,并不提供
通过重定向链流式传输二进制内容所需的
-L / -o 标志。
<target> 必须是完整的文件路径(例如
./downloads/lodash-4.18.1.tgz),而不是单纯的目录。jf rt dl --flat
会将目标视为文件名;传入目录会导致具有误导性的
"open path: is a directory" 错误。
repositoryType | 策略 |
|---|---|
local 或 federated | jf rt dl "<repositoryKey>/<leadArtifactPath>" <target-file> --flat |
remote | 针对基础远程仓库(去掉末尾的 -cache)执行 jf rt dl —— 当构件尚未缓存时,它会透明地触发远程拉取 |
local / federated / remote 下载:
jf rt dl "<baseRepoKey>/<leadArtifactPath>" <target-file> --flat
解析远程仓库键: OneModel 为远程位置返回的 repositoryKey
通常已经以 -cache 结尾(例如
devNPM-remote-cache)。jf rt dl 需要的是基础远程仓库名称
(不带 -cache)。存在 -cache 后缀时将其去掉(例如
devNPM-remote-cache → devNPM-remote)。如果该键不以
-cache 结尾,则按原样使用。
仓库内特定包类型的路径格式请参见下方的 Protocol endpoints 表。
步骤 5:检查策展授权
jf api /artifactory/api/system/version \
| jq '.addons | index("curation") != null'
true→ 已获得策展授权。继续执行步骤 6a。false→ 策展不可用。继续执行步骤 6b。
步骤 6a:检查策展策略并下载
当已获得策展授权时,在下载前使用 Xray 策展 API 检查该 包版本是否在所有仓库中均被允许。
RESPONSE_FILE="/tmp/curation-status-$$.json"
PAYLOAD_FILE="/tmp/curation-payload-$$.json"
STDERR_FILE="/tmp/curation-err-$$.log"
jq -n \
--arg type "<TYPE>" \
--arg name "<NAME>" \
--arg version "<VERSION>" \
'{packageType:$type, packageName:$name, packageVersion:$version}' \
> "$PAYLOAD_FILE"
set +e
jf api /xray/api/v1/curation/package_status/all_repos \
-X POST -H "Content-Type: application/json" \
--input "$PAYLOAD_FILE" \
> "$RESPONSE_FILE" 2> "$STDERR_FILE"
RC=$?
set -e
echo "RC=$RC"; echo "$RESPONSE_FILE"
支持的 packageType 值:npm、pypi、maven、go、nuget、
docker、gradle。
使用 jf api 解读结果:与普通的 curl 不同,jf api
通过其退出码以及 stderr 上的一行
"<hh:mm:ss> [Warn] ... returned 4xx/5xx" 来呈现 HTTP 结果(而不是
stdout 中的 %{http_code} 后缀)。响应体始终写入
stdout。需同时解析两者:
if [ "$RC" -eq 0 ]; then
echo "Package is allowed by curation."
elif grep -q 'returned 403' "$STDERR_FILE"; then
echo "Blocked by curation policy:"
cat "$RESPONSE_FILE"
else
echo "Curation check failed (rc=$RC):"
cat "$STDERR_FILE"
fi
评估结果:
- 退出码 0 → 该包被策展策略允许。继续通过远程仓库 下载(与步骤 6b 相同)。
- stderr 上出现
returned 403→ 该包被策展 策略阻止。响应体说明了是哪条策略规则阻止了它。向用户报告 阻止原因并停止——不要尝试下载。 - 任何其他非零退出码 → 视为操作性失败(认证、DNS、 端点已禁用)并报告。
步骤 6b:在没有策展的情况下下载
当未获得策展授权且该包不在 JFrog Platform 中时, 直接通过远程仓库下载。
-
查找正确包类型的远程仓库:
jf api \ "/artifactory/api/repositories?type=remote&packageType=<TYPE>" \ | jq '.[].key' -
下载——针对基础远程仓库(不带
-cache)使用jf rt dl;它会同时处理已缓存和未缓存的构件:jf rt dl "<repo>/<artifact-path>" <target-file> --flat
按包类型划分的构件路径
当 leadArtifactPath 无法从
OneModel 获取时,使用这些路径模式。开头的 <repo>/ 是你传给 jf rt dl 的基础仓库键。
| Type | jf rt dl 目标模式 |
|---|---|
npm | <repo>/<pkg>/-/<pkg>-<version>.tgz |
pypi | <repo>/<pkg>/<version>/<pkg>-<version>.tar.gz |
maven | <repo>/<group-path>/<artifact>/<version>/<artifact>-<version>.jar |
go | <repo>/<module>/@v/<version>.zip |
注意事项
- 二进制下载与
jf api的区别:jf api用于 REST API,而不是二进制内容。它不会透明地跟随重定向获取二进制载荷,也不支持-L/-o。请始终使用jf rt dl(针对基础远程仓库,而非-cache仓库)来实际下载制品。 jf rt dl与未缓存的远程仓库:jf rt dl "<remote>/<path>"—— 针对基础远程仓库而不是<remote>-cache/<path>—— 会透明地触发远程拉取并缓存制品。不要尝试通过jf api预先查询代理。jf rt dl --flat的目标必须是文件路径:下载单个制品时,请传入完整的输出文件路径(例如./downloads/lodash-4.18.1.tgz),而不是目录。CLI 会将目标路径作为文件打开;传入目录会导致晦涩的 "open path: is a directory" 错误,并在失败前重试四次。请从leadArtifactPath推导文件名(取最后一个/之后的部分)。- 包类型检测:如果用户未指定包类型,仅按名称进行 Public Catalog 搜索可能会返回多种类型。请让用户先澄清后再继续。
- 策展端点位于 Xray 下:使用
/xray/api/v1/curation/package_status/all_repos(通过jf api)。不要为其添加/artifactory前缀。 - 使用
jf api判别策展结果:200/403 信号来自jf api的退出码以及 stderr 上的returned NNN行,而不是追加到 stdout 的%{http_code}。请将 stderr 捕获到文件(2> "$STDERR_FILE"),并根据RC+grep 'returned 403'进行分支判断,如步骤 6a 所示。 - 策展 API 的包类型取值:必须为小写,且匹配
npm、pypi、maven、go、nuget、docker、gradle之一。其他值将返回错误。