-
Notifications
You must be signed in to change notification settings - Fork 0
custom rules and autofix
- YAMLを編集できない人 (UXライター・運用担当) が、フォームから禁止ワード・禁止表現を追加できること
- それをセキュアに成立させること
- 検出だけでなく、自動修正のモードを持つこと
辞書は利用者全員の環境で正規表現として実行されます。つまり辞書への書き込みは コード実行に近い権限です。想定する脅威は次の4つです。
| 脅威 | 内容 |
|---|---|
| ReDoS | 破滅的バックトラックを起こす正規表現の混入。CI・フック・エディタが停止する |
| 誤検出爆弾 | 広すぎるパターンの混入で、正当な文書が大量に検出され、ツールが使われなくなる |
| 直列化インジェクション | フォーム入力を文字列連結でYAML化したときの構造破壊 |
| なりすまし・スパム | 誰でも書ける経路を置いた場合の、辞書の汚染 |
[提案層] フォーム GUI (Issue Form / 提案ページ / dead-cliche ui)
↓ 構造化された提案 (リテラル文字列 + why/ask + 例文)
[検証層] スキーマ検証・安全性検査・負例テスト・CI・人間のレビュー
↓ マージ
[辞書層] rules/*.yml (共有辞書) / .deadcliche/custom-rules.yml (プロジェクト辞書)
原則は2つです。
- 信頼できない入力はリテラル文字列 (surface) だけを受け付ける。リテラルはエンジン側で 正規表現エスケープされるため、ReDoSもインジェクションも構造的に起こせない
- 正規表現 (pattern) はレビュー済みの経路だけに通す。フォームからは提案として受け取り、 人間がレビューして初めて辞書に入る
.github/ISSUE_TEMPLATE/propose-rule.yml のフォームで、表現・理由・悪い例・良い例・
負例を構造化して受け付けます。認証はGitHubアカウント、書き込み権限は不要で、
マージまでは辞書に入りません。ホストするサーバーがなく、攻撃面を増やしません。
将来はActionで提案Issueから下書きPRを自動生成します (ロードマップ)。
入力からYAMLスニペットと、上記Issue FormへのプリフィルURLを生成する静的ページです。 バックエンドを持たず、どこにも自動送信しません。生成物を既存のセキュアな経路 (Issue / PR) に運ぶだけなので、設置自体にリスクがありません。
チーム固有の禁止ワードはOSS本体ではなく、各リポジトリの
.deadcliche/custom-rules.yml に置きます。.deadclicherc.json から参照します。
{
"preset": "business",
"customRules": [".deadcliche/custom-rules.yml"]
}- surface (リテラル) は常に許可。フォーム入力をそのまま入れられる安全な形式
- pattern (正規表現) は既定で無効。
"trustCustomPatterns": trueを明示した場合のみ 読み込み、さらに長さ上限とコンパイル検査、量指定子の入れ子の拒否を通す - カスタム辞書はリポジトリにコミットされるため、変更は必ずPRレビューを通る
ローカルUI (dead-cliche ui) は実装済みです。127.0.0.1にだけ束ね、起動時に作る
合言葉をページの取得と保存の両方で要求し、受け取るのはsurface (リテラル) だけです。
Hostヘッダを検査して別名からの到達 (DNSリバインディング) を拒み、Originヘッダが
別サイトのときも拒みます。書き込むのはカスタム辞書ファイルだけで、rules/ には
書きません。保存はjs-yamlのdumpを通し、フォーム入力を文字列連結でYAML化しません。
dead-cliche ui [--port 7777] [--file .deadcliche/custom-rules.yml]
起動すると合言葉付きのURLが表示されます。そのURLでだけ開けます。
- スキーマ検証と重複idの拒否 (実装済み、CI)
- 悪い例が検出され、良い例と負例が検出されないことの強制 (実装済み、CI)
- カスタムパターンの安全性検査 (実装済み): 200文字上限、コンパイル可能、
(a+)+型の量指定子の入れ子をヒューリスティックで拒否 - 静的検査でReDoSを完全には排除できないため、信頼境界を「レビューを通ったか」に 置きます。フォーム入力がレビューなしで実行に到達する経路を作らないことが本体です
クリシェの大半は「情報の欠落」であり、機械置換では直せません (羅針盤 を消しても、
誰が何を判断するのかは書かれないままです)。そこで修正を2層に分けます。
意味を変えずに機械置換できるルールにだけ、辞書に fix フィールドを持たせます。
表記の規範 (して下さい→してください、が失敗しました→に失敗しました、
することができます→できます など) が対象です。
- CLI:
dead-cliche fix <files>は差分の提示のみ (dry-runが既定)。--writeを付けたときだけ書き込む - textlint: fixerとして実装済み。
npx textlint --fixで同じ置換が効く - fixを持つルールはテストで往復検証される (悪い例にfixを適用すると検出0件になる)
fixを持たないルールはask (何を書くべきかの問い) に答える書き直しが必要で、
これはClaude側の役割です。フックが検出時にexit 2で書き直しを要求する現行の
仕組みが、Claude環境ではそのまま自動修正モードとして機能します。全自動にしたい場合は
/dead-cliche:check --fix を使います。書き直し後に再チェックが走り、0件になる
まで収束させます。LLMの書き直しは非決定的なため、CIには第1層だけを載せます。
| フェーズ | 内容 | 状態 |
|---|---|---|
| 1 | custom-rules機構、fixフィールド、Issue Form、提案ページ | 実装済み (v0.7.0) |
| 2 | 提案Issueから下書きPRを生成するAction | 実装済み |
| 3 |
dead-cliche ui (ローカル編集フォーム) |
実装済み |
| 4 | 組織ダッシュボード (検出統計・辞書の採用状況) | 構想のみ |