Skip to content

Commit 5ea6e0b

Browse files
committed
(CONT-339) Add Top Scope Facts Check
This commit introduces the top_scope_facts check. The plugin originated here: https://github.com/mmckinst/puppet-lint-top_scope_facts-check and was authored by mmckinst. Permission has been given to migrate this check to puppet-lints default plugin set in this PR: mmckinst/puppet-lint-top_scope_facts-check#11
1 parent bbcb5c2 commit 5ea6e0b

File tree

3 files changed

+218
-1
lines changed

3 files changed

+218
-1
lines changed
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
PuppetLint.new_check(:top_scope_facts) do
2+
TOP_SCOPE_FACTS_VAR_TYPES = Set[:VARIABLE, :UNENC_VARIABLE]
3+
def check
4+
whitelist = ['trusted', 'facts'] + (PuppetLint.configuration.top_scope_variables || [])
5+
whitelist = whitelist.join('|')
6+
tokens.select { |x| TOP_SCOPE_FACTS_VAR_TYPES.include?(x.type) }.each do |token|
7+
next unless token.value.match(/^::/)
8+
next if token.value.match(/^::(#{whitelist})\[?/)
9+
next if token.value =~ /^::[a-z0-9_][a-zA-Z0-9_]+::/
10+
11+
notify :warning, {
12+
:message => 'top scope fact instead of facts hash',
13+
:line => token.line,
14+
:column => token.column,
15+
:token => token,
16+
}
17+
end
18+
end
19+
20+
def fix(problem)
21+
problem[:token].value = "facts['" + problem[:token].value.sub(/^::/, '') + "']"
22+
end
23+
end

puppet-lint.gemspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,5 +32,5 @@ Gem::Specification.new do |spec|
3232
]
3333
spec.license = 'MIT'
3434

35-
spec.required_ruby_version = Gem::Requirement.new('>= 2.7'.freeze)
35+
spec.required_ruby_version = Gem::Requirement.new('>= 2.5'.freeze)
3636
end
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
require 'spec_helper'
2+
3+
describe 'top_scope_facts' do
4+
let(:msg) { 'top scope fact instead of facts hash' }
5+
context 'with fix disabled' do
6+
context 'fact variable using $facts hash' do
7+
let(:code) { "$facts['operatingsystem']" }
8+
9+
it 'should not detect any problems' do
10+
expect(problems).to have(0).problem
11+
end
12+
end
13+
context 'non-fact variable with two colons' do
14+
let(:code) { "$foo::bar" }
15+
16+
it 'should not detect any problems' do
17+
expect(problems).to have(0).problem
18+
end
19+
end
20+
21+
context 'top scope $::facts hash' do
22+
let(:code) { "$::facts['os']['family']" }
23+
24+
it 'should not detect any problems' do
25+
expect(problems).to have(0).problem
26+
end
27+
end
28+
29+
context 'top scope $::trusted hash' do
30+
let(:code) { "$::trusted['certname']" }
31+
32+
it 'should not detect any problems' do
33+
expect(problems).to have(0).problem
34+
end
35+
end
36+
37+
context 'fact variable using top scope' do
38+
let(:code) { '$::operatingsystem' }
39+
40+
it 'should only detect a single problem' do
41+
expect(problems).to have(1).problem
42+
end
43+
44+
it 'should create a warning' do
45+
expect(problems).to contain_warning(msg).on_line(1).in_column(1)
46+
end
47+
end
48+
49+
context 'fact variable using top scope with curly braces in double quote' do
50+
let(:code) { '"${::operatingsystem}"' }
51+
52+
it 'should only detect a single problem' do
53+
expect(problems).to have(1).problem
54+
end
55+
56+
it 'should create a warning' do
57+
expect(problems).to contain_warning(msg).on_line(1).in_column(4)
58+
end
59+
end
60+
61+
context 'out of scope namespaced variable with leading ::' do
62+
let(:code) { '$::profile::foo::bar' }
63+
64+
it 'should not detect any problems' do
65+
expect(problems).to have(0).problem
66+
end
67+
68+
context 'inside double quotes' do
69+
let(:code) { '"$::profile::foo::bar"' }
70+
71+
it 'should not detect any problems' do
72+
expect(problems).to have(0).problem
73+
end
74+
end
75+
76+
77+
context 'with curly braces in double quote' do
78+
let(:code) { '"${::profile::foo::bar}"' }
79+
80+
it 'should not detect any problems' do
81+
expect(problems).to have(0).problem
82+
end
83+
end
84+
end
85+
end
86+
87+
context 'with fix enabled' do
88+
before do
89+
PuppetLint.configuration.fix = true
90+
end
91+
92+
after do
93+
PuppetLint.configuration.fix = false
94+
end
95+
96+
context 'fact variable using $facts hash' do
97+
let(:code) { "$facts['operatingsystem']" }
98+
99+
it 'should not detect any problems' do
100+
expect(problems).to have(0).problem
101+
end
102+
end
103+
104+
context 'non-fact variable with two colons' do
105+
let(:code) { "$foo::bar" }
106+
107+
it 'should not detect any problems' do
108+
expect(problems).to have(0).problem
109+
end
110+
end
111+
112+
context 'top scope $::facts hash' do
113+
let(:code) { "$::facts['os']['family']" }
114+
115+
it 'should not detect any problems' do
116+
expect(problems).to have(0).problem
117+
end
118+
end
119+
120+
context 'top scope $::trusted hash' do
121+
let(:code) { "$::trusted['certname']" }
122+
123+
it 'should not detect any problems' do
124+
expect(problems).to have(0).problem
125+
end
126+
end
127+
128+
context 'fact variable using top scope' do
129+
let(:code) { '$::operatingsystem' }
130+
131+
it 'should only detect a single problem' do
132+
expect(problems).to have(1).problem
133+
end
134+
135+
it 'should fix the problem' do
136+
expect(problems).to contain_fixed(msg).on_line(1).in_column(1)
137+
end
138+
139+
it 'should should use the facts hash' do
140+
expect(manifest).to eq("$facts['operatingsystem']")
141+
end
142+
end
143+
144+
context 'fact variable using top scope with curly braces in double quote' do
145+
let(:code) { '"${::operatingsystem}"' }
146+
147+
it 'should fix the problem' do
148+
expect(problems).to contain_fixed(msg).on_line(1).in_column(4)
149+
end
150+
151+
it 'should should use the facts hash' do
152+
expect(manifest).to eq('"${facts[\'operatingsystem\']}"')
153+
end
154+
end
155+
156+
context 'with custom top scope fact variables' do
157+
before do
158+
PuppetLint.configuration.top_scope_variables = ['location', 'role']
159+
end
160+
161+
context 'fact variable using $facts hash' do
162+
let(:code) { "$facts['operatingsystem']" }
163+
164+
it 'should not detect any problems' do
165+
expect(problems).to have(0).problem
166+
end
167+
end
168+
169+
context 'fact variable using $trusted hash' do
170+
let(:code) { "$trusted['certname']" }
171+
172+
it 'should not detect any problems' do
173+
expect(problems).to have(0).problem
174+
end
175+
end
176+
177+
context 'whitelisted top scope variable $::location' do
178+
let(:code) { "$::location" }
179+
180+
it 'should not detect any problems' do
181+
expect(problems).to have(0).problem
182+
end
183+
end
184+
185+
context 'non-whitelisted top scope variable $::application' do
186+
let(:code) { "$::application" }
187+
188+
it 'should not detect any problems' do
189+
expect(problems).to have(1).problem
190+
end
191+
end
192+
end
193+
end
194+
end

0 commit comments

Comments
 (0)