mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-29 04:10:00 +08:00
feat(hermes): add terminal ssh config
This commit is contained in:
@@ -5163,6 +5163,10 @@ export function buildHermesTerminalConfigValues(config = {}) {
|
||||
terminalSingularityImage: typeof terminal.singularity_image === 'string' ? terminal.singularity_image.trim() : '',
|
||||
terminalModalImage: typeof terminal.modal_image === 'string' ? terminal.modal_image.trim() : '',
|
||||
terminalDaytonaImage: typeof terminal.daytona_image === 'string' ? terminal.daytona_image.trim() : '',
|
||||
terminalSshHost: typeof terminal.ssh_host === 'string' ? terminal.ssh_host.trim() : '',
|
||||
terminalSshUser: typeof terminal.ssh_user === 'string' ? terminal.ssh_user.trim() : '',
|
||||
terminalSshPort: parseHermesInteger(terminal.ssh_port, 'terminal.ssh_port', 22, 1, 65535, false),
|
||||
terminalSshKey: typeof terminal.ssh_key === 'string' ? terminal.ssh_key.trim() : '',
|
||||
terminalContainerCpu: parseHermesInteger(terminal.container_cpu, 'terminal.container_cpu', 1, 1, 64, false),
|
||||
terminalContainerMemory: parseHermesInteger(terminal.container_memory, 'terminal.container_memory', 5120, 128, 1048576, false),
|
||||
terminalContainerDisk: parseHermesInteger(terminal.container_disk, 'terminal.container_disk', 51200, 1024, 10485760, false),
|
||||
@@ -5192,6 +5196,16 @@ export function mergeHermesTerminalConfig(config = {}, form = {}) {
|
||||
if (image) terminal[yamlKey] = image
|
||||
else delete terminal[yamlKey]
|
||||
}
|
||||
for (const [formKey, yamlKey] of [
|
||||
['terminalSshHost', 'ssh_host'],
|
||||
['terminalSshUser', 'ssh_user'],
|
||||
['terminalSshKey', 'ssh_key'],
|
||||
]) {
|
||||
const value = normalizeHermesOptionalString(Object.hasOwn(form, formKey) ? form[formKey] : currentValues[formKey], `terminal.${yamlKey}`)
|
||||
if (value) terminal[yamlKey] = value
|
||||
else delete terminal[yamlKey]
|
||||
}
|
||||
terminal.ssh_port = parseHermesInteger(Object.hasOwn(form, 'terminalSshPort') ? form.terminalSshPort : currentValues.terminalSshPort, 'terminal.ssh_port', 22, 1, 65535, true)
|
||||
terminal.container_cpu = parseHermesInteger(Object.hasOwn(form, 'terminalContainerCpu') ? form.terminalContainerCpu : currentValues.terminalContainerCpu, 'terminal.container_cpu', 1, 1, 64, true)
|
||||
terminal.container_memory = parseHermesInteger(Object.hasOwn(form, 'terminalContainerMemory') ? form.terminalContainerMemory : currentValues.terminalContainerMemory, 'terminal.container_memory', 5120, 128, 1048576, true)
|
||||
terminal.container_disk = parseHermesInteger(Object.hasOwn(form, 'terminalContainerDisk') ? form.terminalContainerDisk : currentValues.terminalContainerDisk, 'terminal.container_disk', 51200, 1024, 10485760, true)
|
||||
|
||||
@@ -7867,6 +7867,12 @@ fn build_hermes_terminal_config_values(config: &serde_yaml::Value) -> Value {
|
||||
let terminal_singularity_image = terminal_string("singularity_image");
|
||||
let terminal_modal_image = terminal_string("modal_image");
|
||||
let terminal_daytona_image = terminal_string("daytona_image");
|
||||
let terminal_ssh_host = terminal_string("ssh_host");
|
||||
let terminal_ssh_user = terminal_string("ssh_user");
|
||||
let terminal_ssh_port = terminal
|
||||
.map(|map| bounded_hermes_i64(yaml_i64_field(map, "ssh_port"), 22, 1, 65535))
|
||||
.unwrap_or(22);
|
||||
let terminal_ssh_key = terminal_string("ssh_key");
|
||||
let terminal_container_cpu = terminal
|
||||
.map(|map| bounded_hermes_i64(yaml_i64_field(map, "container_cpu"), 1, 1, 64))
|
||||
.unwrap_or(1);
|
||||
@@ -7891,6 +7897,10 @@ fn build_hermes_terminal_config_values(config: &serde_yaml::Value) -> Value {
|
||||
"terminalSingularityImage": terminal_singularity_image,
|
||||
"terminalModalImage": terminal_modal_image,
|
||||
"terminalDaytonaImage": terminal_daytona_image,
|
||||
"terminalSshHost": terminal_ssh_host,
|
||||
"terminalSshUser": terminal_ssh_user,
|
||||
"terminalSshPort": terminal_ssh_port,
|
||||
"terminalSshKey": terminal_ssh_key,
|
||||
"terminalContainerCpu": terminal_container_cpu,
|
||||
"terminalContainerMemory": terminal_container_memory,
|
||||
"terminalContainerDisk": terminal_container_disk,
|
||||
@@ -7994,6 +8004,32 @@ fn merge_hermes_terminal_config(
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
let terminal_ssh_host = form_string(form, "terminalSshHost")
|
||||
.or_else(|| current["terminalSshHost"].as_str().map(ToString::to_string))
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
let terminal_ssh_user = form_string(form, "terminalSshUser")
|
||||
.or_else(|| current["terminalSshUser"].as_str().map(ToString::to_string))
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
let terminal_ssh_port = validate_hermes_i64(
|
||||
if form.get("terminalSshPort").is_some() {
|
||||
form_i64(form, "terminalSshPort")
|
||||
} else {
|
||||
Some(current["terminalSshPort"].as_i64().unwrap_or(22))
|
||||
},
|
||||
"terminal.ssh_port",
|
||||
22,
|
||||
1,
|
||||
65535,
|
||||
)?;
|
||||
let terminal_ssh_key = form_string(form, "terminalSshKey")
|
||||
.or_else(|| current["terminalSshKey"].as_str().map(ToString::to_string))
|
||||
.unwrap_or_default()
|
||||
.trim()
|
||||
.to_string();
|
||||
let terminal_container_cpu = validate_hermes_i64(
|
||||
if form.get("terminalContainerCpu").is_some() {
|
||||
form_i64(form, "terminalContainerCpu")
|
||||
@@ -8061,6 +8097,13 @@ fn merge_hermes_terminal_config(
|
||||
set_optional_yaml_string(terminal, "singularity_image", terminal_singularity_image);
|
||||
set_optional_yaml_string(terminal, "modal_image", terminal_modal_image);
|
||||
set_optional_yaml_string(terminal, "daytona_image", terminal_daytona_image);
|
||||
set_optional_yaml_string(terminal, "ssh_host", terminal_ssh_host);
|
||||
set_optional_yaml_string(terminal, "ssh_user", terminal_ssh_user);
|
||||
terminal.insert(
|
||||
yaml_key("ssh_port"),
|
||||
serde_yaml::Value::Number(terminal_ssh_port.into()),
|
||||
);
|
||||
set_optional_yaml_string(terminal, "ssh_key", terminal_ssh_key);
|
||||
terminal.insert(
|
||||
yaml_key("container_cpu"),
|
||||
serde_yaml::Value::Number(terminal_container_cpu.into()),
|
||||
@@ -16582,6 +16625,10 @@ mod hermes_terminal_config_tests {
|
||||
assert_eq!(values["terminalSingularityImage"], "");
|
||||
assert_eq!(values["terminalModalImage"], "");
|
||||
assert_eq!(values["terminalDaytonaImage"], "");
|
||||
assert_eq!(values["terminalSshHost"], "");
|
||||
assert_eq!(values["terminalSshUser"], "");
|
||||
assert_eq!(values["terminalSshPort"], 22);
|
||||
assert_eq!(values["terminalSshKey"], "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -16599,6 +16646,10 @@ terminal:
|
||||
singularity_image: docker://nikolaik/python-nodejs:python3.11-nodejs20
|
||||
modal_image: python:3.12
|
||||
daytona_image: ubuntu:24.04
|
||||
ssh_host: build.example.com
|
||||
ssh_user: deploy
|
||||
ssh_port: 2222
|
||||
ssh_key: ~/.ssh/hermes_ed25519
|
||||
container_cpu: 4
|
||||
container_memory: 8192
|
||||
container_disk: 102400
|
||||
@@ -16623,6 +16674,10 @@ terminal:
|
||||
);
|
||||
assert_eq!(values["terminalModalImage"], "python:3.12");
|
||||
assert_eq!(values["terminalDaytonaImage"], "ubuntu:24.04");
|
||||
assert_eq!(values["terminalSshHost"], "build.example.com");
|
||||
assert_eq!(values["terminalSshUser"], "deploy");
|
||||
assert_eq!(values["terminalSshPort"], 2222);
|
||||
assert_eq!(values["terminalSshKey"], "~/.ssh/hermes_ed25519");
|
||||
assert_eq!(values["terminalContainerCpu"], 4);
|
||||
assert_eq!(values["terminalContainerMemory"], 8192);
|
||||
assert_eq!(values["terminalContainerDisk"], 102400);
|
||||
@@ -16660,6 +16715,10 @@ streaming:
|
||||
"terminalSingularityImage": "docker://ubuntu:24.04",
|
||||
"terminalModalImage": "debian:bookworm",
|
||||
"terminalDaytonaImage": "ubuntu:22.04",
|
||||
"terminalSshHost": "ssh.example.com",
|
||||
"terminalSshUser": "hermes",
|
||||
"terminalSshPort": "2200",
|
||||
"terminalSshKey": "~/.ssh/id_ed25519",
|
||||
"terminalContainerCpu": "2",
|
||||
"terminalContainerMemory": "6144",
|
||||
"terminalContainerDisk": "20480",
|
||||
@@ -16698,6 +16757,16 @@ streaming:
|
||||
config["terminal"]["daytona_image"].as_str(),
|
||||
Some("ubuntu:22.04")
|
||||
);
|
||||
assert_eq!(
|
||||
config["terminal"]["ssh_host"].as_str(),
|
||||
Some("ssh.example.com")
|
||||
);
|
||||
assert_eq!(config["terminal"]["ssh_user"].as_str(), Some("hermes"));
|
||||
assert_eq!(config["terminal"]["ssh_port"].as_i64(), Some(2200));
|
||||
assert_eq!(
|
||||
config["terminal"]["ssh_key"].as_str(),
|
||||
Some("~/.ssh/id_ed25519")
|
||||
);
|
||||
assert_eq!(config["terminal"]["container_cpu"].as_i64(), Some(2));
|
||||
assert_eq!(config["terminal"]["container_memory"].as_i64(), Some(6144));
|
||||
assert_eq!(config["terminal"]["container_disk"].as_i64(), Some(20480));
|
||||
@@ -16750,6 +16819,41 @@ terminal:
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_terminal_config_removes_empty_ssh_fields() {
|
||||
let mut config: serde_yaml::Value = serde_yaml::from_str(
|
||||
r#"
|
||||
terminal:
|
||||
ssh_host: old-host
|
||||
ssh_user: old-user
|
||||
ssh_port: 2200
|
||||
ssh_key: ~/.ssh/old
|
||||
custom_flag: keep-terminal
|
||||
"#,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
merge_hermes_terminal_config(
|
||||
&mut config,
|
||||
&json!({
|
||||
"terminalSshHost": "",
|
||||
"terminalSshUser": " ",
|
||||
"terminalSshPort": "22",
|
||||
"terminalSshKey": "",
|
||||
}),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert!(config["terminal"]["ssh_host"].is_null());
|
||||
assert!(config["terminal"]["ssh_user"].is_null());
|
||||
assert!(config["terminal"]["ssh_key"].is_null());
|
||||
assert_eq!(config["terminal"]["ssh_port"].as_i64(), Some(22));
|
||||
assert_eq!(
|
||||
config["terminal"]["custom_flag"].as_str(),
|
||||
Some("keep-terminal")
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn merge_terminal_config_rejects_invalid_values() {
|
||||
let mut config = serde_yaml::Value::Mapping(serde_yaml::Mapping::new());
|
||||
@@ -16771,6 +16875,12 @@ terminal:
|
||||
merge_hermes_terminal_config(&mut config, &json!({ "terminalContainerMemory": 127 }))
|
||||
.unwrap_err();
|
||||
assert!(err.contains("terminal.container_memory"));
|
||||
let err = merge_hermes_terminal_config(&mut config, &json!({ "terminalSshPort": 0 }))
|
||||
.unwrap_err();
|
||||
assert!(err.contains("terminal.ssh_port"));
|
||||
let err = merge_hermes_terminal_config(&mut config, &json!({ "terminalSshPort": 65536 }))
|
||||
.unwrap_err();
|
||||
assert!(err.contains("terminal.ssh_port"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,6 +266,10 @@ const TERMINAL_DEFAULTS = {
|
||||
terminalSingularityImage: '',
|
||||
terminalModalImage: '',
|
||||
terminalDaytonaImage: '',
|
||||
terminalSshHost: '',
|
||||
terminalSshUser: '',
|
||||
terminalSshPort: 22,
|
||||
terminalSshKey: '',
|
||||
terminalContainerCpu: 1,
|
||||
terminalContainerMemory: 5120,
|
||||
terminalContainerDisk: 51200,
|
||||
@@ -1993,6 +1997,25 @@ export function render() {
|
||||
<span>${t('engine.hermesTerminalConfigContainerPersistent')}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-config-subtitle">${t('engine.hermesTerminalConfigSshTitle')}</div>
|
||||
<div class="hm-config-runtime-grid hm-config-terminal-grid">
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTerminalConfigSshHost')}</span>
|
||||
<input id="hm-terminal-ssh-host" class="hm-input" value="${esc(terminalValues.terminalSshHost)}" placeholder="my-server.example.com" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTerminalConfigSshUser')}</span>
|
||||
<input id="hm-terminal-ssh-user" class="hm-input" value="${esc(terminalValues.terminalSshUser)}" placeholder="deploy" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTerminalConfigSshPort')}</span>
|
||||
<input id="hm-terminal-ssh-port" class="hm-input" type="number" inputmode="numeric" min="1" max="65535" step="1" value="${esc(terminalValues.terminalSshPort)}" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
<label class="hm-field">
|
||||
<span class="hm-field-label">${t('engine.hermesTerminalConfigSshKey')}</span>
|
||||
<input id="hm-terminal-ssh-key" class="hm-input" value="${esc(terminalValues.terminalSshKey)}" placeholder="~/.ssh/id_ed25519" ${disabled ? 'disabled' : ''}>
|
||||
</label>
|
||||
</div>
|
||||
<div class="hm-config-subtitle">${t('engine.hermesTerminalConfigContainerTitle')}</div>
|
||||
<div class="hm-config-runtime-grid hm-config-terminal-grid">
|
||||
<label class="hm-field">
|
||||
@@ -3698,6 +3721,10 @@ export function render() {
|
||||
terminalSingularityImage: el.querySelector('#hm-terminal-singularity-image')?.value || '',
|
||||
terminalModalImage: el.querySelector('#hm-terminal-modal-image')?.value || '',
|
||||
terminalDaytonaImage: el.querySelector('#hm-terminal-daytona-image')?.value || '',
|
||||
terminalSshHost: el.querySelector('#hm-terminal-ssh-host')?.value || '',
|
||||
terminalSshUser: el.querySelector('#hm-terminal-ssh-user')?.value || '',
|
||||
terminalSshPort: el.querySelector('#hm-terminal-ssh-port')?.value || '22',
|
||||
terminalSshKey: el.querySelector('#hm-terminal-ssh-key')?.value || '',
|
||||
terminalContainerCpu: el.querySelector('#hm-terminal-container-cpu')?.value || '1',
|
||||
terminalContainerMemory: el.querySelector('#hm-terminal-container-memory')?.value || '5120',
|
||||
terminalContainerDisk: el.querySelector('#hm-terminal-container-disk')?.value || '51200',
|
||||
|
||||
@@ -521,6 +521,11 @@ export default {
|
||||
hermesTerminalConfigDockerRunAsHostUser: _('Docker 使用宿主用户运行', 'Run Docker as host user', 'Docker 使用宿主使用者執行'),
|
||||
hermesTerminalConfigContainerPersistent: _('容器文件系统持久化', 'Persist container filesystem', '容器檔案系統持久化'),
|
||||
hermesTerminalConfigContainerTitle: _('容器资源限制', 'Container resource limits', '容器資源限制'),
|
||||
hermesTerminalConfigSshTitle: _('SSH 远程执行', 'SSH remote execution', 'SSH 遠端執行'),
|
||||
hermesTerminalConfigSshHost: _('SSH 主机(可选)', 'SSH host (optional)', 'SSH 主機(可選)'),
|
||||
hermesTerminalConfigSshUser: _('SSH 用户(可选)', 'SSH user (optional)', 'SSH 使用者(可選)'),
|
||||
hermesTerminalConfigSshPort: _('SSH 端口', 'SSH port', 'SSH 連接埠'),
|
||||
hermesTerminalConfigSshKey: _('SSH 密钥路径(可选)', 'SSH key path (optional)', 'SSH 金鑰路徑(可選)'),
|
||||
hermesTerminalConfigDockerImage: _('Docker 镜像(可选)', 'Docker image (optional)', 'Docker 映像(可選)'),
|
||||
hermesTerminalConfigSingularityImage: _('Singularity 镜像(可选)', 'Singularity image (optional)', 'Singularity 映像(可選)'),
|
||||
hermesTerminalConfigModalImage: _('Modal 镜像(可选)', 'Modal image (optional)', 'Modal 映像(可選)'),
|
||||
@@ -528,7 +533,7 @@ export default {
|
||||
hermesTerminalConfigContainerCpu: _('CPU 核数', 'CPU cores', 'CPU 核心數'),
|
||||
hermesTerminalConfigContainerMemory: _('内存 MB', 'Memory MB', '記憶體 MB'),
|
||||
hermesTerminalConfigContainerDisk: _('磁盘 MB', 'Disk MB', '磁碟 MB'),
|
||||
hermesTerminalConfigFootnote: _('镜像字段只在对应 Docker、Singularity、Modal 或 Daytona 后端生效;留空会移除覆盖并使用 Hermes 默认值。Docker 挂载启动目录会把宿主目录暴露给沙箱,仅在可信项目和无人值守任务中开启;SSH、环境变量等高级参数仍可在 raw YAML 中编辑。', 'Image fields only apply to the matching Docker, Singularity, Modal, or Daytona backend. Leaving them blank removes the override and uses Hermes defaults. Mounting the launch cwd exposes host files to the sandbox; enable it only for trusted projects or unattended jobs. SSH and environment advanced fields remain editable in raw YAML.', '映像欄位只在對應 Docker、Singularity、Modal 或 Daytona 後端生效;留空會移除覆蓋並使用 Hermes 預設值。Docker 掛載啟動目錄會把宿主目錄暴露給沙箱,僅在可信專案和無人值守任務中開啟;SSH、環境變數等進階參數仍可在 raw YAML 中編輯。'),
|
||||
hermesTerminalConfigFootnote: _('SSH 字段只在 SSH 后端生效,留空会移除主机、用户和密钥覆盖;面板不保存 SSH 密码。镜像字段只在对应 Docker、Singularity、Modal 或 Daytona 后端生效;留空会移除覆盖并使用 Hermes 默认值。Docker 挂载启动目录会把宿主目录暴露给沙箱,仅在可信项目和无人值守任务中开启;环境变量等高级参数仍可在 raw YAML 中编辑。', 'SSH fields only apply to the SSH backend. Leaving them blank removes host, user, and key overrides; the panel does not save SSH passwords. Image fields only apply to the matching Docker, Singularity, Modal, or Daytona backend. Leaving them blank removes the override and uses Hermes defaults. Mounting the launch cwd exposes host files to the sandbox; enable it only for trusted projects or unattended jobs. Environment advanced fields remain editable in raw YAML.', 'SSH 欄位只在 SSH 後端生效,留空會移除主機、使用者和金鑰覆蓋;面板不儲存 SSH 密碼。映像欄位只在對應 Docker、Singularity、Modal 或 Daytona 後端生效;留空會移除覆蓋並使用 Hermes 預設值。Docker 掛載啟動目錄會把宿主目錄暴露給沙箱,僅在可信專案和無人值守任務中開啟;環境變數等進階參數仍可在 raw YAML 中編輯。'),
|
||||
hermesStreamingConfigTitle: _('网关流式输出', 'Gateway streaming output', '閘道流式輸出'),
|
||||
hermesStreamingConfigDesc: _('控制 Hermes Gateway 回复时是否边生成边更新消息,以及消息刷新节奏。适合需要更快看到长回复进度的渠道。', 'Control whether Hermes Gateway updates messages while replies are generated, plus the refresh cadence. Useful when channels need quicker progress for long replies.', '控制 Hermes Gateway 回覆時是否邊生成邊更新訊息,以及訊息刷新節奏。適合需要更快看到長回覆進度的渠道。'),
|
||||
hermesStreamingConfigStatusReady: _('结构化配置', 'structured settings', '結構化設定'),
|
||||
|
||||
@@ -396,6 +396,10 @@ test('Hermes 配置页会暴露终端执行结构化配置字段', () => {
|
||||
'hm-terminal-singularity-image',
|
||||
'hm-terminal-modal-image',
|
||||
'hm-terminal-daytona-image',
|
||||
'hm-terminal-ssh-host',
|
||||
'hm-terminal-ssh-user',
|
||||
'hm-terminal-ssh-port',
|
||||
'hm-terminal-ssh-key',
|
||||
'hm-terminal-container-cpu',
|
||||
'hm-terminal-container-memory',
|
||||
'hm-terminal-container-disk',
|
||||
|
||||
@@ -24,6 +24,10 @@ test('Hermes 终端执行配置读取会提供上游默认值', () => {
|
||||
terminalSingularityImage: '',
|
||||
terminalModalImage: '',
|
||||
terminalDaytonaImage: '',
|
||||
terminalSshHost: '',
|
||||
terminalSshUser: '',
|
||||
terminalSshPort: 22,
|
||||
terminalSshKey: '',
|
||||
})
|
||||
})
|
||||
|
||||
@@ -40,6 +44,10 @@ test('Hermes 终端执行配置读取会回显 YAML 字段', () => {
|
||||
singularity_image: 'docker://nikolaik/python-nodejs:python3.11-nodejs20',
|
||||
modal_image: 'python:3.12',
|
||||
daytona_image: 'ubuntu:24.04',
|
||||
ssh_host: 'build.example.com',
|
||||
ssh_user: 'deploy',
|
||||
ssh_port: 2222,
|
||||
ssh_key: '~/.ssh/hermes_ed25519',
|
||||
container_cpu: 4,
|
||||
container_memory: 8192,
|
||||
container_disk: 102400,
|
||||
@@ -57,6 +65,10 @@ test('Hermes 终端执行配置读取会回显 YAML 字段', () => {
|
||||
assert.equal(values.terminalSingularityImage, 'docker://nikolaik/python-nodejs:python3.11-nodejs20')
|
||||
assert.equal(values.terminalModalImage, 'python:3.12')
|
||||
assert.equal(values.terminalDaytonaImage, 'ubuntu:24.04')
|
||||
assert.equal(values.terminalSshHost, 'build.example.com')
|
||||
assert.equal(values.terminalSshUser, 'deploy')
|
||||
assert.equal(values.terminalSshPort, 2222)
|
||||
assert.equal(values.terminalSshKey, '~/.ssh/hermes_ed25519')
|
||||
assert.equal(values.terminalContainerCpu, 4)
|
||||
assert.equal(values.terminalContainerMemory, 8192)
|
||||
assert.equal(values.terminalContainerDisk, 102400)
|
||||
@@ -84,6 +96,10 @@ test('Hermes 终端执行配置保存会保留未知字段并写入上游结构'
|
||||
terminalSingularityImage: 'docker://ubuntu:24.04',
|
||||
terminalModalImage: 'debian:bookworm',
|
||||
terminalDaytonaImage: 'ubuntu:22.04',
|
||||
terminalSshHost: 'ssh.example.com',
|
||||
terminalSshUser: 'hermes',
|
||||
terminalSshPort: '2200',
|
||||
terminalSshKey: '~/.ssh/id_ed25519',
|
||||
terminalContainerCpu: '2',
|
||||
terminalContainerMemory: '6144',
|
||||
terminalContainerDisk: '20480',
|
||||
@@ -102,6 +118,10 @@ test('Hermes 终端执行配置保存会保留未知字段并写入上游结构'
|
||||
assert.equal(next.terminal.singularity_image, 'docker://ubuntu:24.04')
|
||||
assert.equal(next.terminal.modal_image, 'debian:bookworm')
|
||||
assert.equal(next.terminal.daytona_image, 'ubuntu:22.04')
|
||||
assert.equal(next.terminal.ssh_host, 'ssh.example.com')
|
||||
assert.equal(next.terminal.ssh_user, 'hermes')
|
||||
assert.equal(next.terminal.ssh_port, 2200)
|
||||
assert.equal(next.terminal.ssh_key, '~/.ssh/id_ed25519')
|
||||
assert.equal(next.terminal.container_cpu, 2)
|
||||
assert.equal(next.terminal.container_memory, 6144)
|
||||
assert.equal(next.terminal.container_disk, 20480)
|
||||
@@ -133,6 +153,29 @@ test('Hermes 终端执行配置保存空镜像会删除对应字段', () => {
|
||||
assert.equal(next.terminal.custom_flag, 'keep-terminal')
|
||||
})
|
||||
|
||||
test('Hermes 终端执行配置保存空 SSH 字段会删除对应字段', () => {
|
||||
const next = mergeHermesTerminalConfig({
|
||||
terminal: {
|
||||
ssh_host: 'old-host',
|
||||
ssh_user: 'old-user',
|
||||
ssh_port: 2200,
|
||||
ssh_key: '~/.ssh/old',
|
||||
custom_flag: 'keep-terminal',
|
||||
},
|
||||
}, {
|
||||
terminalSshHost: '',
|
||||
terminalSshUser: ' ',
|
||||
terminalSshPort: '22',
|
||||
terminalSshKey: '',
|
||||
})
|
||||
|
||||
assert.equal(Object.hasOwn(next.terminal, 'ssh_host'), false)
|
||||
assert.equal(Object.hasOwn(next.terminal, 'ssh_user'), false)
|
||||
assert.equal(Object.hasOwn(next.terminal, 'ssh_key'), false)
|
||||
assert.equal(next.terminal.ssh_port, 22)
|
||||
assert.equal(next.terminal.custom_flag, 'keep-terminal')
|
||||
})
|
||||
|
||||
test('Hermes 终端执行配置保存会拒绝非法后端和越界值', () => {
|
||||
assert.throws(
|
||||
() => mergeHermesTerminalConfig({}, { terminalBackend: 'unsafe' }),
|
||||
@@ -154,4 +197,12 @@ test('Hermes 终端执行配置保存会拒绝非法后端和越界值', () => {
|
||||
() => mergeHermesTerminalConfig({}, { terminalContainerMemory: '127' }),
|
||||
/terminal\.container_memory/,
|
||||
)
|
||||
assert.throws(
|
||||
() => mergeHermesTerminalConfig({}, { terminalSshPort: '0' }),
|
||||
/terminal\.ssh_port/,
|
||||
)
|
||||
assert.throws(
|
||||
() => mergeHermesTerminalConfig({}, { terminalSshPort: '65536' }),
|
||||
/terminal\.ssh_port/,
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user