opencontrol-linter 0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|
+
[](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
|