Pigeon:サブエージェントができることを署名付きパスで制限
Pigeon, a signed Pass for what a sub-agent may do (github.com)
要約
Pigeonは、エージェントが生成したサブエージェントに対し、APIキーのコピーではなく、実行可能な操作を限定した署名付き認証情報(パス)を付与するシステムです。これにより、サブエージェントが意図せず機密情報にアクセスしたり、重要な操作を実行したりするリスクを防ぎます。Pythonライブラリとして提供され、エージェントの権限管理を安全かつ細かく制御できます。
全文翻訳
Pigeon: サブエージェントができることのための署名付きパス
エージェントがサブエージェントを起動し、同じAPIキーを渡したとします。そのサブエージェントは、本番環境へのデプロイ、支払いデータベースの読み取り、メインブランチへのマージが可能になります。
Pigeonはそれを阻止します。子に渡すのは、あなたがすべてできることのコピーではなく、Pigeon Pass: 実行できることを限定し、署名された認証情報です。
インストール
Python 3.12 以降が必要です。
git clone https://github.com/pigeonlabsHQ/pigeon.git
cd pigeon
pip install .
全体のアイデアを20行で
from pigeon import grant, verify
authority = grant(
subject="agent:deployer",
capabilities=["deploy"],
resources=["environment:staging"],
)
allowed = verify(authority, action="deploy", resource="environment:staging")
assert allowed.allowed
denied = verify(authority, action="deploy", resource="environment:production")
assert not denied.allowed
assert denied.reason_code == "RESOURCE_NOT_ALLOWED"
print(denied.reason_code, denied.message, denied.details)
verify は常にブーリアン値を返しません。拒否された場合、理由コード、メッセージ、および失敗した比較(requested vs allowed)が含まれます。
自分で書かずに試してみてください。
python examples/01_infrastructure.py
python demo/agent.py
エージェントにおける位置づけ
接続するPigeonサーバーはありません。すでに存在する2つの場所を変更します。
- 起動 (Spawn): サブエージェントにAPIキーをコピーしていた場所で、
delegate(...)を呼び出し、子にPassを渡します。 - ツール (Tool): サイドエフェクトが発生する場所(デプロイ、クエリ、MCPツール)で、
verify(...)を呼び出し、拒否された場合はツールを実行しません。
実際の秘密はランナー(実行環境)に保管します。子はPassを持ち運びます。
from pigeon import delegate, grant, verify, DelegationError
parent = grant(
subject="agent:orchestrator",
capabilities=["deploy", "open_pr"],
resources=["environment:staging", "repo:acme/api"],
constraints={"max_deploys_per_hour": 3},
)
worker = delegate(
parent,
subject="agent:pr-bot",
capabilities=["open_pr"],
resources=["repo:acme/api"],
constraints={"max_deploys_per_hour": 3}, # 親の制約をドロップすることはできない
)
result = verify(worker, action="open_pr", resource="repo:acme/api")
assert result.allowed
denied = verify(worker, action="deploy", resource="environment:staging")
assert denied.reason_code == "CAPABILITY_NOT_GRANTED"
try:
delegate(worker, "agent:rogue", ["open_pr", "deploy"], ["repo:acme/api"])
except DelegationError as exc:
assert exc.reason_code == "PRIVILEGE_ESCALATION"
子は、機能を追加したり、リソースを広げたり、境界を引き上げたり、親の制約をドロップしたりすることはできません。Pigeonが子がより狭い権限であることを証明できない場合、拒否します。
ランナーが verify を呼び出さない場合、Passは装飾に過ぎません。
MCPミドルウェア
これは強制ポイントであり、プロトコルの一部ではありません。クライアントはツール呼び出しごとに、より狭い権限のPassを発行します。サーバーはツールが実行される前にそれを検証します。
from pigeon import grant
from pigeon.integrations.mcp import execute_tool, pass_for_tool
parent = grant(
subject="agent:github",
capabilities=["create_issue", "merge_pr"],
resources=["mcp:github"],
)
tool_pass = pass_for_tool(parent, "create_issue", "mcp:github")
def create_issue(*, title, body):
return {"created": True, "title": title}
ok = execute_tool(tool_pass, "create_issue", "mcp:github",
{"title": "bump deps", "body": "automated"}, create_issue)
assert ok["allowed"]
no = execute_tool(tool_pass, "merge_pr", "mcp:github",
{"title": "nope", "body": "nope"}, create_issue)
assert no["reason_code"] == "CAPABILITY_NOT_GRANTED"
IDはエージェントが誰であるかを示します。権限はそれが何を行えるかを示します。
CLI
pigeon keygen
pigeon inspect pass.json
これは何かではない
Pigeonは小さなプリミティブです。プラットフォーム、ポリシーエンジン、IDプロバイダー、またはキー保管庫ではありません。プロンプトインジェクションを停止しません。Passに設定した次元に沿って、それらの次元のみで、ブラスト半径を制限します。
- プロトコル:
SPEC.md - 制限:
SECURITY.md - その他のスクリプト:
examples/(インフラ、データ、コード、そして支払い)