Skip to content

#677 [ci][tests] CI の runner は legacy_tiocsti=0 で TIOCSTI の拒否を測れず、判定もログに残らない - #679

Merged
Kewton merged 1 commit into
developfrom
feature/issue-677-ci-tests-ci-runner-legacy-tiocsti-0-tiocsti
Oct 15, 2026
Merged

Kewton merged 1 commit into
developfrom
feature/issue-677-ci-tests-ci-runner-legacy-tiocsti-0-tiocsti

Conversation

@Kewton

@Kewton Kewton commented Oct 15, 2026

Copy link
Copy Markdown
Owner

Refs #677

概要

GitHub-hosted の Ubuntu の runner では kernel が dev.tty.legacy_tiocsti=0 なので、#667 の TIOCSTI の試験は毎回 UNVERIFIED になります。しかも判定(BLOCKED・UNVERIFIED)は CI のログに残りません。この PR は、CI で TIOCSTI の拒否を測れるようにし、probe の判定を job のログと annotation で読めるようにします。

変更の要約

  • .github/workflows/ci.yml(commandagent-guardrails の job)
    • Enable legacy TIOCSTI for the isolation probes(試験の前)
      • sudo sysctl -w dev.tty.legacy_tiocsti=1 を実行します。書けない kernel でも job は落とさず、could not write … (exit N) をログに出します。
      • 続けて sysctl -n dev.tty.legacy_tiocsti の値を出します。
      • sudo を使うのは sysctl だけです。試験は root や CAP_SYS_ADMIN では流しません。そうすると負の対照も注入できてしまい、正しく測れないからです。
    • Repository acceptance suite:COMMANDAGENT_PROBE_VERDICT_FILE=${{ runner.temp }}/probe-verdicts.txt を渡します。
    • Report isolation probe verdicts(if: always())
      • ファイルを cat します。
      • UNVERIFIED を含む行ごとに ::warning:: を出します。
      • ファイルが無い、または空のときも ::warning:: を出します。
      • この step は job を失敗させません。
  • tests/issue502_os_sandbox_write.rs
    • COMMANDAGENT_PROBE_VERDICT_FILE が設定されているとき、4 つの probe の判定を 1 行ずつ追記します。
      • 対象:TIOCSTI(legacy_tiocsti の値つき)、stdin、devnull-fd、terminal-read。
    • 変数が無いときは何もしません。書き込みの失敗で試験は落ちません($GITHUB_STEP_SUMMARY への記録と同じ扱いです)。
    • 次のものは変えていません:既存の stdout と $GITHUB_STEP_SUMMARY への出力、assert!、期待、#[ignore]、UNVERIFIED の扱い。
  • scripts/ci.sh は変えていません。

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

  • なし。製品のコード(src/)は変えていません。
  • CI の CommandAgent Test and Guardrails の job に step が 2 つ増えます(sysctl と判定の報告)。

検証

  • 15 ゲート:commandmate verify passed 15/15。HEAD 4d882fd5 で、最後の commit の後、clean です。
  • cargo deny:ok。
  • Linux の確認:cargo-zigbuild clippy --all-targets --target x86_64-unknown-linux-gnu exit 0。
  • workflow の構文:bash -n scripts/ci.sh、shellcheck scripts/*.sh、actionlint .github/workflows/ci.yml は exit 0 です。python の yaml でも読めます。
  • Docker の条件:kernel 7.0.14、legacy_tiocsti=1、uid 1000、--network none、mount なし、CapEff 0。
    • D1(CI と同じ形、CI=true、変数あり):28 passed。ファイルには次の 4 行が書かれました。
      issue667/tiocsti: blocked; legacy_tiocsti=1
      issue667/stdin: blocked (both the isolated and unisolated launches detach a terminal stdin)
      issue667/devnull-fd: blocked (both the isolated and unisolated launches close the /dev/null descriptor)
      issue667/terminal-read: blocked
      
    • D2(変数なし):28 passed。ファイルは作られません。
    • D3(workflow から抜き出した報告の step の本文を bash -eo pipefail で流した)。どれも exit 0 です。
      • 実際のファイル:warning は 0 件。
      • UNVERIFIED の行:::warning:: が 1 件。
      • 空・無し:「記録なし」の ::warning::。
  • 二点測定(同じ Docker。写しは worktree の外の使い捨て):
    • tpB(configure_child_session を [security][tools] OS の隔離の中から制御端末へ TIOCSTI で入力を注入でき、/dev/pts の他の端末へ書ける #667 の前の process_group(0) に戻した写し。setsid も stdin の付け替えもなし):isolated_child_cannot_inject_into_the_controlling_terminal は FAILED でした(an isolated child injected into the controlling terminal: master echoed "Y")。
    • HEAD:pass(BLOCKED)。
    • tpA の注記(setsid だけを外し、detach_terminal_stdin は残した写し):
      • TIOCSTI の試験は pass します。fd 0 の pty が /dev/null に付け替えられ、fd 0 への TIOCSTI がそもそも成り立たないからです。
      • この回帰は、同じファイルの bounded_child_runs_in_its_own_session_and_process_group(sid = pid の確認)が FAILED で検出します。
  • 手元の挙動は変わりません:変数なしで、macOS は 29 passed、判定は 4 つとも BLOCKED(自前の pty だけ)。Linux は 28 passed です。

未決定の点

  • Issue の対処の方向 3(CI で TIOCSTI の UNVERIFIED を失敗にするか)は、この PR には入れていません。
  • この PR の CI で sysctl が効くか(runner の kernel が書けるか)を確かめた後、PM・利用者が決めます。

🤖 Generated with Claude Code

Set dev.tty.legacy_tiocsti=1 before the acceptance suite in the
commandagent-guardrails job, logging the outcome and never failing the
job when the kernel refuses the write, and print the resulting value.
Pass $RUNNER_TEMP/probe-verdicts.txt to the test step through
COMMANDAGENT_PROBE_VERDICT_FILE, and add an if: always() step that cats
the file and turns every UNVERIFIED line into a ::warning:: annotation
(a missing or empty file also warns). The four issue667 probes append one
verdict line each - BLOCKED or UNVERIFIED with the reason, plus the
legacy_tiocsti value for TIOCSTI - so the verdict reaches the job log and
the check-runs annotations; the existing stdout and $GITHUB_STEP_SUMMARY
output is unchanged, and an unset variable keeps the previous local
behaviour.

判断: the verdict line reuses the $GITHUB_STEP_SUMMARY format
  (issue667/<probe>: blocked|unverified ...), so the reporting step
  matches UNVERIFIED case-insensitively
判断: scripts/ci.sh needs no change; the workflow passes the target file
  through the test step's env
本文に無い指摘: a code reading (not measured locally - the two-point
  measurement is the leader's Docker run) says removing setsid() alone
  still leaves the /dev/null stdin detachment, which blocks TIOCSTI on
  fd 0, so a copy with only setsid() removed keeps reporting BLOCKED

Co-authored-by: CommandCodeBot <noreply@commandcode.ai>
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