HN 日本語サマリー

← 一覧へ戻る
プログラミング

Pigeon:サブエージェントができることを署名付きパスで制限

Pigeon, a signed Pass for what a sub-agent may do (github.com)

7 pointsby pigeonlabshq4 コメント

要約

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つの場所を変更します。

  1. 起動 (Spawn): サブエージェントにAPIキーをコピーしていた場所で、delegate(...) を呼び出し、子にPassを渡します。
  2. ツール (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/ (インフラ、データ、コード、そして支払い)