1+ #!/opt/puppetlabs/puppet/bin/ruby
2+ # frozen_string_literal: true
3+
4+ require 'json'
5+ require 'net/https'
6+ require 'puppet'
7+
8+ # CheckPeMasterRules task class
9+ class CheckPeMasterRules
10+ def initialize ( params )
11+ @params = params
12+ end
13+
14+ def https_client
15+ client = Net ::HTTP . new ( Puppet . settings [ :certname ] , 4433 )
16+ client . use_ssl = true
17+ client . cert = @cert ||= OpenSSL ::X509 ::Certificate . new ( File . read ( Puppet . settings [ :hostcert ] ) )
18+ client . key = @key ||= OpenSSL ::PKey ::RSA . new ( File . read ( Puppet . settings [ :hostprivkey ] ) )
19+ client . verify_mode = OpenSSL ::SSL ::VERIFY_PEER
20+ client . ca_file = Puppet . settings [ :localcacert ]
21+ client
22+ end
23+
24+ def get_pe_master_group_id
25+ net = https_client
26+ res = net . get ( '/classifier-api/v1/groups' )
27+
28+ unless res . code == '200'
29+ raise "Failed to fetch groups: HTTP #{ res . code } - #{ res . body } "
30+ end
31+
32+ groups = JSON . parse ( res . body )
33+ pe_master_group = groups . find { |group | group [ 'name' ] == 'PE Master' }
34+
35+ raise 'Could not find PE Master group' unless pe_master_group
36+ pe_master_group [ 'id' ]
37+ rescue JSON ::ParserError => e
38+ raise "Invalid JSON response from server: #{ e . message } "
39+ rescue StandardError => e
40+ raise "Error fetching PE Master group ID: #{ e . message } "
41+ end
42+
43+ def get_current_rules ( group_id )
44+ net = https_client
45+ url = "/classifier-api/v1/groups/#{ group_id } /rules"
46+ req = Net ::HTTP ::Get . new ( url )
47+ res = net . request ( req )
48+
49+ unless res . code == '200'
50+ raise "Failed to fetch rules: HTTP #{ res . code } - #{ res . body } "
51+ end
52+
53+ JSON . parse ( res . body ) [ 'rule' ]
54+ rescue JSON ::ParserError => e
55+ raise "Invalid JSON response from server: #{ e . message } "
56+ rescue StandardError => e
57+ raise "Error fetching rules: #{ e . message } "
58+ end
59+
60+ def check_rules_updated ( rules )
61+ # If not an array, return false
62+ return false unless rules . is_a? ( Array )
63+
64+ # Check if this is an 'and' rule with at least 2 elements
65+ if rules [ 0 ] == 'and' && rules . length > 1
66+ # Check if the first element is an 'or' rule for pe_compiler and pe_compiler_legacy
67+ if rules [ 1 ] . is_a? ( Array ) && rules [ 1 ] [ 0 ] == 'or'
68+ # Look for the pe_compiler and pe_compiler_legacy rules
69+ pe_compiler_found = false
70+ pe_compiler_legacy_found = false
71+
72+ rules [ 1 ] [ 1 ..-1 ] . each do |rule |
73+ if rule . is_a? ( Array ) &&
74+ rule [ 0 ] == '=' &&
75+ rule [ 1 ] . is_a? ( Array ) &&
76+ rule [ 1 ] == [ 'trusted' , 'extensions' , 'pp_auth_role' ]
77+
78+ pe_compiler_found = true if rule [ 2 ] == 'pe_compiler'
79+ pe_compiler_legacy_found = true if rule [ 2 ] == 'pe_compiler_legacy'
80+ end
81+ end
82+
83+ return pe_compiler_found && pe_compiler_legacy_found
84+ end
85+ end
86+
87+ # Check if the rule is already using a regex match
88+ if rules [ 0 ] == '~' &&
89+ rules [ 1 ] . is_a? ( Array ) &&
90+ rules [ 1 ] == [ 'trusted' , 'extensions' , 'pp_auth_role' ] &&
91+ rules [ 2 ] == '^pe_compiler.*$'
92+ return true
93+ end
94+
95+ false
96+ end
97+
98+ def execute!
99+ begin
100+ group_id = get_pe_master_group_id
101+ current_rules = get_current_rules ( group_id )
102+
103+ is_updated = check_rules_updated ( current_rules )
104+
105+ result = {
106+ 'updated' => is_updated ,
107+ 'message' => is_updated ?
108+ 'PE Master rules have already been updated with pe_compiler_legacy support' :
109+ 'PE Master rules need to be updated to support pe_compiler_legacy'
110+ }
111+
112+ puts result . to_json
113+ rescue StandardError => e
114+ puts ( { 'error' => e . message , 'updated' => false } . to_json )
115+ exit 1
116+ end
117+ end
118+ end
119+
120+ # Run the task unless an environment flag has been set
121+ unless ENV [ 'RSPEC_UNIT_TEST_MODE' ]
122+ Puppet . initialize_settings
123+ task = CheckPeMasterRules . new ( JSON . parse ( STDIN . read ) )
124+ task . execute!
125+ end
0 commit comments