跳转至

前端 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):

 *   node .scratch/ispublicip-test.js

本工具不接受任何命令行参数:

参数 类型 默认值 说明
(无) — — 不读 process.argv、不读环境变量;全部输入为源码内置用例

无参数时的默认行为:跑完 U.isPublicIp/ipKind/ipMark/labelIp/extractIp 全部断言并打印结论。

示例

从仓库根目录执行:

node deploy/nfos/tools/ispublicip-test.js

期望输出(实测:检查项 59、失败 0,末行 ALL_PASS):

== U.isPublicIp / U.ipKind 边界 ==
  ok   ipKind("10.0.0.1") = private
  ...
检查项 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 或任何其它文件;
  • 无需清理。