baseline-rb 0.2.0 → 0.2.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 +4 -0
- data/README-zh.md +2 -0
- data/README.md +2 -0
- data/lib/baseline/cisco/parser.rb +3 -3
- data/lib/baseline/comware/parser.rb +3 -3
- data/lib/baseline/evaluator.rb +3 -0
- data/lib/baseline/hillstone/parser.rb +4 -4
- data/lib/baseline/palo_alto/parser.rb +9 -3
- data/lib/baseline/parser.rb +14 -0
- 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: 2386adb307215040a989dccfcba29d403bd31f28d400cbb6ba9f34215c13e7bb
|
|
4
|
+
data.tar.gz: 975bc0b9e0136528a8af240d21fe623068ec334c3f444746ce84dcbc25e097e6
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 81a940f8b6b82df076c2c1f541ee6b5f7e95154095ca3ccffc2b70580d129388d5ec40c6c6f9a926c30f813c31d5cc39f669f2c7f487dda94718954707e5f5f9
|
|
7
|
+
data.tar.gz: cc66c2181c786de9341533ae65caf8214d0e8d28d40628c7b22b9161e3189174144a38cb58f8599dd2b0848cc511b3ebb31a5634e807b957ef074201eee1624e
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
Changes to the public contract are recorded here. Versions follow Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.2.1 (2026-10-17)
|
|
6
|
+
|
|
7
|
+
- Reject duplicate normalized context keys before policy selection; preserve source lines and cursor captures for scalar NTP and Syslog configuration facts.
|
|
8
|
+
|
|
5
9
|
## 0.2.0 (2026-10-17)
|
|
6
10
|
|
|
7
11
|
### Changed
|
data/README-zh.md
CHANGED
|
@@ -73,6 +73,8 @@ puts report.to_text
|
|
|
73
73
|
|
|
74
74
|
解析辅助方法直接描述提取意图:`matching_blocks`、`configured_values`、`last_configured_value`、`configured_state` 和 `acl_source_network`。SNMP 写权限规则统一为 `snmp.write_enabled`,禁止写入时配置 `expected: false`。自定义策略需迁移旧键 `snmp.read_only`;旧类名与规则键不保留兼容别名。
|
|
75
75
|
|
|
76
|
+
上下文允许字符串或符号键,但归一化后重复的键会抛出 `ArgumentError`,避免依赖插入顺序选择设备策略。
|
|
77
|
+
|
|
76
78
|
`complete: true` 表示调用方提供了完整快照。报告通过 `input_complete` 保留这项声明,与解析状态分别记录。不完整的有序 ACL 可能缺少更早的 deny,因此不能仅根据已见 permit 判断来源越界,此时保持 `unknown`。
|
|
77
79
|
|
|
78
80
|
## 开发与测试
|
data/README.md
CHANGED
|
@@ -73,6 +73,8 @@ Vendor-specific code lives in a vendor namespace: `Baseline::Hillstone::Parser`
|
|
|
73
73
|
|
|
74
74
|
Parser helpers describe the evidence they extract: `matching_blocks`, `configured_values`, `last_configured_value`, `configured_state`, and `acl_source_network`. SNMP write permission uses the policy key `snmp.write_enabled` (`expected: false` to prohibit writes). Update custom policies that used `snmp.read_only`; old class names and rule keys have no compatibility aliases.
|
|
75
75
|
|
|
76
|
+
Context accepts string or symbol keys, but rejects duplicate keys after normalization with `ArgumentError` rather than selecting a device policy by insertion order.
|
|
77
|
+
|
|
76
78
|
`complete: true` asserts that the caller supplied the entire snapshot. Reports retain that assertion as `input_complete`, separately from parser status. A partial ordered ACL cannot prove an out-of-policy source: an unseen earlier deny may change its meaning, so the finding stays `unknown`.
|
|
77
79
|
|
|
78
80
|
## Development and tests
|
|
@@ -85,12 +85,12 @@ module Baseline
|
|
|
85
85
|
# 采集明确启用或禁用的管理服务。
|
|
86
86
|
def services
|
|
87
87
|
record("ntp.servers", configured_values(/\Antp server(?: vrf \S+)?\s+(\S+)/), matching_blocks(/\Antp server/))
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
record_configured_state("ntp.authentication", /\Antp authenticate\z/, /\Ano ntp authenticate\z/)
|
|
89
|
+
record_configured_value("ntp.source", /\Antp source(?:-interface)?\s+(\S+)\z/)
|
|
90
90
|
hosts = configured_values(nxos? ? /\Alogging server\s+(\S+)/ : /\Alogging host(?: ipv6)?\s+(\S+)/)
|
|
91
91
|
hosts |= configured_values(/\Alogging\s+(\d+(?:\.\d+){3})\z/) unless nxos?
|
|
92
92
|
record("syslog.servers", hosts, matching_blocks(/\Alogging (?:host|server)/))
|
|
93
|
-
|
|
93
|
+
record_configured_value("syslog.source", /\Alogging source-interface\s+(\S+)\z/)
|
|
94
94
|
snmp = matching_blocks(/\Asnmp-server\b/)
|
|
95
95
|
enabled = nxos? ? configured_state(/\Asnmp-server protocol enable\z/, /\Ano snmp-server protocol enable\z/) : nil
|
|
96
96
|
enabled = nxos? || snmp.any? if enabled.nil? && (@facts.complete? || snmp.any?)
|
|
@@ -79,12 +79,12 @@ module Baseline
|
|
|
79
79
|
# 采集明确启用或禁用的管理服务。
|
|
80
80
|
def services
|
|
81
81
|
record("ntp.servers", configured_values(/\Antp-service unicast-server\s+(\S+)/), matching_blocks(/\Antp-service unicast-server/))
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
record_configured_state("ntp.authentication", /\Antp-service authentication enable\z/, /\Aundo ntp-service authentication enable\z/)
|
|
83
|
+
record_configured_value("ntp.source", /\Antp-service source(?:-interface)?\s+(\S+)\z/)
|
|
84
84
|
# 从日志服务器中排除 source 子命令,并保留评估所需的归纳事实。
|
|
85
85
|
hosts = configured_values(/\Ainfo-center loghost\s+(\S+)/) - [ "source" ]
|
|
86
86
|
record("syslog.servers", hosts, matching_blocks(/\Ainfo-center loghost/))
|
|
87
|
-
|
|
87
|
+
record_configured_value("syslog.source", /\Ainfo-center loghost source\s+(\S+)\z/)
|
|
88
88
|
enabled = configured_state(/\Asnmp-agent(?:\s|\z)/, /\Aundo snmp-agent\z/)
|
|
89
89
|
record("snmp.enabled", enabled.nil? && @facts.complete? ? false : enabled)
|
|
90
90
|
versions = last_configured_value(/\Asnmp-agent sys-info version\s+(.+)\z/)&.split
|
data/lib/baseline/evaluator.rb
CHANGED
|
@@ -15,6 +15,9 @@ module Baseline
|
|
|
15
15
|
# 评估适用基线规则,分别报告合规结果与证据覆盖率。
|
|
16
16
|
def call(configuration:, context: {})
|
|
17
17
|
raise ArgumentError, "Invalid baseline context" unless context.is_a?(Hash)
|
|
18
|
+
unless context.keys.all? { |key| key.is_a?(String) || key.is_a?(Symbol) } && context.keys.map(&:to_s).uniq.size == context.size
|
|
19
|
+
raise ArgumentError, "Ambiguous baseline context"
|
|
20
|
+
end
|
|
18
21
|
context = context.transform_keys(&:to_s).merge("vendor" => configuration.platform)
|
|
19
22
|
unless (context.keys - Policy::SCOPES).empty? && context.values.all? { |value| value.is_a?(String) && !value.strip.empty? }
|
|
20
23
|
raise ArgumentError, "Invalid baseline context"
|
|
@@ -95,8 +95,8 @@ module Baseline
|
|
|
95
95
|
analyze(entry) { parts[2] }
|
|
96
96
|
end
|
|
97
97
|
record("ntp.servers", servers.uniq, entries)
|
|
98
|
-
|
|
99
|
-
record("ntp.source", sources.first) if sources.any? && sources.first && sources.uniq.one?
|
|
98
|
+
record_configured_state("ntp.authentication", /\Antp authentication\z/, /\Ano ntp authentication\z/)
|
|
99
|
+
record("ntp.source", sources.first, entries) if sources.any? && sources.first && sources.uniq.one?
|
|
100
100
|
unknown("ntp", matching_blocks(/\Ano ntp server\b/)) if matching_blocks(/\Ano ntp server\b/).any?
|
|
101
101
|
end
|
|
102
102
|
|
|
@@ -124,13 +124,13 @@ module Baseline
|
|
|
124
124
|
analyze(entry) { parts[2] }
|
|
125
125
|
end
|
|
126
126
|
record("syslog.servers", servers.uniq, entries)
|
|
127
|
-
record("syslog.source", sources.first) if sources.any? && sources.first && sources.uniq.one?
|
|
127
|
+
record("syslog.source", sources.first, entries) if sources.any? && sources.first && sources.uniq.one?
|
|
128
128
|
unknown("syslog", matching_blocks(/\Ano logging syslog\b/)) if matching_blocks(/\Ano logging syslog\b/).any?
|
|
129
129
|
end
|
|
130
130
|
|
|
131
131
|
# 轮询主机权限独立于出站 Trap 接收端。
|
|
132
132
|
def snmp
|
|
133
|
-
|
|
133
|
+
record_configured_state("snmp.enabled", /\Asnmp-server manager\z/, /\Ano snmp-server manager\z/)
|
|
134
134
|
entries = matching_blocks(/\Asnmp-server host\b/)
|
|
135
135
|
versions, sources, communities = [], [], []
|
|
136
136
|
entries.each do |entry|
|
|
@@ -144,9 +144,9 @@ module Baseline
|
|
|
144
144
|
end
|
|
145
145
|
record("ntp.servers", servers.map { |server| server[:address] }.uniq, entries.map { |row| row[:entry] })
|
|
146
146
|
if servers.any? && servers.none? { |server| server[:authenticated].nil? }
|
|
147
|
-
record("ntp.authentication", servers.all? { |server| server[:authenticated] })
|
|
147
|
+
record("ntp.authentication", servers.all? { |server| server[:authenticated] }, entries.map { |row| row[:entry] })
|
|
148
148
|
end
|
|
149
|
-
|
|
149
|
+
record_scalar("ntp.source", %w[deviceconfig system route service ntp source interface])
|
|
150
150
|
end
|
|
151
151
|
|
|
152
152
|
# 仅完整的认证声明才能证明所有服务器均满足认证要求。
|
|
@@ -176,7 +176,7 @@ module Baseline
|
|
|
176
176
|
value
|
|
177
177
|
end
|
|
178
178
|
record("syslog.servers", servers.uniq, entries.map { |row| row[:entry] })
|
|
179
|
-
|
|
179
|
+
record_scalar("syslog.source", %w[deviceconfig system route service syslog source interface])
|
|
180
180
|
end
|
|
181
181
|
|
|
182
182
|
# 轮询用户、团体字与出站 SNMP Trap 配置相互独立。
|
|
@@ -321,6 +321,12 @@ module Baseline
|
|
|
321
321
|
nil
|
|
322
322
|
end
|
|
323
323
|
|
|
324
|
+
# 标量语法与事实来源共享同一条最终声明。
|
|
325
|
+
def record_scalar(path, prefix)
|
|
326
|
+
row = rows(*prefix).last
|
|
327
|
+
record(path, scalar(prefix), row ? [ row[:entry] ] : [])
|
|
328
|
+
end
|
|
329
|
+
|
|
324
330
|
# 严格校验词元数量,避免尾随内容使错误配置被误判为已知事实。
|
|
325
331
|
def scalar(prefix)
|
|
326
332
|
row = rows(*prefix).last
|
data/lib/baseline/parser.rb
CHANGED
|
@@ -98,6 +98,20 @@ module Baseline
|
|
|
98
98
|
analyze(entry) { entry.text[pattern, 1] }
|
|
99
99
|
end
|
|
100
100
|
|
|
101
|
+
# 保存最后生效的标量声明及对应来源,不将被覆盖的声明作为当前证据。
|
|
102
|
+
def record_configured_value(path, pattern, entries = roots)
|
|
103
|
+
entry = entries.reverse.find { |candidate| !candidate.text[pattern, 1].nil? }
|
|
104
|
+
return unless entry
|
|
105
|
+
|
|
106
|
+
record(path, analyze(entry) { entry.text[pattern, 1] }, [ entry ])
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
# 启用状态可能由正向或撤销声明决定,保留所有参与归约的来源。
|
|
110
|
+
def record_configured_state(path, on, off)
|
|
111
|
+
entries = roots.select { |entry| on.match?(entry.text) || off.match?(entry.text) }
|
|
112
|
+
record(path, configured_state(on, off, entries), entries)
|
|
113
|
+
end
|
|
114
|
+
|
|
101
115
|
# 保存归一化事实及其来源证据。
|
|
102
116
|
def record(path, value, entries = [])
|
|
103
117
|
return unless @facts.record(path, value, lines: entries.map(&:line))
|
data/lib/baseline/version.rb
CHANGED