baseline-rb 0.3.0 → 0.3.1
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 +11 -0
- data/lib/baseline/cisco/parser.rb +35 -5
- data/lib/baseline/parser.rb +9 -2
- data/lib/baseline/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0ab48a464a299fae539f474ad2fdfce3079f8b6b49f930b72e92d3e686b0fd11
|
|
4
|
+
data.tar.gz: 500bf4fde6b208357f3fd8aa1fcbb8df4f24ed046568b9ed8ed888a2ee566586
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 503da5d853fd3d86c8503f2df927fd9da752b8a4416552855e3063f0e5ee902610682de09eb023f5c7a645754aac552e1e6c6b947a646ea22f43cd567de6daec
|
|
7
|
+
data.tar.gz: dbfdd6e5590c2d2eb29c375858edaba14ff599452059f5ad0011b592e95c09c35c95826a021b5787e129e8d3f2d91f32bd8e7d775ec46cddbab57f549f28c2c4
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
Changes to the public contract are recorded here. Versions follow Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.3.1 (2026-10-18)
|
|
6
|
+
|
|
7
|
+
- Withhold IOS SNMP ACL facts after contradictory community access declarations, while accepting equivalent repeats and preserving NX-OS incremental attributes.
|
|
8
|
+
|
|
9
|
+
- Clear Bundler bootstrap variables when verifying packages in an isolated gem installation, including calls made through bundle exec.
|
|
10
|
+
|
|
11
|
+
- Remove cancelled IOS SNMP communities and their credential evidence before deriving access and permission facts.
|
|
12
|
+
|
|
13
|
+
- Keep management restrictions unknown when vendor ACL rules repeat an explicit sequence identity.
|
|
14
|
+
- Stop reusing Cisco TACACS login methods after the final named list is cancelled or malformed; independent lists remain available.
|
|
15
|
+
|
|
5
16
|
## 0.3.0 (2026-10-18)
|
|
6
17
|
|
|
7
18
|
- Breaking: rename mutable fact assembly to `FactBuilder`, immutable parsed snapshots to `Evidence`, multiline quoted-value documents to `MultilineDocument`, and the PAN-OS prefix lookup to `CommandIndex#matching_prefix`.
|
|
@@ -147,8 +147,8 @@ module Baseline
|
|
|
147
147
|
enabled = nxos? ? configured_state(/\Asnmp-server protocol enable\z/, /\Ano snmp-server protocol enable\z/) : nil
|
|
148
148
|
enabled = nxos? || snmp_entries.any? if enabled.nil? && (@fact_builder.complete? || snmp_entries.any?)
|
|
149
149
|
record_fact("snmp.enabled", enabled)
|
|
150
|
-
communities = {}
|
|
151
|
-
|
|
150
|
+
communities, community_acls = {}, {}
|
|
151
|
+
configured_community_entries.each do |entry|
|
|
152
152
|
match = /\Asnmp-server community\s+(\S+)(?:\s+(.*))?\z/.match(entry.text)
|
|
153
153
|
unless match
|
|
154
154
|
record_unknown_snmp_access([ entry ])
|
|
@@ -162,6 +162,14 @@ module Baseline
|
|
|
162
162
|
community[:write] = SNMP_ROLE_WRITE[role] if role
|
|
163
163
|
acl = nxos? ? settings[/\buse-ipv4acl\s+(\S+)/, 1] : settings[/\A(?:ro|rw)\s+(\S+)\z/i, 1]
|
|
164
164
|
community[:acl] = acl if acl
|
|
165
|
+
unless nxos?
|
|
166
|
+
access = (community_acls[match[1]] ||= { value: acl, conflicted: false })
|
|
167
|
+
access[:conflicted] ||= access[:value] != acl
|
|
168
|
+
if access[:conflicted]
|
|
169
|
+
community.delete(:acl)
|
|
170
|
+
record_unknown_fact("snmp.acl", [ entry ], code: :conflicting_community_acl)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
165
173
|
record_credential("snmp-community", "snmp", "plain", match[1], entry) unless @fact_builder.credential_recorded?(community[:line])
|
|
166
174
|
end
|
|
167
175
|
versions = communities.any? ? %w[v1 v2c] : []
|
|
@@ -226,6 +234,24 @@ module Baseline
|
|
|
226
234
|
record_fact("snmp.versions", versions) unless versions.empty?
|
|
227
235
|
end
|
|
228
236
|
|
|
237
|
+
# IOS 的 no 声明撤销整项团体字;先归约有效来源,避免留下访问或凭据事实。
|
|
238
|
+
def configured_community_entries
|
|
239
|
+
return matching_blocks(/\Asnmp-server community\b/) if nxos?
|
|
240
|
+
|
|
241
|
+
active = {}
|
|
242
|
+
matching_blocks(/\A(?:no )?snmp-server community\b/).each do |entry|
|
|
243
|
+
if (match = /\Ano snmp-server community\s+(\S+)\z/.match(entry.text))
|
|
244
|
+
analyze(entry) { active.delete(match[1]) }
|
|
245
|
+
elsif entry.text.start_with?("no ")
|
|
246
|
+
record_unknown_snmp_access([ entry ])
|
|
247
|
+
else
|
|
248
|
+
name = entry.text.split[2]
|
|
249
|
+
(active[name] ||= []) << entry
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
active.values.flatten.sort_by(&:line)
|
|
253
|
+
end
|
|
254
|
+
|
|
229
255
|
# NX-OS 通常会同步 CLI 与 SNMP 账号;缺少证据时不能构造虚拟用户。
|
|
230
256
|
def record_unverified_snmp_user_sync(users, enabled:)
|
|
231
257
|
return if enabled == false
|
|
@@ -318,8 +344,12 @@ module Baseline
|
|
|
318
344
|
# 解析各 VTY 实际选用的登录列表,包括命名列表。
|
|
319
345
|
def record_tacacs_login_usage(servers, groups)
|
|
320
346
|
pattern = /\Aaaa authentication login\s+(\S+)\s+(.+)\z/
|
|
321
|
-
|
|
322
|
-
|
|
347
|
+
family = /\A(?:no )?aaa authentication login\s+(\S+)(?:\s|\z)/
|
|
348
|
+
lists = matching_blocks(family).each_with_object({}) do |entry, result|
|
|
349
|
+
name = entry.text[family, 1]
|
|
350
|
+
match = pattern.match(entry.text)
|
|
351
|
+
# 最后同名声明决定列表证据;撤销或损坏不能复用先前的方法。
|
|
352
|
+
methods = match ? analyze(entry) { match[2] } : nil
|
|
323
353
|
result[name] = { methods: methods, entry: entry }
|
|
324
354
|
end
|
|
325
355
|
entries = @fact_builder.vtys.filter_map { |vty| lists[vty[:authentication_list]]&.fetch(:entry) }.uniq
|
|
@@ -329,7 +359,7 @@ module Baseline
|
|
|
329
359
|
elsif vty[:authentication] != "aaa"
|
|
330
360
|
false
|
|
331
361
|
elsif (list = lists[vty[:authentication_list]])
|
|
332
|
-
tacacs_login_method_state(list[:methods], servers, groups)
|
|
362
|
+
list[:methods] ? tacacs_login_method_state(list[:methods], servers, groups) : :authentication_list_unresolved
|
|
333
363
|
else
|
|
334
364
|
:authentication_list_unresolved
|
|
335
365
|
end
|
data/lib/baseline/parser.rb
CHANGED
|
@@ -244,6 +244,12 @@ module Baseline
|
|
|
244
244
|
# 注册有序 ACL 规则与别名,同时保留不支持的语法。
|
|
245
245
|
def register_acl(name, entries, aliases: [], supported: true, source: nil, &block)
|
|
246
246
|
commands = entries.reject { |entry| /\A(?:\d+\s+)?(?:description|remark|step|statistics|hardware-count)\b/.match?(entry.text) }
|
|
247
|
+
# 厂商显式序号是规则身份;重复身份不能靠来源先后消解。无序号规则保留原有顺序语义。
|
|
248
|
+
sequences = commands.filter_map do |entry|
|
|
249
|
+
match = /\A(?:access-list\s+\S+\s+)?(?:rule\s+)?(\d+)\s+(?:permit|deny)\b/.match(entry.text)
|
|
250
|
+
Integer(match[1], 10) if match
|
|
251
|
+
end
|
|
252
|
+
duplicate_sequences = sequences.uniq.size != sequences.size
|
|
247
253
|
parsed = commands.map.with_index do |entry, index|
|
|
248
254
|
value = analyze(entry) { block.call(entry, index) }
|
|
249
255
|
cursor.mark(entry.index, state: :unsupported) unless value
|
|
@@ -256,8 +262,9 @@ module Baseline
|
|
|
256
262
|
source ? source.line_range.cover?(line) : damaged_numbered_acl?(cursor.lines.fetch(line - 1).text, name)
|
|
257
263
|
end
|
|
258
264
|
acl = Acl.new(name: name, line: entries.first&.line, rules: parsed.compact,
|
|
259
|
-
supported: supported && !damaged && parsed.none?(&:nil?))
|
|
260
|
-
|
|
265
|
+
supported: supported && !damaged && !duplicate_sequences && parsed.none?(&:nil?))
|
|
266
|
+
conflicts = @fact_builder.register_acl(acl, aliases: aliases, lines: entries.map(&:line))
|
|
267
|
+
if duplicate_sequences || conflicts.any?
|
|
261
268
|
entries.each { |entry| cursor.mark(entry.index, state: :unsupported) }
|
|
262
269
|
end
|
|
263
270
|
end
|
data/lib/baseline/version.rb
CHANGED