Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
AriaXLi committed Aug 7, 2024
1 parent 465c119 commit 519dfc0
Show file tree
Hide file tree
Showing 2 changed files with 115 additions and 0 deletions.
94 changes: 94 additions & 0 deletions acceptance/tests/facts/schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
test_name "Validate facter output conforms to schema" do
tag 'risk:high'

require 'yaml'
require 'ipaddr'
# require 'psych'
# require 'json'
# require 'facter/acceptance/base_fact_utils'

# Extra credit to make this a spec test so it runs on PRs too...

# @param
# @return
def validate_fact(schema_fact, schema_fact_value, output_fact, output_fact_value)
fact_type = output_fact_value.class.to_s
schema_fact_type = schema_fact ? schema_fact_value["type"].capitalize : nil
if fact_type == "Hash"
fact_type = "Map"
end
if fact_type == "TrueClass" || fact_type == "FalseClass" #boolean.class returns FalseClass or TrueClass
fact_type = "Boolean"
end
if fact_type == "Float"
fact_type = "Double"
end
ipv4_regex = Regexp.new('^((25[0-5]|(2[0-4]|1\d|[1-9]|)\d)\.?\b){4}$')
ipv6_regex = Regexp.new('^(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))$')
mac_regex = Regexp.new('^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$')
if schema_fact_type == "Ip"
fact_type = ipv4_regex.match?(output_fact_value) ? "Ip" : fact_type
end
if schema_fact_type == "Ip6"
fact_type = ipv6_regex.match?(output_fact_value) ? "Ip6" : fact_type
end
if schema_fact_type == "Mac"
fact_type = mac_regex.match?(output_fact_value) ? "Mac" : fact_type
end
if fact_type == "Map"
schema_elements = schema_fact_value["elements"]
output_fact_value.each do |fact, value|
if value.nil? || !schema_elements
puts "skipped"
puts "fact: #{fact} fact value: #{value}"
puts "no schema elements: #{schema_elements} \n\n"
next
end
schema_fact, schema_fact_value = get_fact(schema_elements, fact)
validate_fact(schema_fact, schema_fact_value, fact, value)
end
end
if fact_type != schema_fact_type
puts "#{output_fact} has value: #{output_fact_value} and type: #{fact_type} does not conform to schema fact value type: #{schema_fact_type} \n\n"
end
#assert_match(fact_type, schema_fact_type, "#{output_fact} has value: #{output_fact_value} and type: #{fact_type} does not conform to schema fact value type: #{schema_fact_type}")
end

# @param
# @return
def get_fact(fact_hash, fact_name)
fact_hash.each_key do |fact|
fact_pattern = fact_hash[fact]["pattern"]
fact_regex = fact_pattern ? Regexp.new(fact_pattern) : nil
if (fact_pattern && fact_regex.match?(fact_name)) || fact_name == fact
return fact, fact_hash[fact]
end
end
return nil
end

step 'Validate fact collection conforms to schema' do
agents.each do |agent|

# Load schema to compare to output_facts
PATH_TO_SCHEMA = File.join(File.dirname(__FILE__), '../../../lib/schema/facter.yaml')
schema = YAML.load_file(PATH_TO_SCHEMA)


on(agent, facter('--yaml')) do |facter_output|

#get facter output for each platform
output_facts = YAML.load(facter_output.stdout)

# validate facter output matches schema
output_facts.each do |fact, value|
schema_fact, schema_fact_value = get_fact(schema, fact)
#fact_type, schema_fact_type = validate_fact(schema_fact, schema_fact_value, fact, value)
validate_fact(schema_fact, schema_fact_value, fact, value)
# puts "fact: #{fact}"
# puts "value: #{value}\n\n"
end
end
end
end
end
21 changes: 21 additions & 0 deletions lib/schema/facter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,9 @@ dmi:
uuid:
type: string
description: The product unique identifier of the system.
version:
type: string
description: The product model information of the system.

domain:
type: string
Expand Down Expand Up @@ -1031,6 +1034,9 @@ networking:
dhcp:
type: ip
description: The DHCP server for the network interface.
duplex:
type: string
description: The duplex settings for physical network interfaces on Linux using /sys/class/net.
ip:
type: ip
description: The IPv4 address for the network interface.
Expand All @@ -1055,9 +1061,18 @@ networking:
network6:
type: ip6
description: The IPv6 network for the network interface.
operational_state:
type: string
description: Linux only? TODO
physical:
type: boolean
description: Return whether network interface is a physical device on Linux based systems.
scope6:
type: string
description: The IPv6 scope for the network interface.
speed:
type: integer
description: The speed of physical network interfaces on Linux using /sys/class/net.
ip:
type: ip
description: The IPv4 address of the default network interface.
Expand Down Expand Up @@ -1182,6 +1197,9 @@ os:
type: map
description: Represents information about the Mac OSX version.
elements:
extra:
type: string
description: The ProductVersionExtra value. Only supported on macOS 13 and later.
full:
type: string
description: The full Mac OSX version number.
Expand Down Expand Up @@ -1366,6 +1384,9 @@ processors:
count:
type: integer
description: The count of logical processors.
extensions:
type: array
description: The CPU extensions the processor supports.
isa:
type: string
description: The processor instruction set architecture.
Expand Down

0 comments on commit 519dfc0

Please sign in to comment.