Module: Ruby::Rego::Builtins::Net

Extended by:
RegistryHelpers
Defined in:
lib/ruby/rego/builtins/net.rb,
lib/ruby/rego/builtins/net/cidr_merge.rb,
lib/ruby/rego/builtins/net/contains_matches.rb

Overview

net.cidr_contains_matches — the cidr-vs-address containment cross-product. Lives apart from the net.* core so that file stays under RubyCritic’s complexity budget. Reopens Net; bare references to shared helpers (parse_cidr, parse_addr, normalize, raise_invalid_addr) resolve via the reopened module’s lexical scope.

Constant Summary collapse

MAX_EXPAND_SIZE =

cidr_expand has no bound in OPA (it relies on Go’s runtime); expanding a CIDR with more than this many addresses yields undefined here. A /12 (IPv4) is ~1M.

1_000_000
NET_FUNCTIONS =
{
  "net.cidr_contains" => { arity: 2, handler: :cidr_contains },
  "net.cidr_contains_matches" => { arity: 2, handler: :cidr_contains_matches },
  "net.cidr_expand" => { arity: 1, handler: :cidr_expand },
  "net.cidr_intersects" => { arity: 2, handler: :cidr_intersects },
  "net.cidr_is_valid" => { arity: 1, handler: :cidr_is_valid },
  "net.cidr_merge" => { arity: 1, handler: :cidr_merge }
}.freeze
IPV4_BITS =
32
IPV6_BITS =
128
V4_MAPPED_OFFSET =

Offset of the IPv4-mapped IPv6 block (::ffff:0:0/96); IPv4 ranges live here in the unified merge space so a containing IPv6 range absorbs them as OPA does.

0xFFFF << 32

Class Method Summary collapse

Methods included from RegistryHelpers

register_configured_functions

Class Method Details

.cidr_contains(cidr_value, other_value) ⇒ Ruby::Rego::BooleanValue

True when cidr (a CIDR) contains other (an IP or CIDR). Undefined if cidr is not a valid CIDR, other is not a valid IP/CIDR, or either is non-string.

Parameters:

Returns:



61
62
63
64
65
# File 'lib/ruby/rego/builtins/net.rb', line 61

def self.cidr_contains(cidr_value, other_value)
  cidr = normalize(cidr_arg(cidr_value, "net.cidr_contains"))
  other = normalize(addr_arg(other_value, "net.cidr_contains"))
  BooleanValue.new(cidr.include?(other))
end

.cidr_contains_matches(cidrs, addrs) ⇒ Set<Array>

The set of [cidr_key, addr_key] pairs for which a CIDR in the first collection contains an address/CIDR in the second. Each operand may be an array (key is the index), object (key is the key), set or scalar (key is the element itself). A first-collection element must be a valid CIDR, a second-collection element a valid IP or CIDR; any non-string or unparseable element yields undefined.

Parameters:

Returns:

  • (Set<Array>)


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/ruby/rego/builtins/net/contains_matches.rb', line 20

def self.cidr_contains_matches(cidrs, addrs)
  context = "net.cidr_contains_matches"
  networks = entries(cidrs)
  return Set.new if networks.empty?

  # OPA structurally checks every cidr-side element (it must be a string or a
  # non-empty array) even with no addresses, but only value-parses — and touches the
  # address side at all — once the address side is non-empty.
  validate_structure(networks, context)
  addresses = entries(addrs)
  return Set.new if addresses.empty?

  containment_pairs(
    networks.map { |key, element| [key, normalize(cidr_from(element, context))] },
    addresses.map { |key, element| [key, normalize(addr_from(element, context))] }
  )
end

.cidr_expand(value) ⇒ Set<String>

Expands a CIDR into the set of every address it contains (host bits are masked to the network first, matching OPA). The argument must be a valid CIDR (a prefix is required); a non-string, an invalid CIDR, or a block larger than MAX_EXPAND_SIZE yields undefined.

Parameters:

Returns:

  • (Set<String>)


99
100
101
102
103
# File 'lib/ruby/rego/builtins/net.rb', line 99

def self.cidr_expand(value)
  cidr = cidr_arg(value, "net.cidr_expand")
  guard_expand_size(cidr, "net.cidr_expand")
  Set.new(cidr.to_range.map { |address| normalize(address).to_s })
end

.cidr_intersects(cidr1_value, cidr2_value) ⇒ Ruby::Rego::BooleanValue

True when the two CIDRs overlap. Aligned CIDR blocks are either nested or disjoint, so they intersect iff one contains the other. Both arguments must be valid CIDRs (a bare IP is undefined), matching OPA.

Parameters:

Returns:



74
75
76
77
78
# File 'lib/ruby/rego/builtins/net.rb', line 74

def self.cidr_intersects(cidr1_value, cidr2_value)
  first = normalize(cidr_arg(cidr1_value, "net.cidr_intersects"))
  second = normalize(cidr_arg(cidr2_value, "net.cidr_intersects"))
  BooleanValue.new(first.include?(second) || second.include?(first))
end

.cidr_is_valid(value) ⇒ Ruby::Rego::BooleanValue

True when value is a string in valid CIDR notation (prefix length required). Total over runtime values: a non-string yields false, matching OPA.

:reek:NilCheck

Parameters:

Returns:



86
87
88
89
90
# File 'lib/ruby/rego/builtins/net.rb', line 86

def self.cidr_is_valid(value)
  return BooleanValue.new(false) unless value.is_a?(StringValue)

  BooleanValue.new(!parse_cidr(value.value).nil?)
end

.cidr_merge(value) ⇒ Set<String>

Merges a list (array or set) of IP addresses and CIDRs into the smallest set of CIDRs covering exactly the same addresses, matching OPA (a port of Cilium’s algorithm). A bare IPv4 address takes its classful default mask; a bare IPv6 address is undefined (a prefix is required), as is a non-string element, an unparseable element, or a non-collection operand. IPv4 ranges are merged in their ::ffff: IPv6-mapped block, so a containing IPv6 range (e.g. ::/0) absorbs them just as OPA does. A CIDR is masked to its network; a bare address keeps its host form unless it is merged with another.

Parameters:

Returns:

  • (Set<String>)


31
32
33
# File 'lib/ruby/rego/builtins/net/cidr_merge.rb', line 31

def self.cidr_merge(value)
  Set.new(merge_group(merge_operands(value, "net.cidr_merge")))
end

.register!Ruby::Rego::Builtins::BuiltinRegistry



47
48
49
50
51
# File 'lib/ruby/rego/builtins/net.rb', line 47

def self.register!
  registry = BuiltinRegistry.instance
  register_configured_functions(registry, NET_FUNCTIONS)
  registry
end