From 6434df13aa9596bf2e27f1c03760546bc33c8f68 Mon Sep 17 00:00:00 2001 From: Hare Date: Sun, 21 Jun 2026 16:15:36 +0900 Subject: [PATCH] ticket: plugin request/ws support --- .yoi/tickets/00001KVMG8FTW/artifacts/.gitkeep | 0 .yoi/tickets/00001KVMG8FTW/item.md | 141 ++++++++++++++++++ .yoi/tickets/00001KVMG8FTW/thread.md | 7 + .yoi/tickets/00001KVMGAEJN/artifacts/.gitkeep | 0 .yoi/tickets/00001KVMGAEJN/item.md | 138 +++++++++++++++++ .yoi/tickets/00001KVMGAEJN/thread.md | 23 +++ 6 files changed, 309 insertions(+) create mode 100644 .yoi/tickets/00001KVMG8FTW/artifacts/.gitkeep create mode 100644 .yoi/tickets/00001KVMG8FTW/item.md create mode 100644 .yoi/tickets/00001KVMG8FTW/thread.md create mode 100644 .yoi/tickets/00001KVMGAEJN/artifacts/.gitkeep create mode 100644 .yoi/tickets/00001KVMGAEJN/item.md create mode 100644 .yoi/tickets/00001KVMGAEJN/thread.md diff --git a/.yoi/tickets/00001KVMG8FTW/artifacts/.gitkeep b/.yoi/tickets/00001KVMG8FTW/artifacts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.yoi/tickets/00001KVMG8FTW/item.md b/.yoi/tickets/00001KVMG8FTW/item.md new file mode 100644 index 00000000..93b03173 --- /dev/null +++ b/.yoi/tickets/00001KVMG8FTW/item.md @@ -0,0 +1,141 @@ +--- +title: 'Plugin: host_api.https を廃止して URL 権限ベースの host_api.request に統合する' +state: 'ready' +created_at: '2026-06-21T07:10:30Z' +updated_at: '2026-06-21T07:10:30Z' +assignee: null +readiness: 'implementation_ready' +risk_flags: ['plugin', 'host-api', 'public-api', 'permissions', 'security', 'local-network', 'breaking-change'] +--- + +## User claims / request snapshot + +- 現行 `host_api.https` は localhost/private address を拒否するため、Plugin とローカル外部プロセスの通信に合わない。 +- `host_api.https` は廃止し、one-shot request/response 型通信は `host_api.request` に統合する。 +- WebSocket は `request` に混ぜず、別 capability として扱う。 +- 対象 host / URL は Plugin 側が権限として要求する前提にする。 +- 任意 URL access は便利だが大きすぎる権限であり、導入時に「何が可能になる権限を要求しているか」がわかりやすいことを優先する。 +- Regex を許してもよいが、permission review の可読性を壊さないことが重要。 + +## Confirmed facts / sources + +- `docs/development/plugin-development.md` は `https` host API を outbound-only / grant-gated とし、WebSocket/Gateway/inbound HTTP surface ではないと説明している。 +- 同 docs は manifest permission `host_api.https` と enablement grant `grants.https` による host/method/path allowlist を説明している。 +- 同 docs は `http://`, localhost/private/link-local targets, disallowed hosts/methods, oversize requests/responses, missing grants を reject すると説明している。 +- `crates/manifest/src/plugin.rs` には `PluginGrantConfig.https`, `PluginHttpsGrant`, `PluginHostApi::Https` がある。 +- `crates/pod/src/feature/plugin.rs` の `validate_plugin_https_request` は URL scheme を `https` に限定し、static HTTPS target validation と allowlist authorization を行っている。 +- Closed Ticket `00001KVFDX9AF` は localhost/private/link-local rejection と WebSocket/SSE non-goals を含む HTTPS host API 実装だった。 +- Closed Ticket `00001KVJHYP4Q` は Plugin Service/Ingress lifecycle 基盤を入れたが、実外部 socket/event source は scope 外だった。 + +## Unverified hypotheses + +- 初期 schema は named request permission として `id`, `schemes`, `hosts`, `ports`, `methods`, `path_prefixes` を持たせると、導入時表示と runtime authorization の両方を扱いやすい。 +- Arbitrary URL access は `broad = "any_url"` のような明示的な broad permission として扱うと、人間がレビューしやすい。 +- Regex は初期 non-goal でもよい。入れる場合も opaque regex ではなく、normalized display / warning / label を伴う必要がある。 + +## Undecided points / open questions + +- 最終的な TOML/Rust 型名は実装時に決めてよい。 +- Regex support を初回に含めるかは実装裁量。ただし、入れる場合は導入時に可能範囲が読める表示と broad/opaque pattern の診断が必要。 +- Private LAN targets を loopback targets と同じ category にするか、より大きい broad/local-network permission として表示するかは実装時に整理してよい。 + +## Background + +現行 `host_api.https` は public outbound HTTPS API 用の安全な最小能力として実装された。一方で、Plugin と local bridge process / 外部プロセスを連携させる用途では、`https` 固定・localhost/private 拒否・WebSocket 非対応という名前と境界が合わない。 + +この Ticket では、one-shot request/response 型通信を `host_api.request` に統合し、Plugin package manifest が必要な target URL 権限を静的に要求し、workspace/user enablement grant がそれを明示承認する model に変更する。WebSocket / persistent streaming / bidirectional connection は別 Ticket の対象であり、`request` に混ぜない。 + +## Requirements + +- `host_api.https` naming/API を廃止し、one-shot request/response 型通信を `host_api.request` に統合する。 +- Active public/model/config-facing API から `host_api.https`, `PluginHttps*`, `grants.https` naming を除去し、`request` naming に統一する。 +- `PluginPackageManifest` 側に、Plugin が必要とする request target permissions を静的に宣言できる schema を追加する。 +- `PluginEnablementConfig.grants` 側に、manifest-declared request target permission を実際に許可する grant schema を追加する。 +- Runtime authorization は、原則として「Plugin が manifest で要求した request target」かつ「enablement grant で承認された request target」だけを許可する。 +- `request` target permission は URL を前提にし、少なくとも scheme, host, optional port, method, path prefix を人間が読める形で表現できること。 +- 任意 URL / broad network access は許可可能にしてもよいが、通常 host grant と区別して「大きい権限」として導入時に明示する。 +- localhost/loopback/private/local targets を許す場合も ambient に開けず、manifest-declared URL permission と enablement grant の両方がある場合だけ許可する。 +- `request` は WebSocket, persistent streaming, background event handling, Service lifecycle を含めない。 +- Embedded credentials, credential-like headers, oversize request/response, missing grants, untrusted external content handling などの既存 safety は維持する。 +- Manifest resolution / `yoi plugin show` / diagnostics で以下を区別して表示する: + - Plugin が要求している request permissions; + - workspace/user が grant している request permissions; + - requested だが未 grant のため拒否された request permissions; + - arbitrary URL / broad network access 相当の request permissions。 +- 不要な backward compatibility alias は追加しない。必要になった場合は escalation する。 + +## Acceptance criteria + +- `host_api.https` / `PluginHttps*` / `grants.https` naming が active API から消え、`host_api.request` / request grant naming に統一される。 +- Plugin manifest だけを見れば、その Plugin がどの URL/request target 権限を要求しているか分かる。 +- `yoi plugin show` 相当の inspection で request 権限要求と grant 状態が bounded / human-readable に表示される。 +- Enablement grant が manifest-declared request target と照合される。 +- Manifest で要求されていない target への request は、grant だけがあっても原則 fail closed する、または明示 override として安全に診断される。 +- Grant されていない requested target への runtime request は fail closed する。 +- 既存の HTTPS request use case は `host_api.request` として動く。 +- `http://localhost` / loopback request は、manifest-declared URL permission と enablement grant がある場合だけ許可される。 +- Arbitrary URL / broad access は通常 host grant と区別して表示・診断される。 +- Regex を入れる場合、broad/opaque pattern を review で見落とさない表示・テストがある。 +- WebSocket URL / upgrade / persistent stream は `request` では拒否または非対応として明示される。 +- Docs / templates / tests / diagnostics が `host_api.request` と WebSocket 別サポート方針に更新される。 + +## Binding decisions / invariants + +- `host_api.https` は残さない。 +- `request` は one-shot request/response 用であり、WebSocket / SSE / persistent connection を含めない。 +- Request authority は URL permission を前提にする。 +- Plugin 側が対象 URL/host scope を権限として要求し、user/workspace enablement がそれを承認する二段階 model にする。 +- 任意 URL access は大きい権限として明示されなければならない。 +- Local/private communication is not ambient; it requires explicit manifest declaration and explicit grant. +- Hidden context injection はしない。 +- External content is untrusted and bounded. +- Backward compatibility alias は追加しない unless explicitly reapproved. + +## Implementation latitude + +- Type names are free to choose, but model-facing/config-facing names should be `request`. +- Internal implementation may reuse existing HTTPS request code paths after renaming/refactoring. +- Request permission schema は exact host / scheme / port / method / path prefix を基本にしてよい。 +- Regex support は入れても入れなくてもよいが、入れる場合は permission review の可読性を守ること。 +- Private LAN target は loopback より広い権限として表示してよい。 +- `yoi plugin show` の表示形式は実装裁量だが、requested/granted/denied/broad の区別は維持する。 + +## Readiness + +- readiness: implementation_ready +- risk_flags: [plugin, host-api, public-api, permissions, security, local-network, breaking-change] + +## Escalation conditions + +- `request` に WebSocket / SSE / daemon lifecycle を混ぜたくなる場合。 +- Local/private target policy が manifest declaration + grant model なしに広がる場合。 +- 任意 URL access が通常権限として目立たなくなる場合。 +- Secret-bearing headers/env/config を guest memory から直接渡す設計になりそうな場合。 +- Compatibility alias を追加したくなる場合。 +- Regex が導入時 review で理解不能な opaque permission になりそうな場合。 + +## Validation + +- Focused plugin host API tests. +- Manifest-declared request permission parsing/resolution tests. +- Grant allow/deny tests. +- Requested-but-ungranted and granted-but-unrequested denial tests. +- Loopback/local target allow/deny tests. +- Broad/arbitrary URL display/diagnostic tests. +- Docs/template updates. +- `cargo fmt --check` +- relevant `cargo test` +- `cargo check` +- `git diff --check` + +## Related work + +- `00001KVFDX9AF` — Plugin HTTPS host API, closed. +- `00001KVJHYP4Q` — Plugin Service/Ingress component lifecycle surface, closed. +- `00001KSXRQ4G8` — Plugin runtime/surface/host API design record, closed/superseded. +- `docs/development/plugin-development.md` +- `docs/design/plugin-component-model.md` +- `docs/design/plugin-packages.md` +- `crates/manifest/src/plugin.rs` +- `crates/pod/src/feature/plugin.rs` +- `crates/yoi/src/plugin_cli.rs` diff --git a/.yoi/tickets/00001KVMG8FTW/thread.md b/.yoi/tickets/00001KVMG8FTW/thread.md new file mode 100644 index 00000000..b2f05bc1 --- /dev/null +++ b/.yoi/tickets/00001KVMG8FTW/thread.md @@ -0,0 +1,7 @@ + + +## 作成 + +LocalTicketBackend によって作成されました。 + +--- diff --git a/.yoi/tickets/00001KVMGAEJN/artifacts/.gitkeep b/.yoi/tickets/00001KVMGAEJN/artifacts/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.yoi/tickets/00001KVMGAEJN/item.md b/.yoi/tickets/00001KVMGAEJN/item.md new file mode 100644 index 00000000..6a0564f7 --- /dev/null +++ b/.yoi/tickets/00001KVMGAEJN/item.md @@ -0,0 +1,138 @@ +--- +title: 'Plugin: URL 権限ベースの別 capability として WebSocket support を設計する' +state: 'ready' +created_at: '2026-06-21T07:11:34Z' +updated_at: '2026-06-21T07:14:05Z' +assignee: null +readiness: 'requirements_sync_needed' +risk_flags: ['plugin', 'host-api', 'websocket', 'service', 'ingress', 'lifecycle', 'permissions', 'security', 'persistence'] +--- + +## User claims / request snapshot + +- WebSocket / bidirectional communication は `host_api.request` に混ぜず、別 capability としてサポートする。 +- WebSocket も、対象 URL を Plugin 側が権限として要求する前提でよい。 +- 任意 URL access は便利だが大きすぎる権限であり、導入時に何が可能になる権限を要求しているかがわかりやすいことを重視する。 +- Regex を許す余地はあるが、本来の権限ニーズは permission review の可読性にある。 + +## Confirmed facts / sources + +- `docs/development/plugin-development.md` は現行 `https` host API を outbound-only / grant-gated とし、WebSocket/Gateway/inbound HTTP surface ではないと説明している。 +- Closed Ticket `00001KVFDX9AF` は WebSocket / SSE / timer host APIs, Service surface lifecycle, Ingress surface, Discord Gateway bridge, Inbound HTTP server を non-goals として HTTPS host API を実装した。 +- Closed Ticket `00001KVJHYP4Q` は Plugin Service/Ingress component lifecycle surface を実装し、PluginInstance lifecycle と in-process ingress dispatch path の基盤を入れたが、実外部 socket/event source は scope 外だった。 +- `docs/design/plugin-component-model.md` / `docs/design/plugin-packages.md` は Plugin instance lifecycle、Service/Ingress、future MCP/plugin bridge、external process authority/lifecycle/permission/diagnostics/trust model の必要性に触れている。 +- 現行 code map では WebSocket 専用 host API / persistent bidirectional Plugin transport はまだ active API として確認できていない。 + +## Unverified hypotheses + +- WebSocket capability は `host_api.websocket` のような host API になるか、Service surface 専用 transport になる可能性がある。 +- Incoming messages は PluginInstance / Service / Ingress lifecycle と接続するのが自然だが、connection ownership と dispatch route は設計判断が必要。 +- URL permission model は `request` と共通概念にできるが、WebSocket は persistent lifecycle / reconnect / shutdown / inbound events を持つため、grant と runtime management は別 schema になる可能性が高い。 + +## Undecided points / open questions + +- WebSocket connection を Yoi host が所有するのか、Plugin instance が host API を通じて所有するのか。 +- Incoming message を Ingress に dispatch するのか、Service event/status stream として扱うのか。 +- Reconnect / backoff / heartbeat / shutdown / cancellation / restore 時の扱いをどこまで初回に含めるか。 +- WebSocket auth/headers/secrets を URL permission とどう分けて表示・grant するか。 +- 初回 work item を design/spec のみで閉じるか、最小実装 slice まで含めるか。 + +## Background + +`host_api.request` は one-shot request/response の authority として設計し、WebSocket / persistent connection / bidirectional event handling を含めない方針になった。一方で、Plugin と外部プロセス・Gateway・bridge service が双方向通信するには、WebSocket 等の persistent transport が必要になる。 + +この Ticket は、WebSocket を `request` とは別 capability として扱い、URL permission を前提にした権限表示・grant・runtime lifecycle・Service/Ingress 接続を設計するための concrete design/spec work item である。実装に進む場合も、Tool call の中に長時間 connection や background daemon を隠さないことを前提にする。 + +## Requirements + +- WebSocket は `host_api.request` に混ぜず、別 capability / host API / transport として設計する。 +- WebSocket も URL permission を前提にし、Plugin package manifest 側が必要な WebSocket URL targets を静的に要求できること。 +- Workspace/user enablement grant は、manifest-declared WebSocket URL permission を明示的に承認する model にすること。 +- Arbitrary WebSocket URL / broad network access は通常 target grant と区別して「大きい権限」として表示・診断すること。 +- Regex を許す場合も、導入時に可能範囲が読める normalized display / warning / label を持つこと。 +- Tool call の中に long-lived WebSocket connection や background daemon を隠さないこと。 +- Service / Ingress / PluginInstance lifecycle との関係を設計すること。 +- Connection ownership, shutdown, cancellation, reconnect/backoff, heartbeat, diagnostics, bounds を設計対象に含めること。 +- Incoming messages が history/model context に入る場合は hidden context injection にせず、durable/visible/routable path を通すこと。 +- Secrets/credentials/auth headers は ambient env ではなく、explicit config / SecretRef / grant model に乗せること。 +- Package discovery / `yoi plugin list/show` は Plugin code 実行、socket connection、external process startup を行わないこと。 + +## Acceptance criteria + +- WebSocket responsibility が `host_api.request` から明確に分離される。 +- WebSocket URL permission の manifest declaration と enablement grant の関係が定義される。 +- Plugin inspection で WebSocket URL permission 要求と grant 状態が bounded / human-readable に表示される設計になる。 +- Arbitrary URL / broad WebSocket access が通常 target grant と区別して表示される。 +- Connection ownership と lifecycle boundary が明確になる。 +- Incoming messages の dispatch path が Service / Ingress / PluginInstance / host routing のどこに属するか決まる。 +- Hidden context injection を避ける durable/visible event path が定義される。 +- Cancellation, shutdown, reconnect/backoff, timeout, message size bounds, diagnostics, redaction の方針が定義される。 +- Auth/secrets handling が explicit config / SecretRef / grant に限定される。 +- 最小実装 slice と non-goals が明確になる。 + +## Binding decisions / invariants + +- WebSocket は `host_api.request` に含めない。 +- WebSocket authority は URL permission を前提にする。 +- Plugin 側が対象 WebSocket URL scope を権限として要求し、user/workspace enablement がそれを承認する二段階 model にする。 +- 任意 URL / broad WebSocket access は大きい権限として明示されなければならない。 +- Long-lived connection を Tool call の中に隠さない。 +- External incoming messages を hidden context injection しない。 +- Package discovery / static inspection は socket connection や process startup を意味しない。 +- External content is untrusted and bounded. + +## Implementation latitude + +- 初回は design/spec Ticket として閉じてもよい。 +- `host_api.websocket` として設計するか、Service surface 専用 transport として設計するかは比較して決めてよい。 +- URL permission expression は `host_api.request` と共通の exact scheme/host/port/path model を流用してもよい。 +- Regex support は入れても入れなくてもよいが、入れる場合は permission review の可読性を守ること。 +- Reconnect/backoff は初回実装 non-goal にしてもよいが、その場合も明示的な failure/diagnostic behavior を定義すること。 + +## Readiness + +- readiness: requirements_sync_needed +- risk_flags: [plugin, host-api, websocket, service, ingress, lifecycle, permissions, security, persistence] + +## Escalation conditions + +- WebSocket を `host_api.request` に混ぜたくなる場合。 +- Connection lifecycle が Tool call / Tool result に隠れそうな場合。 +- Incoming message が history/context に非永続・非可視に注入されそうな場合。 +- URL permission が broad なのに導入時表示で目立たない場合。 +- Secret/auth handling が ambient env や raw config leakage に寄る場合。 +- Restore / cancellation / shutdown / reconnect 方針が決まらないまま実装に進みそうな場合。 + +## Validation + +Design/spec の場合: + +- Docs/design update review. +- Existing Plugin Service/Ingress design との整合性確認。 +- Ticket body の open questions が resolution / follow-up Ticket に変換されていること。 + +実装を含める場合: + +- Focused WebSocket capability tests. +- Manifest-declared WebSocket URL permission parsing/resolution tests. +- Grant allow/deny tests. +- Broad/arbitrary URL display/diagnostic tests. +- Lifecycle shutdown/cancellation tests. +- Message bounds/redaction diagnostics tests. +- No hidden context injection tests. +- `cargo fmt --check` +- relevant `cargo test` +- `cargo check` +- `git diff --check` + +## Related work + +- `00001KVFDX9AF` — Plugin HTTPS host API, closed. +- `00001KVJHYP4Q` — Plugin Service/Ingress component lifecycle surface, closed. +- `00001KSXRQ4G8` — Plugin runtime/surface/host API design record, closed/superseded. +- `00001KVMG8FTW` — Plugin: host_api.https を廃止して URL 権限ベースの host_api.request に統合する。 +- `docs/development/plugin-development.md` +- `docs/design/plugin-component-model.md` +- `docs/design/plugin-packages.md` +- `crates/manifest/src/plugin.rs` +- `crates/pod/src/feature/plugin.rs` diff --git a/.yoi/tickets/00001KVMGAEJN/thread.md b/.yoi/tickets/00001KVMGAEJN/thread.md new file mode 100644 index 00000000..d7224ddb --- /dev/null +++ b/.yoi/tickets/00001KVMGAEJN/thread.md @@ -0,0 +1,23 @@ + + +## 作成 + +LocalTicketBackend によって作成されました。 + +--- + + + +## Intake summary + +ユーザー指示により、この Ticket を Orchestrator が routing できる `ready` 状態にする。readiness は引き続き `requirements_sync_needed` であり、実装直行ではなく WebSocket capability の設計同期・仕様化として扱う。URL 権限を前提にし、`host_api.request` とは分離する binding decisions は Ticket body に記録済み。 + +--- + + + +## State changed + +ユーザーから「readyにして」と明示されたため `planning` から `ready` へ遷移する。未決定点は残っているため、後続 Orchestrator routing では requirements/design sync として扱う。 + +---