aikido-zen 1.2.1 → 1.3.0.beta.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c6c3172c2e8ea724f5b362592c7c9d326396c2ff05ba98a1573ed7ed587a1e55
4
- data.tar.gz: 7c63642333e1f64c6b3011a12f52637438b98348e94754da47cb72f3c84f10ec
3
+ metadata.gz: c0416061d1a6fa8f04202889043e9dc773c4637879e9ad420f93193508e8426d
4
+ data.tar.gz: 163be1d25bfa8ce3f521dc251b15afdb5ea5d434f8f696e4497f74d38cd2e947
5
5
  SHA512:
6
- metadata.gz: 32e2a25c9f2f55a21a3bf2d6e487b36ec3b8780dcaae3db9a82324669a99bf8c0514a6bbe9c810c20b877039e0827fa2446c053f610cf1317b3d5f064bc1e653
7
- data.tar.gz: 41dda121db561eea1d99b0d4c76df3672e1d6e210e9d841e48ea467418120b3ce665151dc7dae9d889593300c40da1738bf3fa2266084fd7af603882146d21e3
6
+ metadata.gz: 2eb9f7becd746a85011c38577a83ebde83fb71c506b5bf4c0bea1a65a7958440aaa1205ed7f56fa7bdec77b69898050d88c7a1b0661cafa70cfea3d6048ebb99
7
+ data.tar.gz: 72def8195a17b242d688e072b66f1173d4cfe2ede3c67b95aa06303968f4dee9aff1e9b466b0394e21b5b8ae93086b73020c16a46c53b1c362e89b42203ebacc
@@ -0,0 +1,39 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "benchmark"
4
+ require "aikido-zen"
5
+
6
+ random_ipv4_ranges = (0..).lazy.map do
7
+ ip_int = rand(2**32)
8
+ prefix = rand(8..32)
9
+ network = IPAddr.new(ip_int, Socket::AF_INET).mask(prefix)
10
+ "#{network}/#{prefix}"
11
+ end
12
+
13
+ random_ipv6_ranges = (0..).lazy.map do
14
+ ip_int = rand(2**128)
15
+ prefix = rand(1..128)
16
+ network = IPAddr.new(ip_int, Socket::AF_INET6).mask(prefix)
17
+ "#{network}/#{prefix}"
18
+ end
19
+
20
+ random_ip_ranges = (0..).lazy.map do
21
+ (rand < 0.5) ? random_ipv4_ranges.next : random_ipv6_ranges.next
22
+ end
23
+
24
+ if __FILE__ == $0
25
+ ip_ranges = random_ip_ranges.take(1000)
26
+
27
+ ip_list = Aikido::Zen::RuntimeSettings::IPList.from_json({
28
+ "key" => "key",
29
+ "source" => "source",
30
+ "description" => "description",
31
+ "ips" => ip_ranges
32
+ })
33
+
34
+ result = Benchmark.measure do
35
+ ip_ranges.all? { |ip_range| ip_list.include?(ip_range) }
36
+ end
37
+
38
+ puts result
39
+ end
@@ -7,12 +7,15 @@ module Aikido::Zen
7
7
  attr_reader :description
8
8
  attr_reader :ips
9
9
 
10
+ attr_reader :ipv4_ranges
11
+ attr_reader :ipv6_ranges
12
+
10
13
  def self.from_json(data)
11
14
  new(
12
15
  key: data["key"],
13
16
  source: data["source"],
14
17
  description: data["description"],
15
- ips: RuntimeSettings::IPSet.from_json(data["ips"])
18
+ ips: Array(data["ips"]).map { |ip| IPAddr.new(ip) }
16
19
  )
17
20
  end
18
21
 
@@ -21,6 +24,22 @@ module Aikido::Zen
21
24
  @source = source
22
25
  @description = description
23
26
  @ips = ips
27
+
28
+ @ipv4_ranges = []
29
+ @ipv6_ranges = []
30
+
31
+ ips.each do |ip|
32
+ if ip.ipv4?
33
+ @ipv4_ranges << ip.to_range
34
+ elsif ip.ipv6?
35
+ @ipv6_ranges << ip.to_range
36
+ else
37
+ raise ArgumentError, "Unsupported IP address family: #{ip.inspect}"
38
+ end
39
+ end
40
+
41
+ @ipv4_ranges.sort_by!(&:begin)
42
+ @ipv6_ranges.sort_by!(&:begin)
24
43
  end
25
44
 
26
45
  def inspect
@@ -28,7 +47,43 @@ module Aikido::Zen
28
47
  end
29
48
 
30
49
  def include?(ip)
31
- @ips.include?(ip)
50
+ native_ip = nativize_ip(ip)
51
+ return false if native_ip.nil?
52
+
53
+ if native_ip.ipv4?
54
+ ranges_cover?(@ipv4_ranges, native_ip)
55
+ elsif native_ip.ipv6?
56
+ ranges_cover?(@ipv6_ranges, native_ip)
57
+ else
58
+ raise ArgumentError, "Unsupported IP address family: #{ip.inspect}"
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def nativize_ip(ip)
65
+ case ip
66
+ when IPAddr
67
+ ip.native
68
+ when String
69
+ begin
70
+ IPAddr.new(ip).native
71
+ rescue IPAddr::InvalidAddressError
72
+ nil
73
+ end
74
+ when nil
75
+ nil
76
+ else
77
+ raise ArgumentError, "no explicit conversion of #{ip.class} to IPAddr"
78
+ end
79
+ end
80
+
81
+ def ranges_cover?(ranges, ip)
82
+ index = ranges.bsearch_index { |range| range.begin > ip }
83
+ index = index ? index - 1 : ranges.size - 1
84
+ return false if index < 0
85
+
86
+ ranges[index].cover?(ip)
32
87
  end
33
88
  end
34
89
  end
@@ -20,6 +20,8 @@ module Aikido::Zen
20
20
 
21
21
  def include?(ip)
22
22
  native_ip = nativize_ip(ip)
23
+ return false if native_ip.nil?
24
+
23
25
  @ips.any? { |pattern| pattern === native_ip }
24
26
  end
25
27
  alias_method :===, :include?
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Aikido
4
4
  module Zen
5
- VERSION = "1.2.1"
5
+ VERSION = "1.3.0.beta.1"
6
6
 
7
7
  # The version of libzen_internals that we build against.
8
8
  LIBZEN_VERSION = "0.1.60"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: aikido-zen
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0.beta.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aikido Security
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-14 00:00:00.000000000 Z
11
+ date: 2026-04-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -82,6 +82,7 @@ files:
82
82
  - README.md
83
83
  - Rakefile
84
84
  - benchmarks/README.md
85
+ - benchmarks/ip_list/benchmark.rb
85
86
  - benchmarks/rails7.1_benchmark.js
86
87
  - benchmarks/rails7.1_sql_injection.js
87
88
  - docs/banner.svg