Skip to content

Commit d56be7f

Browse files
committed
Initial commit.
0 parents  commit d56be7f

File tree

11 files changed

+414
-0
lines changed

11 files changed

+414
-0
lines changed

.gitignore

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/.bundle/
2+
/.yardoc
3+
/_yardoc/
4+
/coverage/
5+
/doc/
6+
/pkg/
7+
/spec/reports/
8+
/tmp/
9+
10+
# rspec failure tracking
11+
.rspec_status
12+
13+
/vendor/
14+
/Gemfile.lock
15+
16+
.*.sw?

.rspec

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
--format documentation
2+
--color
3+
--require spec_helper

Gemfile

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
source "https://rubygems.org"
2+
3+
# Specify your gem's dependencies in scelint.gemspec
4+
gemspec
5+
6+
gem "rake", "~> 12.0"
7+
gem "rspec", "~> 3.0"

README.md

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Scelint
2+
3+
Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/scelint`. To experiment with that code, run `bin/console` for an interactive prompt.
4+
5+
TODO: Delete this and the text above, and describe your gem
6+
7+
## Installation
8+
9+
Add this line to your application's Gemfile:
10+
11+
```ruby
12+
gem 'scelint'
13+
```
14+
15+
And then execute:
16+
17+
$ bundle install
18+
19+
Or install it yourself as:
20+
21+
$ gem install scelint
22+
23+
## Usage
24+
25+
TODO: Write usage instructions here
26+
27+
## Development
28+
29+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30+
31+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32+
33+
## Contributing
34+
35+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/scelint.
36+

Rakefile

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
require "bundler/gem_tasks"
2+
require "rspec/core/rake_task"
3+
4+
RSpec::Core::RakeTask.new(:spec)
5+
6+
task :default => :spec

exe/scelint

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#!/usr/bin/env ruby
2+
# frozen_string_literal: true
3+
4+
require 'scelint'
5+
6+
to_check = ARGV.empty? ? ['.'] : ARGV
7+
lint = Scelint::Lint.new(to_check)
8+
9+
count = lint.files.count
10+
11+
if count.zero?
12+
warn 'No SCE data found.'
13+
else
14+
lint.errors.each do |error|
15+
warn error
16+
end
17+
18+
lint.warnings.each do |warning|
19+
warn warning
20+
end
21+
22+
message = "Checked #{count} files."
23+
if lint.errors.count == 0
24+
message += " No errors."
25+
exit_code = 0
26+
else
27+
message += " #{lint.errors.count} errors."
28+
exit_code = 1
29+
end
30+
31+
if lint.warnings.count > 0
32+
message += " #{lint.warnings.count} warnings."
33+
end
34+
35+
puts message
36+
exit exit_code
37+
end

lib/scelint.rb

+253
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
# frozen_string_literal: true
2+
3+
require 'yaml'
4+
require 'json'
5+
require 'deep_merge'
6+
7+
require 'scelint/version'
8+
9+
module Scelint
10+
class Error < StandardError; end
11+
# Your code goes here...
12+
13+
class Lint
14+
def initialize(paths = ['.'])
15+
@data = {}
16+
@errors = []
17+
@warnings = []
18+
19+
merged_data = {}
20+
21+
paths.each do |path|
22+
if File.directory?(path)
23+
[
24+
'SIMP/compliance_profiles',
25+
'simp/compliance_profiles',
26+
].each do |dir|
27+
['yaml', 'json'].each do |type|
28+
Dir.glob("#{path}/#{dir}/**/*.#{type}").each do |file|
29+
@data[file] = parse(file)
30+
merged_data = merged_data.deep_merge!(@data[file])
31+
end
32+
end
33+
end
34+
elsif File.exist?(path)
35+
@data[path] = parse(path)
36+
else
37+
raise "Can't find path '#{path}'"
38+
end
39+
end
40+
41+
return nil if @data.empty?
42+
43+
@data['merged data'] = merged_data
44+
45+
@data.each do |file, data|
46+
lint(file, data)
47+
end
48+
49+
@data
50+
end
51+
52+
def parse(file)
53+
return @data[file] if @data[file]
54+
55+
type = case file
56+
when %r{\.yaml$}
57+
'yaml'
58+
when %r{\.json$}
59+
'json'
60+
else
61+
nil
62+
end
63+
return YAML.safe_load(File.read(file)) if type == 'yaml'
64+
return JSON.parse(File.read(file)) if type == 'json'
65+
66+
raise "Failed to determine file type of '#{file}'"
67+
end
68+
69+
def files
70+
@data.keys - ['merged data']
71+
end
72+
73+
def warnings
74+
@warnings
75+
end
76+
77+
def errors
78+
@errors
79+
end
80+
81+
def check_version(file, data)
82+
@errors << "Version check failed in #{file}." unless data['version'] == '2.0.0'
83+
end
84+
85+
def check_keys(file, data)
86+
ok = ['version', 'profiles', 'ce', 'checks']
87+
88+
data.keys.each do |key|
89+
@warnings << "Unexpected key '#{key}' found in #{file}." unless ok.include?(key)
90+
end
91+
end
92+
93+
def check_title(file, data)
94+
@warnings << "Bad title #{data} in #{file}." unless data.is_a?(String)
95+
end
96+
97+
def check_description(file, data)
98+
@warnings << "Bad description #{data} in #{file}." unless data.is_a?(String)
99+
end
100+
101+
def check_controls(file, data)
102+
@warnings << "Bad controls #{data} in #{file}." unless data.is_a?(Hash)
103+
104+
data.each do |key, value|
105+
@warnings << "Bad control #{key} in #{file}." unless key.is_a?(String) && value # Should be truthy
106+
end
107+
end
108+
109+
def check_profile_ces(file, data)
110+
@warnings << "Bad ces #{data} in #{file}." unless data.is_a?(Hash)
111+
112+
data.each do |key, value|
113+
@warnings << "Bad ce #{key} in #{file}." unless key.is_a?(String) && value.is_a?(TrueClass)
114+
end
115+
end
116+
117+
def check_confine(file, data)
118+
@warnings << "Bad confine #{data} in #{file}." unless data.is_a?(Hash)
119+
end
120+
121+
def check_identifiers(file, data)
122+
@warnings << "Bad identifiers #{data} in #{file}." unless data.is_a?(Hash)
123+
124+
data.each do |key, value|
125+
@warnings << "Bad identifier #{key} in #{file}." unless key.is_a?(String) && value.is_a?(Array)
126+
value.each do |identifier|
127+
@warnings << "Bad identifier #{identifier} in #{file}." unless identifier.is_a?(String)
128+
end
129+
end
130+
end
131+
132+
def check_oval_ids(file, data)
133+
@warnings << "Bad oval-ids #{data} in #{file}." unless data.is_a?(Array)
134+
135+
data.each do |key|
136+
@warnings << "Bad oval-id #{key} in #{file}." unless key.is_a?(String)
137+
end
138+
end
139+
140+
def check_imported_data(file, data)
141+
ok = ['checktext', 'fixtext']
142+
143+
data.each do |key, value|
144+
@warnings << "Unexpected key '#{key}' found in #{file}" unless ok.include?(key)
145+
146+
@warnings << "Bad #{key} data in #{file}: '#{value}'" unless value.is_a?(String)
147+
end
148+
end
149+
150+
def check_profiles(file, data)
151+
ok = [
152+
'title',
153+
'description',
154+
'controls',
155+
'ces',
156+
'confine',
157+
]
158+
159+
data.each do |profile, value|
160+
value.keys.each do |key|
161+
@warnings << "Unexpected key '#{key}' found in #{file} (profile '#{profile}')." unless ok.include?(key)
162+
end
163+
164+
check_title(file, value['title']) unless value['title'].nil?
165+
check_description(file, value['description']) unless value['description'].nil?
166+
check_controls(file, value['controls']) unless value['controls'].nil?
167+
check_profile_ces(file, value['ces']) unless value['ces'].nil?
168+
check_confine(file, value['confine']) unless value['confine'].nil?
169+
end
170+
end
171+
172+
def check_ce(file, data)
173+
ok = [
174+
'title',
175+
'description',
176+
'controls',
177+
'identifiers',
178+
'oval-ids',
179+
'confine',
180+
'imported_data',
181+
]
182+
183+
data.each do |ce, value|
184+
value.keys.each do |key|
185+
@warnings << "Unexpected key '#{key}' found in #{file} (CE '#{ce}')." unless ok.include?(key)
186+
end
187+
188+
check_title(file, value['title']) unless value['title'].nil?
189+
check_description(file, value['description']) unless value['description'].nil?
190+
check_controls(file, value['controls']) unless value['controls'].nil?
191+
check_identifiers(file, value['identifiers']) unless value['identifiers'].nil?
192+
check_oval_ids(file, value['oval-ids']) unless value['oval-ids'].nil?
193+
check_confine(file, value['confine']) unless value['confine'].nil?
194+
check_imported_data(file, value['imported_data']) unless value['imported_data'].nil?
195+
end
196+
end
197+
198+
def check_type(file, check, data)
199+
@warnings << "Unknown type '#{data}' found in #{file} (check '#{check}')." unless data == 'puppet-class-parameter'
200+
end
201+
202+
def check_settings(file, check, data)
203+
ok = ['parameter', 'value']
204+
205+
data.keys.each do |key|
206+
@warnings << "Unexpected key '#{key}' found in #{file} (check '#{check}')." unless ok.include?(key)
207+
end
208+
end
209+
210+
def check_check_ces(file, data)
211+
@warnings << "Bad ces #{data} in #{file}." unless data.is_a?(Array)
212+
213+
data.each do |key|
214+
@warnings << "Bad ce #{key} in #{file}." unless key.is_a?(String)
215+
end
216+
end
217+
218+
def check_checks(file, data)
219+
ok = [
220+
'type',
221+
'settings',
222+
'controls',
223+
'identifiers',
224+
'oval-ids',
225+
'ces',
226+
'confine',
227+
]
228+
229+
data.each do |check, value|
230+
value.keys.each do |key|
231+
@warnings << "Unexpected key '#{key}' found in #{file} (check '#{check}')." unless ok.include?(key)
232+
end
233+
234+
check_type(file, check, value['type']) if value['type']
235+
check_settings(file, check, value['settings']) if value['settings']
236+
check_controls(file, value['controls']) unless value['controls'].nil?
237+
check_identifiers(file, value['identifiers']) unless value['identifiers'].nil?
238+
check_oval_ids(file, value['oval-ids']) unless value['oval-ids'].nil?
239+
check_check_ces(file, value['ces']) unless value['ces'].nil?
240+
check_confine(file, value['confine']) unless value['confine'].nil?
241+
end
242+
end
243+
244+
def lint(file, data)
245+
check_version(file, data)
246+
check_keys(file, data)
247+
248+
check_profiles(file, data['profiles']) if data['profiles']
249+
check_ce(file, data['ce']) if data['ce']
250+
check_checks(file, data['checks']) if data['checks']
251+
end
252+
end
253+
end

lib/scelint/version.rb

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module Scelint
2+
VERSION = "0.1.0"
3+
end

scelint.gemspec

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
require_relative 'lib/scelint/version'
2+
3+
Gem::Specification.new do |spec|
4+
spec.name = "scelint"
5+
spec.version = Scelint::VERSION
6+
spec.authors = ["Steven Pritchard"]
7+
spec.email = ["[email protected]"]
8+
spec.license = 'Apache-2.0'
9+
10+
spec.summary = %q{Linter SIMP Compliance Engine data}
11+
spec.homepage = "https://github.com/silug/rubygem-simp-scelint"
12+
spec.required_ruby_version = Gem::Requirement.new(">= 2.3.0")
13+
14+
spec.metadata["homepage_uri"] = spec.homepage
15+
spec.metadata["source_code_uri"] = spec.homepage
16+
# spec.metadata["changelog_uri"] = "TODO: Put your gem's CHANGELOG.md URL here."
17+
18+
# Specify which files should be added to the gem when it is released.
19+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
20+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
21+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
22+
end
23+
spec.bindir = "exe"
24+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
25+
spec.require_paths = ["lib"]
26+
27+
spec.add_runtime_dependency 'deep_merge'
28+
end

0 commit comments

Comments
 (0)