ctx_checker 0.2.2 → 0.2.3
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 +6 -0
- data/lib/ctx_checker/checks/routing.rb +10 -1
- data/lib/ctx_checker/observation_merger.rb +22 -3
- data/lib/ctx_checker/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: 5439af7466ca88a19bb7e41cacb918eb78e73d8ae84b2390a060dfa75d5aba4a
|
|
4
|
+
data.tar.gz: b016023aac35315ea418c880a5b1feb29e277791702351feed6115e8eaaf0cd8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e087da6d36474f725cc0626762f79bdfd8b22fb28800fbb4fb98ce461ced95d6f8c72383e33be627c8ea513fe6ac988a0448d4a54ef6a1c6352ba11f2f673b91
|
|
7
|
+
data.tar.gz: bfa74421c286aefad66d9c7f2266367c79f2b6b006198b4ee461569f8ec4226b14046aeb7f8137872c38cafebe3187f35b7828c1c027b456a061430a7c9867be
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,12 @@
|
|
|
2
2
|
|
|
3
3
|
Changes to the public contract are recorded here. Versions follow Semantic Versioning.
|
|
4
4
|
|
|
5
|
+
## 0.2.3 (2026-10-18)
|
|
6
|
+
|
|
7
|
+
- Clear Bundler bootstrap variables when verifying packages in an isolated gem installation, including calls made through bundle exec.
|
|
8
|
+
|
|
9
|
+
- Index protocol coverage and conflicting scopes by field sets, preserving wildcard identities and OSPF interface scopes without quadratic scans.
|
|
10
|
+
|
|
5
11
|
## 0.2.2 (2026-10-18)
|
|
6
12
|
|
|
7
13
|
- Snapshot validated collection targets and dimensions before caller callbacks can alter them.
|
|
@@ -57,6 +57,7 @@ module CtxChecker
|
|
|
57
57
|
identities = {}
|
|
58
58
|
scopes = {}
|
|
59
59
|
incomplete = Hash.new { |hash, keys| hash[keys] = {} }
|
|
60
|
+
covered = covered_scope_index
|
|
60
61
|
@observation.records.each do |record|
|
|
61
62
|
identities[record.values_at(*fields)] = true
|
|
62
63
|
scopes[record.values_at(*scope)] = true
|
|
@@ -67,7 +68,7 @@ module CtxChecker
|
|
|
67
68
|
next if identities.key?(identity.values_at(*fields))
|
|
68
69
|
|
|
69
70
|
ambiguous = incomplete.any? { |keys, values| values.key?(identity.values_at(*keys)) }
|
|
70
|
-
enumerated =
|
|
71
|
+
enumerated = covered.any? { |keys, values| values.key?(identity.values_at(*keys)) }
|
|
71
72
|
scope_observed = scopes.key?(identity.values_at(*scope))
|
|
72
73
|
status = if ambiguous
|
|
73
74
|
:unknown
|
|
@@ -81,6 +82,14 @@ module CtxChecker
|
|
|
81
82
|
finding(status, :expected_peer_missing, entity: identity, severity: :critical)
|
|
82
83
|
end
|
|
83
84
|
end
|
|
85
|
+
|
|
86
|
+
# 按字段组合索引覆盖范围;OSPF 的进程级与接口级证明分别匹配。
|
|
87
|
+
def covered_scope_index
|
|
88
|
+
@observation.covered_scopes.each_with_object({}) do |entry, index|
|
|
89
|
+
fields = entry.keys.sort
|
|
90
|
+
(index[fields] ||= {})[entry.values_at(*fields)] = true
|
|
91
|
+
end
|
|
92
|
+
end
|
|
84
93
|
end
|
|
85
94
|
end
|
|
86
95
|
end
|
|
@@ -48,9 +48,9 @@ module CtxChecker
|
|
|
48
48
|
issues << { code: :duplicate_identity, count: grouped.duplicate_identity_count }
|
|
49
49
|
records = grouped.unambiguous.dup
|
|
50
50
|
# 隔离的对等体实际已被观察到,因此移除后不能再据其作用域证明缺失。
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
51
|
+
if covered_scopes.any?
|
|
52
|
+
ambiguous = grouped.first_occurrences - grouped.unambiguous
|
|
53
|
+
covered_scopes = unambiguous_scopes(covered_scopes, ambiguous)
|
|
54
54
|
end
|
|
55
55
|
end
|
|
56
56
|
if name == :counters && required_metrics.any?
|
|
@@ -78,5 +78,24 @@ module CtxChecker
|
|
|
78
78
|
Observation.new(name: name, status: status, records: records, issues: issues.uniq,
|
|
79
79
|
covered_scopes: covered_scopes, evidence: observations.flat_map(&:evidence))
|
|
80
80
|
end
|
|
81
|
+
|
|
82
|
+
# 各覆盖字段组合只建立一次冲突索引,保留原有范围顺序。
|
|
83
|
+
def self.unambiguous_scopes(scopes, records)
|
|
84
|
+
indexes = scopes.map { |scope| scope.keys.sort }.uniq.to_h do |fields|
|
|
85
|
+
[ fields, ambiguity_index(records, fields) ]
|
|
86
|
+
end
|
|
87
|
+
scopes.reject do |scope|
|
|
88
|
+
indexes.fetch(scope.keys.sort).any? { |fields, values| values.key?(scope.values_at(*fields)) }
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
# 冲突记录中缺失的字段仍匹配任意值,不能据此证明某个范围为空。
|
|
93
|
+
def self.ambiguity_index(records, fields)
|
|
94
|
+
records.each_with_object({}) do |record, index|
|
|
95
|
+
present = fields.reject { |field| record[field].nil? }
|
|
96
|
+
(index[present] ||= {})[record.values_at(*present)] = true
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
private_class_method :unambiguous_scopes, :ambiguity_index
|
|
81
100
|
end
|
|
82
101
|
end
|
data/lib/ctx_checker/version.rb
CHANGED