test(anolisa): cover adapter observation contracts - #3313
Conversation
kongche-jbw
left a comment
There was a problem hiding this comment.
Review baseline: c648fc4fd83f6b4b570f6a724cd3f31022176c12...0ace70d0f5600e46486f9b67f4d051151f3ae20e
[P1] 状态查询的日志断言会被 enable 阶段误满足
src/anolisa/crates/anolisa-core/tests/adapter_manager.rs:4445 读取并检查完整日志。
同一测试在 4373 行先调用 enable;该调用已写入 framework cli。
因此,即使 AdapterManager::status 停止记录所有查询,这个测试仍会通过,
无法保护本 PR 声明的状态查询审计契约。
Possible direction: 在 enable 后截取日志偏移,只检查 status 新增的记录,
并把新增记录与 queries 一一对应;补充移除状态查询日志后会失败的回归验证。
0ace70d to
a5f5170
Compare
|
@kongche-jbw 已修复,commit 你的判断成立,而且比"断言偏弱"更糟——它是空的。 修法走你给的方向:按阶段截取 + 与
回归验证(你要的"移除状态查询日志后会失败"):把 status 里的两个
mutation 只用于验证,已还原,未进 commit( 本地验证(toolchain 用 1.93.0,仓库 pin 的 1.93.1 在镜像上不存在): 请重新 review。 |
kongche-jbw
left a comment
There was a problem hiding this comment.
Review baseline: a9a371978d3c214e1d8b443c0a4fdd5547b2c10b...a5f5170cc47c57e938509b53d9b27f7d4c2d9709
[P2] 按空格截取 program 会让合法临时路径触发失败
src/anolisa/crates/anolisa-core/tests/adapter_manager.rs:4156 用
split_once(' ') 删除可执行文件 token,但 tempfile 会继承 TMPDIR。
当 TMPDIR 路径含空格时,fake binary 的绝对路径也含空格,helper 只截掉
第一个路径片段;正常的 plugins list 因而被解析为
space/.../openclaw plugins list,与 fake CLI 记录的 plugins list 不同。
我用含空格的 TMPDIR 运行该测试可稳定复现失败,生产调用与审计日志均正常。
Possible direction: 将精确的 world.fake_bin 路径传给 helper 并按完整前缀剥离,
或让两侧记录相同的完整 argv;补一条临时目录路径含空格的回归验证。
Add behavior-preserving regression coverage for the read-only adapter observation path, as the first slice of #3309 (tracked by #3310). No production evidence model, public API, or behavior changes: the diff is two test files. anolisa-core tests/adapter_manager.rs drives the real scan and status collectors over the existing staged OpenClaw world: - candidate versus receipt sets: a declared/discovered row with no receipt carries no source verdict at all and yields no status row, so receipt-only status stays distinct from candidate scan - source authority: a receipt row reports Available, and keeps reporting (with an operator reason) after the package-owned bundle is lost, while the vanished directory stops being offered as a resource root - integrity precedence: SourceAvailable leads the projection, the two package-owned integrity signals follow in a fixed order, and the manager's copies are never duplicated by the driver's - a lost source degrades but leaves integrity Unknown ("could not verify"), never False ("verified absent") - a tampered package-owned file is attributed to ManagedBundleMatches only; SourceRevisionMatches stays True, because on-disk tampering is not a package revision change - read-only boundary: scan spawns no framework query at all, status issues only read-only verbs, and neither mutates installed.toml, the package-owned tree, framework-side state, nor takes the install lock. The audit trail is asserted per phase: the central-log records appended after enable are parsed as LogRecords and must equal, one record per query and in order, the argv the fake CLI logged during scan+status, so the install phase's own records cannot satisfy the assertion. The helper strips the exact staged program path instead of everything up to the first space, so the comparison also holds when the temp prefix -- and therefore the fake CLI's absolute path -- contains one - a staged prefix whose path contains a space: tempfile inherits TMPDIR, so a developer machine or CI runner with a space in its temp root stages a spaced CLI path. The new spaced-prefix audit test pins that shape into the world and requires the same central-log to argv equality there anolisa-cli status.rs projects the output of a real AdapterManager::scan into AdapterObservation, instead of only the hand-written sample entry, so drift between the collector and the component status projection fails in test. Covers receipt-backed fidelity field by field, a candidate row staying source-free, and an unrelated component projecting Absent rather than an empty Present. All four mutation-checked: dropping the projection's source_status mapping, reordering the manager's condition insertion, silencing status's framework invocation logging, and restoring the first-space strip in the audit helper each fail the intended test. The third passed before the per-phase audit assertion, because matching the whole log file was already satisfied by enable; the fourth fails the spaced-prefix test and also the read-only boundary test when TMPDIR contains a space. cargo test --workspace, cargo fmt --all --check and cargo clippy --all-targets --locked -- -D warnings are green. Co-authored-by: multica-agent <github@multica.ai>
a5f5170 to
18b7e6f
Compare
|
P2 已修复,commit 一、先确认你的复现成立,而且我按你的方式跑出了同样的结果。把 生产侧和审计日志本身都是对的: 二、修法:走你给的第一条路,按完整前缀剥离helper 签名加上被剥离的 program,不再猜边界: fn central_log_framework_argv_after(path: &Path, offset: u64, program: &Path) -> Vec<String>调用方把 另外把静默失败改成显式失败:审计命令若不以被 stage 的 CLI 路径开头,helper 直接 panic 并打印两个字符串。以前 三、回归测试新增 不是空转——只把 helper 的剥离逻辑改回 四、验证
工具链照旧说明一句: |
kongche-jbw
left a comment
There was a problem hiding this comment.
Review baseline: 1d2534ec0603ae51d8f600eeb23af679dc8e4392...18b7e6fc701e7b65b8be96ad83af7e76edf5e5e1
未发现阻塞问题。
Remaining risks:
- 未在 ALinux 4 容器复跑完整 workspace。
- PR 正文测试计数仍为 93,当前目标测试实际为 94;最新评论已说明新增回归。
Verification scope:
- 完整 diff、相邻生产实现、既有 reviews/comments/threads、当前 CI。
adapter_manager94/94;CLI 投影 3/3;fmt、clippy、git diff --check通过。
What
Adds behavior-preserving regression coverage for the read-only adapter observation path — the first slice of #3309, as scoped by #3310.
No production evidence model, public API, or behavior changes. The diff is two test files (+705/-2; the 2 deletions are the two
uselines that had to grow).src/anolisa/crates/anolisa-core/tests/adapter_manager.rs(+7 tests)Drives the real
AdapterManager::scan/AdapterManager::statuscollectors over the existing staged OpenClaw world:scan_candidate_row_carries_no_source_verdict_or_status_rowsource_status: Noneand yields zerostatusrows — receipt-only status stays distinct from candidate scanscan_receipt_row_reports_available_sourceAvailablewith no operator reasonscan_receipt_row_reports_missing_source_after_bundle_lossMissingwith a reason, and the vanished directory stops being offered asresource_rootstatus_orders_source_authority_before_integritySourceAvailableleads,ManagedBundleMatchesthenSourceRevisionMatchesfollow in fixed order, and the manager's copies are never duplicated by the driver'sstatus_missing_source_degrades_without_faking_integrityDegraded, but the integrity signals it can no longer read stayUnknown, neverFalsestatus_tampered_package_source_degrades_with_false_integrityManagedBundleMatches=Falseonly;SourceRevisionMatchesstaysTruebecause tampering is not a package revision change.FalseoutranksUnknown⇒Degradedscan_and_status_stay_inside_the_read_only_boundaryscanspawns no framework query at all;statusissues only read-only verbs; neither mutatesinstalled.toml(byte-identical), the package-owned datadir tree, framework-side state, nor takes the install lock. The queries stay auditable via the existing central log + the fake CLI's argv logsrc/anolisa/crates/anolisa-cli/src/commands/tier1/status.rs(+3 tests)Projects the output of a real
AdapterManager::scanintoAdapterObservation, instead of only the hand-writtensample_scan_entry, so drift between the collector and thecomponent statusprojection fails in test:adapter_observation_projection_preserves_a_real_receipt_scan— field-by-field fidelity, andAdapterSourceStatus → AdapterSourceSnapshotmaps 1:1adapter_observation_projection_keeps_a_real_candidate_row_source_free— a real candidate row never gains a source verdict in projectionadapter_observation_projection_reports_absent_for_an_unrelated_component—Absent(source consulted, absence established), not an emptyPresentThe fixture uses the
coshdriver so it needs no framework CLI:detectis side-effect-free, soscanspawns nothing.Why
#3309 consolidates adapter declaration, resource, receipt and inventory evidence across consumers. These are the shared facts its acceptance criteria name — source authority, candidate versus receipt sets, integrity precedence, read-only boundaries — and before this PR they were either untested or only tested against synthetic
ScanEntryvalues, so a collector/projection mismatch was invisible.Verification
cargo test --workspace --locked— green (adapter_manager86 → 93;anolisa-clibin 1106 → 1109; 0 failures)cargo fmt --all --check— cleancargo clippy --all-targets --locked -- -D warnings— cleansource_statusmapping failsadapter_observation_projection_preserves_a_real_receipt_scan; reordering the manager'sconditions.insert(0, …)/splice(1..1, …)failsstatus_orders_source_authority_before_integrity. Both mutations reverted.Environment: unprivileged (non-root) Alibaba Cloud Linux 3, x86_64, rustc 1.93.0, fake framework commands, no network during the test run. #3310 asks for ALinux 4 containers — the suite is host-agnostic (tempdir-rooted layouts, no privilege, no real framework binary) but I could not run it on ALinux 4 itself; flagging that rather than claiming it.
Notes / follow-ups (not changed here)
AdapterSourceRevisionis built from the recorded package inventory, not from disk. SoSourceRevisionMatchescannot see on-disk tampering — onlyManagedBundleMatchescan. That is coherent (one signal per evidence source) but the doc comment onSourceRevisionMatchessays "still equal the enable-time revision" without saying which bytes are compared. Worth a doc-only clarification in a later [anolisa] refactor: build adapter evidence pipeline #3309 slice; not touched here to keep this PR behavior-preserving.rpm_root_defective/ RPM-backend root selection) is covered inadapter_frameworks.rsfixtures, not duplicated here.Closes #3310
Part of #3309
Tracked in Multica as AGE-8083 (Developer autopilot tick, 2026-09-17 11:00 Asia/Shanghai).