# Eva-CLI GitHub Packages 发布方案

日期：2026-07-14
范围：`.github/workflows/release.yml` 当前实现的 GHCR 容器通道

Eva-CLI 在 `ghcr.io/yetmos/eva-cli` 发布容器 package。它是发布输出之一，不是
版本事实来源，也不能替代 GitHub Release 记录。

![Eva-CLI package 与发布证据路径](../../../assets/release-workflow-evidence-path.zh-CN.svg)

## 当前已发布 Package

最新成功公开 package 对应 `v1.11.4-alpha`：

```text
image=ghcr.io/yetmos/eva-cli
tag=1.11.4-alpha
digest=sha256:9902e18131088408936d16e554078cd8f1c70b457a16b8c5ecc7dbb518ff8ad3
platforms=linux/amd64,linux/arm64
```

后续 `v1.11.5-alpha` release workflow 在 Ubuntu 验证阶段失败，因此 package job
被跳过。当前 `main` 仍报告 `1.11.5-alpha`，但它没有成功发布的对应 package。

## 真实发布顺序

Ubuntu、Windows 和 macOS 的 `verify` 矩阵全部通过后，`packages` job 才开始：

1. checkout 所选 immutable source tag，并带该 tag 运行
   `scripts/validate-version-management.ps1`；
2. 仅当 `Dockerfile` 和 `.dockerignore` 同时存在时启用 package 支持；
3. 为 runner 架构构建本地 smoke image，并在其中运行 `eva --version`；
4. 使用 Buildx 推送 `linux/amd64` 和 `linux/arm64` image，同时启用 provenance 和
   SBOM 生成；
5. 对已推送 digest 运行 `docker buildx imagetools inspect`；
6. 写入 `release-evidence/package-ghcr.json` 并上传 package evidence Actions artifact；
7. 由最终 `publish` job 把 package 结果合并进 provenance 和 distribution evidence。

已推送 digest inspect 只是 registry manifest metadata 检查，不是 pull、install 或
runtime smoke。工作流没有运行已推送的 arm64 image。

## Tag 与 Digest 规则

所有 image tags 都从所选 Git tag 派生：

| Release 类型 | Git tag | GHCR tags |
| --- | --- | --- |
| Alpha/beta | `v1.12.0-beta.1` | `1.12.0-beta.1`、`sha-<7位sha>` |
| Stable | `v1.12.0` | `1.12.0`、`1.12`、`latest`、`sha-<7位sha>` |

预发布版本不更新 `latest` 或 `MAJOR.MINOR` tag，稳定版会更新。但工作流不强制
registry tag 不可变：对已有 tag 手动 dispatch 可以再次推送同名标签。需要确定内容身份时
必须使用 digest。

## Evidence 语义

成功发布时，`package-ghcr.json` 记录 source tag/SHA、package URL、image tags、
platforms、digest、metadata inspect 命令，以及 Buildx provenance/SBOM 生成设置。

Evidence 会保存建议的 provenance 和 SBOM inspect 命令，但 workflow 没有执行这两个
带格式参数的命令，只执行基础 digest inspect。因此：

- `package_manager_dry_run.status=passed` 只表示已推送 digest 可被 inspect；
- 它不证明消费者成功 pull 或运行任一平台；
- Buildx provenance 和 SBOM 不是 OCI image signature；
- 此通道没有生产签名 key 或 signature verification。

最终 release gate 通过 `release-distribution.evidence` 消费 package 状态，但此时
package 已经存在于 GHCR。

## 权限与信任边界

Job 使用仓库 `GITHUB_TOKEN` 和 workflow 声明的权限：

```yaml
permissions:
  contents: read
  id-token: write
  packages: write
  attestations: write
```

当前同仓库 package 通道不需要 personal access token。Image 使用 Debian bookworm
阶段构建，最终以非 root `eva` 用户运行，工作目录为 `/workspace`，runtime image 只复制
`eva` binary。需要项目配置或 durable state 的命令必须由调用方提供相应挂载或文件。

## 消费者验证

优先使用成功 GitHub Release 或 package evidence 中记录的 digest：

```powershell
$Image = "ghcr.io/yetmos/eva-cli@sha256:9902e18131088408936d16e554078cd8f1c70b457a16b8c5ecc7dbb518ff8ad3"
docker pull $Image
docker run --rm $Image --version
docker buildx imagetools inspect $Image
```

这些是消费者侧检查；release workflow 当前只执行 push 前本地 version smoke 和 push
后 digest metadata inspect。

## 失败边界

Package job 与原生压缩包 jobs 并行，并且早于最终 publish job。因此：

- 即使后续原生构建或最终 evidence gate 失败，已经成功 push 的 GHCR image 仍会保留；
- 失败的最终发布必须记录并评审已经发布的 digest；
- 重跑旧 tag 不能包含 tag 之后的代码修复；
- 修复发布应使用新的 prerelease serial 或 patch tag，不能移动原 tag。

## 范围限制

该工作流不发布 signed container image、native installer、Homebrew/Winget/Apt
package 或 Rust crate。GitHub Packages 不能替代 crates.io 的公共 Cargo crate 分发。

## 相关文档

- [项目发布方案](项目发布方案.md)
- [版本管理方案](版本管理方案.md)
- [安装、升级和卸载说明](安装升级卸载说明.md)
