← 活動記録一覧

FACTUAL ACTIVITY RECORD · 実際の作業をもとにした活動記録

安全な日常操作を制約付きworkflowへ集約する

反復承認を減らしながら、workspace境界、秘密情報、高リスク操作の停止条件を維持する

対象期間:

目的

workspace内の編集や検証、GitHub上の非破壊的な日常操作でも、必要な安全経路がなければ承認dialogが繰り返されるか、作業が止まっていた。広いcommand許可で解消すると危険な引数まで通るため、通常操作だけを狭いinterfaceへまとめる必要があった。

すべてのcustom roleがworkspace内の通常作業を進められる一方、workspace外write、delete、secret・credential、高リスクなlifecycle操作、deploy、publicationは従来の承認境界へ残すことを目指した。

実装

.codex/config.tomlと9つのcustom role定義をworkspace-writeへ揃え、通常の成果物とtemporary artifactをrepository内へ限定した。systemのtemporary directoryは自動write対象から除外し、workspace外の変更とdeleteは承認対象のままにした。

  • source-control workflow helperはrepository-localなsource-control read、差分、選択pathのstageなどを制約付きsubcommandとして提供する。
  • GitHub workflow helperはcurrent repositoryに限ったTask、Issue・PR read、Issue comment、draft作成、checks、read-only API、本文だけのIssue更新を扱う。
  • workspace validation helperはfile一覧、bounded read、search、syntax・metadata・policy validation、安全なdry-runを一つの入口へ集約する。

.codex/hooks/pre_tool_use_command_policy.pyをPreToolUseへ接続し、review済みのliteral entrypointだけを許すdefault-deny policyを実装した。command substitution、pipe、redirect、compound command、absolute path、./ alias、env、arbitrary interpreter、script-file、unknown executableは実行前に拒否する。

workspaceのreadとsearchでは、path traversal、Git metadata、credential-like name、repository外、symlinkをcase-insensitiveに検査する。directoryやpath省略の再帰searchは、rg --files -0で候補名だけを列挙し、全candidateをcontent access前に検証してから、安全なregular fileだけを一度のcontent searchへ渡す。

  • 複数targetにinvalid pathが混ざる場合は、safe targetの内容も出力せず即時失敗する。
  • 認証preflightはsecretを表示せず、credential stateも変更しないread-only確認へ限定した。
  • 旧い4つの単機能entrypointはwrapperやfallbackとして残さず、3つのcanonical workflowへ責務を移した。

最終確認でIssue本文を更新する安全な入口が不足していることが判明したため、issue-edit-bodyを追加した。digits-onlyの対象番号、current repository、workspace内のnon-empty regular non-symlink body fileだけを受理し、credential-like file、arbitrary repository、unknown argument、title・state・type・parent・closeの変更を拒否するbody-only interfaceにした。

.codex/hooks/pre_tool_use_command_policy.py — default-deny command分類(抜粋)公開境界に合わせた抜粋
ALLOWED_ENTRYPOINTS = frozenset(
    {
        "generated-output cleanup",
        "authentication preflight",
        "local Git workflow",
        "GitHub workflow",
        "post-merge cleanup",
        "workspace workflow",
        "gh",
    }
)
CONTROL_CHARS = frozenset(";&|<>()")


def classify_command(command: Any) -> tuple[bool, str]:
    if not isinstance(command, str) or not command.strip():
        return False, "Bash command must be a non-empty string."
    if "\x00" in command or "\n" in command or "\r" in command:
        return False, "Multiline and NUL-containing Bash commands are not allowed."
shell requestをhookから制約付きworkflowへ送るrouting

図を描画しています…

確認したこと

確認結果

command policy self-testは18の拒否例、8の許可例、3つのhook payloadを検査して通過した。

path policyはregular file、final・intermediate symlink、大小文字のcredential-like pathとGit metadata、valid・invalid混在、recursive safe searchを検査し、restricted candidateのpathとcontentを出力しなかった。

issue-edit-bodyは正常な引数を受理し、非数字の番号、arbitrary repository、unknown argument、workspace外body、credential-like bodyを拒否した。

Bash 6件、Python 1件、JSON 2件、TOML 10件、repository-local Skill 3件の検証が通り、9 roleと12 thread capacityも確認された。

cutoff時点で3つのcanonical workflow、default-deny hook、path policy、role設定、documentationは対象へ反映されていた。project trust設定は確認されたが、記録されたUIではhook activationを直接表示できず、複数sessionでのruntime activationは未確認だった。

完了とした根拠

通常操作のpositive pathと危険・曖昧な入力のnegative pathが検査を通り、途中で見つかったrecursive searchとIssue本文更新の欠落を修正した最終設定が対象へ反映されたことをもって、この安全化の範囲を完了とした。