Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/requirements/ssh-test.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Test-only in-memory SSH server; never a runtime or build dependency.
paramiko==4.0.0
3 changes: 3 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ jobs:
python-version: ${{ matrix.python }}
- name: Install pinned test-only source verification dependency
run: python -m pip install --requirement .github/requirements/test.txt
- name: Install optional native SSH handshake fixture
if: matrix.os != 'windows-latest' && matrix.python == '3.13'
run: python -m pip install --requirement .github/requirements/ssh-test.txt
- name: Compile
run: python -m compileall -q cc_peer.py session_peer.py tests
- name: Generated standalone is current
Expand Down
42 changes: 42 additions & 0 deletions docs/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -956,3 +956,45 @@ list/send/wake/wait/ack support; it does not grant permission or prove readiness
SSH validates the final shell-quoted remote command as UTF-8 bytes before starting any SSH subprocess. The conservative limit is 131071 bytes, including base64 message expansion, envelope, options and quoting. Oversized commands fail locally with `ssh_command_too_large` and `submitted: false`; character-count validation alone is insufficient for Unicode. Local delivery limits are unchanged. This per-command guard cannot guarantee that every remote operating system has enough total environment/argument space.

At native delivery, session-peer quotes every peer-body line and marks sender/session claims and reply routes as unverified. Codex and Antigravity also receive an explicit warning that peer text is not user permission; Claude Code already provides that warning, so it is not repeated. The `--no-from` and `--no-reply-to` options suppress sender metadata, not this receiving-side frame. Reply-To remains inert routing data: verify the surrounding frame and confirm a third-party destination with the session owner before replying. Framing reduces ambiguity, not all prompt injection. The frame and escaped control characters count toward message limits; `chars` describes the delivered framed text. Submission and consumption/ACK meanings do not change.

## Connection-bound SSH key identity (development)

The opt-in `--ssh-identity` flag reports `sshIdentity` for `list`, `send`,
and `doctor --host`. Only the fingerprint and key algorithm come from the
actual OpenSSH host-key callback followed by a complete validated remote result.
The destination, port and key-lookup name are **preflight SSH configuration**,
not independent proof of the final network endpoint. An offered key without a
completed remote result is only `observed`, not `verified`.

```sh
session-peer list --host workstation --ssh-identity --json
session-peer send --host workstation --to reviewer --message="Review this change" \
--require-ssh-host-key 'SHA256:<previously-verified-fingerprint>' --json
```

Copy the verified fingerprint from discovery; the placeholder above is not a
valid key. The pin is checked on the **send connection**, before authentication
and remote execution, rather than by a separate probe. A changed key is refused;
key rotation requires explicit verification and a new pin. Connection reuse is
disabled in this mode and strict host-key verification stays enabled. In report
mode the user's known-hosts trust is retained; pin mode trusts only the supplied
public-key fingerprint for that connection and writes no known-hosts entry.
A server key can be reused by multiple hosts, so it is not a unique machine,
account, session-generation or message-consumption identity.

This development path is POSIX-only and supports ordinary Ed25519, RSA and
ECDSA keys, not host certificates or security-key algorithms. It refuses a
user-configured `KnownHostsCommand` instead of silently replacing that trust
policy. Existing SSH configuration and jump-host trust remain operator-owned.
The optional second installed-version probe is omitted for identity-mode
listing because its separate connection is not covered by the receipt. Missing
receipt after a complete native response preserves that submission evidence,
never permits automatic retry, and cannot satisfy a required key pin.

Default output and SSH behavior are unchanged without opt-in. These options
are not part of published v1.0.4. Local tests cover the native callback helper,
read-only configuration, fake transports and actual OpenSSH handshakes against
an owned loopback fixture. A mismatched key caused zero authentication and
remote-exec requests. Fixture host private keys remain in memory, never files.
This is not a real remote-host or live-agent acceptance test; platform CI must
also pass.
2 changes: 1 addition & 1 deletion docs/i18n-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
"docs/ai-assistant-guide.md": "9624ec96b92fb688fae3be3c94cb3564c77985091be451fbf1f056a1af9b9d9c",
"docs/antigravity.md": "f2b5122a0ce6e6fb5bd4d8ed50ce2c8bd2dc9c98ec8ce328405cf7c2cd24229d",
"docs/architecture/agent-transports.md": "01a4e3942e87acb476595859f2e37f9653ea1e3bc19ebc68dced1adf20a6966f",
"docs/cli-reference.md": "3a366585e7ef093f79fc7e83c843ce9b291731fa4c0055348b92bcc2a2765cd7",
"docs/cli-reference.md": "7fbc82834883a13e91f3a31b058296eefca7117bd7dd08409e44faccc82e1f03",
"docs/compatibility-v1.md": "7e551aad37a369faff7e370728376763efb54c2c9e9cfd8556a0c19aabc3d103",
"docs/contracts/handoff-v1.md": "46a953010c49214bd8f969412f26713384fbe09a0ba78ebf0fef75da40d0d889",
"docs/diagnostics.md": "0949e53612eeab2cd7c7bbda498e14d71e9cb1b1189aa7722030cb8702cd8481",
Expand Down
36 changes: 36 additions & 0 deletions docs/ja/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -928,3 +928,39 @@ list/send/wake/wait/ack サポートを記述します。権限を付与した
SSHは起動前に最終的なshell引用済みコマンドのUTF-8バイト数を検証します。上限131071バイトにはbase64展開、envelope、option、引用が含まれます。超過はローカルで `ssh_command_too_large` と `submitted: false` を返します。Unicodeには文字数だけでは不十分です。ローカル送信制限は不変で、全OSの引数・環境合計容量を保証するものではありません。

ネイティブ配送時、session-peer は相手の本文の全行を引用し、送信セッションと返信先を未検証の申告として示します。Codex と Antigravity には、相手の本文はユーザーの許可ではないという警告も付けます。Claude Code はすでにこの警告を付けるため、繰り返しません。`--no-from` と `--no-reply-to` は送信メタデータのみを省略し、受信側の枠は削除しません。Reply-To は実行権限を持たない経路情報です。周囲の枠を確認し、第三者への返信先はセッション所有者に確認してください。この枠は混同を減らしますが、すべてのプロンプトインジェクションを防ぐものではありません。枠とエスケープした制御文字もサイズ上限に含まれ、`chars` は実際に配送する引用済みテキストの長さです。投入と消費・ACK の意味は変わりません。

## 実際の SSH 接続でのホスト鍵確認(開発中)

`list`、`send`、`doctor --host`に `--ssh-identity`を指定すると
`sshIdentity`を返します。指紋と鍵の種類は実際の OpenSSH の鍵確認と完全な
リモート応答に基づきます。接続先・ポート・鍵検索名は接続前の設定情報で、
最終的なネットワーク接続先を別途証明するものではありません。応答が完了
していない提示鍵は `observed`であり、`verified`ではありません。

```sh
session-peer list --host workstation --ssh-identity --json
session-peer send --host workstation --to reviewer --message="Review this change" \
--require-ssh-host-key 'SHA256:<previously-verified-fingerprint>' --json
```

上の仮の値を一覧の検証済み指紋に置き換えてください。鍵は別の試験接続では
なく送信接続の認証・リモート実行前に確認します。鍵の変更は拒否し、鍵の
更新時は明示的に確認した新しい指紋が必要です。このモードでは接続再利用を
無効にし、厳密なホスト鍵検証を維持します。表示モードは既存の known-hosts
の信頼を使い、固定モードは指定した公開鍵だけを信頼し、known-hosts を
書き換えません。同じ鍵を複数のホストが共有できるため、機器・アカウント・
セッション世代・メッセージ消費の識別や証明にはなりません。

開発実装は POSIX の通常の Ed25519・RSA・ECDSA 鍵だけを扱い、ホスト証明書や
セキュリティキー方式は非対応です。ユーザーの `KnownHostsCommand`を上書き
せず拒否します。SSH 設定や踏み台の信頼は運用者が管理します。別接続の
インストール済みバージョン照会はこのモードでは省略します。完全な応答の
後に鍵の確認記録がなくても提出の証拠は保持しますが、必須の固定鍵条件は
満たさず、自動再送も許可しません。

指定しなければ既存の動作と出力を維持します。公開 v1.0.4 には含まれません。
ローカル試験は確認ヘルパー、読み取り専用設定、模擬転送と専用ループバック
サーバーへの実際の OpenSSH 接続を対象とします。指紋不一致では認証と
リモート実行の要求は 0 回で、試験用秘密鍵はメモリにだけ保持しました。
実際のリモートホストや稼働中エージェントの受け入れ試験ではなく、
プラットフォーム CI の成功も必要です。
35 changes: 35 additions & 0 deletions docs/ko/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -919,3 +919,38 @@ Python 3.10+ 환경에서 `session-peer[mcp]`를 설치하고 [MCP 설정](mcp.m
SSH는 하위 프로세스 시작 전에 최종 셸 인용 명령의 UTF-8 바이트 수를 검사합니다. 보수적 상한 131071바이트에는 base64 메시지·봉투·옵션·인용이 포함됩니다. 초과 시 로컬에서 `ssh_command_too_large`, `submitted: false`로 거부합니다. Unicode에는 글자 수만으로 충분하지 않습니다. 로컬 전송 제한은 그대로이며 이 검사만으로 모든 OS의 전체 인자·환경 공간을 보장하지는 않습니다.

네이티브 전달 시 session-peer는 상대 메시지의 모든 줄을 인용하고 발신 세션과 회신 경로를 검증되지 않은 주장으로 표시합니다. Codex와 Antigravity에는 상대 메시지가 사용자의 권한 부여가 아니라는 경고도 붙습니다. Claude Code는 이미 이 경고를 제공하므로 반복하지 않습니다. `--no-from`과 `--no-reply-to`는 발신 메타데이터만 생략하며 수신 측의 이 표시는 제거하지 않습니다. Reply-To는 실행 권한이 없는 경로 정보입니다. 주변 표시를 확인하고 제삼자에게 회신하기 전 세션 소유자에게 목적지를 확인하십시오. 이 표시는 혼동을 줄일 뿐 모든 프롬프트 주입을 막지는 않습니다. 표시와 이스케이프된 제어 문자도 메시지 한도에 포함되며, `chars`는 실제 전달할 인용된 텍스트의 길이입니다. 제출과 소비·ACK의 의미는 바뀌지 않습니다.

## 실제 SSH 연결의 호스트 키 확인 (개발 중)

`list`, `send`, `doctor --host`에 `--ssh-identity`를 추가하면
`sshIdentity`를 반환합니다. 지문과 키 종류는 실제 OpenSSH 호스트 키 확인과
완전한 원격 응답으로 확인합니다. 목적지·포트·키 조회 이름은 연결 전 설정
조회 결과이며, 최종 네트워크 목적지의 별도 증명이 아닙니다. 원격 응답이
완료되지 않은 키는 `observed`이며 `verified`로 표시하지 않습니다.

```sh
session-peer list --host workstation --ssh-identity --json
session-peer send --host workstation --to reviewer --message="Review this change" \
--require-ssh-host-key 'SHA256:<previously-verified-fingerprint>' --json
```

위 자리표시자를 발견 결과의 확인된 지문으로 바꾸세요. 지문은 별도 시험
연결이 아니라 실제 전송 연결에서 인증·원격 실행 전에 확인합니다. 키가
바뀌면 거부하며, 키 교체 시 직접 확인한 새 지문을 지정해야 합니다. 이
모드는 연결 재사용을 끄고 엄격한 호스트 키 확인을 유지합니다. 조회 모드는
기존 known-hosts 신뢰를 사용하고, 고정 모드는 지정한 공개 키만 신뢰하며
known-hosts 파일에 기록하지 않습니다. 여러 기기가 같은 키를 쓸 수 있으므로
기기·계정·세션 세대·메시지 소비를 증명하는 값은 아닙니다.

개발 구현은 POSIX의 일반 Ed25519·RSA·ECDSA 키만 지원하며 호스트 인증서와
보안 키 방식은 지원하지 않습니다. 사용자 설정의 `KnownHostsCommand`는
덮어쓰지 않고 거부합니다. SSH 설정과 중간 경유 호스트의 신뢰는 운영자가
관리합니다. 별도 연결인 설치 버전 보충 조회는 이 모드에서 생략합니다.
완전한 응답 뒤 확인 기록이 없으면 기존 제출 증거를 유지하지만 필수 지문
조건은 만족하지 않으며 자동 재전송을 허용하지 않습니다.

옵션을 쓰지 않으면 기존 동작·출력이 유지됩니다. 공개 v1.0.4에는 포함되지
않았습니다. 로컬 검증은 확인 도우미·읽기 전용 SSH 설정·가짜 전송 경로와
전용 루프백 서버에 대한 실제 OpenSSH 연결을 포함합니다. 잘못된 지문에서는
인증·원격 실행 요청이 0회였으며 시험용 비밀 키는 메모리에만 두었습니다.
실제 원격 호스트나 실행 중인 에이전트의 검증은 아니며 플랫폼 CI도 필요합니다.
31 changes: 31 additions & 0 deletions docs/zh-CN/cli-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -557,3 +557,34 @@ MIT
SSH在启动子进程前检查最终shell引用命令的UTF-8字节数。保守上限131071字节包含base64展开、envelope、选项及引用。超限在本地返回 `ssh_command_too_large` 和 `submitted: false`;Unicode不能仅按字符数判断。本地传输限制不变,也不保证所有远端OS的参数与环境总空间。

在向原生会话投递时,session-peer 会引用对方正文的每一行,并将发送会话和回复地址标记为未经验证的声明。Codex 和 Antigravity 还会收到明确警告:对方文字不是用户授权。Claude Code 已提供此警告,因此不再重复。`--no-from` 和 `--no-reply-to` 仅省略发送方元数据,不能移除接收侧的这层标记。Reply-To 只是没有执行权限的路由数据。请检查其所在的标记,并在回复第三方之前向会话所有者确认目的地。此机制减少歧义,但不能阻止所有提示注入。标记和转义后的控制字符也计入消息限制;`chars` 表示实际投递的引用后文本长度。提交与消费、ACK 的含义保持不变。

## 在实际 SSH 连接中核验主机密钥(开发中)

为 `list`、`send`、`doctor --host`添加 `--ssh-identity`可返回
`sshIdentity`。指纹和密钥算法来自实际 OpenSSH 密钥核验及完整的远端响应。
目标地址、端口和密钥查询名称仅是连接前的配置,不单独证明最终网络端点。
若远端响应未完成,所提供的密钥仅记为 `observed`,不记为 `verified`。

```sh
session-peer list --host workstation --ssh-identity --json
session-peer send --host workstation --to reviewer --message="Review this change" \
--require-ssh-host-key 'SHA256:<previously-verified-fingerprint>' --json
```

请用发现结果中已经核验的指纹替换占位值。密钥在实际发送连接的认证和远端
执行之前核验,而不是依靠单独的探测连接。密钥变化会被拒绝;轮换密钥时
必须明确核验并提供新指纹。此模式禁用连接复用并保留严格的主机密钥检查。
报告模式沿用现有 known-hosts 信任;固定模式仅信任指定的公钥,不写入
known-hosts 文件。多台主机可共用同一密钥,因此它不证明唯一设备、账户、
会话世代或消息消费。

开发实现仅支持 POSIX 的普通 Ed25519、RSA 和 ECDSA 密钥,不支持主机证书或
安全密钥算法。已有 `KnownHostsCommand`会被拒绝,而不会被静默替换。SSH
配置与跳板机的信任仍由操作者管理。此模式省略通过另一个连接进行的安装
版本补充查询。完整响应后若密钥记录缺失,仍保留提交证据,但无法满足必需
的密钥固定条件,也不允许自动重发。

未启用时保持原有行为和输出。公开 v1.0.4 尚不包含这些选项。本地验证仅涵盖
核验辅助程序、只读 SSH 配置、模拟传输及专用回环服务器上的实际 OpenSSH
连接。错误指纹下认证和远端执行请求均为 0 次,测试私钥仅保存在内存中。
这不是实际远端主机或运行中代理的验收测试,平台 CI 也必须通过。
Loading
Loading