Files
dsh_shenxian/test/remote-spawner.test.mjs
admin 452924d89c feat(config): 涉密内容外置到配置目录(档案 140)
把散落在代码里的真实部署值统一收进 config/,代码改为引用配置,
使仓库副本/开源导出不再带出生产域名、IP、内网路径与凭据。

新增 config/:platform.env.example(模板)· load.sh(shell 加载器)·
index.cjs(node 加载器)· README.md(键一览与优先级)。
真实值放 config/platform.env —— 已 .gitignore 排除,不入库、不进导出。

TS 侧新增 src/platform-paths.ts 作部署路径的唯一解析处(零副作用):
platformDir/stateDir/backupDir/artifactDir/installDir/scriptPath。
config.ts 接入这些字段;内置中继种子由生产 URL 改为空(改由
DSHS_OVERLAY_BOOTSTRAP_SEEDS 提供)。修掉 5 处硬编码绝对路径,
src/** 注释中性化 116 行/53 文件。

scripts/** 36 个内部运维脚本:真令牌/PG 口令/隧道目标/主机号/路径
一律改从配置取;web/wake.html 的注册域白名单改为运行时从
location.hostname 推导;test/** 夹具 119 行/13 文件改 RFC 2606/5737
保留值,并把「内置种子必须为空」固化为回归断言。

取证:tsc 0 错;npm test 373/375(唯一失败 lease 属既有);
全仓扫描(大小写不敏感)代码面涉密标识 = 0;已部署 47 并零回归
(/opt/dsh/* 未搬家,/var/lib/dshs/platform 未被误建)。
2026-09-19 15:12:19 +08:00

95 lines
3.8 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* Manager 侧 `RemoteSpawner.endpointFor` 的**端点翻译接线**单测(覆盖网络 R4)。
*
* ## 为什么单独立一个文件(2026-09-16 实测代价)
* `translateEndpoint` 是 R4 的**唯一**翻译点:`via='relay'` 的 host,其实例在 Worker 上监听
* `127.0.0.1:<实例端口>`,而 Manager 必须拨 relay 为那个端口开的**动态回环口号**。
*
* 首版实现里 `RemoteSpawner` 的构造函数**漏了 `this.translateEndpoint = options.translateEndpoint`**
* —— 于是整个翻译**静默失效**:`endpointFor` 原样返回 Worker 侧口号 ⇒ Manager 往**自己本机**
* 拨 `127.0.0.1:21000` ⇒ 连接被拒两次 ⇒ 代理 `reply.raw.destroy()`。
* 现场表现只有两条:浏览器/curl 看到 **`Empty reply from server`**;平台日志**一行错误都没有**。
* (定位靠"在 47 上临时监听 21000,请求被这个探针接走"——即**用判别器测,而不是读代码猜**。)
*
* ⇒ 本文件把"翻译必须真的生效"钉成断言:**构造时就验**,不依赖集群环境、不依赖 relay 在跑。
*
* 运行:`node --test test/remote-spawner.test.mjs`(已登记进 `npm test` / `npm run verify`)。
*
* @module test/remote-spawner
*/
import assert from 'node:assert/strict'
import { test } from 'node:test'
import { RemoteSpawner } from '../lib/supervisor/remote-spawner.js'
/* ─────────── 小工具 ─────────── */
/** Worker 侧 agent 的回包(`GET /endpoint/:userId` 的形状)。 */
function fakeFetch(payload) {
const calls = []
const impl = async (url, init) => {
calls.push(`${init?.method ?? 'GET'} ${url}`)
return { ok: true, status: 200, json: async () => payload, text: async () => JSON.stringify(payload) }
}
impl.calls = calls
return impl
}
/** `via='relay'` 的一台 worker:agent 口号 19000,relay 已把它映射到本机 38253。 */
const W106 = {
hostId: 'w-2',
agentUrl: 'http://127.0.0.1:19000',
reachability: { hostId: 'w-2', via: 'relay', address: '127.0.0.1:38253', scheme: 'http' },
token: 'tok-106',
}
function make(opts = {}) {
return new RemoteSpawner({
agentUrl: 'http://127.0.0.1:19100',
token: 'tok-local',
defaultHostId: 'w-1',
hostIdFor: async () => 'w-2',
hostsProvider: async () => [W106],
fetchImpl: fakeFetch({ running: true, host: '127.0.0.1', port: 21000 }),
...opts,
})
}
/* ─────────── T1–T4 ─────────── */
test('T1 翻译器被真的接上:传入的 hostId/endpoint 与返回值都要生效', async () => {
const seen = []
const s = make({
translateEndpoint: (hostId, ep) => {
seen.push([hostId, ep])
return { host: '127.0.0.1', port: 34241 }
},
})
assert.deepEqual(await s.endpointFor('u1'), { host: '127.0.0.1', port: 34241 })
// ★ 这一条就是首版漏赋值时唯一会红的断言:漏了 ⇒ seen 为空、返回 {21000}
assert.deepEqual(seen, [['w-2', { host: '127.0.0.1', port: 21000 }]])
})
test('T2 未给翻译器 ⇒ 原样透传(local / manager-ssh 的同号语义,行为零变化)', async () => {
const s = make()
assert.deepEqual(await s.endpointFor('u1'), { host: '127.0.0.1', port: 21000 })
})
test('T3 翻译器回 undefined ⇒ endpointFor 也回 undefined(失败关闭,不回退 Worker 口号)', async () => {
const s = make({ translateEndpoint: () => undefined })
assert.equal(await s.endpointFor('u1'), undefined)
})
test('T4 实例未运行 ⇒ undefined,且**不该**调翻译器(没有端口可翻)', async () => {
let called = false
const s = make({
fetchImpl: fakeFetch({ running: false }),
translateEndpoint: () => {
called = true
return undefined
},
})
assert.equal(await s.endpointFor('u1'), undefined)
assert.equal(called, false)
})