Skip to content

#676 [tests] planner の issue458 の試験が root(Docker uid 0)で落ちる:昇格の失敗を権限に頼らない形にする - #681

Merged
Kewton merged 1 commit into
developfrom
feature/issue-676-tests-planner-issue458-root-docker-uid-0
Oct 15, 2026
Merged

Kewton merged 1 commit into
developfrom
feature/issue-676-tests-planner-issue458-root-docker-uid-0

Conversation

@Kewton

@Kewton Kewton commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Refs #676

概要

issue458 の promotion の mode は、workspace の app.txt を読み取り専用にして、昇格の書き込みを失敗させていました。root はファイルの権限(DAC)を無視するので、Docker の uid 0 では書き込みが成功して昇格が起き、issue458_finish_terminal_observation_and_transaction_matrix が落ちていました。

この PR は、昇格の失敗を試験用の故障注入で起こし、権限に頼らない形にします。権限に頼るほかの試験(P3)の扱いもそろえます。

変更の要約

  • src/planner/recovery_snapshot.rs
    • #[cfg(test)] pub(crate) mod test_hooks を足しました。仕組みは次のとおりです。
      • fail_sync_source_tree_copy_for_workspace(&Path) が guard を返します。guard は Drop で元に戻すので、panic しても戻ります。
      • 状態は thread-local に持ちます。
      • その試験の workspace のパス(canonicalize 済み)と一致したときだけ、sync_source_tree の copy を失敗させます。
      • 1 回失敗させると消えます。そのため、後に続く control の保持や巻き戻しの copy は失敗しません。
      • 並列に走る別の試験には漏れません。
    • sync_source_tree の std::fs::copy の直前に、#[cfg(test)] の分岐を足しました。エラーの context は製品と同じ restore Recovery control artifact … です。
    • hook 自体の単体試験 test_hooks_fail_sync_copy_is_scoped_and_resets_on_drop も足しました。
  • src/planner/auto_recovery/issue458_tests.rs
    • promotion の mode で、finish の前に hook を仕込みます。
    • 読み取り専用の設定は残しました。hook が無くても、uid 1000 では今の経路で昇格が失敗します(下の二点測定で確かめました)。
    • 既存の assert は変えていません:unexpected promotion、source の sha が変わらないこと、NonRecoverable、昇格の event が無いこと、treatment_promotion_failed: の event があること。
  • src/tools/path_guard.rs:権限が効かないときに黙って return していた部分を、理由を出して落ちる assert に替えました。
  • tests/missing_read_paths.rs:判定は同じです。root でも理由の文が必ず出る形にしました。
  • docs/dev/parallel-dev-harness.md:§3a の Docker の規則に「baseline と mutation の両方を uid 1000 で流す」という 1 文を足しました。

P3 の分類

試験 何に頼っているか uid 0 での挙動 扱い
src/tools/path_guard.rs ensure_bash_write_target_rejects_unreadable_parent 実際の EACCES(0o000 のディレクトリ) 理由(run under an unprivileged account)を出して落ちる。前は黙って pass していた 理由を出して落ちる形にそろえた。黙った成功はなくなった
tests/missing_read_paths.rs actual_permission_denial_is_not_ordinary_missing 実際の EACCES 理由を出して落ちる。前は理由の文なしで panic していた 理由の文が必ず出る形にした。判定は同じ
src/planner/recovery_contract_binding.rs:275 製品のコード(契約ファイルを読み取り専用にする)。試験は readonly() のビットだけを見る pass(5 本) 変更なし。権限の拒否には頼っていない

利用者に見える挙動の変化

  • なし。製品のコードに足したのは #[cfg(test)] の部分だけで、製品の挙動・event・schema は変わりません。

検証(head 963b24cf)

  • 15 ゲート:commandmate verify passed 15/15。最後の commit の後で、clean です。
  • cargo deny:ok。
  • Linux:cargo-zigbuild clippy --all-targets --target x86_64-unknown-linux-gnu exit 0。
  • release の記号:cargo build --release の binary の nm・strings に、hook の記号と simulated failure copying の文字列は 0 件でした。
  • Docker:kernel 7.0.14、--network none、mount なし、--privileged なし。同じ image で uid 0 と uid 1000 を流しました。
試験 uid 0 uid 1000
issue458_finish_terminal_observation_and_transaction_matrix ok ok
planner::recovery_snapshot::(hook の単体試験を含む 8 本) ok ok
planner::recovery_contract_binding::(5 本) ok ok
ensure_bash_write_target_rejects_unreadable_parent 理由を出して FAILED(意図どおり) ok
tests/missing_read_paths(10 本) 9 passed・1 本は理由を出して FAILED(意図どおり) 10 passed
  • 二点測定:hook を仕込まない写し(if mode == "promotion" を if false && … にしたもの。worktree の外の使い捨て)を流しました。
    • uid 0 では promotion: unexpected promotion で FAILED、HEAD では pass でした。つまり、uid 0 で pass したのは hook が昇格の失敗の経路を通しているからです。
    • 同じ写しを uid 1000 で流すと pass しました。読み取り専用の設定が今も昇格の失敗を起こしています。

注意

  • 同じ Docker の image で lib の試験を全部流すと、uid 0 で 16 件、uid 1000 で 15 件落ちます。
    • ほとんどは両方の uid に共通の、環境に由来する失敗です(Next.js・python・node の fixture)。CI と macOS の 15 ゲートでは pass しています。
    • 差の 1 件は、uid 0 で理由を出して落ちる path_guard で、意図どおりです。
  • 今回の worker は、利用者の承認のもとで Command Code ではなく Antigravity でした。成果は development leader が別途検証しています(上の検証)。

🤖 Generated with Claude Code

…r tests

判断: recovery_contract_binding:275 は製品コードであり、そのテストは readonly() ビットのみを検証しているため root (uid 0) でも pass することを確認し、製品コードおよびテストは無変更とした
読み替え: path_guard:990 の黙った return を tests/missing_read_paths と同じく unprivileged account 要求の明示的 assert_eq! に揃えた
@Kewton
Kewton merged commit cde19ba into develop Oct 15, 2026
5 checks passed
@Kewton
Kewton deleted the feature/issue-676-tests-planner-issue458-root-docker-uid-0 branch October 17, 2026 10:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant