net-connector 0.4.1 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -0
- data/CONTRIBUTING.md +40 -0
- data/README.md +61 -9
- data/SECURITY.md +11 -0
- data/docs/VERIFICATION.md +129 -6
- data/docs/architecture.md +184 -7
- data/lib/net/connector/device/base.rb +11 -4
- data/lib/net/connector/device/running_config.rb +2 -0
- data/lib/net/connector/engine/command.rb +14 -2
- data/lib/net/connector/engine/configuration.rb +10 -7
- data/lib/net/connector/engine/dialogue.rb +52 -28
- data/lib/net/connector/engine/errors.rb +40 -55
- data/lib/net/connector/engine/execution.rb +32 -5
- data/lib/net/connector/engine/log.rb +11 -9
- data/lib/net/connector/engine/session.rb +38 -7
- data/lib/net/connector/engine/terminal_renderer.rb +7 -4
- data/lib/net/connector/netdisco/batch.rb +31 -3
- data/lib/net/connector/netdisco/cli.rb +73 -31
- data/lib/net/connector/netdisco/client.rb +206 -73
- data/lib/net/connector/netdisco/config_file.rb +26 -4
- data/lib/net/connector/netdisco/diagnostic.rb +91 -0
- data/lib/net/connector/netdisco/fleet.rb +103 -60
- data/lib/net/connector/netdisco/inventory_budget.rb +49 -0
- data/lib/net/connector/netdisco/report.rb +94 -0
- data/lib/net/connector/netdisco/rules.rb +28 -5
- data/lib/net/connector/netdisco/settings.rb +194 -85
- data/lib/net/connector/netdisco/worker.rb +26 -17
- data/lib/net/connector/operations/backup_lock.rb +116 -0
- data/lib/net/connector/operations/local_backup.rb +49 -9
- data/lib/net/connector/operations/parse_output.rb +20 -3
- data/lib/net/connector/operations/private_file.rb +94 -5
- data/lib/net/connector/operations/safe_file.rb +62 -0
- data/lib/net/connector/operations/saved_config/legacy_index.rb +109 -0
- data/lib/net/connector/operations/saved_config.rb +40 -10
- data/lib/net/connector/operations/tftp/file_upload.rb +14 -1
- data/lib/net/connector/operations/tftp_backup.rb +78 -15
- data/lib/net/connector/operations/tftp_receipt.rb +73 -0
- data/lib/net/connector/operations/topology/immediate_strategy.rb +45 -0
- data/lib/net/connector/operations/topology/strategy.rb +20 -0
- data/lib/net/connector/operations/topology.rb +97 -29
- data/lib/net/connector/operations.rb +6 -0
- data/lib/net/connector/vendor/cisco_ios/tftp_backup.rb +9 -2
- data/lib/net/connector/vendor/cisco_ios/topology.rb +10 -4
- data/lib/net/connector/vendor/cisco_nxos/tftp_backup.rb +8 -1
- data/lib/net/connector/vendor/h3c/tftp_backup.rb +5 -0
- data/lib/net/connector/vendor/h3c/topology.rb +9 -4
- data/lib/net/connector/vendor/hillstone/tftp_backup.rb +12 -3
- data/lib/net/connector/vendor/hillstone/topology.rb +9 -4
- data/lib/net/connector/vendor/huawei/tftp_backup.rb +6 -0
- data/lib/net/connector/vendor/palo_alto/tftp_backup.rb +14 -5
- data/lib/net/connector/vendor/palo_alto/topology.rb +7 -2
- data/lib/net/connector/vendor/radware/tftp_backup.rb +9 -2
- data/lib/net/connector/vendor/radware/topology.rb +1 -0
- data/lib/net/connector/version.rb +1 -1
- metadata +35 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 270bbad958cd8e550f509079506edbc5af22c0875d80da8c21dc62dc14429517
|
|
4
|
+
data.tar.gz: a5954b6dac0c7b127789c332cbe70ef112dcb527b0b0c52d82134f9c06f863a7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7e56210010899199028a1cff560bd1fd333938537f317cc90d4c0d8e354c85e5182cee74cf71b887f6ac08e1e28853a77a945da14c66e4e40daf4be6e5f1e7fa
|
|
7
|
+
data.tar.gz: 0d431b190d4abc3fcefcb9cb992863ff19f940dfeecdc5841388f16ce774280d3c26eaee3831c94177edb9c696ed5e8a056d3498260de0a6a84311983bdea52d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,39 @@
|
|
|
1
1
|
# 更新记录
|
|
2
2
|
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.4.2 - 2026-09-27
|
|
6
|
+
|
|
7
|
+
- 增加带 Ruby/依赖版本和未命中位置的覆盖率 JSON,以 NC-00 实测计数检查同环境覆盖率不下降;CI 分别保存平台报告,并检查最低 expect-pty/textfsm 组合的全量测试及隔离安装。
|
|
8
|
+
- 补充厂商合成证据索引、完整/截断 PAN-OS 引号回归及公开方法返回/抛错契约,区分响应完成、状态读回和持久化确认;协作取消及 TFTP 服务端核验明确列为后置可选项。
|
|
9
|
+
|
|
10
|
+
- 新增离线内存基准,分开记录响应、渲染、清理、解析、结果保留及聚合输出成本,保留机器和原始统计;小型正确性烟测进入本地 CI。
|
|
11
|
+
- 新增可选 `max_script_output_bytes`(默认 nil),主命令和追加查询累计原始响应字节,发送前及完成后检查;超额仍保留已完成步骤,停止后续命令,不自动重试。YAML/ENV/CLI 与不可变批次策略接入,原单响应上限不变。
|
|
12
|
+
- 批量备份共享惰性的旧命名文件索引:规范文件全命中时不扫描,迁移目录每批最多扫描一次,新批次刷新;旧文件身份在读取前后变化时明确失败,保留规范路径优先和歧义拒绝。
|
|
13
|
+
- Netdisco 入口和离线导出延迟加载 TextFSM;解析严格校验原文与终端编辑后的 UTF-8,非法字节返回 `invalid_output_encoding`,不继续生成记录或拓扑计划。日志显示和原始备份字节保持原行为。
|
|
14
|
+
- 保留默认 strict 成功规则和旧 JSON;新增显式 selected 策略及 v2 Report 包装。selected 只允许过滤/采样跳过,部分成功、其他跳过、未知状态和回调/报告故障仍阻止成功;独立显示策略结果与清单覆盖,旧 Batch/Outcome 的 Data 成员不变。
|
|
15
|
+
- v2 诊断只接受受控错误码、类型、阶段和匹配产物回执,不携带异常原消息、输出、命令、source 或 line。设备和 v2 批次耗时改用单调时钟,UTC 审计时间保留;旧自定义 ResultStore 的 write 签名不变。
|
|
16
|
+
- TFTP 内置厂商参数在源文件探测前预检,探测、上传及完成回执共用一次会话租约。旧扩展策略保持调用契约,重写脚本后需显式实现新钩子才能启用相应预检和来源声明。
|
|
17
|
+
- 新增组合式 `TftpReceipt` 与 `tftp_backup_receipt`,保留原 `TftpBackup` 三成员接口,明确配置来源、格式及 requested/actual 路径;默认仍是 device_reported,没有服务器摘要。已确认上传后的日志/清理失败携带安全回执,Fleet 标为 reported_with_error;实际路径异常单独诊断,不自动重传。
|
|
18
|
+
- TFTP 批量示例在实际路径未确认时停止服务器文件核验,避免把计划文件名对应的其他备份误报为本次上传结果。
|
|
19
|
+
- 拓扑描述改写按“修改并退出视图 → 读回 → 保存”执行,读回不匹配、解析不完整或查询与审批不同均不保存。计划命令新增读回序列,旧计划必须重新生成;完成步骤跨阶段保留,stale_plan 的写入前异常契约不变。
|
|
20
|
+
- 保存需要明确的设备完成消息,超时或缺少证据返回 persistence_unconfirmed,不自动重放或回滚。现有会话租约覆盖全部阶段及间隙,未实现分阶段契约的自定义策略暂只允许读取。
|
|
21
|
+
- PAN-OS 自动描述计划及改写在 I/O 前以 candidate_isolation_unavailable 拒绝,能力查询返回 false;待目标固件的候选归属、锁与提交协议通过实验后再开启,只读邻居与描述查询保留。
|
|
22
|
+
- 本地备份在采集前获取跨实例/进程的私有路径锁,默认争用返回 `backup_busy`,可显式有限等待。统一目录、大小写和 Unicode 别名;锁文件长期保留。锁必须在会话租约外获取,已有租约内调用 `backup` 会返回 `SessionBusy`。
|
|
23
|
+
- 旧备份比较和离线读取通过同一个 `NOFOLLOW` 文件描述符检查类型与读取;保留直接备份安全替换末级符号链接、Fleet/离线入口拒绝符号链接的原有区别。
|
|
24
|
+
- 私有写入增加父目录同步及阶段回执。替换后失败保留已知产物,Fleet 标为部分成功,报告保留已提交位置;目录同步不支持单独报错。`Backup`/`Outcome`/`Batch` 成员、默认 JSON 和 strict 成功规则保持不变。
|
|
25
|
+
- Netdisco 清单增加单响应/累计字节、设备数和总期限预算,认证、分页与兼容查询共享计数;默认 HTTP 在下载过程中检查并关闭超额连接,失败不执行部分清单。旧 requester 回调保留,阻塞由调用方负责;HTTP 默认兼容,新增显式禁止明文的配置。
|
|
26
|
+
- 批次开始时冻结非敏感设置,执行中 ENV 修改只影响新批次,设备凭据仍逐台动态解析。集中预检协议、主机密钥、日志、采样和清单预算;CLI > ENV > YAML > 默认值的优先级明确,离线导出不要求清单配置。自定义凭据解析器仍可显式覆盖连接默认值。
|
|
27
|
+
- 复用 expect-pty 的公共 `Expect::Redactor`,移除连接器重复的字节匹配、重叠合并和分片算法,只保留秘密作用域与输出敏感性策略。依赖要求调整为 `~> 0.5.0`,使用已正式发布的公共接口。
|
|
28
|
+
- 配置采集默认将响应正文视为敏感数据:所有厂商的采集、候选差异、追加查询及结果清理异常均不把配置正文传入 text/debug/raw 日志、外部 logger 或错误诊断。`running_config.value!`、已完成步骤与本地备份保留原始业务内容。
|
|
29
|
+
- `Command` 增加独立的 `output_sensitive: false` 标记和 `output_sensitive?` 查询,`with_text` 保留该标记。手写采集命令可显式启用;包含秘密的命令文本仍需 `sensitive: true`。敏感范围结束后恢复普通命令诊断,不长期登记配置正文。
|
|
30
|
+
|
|
31
|
+
- 核心引擎、脱敏与错误处理(含 `Redactor`)、批量并发分别要求行和分支覆盖率均达到 80%;关键文件未测量时失败,并列出全部未加载库文件。测试、CI 与发布预检共用门槛。
|
|
32
|
+
- 在 `engine/` 和 `netdisco/` 启用方法长度 40、ABC 复杂度 60 的检查;拆分响应读取、CLI、清单规则校验和工作线程的职责。
|
|
33
|
+
- 补充连接恢复、传输参数、终端控制字符、覆盖率退出状态等边界测试,统一会话错误输出的 4096 字节截断逻辑,保持先脱敏后截断。
|
|
34
|
+
- TFTP 文件名在字节截断前明确拒绝非 ASCII 清单标签,保留合法 ASCII 路径和原有长度限制。
|
|
35
|
+
- 新增安全上报及贡献指南,并随 gem 分发;记录关键依赖的维护核对、替代方案边界及厂商、模板、调度等候选工作。
|
|
36
|
+
|
|
3
37
|
## 0.4.1 - 2026-09-27
|
|
4
38
|
|
|
5
39
|
- 用 Ruby 标准库 `Logger` 替代 ActiveSupport 日志依赖,保留设备标记、级别、脱敏和注入日志器的所有权。
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# 参与开发
|
|
2
|
+
|
|
3
|
+
请先阅读 [README](README.md) 和[架构文档](docs/architecture.md),在源码检出目录中开发。问题和 PR 可使用中文或英文;涉及凭据泄露或可利用漏洞时,使用 [SECURITY.md](SECURITY.md) 中的私密渠道。
|
|
4
|
+
|
|
5
|
+
## 本地检查
|
|
6
|
+
|
|
7
|
+
需要 Ruby 3.2 及以上版本、POSIX 环境和 Git。安装依赖后运行完整预检:
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bundle install
|
|
11
|
+
script/ci
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
也可使用 `bundle exec rake release:check`;它执行同样的检查,不上传发布包。首次运行需要联网下载依赖、Gitleaks 和 actionlint。检查包含敏感数据扫描、RuboCop、工作流校验、测试、gem 白名单与隔离安装,以及本地 PTY 烟测。它不会连接真实设备。
|
|
15
|
+
|
|
16
|
+
开发中可直接运行一个测试文件:
|
|
17
|
+
|
|
18
|
+
```sh
|
|
19
|
+
bundle exec ruby -Ilib -Itest test/engine_reliability_test.rb
|
|
20
|
+
bundle exec rake lint
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
提交前执行完整的 `bundle exec rake test` 或 `script/ci`。完整测试会检查核心引擎、脱敏与错误处理、批量工作线程各组的行和分支覆盖率,两项均不得低于 80%;任何关键文件没有覆盖率数据也会失败。只运行一个文件不能代替这个门槛,详细口径见[验证文档](docs/VERIFICATION.md)。
|
|
24
|
+
|
|
25
|
+
## 代码与测试约定
|
|
26
|
+
|
|
27
|
+
- `engine/` 与 `netdisco/` 启用 `Metrics/MethodLength`(40)和 `Metrics/AbcSize`(60)。超限时按职责拆分,不添加目录豁免或提高阈值来掩盖增长。
|
|
28
|
+
- 复用现有 Ruby 对象、不可变档案和厂商策略。复杂的资源所有权、锁、截止时间及脱敏生命周期继续用中文注释说明原因。
|
|
29
|
+
- 测试应证明业务行为:失败不覆盖备份、中断释放全部资源、命令不自动重放、错误不泄露凭据。并发测试用队列等同步手段控制执行顺序。
|
|
30
|
+
- 使用虚构凭据和 `192.0.2.0/24` 等文档地址。不要提交设备配置、备份、私有地址或日志;扫描规则同样适用于测试和示例。
|
|
31
|
+
- 行为或公开契约变更写入 `CHANGELOG.md` 的 `Unreleased`,同步修改相应文档。保留与本次任务无关的工作区改动。
|
|
32
|
+
|
|
33
|
+
## 增加厂商或模板
|
|
34
|
+
|
|
35
|
+
1. 在 `lib/net/connector/vendor/<厂商>.rb` 声明提示符、命令、交互及策略绑定,并在设备注册入口登记厂商键。已有规则可直接复用,差异逻辑放在该厂商目录中。
|
|
36
|
+
2. 只声明实际实现并经过验证的能力。配置采集覆盖登录、分页、完整提示符、失败响应、空配置和视图恢复;TFTP 需要明确的上传完成证据;拓扑变更还需要计划重验与回读。
|
|
37
|
+
3. 新 TextFSM 模板放入 `lib/net/connector/templates/`,按需更新 `index`。提供脱敏的正常、空表、畸形与部分输出样本,验证字段和完整性判断;注明样本的设备系列、固件及来源许可。
|
|
38
|
+
4. 补齐对应测试及能力矩阵,运行完整预检,确认模板进入实际构建的 gem。现场验证应在 PR 中注明环境和结果,模拟传输测试不能代替现场证据。
|
|
39
|
+
|
|
40
|
+
PR 请说明具体问题、修改后的行为、验证命令及仍未验证的范围。仓库的 PR 模板和[发布文档](docs/RELEASING.md)提供交付约定。
|
data/README.md
CHANGED
|
@@ -4,7 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
代码按职责组织:`engine/` 管理会话、传输、脚本、结果和日志;`device/` 提供设备入口、档案、运行配置和接口名称处理;`vendor/<厂商>/` 保存各厂商的采集、TFTP 和拓扑规则;`operations/` 实现公共业务流程;`netdisco/` 负责清单和批量编排。相同规则直接复用,设计说明见[架构文档](docs/architecture.md)。用 `require "net/connector"` 加载设备 API,用 `require "net/connector/netdisco"` 加载 Netdisco 集成;厂商规则和 TextFSM 解析器按需加载。
|
|
6
6
|
|
|
7
|
-
支持 Ruby 3.2 及以上版本和 POSIX 系统。SSH 调用本机 OpenSSH,Telnet 需要本机安装 `telnet` 并显式选择。主要依赖为 [`expect-pty`](https://rubygems.org/gems/expect-pty) 0.
|
|
7
|
+
支持 Ruby 3.2 及以上版本和 POSIX 系统。SSH 调用本机 OpenSSH,Telnet 需要本机安装 `telnet` 并显式选择。主要依赖为 [`expect-pty`](https://rubygems.org/gems/expect-pty) 0.5.x 和 [`textfsm`](https://rubygems.org/gems/textfsm) 0.2.x。
|
|
8
|
+
|
|
9
|
+
脱敏直接复用 expect-pty 从 0.5.0 起公开的 `Expect::Redactor` 接口;连接器只管理秘密作用域和配置输出的隐私策略。
|
|
8
10
|
|
|
9
11
|
## 安装
|
|
10
12
|
|
|
@@ -45,7 +47,11 @@ Net::Connector.open(:cisco_ios,
|
|
|
45
47
|
end
|
|
46
48
|
```
|
|
47
49
|
|
|
48
|
-
`open` 会在代码块结束或出错时关闭会话。`backup`
|
|
50
|
+
`open` 会在代码块结束或出错时关闭会话。`backup` 在采集前取得目标路径锁,持有到比较、保存和生成原有 `Backup` 元数据对象完成;采集失败不会覆盖旧备份。同路径争用默认立即抛出 `BackupBusy`(`code: :backup_busy`),需要有限等待可传 `lock_timeout: 2`,单位为秒。直接调用 `backup`;不要在已有 `with_operation` 会话租约内调用,否则会因锁顺序返回 `SessionBusy`。
|
|
51
|
+
|
|
52
|
+
写入使用 `0600` 临时文件、文件同步、原子替换及父目录同步。替换后同步或收尾失败会抛出 `BackupPersistenceError`,`error.backup` 保留已写文件的元数据,`error.receipt` 区分 `:committed`(持久性未确认)和 `:durable`(同步已完成)。目录同步不受支持对应 `:backup_durability_unsupported`,不会静默报告持久化成功,也不会自动重做设备采集。
|
|
53
|
+
|
|
54
|
+
调用方应创建并保护备份目录,运行配置可能含有设备凭据。同目录下的 `.net-connector-<摘要>.lock` 是私有的长期锁文件,正常释放不删除它。所有写入者须使用本库的锁协议;`NOFOLLOW` 不保护被外部替换的祖先目录。锁名保守合并大小写及 Unicode 等价写法,实际备份文件名不变;在区分大小写的文件系统上,这些名称也会串行。
|
|
49
55
|
|
|
50
56
|
## 设备发起的 TFTP 备份
|
|
51
57
|
|
|
@@ -63,10 +69,16 @@ end
|
|
|
63
69
|
|
|
64
70
|
只有设备回显确认传输完成,方法才返回 `TftpBackup(server:, path:, completed_at:)`。明确失败对应 `:transfer_failed`,缺少成功证据对应 `:transfer_unconfirmed`。本方法不读取服务器上的文件。TFTP 不加密配置数据,应限制在合适的管理网络中使用。
|
|
65
71
|
|
|
72
|
+
需要来源和格式时,调用 `device.tftp_backup_receipt(...)`,参数与旧入口相同。返回的不可变 `TftpReceipt` 包含原 `transfer`,以及 `configuration_kind`、`source_file`、`format`、`requested_path`、`actual_path`、`verification` 和 `server_sha256`。当前验证等级为 `:device_reported`,摘要为 `nil`。H3C 自动探测结果标为 `:startup`;H3C/华为显式文件标为 `:saved_file`,格式为 `:unknown`,不凭扩展名推断内容。山石未指定文件名时 `requested_path` 为 `nil`,`actual_path` 保留设备生成名称。
|
|
73
|
+
|
|
74
|
+
内置策略先校验参数组合,再在同一次会话租约中完成源探测、上传、证据检查和收尾。上传已确认但日志或清理失败时抛出 `TftpCompletionError`,通过 `error.receipt` 和 `error.transfer` 保留完成事实。显式请求与实际路径不同返回 `:transfer_path_mismatch`;实际路径无法安全确认返回 `:transfer_path_unconfirmed`,此时回执的 `actual_path` 和 `transfer.path` 为 `nil`。这些错误不会自动重传;Fleet 保留上传事实并标为 `reported_with_error`。原 `TftpBackup` 的三个成员和构造方式不变。
|
|
75
|
+
|
|
66
76
|
可运行[单设备示例](examples/tftp_backup.rb)。它从环境变量读取 `DEVICE_VENDOR`、`DEVICE_HOST`、`DEVICE_USERNAME`、`DEVICE_PASSWORD` 和 `TFTP_HOST`;`TFTP_SOURCE_FILE`、`TFTP_PATH`、`TFTP_VRF` 分别指定源文件、目标文件和设备 VRF。
|
|
67
77
|
|
|
68
78
|
只需在内存中采集配置时,调用 `device.running_config`;它返回 `Result`,`result.value!` 返回清理后的文本,失败时抛出对应错误。
|
|
69
79
|
|
|
80
|
+
配置采集默认屏蔽日志和错误诊断中的配置正文,包括 debug/raw 日志和外部 logger;返回的配置、步骤输出和备份内容保持完整。调用方应按敏感数据保管这些业务结果。
|
|
81
|
+
|
|
70
82
|
## TextFSM 解析
|
|
71
83
|
|
|
72
84
|
`parse_command` 执行一条命令,再按厂商和命令选择 TextFSM 模板。内置索引覆盖 Cisco IOS 的 `show ip interface brief`,以及拓扑发现使用的 CDP/LLDP 命令:
|
|
@@ -92,6 +104,8 @@ saved = Net::Connector::Operations::SavedConfig.new(directory: "/var/backups")
|
|
|
92
104
|
rows = saved.parse(host: "192.0.2.10", template: "/path/to/template.textfsm")
|
|
93
105
|
```
|
|
94
106
|
|
|
107
|
+
解析默认严格检查 UTF-8 字节,包括终端控制符处理前的原文和处理后的文本;非法字节会抛出 `ParsingError`(`code: :invalid_output_encoding`),不会转成替换文本继续生成记录或拓扑计划。库不猜测或自动转换其他编码,原始结果、备份和离线导出保持原字节。Netdisco 入口及纯文件导出不加载 TextFSM,实际解析时才加载。
|
|
108
|
+
|
|
95
109
|
## 邻居发现与接口描述
|
|
96
110
|
|
|
97
111
|
`neighbors` 在 Cisco IOS/NX-OS 上查询 CDP,在 H3C、H3C 无线、山石和 PAN-OS 上查询 LLDP。记录包含 `local_interface`、`neighbor_name`、`neighbor_interface`、`chassis_id` 和 `protocol`。H3C 会按表头选择不同列顺序的模板;未知输出会抛出 `ParsingError`,不会误判为空表。`interface_descriptions` 从运行配置读取当前描述,Radware 则从配置转储读取端口名称。
|
|
@@ -110,7 +124,11 @@ end
|
|
|
110
124
|
|
|
111
125
|
默认描述为 `To <邻居名称> <邻居接口简称>`。接口缩写默认开启并保留大小写:`ethernet1/1` 变为 `eth1/1`,`Ethernet1/1` 变为 `Eth1/1`,`GigabitEthernet1/0/1` 变为 `Gi1/0/1`;未知形式保持原样。原始邻居记录、计划证据和本机下发接口名不会被缩写。`abbreviate: false` 关闭缩写,`lowercase: true` 才会转为小写;也可传入代码块自行生成完整描述。公共纯函数是 `Net::Connector::InterfaceDescription.format`。
|
|
112
126
|
|
|
113
|
-
规划会拒绝歧义邻居、缺少对端身份、不安全文本和无法识别的输出。下发必须传 `confirmed: true
|
|
127
|
+
规划会拒绝歧义邻居、缺少对端身份、不安全文本和无法识别的输出。下发必须传 `confirmed: true`,操作会再次读取邻居和旧描述;证据变化在写入前抛出 `DeviceError`,其 `code` 为 `:stale_plan`。IOS/NX-OS、H3C 和山石采用“修改 → 退出配置视图 → 读回 → 保存”的顺序;读回不匹配返回 `:description_unconfirmed`,解析不完整或查询命令不符合审批时也不会保存。
|
|
128
|
+
|
|
129
|
+
`plan.commands` 现在包括读回命令,旧版计划必须重新生成、审核;执行仍返回 `Result`,保留修改、读回及保存阶段已经完成的步骤。只有设备提供明确保存完成行才成功,保存超时、失败或只有提示符会返回 `:persistence_unconfirmed`,此时描述可能已生效,不能自动重放或回滚。现场下发前仍应按设备固件核对命令与回显。
|
|
130
|
+
|
|
131
|
+
PAN-OS 的自动描述计划及改写暂不提供,`supports?(:interface_description_changes)` 为 false,入口在设备 I/O 前抛出 `:candidate_isolation_unavailable`。候选配置的归属、验证及提交需要经目标固件实验确认的独立流程;目前可继续只读查询邻居和描述。Radware 支持读取端口名称,但不提供邻居发现或自动改写,其 `neighbors` 返回 `:neighbor_discovery_unsupported`。
|
|
114
132
|
|
|
115
133
|
PAN-OS 在导出前后检查候选配置差异,并拒绝 XML 或非 set 格式输出,避免将未提交配置误作运行配置。
|
|
116
134
|
|
|
@@ -137,8 +155,12 @@ end
|
|
|
137
155
|
|
|
138
156
|
`execute` 执行一条命令;`execute_script` 接收 `Script` 或命令数组;`Script.load(path)` 读取脚本文件。所有命令在设备 I/O 前校验,后续步骤失败时仍保留已完成结果,库不会自动重放命令。`save_config` 显式执行厂商保存命令,普通脚本不会自动保存。
|
|
139
157
|
|
|
158
|
+
创建连接器时可设置 `max_script_output_bytes: 8 * 1024 * 1024`,限制每个脚本及其追加查询累计收到的原始响应字节;默认 `nil` 保持原有完整输出行为。达到上限后不再发送下一命令,当前响应超过上限时保留刚完成的步骤并返回 `ScriptOutputLimitExceeded`(`code: :script_output_limit_exceeded`)。命令可能已经执行,不会自动重试。原有 `max_output_bytes` 继续限制单次读取响应;累计预算不是进程内存上限,详细计数规则见架构文档。
|
|
159
|
+
|
|
140
160
|
厂商档案处理分页和常见确认提示。特定命令可给 `execute` 传入 `interactions: [Net::Connector::Interaction.new(/Token:\z/, ->(_) { "value\n" }, sensitive: true)]`。敏感命令及交互会暂停回显日志并在错误中脱敏;若普通命令文本包含秘密,必须显式标记 `sensitive: true`。
|
|
141
161
|
|
|
162
|
+
命令文本安全、输出可能包含秘密时,使用 `device.execute("show running-config", output_sensitive: true)`。该标记保护响应及其准备、后处理、回调异常,保留安全命令文字;不会改写 `Result` 的业务输出。`running_config` 和 `collect_config` 自动启用此保护,手写脚本的默认值仍为 `false`。
|
|
163
|
+
|
|
142
164
|
## 连接与日志设置
|
|
143
165
|
|
|
144
166
|
`Configuration` 支持 `protocol: :ssh`(默认)或 `:telnet`,以及端口、超时、输出大小、`log_file`、`logger`、`log_format`、`log_level` 和 `known_hosts` 等参数。文本日志使用 Ruby 标准库 `Logger`,记录本地时间、级别、设备标记和中文事件。`:info` 记录连接、登录、命令和 TFTP 结果;`:debug` 还记录脱敏回显与耗时;`:warn`、`:error` 只保留相应级别。`:raw` 文件只写设备字节,不写事件元数据。可注入 `logger: Rails.logger`,连接器不会关闭或修改调用方的日志器。
|
|
@@ -149,11 +171,19 @@ end
|
|
|
149
171
|
|
|
150
172
|
`Net::Connector::Netdisco` 读取并验证完整清单,再将支持的记录映射到连接器,使用有上限的工作线程执行备份。Netdisco 只提供清单字段;设备凭据来自环境变量或调用方提供的解析器。清单会在连接任何设备前完成校验;不支持、被过滤、重复、缺少凭据、失败,以及保存成功但关闭失败的结果分别保留。
|
|
151
173
|
|
|
152
|
-
`
|
|
174
|
+
每次 `Client#devices` 默认限制单响应 16 MiB、累计响应 128 MiB、去重前 100,000 条记录、10,000 页和 300 秒总期限。认证、分页及兼容查询共用这些预算;默认 HTTP 客户端逐块计数,超限会关闭连接并抛出带稳定 `code` 的 `Client::Error`,Fleet 不会执行半份清单。这些默认值是可调整的设计起点,不是实测容量。旧 `requester: ->(uri, request)` 仍可使用,但只能在回调返回后检查正文和期限,回调自身的阻塞及内存用量由注入方控制。
|
|
175
|
+
|
|
176
|
+
推荐使用 HTTPS,标准证书验证保持开启。为兼容既有部署,`allow_insecure_http` 默认仍为 `true`;设为 `false` 可在发请求前拒绝 HTTP,ENV 中对应 `NETDISCO_ALLOW_INSECURE_HTTP=false`。HTTP 会明文传输登录凭据和 API key,迁移时应先提供可验证的 HTTPS 端点。
|
|
177
|
+
|
|
178
|
+
`Fleet#plan_backup` 和 `Fleet#plan_tftp_backup` 从同一份清单生成计划。把计划传给 `backup_all(plan:)` 或 `tftp_backup_all(plan:)`,可使预览与执行选择同一批设备;计划与清单不符时会拒绝执行。单台设备异常或结果回调失败不会阻止其他设备。`batch.summary` 包含总数、成功、失败、部分成功、跳过、具体状态和逐台结果。部分成功包括已保存但关闭失败,以及本地文件已替换但目录同步或收尾失败;后者保留 backup 并标为 `saved_with_error`。TFTP 的 `reported_uploaded` 仅代表设备报告上传,不代表服务器文件已核验。
|
|
179
|
+
|
|
180
|
+
本地 `backup(path:)` 用 SHA-256 比较新旧配置,`backup.change` 返回 `:created`、`:changed` 或 `:unchanged`;内容未变且权限、文件身份正常时保留修改时间。这不补验历史写入的断电持久性。`backup_all` 的 `on_change:` 仅在新建或更改文件保存后触发;`on_start:` 和 `on_result:` 观察每台已尝试设备。回调异常记录在 `batch.callback_errors`,不丢弃设备结果。每项结果包含开始、结束和耗时。TFTP 无法比较服务器文件,因此没有 `change`,也不触发变更通知。
|
|
181
|
+
|
|
182
|
+
每批默认写入私有 JSON 报告,路径见 `batch.report_location`。调用方如有数据库仓储,可传 `ResultStore::Database.new(repository: YourModel)`;仓储需实现 `create!(attributes)`。`result_store: nil` 表示由调用方自行持久化。报告失败保留在 `batch.report_error`,同时使 `batch.success?` 为假。若报告已替换但目录同步失败,仍保留位置;离线 `--export --output` 遇到同类错误返回 2,并说明文件已经提交。
|
|
153
183
|
|
|
154
|
-
|
|
184
|
+
默认仍返回原 `Batch` 和原 JSON 字段。显式传 `report_schema: 2` 可获得 `Netdisco::Report`,通过 `report.batch` 访问原批次;`success?` 和 `status` 仍保留严格语义。新报告增加 `policy`、`policy_success`、清单覆盖和受控诊断。任务耗时使用单调时钟,UTC 开始/结束时间独立保留;墙钟调整不会产生负的设备耗时。已有批次可用 `batch.report(policy: :selected)` 创建 v2 视图,不会再次执行设备或重写已有报告。
|
|
155
185
|
|
|
156
|
-
|
|
186
|
+
`success_policy: :selected` 显式使用 v2:至少一台设备成功,其他记录只因 `filtered` 或 `sample_limit` 跳过,而且没有部分成功、回调或报告错误时,`report.policy_success?` 才为真。缺少凭据、重复地址、无效地址、未知厂商、目标冲突和未知状态均会阻止成功。`coverage.complete` 只表示每条清单记录都已尝试任务;失败任务也计入尝试,不能据此判断配置已保存。所有设备成功与否仍单独查看 `policy_success` 和逐台结果。自定义 `ResultStore#write(result, directory:)` 签名保持;选择 v2 时传入 Report,其 `summary` 为新格式。
|
|
157
187
|
|
|
158
188
|
```sh
|
|
159
189
|
export NETDISCO_URL=https://netdisco.example/netdisco
|
|
@@ -189,6 +219,12 @@ exit 1 unless batch.success?
|
|
|
189
219
|
netdisco:
|
|
190
220
|
url: https://netdisco.example/netdisco
|
|
191
221
|
page_size: 500
|
|
222
|
+
max_response_bytes: 16777216
|
|
223
|
+
max_inventory_bytes: 134217728
|
|
224
|
+
max_devices: 100000
|
|
225
|
+
max_pages: 10000
|
|
226
|
+
inventory_timeout: 300
|
|
227
|
+
allow_insecure_http: false
|
|
192
228
|
backup:
|
|
193
229
|
directory: /var/backups/network
|
|
194
230
|
concurrency: 4
|
|
@@ -198,6 +234,7 @@ inventory:
|
|
|
198
234
|
192.0.2.7: h3c_wireless
|
|
199
235
|
ssh:
|
|
200
236
|
host_key_policy: strict
|
|
237
|
+
max_script_output_bytes: null # 可选正整数字节数;null 保持不限制累计值。
|
|
201
238
|
tftp:
|
|
202
239
|
server: 192.0.2.10
|
|
203
240
|
vrfs:
|
|
@@ -215,7 +252,9 @@ net-connector-backup --config config.yml --export 192.0.2.7 --output ./exports/d
|
|
|
215
252
|
|
|
216
253
|
`--plan` 只拉取并验证清单;`--host` 选择一个管理地址;`--tftp` 默认每厂商最多选择五台,`--all` 选择所有就绪设备。本地备份默认选择所有就绪设备,可用 `--limit-per-vendor` 限制。`--show-config` 只输出有效的非敏感设置,不访问 Netdisco。CLI 会拒绝未知 YAML 字段、Ruby 对象标签及配置中的凭据。`--export IP` 离线读取已有 `<IP>.txt`,或唯一匹配的旧版 `<设备名>-<IP>.txt`;默认原样写到标准输出,指定 `--output` 后以 `0600` 权限原子写文件。导出的配置仍是敏感数据。
|
|
217
254
|
|
|
218
|
-
CLI 的计划与批次摘要使用 JSON
|
|
255
|
+
CLI 的计划与批次摘要使用 JSON。默认 `--success-policy strict` 保留原规则:非空清单且全部成功、回调及报告正常时为 `0`;空清单或有跳过、部分成功、失败时为 `1`;清单或配置错误为 `2`。`--host` 未在清单中找到也返回 `2`。由于其他清单记录会标记为过滤,默认单主机备份成功时批次退出码仍可能是 `1`;应查看 JSON 中的 `succeeded`、`skipped` 和逐台 `status`。
|
|
256
|
+
|
|
257
|
+
显式使用 `--success-policy selected` 后,CLI 按上述 selected 规则决定退出码,并自动输出/存储 v2 报告,保留 `status: incomplete` 与跳过计数,另列 `policy_success`。例如 `net-connector-backup --config config.yml --host 192.0.2.7 --success-policy selected`。仅想增加诊断时使用 `--report-schema 2`,成功策略仍为 strict;selected 不能配合 schema 1。策略和报告版本由本次 CLI/API 参数指定,不改变已批准的清单选择,也不触发重试。
|
|
219
258
|
|
|
220
259
|
小范围现场试运行可用[本地批量示例](examples/netdisco_backup.rb),默认每厂商最多三台;`NET_CONNECTOR_SAMPLE_PER_VENDOR` 可设为 1 至 5。设备发起 TFTP 上传可用[批量 TFTP 示例](examples/netdisco_tftp_backup.rb),默认每厂商最多五台;`NET_CONNECTOR_ALL=1` 才选择全部就绪设备,全量任务默认并发 50。`NET_CONNECTOR_CONCURRENCY` 可覆盖并发数。两类示例将结果和日志写入唯一的 `examples/backups/<UTC 时间戳>-<后缀>/` 目录,该目录不纳入 Git。
|
|
221
260
|
|
|
@@ -225,6 +264,8 @@ CLI 的计划与批次摘要使用 JSON。非空清单且全部成功时退出
|
|
|
225
264
|
|
|
226
265
|
本地配置备份写到 `<目录>/<IP>.txt`,IPv6 的 `:` 转成 `_`。设备改名不改变文件名或比较基线。若规范文件不存在,唯一匹配的旧版 `<设备名>-<IP>.txt` 可作比较基线但不会被改写;匹配多个旧文件时会明确失败。规范文件优先,符号链接和非普通文件会被拒绝。文件原子替换为 `0600`,新目录权限为 `0700`。批次在当前进程执行,需要定时任务或持久队列时由调用方安排;失败命令不会自动重试。
|
|
227
266
|
|
|
267
|
+
同批次的旧文件目录最多扫描一次,规范文件全命中时不扫描;新批次重建索引。索引只保留文件名和身份元数据,读取时再次核验;旧文件在快照后消失、替换或修改会返回 `SavedConfigChanged`(`code: :saved_config_changed`),该设备不继续采集。批次中新出现的旧名称文件到下一批才可见,规范文件始终优先。
|
|
268
|
+
|
|
228
269
|
| 环境变量 | 默认值 | 用途 |
|
|
229
270
|
| --- | --- | --- |
|
|
230
271
|
| `NETDISCO_URL` | 必填 | Netdisco 服务根地址,可包含租户路径 |
|
|
@@ -232,10 +273,17 @@ CLI 的计划与批次摘要使用 JSON。非空清单且全部成功时退出
|
|
|
232
273
|
| `NETDISCO_USERNAME`, `NETDISCO_PASSWORD` | 未提供 API 密钥时必填 | 清单 API 登录 |
|
|
233
274
|
| `NETDISCO_API_KEY` | 未设置 | 直接使用已有 API 密钥 |
|
|
234
275
|
| `NETDISCO_PAGE_SIZE` | `500` | 清单分页大小 |
|
|
276
|
+
| `NETDISCO_MAX_PAGES` | `10000` | 最大分页次数 |
|
|
277
|
+
| `NETDISCO_MAX_RESPONSE_BYTES` | `16777216` | 单次响应正文上限,认证和错误正文也计数 |
|
|
278
|
+
| `NETDISCO_MAX_INVENTORY_BYTES` | `134217728` | 一次清单调用的累计正文上限 |
|
|
279
|
+
| `NETDISCO_MAX_DEVICES` | `100000` | 去重前累计记录上限,兼容查询共用 |
|
|
280
|
+
| `NETDISCO_INVENTORY_TIMEOUT` | `300` | 整次清单调用的有限正数秒数 |
|
|
281
|
+
| `NETDISCO_ALLOW_INSECURE_HTTP` | `true` | 显式设为 `false` 拒绝明文 HTTP |
|
|
235
282
|
| `NET_CONNECTOR_DEVICE_USERNAME`, `NET_CONNECTOR_DEVICE_PASSWORD` | 未设置 | 设备登录默认凭据 |
|
|
236
283
|
| `NET_CONNECTOR_<VENDOR>_USERNAME`, `NET_CONNECTOR_<VENDOR>_PASSWORD` | 未设置 | 单厂商凭据,例如 `CISCO_IOS` |
|
|
237
284
|
| `NET_CONNECTOR_BACKUP_DIRECTORY` | `./backups` | 备份及默认报告目录 |
|
|
238
285
|
| `NET_CONNECTOR_CONCURRENCY` | `4` | 并发设备数,范围 1 至 50 |
|
|
286
|
+
| `NET_CONNECTOR_MAX_SCRIPT_OUTPUT_BYTES` | 未设置 | 每个脚本的累计响应上限;CLI `--max-script-output-bytes N` 优先 |
|
|
239
287
|
| `NET_CONNECTOR_INCLUDE_HOSTS`, `NET_CONNECTOR_EXCLUDE_HOSTS` | 未设置 | 逗号分隔的管理地址过滤器 |
|
|
240
288
|
| `NET_CONNECTOR_INCLUDE_VENDORS` | 未设置 | 逗号分隔的厂商标识过滤器 |
|
|
241
289
|
| `NET_CONNECTOR_VENDOR_OVERRIDES` | `{}` | Netdisco 厂商标签到连接器标识的 JSON 映射 |
|
|
@@ -254,7 +302,9 @@ CLI 的计划与批次摘要使用 JSON。非空清单且全部成功时退出
|
|
|
254
302
|
export NET_CONNECTOR_DEVICE_RULES='[{"vendor":"Cisco","model_prefix":"N9K","connector":"cisco_nxos"}]'
|
|
255
303
|
```
|
|
256
304
|
|
|
257
|
-
`
|
|
305
|
+
`Fleet` 每次规划或执行前通过 `Settings#snapshot(mode:)` 固定非敏感设置,包括筛选规则、目录、并发、协议、主机密钥、日志、TFTP 参数和清单预算。执行中修改 ENV 不改变当批策略;再次调用会读取新值。CLI 一次调用的规划与执行共用策略,优先级为 CLI > ENV > YAML > 默认值。`Settings#validate!(mode:)` 复用连接配置及 Planner 的枚举和范围规则;`--show-config` 会拒绝非法设置,`--export` 只验证离线目录,不要求清单地址或认证。
|
|
306
|
+
|
|
307
|
+
每台任务开始时仍读取设备凭据,`Settings.from_file` 也保留轮换能力。纯策略快照不保存密码、API key 或凭据解析器。需要让多次 API 调用共用策略时,可传 `Settings.new.for_run(mode: :backup)`。自定义 `credentials:` 解析器仍可逐设备返回连接设置,它显式给出的选项优先于批次默认值,由调用方负责一致性;注入的 `client:` 生命周期也由调用方管理。传入 `plan:` 的执行不会重新拉取或筛选已批准清单。`fleet.devices` 可在不连接设备时检查映射。
|
|
258
308
|
|
|
259
309
|
## 开发与验证
|
|
260
310
|
|
|
@@ -265,6 +315,8 @@ script/ci
|
|
|
265
315
|
|
|
266
316
|
CI 在 Linux 和 macOS 上覆盖 Ruby 3.2、3.3、3.4、4.0。`script/ci` 扫描源码与可用 Git 历史中的敏感数据,执行 Ruby 与工作流 lint、完整测试,并验证已构建 gem 的隔离安装和本地 PTY 烟测;不连接真实网络设备。首次运行需下载固定校验和的 Gitleaks 与 actionlint。
|
|
267
317
|
|
|
268
|
-
`bundle exec rake test`
|
|
318
|
+
`bundle exec rake test` 报告当前测试进程的行、分支覆盖率和未加载文件清单。核心引擎、脱敏与错误处理(含 `Redactor`)、批量工作线程分别要求行和分支覆盖率均达到 80%,关键文件没有覆盖率数据也会失败;该门槛同时阻止 CI 和发布预检通过。`bundle exec rake lint` 检查 Ruby 代码,并对 `engine/`、`netdisco/` 限制方法长度(40)和 ABC 复杂度(60)。`bundle exec rake security:check` 扫描敏感数据,`bundle exec rake release:check` 执行完整预检。构建产物和脱敏扫描报告保存在被忽略的 `tmp/` 下。
|
|
319
|
+
|
|
320
|
+
参与开发见 [CONTRIBUTING.md](CONTRIBUTING.md),漏洞报告见 [SECURITY.md](SECURITY.md)。实现注释和主要文档使用中文,欢迎中文或英文的问题与 PR。
|
|
269
321
|
|
|
270
322
|
真实凭据应放在环境变量和版本库外的本地配置中。检查范围、依赖政策和忽略规则见[验证文档](docs/VERIFICATION.md),发布流程见[发布文档](docs/RELEASING.md)。
|
data/SECURITY.md
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# 安全问题上报
|
|
2
|
+
|
|
3
|
+
请通过 GitHub 的[私密漏洞报告入口](https://github.com/gatework/net-connector/security/advisories/new)联系维护者。仓库已启用 Private vulnerability reporting;报告内容在协作披露前不会作为公开 Issue 发布。普通功能问题和使用疑问请提交 Issue。
|
|
4
|
+
|
|
5
|
+
报告中请提供受影响的 gem / Ruby / 操作系统版本、涉及的厂商与固件、最小复现步骤、预期和实际结果,以及可能影响的凭据、文件或设备操作。使用文档地址和虚构凭据重现;不要附上真实密码、令牌、私钥、完整生产配置或未经脱敏的会话日志。维护者会在私密报告中沟通复现、修复和披露安排。
|
|
6
|
+
|
|
7
|
+
凭据泄露、脱敏绕过、命令注入、主机密钥校验绕过、路径越界,以及中断后遗留设备操作等问题均适合私密报告。若发现已公开的真实凭据,请立即在对应系统撤销或轮换,并在私密报告中提供泄露位置;删除当前文件不能撤销已经分发的秘密。
|
|
8
|
+
|
|
9
|
+
修复优先面向最新发布版本。请尽可能确认问题是否仍存在于最新版本,并注明首次发现问题的版本;旧版本是否回补在具体报告中评估,不承诺每个历史版本都有维护分支。
|
|
10
|
+
|
|
11
|
+
Please [report vulnerabilities privately](https://github.com/gatework/net-connector/security/advisories/new). Include affected versions and a minimal reproduction with synthetic credentials. Reports in English or Chinese are welcome.
|
data/docs/VERIFICATION.md
CHANGED
|
@@ -15,16 +15,106 @@ script/ci
|
|
|
15
15
|
| 步骤 | 内容 |
|
|
16
16
|
| --- | --- |
|
|
17
17
|
| `security:check` | 扫描待提交源码和可用的完整 Git 历史;拒绝混入源码的本地凭据、配置和产物 |
|
|
18
|
-
| `lint` | 对库、脚本、示例、测试、Gemfile、gemspec 和 Rakefile 执行 RuboCop |
|
|
18
|
+
| `lint` | 对库、脚本、示例、测试、Gemfile、gemspec 和 Rakefile 执行 RuboCop;引擎及 Netdisco 方法上限为 40 行、ABC 60 |
|
|
19
19
|
| `lint:workflows` | 用 actionlint 校验 GitHub Actions 工作流 |
|
|
20
|
-
| `test` | 执行全部 Minitest
|
|
20
|
+
| `test` | 执行全部 Minitest,列出未加载文件,并执行关键模块的行与分支覆盖率门槛;敏感信息和发布测试使用临时文件、临时仓库与模拟远端响应 |
|
|
21
|
+
| `benchmark:smoke` | 每项 16 KiB 的合成工作负载,验证假传输、本地 PTY、配置清理、解析、结果保留与日志;只检查正确性,不按机器速度设门槛 |
|
|
21
22
|
| `package:verify` | 构建 gem,检查元数据、文件白名单、源文件字节和执行位,扫描解包内容及元数据,再进行隔离安装 |
|
|
22
23
|
|
|
23
24
|
隔离安装清除当前 Bundler 和 Ruby 注入变量,分别验证普通 `gem install`
|
|
24
25
|
和只有 `net-connector` 依赖的最小 Bundler 应用。烟测加载全部厂商,使用本地
|
|
25
26
|
PTY 子进程采集配置,读取包内 TextFSM 模板,并检查 CLI。它不连接网络设备,
|
|
26
27
|
也不证明现场设备协议或真实发布服务已验收。
|
|
27
|
-
|
|
28
|
+
|
|
29
|
+
## 配置输出隐私回归
|
|
30
|
+
|
|
31
|
+
`test/output_sensitive_test.rb` 使用每次运行新生成、不同于登录凭据的假秘密,
|
|
32
|
+
覆盖 text/info、text/debug、raw 和外部 logger;检查成功采集、控制符分片、
|
|
33
|
+
超时、输出超限、设备错误、厂商追加查询、命令替换、结果选择、清理异常和
|
|
34
|
+
日志器故障。断言包含错误 message/output、底层 message/backtrace、
|
|
35
|
+
`exception.full_message` 及 cause,同时核对完整结果、备份字节与 SHA-256。
|
|
36
|
+
还验证普通命令诊断恢复、失败重连、非局部退出及元数据复制。
|
|
37
|
+
|
|
38
|
+
`test/transport_test.rb` 另用本地 Ruby PTY 验证配置日志隔离、控制字符、
|
|
39
|
+
真实读取超时和子进程回收。厂商覆盖来自合成输出,固件范围为 unknown;
|
|
40
|
+
这些结果不构成真实设备、真实凭据或生产 TFTP 服务验收。
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
bundle exec ruby -Ilib:test test/output_sensitive_test.rb
|
|
44
|
+
bundle exec ruby -Ilib:test test/redaction_contract_test.rb
|
|
45
|
+
bundle exec ruby -Ilib:test test/transport_test.rb
|
|
46
|
+
bundle exec ruby -Ilib:test test/collection_contract_test.rb
|
|
47
|
+
bundle exec ruby -Ilib:test test/running_config_strategy_test.rb
|
|
48
|
+
bundle exec ruby -Ilib:test test/module_loading_test.rb
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
实施记录保存在源码树的 `docs/optimization/`,不进入 gem 发布白名单。
|
|
52
|
+
每个工作包的初始状态、已运行命令与未验证边界均以该记录中的日期和环境为限。
|
|
53
|
+
|
|
54
|
+
## 离线内存基准与累计预算
|
|
55
|
+
|
|
56
|
+
`bundle exec ruby script/benchmark_memory.rb --suite baseline --directory tmp/benchmarks/my-run`
|
|
57
|
+
逐个启动独立 Ruby 进程,报告 1/8/32 MiB 响应、1/10/100 命令、1/4/16 并发的
|
|
58
|
+
选定组合,不运行最大值的笛卡尔积。单个样本计划响应正文不得超过 128 MiB,
|
|
59
|
+
已有输出目录拒绝覆盖。较小的 `--suite smoke` 纳入 `rake ci`。
|
|
60
|
+
|
|
61
|
+
每个样本保留机器信息、实际依赖版本、源码摘要、外部 `/usr/bin/time` 原始统计,
|
|
62
|
+
以及各阶段的分配对象数、单调耗时、`ps` 测得的 RSS 端点。峰值是 time 的进程
|
|
63
|
+
高水位,不是 worker/PTY 子进程 RSS 总和;构造夹具和连接在阶段计时前完成,
|
|
64
|
+
仍计入进程峰值。GC 正常启用。默认日志采用 Configuration 默认值,另有显式
|
|
65
|
+
debug Logger 计数目标样本;不关闭协议检查、丢弃步骤或共享有状态 Parser。
|
|
66
|
+
|
|
67
|
+
响应构造、终端渲染、配置清理、解析、完整采集与步骤保留分别计量。
|
|
68
|
+
`Result#output` 单次与重复调用单列,不把对象分配数误当字节数,也不据一次采样
|
|
69
|
+
承诺内存降低比例。带 `--script-budget-bytes N` 的 retain 样本同时验证预算失败
|
|
70
|
+
及保留输出;它执行的命令较少,不能与完整脚本称为相同工作量的性能提升。
|
|
71
|
+
基准脚本和原始实施记录不进入运行 gem。
|
|
72
|
+
|
|
73
|
+
`test/script_output_budget_test.rb` 覆盖默认关闭、精确边界、多字节、分页的原始字节、
|
|
74
|
+
各类钩子追加查询、提示符回调、异常被吞掉后仍失败、故障位置、完整步骤、新脚本
|
|
75
|
+
重置、原单响应限制及 TFTP 回执。输出隐私矩阵保留日志和原始结果双向断言,
|
|
76
|
+
真实 PTY 测试核对关闭和 waitpid 回收;设置测试验证优先级、批内不变及离线导出。
|
|
77
|
+
|
|
78
|
+
## 覆盖率与复杂度门槛
|
|
79
|
+
|
|
80
|
+
`script/coverage.rb` 在测试加载源码前启动 Ruby `Coverage`,由
|
|
81
|
+
`script/coverage_report.rb` 检查以下三个组。各组分别按实际可执行行、分支
|
|
82
|
+
累计命中比例,不取文件百分比的平均值,不先四舍五入再判断。
|
|
83
|
+
|
|
84
|
+
| 组 | 文件范围 | 行 / 分支最低覆盖率 |
|
|
85
|
+
| --- | --- | --- |
|
|
86
|
+
| 核心引擎 | `lib/net/connector/engine/**/*.rb` | 80% / 80% |
|
|
87
|
+
| 脱敏与错误处理 | `lib/net/connector/engine/errors.rb`,包含 `Redactor` | 80% / 80% |
|
|
88
|
+
| 批量并发 | `lib/net/connector/netdisco/worker.rb` | 80% / 80% |
|
|
89
|
+
|
|
90
|
+
关键组为空、任一关键文件未测量或组内没有可执行行时均失败。没有分支的组
|
|
91
|
+
不需要分支命中,但仍须通过行覆盖率及文件加载检查。
|
|
92
|
+
全库输出中的“未加载文件”表示当前测试进程没有采集到数据:可能只在隔离
|
|
93
|
+
子进程中加载,也可能在覆盖率启动前被 Bundler 加载,不等同于从未测试。
|
|
94
|
+
报告会逐项列出路径,不自动预加载源码,也不把子进程覆盖率并入主进程。
|
|
95
|
+
|
|
96
|
+
每次完整测试同时写入 `tmp/coverage/summary.json`:Ruby 描述和平台、实际依赖版本、
|
|
97
|
+
库文件总数/已加载数、逐文件及上述三个组的行/分支计数、未命中位置和未加载文件。
|
|
98
|
+
`NET_CONNECTOR_COVERAGE_OUTPUT` 只改变输出位置,不改变门槛。报告不保存配置正文、
|
|
99
|
+
环境变量值或源码片段。CI 每个 Ruby/平台和最低依赖任务分别上传报告。
|
|
100
|
+
|
|
101
|
+
`script/coverage-baseline.json` 来自 NC-00 实测的初始 dirty 工作树,保存三个组及
|
|
102
|
+
已加载库总计的原始分数。Ruby 描述(含平台)相同时按整数交叉相乘比较,任一
|
|
103
|
+
行/分支比例下降均失败;不会自动更新基线。其他运行时标为 `not_comparable`,
|
|
104
|
+
继续执行原有 80% 门槛与全部行为测试,不能把跨 Ruby 插桩差异当业务回归。
|
|
105
|
+
NC-00 未保存逐文件数据,因此本轮不伪造逐文件历史下限;现在的逐文件报告供后续
|
|
106
|
+
同环境审阅建立更细基线。基线更新必须审阅,不能用新的低值覆盖旧值来消除失败。
|
|
107
|
+
|
|
108
|
+
门槛失败由 `Minitest.after_run` 返回非零退出码,`rake test`、`ci`、
|
|
109
|
+
`release:check` 都会失败;测试本身的失败也不会被达标的覆盖率覆盖。
|
|
110
|
+
单文件开发检查请用 `bundle exec ruby -Ilib -Itest test/<名称>_test.rb`,
|
|
111
|
+
完整预检仍须运行全部测试,不提供环境变量来降低发布门槛。
|
|
112
|
+
|
|
113
|
+
`.rubocop.yml` 对 `engine/` 和 `netdisco/` 启用 `Metrics/MethodLength`
|
|
114
|
+
(40)及 `Metrics/AbcSize`(60)。这是初始上限;按职责拆分超限方法,
|
|
115
|
+
不通过自动生成文件豁免维持基线。方法行数按 RuboCop 口径计算。
|
|
116
|
+
|
|
117
|
+
## 平台与工具
|
|
28
118
|
|
|
29
119
|
CI 矩阵为 Ubuntu 24.04 / macOS 15 × Ruby 3.2、3.3、3.4、4.0。
|
|
30
120
|
GitHub Actions 固定提交 SHA;Gitleaks 与 actionlint 固定版本和各平台归档
|
|
@@ -35,16 +125,49 @@ SHA-256,首次使用时从官方 GitHub Release 下载,缓存到 `tmp/tools/
|
|
|
35
125
|
|
|
36
126
|
## 依赖与打包
|
|
37
127
|
|
|
128
|
+
`test/topology_stages_test.rb` 使用 `test/support/topology_fixture.rb` 的四类合成对话,验证视图转换、先读回后保存、各阶段超时、读回不匹配/不完整、审批与实际查询一致、旧计划拒绝、保存完成证据和重连不重放。Queue 固定读回完成至保存之前的竞争窗口,检查线程和 Fiber 所有权。PAN-OS 无候选隔离证据时在 I/O 前拒绝自动改写,保留只读解析。夹具的官方来源、推断和 unknown 固件范围见 `test/fixtures/topology/README.md`;测试不等于现场设备认证。普通及最小 Bundler 隔离安装另用本地 PTY 验证分阶段拓扑流程及读回输出敏感标记。
|
|
129
|
+
|
|
130
|
+
`test/tftp_boundary_test.rb` 验证内置策略在首次 I/O 前拒绝不支持的参数组合,使用 Queue 固定 H3C 源探测后的竞争窗口,检查线程/Fiber 拒绝。上传确认后的日志、命令清理、租约清理、路径和元数据钩子失败保留回执且不重传;随机假秘密不进入新错误正文。回执测试保留旧 Data 解构/成员,核对配置来源及设备报告等级;Fleet 拒绝第三方和子类提供的完成事实。既有成功/失败/echo/控制符证据用同一套合成夹具继续测试,来源和 unknown 固件范围见 `test/fixtures/tftp/README.md`。普通及最小 Bundler 安装通过本地 PTY 验证新的回执入口,没有连接真实 TFTP 服务器或上传配置。
|
|
131
|
+
|
|
132
|
+
`test/netdisco_reporting_test.rb` 覆盖 strict/selected 的状态决策矩阵、显式 CLI 退出码、默认 JSON 键及 Data 成员/位置参数不变、旧 Fleet/ResultStore 签名,以及部分成功/回调/报告错误阻止 selected 成功。动态假秘密放入异常消息、输出、命令、source、line、phase、code 和自定义类型名,v2 报告与私有 JSON 不得含它。受控文件/TFTP 回执阶段跨 Worker 复制仍保留,普通文件异常不能冒充设备产物。可控时钟让 UTC 倒退而单调时间前进,断言设备及批次耗时准确且无负值;没有用固定睡眠推断时间行为。
|
|
133
|
+
|
|
134
|
+
`test/backup_lock_test.rb` 通过 Queue、独立 Ruby 进程及可控单调时钟检查采集前互斥、有限等待、锁释放、线程/Fiber/回调递归、路径别名、私有权限、硬链接/FIFO 拒绝和符号链接替换。`test/backup_identity_test.rb` 保留旧命名比较及 mtime 契约;稳定锁文件不再作为多余备份计数。
|
|
135
|
+
|
|
136
|
+
`test/legacy_index_test.rb` 用 8 台合成设备和 4 个 worker 统计目录扫描:旧命名迁移一批只扫描一次,规范文件全命中时为零;同一 Fleet 的新批次重新识别歧义。覆盖 IPv6/zone 身份、文件类型、快照失败及文件消失、替换、原位修改;在读返回期间注入修改,断言失效正文不交付。端到端批次验证失效基线在凭据和连接器调用前失败。计数证明扫描次数减少,不代表已经测出墙钟性能提升。
|
|
137
|
+
|
|
138
|
+
`test/module_loading_test.rb` 在独立 Ruby 进程核验 Netdisco 加载、CLI 离线导出和实际解析的 `$LOADED_FEATURES`;旧入口双加载顺序继续检查。`test/parsing_encoding_test.rb` 覆盖 UTF-8/二进制标签、非法 UTF-8、Latin-1 字节、回车/退格/ANSI、被控制符隐藏的非法输入、分裂多字节字符、原备份不变及拓扑不能把异常输出当作空表。原有 PAN-OS 引号多行拒绝及多线程独立解析测试保留。没有真实其他编码设备样本,本次不增加自动或显式设备编码配置;严格转码能力留待实际设备需求验证。
|
|
139
|
+
|
|
140
|
+
`test/file_persistence_test.rb` 对临时文件创建、写入、flush/fsync、rename、父目录打开/同步及收尾注入故障,检查磁盘内容、阶段回执、无正文诊断、Fleet 部分成功及报告/导出行为。同步不支持与 EIO 分开,第三方回执子类不能供应完成事实。隔离安装烟测还通过真实本地 PTY 采集写入,验证私有锁、目录同步及安全读取。本地 macOS 测试证明协议与故障分支;Linux、网络文件系统、真实断电恢复需单独验证。
|
|
141
|
+
|
|
142
|
+
`test/netdisco_budget_test.rb` 用合成响应、可控单调时钟及本地 TCP HTTP 端点验证单页/累计字节、记录数、分页、认证和兼容查询的共用期限。流式上限覆盖 chunked、无长度和虚报长度;超限时设备工厂与凭据解析器均未调用。阻塞读取场景断言关闭自有传输并回收观察线程,不靠固定 sleep 判断竞态。旧 requester 只验证返回后的预算,不声称能强制中止任意回调。
|
|
143
|
+
|
|
144
|
+
`test/netdisco_settings_test.rb` 验证批内 ENV 策略变化被隔离、逐设备凭据轮换、后续批次刷新、批准计划不重抓清单、CLI/ENV/YAML 优先级及离线导出。策略快照的序列化和 inspect 不含秘密;非法枚举、采样范围及预算在创建 Fleet 或设备前拒绝。默认预算没有经过生产容量压测,真实 Netdisco 及多平台远端矩阵仍需单独验收。
|
|
145
|
+
|
|
38
146
|
运行依赖写在 `net-connector.gemspec`,包括直接使用的、可能从 Ruby 默认
|
|
39
147
|
安装中拆出的标准库 gem。开发工具只写在 Gemfile,不进入运行依赖。
|
|
40
|
-
`expect-pty
|
|
148
|
+
共享脱敏要求 `expect-pty ~> 0.5.0`,使用已发布的公共 `Expect::Redactor`。
|
|
149
|
+
开发及隔离安装检查使用正式依赖包,不再需要本地 expect 补丁或联调环境包装脚本。
|
|
150
|
+
开发用 `parallel` 保持 1.x,以支持 Ruby 3.2。
|
|
41
151
|
|
|
42
152
|
本项目是库,`Gemfile.lock` 仅作本地开发记录并被忽略;各 Ruby 版本的 CI
|
|
43
153
|
分别解析兼容依赖。应用使用者应在自己的应用中提交 lockfile。测试和打包
|
|
44
154
|
脚本通过隔离安装检查运行依赖,避免依赖开发环境里偶然存在的 gem。
|
|
45
155
|
|
|
46
|
-
|
|
47
|
-
|
|
156
|
+
`gemfiles/minimum.gemfile` 固定关键业务依赖下限 expect-pty 0.5.0、textfsm 0.2.0;
|
|
157
|
+
标准库和开发工具仍按主 Gemfile 的兼容范围解析。普通矩阵检查允许版本的正常解析,
|
|
158
|
+
另在 Ubuntu / Ruby 3.2、4.0 检查下限组合的全量测试与隔离安装。本地复现:
|
|
159
|
+
|
|
160
|
+
```sh
|
|
161
|
+
BUNDLE_GEMFILE=gemfiles/minimum.gemfile bundle install
|
|
162
|
+
BUNDLE_GEMFILE=gemfiles/minimum.gemfile bundle exec rake test package:verify
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
这不是所有传递依赖最旧版本的笛卡尔积,也不声称本地 macOS 运行证明远端矩阵通过。
|
|
166
|
+
当前这两个关键依赖的正常解析与下限恰好相同,报告仍记录实际版本,供以后比较。
|
|
167
|
+
开发锁文件均忽略;gemspec 保持兼容范围,基准、夹具、兼容 Gemfile 和审阅报告均不进 gem。
|
|
168
|
+
|
|
169
|
+
gem 只收录库代码、TextFSM 模板、CLI、架构/验证/发布文档、README、LICENSE、
|
|
170
|
+
CHANGELOG、SECURITY 和 CONTRIBUTING。测试、示例、发布工具、工作流、本地评审快照、配置和备份不进入包。
|
|
48
171
|
更改 gemspec 后,实际归档仍须通过独立的文件白名单检查。
|
|
49
172
|
|
|
50
173
|
## 敏感数据
|