fix(tokenless): fail RPM build when spec lacks anolisa-component Provides - #2868
fix(tokenless): fail RPM build when spec lacks anolisa-component Provides#2868Forrest-ly wants to merge 2 commits into
Conversation
…ides Mirror the build_cosh_ng component-contract guard for build_tokenless: derive the component name from .anolisa/component.toml.in, verify it matches the RPM package name, and require an exact "Provides: anolisa-component(<name>)" line in tokenless.spec.in before running rpmbuild. Spec drift now fails the build instead of shipping an RPM that silently lacks the capability used by `anolisa install tokenless` when the component index is unavailable (alibabaGH-2836). Signed-off-by: 林生 <linyan.lin@alibaba-inc.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b6181ff416
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if ! grep -Fqx "Provides: anolisa-component(${component_name})" "$spec_in"; then | ||
| err "tokenless spec must provide anolisa-component(${component_name})" | ||
| return 1 |
There was a problem hiding this comment.
Enforce the guard in the RPM-producing workflow
When tokenless RPMs are produced by the checked-in nightly pipeline, this guard never runs: .github/workflows/docker-nightly.yaml delegates the tokenless job to _rpm-build.yaml, which processes the archived spec and invokes rpmbuild directly. Consequently, removing the Provides line still lets that pipeline publish an RPM with the original defect; move or duplicate this assertion in _rpm-build.yaml (ideally verify the built RPM's capabilities) so the production artifact path is protected.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Good catch — accepted. Verified the gap: docker-nightly.yaml delegates the rpm-tokenless job to _rpm-build.yaml, which processes the archived spec and invokes rpmbuild directly, so the guard in scripts/rpm-build.sh never runs on the nightly path.
Fixed in f359ab9 by duplicating the assertion into _rpm-build.yaml (gated on inputs.component == 'tokenless', other components unaffected) and adding the artifact capability verification:
- New
Verify tokenless component contractstep beforeBuild RPM: derives the component name from.anolisa/component.toml.inin the source archive, verifies it matches the RPM package name, and requires the exactProvides: anolisa-component(<name>)line in the processed spec — same assertions asbuild_tokenless. Collect RPM artifactsnow verifies each built RPM actually publishes the capability viarpm -qp --provides, catching a malformed Provides line that rpmbuild would silently drop (mirrors the existing agentsight verification hook).
Local verification: simulated the nightly spec processing with the real tokenless.spec.in + component.toml.in — happy path passes; removing the Provides line (the original defect scenario), a Name/component mismatch, and a missing contract template all fail the guard; built minimal test RPMs with/without the capability to confirm the artifact check accepts/rejects correctly; actionlint clean. CI re-runs on this push.
The checked-in nightly pipeline produces tokenless RPMs through docker-nightly.yaml -> _rpm-build.yaml, which processes the archived spec and calls rpmbuild directly, so the build_tokenless guard added to scripts/rpm-build.sh never runs there: deleting the "Provides: anolisa-component(tokenless)" line would still let the nightly publish an RPM with the original defect (alibabaGH-2836). Close the gap with the same component contract assertion, gated on inputs.component == 'tokenless' so other components are unaffected: - New "Verify tokenless component contract" step before rpmbuild: derive the component name from .anolisa/component.toml.in in the source archive, verify it matches the RPM package name, and require an exact "Provides: anolisa-component(<name>)" line in the processed spec. - Extend "Collect RPM artifacts" to verify every built RPM actually publishes the anolisa-component(<name>) capability via rpm -qp --provides, catching malformed Provides lines that rpmbuild would silently drop. Signed-off-by: 林生 <linyan.lin@alibaba-inc.com>
kongche-jbw
left a comment
There was a problem hiding this comment.
Review baseline: 83781b482182...f359ab95d291
[P2] 更新 PR 描述以覆盖 nightly workflow 变更
.github/workflows/_rpm-build.yaml:252 起已经加入 nightly 构建前检查和成品 RPM
能力校验,但 PR 正文仍称最终仅修改 scripts/rpm-build.sh,验证表也只覆盖首个提交。
这会让后续审查者无法从 PR 正文复现当前范围与风险。建议同步更新 What changed、
Validation 和 Risk,记录 f359ab9 中新增路径的实际验证结果。
|
@kongche-jbw 感谢 review,意见合理,已采纳:PR 描述已更新,完整覆盖 What changed:拆分为两个 commit 小节 —— Validation:保留原有针对首个提交的实测表,并新增
Risk:已更新,注明两处守卫均为新增断言、不改变 spec/归档/rpmbuild 调用,workflow 守卫按 CI 在 |
kongche-jbw
left a comment
There was a problem hiding this comment.
Review baseline: 83781b482182...f359ab95d291
未发现阻塞问题。
Remaining risks:
- 本轮未触发 GitHub-hosted nightly 端到端构建;当前环境也没有 rpm/rpmbuild,
因此未独立重建并查询成品 RPM。
Verification scope:
- 复核完整 diff、归档与 nightly 调用链、全部 PR 评论、Review 和 reviewThreads。
git diff --check、bash -n scripts/rpm-build.sh、两份 workflow 的 PyYAML 解析通过。- 当前 head SHA 上远端检查无失败项;组件测试按本次变更范围跳过。
|
Closing because the internal RPM release pipeline does not use either scripts/rpm-build.sh or .github/workflows/_rpm-build.yaml. The repository and tokenless/v0.7.12 tag already contain Provides: anolisa-component(tokenless), so this PR does not change the path that produced the affected artifact. The release-side spec will be corrected in the internal publishing process. Keeping #2836 open until a corrected RPM is published and verified. |
Why
The released tokenless 0.7.12 RPM still lacks
Provides: anolisa-component(tokenless)even though the spec fix (#2576) landed onmain. The in-repo build path (scripts/rpm-build.sh) never asserted the capability for tokenless, so a spec baseline that drifted away from the fix could build and ship silently.build_cosh_ngalready guards this (see its identity + Provides + manifest checks); tokenless did not. In addition, the nightly pipeline (docker-nightly.yaml→_rpm-build.yaml) never runsscripts/rpm-build.shat all — it processes the archived spec and callsrpmbuilddirectly — so the in-repo script fix alone leaves the nightly artifact path unprotected.Fixes #2836.
What changed
Commit
b6181ff— in-repo build guard (scripts/rpm-build.sh)Added a component-contract guard to
build_tokenlessinscripts/rpm-build.sh, mirroring the existingbuild_cosh_ngpattern:src/tokenless/.anolisa/component.toml.in.tokenless.spec.incontains an exactProvides: anolisa-component(<component>)line.No change to the shipped spec content (the
Provides:line already exists atsrc/tokenless/tokenless.spec.in); this only makes a future regression fail loudly at build time instead of shipping.Commit
f359ab9— nightly workflow guard (.github/workflows/_rpm-build.yaml)The checked-in nightly pipeline produces tokenless RPMs through
docker-nightly.yaml→_rpm-build.yaml, which processes the archived spec and callsrpmbuilddirectly, so thebuild_tokenlessguard above never runs there: deleting theProvides:line would still let the nightly publish an RPM with the original defect. This commit closes the gap with the same component-contract assertion, gated oninputs.component == 'tokenless'so other components are unaffected:Verify tokenless component contractstep beforeBuild RPM(_rpm-build.yaml:252): derive the component name from.anolisa/component.toml.inin the source archive, verify it matches the RPMName:of the processed spec, and require an exactProvides: anolisa-component(<name>)line in the processed spec.Collect RPM artifacts: for tokenless, verify every built RPM actually publishes theanolisa-component(<name>)capability viarpm -qp --provides, catching malformed Provides lines that pass the text guard but are silently dropped by rpmbuild (mirrors the existing agentsight verification hook).Archive layout note:
package-sourceships the fullsrc/tokenlesstree plus themake generate-component-contractoutput, so the extracted archive contains both the.anolisa/component.toml.intemplate read by the guard and the generated.anolisa/component.toml; the guard'sfindpattern matches only the.intemplate.Validation
Environment (public info only): Linux Alibaba Cloud Linux 3, x86_64; GNU bash 4.4.20; GNU Make 4.2.1; rustc/cargo 1.96.0; node v22.21.1 / npm 10.9.4; rpmbuild 4.14.3; python3 + PyYAML (YAML syntax check only).
Commit
b6181ff— in-repo guardReal runs performed (not simulated):
bash -n scripts/rpm-build.shbash scripts/rpm-build.sh tokenlessrpm -qp --provides <built rpm>anolisa-component(tokenless)presentProvides:line, re-ran buildtokenless spec must provide anolisa-component(tokenless), exit 1tokenlessx, re-ran buildtokenless identity mismatch: RPM name 'tokenless', component name 'tokenlessx', exit 1Positive build output:
tokenless-0.7.13-1.al8.x86_64.rpm;rpm -qp --providesreturnsanolisa-component(tokenless)as the first capability. Negative cases were run against temporary edits and reverted.Re-run on the final tree (
f359ab9):bash scripts/rpm-build.sh tokenlessexits 0, writestokenless-0.7.13-1.al8.x86_64.rpm, and rpmbuild reportsProvides: anolisa-component(tokenless)— confirming the commit-1 guard still passes and commit 2 does not alter the in-repo path.Commit
f359ab9— nightly workflow guardThe nightly path only executes in CI, so each new step body was extracted verbatim from the workflow YAML (only
${{ inputs.* }}substituted, isolated$HOMEinstead of the runner home) and run against a faithful local reproduction of the nightly inputs:.github/actions/package-sourcereproduced for tokenless (copysrc/tokenless/tree →make generate-component-contract→ tar intotokenless-0.7.13.nightly.tar.gz; the rtk vendoring step was skipped because it only affectsthird_party/rtk, which the guard never reads), thenPrepare source and specrun verbatim (extract archive, copy tarball toSOURCES, processtokenless.spec.in→tokenless.specwithsed s/@VERSION@/0.7.13/). The archive was verified to contain both.anolisa/component.toml.inand the generated.anolisa/component.toml._rpm-build.yaml,docker-nightly.yamlsafe_load)Verify tokenless component contract, positive (current tree)tokenless component contract OK: tokenless provides anolisa-component(tokenless), exit 0Provides:line removed from processed specERROR: tokenless spec must provide anolisa-component(tokenless), exit 1tokenlessxin archivedcomponent.toml.inERROR: tokenless identity mismatch: RPM name 'tokenless', component name 'tokenlessx', exit 1.anolisa/component.toml.indeleted from archiveERROR: component contract template (.anolisa/component.toml.in) not found in source archive, exit 1Collect RPM artifactscapability check, positive (freshly built tokenless RPM)Verifying tokenless RPM capabilities: .../tokenless-0.7.13-1.al8.x86_64.rpm, exit 0ERROR: ... does not provide anolisa-component(tokenless)and prints actual provides, exit 1CI at
f359ab9: green, no failed checks (checks for other components are skipped by design on this PR).Risk and compatibility
Build/packaging behavior changed (new fail-fast guards)
The guards only add pre-build and post-build assertions; they do not alter the spec, tarball layout, or rpmbuild invocation. Builds from a correct tree behave exactly as before. No runtime or user-facing behavior changes.
The workflow guards are gated on
inputs.component == 'tokenless': RPM builds for the other components (copilot-shell, cosh-ng, agent-sec-core, agentsight, os-skills, ws-ckpt, agent-memory, skillfs, anolisa) run through unchanged code paths.The collect-step check can only fail a build whose built RPM lacks the declared capability — exactly the defect this PR exists to stop shipping ([tokenless] bug: released 0.7.12 RPM still missing Provides: anolisa-component(tokenless) despite fix #2576 on main #2836).
Not run
cargo test) was not re-run here because the change touches only the shell build guard and CI workflow YAML, not Rust sources.docker-nightly.yaml) was not triggered end-to-end as part of this validation; the new steps were validated by running them verbatim against locally reproduced nightly inputs (source archive, processed spec, built RPM) as detailed above.