From 433b28212d295608d694a732574319c96d6bbe52 Mon Sep 17 00:00:00 2001 From: yen <5915590+antigenius0910@users.noreply.github.com> Date: Thu, 22 Oct 2026 17:40:24 -0500 Subject: [PATCH 1/2] docs(release): add SECURITY.md and base image security runbook Add SECURITY.md with the support policy decided in #1567: only the latest minor line gets fixes, with no backports. It covers private vulnerability reporting and how upstream CVEs in the Node.js base image, agent CLIs, and Debian packages ship as new releases. Add a "Base Image Security Release" runbook to RELEASING.md with a release-note template that has separate sections for breaking-change migration and the deprecated per-agent repositories. Fix outdated references in RELEASING.md. The release build is build-operator.yml, not build.yml. Images use the unified openab:- tags. Cargo.toml carries only the stable version. Manual re-runs need --ref ; without it the workflow builds main HEAD and tags the result as the requested version. Refs #1567 Co-Authored-By: Claude Opus 5.5 --- RELEASING.md | 154 +++++++++++++++++++++++++++++++++++++++++++-------- SECURITY.md | 32 +++++++++++ 2 files changed, 162 insertions(+), 24 deletions(-) create mode 100644 SECURITY.md diff --git a/RELEASING.md b/RELEASING.md index 3fd38dc6c..0ff5dcc82 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -11,6 +11,8 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo | Auto major | major bump + beta | `0.6.0 → 1.0.0-beta.1` | | Manual | 自行指定 | `0.8.0-beta.1` or `0.8.0` | +目前版本已經是 beta 時,auto bump 會忽略 bump type,只把 beta 號碼加 1(e.g. `0.7.0-beta.1 → 0.7.0-beta.2`)。 + ## Release Flow (Tag-Driven) > **核心原則:測過什麼就發什麼 (what you tested is what you ship)** @@ -39,10 +41,13 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo │ │ │ → tag-on-merge.yml 偵測 release/ branch merge │ │ → 自動打 tag (e.g. v0.7.0-beta.1) │ - │ → build.yml 觸發 (is_prerelease=true) │ - │ → build-image: 4 variants × 2 platforms (amd64 + arm64) │ - │ → merge-manifests: image tags = + 0.7.0-beta.1 │ + │ → build-operator.yml 觸發 (is_prerelease=true) │ + │ → build-core: shared builder stage × 2 platforms │ + │ → build-agents: 每個 agent × 2 platforms (amd64 + arm64) │ + │ → merge-manifests: image tags = 0.7.0-beta.1-, │ + │ beta-, - │ │ → release-chart: helm chart → OCI registry │ + │ → build-binaries.yml: openab binaries → GitHub Release │ └─────────────────────────────────────────────────────────────────┘ │ ▼ @@ -63,15 +68,16 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo ``` ┌─────────────────────────────────────────────────────────────────┐ │ 測試通過後,再跑一次 Release PR workflow │ - │ → 手動指定 version: 0.7.0 (不帶 rc) │ + │ → 手動指定 version: 0.7.0 (不帶 -beta.N) │ │ → merge Release PR │ │ → tag-on-merge.yml 打 tag v0.7.0 │ │ │ - │ → build.yml 觸發 (is_prerelease=false) │ + │ → build-operator.yml 觸發 (is_prerelease=false) │ │ → promote-stable: │ │ 1. 找到最新的 pre-release tag (v0.7.0-beta.2) │ │ 2. 驗證 pre-release image 存在 │ - │ 3. re-tag 0.7.0-beta.2 → 0.7.0 / 0.7 / latest │ + │ 3. 每個 agent re-tag 0.7.0-beta.2- → │ + │ 0.7.0-, 0.7-, stable- │ │ ⚠️ 不 rebuild,跟 pre-release 是同一個 artifact │ │ → release-chart: helm chart → OCI registry │ └─────────────────────────────────────────────────────────────────┘ @@ -106,15 +112,113 @@ Versions follow SemVer (e.g. `0.7.0`). Version bumps are controlled via `workflo # → merge → 自動打 tag → promote beta image (不 rebuild) # ── 手動重跑(build 失敗時)────────────────────────── -gh workflow run build.yml -f tag=v0.7.0-beta.1 -gh workflow run build.yml -f tag=v0.7.0 +# --ref 讓 workflow checkout tag 的 commit。不加的話會 build main 的 HEAD。 +gh workflow run build-operator.yml --ref v0.7.0-beta.1 -f tag=v0.7.0-beta.1 +gh workflow run build-operator.yml --ref v0.7.0 -f tag=v0.7.0 ``` +## Base Image Security Release + +Node.js base image 或其他 upstream component 出 security release 時,照這個流程出新版。Support policy 見 [SECURITY.md](SECURITY.md)。只修最新的 minor line,不 backport。 + +##### Step 1 — 發現 security release + +`node-security-check.yml` 每天跑一次。下面任一情況成立時,它會開一個 `node-security` label 的 issue。Issue 已經存在時,它更新同一個 issue。 + +- Node.js security release 比 Dockerfile 裡的 `NODE22_VERSION` 或 `NODE24_VERSION` 新。 +- Node.js security release 比已發佈的 `stable-*` 或 `beta-*` image 裡的 Node.js 新。 + +有人直接回報 security release 時,也從這一步開始。 + +##### Step 2 — Bump Node.js pin + +1. 找出所有宣告 pin 的 Dockerfile: + + ```bash + git grep -lE 'ARG NODE(22|24)_VERSION' -- 'Dockerfile*' + ``` + +2. 在每個檔案把 `NODE22_VERSION` 和 `NODE24_VERSION` 改成修補後的版本。 +3. 開 PR。Smoke tests 會檢查 `node --version` 等於 ARG,CI 通過就代表 image 用了新版 Node.js。 + +##### Step 3 — 出下一個 beta + +1. Bump PR merge 後,照 [Release Flow](#release-flow-tag-driven) 的 Step 1 和 Step 2 出下一個 beta。目前已經是 beta 時,留空 version 就會得到下一個 beta 號碼。 +2. 等 `build-operator.yml` 跑完,確認每個含 Node.js 的 agent 都拿到新版。`kimi` 用 Node.js 24,其他用 Node.js 22: + + ```bash + for agent in claude codex copilot gemini kimi mimocode opencode pi; do + printf '%s: ' "$agent" + docker run --rm --pull always --entrypoint node "ghcr.io/openabdev/openab:beta-$agent" --version + done + ``` + +3. 如果 GitHub Actions cache 給了舊的 base layer,image 裡的 Node.js 會是舊版。這時不用 cache 重 build 同一個 tag: + + ```bash + gh workflow run build-operator.yml --ref -f tag= -f no_cache=true + ``` + + 這會覆蓋 `-`。只在 beta 剛 build 完、還沒公告前這樣做。已公告的版本要修,就出下一個 beta。 + +##### Step 4 — Promote 到 stable + +Beta 驗證通過後,照 [Release Flow](#release-flow-tag-driven) 的 Step 3 promote。Stable 和 beta 是同一個 image,不 rebuild。舊的 minor line 不出修補版。 + +Promote 完成後,把 Step 3 的迴圈換成 `stable-$agent` 再跑一次。 + +##### Step 5 — 發 release note + +chart-releaser 建立的 `openab-` GitHub Release 已經有 `release.yml` 附加的安裝說明。把 security note 加在最前面,不要覆蓋原本內容: + +```bash +VERSION= +gh release view "openab-$VERSION" -R openabdev/openab --json body --jq .body > existing.md +cat security-note.md existing.md > release-note.md +gh release edit "openab-$VERSION" -R openabdev/openab --notes-file release-note.md +``` + +在 `node-security` issue 留下 release 連結後關閉它。 + +`security-note.md` 用下面的 template。Release note 用英文。 + +- 這個 release 同時帶 breaking change 時,一定要填 "Breaking changes and migration"。沒有 breaking change 才刪掉這一段。 +- Per-agent repositories 的刪除日期填 release 後 2 到 4 週。刪除由 org admin 執行。GHCR package 刪除後無法復原。 + +````markdown +## Security + +This release ships images built on Node.js <22.x.y> (Node.js <24.x.y> for `kimi`) to fix . + +- These agent images contain Node.js and get the fix: `claude`, `codex`, `copilot`, `gemini`, `kimi`, `mimocode`, `opencode`, and `pi`. The other agent images do not contain Node.js. +- The floating tags `stable-`, `-`, and `beta-` now point to this build. A deployment that uses one of them gets the fix on its next image pull. +- Existing version tags are not rebuilt. `-` and earlier versions keep the old Node.js. To get the fix, move to `-`. +- Releases older than `` get no fix. Only the latest minor line is supported. See [SECURITY.md](https://github.com/openabdev/openab/blob/main/SECURITY.md). + +To check the Node.js version in an image, run: + +```bash +docker run --rm --pull always --entrypoint node ghcr.io/openabdev/openab:- --version +``` + +The output is `v<22.x.y>`. For `kimi`, the output is `v<24.x.y>`. + +## Breaking changes and migration + + + + + +## Deprecated per-agent image repositories + +The per-agent repositories, such as `ghcr.io/openabdev/openab-claude`, do not receive updates. They do not have this fix. An org admin deletes them on . After that date, a deployment that pulls from them fails with `ImagePullBackOff`. Move to `ghcr.io/openabdev/openab:-`. See [Docker image tags](https://github.com/openabdev/openab/blob/main/docs/image-tags.md). +```` + ## GitHub Releases | Release | Tag 格式 | 內容 | |---|---|---| -| chart-releaser | `openab-0.7.0` | Version Info + Installation instructions | +| chart-releaser | `openab-0.7.0` | Version Info + Installation instructions,加上 `build-binaries.yml` 的 openab binaries 和 `build-oabctl.yml` 的 oabctl | ## Workflow 對應表 @@ -123,8 +227,10 @@ gh workflow run build.yml -f tag=v0.7.0 | `ci.yml` | pull_request (src/Cargo/Dockerfile) | cargo check + clippy + test | | `release-pr.yml` | workflow_dispatch | 建立 Release PR(更新版本檔案) | | `tag-on-merge.yml` | release/ PR merge to main | 自動打 tag | -| `build.yml` | tag push `v*` | pre-release: 完整 build / stable: promote | +| `build-operator.yml` | tag push `v*` | pre-release: 完整 build / stable: promote;兩者都 push helm chart 到 OCI | +| `build-binaries.yml` | tag push `v*` | build openab binaries,上傳到 `openab-` GitHub Release | | `release.yml` | Chart.yaml 變更 push to main | chart-releaser 更新 GitHub Pages index | +| `build-oabctl.yml` | Chart.yaml 變更 push to main | build oabctl,上傳到 `openab-` GitHub Release | ## Version 同步 @@ -136,30 +242,29 @@ release-pr.yml 在 Release PR 中自動更新以下檔案的版本: | `charts/openab/Chart.yaml` | `version` | | `charts/openab/Chart.yaml` | `appVersion` | -三者統一為同一個 semver(e.g. `0.7.0`)。 +`Chart.yaml` 的 `version` 和 `appVersion` 是完整版本(e.g. `0.7.0-beta.1`)。`Cargo.toml` 只寫 stable 部分(e.g. `0.7.0`),讓 main 不帶 pre-release suffix。 ## Image Variants -每次 build 產出 6 個 multi-arch image (linux/amd64 + linux/arm64): +`build-operator.yml` 用 `Dockerfile.unified`,為 `AGENTS` env 列出的每個 agent build 一個 multi-arch image (linux/amd64 + linux/arm64)。所有 agent 都在同一個 repository,用 tag 區分 agent: ``` -ghcr.io/openabdev/openab # default (kiro-cli) -ghcr.io/openabdev/openab-codex # codex -ghcr.io/openabdev/openab-claude # claude -ghcr.io/openabdev/openab-gemini # gemini -ghcr.io/openabdev/openab-opencode # opencode -ghcr.io/openabdev/openab-copilot # copilot -ghcr.io/openabdev/openab-cursor # cursor +ghcr.io/openabdev/openab:- ``` Image tags 依 release 類型不同: | Tag | Stable (`v0.7.0`) | Pre-release (`v0.7.0-beta.1`) | |---|---|---| -| `` | v (from pre-release) | v | -| `0.7.0` / `0.7.0-beta.1` | v | v | -| `0.7` | v | x | -| `latest` | v | x | +| `-` | v (from pre-release) | v | +| `0.7.0-` / `0.7.0-beta.1-` | v | v | +| `beta-` | x | v | +| `0.7-` | v | x | +| `stable-` | v | x | + +沒有 `latest` tag,也沒有 default agent。完整的 tag 規則見 [docs/image-tags.md](docs/image-tags.md)。Agent 清單以 `build-operator.yml` 的 `AGENTS` env 為準。 + +舊的 per-agent repositories(`ghcr.io/openabdev/openab-claude`、`ghcr.io/openabdev/openab-codex` 等)已經 deprecated,不再更新。公告後的 grace period 結束時,由 org admin 刪除。 ## Installation @@ -184,7 +289,8 @@ helm install openab oci://ghcr.io/openabdev/charts/openab --version 0.7.0 | 準備 release | Actions → Release PR → Run workflow | | 需要 beta 測試 | 指定 version 如 `0.7.0-beta.1` | | 測試通過 | 指定 stable version 如 `0.7.0` → promote | -| build 失敗或需重跑 | `gh workflow run build.yml -f tag=` | +| build 失敗或需重跑 | `gh workflow run build-operator.yml --ref -f tag=` | +| Node.js 或其他 base image 有 security release | 照 [Base Image Security Release](#base-image-security-release) | ## GitHub App 權限 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..6bad552e0 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,32 @@ +# Security policy + +## Supported versions + +openab supports only the latest minor release line. That line includes its stable releases and the betas toward the next release. Older minor lines get no fixes, and maintainers do not backport fixes to them. + +For example, when `0.10.0` is the latest stable release, `0.10.x` and the betas toward the next release are supported. `0.9.x` is not. + +To get security fixes, upgrade to the latest stable release. + +## Report a vulnerability + +Do not open a public issue, pull request, or discussion for a vulnerability that is not yet public. Report it privately through GitHub: + +1. Open the [Security tab](https://github.com/openabdev/openab/security) of this repository. +2. Click **Report a vulnerability**. +3. Describe the problem, the affected version or image tag, and the steps to reproduce it. + +Maintainers follow up in the private advisory that your report creates. + +A vulnerability that is already public, such as a published CVE in a dependency, can go in a regular issue. + +## Dependencies and base images + +Release images include upstream components: the Node.js base image, the agent CLIs, and Debian packages. When one of them has a CVE, maintainers rebuild the images on the supported line and release a new version. The fix ships as a new beta. Maintainers then promote that beta to stable without a rebuild. + +- A fix never overwrites an existing version tag such as `0.10.0-claude`. It always ships under a new version. +- The floating tags `stable-`, `-`, and `beta-` move to the fixed build. +- `nightly-` floats and has no compatibility guarantee. It is not a release. +- The deprecated per-agent repositories, such as `ghcr.io/openabdev/openab-claude`, receive no updates and will be deleted. Move to the unified tags in [Docker image tags](docs/image-tags.md). + +The `node-security-check.yml` workflow runs daily. It opens or updates one issue labeled `node-security` when a Node.js security release is newer than the pinned `NODE22_VERSION` or `NODE24_VERSION`, or newer than the Node.js in the published `stable-*` or `beta-*` images. Maintainers then follow [Base Image Security Release](RELEASING.md#base-image-security-release) in `RELEASING.md`. From 5742a5d2b5db9170e3871e1325ceb65793986be8 Mon Sep 17 00:00:00 2001 From: yen <5915590+antigenius0910@users.noreply.github.com> Date: Thu, 22 Oct 2026 21:33:35 -0500 Subject: [PATCH 2/2] docs(release): address review on the security release runbook - Remove the no_cache rebuild step. It re-pushed an existing version tag, which contradicts SECURITY.md. A failed verification now leads to the next beta. - The bump step says each Dockerfile declares only its own Node major ARG and that the smoke tests read the expected value from the Dockerfiles, so a bump does not edit any workflow. - Make the release-note step idempotent with a marker, and use VERSION=0.10.0 as the example. - Reduce the reusable template to the Security section. Breaking-change migration and the per-agent repository notice belong in the specific release note. - Derive the Node agent list from Dockerfile.unified instead of keeping two hand-written lists. Refs #1567 Co-Authored-By: Claude Opus 5.5 --- RELEASING.md | 55 +++++++++++++++++++++------------------------------- 1 file changed, 22 insertions(+), 33 deletions(-) diff --git a/RELEASING.md b/RELEASING.md index 0ff5dcc82..c48de7069 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -135,31 +135,26 @@ Node.js base image 或其他 upstream component 出 security release 時,照 1. 找出所有宣告 pin 的 Dockerfile: ```bash - git grep -lE 'ARG NODE(22|24)_VERSION' -- 'Dockerfile*' + git grep -lE 'ARG NODE[0-9]+_VERSION' -- 'Dockerfile*' ``` -2. 在每個檔案把 `NODE22_VERSION` 和 `NODE24_VERSION` 改成修補後的版本。 -3. 開 PR。Smoke tests 會檢查 `node --version` 等於 ARG,CI 通過就代表 image 用了新版 Node.js。 +2. 每個 Dockerfile 只宣告它自己用到的 Node.js major 的 ARG,例如 `Dockerfile.kimi` 只有 `NODE24_VERSION`。在上面列出的每個檔案,把它宣告的 ARG 改成修補後的版本。 +3. 開 PR。Smoke tests 從 Dockerfile 讀預期的版本(以 `Dockerfile.unified` 為準),所以 bump 只改 `Dockerfile*`,不用改 workflow。Image 含 Node.js 卻沒有對應的 pin,或各檔案的 pin 不一致時,smoke test 會失敗。CI 通過就代表 image 用了新版 Node.js。 ##### Step 3 — 出下一個 beta 1. Bump PR merge 後,照 [Release Flow](#release-flow-tag-driven) 的 Step 1 和 Step 2 出下一個 beta。目前已經是 beta 時,留空 version 就會得到下一個 beta 號碼。 -2. 等 `build-operator.yml` 跑完,確認每個含 Node.js 的 agent 都拿到新版。`kimi` 用 Node.js 24,其他用 Node.js 22: +2. 等 `build-operator.yml` 跑完,確認每個含 Node.js 的 agent 都拿到新版。在 repo root 執行。`NODE_AGENTS` 從 `Dockerfile.unified` 取出 `FROM base-node` 和 `FROM node:${NODE_VERSION}...` 的 stage,排除 `base-*`: ```bash - for agent in claude codex copilot gemini kimi mimocode opencode pi; do + NODE_AGENTS=$(awk 'toupper($1) == "FROM" && toupper($3) == "AS" && $4 !~ /^base-/ && ($2 == "base-node" || $2 ~ /^node:\$\{NODE[0-9]+_VERSION\}/) { print $4 }' Dockerfile.unified) + for agent in $NODE_AGENTS; do printf '%s: ' "$agent" docker run --rm --pull always --entrypoint node "ghcr.io/openabdev/openab:beta-$agent" --version done ``` -3. 如果 GitHub Actions cache 給了舊的 base layer,image 裡的 Node.js 會是舊版。這時不用 cache 重 build 同一個 tag: - - ```bash - gh workflow run build-operator.yml --ref -f tag= -f no_cache=true - ``` - - 這會覆蓋 `-`。只在 beta 剛 build 完、還沒公告前這樣做。已公告的版本要修,就出下一個 beta。 +3. 如果驗證看到舊的 Node.js,修好原因後出下一個 beta,不要重新 push 已經存在的 version tag。 ##### Step 4 — Promote 到 stable @@ -169,28 +164,32 @@ Promote 完成後,把 Step 3 的迴圈換成 `stable-$agent` 再跑一次。 ##### Step 5 — 發 release note -chart-releaser 建立的 `openab-` GitHub Release 已經有 `release.yml` 附加的安裝說明。把 security note 加在最前面,不要覆蓋原本內容: +chart-releaser 建立的 `openab-` GitHub Release 已經有 `release.yml` 附加的安裝說明。把 security note 加在最前面,不要覆蓋原本內容。`VERSION` 是 promote 後的 stable chart version,不加 `v`。例如 `VERSION=0.10.0` 對應 release `openab-0.10.0`: ```bash -VERSION= +VERSION=0.10.0 gh release view "openab-$VERSION" -R openabdev/openab --json body --jq .body > existing.md -cat security-note.md existing.md > release-note.md -gh release edit "openab-$VERSION" -R openabdev/openab --notes-file release-note.md +if grep -qF '' existing.md; then + echo "openab-$VERSION already has a security note. Edit it by hand." >&2 +else + { cat security-note.md; printf '\n\n'; cat existing.md; } > release-note.md + gh release edit "openab-$VERSION" -R openabdev/openab --notes-file release-note.md +fi ``` -在 `node-security` issue 留下 release 連結後關閉它。 +Release 已經有 `` 時,指令會停下來,不會再加一次。這時在 GitHub 上手動改 release note。 -`security-note.md` 用下面的 template。Release note 用英文。 +在 `node-security` issue 留下 release 連結。Pin 和 image 都更新後,`node-security-check.yml` 下一次執行會自己關閉這個 issue。 -- 這個 release 同時帶 breaking change 時,一定要填 "Breaking changes and migration"。沒有 breaking change 才刪掉這一段。 -- Per-agent repositories 的刪除日期填 release 後 2 到 4 週。刪除由 org admin 執行。GHCR package 刪除後無法復原。 +`security-note.md` 用下面的 template。Release note 用英文。`` 填 Step 3 的 `NODE_AGENTS`。這個 release 同時帶 breaking change 時,在 note 裡另外加一段 migration(例如 #1567 要求 0.10.0 要有)。 ````markdown + ## Security -This release ships images built on Node.js <22.x.y> (Node.js <24.x.y> for `kimi`) to fix . +This release updates the Node.js base image to <22.x.y> and <24.x.y> to fix . -- These agent images contain Node.js and get the fix: `claude`, `codex`, `copilot`, `gemini`, `kimi`, `mimocode`, `opencode`, and `pi`. The other agent images do not contain Node.js. +- The agent images built on Node.js () get the fix. The other agent images do not contain Node.js. - The floating tags `stable-`, `-`, and `beta-` now point to this build. A deployment that uses one of them gets the fix on its next image pull. - Existing version tags are not rebuilt. `-` and earlier versions keep the old Node.js. To get the fix, move to `-`. - Releases older than `` get no fix. Only the latest minor line is supported. See [SECURITY.md](https://github.com/openabdev/openab/blob/main/SECURITY.md). @@ -201,17 +200,7 @@ To check the Node.js version in an image, run: docker run --rm --pull always --entrypoint node ghcr.io/openabdev/openab:- --version ``` -The output is `v<22.x.y>`. For `kimi`, the output is `v<24.x.y>`. - -## Breaking changes and migration - - - - - -## Deprecated per-agent image repositories - -The per-agent repositories, such as `ghcr.io/openabdev/openab-claude`, do not receive updates. They do not have this fix. An org admin deletes them on . After that date, a deployment that pulls from them fails with `ImagePullBackOff`. Move to `ghcr.io/openabdev/openab:-`. See [Docker image tags](https://github.com/openabdev/openab/blob/main/docs/image-tags.md). +The output is the patched Node.js version for that image, `v<22.x.y>` or `v<24.x.y>`. ```` ## GitHub Releases