opencontrol-linter 0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +20 -0
- data/README.md +94 -0
- data/exe/opencontrol-linter +8 -0
- data/lib/opencontrol.rb +3 -0
- data/lib/opencontrol/cli.rb +231 -0
- data/lib/opencontrol/messages.rb +45 -0
- data/lib/opencontrol/version.rb +22 -0
- data/vendor/README.md +9 -0
- data/vendor/schemas/CONTRIBUTING.md +37 -0
- data/vendor/schemas/README.md +175 -0
- data/vendor/schemas/examples/component_v3.0.0.yaml +70 -0
- data/vendor/schemas/examples/component_v3.1.0.yaml +81 -0
- data/vendor/schemas/examples/opencontrol_v1.0.0.yaml +22 -0
- data/vendor/schemas/kwalify/README.md +31 -0
- data/vendor/schemas/kwalify/certification/v1.0.0.yaml +12 -0
- data/vendor/schemas/kwalify/component/test_data_validity.py +25 -0
- data/vendor/schemas/kwalify/component/v1.0.0.yaml +100 -0
- data/vendor/schemas/kwalify/component/v2.0.0.yaml +100 -0
- data/vendor/schemas/kwalify/component/v3.0.0.yaml +112 -0
- data/vendor/schemas/kwalify/component/v3.1.0.yaml +138 -0
- data/vendor/schemas/kwalify/opencontrol/v1.0.0.yaml +67 -0
- data/vendor/schemas/kwalify/requirements.txt +3 -0
- data/vendor/schemas/kwalify/standard/v1.0.0.yaml +14 -0
- data/vendor/schemas/transformation-scripts/utils.py +12 -0
- data/vendor/schemas/transformation-scripts/v1_example.yaml +40 -0
- data/vendor/schemas/transformation-scripts/v1_from_v2_example.yaml +41 -0
- data/vendor/schemas/transformation-scripts/v1_to_v2.py +75 -0
- data/vendor/schemas/transformation-scripts/v2_example.yaml +45 -0
- data/vendor/schemas/transformation-scripts/v2_from_v1_example.yaml +45 -0
- data/vendor/schemas/transformation-scripts/v2_to_v1.py +74 -0
- metadata +320 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f5809df9b521e096796e994cacf885be8dd2d41b
|
4
|
+
data.tar.gz: 4b1b9250c44fbc75d3a2b941003de47a5f0def13
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 27353289411c6cf7bd42794274c6a134a89c51b3cf7555c6bafc047ec2bbfce4b743760c4719a58451f2e9d3b9c8495437e609c6687c41bef4448b91928f57ba
|
7
|
+
data.tar.gz: 722a2e65f5f4c6aaa2a8d7806f34669513e195cde7fd654927d3dd514427c0d88286de961abbbd73ac7813f29ea380136ca19796687601ca701fd3ada2fb1d4d
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2019 Center for Medicare Services
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
[![CircleCI](https://circleci.com/gh/huge-robot/opencontrol-linter.svg?style=svg&circle-token=7873c3440387ef3e3b04964f5c51a15f7e3f26de)](https://circleci.com/gh/huge-robot/opencontrol-linter)
|
2
|
+
|
3
|
+
|
4
|
+
**Open Control Linter** is a linter for the OpenControl standard of security controls.
|
5
|
+
Use it to check the correctness of opencontrols components, standards and certifications quickly.
|
6
|
+
|
7
|
+
To find out more about opencontrol see:
|
8
|
+
http://opencontrol.cfapps.io/
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
```sh
|
13
|
+
$ gem install opencontrol-linter
|
14
|
+
```
|
15
|
+
|
16
|
+
If you'd rather install Open Control Linter using `bundler`, don't require it in your `Gemfile`:
|
17
|
+
|
18
|
+
```rb
|
19
|
+
gem 'opencontrol-linter', require: false
|
20
|
+
```
|
21
|
+
|
22
|
+
## Quickstart
|
23
|
+
|
24
|
+
Just type `opencontrol-linter` in a control project root directory.
|
25
|
+
|
26
|
+
```
|
27
|
+
$ cd awesome/opencontrols/
|
28
|
+
$ opencontrol-linter
|
29
|
+
```
|
30
|
+
|
31
|
+
## Documentation
|
32
|
+
|
33
|
+
Detailed command line arguments
|
34
|
+
|
35
|
+
```
|
36
|
+
usage: opencontrol-linter
|
37
|
+
|
38
|
+
optional arguments:
|
39
|
+
-h, --help show this help message and exit
|
40
|
+
-c, --components
|
41
|
+
Specify component files should be checked. Defaults to
|
42
|
+
true. Searches ./**/component.yaml or the search you
|
43
|
+
optionally specify.
|
44
|
+
-n, --certifications
|
45
|
+
Specify certification (eg FISMA high)files should be
|
46
|
+
checked. Defaults to true. Searches
|
47
|
+
./certifications/*.yaml or the search you optionally
|
48
|
+
specify.
|
49
|
+
-s, --standards
|
50
|
+
Specify standard files (eg NIST 800.53) should be
|
51
|
+
checked. Defaults to true. Searches ./standards/*.yaml
|
52
|
+
or the search you optionally specify.
|
53
|
+
-a, --all Run all types of validations (this is the default).
|
54
|
+
-v, --version Show the version of this utility.
|
55
|
+
|
56
|
+
|
57
|
+
```
|
58
|
+
|
59
|
+
Usage examples
|
60
|
+
|
61
|
+
```
|
62
|
+
# lint all components, standards and certifications in the current directory
|
63
|
+
opencontrol-linter
|
64
|
+
|
65
|
+
# lint all components subdir components
|
66
|
+
opencontrol-linter --components './components/**/component.yaml'
|
67
|
+
|
68
|
+
# lint all standards files found
|
69
|
+
opencontrol-linter --standards
|
70
|
+
|
71
|
+
# lint one component
|
72
|
+
opencontrol-linter --components './components/AU_policy/component.yaml'
|
73
|
+
|
74
|
+
```
|
75
|
+
|
76
|
+
## Compatibility
|
77
|
+
|
78
|
+
Open Control Linter supports the following Open Control schemas:
|
79
|
+
|
80
|
+
- Component: (all v1.0 through v3.1)
|
81
|
+
- Standard: (all v1.0 through v1.0)
|
82
|
+
- Certification: (all v1.0 through v1.0)
|
83
|
+
|
84
|
+
## Related
|
85
|
+
http://opencontrol.cfapps.io/
|
86
|
+
https://github.com/opencontrol
|
87
|
+
|
88
|
+
## Team
|
89
|
+
|
90
|
+
Here's a list of Open Control Linter's core developers:
|
91
|
+
|
92
|
+
* [Adrian Kierman](https://github.com/adriankierman)
|
93
|
+
* James Connor
|
94
|
+
|
data/lib/opencontrol.rb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
require 'kwalify'
|
2
|
+
require 'yaml'
|
3
|
+
require 'opencontrol'
|
4
|
+
require 'rationalist'
|
5
|
+
require 'colorize'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
# frozen_string_literal: true
|
9
|
+
|
10
|
+
module Opencontrol
|
11
|
+
# This module holds the Opencontrol Linter Command Line Interface.
|
12
|
+
module CLI
|
13
|
+
USAGE_TEXT = <<USAGE_TEXT.freeze
|
14
|
+
usage: opencontrol-linter
|
15
|
+
|
16
|
+
optional arguments:
|
17
|
+
-h, --help show this help message and exit
|
18
|
+
-c, --components
|
19
|
+
Specify component files should be checked. Defaults to
|
20
|
+
true. Searches ./**/component.yaml or the search you
|
21
|
+
optionally specify.
|
22
|
+
-n, --certifications
|
23
|
+
Specify certification (eg FISMA high)files should be
|
24
|
+
checked. Defaults to true. Searches
|
25
|
+
./certifications/*.yaml or the search you optionally
|
26
|
+
specify.
|
27
|
+
-s, --standards
|
28
|
+
Specify standard files (eg NIST 800.53) should be
|
29
|
+
checked. Defaults to true. Searches ./standards/*.yaml
|
30
|
+
or the search you optionally specify.
|
31
|
+
-a, --all Run all types of validations (this is the default).
|
32
|
+
-v, --version Show the version of this utility.
|
33
|
+
|
34
|
+
Usage examples:
|
35
|
+
|
36
|
+
# lint all components, standards and certifications in the current directory
|
37
|
+
opencontrol-linter
|
38
|
+
|
39
|
+
# lint all components subdir components
|
40
|
+
opencontrol-linter --components './components/**/component.yaml'
|
41
|
+
|
42
|
+
# lint all standards files found
|
43
|
+
opencontrol-linter --standards
|
44
|
+
|
45
|
+
# lint one component
|
46
|
+
opencontrol-linter --components './components/AU_policy/component.yaml'
|
47
|
+
USAGE_TEXT
|
48
|
+
|
49
|
+
DEFAULT_SPECIFICATION = {
|
50
|
+
action: :run,
|
51
|
+
targets: [
|
52
|
+
{
|
53
|
+
type: :components,
|
54
|
+
pattern: '**/component.yaml'
|
55
|
+
},
|
56
|
+
{
|
57
|
+
type: :standards,
|
58
|
+
pattern: './standards/*.yaml'
|
59
|
+
},
|
60
|
+
{
|
61
|
+
type: :certifications,
|
62
|
+
pattern: './certifications/*.yaml'
|
63
|
+
}
|
64
|
+
]
|
65
|
+
}.freeze
|
66
|
+
|
67
|
+
def self.show_help
|
68
|
+
puts USAGE_TEXT
|
69
|
+
0 # exit with no error
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.show_version
|
73
|
+
puts 'Opencontrol linter version: v' + Opencontrol::Version.version
|
74
|
+
puts 'CMS 2019 Adrian Kierman '
|
75
|
+
0 # exit with no error
|
76
|
+
end
|
77
|
+
|
78
|
+
# @param [String] version
|
79
|
+
def self.find_schema(type, version)
|
80
|
+
dir = __dir__
|
81
|
+
case type
|
82
|
+
when :components
|
83
|
+
"#{dir}/../../vendor/schemas/kwalify/component/v#{version}.yaml"
|
84
|
+
when :standards
|
85
|
+
"#{dir}/../../vendor/schemas/kwalify/standard/v#{version}.yaml"
|
86
|
+
when :certifications
|
87
|
+
"#{dir}/../../vendor/schemas/kwalify/certification/v#{version}.yaml"
|
88
|
+
else
|
89
|
+
throw "Unknown type of schema specified #{type} " \
|
90
|
+
"tried to get schema version #{version}"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def self.load_schema(schema_file)
|
95
|
+
## load schema data
|
96
|
+
# Kwalify::Yaml.load_file(schema_file)
|
97
|
+
## or
|
98
|
+
YAML.load_file(schema_file)
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.show_issues(issues, filename)
|
102
|
+
if issues && !issues.empty?
|
103
|
+
puts "✗ #{filename}".red
|
104
|
+
issues.each do |issue|
|
105
|
+
puts Opencontrol::Messages.detail(issue).yellow
|
106
|
+
end
|
107
|
+
else
|
108
|
+
puts "✓ #{filename}".green
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.schema_for_document(type, document)
|
113
|
+
version = document['schema_version'] || '1.0.0'
|
114
|
+
schema_file = find_schema(type, version)
|
115
|
+
load_schema(schema_file)
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.targets_for_type(type, specification)
|
119
|
+
specification[:targets].select { |t| t[:type] == type }
|
120
|
+
end
|
121
|
+
|
122
|
+
def self.default_pattern_for_type(type)
|
123
|
+
targets_for_type(type, DEFAULT_SPECIFICATION).first[:pattern]
|
124
|
+
end
|
125
|
+
|
126
|
+
def self.add_target(type, opts, specification)
|
127
|
+
# pick a reasonable default
|
128
|
+
use_defaults = false
|
129
|
+
use_defaults = default_pattern_for_type(type) if opts[type] == true
|
130
|
+
specification[:targets].push(
|
131
|
+
type: type,
|
132
|
+
pattern: use_defaults || opts[type]
|
133
|
+
)
|
134
|
+
end
|
135
|
+
|
136
|
+
def self.validate(type, filename)
|
137
|
+
## load document
|
138
|
+
# document = Kwalify::Yaml.load_file(filename)
|
139
|
+
## or
|
140
|
+
document = YAML.load_file(filename)
|
141
|
+
schema = schema_for_document(type, document)
|
142
|
+
|
143
|
+
validator = Kwalify::Validator.new(schema)
|
144
|
+
validator.validate(document)
|
145
|
+
end
|
146
|
+
|
147
|
+
def self.files_not_found_issue
|
148
|
+
Kwalify::BaseError.new(
|
149
|
+
'No validation files found for the pattern supplied. \
|
150
|
+
Adding an issue to avoid failing silently.',
|
151
|
+
nil,
|
152
|
+
nil,
|
153
|
+
nil,
|
154
|
+
:linter_files_not_found_issue
|
155
|
+
)
|
156
|
+
end
|
157
|
+
|
158
|
+
def self.validate_target(target)
|
159
|
+
filenames = Dir[target[:pattern]]
|
160
|
+
if filenames.empty?
|
161
|
+
issues = [files_not_found_issue]
|
162
|
+
show_issues(issues, target[:pattern])
|
163
|
+
return issues
|
164
|
+
end
|
165
|
+
filenames.collect do |filename|
|
166
|
+
issues = validate(target[:type], filename)
|
167
|
+
show_issues(issues, filename)
|
168
|
+
issues
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def self.validate_all(specification)
|
173
|
+
specification[:targets].collect do |target|
|
174
|
+
validate_target(target)
|
175
|
+
end.flatten
|
176
|
+
end
|
177
|
+
|
178
|
+
def self.should_lint?(opts)
|
179
|
+
!(opts[:version] || opts[:help])
|
180
|
+
end
|
181
|
+
|
182
|
+
def self.all_targets_selected?(opts, specification)
|
183
|
+
opts[:all] || specification[:targets].empty?
|
184
|
+
end
|
185
|
+
|
186
|
+
def self.use_default?(opts, specification)
|
187
|
+
all_targets_selected?(opts, specification) && should_lint?(opts)
|
188
|
+
end
|
189
|
+
|
190
|
+
ALIASES = {
|
191
|
+
components: %w[component c],
|
192
|
+
standards: %w[standard s],
|
193
|
+
certifications: %w[certification n],
|
194
|
+
all: 'a',
|
195
|
+
help: 'h',
|
196
|
+
version: 'v'
|
197
|
+
}.freeze
|
198
|
+
|
199
|
+
def self.parse_args(arguments)
|
200
|
+
opts = Rationalist.parse(arguments, alias: ALIASES)
|
201
|
+
specification = {
|
202
|
+
action: :run,
|
203
|
+
targets: []
|
204
|
+
}
|
205
|
+
specification[:action] = :version if opts[:version]
|
206
|
+
specification[:action] = :help if opts[:help]
|
207
|
+
add_target(:components, opts, specification) if opts[:components]
|
208
|
+
add_target(:standards, opts, specification) if opts[:standards]
|
209
|
+
add_target(:certifications, opts, specification) if opts[:certifications]
|
210
|
+
specification = DEFAULT_SPECIFICATION if use_default?(opts, specification)
|
211
|
+
specification
|
212
|
+
end
|
213
|
+
|
214
|
+
def self.run(specification)
|
215
|
+
issues = validate_all(specification)
|
216
|
+
if !issues.empty?
|
217
|
+
puts "Complete. #{issues.length} issues found.".red
|
218
|
+
else
|
219
|
+
puts 'Complete. No problems found.'.green
|
220
|
+
end
|
221
|
+
issues.length
|
222
|
+
end
|
223
|
+
|
224
|
+
def self.run_with_args(args)
|
225
|
+
specification = parse_args(args)
|
226
|
+
exit(run(specification)) if specification[:action] == :run
|
227
|
+
show_version if specification[:action] == :version
|
228
|
+
show_help if specification[:action] == :help
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'kwalify'
|
4
|
+
|
5
|
+
module Opencontrol
|
6
|
+
# This module holds the Opencontrol Linter detailed issue messages.
|
7
|
+
module Messages
|
8
|
+
def self.detail(issue)
|
9
|
+
case issue.error_symbol
|
10
|
+
when :enum_notexist
|
11
|
+
<<-MESSAGE
|
12
|
+
At: YAML path #{issue.path}.
|
13
|
+
Message: #{issue.message}
|
14
|
+
Expected: one of #{issue.rule.enum}.
|
15
|
+
Actual: The value '#{issue.value}' was found.
|
16
|
+
To fix this: Use one of #{issue.rule.enum}
|
17
|
+
instead of the value '#{issue.value}'
|
18
|
+
MESSAGE
|
19
|
+
when :key_undefined
|
20
|
+
<<-MESSAGE
|
21
|
+
At: YAML path #{issue.path}.
|
22
|
+
Expected: A key allowed by the schema.
|
23
|
+
Actual: A key was found that is not defined in the schema (#{issue.path}).
|
24
|
+
To fix this: Its possible the key found is a typo,
|
25
|
+
Remove #{issue.path} or correct the key.
|
26
|
+
MESSAGE
|
27
|
+
else
|
28
|
+
<<-MESSAGE
|
29
|
+
At: YAML path #{issue.path}.
|
30
|
+
Message: #{issue.message}
|
31
|
+
MESSAGE
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.verbose(issue)
|
36
|
+
<<-MESSAGE
|
37
|
+
At: YAML path #{issue.path}.
|
38
|
+
Message: #{issue.message}
|
39
|
+
Rule: #{issue.rule.to_yaml}
|
40
|
+
Value: #{issue.value}
|
41
|
+
Symbol: #{issue.error_symbol}
|
42
|
+
MESSAGE
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Opencontrol
|
4
|
+
# This module holds the Opencontrol Linter version information.
|
5
|
+
module Version
|
6
|
+
STRING = '0.1'.freeze
|
7
|
+
|
8
|
+
MSG = '%<version>s (using Parser %<parser_version>s, running on ' \
|
9
|
+
'%<ruby_engine>s %<ruby_version>s %<ruby_platform>s)'.freeze
|
10
|
+
|
11
|
+
def self.version(debug = false)
|
12
|
+
if debug
|
13
|
+
require 'kwalify'
|
14
|
+
format(MSG, version: STRING, parser_version: Kwalify::VERSION,
|
15
|
+
ruby_engine: RUBY_ENGINE, ruby_version: RUBY_VERSION,
|
16
|
+
ruby_platform: RUBY_PLATFORM)
|
17
|
+
else
|
18
|
+
STRING
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|