feat(herdr): 安全な worktree 作成プラグインを追加 - #73
Merged
Merged
Conversation
Herdr 標準の `herdr worktree create --base <ref>` は ref をローカルで解決するため、 `--base main` は古いままのローカル main を、`--base HEAD` は現在のチェックアウトを 黙って使う。どちらも成功するので、古い base で作ったことに気づくのは PR を出した後 になりやすい。 ローカルプラグイン `dotfiles.safe-worktree` を追加し、この経路を塞ぐ。 - allowlist(`config/repos.json` + マシンローカルの `repos.local.json`)に無い リポジトリでは作成しない - 既定ブランチは毎回 `git ls-remote --symref` で問い合わせ、fetch 後の SHA を base に 渡す(上流の既定ブランチ付け替えに自動追従する) - `HEAD` とローカルブランチ名は base として拒否し、`<remote>/<branch>` と存在確認済み SHA だけを受け付ける - 既存ブランチでの新規作成は拒否し、再利用は `worktree open` に回す。リモートにだけ 同名ブランチがある場合も拒否する - 作成後に実 HEAD と突き合わせてから成功を報告する - `worktree.created` イベントでプラグインを経由しない作成と想定外の base を監査する (記録と通知のみ。削除・自動修復はしない) 配置は Tier 2 の `setup/herdr-sync.zsh` が担当し、`setup/migrate.zsh` の Phase 3 と health check に組み込む。`herdr plugin link` は渡されたパスをそのまま登録先にするため、 link と設定配置は primary チェックアウトから実行したときだけ行う。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
gotomts
force-pushed
the
feat/herdr-safe-worktree-plugin
branch
from
August 28, 2026 06:59
b435519 to
4a9a51a
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
目的
Herdr 標準の
herdr worktree create --base <ref>は<ref>をローカルで解決する。どちらも成功して worktree ができるので、古い base で作ったことに気づくのはだいたい PR を出した後になる。この経路を塞ぐ Herdr ローカルプラグイン
dotfiles.safe-worktreeを追加する。変更概要
プラグイン本体(
herdr/plugins/safe-worktree/)config/repos.json(追跡・公開リポジトリ用)とrepos.local.json(マシンローカル・非公開リポジトリ用)を結合。未登録のリポジトリでは作成しない。突き合わせは scheme / userinfo / port / 末尾.gitを無視したホスト/パスで行い、正規化に失敗した URL は不一致として扱うgit ls-remote --symrefで問い合わせ、fetch 後の SHA を base として渡す。上流が既定ブランチを付け替えても(v2→mainなど)ローカル設定を触らずに追従するHEAD/ ローカルブランチ名 / 相対指定は拒否。<remote>/<branch>と存在確認済み SHA だけを受け付ける--reuseでworktree openに回す。リモートにだけ同名ブランチがある場合は--reuseでも拒否する(base から作ると同名で別履歴が 2 つできるため)。リモートへの問い合わせが失敗した場合は「存在しない」と読み替えず停止するworktree.createdイベントで、プラグインを経由しない作成と想定外の base を記録・通知する。削除・自動修復は一切しない配置(
setup/herdr-sync.zsh, Tier 2)herdr plugin linkでリポジトリの作業ツリーを直接登録し、allowlist の SSOT をプラグイン設定ディレクトリへシンボリックリンクする。setup/migrate.zshの Phase 3 と health check に組み込んだ。パス解決はsetup/lib/herdr.zshに集約し、配置する側と確認する側が同じ関数を引く。herdr plugin linkは渡されたパスをそのまま登録先として保存するため、link と設定配置は primary チェックアウト(~/.dotfiles)から実行したときだけ行う。使い捨ての worktree を登録すると、削除時にプラグイン本体と allowlist の symlink が同時に壊れる。CI
.github/workflows/setup-check.ymlの対象にherdr/**を追加し、プラグインの bats スイートも実行する。検証
bats 184 件 全 pass(プラグイン 66 / herdr-sync 21 / 既存 setup 97、失敗 0)。実
herdrはスタブに差し替え、gitはサンドボックス内の使い捨てリポジトリにのみ実行するmain が同じ workflow に追加した Claude Code hook の unit test(
python3 claude/hooks/destructive-command-guard.test.py、10 件)も rebase 後にローカルで実行し pass を確認実機確認: allowlist 済みの非公開リポジトリに対し、リモート既定ブランチ(
origin/v2)の最新 SHA 起点で linked worktree を作成 → 監査ログplugin_ok(head_sha == expected_sha)、pending マーカー残留 0 を確認。allowlist 外の拒否、base の許可/拒否、linked worktree からの呼び出し、プラグインを経由しない作成の監査もすべて実機で確認済み。検証用に作成した worktree とブランチは削除済みmigrate.zsh --dry-run:herdr-syncのみ[WOULD RUN]、他は全 SKIP を確認独立 read-only レビュー(
dotfiles-swt-review): 最終 finding なしrebase 済み: 公開後に main が 4 commit 進み機械的に競合したため
origin/main(b2c752d)へ rebase した。競合は.github/workflows/setup-check.ymlとAGENTS.mdの 2 ファイルのみで、いずれも main 側の更新と safe-worktree の追記を両方保持する形で解消している。他の 14 ファイルは rebase 前後で blob 一致を確認済み既知の制約
repos.jsonに書かない。 このリポジトリは公開されており、非公開リポジトリ名がそのまま外部に出る。マシンローカルのrepos.local.json(プラグイン設定ディレクトリ配置・追跡外)に書く。リポジトリ内に誤って作られた場合の保険として.gitignoreにも入れてある。追跡されないため別のマシンには複製されないmigrate.zsh --applyは merge 後に primary チェックアウトで実行する。 feature worktree から実行するとherdr-syncが manifest に success として記録され、プラグインの登録先が消える予定のパスに固定されるherdr::plugin_config_dirがherdr plugin config-dirに問い合わせるのは呼び出し元自身のホームを対象にするときだけ。root で走る health check が元ユーザーのホームを検査する経路では既定パスの組み立てを使うため、Herdr がレイアウトを変えても追従しない(変わった場合は health check が先に落ちる)refs/remotes/<remote>/HEADに対して行う。イベントフックでネットワーク I/O をして待たせないため、「最後に fetch した時点のリモート像」に対する判定になる🤖 Generated with Claude Code