前端 IP 口径离线自测(ispublicip-test.js)¶
位置:
deploy/nfos/tools/ispublicip-test.js| 语言:node(CommonJS,.js) | 是否需要 root:否
工具性质:离线自测(不需要浏览器/jsdom;不写任何文件)
运行前提:仓库检出必须在场 —— 读 apps/web/online/js/core/config.js。可从任意位置运行(工具自动向上找到含 deploy/nfos 的祖先目录)
部署状态:随仓库检出运行,不部署到 /opt/Cy/services/system.d/nfos/
用途¶
对前端 NF.util 的地址口径做离线自测:isPublicIp / ipKind / ipMark / labelIp / extractIp。
源码头部注释(逐字引用):
/* 前端 NF.util 地址口径离线自测(不需要浏览器/jsdom,直接跑 core/config.js)。
*
* node .scratch/ispublicip-test.js
*
* 覆盖:与后端 deploy/nfos/monitoring/alert-enrich.py 同一份边界清单
* + U.extractIp 从 dedup_key/subject/证据文本里取 IP
*/
实现方式:用 vm.createContext 造一个最小上下文(window / document / location / sessionStorage / console / 定时器),在其中真实执行 config.js,然后取 window.NF.util 做断言。覆盖内容:
| 分组 | 覆盖内容 |
|---|---|
U.isPublicIp / U.ipKind 边界 |
26 组 IP(10/8、172.16-31、172.32、192.168、192.169、127、169.254、2001:db8::、fc00::/fd00::、fe80::、::1、::、2606:4700:4700::1111、组播 224./239.、255.255.255.255、0.0.0.0、::ffff: mapped、fe80::1%eth0、[2001:db8::1]) |
| 非法输入 | ''、null、undefined、abc、1.2.3.4:443、999.1.1.1、1.2.3、1.2.3.4.5、-、::gg → isPublicIp 为 false、ipKind 为 unknown |
| 标记 | ipMark('8.8.8.8') === '🌐公网'、ipMark('10.0.0.1') === '🏠内网'、ipMark('nope') === ''、labelIp('8.8.8.8') === '🌐公网 8.8.8.8'、labelIp('') === '' |
U.extractIp |
dedup_key 的 ip: 段、IPv6、subject 里的 IPv4、无 IP → 空、证据字段 对端=、按出现顺序取第一个、空输入/null |
末尾固定打印 检查项 <N>,失败 <M>,全通过时再打印 ALL_PASS。
典型场景¶
- 改动
apps/web/*/js/core/config.js里的地址判定(isPublicIp/ipKind/extractIp)之后的提交前回归; - 前后端口径对齐:与后端
alert-enrich-test.py覆盖同一份边界清单,任何一侧改了边界都应让另一侧的红/绿保持一致; - 前端告警列表把内网 IP 标成公网(或反之)、
extractIp从dedup_key取错 IP 时,在本地复现并定位边界。
用法与参数¶
源码头部给出的用法(逐字引用,.scratch/ 为升级前旧路径,本页按新位置书写为 node deploy/nfos/tools/ispublicip-test.js):
本工具不接受任何命令行参数:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| (无) | — | — | 不读 process.argv、不读环境变量;全部输入为源码内置用例 |
无参数时的默认行为:跑完 U.isPublicIp/ipKind/ipMark/labelIp/extractIp 全部断言并打印结论。
示例¶
从仓库根目录执行:
期望输出(实测:检查项 59、失败 0,末行 ALL_PASS):
| 情形 | 期望退出码 |
|---|---|
全部通过(检查项 N,失败 0 + ALL_PASS) |
0 |
存在失败项(逐条列出 FAIL ...) |
1 |
config.js 缺失 / 加载抛异常 |
1(Node 异常栈,非自检语义) |
依赖与权限¶
- 语言/版本:Node.js(CommonJS,
require('fs')/path/vm)。 - 第三方依赖:无;不需要浏览器或 jsdom。
- 仓库依赖:必需 —— 读取
<repo>/apps/web/online/js/core/config.js。仓库根由一个 IIFE 向上探测:fs.existsSync(path.join(d, 'deploy', 'nfos'))成立即返回该目录,一路到根仍找不到时回落为path.resolve(__dirname, '..')。 - 权限:不需要 root、不需要写权限、不需要网络(纯只读)。
风险与注意事项¶
- 纯离线只读:不写文件、不联网、不起服务;只在
vm上下文里执行config.js。 - 只读且只测
online站点的那一份config.js:硬编码路径为apps/web/online/js/core/config.js。若其它站点的config.js是独立副本,本自测不覆盖它们(需另行扩展)。 - 宿主的
console/定时器被透传进沙箱:console、setTimeout、clearTimeout直接引用宿主实现,sessionStorage是空实现(setItem空函数、getItem恒null),因此依赖 sessionStorage 的逻辑在沙箱里都是“无值”分支。 - 断言锁定文案与 emoji(
🌐公网/🏠内网)与边界口径(如203.0.113.77按公网、::ffff:8.8.8.8按公网);有意调整口径时需同时改后端alert-enrich-test.py,否则前后端自测会出现一侧红一侧绿。 - 终端编码:断言里的 emoji 由 Node 以 UTF-8 写出,不会像 Python 那样抛
UnicodeEncodeError;但在 GBK 代码页的 Windows 控制台里可能显示为乱码,断言本身仍正常执行,不影响退出码。 extractIp有一例专门锁定“按出现顺序取第一个”(本地=127.0.0.1:39210 对端=45.9.148.7:443→127.0.0.1),这与后端ip_from_dedup的“兜底取 IP”策略不同,属有意差异,不要“顺手对齐”。
回滚¶
本工具不部署到线上、不改线上系统,且不产出任何文件:
- 无输出文件、无临时目录、无状态文件、无缓存;
- 不改动
config.js或任何其它文件; - 无需清理。