net-connector 0.19.0 → 0.21.0
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 +12 -0
- data/README.md +5 -1
- data/README.zh-CN.md +1 -1
- data/docs/VERIFICATION.md +9 -10
- data/docs/usage.md +1 -1
- data/docs/usage.zh-CN.md +2 -2
- data/lib/net/connector/collect/progress.rb +1 -1
- data/lib/net/connector/device/interfaces/audit.rb +2 -2
- data/lib/net/connector/device/interfaces/description.rb +3 -3
- data/lib/net/connector/device/interfaces/neighbor.rb +6 -6
- data/lib/net/connector/device/interfaces.rb +5 -5
- data/lib/net/connector/netdisco/ssh/archive/worker.py +15 -0
- data/lib/net/connector/netdisco/topology/options.rb +3 -3
- data/lib/net/connector/version.rb +1 -1
- metadata +20 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7e379dbe5598c3f170fdcfbc123103c4eb178941508e8fa0df12e2b8043fdf93
|
|
4
|
+
data.tar.gz: 3ad7934b5aa811031ea1a1283c67743494795472a0361207869d6b16d03cfda0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 07e68bd1ebd341839e6c45db6e821e76f8371c7b5d2e135a064925be5ca6f0d06189cf22be97fd2d8ea676fc542216dc67bfeff88fd06043b310fe72e642b67b
|
|
7
|
+
data.tar.gz: 96400e19508ca207d0e4aeccb0dc5aad7529bafebb0e2a4723a10e9d3907e07c5ba9f722afaabf5d78f257184f2b7f27aab82da91c7e64f60ca005188d1aa445
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.21.0 - 2026-10-30
|
|
6
|
+
|
|
7
|
+
- Rename neighbor fields to `remote_name`, `remote_interface` and `remote_chassis_id`, retaining `local_interface`. Collection progress reads schema 4 `target`; require ctx_cli 0.5. No legacy accessor aliases.
|
|
8
|
+
|
|
9
|
+
## 0.20.0 - 2026-10-29
|
|
10
|
+
|
|
11
|
+
- Require the latest stable TextFSM 0.5.1, align the minimum dependency matrix, and verify JSON 3 with its original published package instead of a source metadata patch.
|
|
12
|
+
|
|
13
|
+
- Recheck streamed archive content on the pinned descriptor so same-timestamp overwrites cannot receive a successful copy or delivery receipt.
|
|
14
|
+
|
|
15
|
+
- Bound compatible ctx_cli and expect-pty dependencies to the contract versions tested with this release (ctx_cli 0.4.x and expect-pty 0.9.6 through 0.9.x).
|
|
16
|
+
|
|
5
17
|
## 0.19.0 - 2026-10-29
|
|
6
18
|
|
|
7
19
|
- Extract `Netdisco::Catalog#devices(policy:)` for immutable inventory without credentials or operations; Fleet delegates inventory access. Add live, injected `Credentials#resolve(platform:)` with platform-specific username/password/enable-password precedence and independent secret snapshots.
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
Ruby sessions for network device CLIs over SSH or Telnet. Collect configurations, save private backups, run interactive scripts, parse output with TextFSM, and back up fleets from Netdisco inventories.
|
|
6
6
|
|
|
7
|
-
Requires Ruby 3.4+, expect-pty 0.9.4+ and a POSIX system. SSH uses local OpenSSH; Telnet requires a local `telnet` executable and explicit configuration.
|
|
7
|
+
Requires Ruby 3.4+, expect-pty 0.9.6+, ctx_cli 0.4.x, TextFSM 0.5.1+ and a POSIX system. SSH uses local OpenSSH; Telnet requires a local `telnet` executable and explicit configuration.
|
|
8
8
|
|
|
9
9
|
## Install
|
|
10
10
|
|
|
@@ -85,3 +85,7 @@ credentials = Net::Connector::Credentials.new(env: ENV).resolve(platform: :cisco
|
|
|
85
85
|
Catalog owns inventory reading, normalization, duplicate marking and cache status (`#status`). It does not resolve device credentials, log into devices or create operation reports. Pass one policy snapshot throughout a run. Fleet delegates to Catalog and retains operation orchestration.
|
|
86
86
|
|
|
87
87
|
Credentials reads the injected environment on every `resolve`; it returns an independent frozen hash, or nil when no username is available. Platform-specific `NC_<PLATFORM>_USERNAME`, `_PASSWORD`, and `_ENABLE_PASSWORD` override `NC_DEVICE_USERNAME`, `NC_DEVICE_PASSWORD`, and `NC_ENABLE_PASSWORD` respectively. Blank values fall back. Secrets are never cached or included in object inspection.
|
|
88
|
+
|
|
89
|
+
## Domain contract migration (2026-10-30)
|
|
90
|
+
|
|
91
|
+
Rename neighbor fields to `remote_name`, `remote_interface` and `remote_chassis_id`, retaining `local_interface`. Collection progress reads schema 4 `target`; require ctx_cli 0.5. No legacy accessor aliases. See the [schema 4 migration and module contracts](https://github.com/gatework/ctx_runner/blob/main/docs/contracts-2026-10-30.md). Regenerate old collection reports and change plans; changing only their version number is not supported.
|
data/README.zh-CN.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
通过 SSH 或 Telnet 操作网络设备的 Ruby 库。支持配置采集、私有备份、交互脚本、TextFSM 解析,以及基于 Netdisco 清单的批量备份。
|
|
6
6
|
|
|
7
|
-
需要 Ruby 3.4+、expect-pty 0.9.4+ 和 POSIX 系统。SSH 使用本机 OpenSSH;Telnet 需要本机安装 `telnet` 并显式配置。
|
|
7
|
+
需要 Ruby 3.4+、expect-pty 0.9.6+、ctx_cli 0.4.x、TextFSM 0.5.1+ 和 POSIX 系统。SSH 使用本机 OpenSSH;Telnet 需要本机安装 `telnet` 并显式配置。
|
|
8
8
|
|
|
9
9
|
## 安装
|
|
10
10
|
|
data/docs/VERIFICATION.md
CHANGED
|
@@ -155,7 +155,7 @@ SHA-256,首次使用时从官方 GitHub Release 下载,缓存到 `tmp/tools/
|
|
|
155
155
|
|
|
156
156
|
运行依赖写在 `net-connector.gemspec`,包括直接使用的、可能从 Ruby 默认
|
|
157
157
|
安装中拆出的标准库 gem。开发工具只写在 Gemfile,不进入运行依赖。
|
|
158
|
-
PTY 与共享脱敏直接依赖 expect-pty 0.9.
|
|
158
|
+
PTY 与共享脱敏直接依赖 expect-pty 0.9.6+ 的公开 `Session`、`buffer_bytesize` 和 `Expect::Redactor` 接口。
|
|
159
159
|
开发用 `parallel` 保持 1.x。升级 expect-pty 时先验证源码集成,再用本次构建的 gem 验证隔离安装;
|
|
160
160
|
新依赖版本发布前不得将本地构建验证记成已发布版本验收,也不能退回旧接口掩盖依赖缺失。
|
|
161
161
|
|
|
@@ -163,7 +163,7 @@ PTY 与共享脱敏直接依赖 expect-pty 0.9.4+ 的公开 `Session`、`buffer_
|
|
|
163
163
|
分别解析兼容依赖。应用使用者应在自己的应用中提交 lockfile。测试和打包
|
|
164
164
|
脚本通过隔离安装检查运行依赖,避免依赖开发环境里偶然存在的 gem。
|
|
165
165
|
|
|
166
|
-
`gemfiles/minimum.gemfile` 固定受支持的依赖下界 expect-pty 0.9.4、textfsm 0.
|
|
166
|
+
`gemfiles/minimum.gemfile` 固定受支持的依赖下界 expect-pty 0.9.6、ctx_cli 0.4.0、textfsm 0.5.1;
|
|
167
167
|
标准库和开发工具仍按主 Gemfile 的兼容范围解析。普通矩阵检查允许版本的正常解析,
|
|
168
168
|
另在 Ubuntu / Ruby 3.4、4.0 检查这组版本的全量测试与隔离安装。本地复现:
|
|
169
169
|
|
|
@@ -206,17 +206,16 @@ Gitleaks 默认规则之外,还检查网络设备密码/SNMP community 配置
|
|
|
206
206
|
扫描工具不会自动改写 Git 历史或真实设备备份。规则用于拦截常见泄露,
|
|
207
207
|
发布前仍需人工确认设备名称、拓扑和业务配置等上下文信息是否适合公开。
|
|
208
208
|
|
|
209
|
-
## JSON 2
|
|
209
|
+
## 使用已发布 TextFSM 分别验证 JSON 2 与 JSON 3
|
|
210
210
|
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
运行依赖要求 TextFSM 0.5.1 或更新版本;0.5.1 的公开 JSON 声明为 `>= 2.0`,
|
|
212
|
+
允许普通消费者选择 JSON 2 或 JSON 3。最低依赖任务固定 TextFSM 0.5.1 与 JSON 2。
|
|
213
213
|
|
|
214
|
-
CI 的 `json3-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
该任务明确代表尚未发布依赖声明下的源码兼容性;不自动发布、替换正式依赖或修改用户的全局 gem。
|
|
214
|
+
CI 的 `json3-compatibility` 在 Ruby 3.4 / 4.0 使用已发布 TextFSM 0.5.1 与 JSON 3,
|
|
215
|
+
执行完整测试和真实打包隔离安装。脚本核对原始 gem 的 JSON 依赖声明,再将发布包缓存
|
|
216
|
+
交给隔离消费者;不再检出旧源码、修改 metadata 或重建同版本 TextFSM。
|
|
218
217
|
|
|
219
|
-
|
|
218
|
+
本地复现:
|
|
220
219
|
|
|
221
220
|
```sh
|
|
222
221
|
BUNDLE_GEMFILE=gemfiles/json3.gemfile bundle install
|
data/docs/usage.md
CHANGED
|
@@ -165,6 +165,6 @@ Per-command prompts use `interactions: [Net::Connector::Interaction.new(/Token:\
|
|
|
165
165
|
|
|
166
166
|
## Dependencies and extensions
|
|
167
167
|
|
|
168
|
-
Load device APIs with `require "net/connector"`; Netdisco has a separate entrypoint. Vendor implementations and TextFSM load on demand. The gemspec requires expect-pty 0.9.4+; the host application's lockfile selects concrete dependency versions. The minimum dependency matrix uses TextFSM 0.
|
|
168
|
+
Load device APIs with `require "net/connector"`; Netdisco has a separate entrypoint. Vendor implementations and TextFSM load on demand. The gemspec requires expect-pty 0.9.6+, ctx_cli 0.4.x and TextFSM 0.5.1+; the host application's lockfile selects concrete dependency versions. The minimum dependency matrix uses TextFSM 0.5.1 and JSON 2. A separate JSON 3 matrix uses the same published TextFSM package without modifying its dependency metadata.
|
|
169
169
|
|
|
170
170
|
CLI entry points share layered configuration and `.env` loading; dotenv is a declared runtime dependency. Core library calls do not discover host files. Follow the [loading and migration reference](architecture.md#加载入口与厂商策略) (Chinese) for custom profiles, strategies, and protected hooks.
|
data/docs/usage.zh-CN.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
[English](usage.md) | [返回首页](../README.zh-CN.md) | [Netdisco 批量备份](netdisco.zh-CN.md)
|
|
4
4
|
|
|
5
|
-
支持 Ruby 3.4 及以上版本和 POSIX 系统。SSH 调用本机 OpenSSH,Telnet 需要本机安装 `telnet` 并显式选择。要求 [`expect-pty`](https://rubygems.org/gems/expect-pty) 0.9.4
|
|
5
|
+
支持 Ruby 3.4 及以上版本和 POSIX 系统。SSH 调用本机 OpenSSH,Telnet 需要本机安装 `telnet` 并显式选择。要求 [`expect-pty`](https://rubygems.org/gems/expect-pty) 0.9.6 及以上、ctx_cli 0.4.x 和 [`textfsm`](https://rubygems.org/gems/textfsm) 0.5.1 及以上;具体版本由宿主锁定。
|
|
6
6
|
|
|
7
7
|
脱敏直接复用 expect-pty 的公开 `Expect::Redactor` 接口;连接器只管理秘密作用域和配置输出的隐私策略。
|
|
8
8
|
|
|
9
|
-
gemspec
|
|
9
|
+
gemspec 声明所需接口的版本下界;宿主应用通过自己的 Gemfile 和锁文件固定具体依赖版本。最低依赖组合使用 textfsm 0.5.1 与 JSON 2;JSON 3 矩阵也使用同一已发布 TextFSM 包,无需源码或 metadata 补丁。开发工具及测试矩阵的版本约束不进入 gem 的运行依赖。
|
|
10
10
|
|
|
11
11
|
CLI 与示例入口共用分层配置和 `.env` 加载,dotenv 已声明为运行时依赖;核心库调用不自动发现宿主文件。
|
|
12
12
|
|
|
@@ -27,7 +27,7 @@ module Net
|
|
|
27
27
|
when "partial" then "Partially complete (#{code})"
|
|
28
28
|
else "Incomplete (#{code})"
|
|
29
29
|
end
|
|
30
|
-
super(host: result.fetch("
|
|
30
|
+
super(host: result.fetch("target").fetch("host"), success: status == "complete",
|
|
31
31
|
duration_ms: result.fetch("duration_ms"), message: message, error_code: code&.to_sym)
|
|
32
32
|
end
|
|
33
33
|
|
|
@@ -64,7 +64,7 @@ module Net
|
|
|
64
64
|
def inspect_interface(interface, peers)
|
|
65
65
|
peer = peers.first
|
|
66
66
|
current = @descriptions[interface]
|
|
67
|
-
row = { interface: peer.local_interface, neighbor: peer.
|
|
67
|
+
row = { interface: peer.local_interface, neighbor: peer.remote_name, port: peer.remote_interface,
|
|
68
68
|
current: current, expected: nil, status: :unverified }
|
|
69
69
|
@comparisons << row
|
|
70
70
|
if peers.size != 1
|
|
@@ -78,7 +78,7 @@ module Net
|
|
|
78
78
|
local = @strategy.configuration_interface(peer.local_interface)
|
|
79
79
|
Description.validate_interface!(local)
|
|
80
80
|
row.merge!(expected: proposed, status: compare_status(current, proposed, peer))
|
|
81
|
-
@evidence[interface] = [peer.
|
|
81
|
+
@evidence[interface] = [peer.remote_name, peer.remote_interface, current]
|
|
82
82
|
return if row[:status] == :matches
|
|
83
83
|
|
|
84
84
|
@changes << Change.new(interface: local, old_description: current, new_description: proposed, neighbor: peer)
|
|
@@ -10,11 +10,11 @@ module Net
|
|
|
10
10
|
# 将邻居名称和接口拼成默认描述;统一邻居接口简称,原始发现记录保持不变。
|
|
11
11
|
def self.format(neighbor, abbreviate: true, lowercase: false)
|
|
12
12
|
port = if abbreviate
|
|
13
|
-
Name.short(neighbor.
|
|
13
|
+
Name.short(neighbor.remote_interface, lowercase: lowercase)
|
|
14
14
|
else
|
|
15
|
-
lowercase ? neighbor.
|
|
15
|
+
lowercase ? neighbor.remote_interface.downcase : neighbor.remote_interface
|
|
16
16
|
end
|
|
17
|
-
validate!("To_#{neighbor.
|
|
17
|
+
validate!("To_#{neighbor.remote_name.tr(" ", "_")}_#{port.tr(" ", "_")}")
|
|
18
18
|
end
|
|
19
19
|
|
|
20
20
|
# 保留语义相同的旧描述;只归一末尾已知接口别名和大小写,不模糊匹配名称或端口编号。
|
|
@@ -4,11 +4,11 @@ module Net
|
|
|
4
4
|
module Connector
|
|
5
5
|
class Interfaces
|
|
6
6
|
# 邻居身份拥有独立字符串,格式化回调不能改写发现证据。
|
|
7
|
-
Neighbor = Data.define(:local_interface, :
|
|
7
|
+
Neighbor = Data.define(:local_interface, :remote_name, :remote_interface, :remote_chassis_id, :protocol) do
|
|
8
8
|
# 复制并冻结本地端口、邻居名称、远端端口及发现协议。
|
|
9
|
-
def initialize(local_interface:,
|
|
10
|
-
fields = { local_interface: local_interface,
|
|
11
|
-
|
|
9
|
+
def initialize(local_interface:, remote_name:, remote_interface:, remote_chassis_id:, protocol:)
|
|
10
|
+
fields = { local_interface: local_interface, remote_name: remote_name,
|
|
11
|
+
remote_interface: remote_interface, remote_chassis_id: remote_chassis_id }
|
|
12
12
|
raise ArgumentError, "neighbor fields must be Strings" unless fields.values.all?(String)
|
|
13
13
|
raise ArgumentError, "neighbor protocol must be a Symbol" unless protocol.is_a?(Symbol)
|
|
14
14
|
|
|
@@ -18,8 +18,8 @@ module Net
|
|
|
18
18
|
# 原始发现数据保留占位符;规划与下发重验共用身份校验,不能把未知名称写入描述。
|
|
19
19
|
# MAC 是合法的 LLDP Port ID,不凭地址形状猜测设备角色,也不拿 chassis ID 补造名称。
|
|
20
20
|
def identity_issue
|
|
21
|
-
return :unknown_neighbor_name if unknown_identity?(
|
|
22
|
-
return :unknown_neighbor_interface if unknown_identity?(
|
|
21
|
+
return :unknown_neighbor_name if unknown_identity?(remote_name)
|
|
22
|
+
return :unknown_neighbor_interface if unknown_identity?(remote_interface)
|
|
23
23
|
|
|
24
24
|
nil
|
|
25
25
|
end
|
|
@@ -88,9 +88,9 @@ module Net
|
|
|
88
88
|
|
|
89
89
|
rows.map do |row|
|
|
90
90
|
Neighbor.new(local_interface: row.fetch("LOCAL_INTERFACE").strip.freeze,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
remote_name: row.fetch("NEIGHBOR_NAME", "").strip.freeze,
|
|
92
|
+
remote_interface: row.fetch("NEIGHBOR_INTERFACE").strip.freeze,
|
|
93
|
+
remote_chassis_id: row.fetch("CHASSIS_ID", "").strip.freeze,
|
|
94
94
|
protocol: @strategy.protocol).freeze
|
|
95
95
|
end
|
|
96
96
|
end
|
|
@@ -272,7 +272,7 @@ module Net
|
|
|
272
272
|
plan.changes.each do |change|
|
|
273
273
|
Description.validate!(change.new_description)
|
|
274
274
|
unless evidence.fetch(@strategy.interface_key(change.interface)) ==
|
|
275
|
-
[change.neighbor.
|
|
275
|
+
[change.neighbor.remote_name, change.neighbor.remote_interface, change.old_description]
|
|
276
276
|
raise ArgumentError, "plan changes do not match its discovery evidence"
|
|
277
277
|
end
|
|
278
278
|
end
|
|
@@ -319,7 +319,7 @@ module Net
|
|
|
319
319
|
|
|
320
320
|
interfaces.transform_values do |peers|
|
|
321
321
|
peer = peers.fetch(0)
|
|
322
|
-
[peer.
|
|
322
|
+
[peer.remote_name, peer.remote_interface, current.fetch(@strategy.interface_key(peer.local_interface))].freeze
|
|
323
323
|
end.freeze
|
|
324
324
|
end
|
|
325
325
|
|
|
@@ -130,6 +130,21 @@ def read_file(parent, name, missing=False, consume=None):
|
|
|
130
130
|
digest.update(chunk)
|
|
131
131
|
if consume is not None and consume(chunk) != len(chunk):
|
|
132
132
|
raise IOError("incomplete file write")
|
|
133
|
+
# 同一时钟粒度内的覆写可能不改变 stat 时间;投递后重读摘要核对已发送字节。
|
|
134
|
+
if consume is not None:
|
|
135
|
+
f.seek(0)
|
|
136
|
+
verified = hashlib.sha256()
|
|
137
|
+
verified_size = 0
|
|
138
|
+
while True:
|
|
139
|
+
chunk = f.read(CHUNK_BYTES)
|
|
140
|
+
if not chunk:
|
|
141
|
+
break
|
|
142
|
+
verified_size += len(chunk)
|
|
143
|
+
if verified_size > MAX_BYTES:
|
|
144
|
+
raise ValueError("oversized file")
|
|
145
|
+
verified.update(chunk)
|
|
146
|
+
if verified_size != size or verified.digest() != digest.digest():
|
|
147
|
+
raise ValueError("file changed while delivering")
|
|
133
148
|
after = os.fstat(f.fileno())
|
|
134
149
|
if size != after.st_size or fingerprint(before) != fingerprint(after):
|
|
135
150
|
raise ValueError("file changed while reading")
|
|
@@ -51,10 +51,10 @@ module Net
|
|
|
51
51
|
|
|
52
52
|
# 使用当前模板和端口展示策略生成缺失或确需修正的目标描述。
|
|
53
53
|
def description_for(neighbor)
|
|
54
|
-
port = neighbor.
|
|
54
|
+
port = neighbor.remote_interface
|
|
55
55
|
port = Net::Connector::Interfaces::Name.short(port) if abbreviate_ports
|
|
56
56
|
port = port.downcase if lowercase_ports
|
|
57
|
-
format(neighbor: neighbor.
|
|
57
|
+
format(neighbor: neighbor.remote_name, port: port)
|
|
58
58
|
end
|
|
59
59
|
|
|
60
60
|
# 仅显式声明的旧名称前缀可保留;不把未知名称、包含匹配或不同编号当作同一邻居。
|
|
@@ -63,7 +63,7 @@ module Net
|
|
|
63
63
|
return true if comparison.equivalent?(current, expected)
|
|
64
64
|
|
|
65
65
|
neighbor_name_prefixes.any? do |prefix|
|
|
66
|
-
variant = neighbor.with(
|
|
66
|
+
variant = neighbor.with(remote_name: prefix + neighbor.remote_name)
|
|
67
67
|
comparison.equivalent?(current, description_for(variant))
|
|
68
68
|
end
|
|
69
69
|
end
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: net-connector
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.21.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- net-connector contributors
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-10-
|
|
10
|
+
date: 2026-10-30 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: ctx_cli
|
|
@@ -15,42 +15,54 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version:
|
|
18
|
+
version: 0.5.0
|
|
19
|
+
- - "<"
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0.6'
|
|
19
22
|
type: :runtime
|
|
20
23
|
prerelease: false
|
|
21
24
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
25
|
requirements:
|
|
23
26
|
- - ">="
|
|
24
27
|
- !ruby/object:Gem::Version
|
|
25
|
-
version:
|
|
28
|
+
version: 0.5.0
|
|
29
|
+
- - "<"
|
|
30
|
+
- !ruby/object:Gem::Version
|
|
31
|
+
version: '0.6'
|
|
26
32
|
- !ruby/object:Gem::Dependency
|
|
27
33
|
name: expect-pty
|
|
28
34
|
requirement: !ruby/object:Gem::Requirement
|
|
29
35
|
requirements:
|
|
30
36
|
- - ">="
|
|
31
37
|
- !ruby/object:Gem::Version
|
|
32
|
-
version:
|
|
38
|
+
version: 0.9.6
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0.10'
|
|
33
42
|
type: :runtime
|
|
34
43
|
prerelease: false
|
|
35
44
|
version_requirements: !ruby/object:Gem::Requirement
|
|
36
45
|
requirements:
|
|
37
46
|
- - ">="
|
|
38
47
|
- !ruby/object:Gem::Version
|
|
39
|
-
version:
|
|
48
|
+
version: 0.9.6
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '0.10'
|
|
40
52
|
- !ruby/object:Gem::Dependency
|
|
41
53
|
name: textfsm
|
|
42
54
|
requirement: !ruby/object:Gem::Requirement
|
|
43
55
|
requirements:
|
|
44
56
|
- - ">="
|
|
45
57
|
- !ruby/object:Gem::Version
|
|
46
|
-
version:
|
|
58
|
+
version: 0.5.1
|
|
47
59
|
type: :runtime
|
|
48
60
|
prerelease: false
|
|
49
61
|
version_requirements: !ruby/object:Gem::Requirement
|
|
50
62
|
requirements:
|
|
51
63
|
- - ">="
|
|
52
64
|
- !ruby/object:Gem::Version
|
|
53
|
-
version:
|
|
65
|
+
version: 0.5.1
|
|
54
66
|
- !ruby/object:Gem::Dependency
|
|
55
67
|
name: pg
|
|
56
68
|
requirement: !ruby/object:Gem::Requirement
|