1
+ #!/opt/puppetlabs/puppet/bin/ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'json'
5
+ require 'net/https'
6
+ require 'puppet'
7
+
8
+ # UpdatePeMasterRules task class
9
+ class UpdatePeMasterRules
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 transform_rule ( rule )
61
+ return rule unless rule . is_a? ( Array )
62
+
63
+ if rule [ 0 ] == '=' &&
64
+ rule [ 1 ] . is_a? ( Array ) &&
65
+ rule [ 1 ] == [ 'trusted' , 'extensions' , 'pp_auth_role' ] &&
66
+ rule [ 2 ] == 'pe_compiler'
67
+ return [ '~' , [ 'trusted' , 'extensions' , 'pp_auth_role' ] , '^pe_compiler(?:_legacy)?$' ]
68
+ end
69
+
70
+ # Recursively transform nested rules
71
+ rule . map { |element | transform_rule ( element ) }
72
+ end
73
+
74
+ def update_rules ( group_id )
75
+ net = https_client
76
+ begin
77
+ current_rules = get_current_rules ( group_id )
78
+
79
+ # Transform rules recursively to handle nested structures
80
+ new_rules = transform_rule ( current_rules )
81
+
82
+ # Update the group with the modified rules
83
+ url = "/classifier-api/v1/groups/#{ group_id } "
84
+ req = Net ::HTTP ::Post . new ( url )
85
+ req [ 'Content-Type' ] = 'application/json'
86
+ req . body = { rule : new_rules } . to_json
87
+
88
+ res = net . request ( req )
89
+
90
+ case res . code
91
+ when '200' , '201' , '204'
92
+ puts "Successfully transformed pe_compiler rule to use regex match for *_compiler roles in group #{ group_id } "
93
+ else
94
+ begin
95
+ error_body = JSON . parse ( res . body . to_s )
96
+ raise "Failed to update rules: #{ error_body [ 'kind' ] || error_body } "
97
+ rescue JSON ::ParserError
98
+ raise "Invalid response from server (status #{ res . code } ): #{ res . body } "
99
+ end
100
+ end
101
+ rescue StandardError => e
102
+ raise "Error during rules update: #{ e . message } "
103
+ end
104
+ end
105
+
106
+ def execute!
107
+ group_id = get_pe_master_group_id
108
+ update_rules ( group_id )
109
+ end
110
+ end
111
+
112
+ # Run the task unless an environment flag has been set
113
+ unless ENV [ 'RSPEC_UNIT_TEST_MODE' ]
114
+ Puppet . initialize_settings
115
+ task = UpdatePeMasterRules . new ( JSON . parse ( STDIN . read ) )
116
+ task . execute!
117
+ end
0 commit comments