ワークフロー&基本ツール · daymade/claude-code-skills

repomix-safe-mixer

repomix によるコードベースのパッケージングを安全に行うため、パッケージング前にハードコードされた認証情報を自動で検出および削除します。コードを配布用にパッケージングする場合、リファレンスパッケージを作成する場合、またはユーザーが repomix を使用したコード共有時のセキュリティについて懸念を示した場合に使用します。

L4 高権限 · 段階的認可と監査V1 コミット固定コマンド実行ネットワーク通信ファイル書き込みDual-pass Audit
Author daymadeGitHub daymade/claude-code-skills ↗Stars 1392License MIT(仓库根 LICENSE 文件;GitHub API spdx MIT;Copyright (c) 2025 daymade)Commit d5c4678cb5
管理レベルは Skill の能力と推奨統制措置を示すものであり、品質や安全性の認証、利用可否の判定ではありません。使用の可否はユーザーおよび管理者が決定します。Agent 環境によって制約が異なるため、自動保護を仮定しないでください。第三者製 Skill の著作権は原著作者に帰属し、利用リスクは利用者が負います。

1仕組みと動作原理

オーケストレーション方式は「サブプロセス + JSON 規約」です。safe_pack.py はスキャナーをインポートせず、subprocess を使って同一ディレクトリの scan_secrets.py を --json 付きで呼び出し、その stdout をパースしてパッケージングを行うかを判定します。

repomix-safe-mixer/scripts/safe_pack.py
cmd = [sys.executable, str(scan_script), str(directory), '--json']
ここでの処理内容:2つのスクリプトを「スキャナー(JSON および終了コード規约を持つ純粋関数型 CLI)+ オーケストレーター」に疎結合化しています。これにより、スキャナーを pre-commit やクリーンアップ検証用に単体で再利用可能にしつつ、オーケストレーターがスキャナーの内部実装に依存しないようにしています。

検出機能は 13 項目の正規表現ディクショナリ(SECRET_PATTERNS)に基づいており、すべて行単位の正規表現マッチングです。AST、エントロピー解析、機械学習は使用していません。

repomix-safe-mixer/scripts/scan_secrets.py
'aws_access_key': r'(?i)AKIA[0-9A-Z]{16}', 'aws_secret_key': r'(?i)(?:aws_secret|aws.{0,20}secret).{0,20}[=:]\s*["\']?([0-9a-zA-Z/+=]{40})["\']?', 'supabase_url': r'https://[a-z]{20}\.supabase\.co', 'supabase_anon_key': r'eyJ[A-Za-z0-9_-]*\.eyJ[A-Za-z0-9_-]*\.[A-Za-z0-9_-]*', 'stripe_key': r'(?:sk|pk)_(live|test)_[0-9a-zA-Z]{24,}',
ここでの処理内容:セマンティック解析ではなく正規表現を採用することで、ルールが完全に透明で監査可能、ゼロ依存関係、かつオフラインで動作可能になっています。その代償として「それらしい形状」の認証情報しか認識できません(見落としの範囲については検証の第4項および第6項を参照)。

スキャン対象は「拡張子ホワイトリスト + .env ファイル名の特例」の二重定義で限定されており、コードコメントにはなぜ dotenv に特例を設ける必要があるのか(Path('.env').suffix == '')が明記されています。

repomix-safe-mixer/scripts/scan_secrets.py
# Full filenames that must be scanned regardless of Path.suffix. Dotenv # files break suffix matching: Path('.env').suffix == '' and # Path('.env.local').suffix == '.local', so scanning by extension alone # silently skips the most common places secrets end up. SCANNABLE_FILENAMES = { '.env',
ここでの処理内容:「シークレットが最も存在しやすい場所」(.env 関連)をスキャン対象にハードコードすることで、拡張子のみでスキャンした際に最もチェックすべきファイルを見落とす事態を防いでいます。これは本スクリプトにおいて唯一、反事実的推論の痕跡が見られる設計です。

スキップ対象のディレクトリはハードコードされた集合(node_modules、.git、.venv、dist、build など 15 個)であり、.gitignore のパースは行いません。

repomix-safe-mixer/scripts/scan_secrets.py
SKIP_DIRS = { 'node_modules', '.git', '.venv', 'venv', '__pycache__', 'dist', 'build',
ここでの処理内容:スキャンコストとノイズを抑制しています。その代償として、ignore 対象ディレクトリ内にシークレットが潜んでいても報告されず、また --exclude はこれらデフォルトのスキップ項目に追加することしかできず、除外を解除することはできません。

誤検知の抑制には2つの厳格なルールがあります。プレースホルダー辞書に該当した場合はスキップされ、行全体に対する部分一致判定が行われます(行内の任意の位置に 'example' や 'test-' などの単語が含まれている場合、その行のすべての検出が破棄されます)。

repomix-safe-mixer/scripts/scan_secrets.py
placeholders = [ 'your-', 'example', 'placeholder', 'xxx', 'yyy', 'zzz', 'test-', 'demo-', 'sample-', '<YOUR_', '${', 'TODO' ]
ここでの処理内容:プレースホルダーによる誤検知を低減します。ただし、実装が match 単位ではなく line_lower 単位の判定であるため、1行の中に本物のシークレットと 'example' という単語が混在していると行全体が見逃されることになり、抑制範囲が SKILL.md に記載された「test/example/sample ファイルのスキップ」よりも広範になっています。

コメント行は一律スキップされます(行頭が //、#、/*、*)。

repomix-safe-mixer/scripts/scan_secrets.py
if re.search(r'^\s*(?://|#|/\*|\*)', line):
ここでの処理内容:コメント内の記述はサンプルであると仮定しています。副作用として、コメントアウトされた本物の認証情報(デバッグ時の残留物に多く見られる)はレポートに出力されません。

デフォルトはフェイルクローズ(fail-closed)です。シークレットを検出するとパッケージングを拒否して exit 1 で終了し、明示的に --force が渡された場合のみ続行します。--force ルートでも警告を出力します。

repomix-safe-mixer/scripts/safe_pack.py
print("❌ Cannot pack: Secrets detected!")
ここでの処理内容:「セキュリティスキャン」を単なる推奨事項からブロッキングゲートへと格上げしています。SKILL.md のコミットメントである「3. Blocks packaging if secrets found(シークレット検出時にパッケージングをブロック)」はコードの実装と一致しています(唯一の例外は --force および後述する空の stdout による失敗ルートです)。

パッケージング処理は外部 CLI である repomix の呼び出しによって行われます。対象ディレクトリを cwd とし、--config/--output を透過的に渡し、成果物は repomix がディスクに書き込みます。

repomix-safe-mixer/scripts/safe_pack.py
result = subprocess.run(cmd, cwd=directory, capture_output=True, text=True)
ここでの処理内容:本スキル自体はパッケージングを実装せず、「スキャンしてからパッケージング」という順序のオーケストレーションのみを行います。repomix は argv リスト形式(shell=True なし)で呼び出されるため、ディレクトリパスがコマンドインジェクションにつながることはありません。

レポートは検出されたシークレットの抜粋と該当行のコンテキストを stdout に出力します(--json では match が 50 文字、context が 100 文字に切り詰められ、人間向けのレポートでは match/context の先頭 80 文字が出力されます)。スクリプト自体はファイルを一切書き込みません。

repomix-safe-mixer/scripts/scan_secrets.py
print(f" Match: {finding.matched_text[:80]}") print(f" Context: {finding.line_content[:80]}")
ここでの処理内容:ユーザーが具体的なファイルと行番号を特定できるようにしています。副作用として、シークレットの平文抜粋がターミナル出力に含まれることになります。エージェントセッション内ではこれらの出力がモデルのコンテキストや会話ログに入り込むため、「外部送信はされないがサイレントでもない」という中間状態になります。

終了コードがそのままインターフェースとなります。検出時は 1、クリーン時は 0 を返し、SKILL.md ではこれを pre-commit フック(コミットの阻止)として利用することを明示しています。

repomix-safe-mixer/scripts/scan_secrets.py
sys.exit(1 if findings else 0)
ここでの処理内容:スキャナーを CI や git フックに組み込めるようにしています。ただし、safe_pack.py がスキャナーを呼び出す際は戻り値を検査せず、stdout が JSON としてパースできるかのみを見ている点に注意が必要です(検証の第3項にあるフェイルオープンのリスクを参照)。

2コア機能

01パッケージング前のシークレットスキャン:12 カテゴリのルールによる認証情報の検出(AWS アクセスキー/シークレット、Supabase URL および anon key/JWT、Stripe、Cloudflare トークン、R2 アカウント ID、Turnstile、OAuth シークレット、秘密鍵ブロック、汎用 API キー)
02シークレット検出時のパッケージング阻止(フェイルクローズ、終了コード 1)および修復ステップ一覧の提示
03制御されたオーバーライド:--force によるブロックのスキップ(警告は継続表示、ドキュメント上で NOT RECOMMENDED と明記)
04独立したスキャナー用途:クリーンアップ後の再検証、pre-commit フック、既存コードの監査(プログラム連携用の --json)
05タイプ別にグループ化された検出レポート(同一カテゴリは上位3件のみ表示し、残りは件数で折りたたみ)
06repomix パッケージングのオーケストレーション:--config / --output を透過して対象ディレクトリ内で実行
07誤検知の抑制:プレースホルダー辞書、コメント行、サンプル/テストファイル(--exclude による追加指定)
08認証情報の修復プラクティスおよび漏洩後の対処フロー(環境変数への置換 → .env.example → 再検証 → パッケージング、漏洩後の rotate/revoke/audit/monitor)

3外部依存関係

KindDependency / Endpoint
clirepomix(第三方打包 CLI,需用户自行预装)
clipython3(sys.executable 拉起同目录扫描器;仅标准库 os/re/sys/json/subprocess/pathlib)
packagerepomix(npm 生态包,本 skill 只调用命令,不负责安装)

4推奨統制措置と判定根拠

安全運用のための推奨統制措置
Agent 向け
段階的・都度認可、サンドボックス推奨
管理者向け
承認フロー、ロールバック可能、全履歴監査
判定根拠(ファイルパスと抜粋)
  • scripts/: ローカルスクリプトまたはコマンドの実行: python3 scripts/safe_pack.py <directory> [--output file.xml] [--config repo
  • 环境变量 / API Key: ベンダーサービス認証情報の読み取り: 設計通り、正規表現マッチングのために対象ディレクトリ内のファイルテキスト(.env/.env.example/.env.local/.env.production/.env.de を含む)を読み取ります
  • 本地工作目录: ファイルの読み書きと成果物出力: 両スクリプト自体によるファイル書き込みはゼロ(open(...,'w') なし、一時ファイルなし、ログファイルなし)
監査ノート: 動作プロファイル:2つの標準ライブラリ製ローカルスクリプトであり、ネットワーク呼び出しはゼロ(requests/urllib/socket/http/curl/wget は不使用、SKILL.md 内の https:// はすべてプレースホルダーまたは参考用外部リンク)、外部への認証情報送信もゼロです。対象ディレクトリ内のファイル(.env 関連を含む)の読み取りはスキャン機能の前提条件であり、マッチした結果は標準出力に表示されるのみでディスクには保存されません。ローカル CLI のみを呼び出します(repomix は事前インストールが必要なサードパーティ製 npm コマンドであり、argv リスト形式で呼び出されるためシェルインジェクションの余地はありません)。留意事項:①検出された抜粋および該当行の原文が stdout にエコーバックされるため、エージェントセッション内ではモデルのコンテキストや会話履歴に入り込みます。これにより、信頼できないリポジトリにおいてレポートテキストを介したインジェクションと認証情報抜粋のログ残留という2つの懸念が生じます。②オーケストレーターはスキャナーのサブプロセス終了コードを検査しておらず、stdout が空の場合はフェイルオープンとなってそのままパッケージングを実行してしまいます。これは SKILL.md の「Blocks packaging if secrets found(シークレット検出時にパッケージングをブロック)」という強いコミットメントに対して実装上の乖離があるため、CI では終了コードも併せて検証するように変更することを推奨します。

5二重目の独立検証

  • [ok] 外部依赖调用点反查(repomix / python3) — 全目录 grep subprocess 仅 3 处命中:safe_pack.py 的 import、L24 subprocess.run(调 scan_secrets.py,cmd 来自 cmd = [sys.executable, str(scan_script), …])、L74 subprocess.run(cmd, cwd=directory)(cmd 起点为 cmd = ['repomix'])。两个依赖条目均有真实调用点,无第三处。
  • [ok] 网络外发反例查找 — grep requests|urllib|urlopen|socket|http|curl|wget 在两个脚本内零命中;SKILL.md 与 common_secrets.md 中的 https:// 全部是占位符(https://your-project-ref.supabase.co)、示例域名(.r2.cloudflarestorage.com 出现在正则 lookahead 文本中)或文档外链。无 DNS/HTTP 客户端、无遥测、无任何外发路径。
  • [discrepancy] 扫描器返回码未被校验 → fail-open 反例 — run_secret_scan 只做 result = subprocess.run(...);随后 findings = json.loads(result.stdout) if result.stdout.strip() else [],从不检查 result.returncode。若扫描器因解释器缺失/脚本损坏/进程被杀而 stdout 为空,findings 被判为空列表,main 直接进入 '📦 Packing … with repomix' 分支——即『扫描失败』被当成『无密钥』。这与 SKILL.md『3. Blocks packaging if secrets found』的强承诺存在实现缺口:只承诺了『发现密钥时阻断』,未覆盖『扫描本身失败』。
  • [discrepancy] SKILL.md 检测类型清单 vs SECRET_PATTERNS 实际键 — SKILL.md 列出 11 类(AWS Access Keys、R2 Account IDs/Access Keys、Supabase URL/Anon Keys、Stripe、OpenAI sk-、Google Gemini AIza、Generic API Keys、JWT、OAuth Client Secrets、Private Keys、Turnstile)。代码 SECRET_PATTERNS 实为 12 个键,但其中:无 R2 Access Keys 专用规则;无 Google Gemini(AIza…)规则(全目录 grep 'AIza' 零命中);OpenAI sk- 仅在同时出现 api_key/apikey 字样时可被 generic_api_key 捕获,stripe_key 只认 sk_live/sk_test 形式,因此裸的 sk-proj-… 赋值不一定会命中。文档检测类型清单宽于代码能力。
  • [discrepancy] 假阳性抑制范围 vs 文档描述 — SKILL.md『Common False Positives』写的是跳过占位符、『Files matching .*test.*, .*example.*, .*sample.*』的文件与注释行。should_skip_match 实际对整行做 substring 包含判断(placeholder in line_lower),且注释判定用 ^\s*(?://|#|/\*|\*)——即抑制粒度是『行』而非『match』或『文件』:真密钥与 'example' 同行即被放过,被注释掉的真实凭证亦不上报。代码抑制面大于文档描述,属漏报向的偏差。
  • [discrepancy] 扫描面缺口:不在白名单的高风险文件类型 — SCANNABLE_EXTENSIONS 只含 .ts/.tsx/.js/.jsx/.py/.md/.json/.yaml/.yml/.sh/.bash/.zsh/.sql/.go/.java/.rb/.php/.cs,SCANNABLE_FILENAMES 只补 7 个 dotenv 名。因此 *.pem、*.key、id_rsa、*.ppk、*.p12、*.crt、.envrc、*.toml/*.ini/*.conf/*.properties/*.xml 都不被扫描——private_key 规则(-----BEGIN … PRIVATE KEY-----)写好了却基本没有机会命中这些最常见的私钥载体。SKILL.md 未提示该覆盖边界(仅笼统说 may not catch all credential types)。
  • [discrepancy] --force 语义与文档措辞一致性 — SKILL.md 标题写『**Force pack (dangerous, skip scan)**』,暗示跳过扫描;safe_pack.py 中 force = '--force' in sys.argv 之后仍照常执行 run_secret_scan 与 print_findings_report,只是跳过阻断并打印『WARNING: --force flag set, packing anyway despite secrets found!』。实际语义是『扫描照做、仅放行』,措辞『skip scan』不准确。
  • [ok] 证据是否指向被扫文件内容/是否落盘 — 两脚本无 open(...,'w')、无 tempfile、无日志写入;匹配结果只经 print/ json.dumps 到 stdout(scan_secrets 的 to_dict 将 match 截断 50、context 截断 100;人类可读报告打印前 80 字符)。『不落盘、不外发』成立;但『不进日志』不成立——终端输出在 agent 会话中会被留存为上下文。

6結論

  • デフォルトでフェイルクローズとなる強制順序により、セキュリティ検証を単なる推奨ではなく必須ゲートとして機能させる点
  • ルールセットが透明で依存関係がなく、オフラインで監査可能かつ CI に直接組み込める点
  • 能力の境界を誠実に自己開示しており、完全なセキュリティ監査であるかのように偽らない点
  • 付属のリファレンスドキュメントにより、「問題の発見」から「問題の修復」までが接続されている点
  • 最適な用途: 最適な用途:ローカルコードベースを repomix でパッケージングして外部共有する直前の最終自己チェック。CI や pre-commit において、依存関係なしで終了コードを判定基準にできるシークレットスキャンを追加したい場合。自身の技術スタックに合わせて検出項目を拡張するため(AIza や .pem ルールの追加など)、可読・変更可能な正規表現ルールテーブルが必要な場合。典型的な使い方は、CI 内で `scan_secrets.py . --json` を実行してコミットをブロックし、共有前に `safe_pack.py <dir>` を実行して「スキャンを通過した場合のみパッケージング」を行う運用です。
    不向きな用途: 不向きな用途:セキュリティの担保を本ツールに一任するシナリオ。本ツールは完全なシークレットスキャンではなくパターンマッチングに依存しており、明確な検知漏れ領域が存在するため、gitleaks、trufflehog、CI プラットフォームのシークレットスキャン、git 履歴の消去を代替することはできません(SKILL.md 自体も同様に表明しています)。秘密鍵ファイルを主体とするリポジトリのスキャン(*.pem/id_rsa はスキャン対象外)。信頼できないリポジトリに対してエージェントセッション内で直接実行する用途(レポートによりリポジトリのテキストがコンテキストにエコーバックされます)。「認証情報の自動削除」を期待するシナリオ(公式の説明にある「removing hardcoded credentials」は実際にはレポートに基づく手動修正を指しており、スクリプト自体は検出とブロックのみを行います)。
    Install Agent-Ready
    ① Verified Mirror 2026-09-15
    Option A · Direct DownloadDownload repomix-safe-mixer.tar.gz
    sha256: 7847e6113e529f6b…
    Option B · Copy Guide for Agent
    install.json
    Agent はこの JSON ガイドから自動的にダウンロードして検証します。
    ② Upstream GitHub
    GitHub Repo ↗
    Pinned to commit d5c4678cb5.