跳转到主要内容

mcli 20260901 发布

升级至 Go 1.27.0 并以自有模块路径导入 SILO 依赖栈,新增只读的校验和核验命令,修复 Metrics JSON panic,所有 trace 与错误路径的凭据脱敏改为 fail-closed,策略写入严格校验,支持产物改为私有权限,每种产物携带第三方许可证声明,并建立能自证所发之物的发布链:签名标签、精确 main 的 CI 证据、Sigstore 溯源证明与不可变 release。

发布日期: 2026-09-01 · 版本: RELEASE.2026-09-01T00-00-00Z

距离 mcli 20260806 二十六天,本次发布汇总了客户端此后积累的全部变更。工具链升级到 Go 1.27.0,共享依赖栈与 SILO 服务端对齐,SILO 包以自有模块路径导入,go.mod 终于如实描述二进制的构建来源。fork 以来第一个真正的新命令 —— mcli checksum verify —— 到来了,它对端点实际返回的字节只读地核验存储的 S3 附加校验和。让 --json admin prometheus metrics 无法使用的 panic 已修复。而每一条可能打印凭据的路径 —— --debug trace、admin trace、错误消息、JSON 错误文档、checksum 报告 —— 都在三轮对抗性审查之后按 fail-closed 重写。发布流程本身的变化不亚于代码:产物只从 main 精确顶端、且该提交 CI 全绿的 GPG 签名标签构建,每种格式都带有 LICENSENOTICE 与生成的 CREDITS,携带 Sigstore 构建溯源证明,并落入不可变的 GitHub release。

本次发布构建自 ddac5d58,即 pgsty/mc#24 的合并提交:自 RELEASE.2026-08-06T00-00-00Z 以来 49 个提交、262 个文件、+12,487 / −6,089 行。

警告

行为变更

  • macOS 最低版本升至 13。 Go 1.27 链接 darwin 二进制时的最低系统版本为 13.0,darwin 归档包在 macOS 12 及更早版本上无法运行。
  • mcli --json admin prometheus metrics 重新可用,并按名称确定顺序输出 metric family。纯文本 metrics 输出不变。
  • pipe 的标准输入为空时,现在执行普通的零字节 PUT,而非单分片的 multipart 上传。生成的 ETag 是 d41d8cd98f00b204e9800998ecf8427e,而非 <md5>-1 形式。非空输入不受影响。
  • 策略写入在客户端严格校验 —— admin policy createadmin user svcacct add/setidp ldap accesskey create/edit。裸 ARN(如 arn:aws:s3:::)被拒绝(表示该前缀下的全部资源请写 arn:aws:s3:::*);命名策略缺少 Version 被拒绝;空策略被拒绝;同一 statement 内混用 S3 与 admin action 被拒绝。后三种情形服务端本来就会拒绝,因此只有裸 ARN 改变了"什么能被存入"。读取既有策略仍然宽松;服务账号的会话策略仍可省略 Versionadmin user svcacct set --policy 也仍接受空文档 —— 这是清除内联策略、让账号回到继承策略的方式。
  • 写在命令名之前的全局参数格式错误现在会报错。 mcli -H "bad" ls,以及在 app 层无法解析的 --resolve--limit-* 取值,此前会被静默忽略、命令照常运行;现在与命令层形式一样以同样的消息失败,且只报告一次、输出到 stderr(--json 下为 JSON 错误文档);此前 CLI 库会先把该文本回显到 stdout。
  • 错误消息不再回显密钥。 alias set 对错误的 secret key 只报告长度要求;MC_CONFIG_ENV_FILE 的解析错误给出行号而不重复该行;SSE-C 密钥错误不再回显密钥;admin config set 对携带密钥的 key=value 打码;远端复制目标打印时不含凭据;格式错误的 --custom-header 按位置报告,从不按值。
  • 支持产物改为私有。 support diagsupport profilesupport perfsupport inspectadmin cluster bucket exportadmin cluster iam export 写出的文件以 0600 创建,包括对上一个文件的轮转备份。此前是 06440666
  • --debug 显示得更少。 Authorization 头只保留 scheme(AWS4-HMAC-SHA256 **REDACTED**);token、cookie、API key、SSE-C 密钥以及每一个 --custom-header 的值都被打码;2xx 响应的 body 不再 dump。admin trace 的输出在默认与详细两种渲染下以同样方式脱敏:按名字打码的 header 值、查询串、body、错误文本与注记。
  • User-Agent 报告 minio-go/v7.3.0(SDK 自身的版本常量),而非 minio-go/v7.0.98

主要变更

  • Go 1.27.0:模块、容器构建阶段、Linux/macOS/Windows CI、交叉编译、tidy 检查与漏洞分析全部使用 1.27.0。Go 官方维护的模块族同步更新:x/net 0.58.0、x/sys 0.47.0、x/term 0.45.0、x/text 0.41.0、x/crypto 0.55.0、x/mod 0.40.0、x/sync 0.22.0、x/tools 0.49.0。golangci-lint 移出产品模块图,按钉死的 v2.13.1 独立安装。
  • 以自有模块路径导入 SILO 包。 go.mod 现在直接 require github.com/pgsty/silo-pkg/v3 v3.13.0。客户端的策略校验依赖只有那里才有的辅助函数 —— policy.ParseConfigStrictpolicy.Resource.IsBareARN —— 而对上游 minio/pkgreplace 不会被任何把本模块当作依赖引用的项目继承(pgsty/mc#12),因此改为如实声明依赖。上游 minio/pkg 仅作为 colorjson 的间接依赖存在,由依赖下限检查钉在 v3.6.1,gomodguard 则阻止上游 import 路径回流。minio-go 从 v7.0.99 升到 silo-pkg 自身构建所依赖的上游伪版本 v7.3.1-0.20260828014306-0e78d3f18efe;过渡期的 pgsty/silo-go fork 已退役,它唯一的功能性改动已合入上游。共享依赖栈的其余部分跟随服务端:etcd 客户端模块从 3.6.9 升到 3.7.1,包含 GO-2026-6107 / CVE-2026-73500 的修复;grpc-gateway 2.29.0、zap 1.28.0 与 go.yaml.in/yaml/v3 3.0.5 跟随。go-systemd 通过 SILO 共享的可移植性钉子有意停留在 22.6.0 —— 22.7.0 在 NetBSD 上无法编译。
  • 运行时版本下限受到保护。 第一轮依赖调整曾因移除开发工具而悄然拉低了十余个运行时模块的选定版本 —— 其中包括 shoenig/go-m1cpu,其旧版本在启用 CGO 的新款 Apple Silicon 上会在初始化阶段崩溃 —— 该候选版本被否决。buildscripts/check-dependency-floors 现在把 go.mod 中的每一条依赖与上一个 RELEASE.* 标签比较,出现回退即构建失败;唯一允许的例外是 go-systemd 钉子。
  • mcli checksum verify设计文档)。将存储的 S3 附加校验和 —— CRC32、CRC32C、CRC64NVME、SHA1、SHA256,类型为 FULL_OBJECT —— 与对象 API 返回的逻辑字节逐一核验,支持单个对象、--recursive 前缀、--versions 全部版本或精确的 --version-id,以及 JSON Lines 候选清单。对未版本化对象以 If-Match 读取并在读后重新 stat,与核验并发的写入会被报告为 UNKNOWN_OBJECT_CHANGED 而非误判为不匹配。每个对象得到 MATCHMISMATCHNO_CHECKSUMWOULD_VERIFY(dry run)、十种 UNKNOWN_* 分类之一,或三种 SKIPPED_* 之一;汇总包含 objectsverified 计数(MATCH + MISMATCH,即真正重算过校验和的结果)、各状态计数与 incomplete--fail-on 接受 mismatchunknownno-checksum(任一对象缺少校验和、或根本没有核验任何对象时失败)、any(默认:不匹配、未知,以及被 --max-size 跳过的对象)或 none--report 把同样的记录写入新建的 0600 JSON Lines 文件。无论 stdout 是否为终端,结果都写到 stdout;--json 在非终端下输出紧凑的 JSON Lines —— pgsty/mc#5 报告的非 TTY 静默问题已修复。支持 dry run、--max-workers--max-size、时间过滤,以及通过 --enc-c 的 SSE-C。该命令在 CI 中针对真实 SILO 服务器验证。
  • 凭据脱敏,fail-closed。 Codex 的三轮对抗性审查发现,最初的脱敏实现 —— 以及它的前两次重写 —— 只识别预期中的形态、其余原样放行:含斜杠的 access key、首值为空以掩盖第二个值的 Authorization、非十六进制签名、藏进 credential scope 或 SignedHeaders 的密钥、Proxy-Authorization、cookie、X-Api-Key、响应 trailer、带 userinfo 的跳转 Location、把请求头反射进错误 body 的服务端、--json 错误输出中被 JSON 转义的密钥、重复出现两次的短 token。最终设计只有三条规则、没有例外:Authorization 类的值只保留 scheme;名字看起来像密钥、或由调用者通过 --custom-header 提供的头一律打码、不问内容;客户端自己没有生成的文本 —— 响应 body、服务端错误消息、trace 注记 —— 先按凭据形态扫描,再按进程学到的每一个密钥字面值擦除。最后这一层由进程级的密钥登记表支撑:别名 secret key 与会话令牌、MC_HOST_* 取值、各种编码形态的 SSE-C 密钥、tier 与 service principal 密钥、GCS 凭据文件、LDAP 密码及其返回的 STS 凭据、SUBNET 令牌、--secret-key/--account-key/--api-key 参数,以及携带密钥的 key=value 参数,都在读入时、校验或任何网络调用之前登记。出现位置先收集为区间并合并再替换;JSON 错误文档在解码后的值树上只清洗字符串叶子,因此 key 与非终端下的紧凑格式都不受影响。四十余条对抗用例、一个让真实客户端对着"反射所有收到内容"的端点运行的黑盒测试,以及对 SILO 服务器的实时抓包,共同钉住了结果。
  • admin trace 脱敏。 服务端为其他客户端请求提供的 header map 走的是 S3 tracer 从未触及的路径。人类可读与 JSON 两种渲染、默认与详细两种形式,现在都基于脱敏后的副本 —— 事件对象在两者间共享、永不被修改。查询串(预签名 URL 的签名、位于第一个参数的会话令牌)、body、错误文本与注记都会按事件自身的 header 值擦除,因此其他客户端发送的 token 不可能进入特权 trace 输出。header 按名字打码:其他客户端以不像密钥的名字发送的 --custom-header,会按服务端看到的样子显示。

缺陷修复

  • Metrics JSON 不再 panic。 20260806 客户端的 mcli --json admin prometheus metrics 在 v2 与 v3 两种 metrics API 下都会以 panic: Invalid name validation scheme requested: unset 失败。madmin-go 构造了 Prometheus 文本解析器的零值,而 prometheus/common 0.66 起拒绝这种用法。客户端现在以 UTF-8 校验模式构造解析器,遇到问题返回普通解析错误而非 panic,并按名称顺序输出 family。
  • pipe 空输入改为普通 PUT;此前对零字节发起的单分片 multipart 上传既无必要,又会生成 multipart 形式的 ETag。
  • RPM 载荷校验与签名脚本对齐:内容与发布元数据不符的 RPM 会在签名之前被拒绝。
  • sql 打印完结果行后不再 panic。 SDK 的 select 读取器会在每个终止事件上自行关闭 HTTP 响应,而客户端又关闭了一次;在 zstd 压缩的响应上两次排空相互竞争,对 SILO 服务器的查询约五分之二会在结果行已经写出之后以 panic: invalid memory address、退出码 2 收场(pgsty/mc#23)。客户端现在改为取消请求并排空结果管道,而不是再次关闭响应;在真实服务器上连续 820 次查询零 panic,而旧客户端 50 次中失败 21 次。

安全加固

  • 运维人员产出的文件不再对全局可读。 support diag 一边警告归档可能包含敏感环境信息,一边以 0666 写出;共用的 moveFile 帮助函数在把每个 0600 临时文件搬到最终名字的途中放宽为 0644,而即便保留源文件权限,早期客户端留下的 0644 仍会被带进轮转备份。现在每个支持产物都以 0600 创建,并在写入第一个字节之前 chmod。
  • Test_FullSuite 遇 panic 即失败。 功能套件此前会从 panic 中 recover 以执行清理、然后报告成功;套件中任何位置的 panic(包括二进制构建)在 CI 里都不可见。
  • 新命令帮助中残留的 play/ 别名 —— 仓库里唯一仍在宣传 MinIO 运营演示别名的文件 —— 已替换,品牌门禁现在除主机名外也拒绝命令示例中的裸别名。
  • 补齐 AGPL 声明:六个 fork 自有文件此前只带许可证文本的前半段。

工程与交付

  • 每种产物都带第三方声明。 CREDITSbuildscripts/gen-credits.sh 从链接进六个 GoReleaser 目标的运行时模块并集生成,并在 CI 中比对,依赖变更不可能让它悄然过期。LICENSENOTICECREDITS 随 GoReleaser 归档包、DEB/RPM/APK 软件包以及每一个容器镜像(/licenses/ 目录)一同交付。
  • CI 在 main 上运行。 GoCrosscompile 此前只在 pull request 上运行,merge commit —— 真正被打标签的提交 —— 从未被测试;现在每次推送到 main 都会运行。它们的并发组以 github.head_ref 为键,而它在 pull request 之外为空,于是每次手动触发都会取消其他所有运行;现在改以 pull request 编号为键、ref 作为回退。VulnCheck 也改为每周运行,因为归档上游的 fork 可能数周没有提交。CI 中的功能套件现在针对 SILO RELEASE.2026-08-06T00-00-00Z 运行。
  • 只从签名标签发布。 产物工作流没有手动触发;产物来自推送的 RELEASE.* 标签,事件 SHA、标签指向的提交与检出三者必须一致。verify-release-tag.sh 要求 annotated 标签带有来自预期密钥的有效 OpenPGP 签名 —— 指纹与公钥位置来自仓库变量,而非标签指向的树本身,且导入的密钥必须与预期指纹一致。check-release-commit.sh 要求被打标签的提交是 origin/main精确顶端,并且四个工作流对该 SHA 都有成功的 push-to-main 运行、按工作流文件路径匹配;pull request 与手动触发的运行不算证据。check-release-state.shpgsty/mc#6)按标签串行运行、从头替换恰好一个既有 Draft、拒绝已发布的 release,并在上传软件包前再次确认只有一个 Draft。每一个判定都住在带 fixture 覆盖的 shell 脚本里;测试中的假 gh 既钉住判决,也逐字核对传入参数。
  • 溯源与不可变。 归档包、checksums、DEB 与 APK 软件包携带 Sigstore 构建溯源证明(gh attestation verify <file> --repo pgsty/mc)。RPM 有意排除:sign-release-rpms.sh 会在 release 仍为 Draft 时用密钥 9592A7BC7A682E7333376E09E7935D8DB9BD8B20 的分离式 GPG 签名改写其字节,早先做的证明会指向没有任何已发布 RPM 拥有的摘要。GitHub release 一经发布即不可变;修复资产意味着新标签。pgsty/mc 容器镜像只在 gh attestation verify 把每个归档绑定到 release.yml@refs/tags/<tag>、发布提交摘要、GitHub 托管 runner、其自身文件名与 SHA-256 之后才从经证明的归档构建;解包出的二进制的 ELF 机器类型必须与归档架构一致;每个架构的镜像先拉取、运行并检查标签,然后才合并 manifest,latest 只从双架构 manifest 写入。UBI 基础镜像按摘要钉住,由 Dependabot 保持更新。
  • 仓库治理。 main 要求 pull request 与全部八项精确检查(DCO、Linux/macOS/Windows 的 Go、vetchecks、Crosscompile、VulnCheck、Test Release —— 后者现在不带路径过滤地在每个 pull request 与推送上运行);RELEASE.* 标签只有管理员能创建,且永远不能更新或删除;secret scanning、push protection、Dependabot 告警与安全更新已开启。本项目由单人维护,可强制执行的政策是"通过必需检查门禁的 pull request"而非独立人工评审;README 已如实说明。
  • 打标签前的验证。 tidy/verify、依赖下限、go vet、golangci-lint、actionlint、品牌政策、govulncheck 零可达漏洞;Apple Silicon 原生 CGO 执行与完整 race 套件;交叉编译矩阵外加 FreeBSD、OpenBSD、NetBSD 与 Windows ARM64;以及针对已发布 SILO RELEASE.2026-08-06T00-00-00Z 的 HTTP 与 HTTPS 完整功能套件,涵盖 SSE-C、分片上传、watch、mirror、预签名请求、用户与策略。在此之上是 Codex(GPT-5.6)三轮审查与 Claude Code 的独立验证,以及打标签前由六位独立审查者对 20260806 以来全部差异的最后一轮检查 —— 凭据脱敏、checksum verify、行为变更、发布链、模块路径迁移,以及候选二进制与 20260806 二进制在真实服务器上的黑盒对比。49 个提交中有 34 个直接回应这些审查发现的具体问题,每一条在修复前先固化为回归测试。除凭据工作之外,审查还发现并由本次发布修复了:即便没有核验任何对象也可能 exit 0--fail-on no-checksum;会接受"从未真正构建过发布提交"的运行的发布门禁;本会让第一次真实容器发布失败的证明 subject 检查;latest 曾短暂指向仅 amd64 manifest 的时刻;默认 admin trace 渲染不脱敏地打印查询串;把错误消息中的普通文字改写掉的凭据形态;无法再清除策略的 svcacct set;以及由来已久的 sql panic。

兼容性

本版本的完整 --help 树与 20260806 二进制做了 diff:唯一差异是新增的 checksum 命令。在同一服务器上并排对比,headcatgetcpmirrorfindsharesqlstatls 的输出与 JSON 字段集完全一致;二十份真实形态的策略除裸 ARN 外接受/拒绝结果一致;admin policy info --json 逐字节相同。mc 命令名与 mcli 软件包名;~/.mc / ~/.mcli 配置目录;github.com/minio/mc 模块路径及全部 import 路径;MC_* 环境变量;协议头(x-minio-*)与 minio-go User-Agent 前缀;minio tier 类型;.part.minio 传输后缀;minio-job 抓取任务名;以及软件包格式、产物命名与 YYYYMMDDHHMMSS.0.0 版本方案均未改变。客户端继续兼容 MinIO 服务器及其他 S3 兼容端点。把本模块当作 Go 依赖引用的项目现在直接解析到 github.com/pgsty/silo-pkg/v3,不再需要自己为它写 replace

说明

已知问题与边界

  • 当服务端自身的完整性校验拒绝读取时,checksum verify 报告的是 UNKNOWN_READ_ERROR 而非 MISMATCH —— SILO 的 bitrot 保护会在对象 API 返回之前拒绝损坏的分片。MISMATCH 意味着存储的校验和描述的字节与对象 API 返回的不同,这正是该命令要找的历史写入路径缺陷;UNKNOWN 永远不会被报告为 MATCH
  • Access key ID 只要出现在凭据结构内就会被打码,但把裸 access key 反射进错误消息的服务端仍会让它被打印:它在合法消息中同时充当用户标识。短于三个字符的密钥不登记。当 secret key 与 access key 相同时 —— 默认的 minioadmin:minioadmin —— 错误文本中的这个标识也会被打码,因为这个字符串就是密钥。
  • --json 错误文档中 cause.error 的 key 按字母序而非结构体顺序排列;key 与值本身不变。
  • mcli sql 在 stderr 报告查询失败后仍以 0 退出(pgsty/mc#25):逐对象的错误只报告而不中止运行,以便递归查询继续。与上游一致。
  • govulncheck 追踪到间接依赖 x/crypto/openpgp 中的 GO-2026-5932;不存在修复版本,客户端也不调用它。
  • minio/mc#5139 继续适用:mirror --remove --watch 在源端删除对象的 非当前版本 时,可能误删目标端的现存对象。
  • 不阻断发布的质量债 —— 归档可复现性、测试工具链可移植性、KMS / SSE-S3 / 多站点复制的延后覆盖 —— 记录在 pgsty/mc#21
  • 6686b64: chore(deps): align the SILO Go dependency stack
  • 423490d: fix: stop JSON metrics from panicking
  • 14b05e6: build: generate and package third-party notices
  • e938cea: fix: align RPM payload signing validation
  • 8158605: release: adopt Silo Go SDK v7.3.1
  • d6ba236: ci: allow manual release workflow runs
  • b6b2655: ci: release an existing tag on dispatch
  • 70a2950: fix: preserve embeddable pkg compatibility
  • aa07b1c: feat: add read-only object checksum verification
  • 1b39423: fix: preserve checksum output in pipelines
  • a31a42b: docs: record checksum verify output contract
  • 2121081: fix: validate policy writes strictly
  • 712bf3a: fix: use regular PUT for empty pipe input
  • 9a3805d: ci: make release retries tag-idempotent
  • 7bc9843: test: make report permissions portable
  • 2d5abc2: chore: complete the AGPL notice on fork-authored files
  • f5c5dc9: build: import the SILO package under its own module path
  • a8e7eb4: ci: test main on push and stop dispatch runs cancelling each other
  • b75d28b: fix: stop checksum verify help from advertising the play alias
  • c05da7b: chore: drop configuration for bots that are not installed
  • a29b455: fix: stop –debug from printing credentials
  • 08244df: fix: keep secrets out of error messages and traces
  • 30a7ea0: fix: stop writing support artifacts world-readable
  • 14bd724: test: fail the full suite when it panics
  • 4abbb3a: feat: expose how much checksum verify actually verified
  • f484d0d: ci: make a release prove its commit, and pin what it builds from
  • 2c33a4e: chore: ignore the local consumer-module review scratch directory
  • bdc742a: fix: close the remaining –debug credential leaks
  • 3998392: fix: withhold SSE-C keys and credential URLs the parser rejects
  • c1358c4: fix: force 0600 on rotated support artifacts too
  • 45e5144: fix: fail –fail-on no-checksum when nothing was verified
  • 3674933: ci: make the release gate provable and its claims true
  • 8b7b2e9: test: exercise checksum verify against a real server
  • 4b36b0a: fix: make credential redaction fail-closed and scrub final output
  • a6c14da: ci: verify build provenance before repackaging archives into images
  • 915cfd9: fix: reject a malformed app-level global flag instead of ignoring it
  • 81e2767: fix: rebuild SigV4 traces from known fields and widen secret scrubbing
  • 625713c: fix: keep only the scheme of a signed header and scrub JSON structurally
  • ec12b64: fix: redact admin trace output and register every credential ingress
  • 1445e88: ci: release only from a signed tag at the tip of main, verify exact provenance
  • f188939: fix: close final credential and release verification gaps
  • f5b88dd: fix: redact the default admin trace and stop the shape sweep mangling prose
  • 59989f8: fix: let svcacct set clear a policy again, report bad global flags once
  • d38412a: fix: classify an SSE-C refusal with a key as a read error, keep policy and size messages clear
  • b291b53: fix: register a URL password as written, keep listing parameters visible in traces
  • 9dfca8f: test: drive the SSE-C refusal classification through the verify path
  • 76b2e89: fix: keep an unquoted DSN password whole and match auth schemes case-insensitively
  • 328efee: fix: register the password before the first separator of an unquoted DSN payload too
  • 7057705: fix: avoid double-closing S3 Select responses