Skip to content

Commit 25dfd50

Browse files
authored
Merge branch 'master' into glob_modulepath_support
2 parents b833c70 + 317033b commit 25dfd50

File tree

4 files changed

+116
-18
lines changed

4 files changed

+116
-18
lines changed

lib/octocatalog-diff/catalog-diff/differ.rb

+13-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require 'diffy'
4+
require 'digest'
45
require 'hashdiff'
56
require 'json'
67
require 'set'
@@ -11,6 +12,8 @@
1112
require_relative '../util/util'
1213
require_relative 'filter'
1314

15+
HashDiff = Hashdiff unless defined? HashDiff
16+
1417
module OctocatalogDiff
1518
module CatalogDiff
1619
# Calculate the difference between two Puppet catalogs.
@@ -263,7 +266,7 @@ def filter_and_cleanup(catalog_resources)
263266

264267
# Handle parameters
265268
if k == 'parameters'
266-
cleansed_param = cleanse_parameters_hash(v)
269+
cleansed_param = cleanse_parameters_hash(v, resource.fetch('sensitive_parameters', []))
267270
hsh[k] = cleansed_param unless cleansed_param.nil? || cleansed_param.empty?
268271
elsif k == 'tags'
269272
# The order of tags is unimportant. Sort this array to avoid false diffs if order changes.
@@ -456,10 +459,18 @@ def ignored?(diff)
456459

457460
# Cleanse parameters of filtered attributes.
458461
# @param parameters_hash [Hash] Hash of parameters
462+
# @param sensitive_parameters [Array] Array of sensitive parameters
459463
# @return [Hash] Cleaned parameters hash (original input hash is not altered)
460-
def cleanse_parameters_hash(parameters_hash)
464+
def cleanse_parameters_hash(parameters_hash, sensitive_parameters)
461465
result = parameters_hash.dup
462466

467+
# hides sensitive params. We still need to know if there's a going to
468+
# be a diff, so we hash the value.
469+
sensitive_parameters.each do |p|
470+
md5 = Digest::MD5.hexdigest Marshal.dump(result[p])
471+
result[p] = 'Sensitive [md5sum ' + md5 + ']'
472+
end
473+
463474
# 'before' and 'require' handle internal Puppet ordering but do not affect what
464475
# happens on the target machine. Don't consider these for the purpose of catalog diff.
465476
result.delete('before')

lib/octocatalog-diff/util/parallel.rb

+20-16
Original file line numberDiff line numberDiff line change
@@ -129,22 +129,26 @@ def self.run_tasks_parallel(result, task_array, logger)
129129

130130
# Waiting for children and handling results
131131
while pidmap.any?
132-
this_pid, exit_obj = Process.wait2(0)
133-
next unless this_pid && pidmap.key?(this_pid)
134-
index = pidmap[this_pid][:index]
135-
exitstatus = exit_obj.exitstatus
136-
raise "PID=#{this_pid} exited abnormally: #{exit_obj.inspect}" if exitstatus.nil?
137-
raise "PID=#{this_pid} exited with status #{exitstatus}" unless exitstatus.zero?
138-
139-
input = File.read(File.join(ipc_tempdir, "#{this_pid}.dat"))
140-
result[index] = Marshal.load(input) # rubocop:disable Security/MarshalLoad
141-
time_delta = Time.now - pidmap[this_pid][:start_time]
142-
pidmap.delete(this_pid)
143-
144-
logger.debug "PID=#{this_pid} completed in #{time_delta} seconds, #{input.length} bytes"
145-
146-
next if result[index].status
147-
return result[index].exception
132+
pidmap.each do |pid|
133+
status = Process.waitpid2(pid[0], Process::WNOHANG)
134+
next if status.nil?
135+
this_pid, exit_obj = status
136+
next unless this_pid && pidmap.key?(this_pid)
137+
index = pidmap[this_pid][:index]
138+
exitstatus = exit_obj.exitstatus
139+
raise "PID=#{this_pid} exited abnormally: #{exit_obj.inspect}" if exitstatus.nil?
140+
raise "PID=#{this_pid} exited with status #{exitstatus}" unless exitstatus.zero?
141+
142+
input = File.read(File.join(ipc_tempdir, "#{this_pid}.dat"))
143+
result[index] = Marshal.load(input) # rubocop:disable Security/MarshalLoad
144+
time_delta = Time.now - pidmap[this_pid][:start_time]
145+
pidmap.delete(this_pid)
146+
147+
logger.debug "PID=#{this_pid} completed in #{time_delta} seconds, #{input.length} bytes"
148+
149+
next if result[index].status
150+
return result[index].exception
151+
end
148152
end
149153

150154
logger.debug 'All child processes completed with no exceptions raised'

spec/octocatalog-diff/tests/catalog-diff/differ_spec.rb

+24
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,30 @@
382382
result = testobj.catalog1
383383
expect(result.first['title']).to eq('/etc/foo')
384384
end
385+
386+
it 'should hide sensitive parameters' do
387+
json_hash = {
388+
'document_type' => 'Catalog',
389+
'data' => {
390+
'name' => 'rspec-node.github.net',
391+
'tags' => [],
392+
'resources' => [
393+
{
394+
'type' => 'File',
395+
'title' => 'verysecretfile',
396+
'parameters' => {
397+
'content' => 'secret1'
398+
},
399+
'sensitive_parameters' => ['content']
400+
}
401+
]
402+
}
403+
}
404+
catalog = OctocatalogDiff::Catalog.create(json: JSON.generate(json_hash))
405+
testobj = OctocatalogDiff::CatalogDiff::Differ.new(@options, catalog, @empty_puppet_catalog)
406+
result = testobj.catalog1
407+
expect(result.first['parameters']['content']).to eq('Sensitive [md5sum e52d98c459819a11775936d8dfbb7929]')
408+
end
385409
end
386410

387411
describe '#diff' do

spec/octocatalog-diff/tests/util/parallel_spec.rb

+59
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,65 @@
1616
end
1717

1818
context 'with parallel processing' do
19+
it 'should only Process.wait() its own children' do
20+
class Foo
21+
def one(arg, _logger = nil)
22+
'one ' + arg
23+
end
24+
25+
def two(arg, _logger = nil)
26+
'two ' + arg
27+
end
28+
29+
def dont_wait_me_bro(sleep_for = 1)
30+
# do we need a rescue block here?
31+
pid = fork do
32+
sleep sleep_for
33+
Kernel.exit! 0 # Kernel.exit! avoids at_exit from parents being triggered by children exiting
34+
end
35+
pid
36+
end
37+
38+
def wait_on_me(pid)
39+
status = nil
40+
# just in case status never equals anything
41+
count = 100
42+
while status.nil? || count > 0
43+
count -= 1
44+
status = Process.waitpid2(pid, Process::WNOHANG)
45+
end
46+
status
47+
end
48+
end
49+
50+
c = Foo.new
51+
# start my non-parallel process first
52+
just_a_guy = c.dont_wait_me_bro
53+
54+
one = OctocatalogDiff::Util::Parallel::Task.new(method: c.method(:one), args: 'abc', description: 'test1')
55+
two = OctocatalogDiff::Util::Parallel::Task.new(method: c.method(:two), args: 'def', description: 'test2')
56+
result = OctocatalogDiff::Util::Parallel.run_tasks([one, two], nil, true)
57+
expect(result).to be_a_kind_of(Array)
58+
expect(result.size).to eq(2)
59+
60+
one_result = result[0]
61+
expect(one_result).to be_a_kind_of(OctocatalogDiff::Util::Parallel::Result)
62+
expect(one_result.status).to eq(true)
63+
expect(one_result.exception).to eq(nil)
64+
expect(one_result.output).to match(/^one abc/)
65+
66+
two_result = result[1]
67+
expect(two_result).to be_a_kind_of(OctocatalogDiff::Util::Parallel::Result)
68+
expect(two_result.status).to eq(true)
69+
expect(two_result.exception).to eq(nil)
70+
expect(two_result.output).to match(/^two def/)
71+
72+
# just_a_guy should still be need to be waited
73+
result = c.wait_on_me(just_a_guy)
74+
expect(result).to be_a_kind_of(Array)
75+
# test result and check for error conditions
76+
end
77+
1978
it 'should parallelize and return task results' do
2079
class Foo
2180
def one(arg, _logger = nil)

0 commit comments

Comments
 (0)