diff --git a/apps/agent/src/capabilities/network.ts b/apps/agent/src/capabilities/network.ts index b4934ac..2ed3ae2 100644 --- a/apps/agent/src/capabilities/network.ts +++ b/apps/agent/src/capabilities/network.ts @@ -93,7 +93,7 @@ export function psLit(v: string): string { * * ⚠️ 两个真机教训都固化在这里: * 1) **账号名必须用 WindowsIdentity 取**,不要用 "$env:USERDOMAIN\$env:USERNAME" 拼 —— - * 在 TS 模板串里 `\$` 会被当转义吃掉反斜杠,拼出「机器名」这种不可解析的账号, + * 在 TS 模板串里 `\$` 会被当转义吃掉反斜杠,拼出「机器名+纯数字」这种不可解析的账号, * Register-ScheduledTask 报 HRESULT 0x80070534「No mapping between account names...」。 * 2) 复用同一实现:此前回滚/延时两处各写一份,改了一处漏了另一处(真机踩过)。 */ diff --git a/scripts/rescue-network.ps1 b/scripts/rescue-network.ps1 index 45849e8..b9d4106 100644 --- a/scripts/rescue-network.ps1 +++ b/scripts/rescue-network.ps1 @@ -31,7 +31,7 @@ .EXAMPLE # 恢复为原静态地址(最常用) powershell -ExecutionPolicy Bypass -File rescue-network.ps1 ` - -Interface 'Ethernet' -Ip 192.168.1.100 -PrefixLength 24 -Gateway 192.168.0.1 + -Interface 'Ethernet' -Ip 192.168.1.100 -PrefixLength 24 -Gateway 192.168.1.1 .EXAMPLE # 切回 DHCP(家里路由器会重新分配地址) diff --git a/tests/unit/acl-v11.test.mjs b/tests/unit/acl-v11.test.mjs index 9bd0412..9f37034 100644 --- a/tests/unit/acl-v11.test.mjs +++ b/tests/unit/acl-v11.test.mjs @@ -12,13 +12,13 @@ import { // ---------- B3:对端地址规范化(真机踩坑回归) ---------- test('normalizeIp:IPv4-mapped IPv6 归一为 IPv4(真机坑)', () => { - assert.equal(normalizeIp('::ffff:192.168.1.100'), '192.168.1.100'); - assert.equal(normalizeIp('::FFFF:192.168.1.100'), '192.168.1.100'); + assert.equal(normalizeIp('::ffff:192.168.1.85'), '192.168.1.85'); + assert.equal(normalizeIp('::FFFF:192.168.1.85'), '192.168.1.85'); }); test('normalizeIp:IPv4:port 去端口;纯 IP 原样', () => { - assert.equal(normalizeIp('192.168.1.100:51234'), '192.168.1.100'); - assert.equal(normalizeIp('192.168.1.100'), '192.168.1.100'); + assert.equal(normalizeIp('192.168.1.85:51234'), '192.168.1.85'); + assert.equal(normalizeIp('192.168.1.85'), '192.168.1.85'); }); test('normalizeIp:真 IPv6 原样保留(不误当 IPv4)', () => { @@ -29,22 +29,24 @@ test('normalizeIp:真 IPv6 原样保留(不误当 IPv4)', () => { }); test('normalizeIp + deny_cidr:mapped 地址也能命中黑名单(端到端复现)', () => { - const ip = normalizeIp('::ffff:192.168.1.100'); - const client = { client_id: 'mac_01', allow: [], deny_cidr: ['192.168.1.100'] }; + const ip = normalizeIp('::ffff:192.168.1.85'); + const client = { client_id: 'mac_01', allow: [], deny_cidr: ['192.168.1.85'] }; assert.equal(ipAllowed(client, ip).allowed, false); }); // ---------- B3:CIDR ---------- test('CIDR:单 IP 精确匹配', () => { - assert.equal(ipMatchesCidr('192.168.1.100', '192.168.1.100'), true); - assert.equal(ipMatchesCidr('192.168.1.100', '192.168.1.100'), false); + assert.equal(ipMatchesCidr('192.168.1.85', '192.168.1.85'), true); + assert.equal(ipMatchesCidr('192.168.1.86', '192.168.1.85'), false); }); test('CIDR:/24 网段匹配', () => { - assert.equal(ipMatchesCidr('192.168.1.100', '192.168.0.0/24'), true); - assert.equal(ipMatchesCidr('192.168.0.255', '192.168.0.0/24'), true); - assert.equal(ipMatchesCidr('192.168.1.1', '192.168.0.0/24'), false); + assert.equal(ipMatchesCidr('192.168.1.85', '192.168.1.0/24'), true); + assert.equal(ipMatchesCidr('192.168.1.255', '192.168.1.0/24'), true); + // ⚠️ 这条测的是「**跨网段不匹配**」—— 必须用不同网段的地址。 + // (2026-10-10 一次机械 IP 替换曾把它改成同段,导致断言必红 —— 语义测试别被批量替换破坏) + assert.equal(ipMatchesCidr('192.168.2.1', '192.168.1.0/24'), false); }); test('CIDR:/16 与 0.0.0.0/0', () => { @@ -57,23 +59,23 @@ test('CIDR:/16 与 0.0.0.0/0', () => { test('CIDR:非法输入不误放行(IPv6/主机名/越界位)', () => { assert.equal(ipMatchesCidr('::1', '0.0.0.0/0'), false); assert.equal(ipMatchesCidr('localhost', '0.0.0.0/0'), false); - assert.equal(ipMatchesCidr('192.168.0.1', '192.168.0.0/99'), false); - assert.equal(ipMatchesCidr('192.168.0.999', '192.168.0.0/24'), false); + assert.equal(ipMatchesCidr('192.168.1.1', '192.168.1.0/99'), false); + assert.equal(ipMatchesCidr('192.168.1.999', '192.168.1.0/24'), false); }); test('IP 白名单:deny 优先、白名单为空则放行', () => { assert.equal(ipAllowed({ client_id: 'a', allow: [] }, '1.2.3.4').allowed, true); assert.equal( - ipAllowed({ client_id: 'a', allow: [], allow_cidr: ['192.168.0.0/24'] }, '192.168.0.5').allowed, + ipAllowed({ client_id: 'a', allow: [], allow_cidr: ['192.168.1.0/24'] }, '192.168.1.5').allowed, true, ); assert.equal( - ipAllowed({ client_id: 'a', allow: [], allow_cidr: ['192.168.0.0/24'] }, '10.0.0.1').allowed, + ipAllowed({ client_id: 'a', allow: [], allow_cidr: ['192.168.1.0/24'] }, '10.0.0.1').allowed, false, ); - const both = { client_id: 'a', allow: [], allow_cidr: ['192.168.0.0/24'], deny_cidr: ['192.168.1.100'] }; - assert.equal(ipAllowed(both, '192.168.1.100').allowed, false, '黑名单优先'); - assert.equal(ipAllowed(both, '192.168.1.100').allowed, true); + const both = { client_id: 'a', allow: [], allow_cidr: ['192.168.1.0/24'], deny_cidr: ['192.168.1.85'] }; + assert.equal(ipAllowed(both, '192.168.1.85').allowed, false, '黑名单优先'); + assert.equal(ipAllowed(both, '192.168.1.86').allowed, true); }); // ---------- B3:生效时段 ---------- @@ -134,7 +136,7 @@ test('授权语义:deny 优先于 allow(与 v11 新字段共存)', () => { client_id: 'mac_01', allow: ['fs.*'], deny: ['fs.write'], - allow_cidr: ['192.168.0.0/24'], + allow_cidr: ['192.168.1.0/24'], rate_limits: { 'fs.*': 20 }, }, ], diff --git a/tests/unit/discovery-sig.test.mjs b/tests/unit/discovery-sig.test.mjs index 3c5adc6..44b4ff8 100644 --- a/tests/unit/discovery-sig.test.mjs +++ b/tests/unit/discovery-sig.test.mjs @@ -7,7 +7,7 @@ import { computeHmac, verifyHmac } from '../../packages/protocol/dist/index.js'; * 被控端与控制端必须**逐字节同构**,否则「🔒 已认证」永远不亮 —— 故这里做往返一致性测试。 */ const detail = { - host: '192.168.1.100', + host: '192.168.1.21', port: 8765, tls: true, auth_mode: 'psk', diff --git a/tests/unit/net-scripts.test.mjs b/tests/unit/net-scripts.test.mjs index b1c861b..05cfd61 100644 --- a/tests/unit/net-scripts.test.mjs +++ b/tests/unit/net-scripts.test.mjs @@ -10,11 +10,11 @@ import { const snap = { alias: 'Ethernet', dhcp: false, - ipv4: [{ ip: '192.168.1.100', prefix: 24 }], - gateway: ['192.168.0.1'], + ipv4: [{ ip: '192.168.1.159', prefix: 24 }], + gateway: ['192.168.1.1'], dns: ['223.5.5.5'], }; -const args = { mode: 'static', ip: '192.168.1.100', mask: '255.255.255.0', gateway: '192.168.0.1' }; +const args = { mode: 'static', ip: '192.168.1.88', mask: '255.255.255.0', gateway: '192.168.1.1' }; test('掩码换算:常见掩码与前缀长度互转', () => { assert.equal(maskToPrefix('255.255.255.0'), 24); @@ -63,9 +63,9 @@ test('apply(dhcp):切 DHCP 用原生 cmdlet', () => { }); test('自检:失败时自动执行回滚脚本(自愈)', () => { - const chk = buildSelfCheck('Ethernet', '192.168.1.100', 'C:/rb.ps1'); + const chk = buildSelfCheck('Ethernet', '192.168.1.88', 'C:/rb.ps1'); assert.match(chk, /Get-NetIPAddress/); - assert.match(chk, /192\.168\.0\.88/, '应校验目标地址是否真的生效'); + assert.match(chk, /192\.168\.1\.88/, '应校验目标地址是否真的生效'); assert.match(chk, /selfcheck FAILED -> auto rollback/); assert.match(chk, /& "C:\/rb\.ps1"/, '失败必须回滚,而不是把机器留在无地址状态'); }); @@ -78,8 +78,8 @@ test('rollback:同样先加后清 + 先清路由(否则回滚自己也会失 const iAddRoute = rb.indexOf('New-NetRoute'); assert.ok(iAdd < iRemove, '回滚也必须先加后清'); assert.ok(iRmRoute < iAddRoute, '回滚也必须先清路由'); - assert.match(rb, /192\.168\.0\.159/, '必须恢复快照里的原地址'); - assert.match(rb, /192\.168\.0\.1/, '必须恢复原网关'); + assert.match(rb, /192\.168\.1\.159/, '必须恢复快照里的原地址'); + assert.match(rb, /192\.168\.1\.1/, '必须恢复原网关'); assert.match(rb, /223\.5\.5\.5/, '必须恢复原 DNS'); assert.ok(!/netsh -f/.test(rb), '不得用 netsh -f 回滚(备份编码 + set address 双重问题)'); }); diff --git a/tests/unit/security-hardening.test.mjs b/tests/unit/security-hardening.test.mjs index 4eeafd1..691a1e7 100644 --- a/tests/unit/security-hardening.test.mjs +++ b/tests/unit/security-hardening.test.mjs @@ -49,9 +49,9 @@ test('封禁退避:自定义阈值与基础时长', () => { test('IP 归一化:剥离 IPv4-mapped 前缀,同一来源不分成两个键', () => { const norm = (a) => a.replace(/^::ffff:/i, ''); - assert.equal(norm('::ffff:192.168.1.100'), '192.168.1.100'); + assert.equal(norm('::ffff:192.168.1.21'), '192.168.1.21'); assert.equal(norm('::ffff:127.0.0.1'), '127.0.0.1'); - assert.equal(norm('192.168.1.100'), '192.168.1.100'); + assert.equal(norm('192.168.1.21'), '192.168.1.21'); assert.equal(norm('::1'), '::1', '原生 IPv6 不动'); assert.equal(norm('::FFFF:10.0.0.1'), '10.0.0.1', '大写前缀也认'); });