Skip to content

Commit 4df8f9b

Browse files
committed
(CAT-1260) firewallchain Provider unit tests
1 parent 3f70d07 commit 4df8f9b

File tree

1 file changed

+350
-0
lines changed

1 file changed

+350
-0
lines changed
Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,350 @@
1+
# frozen_string_literal: true
2+
3+
require 'spec_helper'
4+
require 'puppet/resource_api'
5+
6+
ensure_module_defined('Puppet::Provider::Firewallchain')
7+
require 'puppet/provider/firewallchain/firewallchain'
8+
9+
RSpec.describe Puppet::Provider::Firewallchain::Firewallchain do
10+
describe 'Public Methods' do
11+
subject(:provider) { described_class.new }
12+
13+
let(:type) { Puppet::Type.type('firewallchain') }
14+
let(:context) { Puppet::ResourceApi::BaseContext.new(type.type_definition.definition) }
15+
16+
describe 'get(_context)' do
17+
let(:iptables) do
18+
'
19+
# Generated by iptables-save v1.8.4 on Thu Aug 10 10:15:14 2023
20+
*filter
21+
:INPUT ACCEPT [62:3308]
22+
:FORWARD ACCEPT [0:0]
23+
:OUTPUT ACCEPT [39:3092]
24+
:TEST_ONE - [0:0]
25+
COMMIT
26+
# Completed on Thu Aug 10 10:15:14 2023
27+
# Generated by iptables-save v1.8.4 on Thu Aug 10 10:15:14 2023
28+
*raw
29+
:PREROUTING ACCEPT [13222:23455532]
30+
:OUTPUT ACCEPT [12523:852730]
31+
:TEST_TWO - [0:0]
32+
COMMIT
33+
# Completed on Thu Aug 10 10:15:14 2023
34+
'
35+
end
36+
let(:ip6tables) do
37+
'
38+
# Generated by ip6tables-save v1.8.4 on Thu Aug 10 10:21:55 2023
39+
*filter
40+
:INPUT ACCEPT [0:0]
41+
:FORWARD ACCEPT [0:0]
42+
:OUTPUT ACCEPT [13:824]
43+
COMMIT
44+
# Completed on Thu Aug 10 10:21:55 2023
45+
'
46+
end
47+
let(:returned_data) do
48+
[{ name: 'INPUT:filter:IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
49+
{ name: 'FORWARD:filter:IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
50+
{ name: 'OUTPUT:filter:IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
51+
{ name: 'TEST_ONE:filter:IPv4', purge: false, ignore_foreign: false, ensure: 'present' },
52+
{ name: 'PREROUTING:raw:IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
53+
{ name: 'OUTPUT:raw:IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
54+
{ name: 'TEST_TWO:raw:IPv4', purge: false, ignore_foreign: false, ensure: 'present' },
55+
{ name: 'INPUT:filter:IPv6', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
56+
{ name: 'FORWARD:filter:IPv6', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
57+
{ name: 'OUTPUT:filter:IPv6', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' }]
58+
end
59+
60+
it 'processes the resource' do
61+
allow(Puppet::Util::Execution).to receive(:execute).with('iptables-save').and_return(iptables)
62+
allow(Puppet::Util::Execution).to receive(:execute).with('ip6tables-save').and_return(ip6tables)
63+
64+
expect(provider.get(context)).to eq(returned_data)
65+
end
66+
end
67+
68+
describe 'create(context, name, should)' do
69+
[
70+
{
71+
should: { name: 'TEST_ONE:filter:IPv4', chain: 'TEST_ONE', table: 'filter', protocol: 'IPv4', purge: false, ignore_foreign: false, ensure: 'present' },
72+
create_command: 'iptables -t filter -N TEST_ONE'
73+
},
74+
{
75+
should: { name: 'TEST_TWO:raw:IPv6', chain: 'TEST_TWO', table: 'raw', protocol: 'IPv6', purge: false, ignore_foreign: false, ensure: 'present' },
76+
create_command: 'ip6tables -t raw -N TEST_TWO'
77+
},
78+
].each do |test|
79+
it "creates the resource: '#{test[:should][:name]}'" do
80+
expect(context).to receive(:notice).with(%r{\ACreating Chain '#{test[:should][:name]}'})
81+
expect(Puppet::Util::Execution).to receive(:execute).with(test[:create_command])
82+
allow(PuppetX::Firewall::Utility).to receive(:persist_iptables).with(context, test[:should][:name], test[:should][:protocol])
83+
84+
provider.create(context, test[:should][:name], test[:should])
85+
end
86+
end
87+
end
88+
89+
describe 'update(context, name, should, is)' do
90+
context 'when passed valid input' do
91+
[
92+
{
93+
should: { name: 'INPUT:filter:IPv4', chain: 'INPUT', table: 'filter', protocol: 'IPv4', ensure: 'present', policy: 'drop' },
94+
is: { name: 'INPUT:filter:IPv4', chain: 'INPUT', table: 'filter', protocol: 'IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
95+
update_command: 'iptables -t filter -P INPUT DROP'
96+
},
97+
{
98+
should: { name: 'OUTPUT:raw:IPv6', chain: 'OUTPUT', table: 'raw', protocol: 'IPv6', ensure: 'present', policy: 'queue' },
99+
is: { name: 'OUTPUT:raw:IPv6', chain: 'OUTPUT', table: 'raw', protocol: 'IPv6', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
100+
update_command: 'ip6tables -t raw -P OUTPUT QUEUE'
101+
},
102+
].each do |test|
103+
it "updates the resource: '#{test[:should]}'" do
104+
expect(context).to receive(:notice).with(%r{\AUpdating Chain '#{test[:should][:name]}'})
105+
expect(Puppet::Util::Execution).to receive(:execute).with(test[:update_command])
106+
allow(PuppetX::Firewall::Utility).to receive(:persist_iptables).with(context, test[:should][:name], test[:should][:protocol])
107+
108+
provider.update(context, test[:should][:name], test[:should], test[:is])
109+
end
110+
end
111+
end
112+
113+
context 'when passed invalid input' do
114+
[
115+
{
116+
should: { name: 'INPUT:filter:IPv4', chain: 'INPUT', table: 'filter', protocol: 'IPv4', ensure: 'present', policy: 'accept' },
117+
is: { name: 'INPUT:filter:IPv4', chain: 'INPUT', table: 'filter', protocol: 'IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
118+
update_command: 'iptables -t filter -P INPUT DROP'
119+
},
120+
{
121+
should: { name: 'TEST_ONE:raw:IPv6', chain: 'TEST_ONE', table: 'raw', protocol: 'IPv6', ensure: 'present', policy: 'queue' },
122+
is: { name: 'TEST_ONE:raw:IPv6', chain: 'TEST_ONE', table: 'raw', protocol: 'IPv6', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
123+
update_command: 'ip6tables -t raw -P OUTPUT QUEUE'
124+
},
125+
].each do |test|
126+
it "does not update the resource: '#{test[:should]}'" do
127+
expect(context).not_to receive(:notice).with(%r{\AUpdating Chain '#{test[:should][:name]}'})
128+
expect(Puppet::Util::Execution).not_to receive(:execute).with(test[:update_command])
129+
130+
provider.update(context, test[:should][:name], test[:should], test[:is])
131+
end
132+
end
133+
end
134+
end
135+
136+
describe 'delete(context, name, is)' do
137+
context 'with custom chains' do
138+
[
139+
{
140+
is: { name: 'TEST_ONE:filter:IPv4', chain: 'TEST_ONE', table: 'filter', protocol: 'IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
141+
flush_command: 'iptables -t filter -F TEST_ONE',
142+
delete_command: 'iptables -t filter -X TEST_ONE'
143+
},
144+
{
145+
is: { name: 'TEST_TWO:raw:IPv6', chain: 'TEST_TWO', table: 'raw', protocol: 'IPv6', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
146+
flush_command: 'ip6tables -t raw -F TEST_TWO',
147+
delete_command: 'ip6tables -t raw -X TEST_TWO'
148+
},
149+
].each do |test|
150+
it "deletes the resource: '#{test[:is]}'" do
151+
allow(context).to receive(:notice).with(%r{\AFlushing Chain '#{test[:is][:name]}'})
152+
expect(Puppet::Util::Execution).to receive(:execute).with(test[:flush_command])
153+
allow(context).to receive(:notice).with(%r{\ADeleting Chain '#{test[:is][:name]}'})
154+
expect(Puppet::Util::Execution).to receive(:execute).with(test[:delete_command])
155+
allow(PuppetX::Firewall::Utility).to receive(:persist_iptables).with(context, test[:is][:name], test[:is][:protocol])
156+
157+
provider.delete(context, test[:is][:name], test[:is])
158+
end
159+
end
160+
end
161+
162+
context 'with inbuilt chains' do
163+
[
164+
{
165+
is: { name: 'INPUT:filter:IPv4', chain: 'INPUT', table: 'filter', protocol: 'IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'drop' },
166+
flush_command: 'iptables -t filter -F INPUT',
167+
revert_command: 'iptables -t filter -P INPUT ACCEPT'
168+
},
169+
{
170+
is: { name: 'OUTPUT:raw:IPv6', chain: 'OUTPUT', table: 'raw', protocol: 'IPv6', purge: false, ignore_foreign: false, ensure: 'present', policy: 'queue' },
171+
flush_command: 'ip6tables -t raw -F OUTPUT',
172+
revert_command: 'ip6tables -t raw -P OUTPUT ACCEPT'
173+
},
174+
].each do |test|
175+
it "reverts the resource: '#{test[:is]}'" do
176+
allow(context).to receive(:notice).with(%r{\AFlushing Chain '#{test[:is][:name]}'})
177+
expect(Puppet::Util::Execution).to receive(:execute).with(test[:flush_command])
178+
allow(context).to receive(:notice).with(%r{\AReverting Internal Chain '#{test[:is][:name]}'})
179+
expect(Puppet::Util::Execution).to receive(:execute).with(test[:revert_command])
180+
allow(PuppetX::Firewall::Utility).to receive(:persist_iptables).with(context, test[:is][:name], test[:is][:protocol])
181+
182+
provider.delete(context, test[:is][:name], test[:is])
183+
end
184+
end
185+
end
186+
end
187+
188+
describe 'insync?(context, _name, property_name, _is_hash, _should_hash)' do
189+
[
190+
{ name: 'TEST_ONE:filter:IPv4', property_name: :name, is_hash: {}, should_hash: {}, result: nil },
191+
{ name: 'TEST_ONE:filter:IPv4', property_name: :policy, is_hash: {}, should_hash: {}, result: nil },
192+
{ name: 'TEST_ONE:filter:IPv4', property_name: :purge, is_hash: {}, should_hash: {}, result: true },
193+
{ name: 'TEST_ONE:filter:IPv4', property_name: :ignore, is_hash: {}, should_hash: {}, result: true },
194+
{ name: 'TEST_ONE:filter:IPv4', property_name: :ignore_foreign, is_hash: {}, should_hash: {}, result: true },
195+
{ name: 'TEST_ONE:filter:IPv4', property_name: :ensure, is_hash: {}, should_hash: {}, result: nil },
196+
].each do |test|
197+
it "check value is insync: '#{test[:property_name]}'" do
198+
expect(context).to receive(:debug).with(%r{\AChecking whether '#{test[:property_name]}'})
199+
expect(provider.insync?(context, test[:name], test[:property_name], test[:is_hash], test[:should_hash])).to eql(test[:result])
200+
end
201+
end
202+
end
203+
204+
describe 'generate' do
205+
let(:iptables) do
206+
'
207+
# Generated by iptables-save v1.8.4 on Thu Aug 10 10:15:14 2023
208+
*filter
209+
:INPUT ACCEPT [62:3308]
210+
:FORWARD ACCEPT [0:0]
211+
:OUTPUT ACCEPT [39:3092]
212+
:TEST_ONE - [0:0]
213+
COMMIT
214+
-A TEST_ONE -p tcp -m comment --comment "001 test rule"
215+
-A INPUT -p tcp -m comment --comment "004 test rule"
216+
-A TEST_ONE -p tcp -m comment --comment "ignore_this foreign"
217+
-A TEST_ONE -p tcp -m comment --comment "foreign"
218+
# Completed on Thu Aug 10 10:15:14 2023
219+
# Generated by iptables-save v1.8.4 on Thu Aug 10 10:15:14 2023
220+
*raw
221+
:PREROUTING ACCEPT [13222:23455532]
222+
:OUTPUT ACCEPT [12523:852730]
223+
COMMIT
224+
-A OUTPUT -p tcp -m comment --comment "003 test rule"
225+
# Completed on Thu Aug 10 10:15:14 2023
226+
'
227+
end
228+
let(:ip6tables) do
229+
'
230+
# Generated by ip6tables-save v1.8.4 on Thu Aug 10 10:21:55 2023
231+
*filter
232+
:INPUT ACCEPT [0:0]
233+
:FORWARD ACCEPT [0:0]
234+
:OUTPUT ACCEPT [13:824]
235+
:TEST_TWO - [0:0]
236+
COMMIT
237+
-A OUTPUT -p tcp -m comment --comment "005 test rule"
238+
# Completed on Thu Aug 10 10:21:55 2023
239+
*raw
240+
:PREROUTING ACCEPT [13222:23455532]
241+
:OUTPUT ACCEPT [12523:852730]
242+
COMMIT
243+
-A TEST_TWO -p tcp -m comment --comment "002 test rule"
244+
# Completed on Thu Aug 10 10:21:55 2023
245+
'
246+
end
247+
248+
[
249+
{
250+
should: { name: 'TEST_ONE:filter:IPv4', purge: true, ensure: 'present' },
251+
purge: ['001 test rule', '9003 ignore_this foreign', '9004 foreign']
252+
},
253+
{
254+
should: { name: 'TEST_ONE:filter:IPv4', purge: true, ignore: 'ignore_this', ensure: 'present' },
255+
purge: ['001 test rule', '9004 foreign']
256+
},
257+
{
258+
should: { name: 'TEST_ONE:filter:IPv4', purge: true, ignore_foreign: true, ensure: 'present' },
259+
purge: ['001 test rule']
260+
},
261+
{
262+
should: { name: 'TEST_TWO:raw:IPv6', purge: true, ensure: 'present' },
263+
purge: ['002 test rule']
264+
},
265+
].each do |test|
266+
before(:each) do
267+
allow(Puppet::Util::Execution).to receive(:execute).with('iptables-save').and_return(iptables)
268+
allow(Puppet::Util::Execution).to receive(:execute).with('ip6tables-save').and_return(ip6tables)
269+
end
270+
271+
it "purge chain: '#{test[:should]}'" do
272+
resources = provider.generate(context, test[:should][:name], {}, test[:should])
273+
274+
names = []
275+
resources.each do |resource|
276+
names << resource.rsapi_current_state[:name]
277+
end
278+
279+
expect(names).to eq(test[:purge])
280+
end
281+
end
282+
end
283+
end
284+
285+
describe 'Private Methods' do
286+
subject(:provider) { described_class }
287+
288+
describe 'self.process_input(is, should)' do
289+
[
290+
{
291+
input: {
292+
is: { title: 'INPUT:filter:IPv4', purge: false, ignore_foreign: false },
293+
should: { name: 'INPUT:filter:IPv4', ensure: 'present' }
294+
},
295+
output: {
296+
is: { title: 'INPUT:filter:IPv4', name: 'INPUT:filter:IPv4', chain: 'INPUT', table: 'filter', protocol: 'IPv4', purge: false, ignore_foreign: false, ensure: 'present', policy: 'accept' },
297+
should: { name: 'INPUT:filter:IPv4', chain: 'INPUT', table: 'filter', protocol: 'IPv4', ensure: 'present', policy: 'accept' }
298+
}
299+
},
300+
].each do |test|
301+
it { expect(provider.process_input(test[:input][:is], test[:input][:should])).to eql([test[:output][:is], test[:output][:should]]) }
302+
end
303+
end
304+
305+
describe 'self.verify(_is, should)' do
306+
[
307+
{
308+
should: { name: 'PREROUTING:filter:IPv4', chain: 'PREROUTING', table: 'filter', protocol: 'IPv4', ensure: 'present', policy: 'accept' },
309+
error: 'INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table \'filter\''
310+
},
311+
{
312+
should: { name: 'BROUTING:mangle:IPv4', chain: 'BROUTING', table: 'mangle', protocol: 'IPv4', ensure: 'present', policy: 'accept' },
313+
error: 'PREROUTING, POSTROUTING, INPUT, FORWARD and OUTPUT are the only inbuilt chains that can be used in table \'mangle\''
314+
},
315+
{
316+
should: { name: 'FORWARD:nat:IPv4', chain: 'FORWARD', table: 'nat', protocol: 'IPv4', ensure: 'present', policy: 'accept' },
317+
error: 'PREROUTING, POSTROUTING, INPUT, and OUTPUT are the only inbuilt chains that can be used in table \'nat\''
318+
},
319+
{
320+
should: { name: 'PREROUTING:nat:IPv6', chain: 'PREROUTING', table: 'nat', protocol: 'IPv6', ensure: 'present', policy: 'accept' },
321+
error: 'table nat isn\'t valid in IPv6. You must specify \':IPv4\' as the name suffix'
322+
},
323+
{
324+
should: { name: 'INPUT:raw:IPv4', chain: 'INPUT', table: 'raw', protocol: 'IPv4', ensure: 'present', policy: 'accept' },
325+
error: 'PREROUTING and OUTPUT are the only inbuilt chains in the table \'raw\''
326+
},
327+
{
328+
should: { name: 'BROUTING:broute:IPv4', chain: 'BROUTING', table: 'broute', protocol: 'IPv4', ensure: 'present' },
329+
error: 'BROUTE is only valid with protocol \'ethernet\''
330+
},
331+
{
332+
should: { name: 'INPUT:broute:ethernet', chain: 'INPUT', table: 'broute', protocol: 'ethernet', ensure: 'present' },
333+
error: 'BROUTING is the only inbuilt chain allowed on on table \'broute\''
334+
},
335+
{
336+
should: { name: 'PREROUTING:security:IPv4', chain: 'PREROUTING', table: 'security', protocol: 'IPv4', ensure: 'present', policy: 'accept' },
337+
error: 'INPUT, OUTPUT and FORWARD are the only inbuilt chains that can be used in table \'security\''
338+
},
339+
{
340+
should: { name: 'TEST_ONE:filter:IPv4', chain: 'TEST_ONE', table: 'filter', protocol: 'IPv4', ensure: 'present', policy: 'accept' },
341+
error: '\'policy\' can only be set on Internal Chains. Setting for \'TEST_ONE:filter:IPv4\' is invalid'
342+
},
343+
].each do |test|
344+
it "Expect error: #{test[:error]}" do
345+
expect { provider.verify({}, test[:should]) }.to raise_error(ArgumentError, test[:error])
346+
end
347+
end
348+
end
349+
end
350+
end

0 commit comments

Comments
 (0)