This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { HelpText } from './HelpText';
|
||||
import { FieldLabel, FieldInput } from './formUtils';
|
||||
import type { SectionFormProps } from './types';
|
||||
@@ -11,6 +12,7 @@ import type { SectionFormProps } from './types';
|
||||
* sibling subtabs of `SshForm`.
|
||||
*/
|
||||
export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenByEnv }: SectionFormProps) {
|
||||
const { t } = useTranslation('settings');
|
||||
const ssh = config.ssh ?? {};
|
||||
const console_ = ssh.console ?? {};
|
||||
|
||||
@@ -24,13 +26,9 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
onChange={e => onChange('ssh.enabled', e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
SSH 機能を有効化する
|
||||
{t('ssh.config.enableLabel')}
|
||||
</label>
|
||||
<HelpText>
|
||||
OFF の間は SshExec / SshUpload / SshDownload / SshConsole* 全ツールが利用不可になり、
|
||||
関連 API も router に登録されない。<code className="font-mono">MCP_ENCRYPTION_KEY</code> 環境変数も
|
||||
別途必須 (鍵が無い場合は ON にしても subsystem は disabled で起動)。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.enableHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -41,13 +39,9 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
onChange={e => onChange('ssh.allowPrivateAddresses', e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
プライベート / loopback アドレスへの接続を許可する
|
||||
{t('ssh.config.allowPrivateLabel')}
|
||||
</label>
|
||||
<HelpText>
|
||||
self-hosted / LAN 上のサーバーに繋ぐ場合に必要。OFF だと <code className="font-mono">10.x</code>,
|
||||
<code className="font-mono">192.168.x</code>, <code className="font-mono">127.0.0.1</code> 等の
|
||||
private アドレスへの接続が reject される。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.allowPrivateHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -58,12 +52,9 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
onChange={e => onChange('ssh.adminBypassesGrants', e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
Admin は grant 無しでも接続を利用できる
|
||||
{t('ssh.config.adminBypassLabel')}
|
||||
</label>
|
||||
<HelpText>
|
||||
ON: admin role の user は per-connection grant 無しでも全接続にアクセス可
|
||||
(監査ログには記録される)。OFF: admin もユーザーと同じく明示的 grant 必須。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.adminBypassHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-6 pt-3 border-t border-slate-200">
|
||||
@@ -71,16 +62,13 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
</h3>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Call timeout (秒)</FieldLabel>
|
||||
<FieldLabel>{t('ssh.config.callTimeout')}</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={ssh.callTimeoutSeconds ?? 30}
|
||||
onChange={v => onChange('ssh.callTimeoutSeconds', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
SshExec / SshUpload / SshDownload の wall-clock 上限 (TCP connect + auth + 実行を含む)。
|
||||
デフォルト 30。SshConsole* には適用されない (こちらは idle/duration cap 側で管理)。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.callTimeoutHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -90,10 +78,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
value={ssh.maxOutputBytes ?? 32768}
|
||||
onChange={v => onChange('ssh.maxOutputBytes', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
SshExec の stdout/stderr の合計バイト上限。超過分は truncate され
|
||||
<code className="font-mono">truncated_stdout: true</code> で返る。デフォルト 32768 (32 KiB)。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.maxOutputHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
@@ -114,32 +99,26 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<HelpText>SshUpload / SshDownload のファイルサイズ上限。超過は転送前に reject。</HelpText>
|
||||
<HelpText>{t('ssh.config.transferSizeHelp')}</HelpText>
|
||||
|
||||
<div>
|
||||
<FieldLabel>Audit retention (日)</FieldLabel>
|
||||
<FieldLabel>{t('ssh.config.auditRetention')}</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={ssh.auditRetentionDays ?? 90}
|
||||
onChange={v => onChange('ssh.auditRetentionDays', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
<code className="font-mono">ssh_audit_log</code> テーブルの保持日数。Audit tab の
|
||||
"Prune" ボタンでこの値より古い行を削除できる。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.auditRetentionHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-6 pt-3 border-t border-slate-200">
|
||||
Abuse detection
|
||||
</h3>
|
||||
<HelpText>
|
||||
ホスト鍵不一致 / 認証失敗 / コマンド失敗が短時間に集中したら接続を一時ロックする。
|
||||
ロック中は同接続が <code className="font-mono">abuse_locked</code> エラーで reject される。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.abuseHelp')}</HelpText>
|
||||
|
||||
<div className="grid grid-cols-3 gap-3">
|
||||
<div>
|
||||
<FieldLabel>Window (分)</FieldLabel>
|
||||
<FieldLabel>{t('ssh.config.abuseWindow')}</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={ssh.abuseWindowMinutes ?? 10}
|
||||
@@ -155,7 +134,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<FieldLabel>Lock duration (分)</FieldLabel>
|
||||
<FieldLabel>{t('ssh.config.abuseLock')}</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={ssh.abuseLockMinutes ?? 30}
|
||||
@@ -165,7 +144,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
</div>
|
||||
|
||||
<h3 className="text-sm font-medium text-slate-600 mt-6 pt-3 border-t border-slate-200">
|
||||
Interactive Console (SSH タブ / SshConsole* tools)
|
||||
{t('ssh.config.consoleSectionTitle')}
|
||||
</h3>
|
||||
|
||||
<div>
|
||||
@@ -176,39 +155,29 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
onChange={e => onChange('ssh.console.enabled', e.target.checked)}
|
||||
className="rounded"
|
||||
/>
|
||||
Console 機能を有効化する
|
||||
{t('ssh.config.consoleEnableLabel')}
|
||||
</label>
|
||||
<HelpText>
|
||||
OFF だと SshConsole* tools と <code className="font-mono">SSH</code> タブが無効。
|
||||
上の "SSH 機能を有効化する" と <code className="font-mono">MCP_ENCRYPTION_KEY</code> も
|
||||
別途必須。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.consoleEnableHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<FieldLabel>Idle timeout (秒)</FieldLabel>
|
||||
<FieldLabel>{t('ssh.config.idleTimeout')}</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={console_.idleTimeoutSeconds ?? 1800}
|
||||
onChange={v => onChange('ssh.console.idleTimeoutSeconds', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
I/O が一定秒無いセッションを auto-close する閾値。人間の入力も AI の入力も
|
||||
activity としてカウントする。デフォルト 1800 (30 分)。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.idleTimeoutHelp')}</HelpText>
|
||||
</div>
|
||||
<div>
|
||||
<FieldLabel>Max session duration (秒)</FieldLabel>
|
||||
<FieldLabel>{t('ssh.config.maxSessionDuration')}</FieldLabel>
|
||||
<FieldInput
|
||||
type="number"
|
||||
value={console_.maxSessionDurationSeconds ?? 14400}
|
||||
onChange={v => onChange('ssh.console.maxSessionDurationSeconds', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
1 セッションの絶対上限。Idle じゃなくてもこの時間を超えると強制 close。
|
||||
デフォルト 14400 (4 時間)。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.maxDurationHelp')}</HelpText>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -219,10 +188,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
value={console_.scrollbackBytes ?? 524288}
|
||||
onChange={v => onChange('ssh.console.scrollbackBytes', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
サーバー側で保持する PTY 出力履歴のリングバッファ容量。ブラウザ再接続時に
|
||||
replay される量。デフォルト 524288 (512 KiB)。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.scrollbackHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -232,10 +198,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
value={console_.maxSessionsPerConnection ?? 3}
|
||||
onChange={v => onChange('ssh.console.maxSessionsPerConnection', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
同じ接続を使う並列セッション数の上限。超えた場合は最も古いセッションが
|
||||
<code className="font-mono">session_cap_evict</code> 理由で close される。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.maxSessionsHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -245,10 +208,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
value={console_.maxInputBytesPerSend ?? 16384}
|
||||
onChange={v => onChange('ssh.console.maxInputBytesPerSend', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
1 回の <code className="font-mono">SshConsoleSend</code> で送れる最大バイト数。
|
||||
デフォルト 16384 (16 KiB)。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.maxInputHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -258,10 +218,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
value={console_.autoInjectScreenLines ?? 24}
|
||||
onChange={v => onChange('ssh.console.autoInjectScreenLines', Number(v))}
|
||||
/>
|
||||
<HelpText>
|
||||
各 LLM iteration の system prompt 末尾に挿入する screen の末尾行数。
|
||||
多いほど AI の状況認識が良くなるが context を消費する。デフォルト 24 行。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.autoInjectHelp')}</HelpText>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
@@ -282,9 +239,7 @@ export function SshConfigForm({ config, onChange, overriddenByEnv: _overriddenBy
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<HelpText>
|
||||
PTY サイズの初期値。クライアントが resize イベントを送れば上書きされる。
|
||||
</HelpText>
|
||||
<HelpText>{t('ssh.config.ptySizeHelp')}</HelpText>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user