octool 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.rdoc +3 -0
- data/bin/octool +93 -0
- data/lib/octool.rb +27 -0
- data/lib/octool/constants.rb +6 -0
- data/lib/octool/generated/certification.rb +35 -0
- data/lib/octool/generated/component.rb +57 -0
- data/lib/octool/generated/config.rb +55 -0
- data/lib/octool/generated/standard.rb +55 -0
- data/lib/octool/parser.rb +103 -0
- data/lib/octool/ssp.rb +47 -0
- data/lib/octool/system.rb +77 -0
- data/lib/octool/version.rb +3 -0
- data/octool.rdoc +52 -0
- data/schemas/v1.0.0/certification.yaml +27 -0
- data/schemas/v1.0.0/component.yaml +60 -0
- data/schemas/v1.0.0/config.yaml +64 -0
- data/schemas/v1.0.0/standard.yaml +50 -0
- data/templates/ssp.erb +120 -0
- metadata +179 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 776fce8b2089c05dcaf562c769ab2c65a81a3887977390a75e3fadda41c2ffe8
|
4
|
+
data.tar.gz: 107d9de9a54bac2b28bac82f26f10be04a28786bce24673b8ddd3cc6fe5afadd
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1c864f87036e072690a9fe2645aa95eb0a50b3e51011bb23e3fc3c5e3cf4efd27b8b999098e2a1b2792af90aeaf35f88d79aaea3e2506cb970f89e167b196e23
|
7
|
+
data.tar.gz: 5e99234200a87b85a7b4de20da9196f3c72814f520bdc0329e8fc47b670b2064e2e5a2b950a11f76954c9becf29ef4d737eb01dde1b29eee49dada9fb329d674
|
data/README.rdoc
ADDED
data/bin/octool
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'gli'
|
3
|
+
require 'octool'
|
4
|
+
|
5
|
+
# Entrypoint and argument parser for the application.
|
6
|
+
class App
|
7
|
+
extend GLI::App
|
8
|
+
|
9
|
+
program_desc 'Open Compliance Tool'
|
10
|
+
version OCTool::VERSION
|
11
|
+
|
12
|
+
subcommand_option_handling :normal
|
13
|
+
arguments :strict
|
14
|
+
|
15
|
+
desc 'Check sanity of configuration'
|
16
|
+
command :validate do |v|
|
17
|
+
v.desc 'validate data'
|
18
|
+
v.arg_name 'path/to/system/config.yaml'
|
19
|
+
v.command :data do |vd|
|
20
|
+
vd.action do |global_options, options, args|
|
21
|
+
config_file = find_config(args)
|
22
|
+
OCTool::Parser.new(config_file).validate_data
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
v.desc 'validate schemas'
|
27
|
+
v.command :schemas do |vs|
|
28
|
+
vs.action do |global_options, options, args|
|
29
|
+
OCTool::Parser.validate_schemas
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
v.default_command :data
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'generate System Security Plan'
|
37
|
+
arg_name 'path/to/system/config.yaml'
|
38
|
+
command :ssp do |s|
|
39
|
+
s.desc 'where to store outputs'
|
40
|
+
s.default_value Dir.tmpdir
|
41
|
+
s.long_desc 'Default output directory respects env vars TMPDIR, TMP, TEMP'
|
42
|
+
s.arg_name 'path/to/output/dir'
|
43
|
+
s.flag [:d, :dir]
|
44
|
+
|
45
|
+
s.action do |global_options, options, args|
|
46
|
+
export_dir = options[:dir]
|
47
|
+
FileUtils.mkdir_p export_dir unless File.directory?(export_dir)
|
48
|
+
config_file = find_config(args)
|
49
|
+
system = OCTool::Parser.new(config_file).load_system
|
50
|
+
Dir.chdir File.dirname(config_file) do
|
51
|
+
OCTool::SSP.new(system, export_dir)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
pre do |global, command, options, args|
|
57
|
+
# Pre logic here
|
58
|
+
#
|
59
|
+
# Return true to proceed;
|
60
|
+
# false to abort and not call the chosen command
|
61
|
+
#
|
62
|
+
# Use skips_pre before a command
|
63
|
+
# to skip this block on that command only.
|
64
|
+
true
|
65
|
+
end
|
66
|
+
|
67
|
+
post do |global, command, options, args|
|
68
|
+
# Post logic here
|
69
|
+
# Use skips_post before a command
|
70
|
+
# to skip this block on that command only.
|
71
|
+
puts 'OK'
|
72
|
+
end
|
73
|
+
|
74
|
+
on_error do |exception|
|
75
|
+
# Error logic here
|
76
|
+
# Return false to skip default error handling.
|
77
|
+
if ENV['DEBUG']
|
78
|
+
puts exception.backtrace
|
79
|
+
pp exception
|
80
|
+
false
|
81
|
+
else
|
82
|
+
true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def find_config(args)
|
88
|
+
path = args.first || OCTool::DEFAULT_CONFIG_FILENAME
|
89
|
+
path = File.join(path, OCTool::DEFAULT_CONFIG_FILENAME) if File.directory?(path)
|
90
|
+
path
|
91
|
+
end
|
92
|
+
|
93
|
+
exit App.run(ARGV)
|
data/lib/octool.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'octool/version.rb'
|
2
|
+
|
3
|
+
# Built-ins.
|
4
|
+
require 'pp'
|
5
|
+
require 'tmpdir'
|
6
|
+
|
7
|
+
# 3rd-party libs.
|
8
|
+
require 'kwalify'
|
9
|
+
require 'kwalify/util/hashlike'
|
10
|
+
require 'paru/pandoc'
|
11
|
+
|
12
|
+
# OCTool libs.
|
13
|
+
require 'octool/constants'
|
14
|
+
require 'octool/parser'
|
15
|
+
require 'octool/ssp'
|
16
|
+
require 'octool/system'
|
17
|
+
|
18
|
+
# Generated libs.
|
19
|
+
require 'octool/generated/certification'
|
20
|
+
require 'octool/generated/component'
|
21
|
+
require 'octool/generated/config'
|
22
|
+
require 'octool/generated/standard'
|
23
|
+
|
24
|
+
# Mixins.
|
25
|
+
module OCTool
|
26
|
+
include Kwalify::Util::HashLike # defines [], []=, and keys?
|
27
|
+
end
|
@@ -0,0 +1,6 @@
|
|
1
|
+
module OCTool
|
2
|
+
LATEST_SCHEMA_VERSION = 'v1.0.0'.freeze
|
3
|
+
BASE_SCHEMA_DIR = File.join(File.dirname(__FILE__), '..', '..', 'schemas').freeze
|
4
|
+
ERB_DIR = File.join(File.dirname(__FILE__), '..', '..', 'templates').freeze
|
5
|
+
DEFAULT_CONFIG_FILENAME = 'config.yaml'.freeze
|
6
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'kwalify/util/hashlike'
|
2
|
+
|
3
|
+
module OCTool
|
4
|
+
|
5
|
+
|
6
|
+
class Certification
|
7
|
+
include Kwalify::Util::HashLike
|
8
|
+
def initialize(hash=nil)
|
9
|
+
if hash.nil?
|
10
|
+
return
|
11
|
+
end
|
12
|
+
@certification_key = hash['certification_key']
|
13
|
+
@name = hash['name']
|
14
|
+
@requires = (v=hash['requires']) ? v.map!{|e| e.is_a?(ControlID) ? e : ControlID.new(e)} : v
|
15
|
+
end
|
16
|
+
attr_accessor :certification_key # str
|
17
|
+
attr_accessor :name # str
|
18
|
+
attr_accessor :requires # seq
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
class ControlID
|
23
|
+
include Kwalify::Util::HashLike
|
24
|
+
def initialize(hash=nil)
|
25
|
+
if hash.nil?
|
26
|
+
return
|
27
|
+
end
|
28
|
+
@standard_key = hash['standard_key']
|
29
|
+
@control_key = hash['control_key']
|
30
|
+
end
|
31
|
+
attr_accessor :standard_key # str
|
32
|
+
attr_accessor :control_key # str
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'kwalify/util/hashlike'
|
2
|
+
|
3
|
+
module OCTool
|
4
|
+
|
5
|
+
|
6
|
+
class Component
|
7
|
+
include Kwalify::Util::HashLike
|
8
|
+
def initialize(hash=nil)
|
9
|
+
if hash.nil?
|
10
|
+
return
|
11
|
+
end
|
12
|
+
@name = hash['name']
|
13
|
+
@component_key = hash['component_key']
|
14
|
+
@description = hash['description']
|
15
|
+
@attestations = (v=hash['attestations']) ? v.map!{|e| e.is_a?(Attestation) ? e : Attestation.new(e)} : v
|
16
|
+
end
|
17
|
+
attr_accessor :name # str
|
18
|
+
attr_accessor :component_key # str
|
19
|
+
attr_accessor :description # str
|
20
|
+
attr_accessor :attestations # seq
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class Attestation
|
25
|
+
include Kwalify::Util::HashLike
|
26
|
+
def initialize(hash=nil)
|
27
|
+
if hash.nil?
|
28
|
+
return
|
29
|
+
end
|
30
|
+
@summary = hash['summary']
|
31
|
+
@status = hash['status']
|
32
|
+
@date_verified = hash['date_verified']
|
33
|
+
@satisfies = (v=hash['satisfies']) ? v.map!{|e| e.is_a?(ControlID) ? e : ControlID.new(e)} : v
|
34
|
+
@narrative = hash['narrative']
|
35
|
+
end
|
36
|
+
attr_accessor :summary # str
|
37
|
+
attr_accessor :status # str
|
38
|
+
attr_accessor :date_verified # date
|
39
|
+
attr_accessor :satisfies # seq
|
40
|
+
attr_accessor :narrative # str
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
class ControlID
|
45
|
+
include Kwalify::Util::HashLike
|
46
|
+
def initialize(hash=nil)
|
47
|
+
if hash.nil?
|
48
|
+
return
|
49
|
+
end
|
50
|
+
@standard_key = hash['standard_key']
|
51
|
+
@control_key = hash['control_key']
|
52
|
+
end
|
53
|
+
attr_accessor :standard_key # text
|
54
|
+
attr_accessor :control_key # text
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'kwalify/util/hashlike'
|
2
|
+
|
3
|
+
module OCTool
|
4
|
+
|
5
|
+
|
6
|
+
class Config
|
7
|
+
include Kwalify::Util::HashLike
|
8
|
+
def initialize(hash=nil)
|
9
|
+
if hash.nil?
|
10
|
+
return
|
11
|
+
end
|
12
|
+
@schema_version = hash['schema_version']
|
13
|
+
@name = hash['name']
|
14
|
+
@overview = hash['overview']
|
15
|
+
@maintainers = hash['maintainers']
|
16
|
+
@metadata = (v=hash['metadata']) && v.is_a?(Hash) ? Metadata.new(v) : v
|
17
|
+
@includes = (v=hash['includes']) ? v.map!{|e| e.is_a?(Include) ? e : Include.new(e)} : v
|
18
|
+
end
|
19
|
+
attr_accessor :schema_version # str
|
20
|
+
attr_accessor :name # str
|
21
|
+
attr_accessor :overview # str
|
22
|
+
attr_accessor :maintainers # seq
|
23
|
+
attr_accessor :metadata # map
|
24
|
+
attr_accessor :includes # seq
|
25
|
+
end
|
26
|
+
|
27
|
+
## Optional metadata.
|
28
|
+
class Metadata
|
29
|
+
include Kwalify::Util::HashLike
|
30
|
+
def initialize(hash=nil)
|
31
|
+
if hash.nil?
|
32
|
+
return
|
33
|
+
end
|
34
|
+
@abstract = hash['abstract']
|
35
|
+
@description = hash['description']
|
36
|
+
end
|
37
|
+
attr_accessor :abstract # str
|
38
|
+
attr_accessor :description # str
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
class Include
|
43
|
+
include Kwalify::Util::HashLike
|
44
|
+
def initialize(hash=nil)
|
45
|
+
if hash.nil?
|
46
|
+
return
|
47
|
+
end
|
48
|
+
@type = hash['type']
|
49
|
+
@path = hash['path']
|
50
|
+
end
|
51
|
+
attr_accessor :type # str
|
52
|
+
attr_accessor :path # str
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'kwalify/util/hashlike'
|
2
|
+
|
3
|
+
module OCTool
|
4
|
+
|
5
|
+
|
6
|
+
class Standard
|
7
|
+
include Kwalify::Util::HashLike
|
8
|
+
def initialize(hash=nil)
|
9
|
+
if hash.nil?
|
10
|
+
return
|
11
|
+
end
|
12
|
+
@name = hash['name']
|
13
|
+
@standard_key = hash['standard_key']
|
14
|
+
@families = (v=hash['families']) ? v.map!{|e| e.is_a?(ControlFamily) ? e : ControlFamily.new(e)} : v
|
15
|
+
@controls = (v=hash['controls']) ? v.map!{|e| e.is_a?(Control) ? e : Control.new(e)} : v
|
16
|
+
end
|
17
|
+
attr_accessor :name # str
|
18
|
+
attr_accessor :standard_key # str
|
19
|
+
attr_accessor :families # seq
|
20
|
+
attr_accessor :controls # seq
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
class ControlFamily
|
25
|
+
include Kwalify::Util::HashLike
|
26
|
+
def initialize(hash=nil)
|
27
|
+
if hash.nil?
|
28
|
+
return
|
29
|
+
end
|
30
|
+
@family_key = hash['family_key']
|
31
|
+
@name = hash['name']
|
32
|
+
end
|
33
|
+
attr_accessor :family_key # str
|
34
|
+
attr_accessor :name # str
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
class Control
|
39
|
+
include Kwalify::Util::HashLike
|
40
|
+
def initialize(hash=nil)
|
41
|
+
if hash.nil?
|
42
|
+
return
|
43
|
+
end
|
44
|
+
@control_key = hash['control_key']
|
45
|
+
@family_key = hash['family_key']
|
46
|
+
@name = hash['name']
|
47
|
+
@description = hash['description']
|
48
|
+
end
|
49
|
+
attr_accessor :control_key # str
|
50
|
+
attr_accessor :family_key # str
|
51
|
+
attr_accessor :name # str
|
52
|
+
attr_accessor :description # str
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module OCTool
|
2
|
+
# Custom error to show validation errors.
|
3
|
+
class ValidationError < StandardError
|
4
|
+
attr_reader :errors
|
5
|
+
def initialize(path, errors)
|
6
|
+
@path = path
|
7
|
+
@errors = errors
|
8
|
+
end
|
9
|
+
|
10
|
+
def message
|
11
|
+
msg = ["[ERROR] #{@path}"]
|
12
|
+
@errors.each do |e|
|
13
|
+
msg << "line #{e.linenum} col #{e.column} [#{e.path}] #{e.message}"
|
14
|
+
end
|
15
|
+
msg.join("\n")
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Logic to wrap the kwalify parser.
|
20
|
+
class Parser
|
21
|
+
def initialize(path)
|
22
|
+
@config_file = path
|
23
|
+
die "#{File.expand_path(path)} not readable" unless File.readable?(path)
|
24
|
+
end
|
25
|
+
|
26
|
+
# Class method: check that schemas are valid.
|
27
|
+
def self.validate_schemas
|
28
|
+
metavalidator = Kwalify::MetaValidator.instance
|
29
|
+
kwalify = Kwalify::Yaml::Parser.new(metavalidator)
|
30
|
+
Dir.glob("#{BASE_SCHEMA_DIR}/**/*.yaml").each do |schema|
|
31
|
+
kwalify.parse_file(schema)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def die(message = nil)
|
36
|
+
puts '[FAIL] ' + message if message
|
37
|
+
exit(1)
|
38
|
+
end
|
39
|
+
|
40
|
+
def validate_file(path, type)
|
41
|
+
parser = kwalify_parser(type)
|
42
|
+
data = parser.parse_file(path)
|
43
|
+
errors = parser.errors
|
44
|
+
raise ValidationError.new(path, errors) unless errors.empty?
|
45
|
+
|
46
|
+
data
|
47
|
+
rescue SystemCallError, Kwalify::SyntaxError, ValidationError => e
|
48
|
+
die e.message
|
49
|
+
end
|
50
|
+
|
51
|
+
def kwalify_parser(type)
|
52
|
+
schema_file = File.join(schema_dir, "#{type}.yaml")
|
53
|
+
schema = Kwalify::Yaml.load_file(schema_file)
|
54
|
+
validator = Kwalify::Validator.new(schema)
|
55
|
+
Kwalify::Yaml::Parser.new(validator) { |p| p.data_binding = true }
|
56
|
+
end
|
57
|
+
|
58
|
+
def schema_dir
|
59
|
+
@schema_dir ||= begin
|
60
|
+
File.join(BASE_SCHEMA_DIR, schema_version).freeze
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def schema_version
|
65
|
+
@schema_version ||= Kwalify::Yaml.load_file(@config_file)['schema_version']
|
66
|
+
rescue StandardError
|
67
|
+
warn "Setting schema_version to #{LATEST_SCHEMA_VERSION}"
|
68
|
+
LATEST_SCHEMA_VERSION
|
69
|
+
end
|
70
|
+
|
71
|
+
# Check that all data files are valid.
|
72
|
+
def validate_data
|
73
|
+
base_dir = File.dirname(@config_file)
|
74
|
+
config = validate_file(@config_file, 'config')
|
75
|
+
config['includes'].each do |inc|
|
76
|
+
path = File.join(base_dir, inc['path'])
|
77
|
+
type = inc['type']
|
78
|
+
validate_file(path, type)
|
79
|
+
end
|
80
|
+
config
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_system
|
84
|
+
base_dir = File.dirname(@config_file)
|
85
|
+
config = load_file(@config_file, 'config')
|
86
|
+
system = System.new(config)
|
87
|
+
config.includes.each do |inc|
|
88
|
+
path = File.join(base_dir, inc.path)
|
89
|
+
system.data << load_file(path, inc.type)
|
90
|
+
end
|
91
|
+
system
|
92
|
+
end
|
93
|
+
|
94
|
+
def load_file(path, type)
|
95
|
+
die "#{File.expand_path(path)} not readable" unless File.readable?(path)
|
96
|
+
klass = Object.const_get("OCTool::#{type.capitalize}")
|
97
|
+
ydoc = Kwalify::Yaml.load_file(path)
|
98
|
+
klass.new(ydoc)
|
99
|
+
rescue SystemCallError, Kwalify::SyntaxError => e
|
100
|
+
die e.message
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
data/lib/octool/ssp.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'erb'
|
2
|
+
|
3
|
+
module OCTool
|
4
|
+
# Build DB, CSV, and markdown.
|
5
|
+
class SSP
|
6
|
+
def initialize(system, output_dir)
|
7
|
+
@system = system
|
8
|
+
@output_dir = output_dir
|
9
|
+
render_template
|
10
|
+
write
|
11
|
+
end
|
12
|
+
|
13
|
+
def render_template
|
14
|
+
print "Building markdown #{md_path} ... "
|
15
|
+
template_path = File.join(ERB_DIR, 'ssp.erb')
|
16
|
+
template = File.read(template_path)
|
17
|
+
output = ERB.new(template, nil, '-').result(binding)
|
18
|
+
File.open(md_path, 'w') { |f| f.puts output }
|
19
|
+
puts 'done'
|
20
|
+
end
|
21
|
+
|
22
|
+
def write
|
23
|
+
print "Building #{pdf_path} ... "
|
24
|
+
pandoc = Paru::Pandoc.new
|
25
|
+
converter = pandoc.configure do
|
26
|
+
from 'markdown'
|
27
|
+
to 'pdf'
|
28
|
+
pdf_engine 'lualatex'
|
29
|
+
toc
|
30
|
+
toc_depth 3
|
31
|
+
number_sections
|
32
|
+
highlight_style 'pygments'
|
33
|
+
end
|
34
|
+
output = converter << File.read(md_path)
|
35
|
+
File.new(pdf_path, 'wb').write(output)
|
36
|
+
puts 'done'
|
37
|
+
end
|
38
|
+
|
39
|
+
def md_path
|
40
|
+
@md_path ||= File.join(@output_dir, 'ssp.md')
|
41
|
+
end
|
42
|
+
|
43
|
+
def pdf_path
|
44
|
+
@pdf_path ||= File.join(@output_dir, 'ssp.pdf')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module OCTool
|
2
|
+
# Representation of a system
|
3
|
+
class System
|
4
|
+
attr_accessor :config
|
5
|
+
attr_accessor :data
|
6
|
+
|
7
|
+
def initialize(config)
|
8
|
+
@config = config
|
9
|
+
@data = []
|
10
|
+
end
|
11
|
+
|
12
|
+
def certifications
|
13
|
+
@certifications ||= @data.select { |e| e.is_a?(OCTool::Certification) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def components
|
17
|
+
@components ||= @data.select { |e| e.is_a?(OCTool::Component) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def standards
|
21
|
+
@standards ||= @data.select { |e| e.is_a?(OCTool::Standard) }
|
22
|
+
end
|
23
|
+
|
24
|
+
# List of all attestations claimed by components in the system.
|
25
|
+
def attestations
|
26
|
+
@attestations ||= begin
|
27
|
+
@attestations = []
|
28
|
+
components.each do |c|
|
29
|
+
# Add a "component_key" field to each attestation.
|
30
|
+
c.attestations.map! { |e| e['component_key'] = c.component_key; e }
|
31
|
+
@attestations << c.attestations
|
32
|
+
end
|
33
|
+
@attestations.flatten!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# List of all coverages.
|
38
|
+
def satisfies
|
39
|
+
@satisfies ||= begin
|
40
|
+
@satisfies = []
|
41
|
+
attestations.each do |a|
|
42
|
+
# Add an "attestation_key" field to each cover.
|
43
|
+
a.satisfies.map! { |e| e['component_key'] = a.commponent_key; e }
|
44
|
+
a.satisfies.map! { |e| e['attestation_key'] = a.attestation_summary; e }
|
45
|
+
@satisfies << a.satisfies
|
46
|
+
end
|
47
|
+
@satisfies.flatten!
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# List of all controls defined by standards in the system.
|
52
|
+
def controls
|
53
|
+
@controls || begin
|
54
|
+
@controls = []
|
55
|
+
standards.each do |s|
|
56
|
+
# Add a "standard_key" field to each control.
|
57
|
+
s.controls.map! { |e| e['standard_key'] = s.standard_key; e }
|
58
|
+
@controls << s.controls
|
59
|
+
end
|
60
|
+
@controls.flatten!
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
# List of all families defined by standards in the system.
|
65
|
+
def families
|
66
|
+
@families || begin
|
67
|
+
@families = []
|
68
|
+
standards.each do |s|
|
69
|
+
# Add a "standard_key" field to each family.
|
70
|
+
s.families.map! { |e| e['standard_key'] = s.standard_key; e }
|
71
|
+
@families << s.families
|
72
|
+
end
|
73
|
+
@families.flatten!
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/octool.rdoc
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
== octool - Open Compliance Tool
|
2
|
+
|
3
|
+
v0.0.1
|
4
|
+
|
5
|
+
=== Global Options
|
6
|
+
=== --help
|
7
|
+
Show this message
|
8
|
+
|
9
|
+
|
10
|
+
|
11
|
+
=== --version
|
12
|
+
Display the program version
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
=== Commands
|
17
|
+
==== Command: <tt>help command</tt>
|
18
|
+
Shows a list of commands or help for one command
|
19
|
+
|
20
|
+
Gets help for the application or its commands. Can also list the commands in a way helpful to creating a bash-style completion function
|
21
|
+
===== Options
|
22
|
+
===== -c
|
23
|
+
List commands one per line, to assist with shell completion
|
24
|
+
|
25
|
+
|
26
|
+
|
27
|
+
==== Command: <tt>ssp path/to/system/config.yaml</tt>
|
28
|
+
generate System Security Plan
|
29
|
+
|
30
|
+
|
31
|
+
===== Options
|
32
|
+
===== -d|--dir path/to/output/dir
|
33
|
+
|
34
|
+
where to store outputs
|
35
|
+
|
36
|
+
[Default Value] /tmp
|
37
|
+
Default output directory respects env vars TMPDIR, TMP, TEMP
|
38
|
+
|
39
|
+
==== Command: <tt>validate </tt>
|
40
|
+
Check sanity of configuration
|
41
|
+
|
42
|
+
|
43
|
+
===== Commands
|
44
|
+
====== Command: <tt>data path/to/system/config.yaml</tt>
|
45
|
+
validate data
|
46
|
+
|
47
|
+
|
48
|
+
====== Command: <tt>schemas </tt>
|
49
|
+
validate schemas
|
50
|
+
|
51
|
+
|
52
|
+
[Default Command] data
|
@@ -0,0 +1,27 @@
|
|
1
|
+
---
|
2
|
+
type: map
|
3
|
+
class: Certification
|
4
|
+
mapping:
|
5
|
+
certification_key:
|
6
|
+
desc: A short, unique identifier for this certification.
|
7
|
+
required: true
|
8
|
+
type: str
|
9
|
+
unique: true
|
10
|
+
name:
|
11
|
+
desc: A human-friendly name for the certification.
|
12
|
+
required: true
|
13
|
+
type: str
|
14
|
+
requires:
|
15
|
+
desc: List of control IDs required by the certification.
|
16
|
+
required: true
|
17
|
+
type: seq
|
18
|
+
sequence:
|
19
|
+
- type: map
|
20
|
+
class: ControlID
|
21
|
+
mapping:
|
22
|
+
standard_key:
|
23
|
+
required: true
|
24
|
+
type: str
|
25
|
+
control_key:
|
26
|
+
required: true
|
27
|
+
type: str
|
@@ -0,0 +1,60 @@
|
|
1
|
+
---
|
2
|
+
type: map
|
3
|
+
class: Component
|
4
|
+
mapping:
|
5
|
+
name:
|
6
|
+
desc: Human-friendly name to appear in the SSP.
|
7
|
+
type: str
|
8
|
+
required: true
|
9
|
+
component_key:
|
10
|
+
desc: Unique identifier for referential integrity.
|
11
|
+
type: str
|
12
|
+
required: true
|
13
|
+
description:
|
14
|
+
desc: A paragraph or two that describes the component.
|
15
|
+
type: str
|
16
|
+
required: true
|
17
|
+
attestations:
|
18
|
+
desc: List of attestations.
|
19
|
+
type: seq
|
20
|
+
sequence:
|
21
|
+
- type: map
|
22
|
+
class: Attestation
|
23
|
+
mapping:
|
24
|
+
summary:
|
25
|
+
desc: Arbitrary verbiage to appear in SSP as a TLDR.
|
26
|
+
type: str
|
27
|
+
required: true
|
28
|
+
status:
|
29
|
+
desc: To what extent is this attestation "done"?
|
30
|
+
type: str
|
31
|
+
required: true
|
32
|
+
enum:
|
33
|
+
- partial
|
34
|
+
- complete
|
35
|
+
- planned
|
36
|
+
- none
|
37
|
+
date_verified:
|
38
|
+
desc: When was this last verified?
|
39
|
+
type: date
|
40
|
+
required: false
|
41
|
+
satisfies:
|
42
|
+
desc: List of control IDs covered by this attestation.
|
43
|
+
type: seq
|
44
|
+
required: false
|
45
|
+
sequence:
|
46
|
+
- type: map
|
47
|
+
class: ControlID
|
48
|
+
mapping:
|
49
|
+
standard_key:
|
50
|
+
type: text
|
51
|
+
required: true
|
52
|
+
control_key:
|
53
|
+
type: text
|
54
|
+
required: true
|
55
|
+
narrative:
|
56
|
+
desc: |
|
57
|
+
Explain how attestation satisfies the indicated controls.
|
58
|
+
The content should be in markdown format.
|
59
|
+
type: str
|
60
|
+
required: true
|
@@ -0,0 +1,64 @@
|
|
1
|
+
---
|
2
|
+
type: map
|
3
|
+
class: Config
|
4
|
+
mapping:
|
5
|
+
schema_version:
|
6
|
+
desc: |
|
7
|
+
Must match one of the schema directories in the octool source.
|
8
|
+
required: true
|
9
|
+
type: str
|
10
|
+
|
11
|
+
name:
|
12
|
+
desc: Human-friendly to appear in the SSP.
|
13
|
+
required: true
|
14
|
+
type: str
|
15
|
+
|
16
|
+
overview:
|
17
|
+
desc: Human-friendly description to appear in the SSP.
|
18
|
+
required: true
|
19
|
+
type: str
|
20
|
+
|
21
|
+
maintainers:
|
22
|
+
desc: Who should somebody contact for questions about this SSP?
|
23
|
+
required: true
|
24
|
+
type: seq
|
25
|
+
sequence:
|
26
|
+
- type: str
|
27
|
+
|
28
|
+
metadata:
|
29
|
+
desc: Optional metadata.
|
30
|
+
required: false
|
31
|
+
type: map
|
32
|
+
class: Metadata
|
33
|
+
mapping:
|
34
|
+
abstract:
|
35
|
+
desc: Abstract appears in document metadata.
|
36
|
+
required: false
|
37
|
+
type: str
|
38
|
+
description:
|
39
|
+
desc: Description appears in document metadata.
|
40
|
+
required: false
|
41
|
+
type: str
|
42
|
+
'=':
|
43
|
+
desc: Arbitrary key:value pair of strings.
|
44
|
+
type: str
|
45
|
+
|
46
|
+
includes:
|
47
|
+
desc: Additional files to include from the system repo.
|
48
|
+
required: true
|
49
|
+
type: seq
|
50
|
+
sequence:
|
51
|
+
- type: map
|
52
|
+
class: Include
|
53
|
+
mapping:
|
54
|
+
type:
|
55
|
+
required: true
|
56
|
+
type: str
|
57
|
+
enum:
|
58
|
+
- certification
|
59
|
+
- component
|
60
|
+
- standard
|
61
|
+
path:
|
62
|
+
desc: Path must be relative within the repo.
|
63
|
+
required: true
|
64
|
+
type: str
|
@@ -0,0 +1,50 @@
|
|
1
|
+
---
|
2
|
+
type: map
|
3
|
+
class: Standard
|
4
|
+
mapping:
|
5
|
+
name:
|
6
|
+
desc: Human-friendly name to appear in SSP.
|
7
|
+
type: str
|
8
|
+
required: true
|
9
|
+
|
10
|
+
standard_key:
|
11
|
+
desc: Unique ID to use within YAML files.
|
12
|
+
type: str
|
13
|
+
required: true
|
14
|
+
|
15
|
+
families:
|
16
|
+
desc: Optional list of control families.
|
17
|
+
type: seq
|
18
|
+
required: false
|
19
|
+
sequence:
|
20
|
+
- type: map
|
21
|
+
class: ControlFamily
|
22
|
+
mapping:
|
23
|
+
family_key:
|
24
|
+
desc: Unique ID of the family
|
25
|
+
type: str
|
26
|
+
unique: true
|
27
|
+
name:
|
28
|
+
desc: Human-friendly name of the family
|
29
|
+
type: str
|
30
|
+
controls:
|
31
|
+
desc: Mandatory list of controls defined by the standard.
|
32
|
+
required: true
|
33
|
+
type: seq
|
34
|
+
sequence:
|
35
|
+
- type: map
|
36
|
+
class: Control
|
37
|
+
mapping:
|
38
|
+
control_key:
|
39
|
+
type: str
|
40
|
+
unique: true
|
41
|
+
required: true
|
42
|
+
family_key:
|
43
|
+
type: str
|
44
|
+
required: false
|
45
|
+
name:
|
46
|
+
type: str
|
47
|
+
required: true
|
48
|
+
description:
|
49
|
+
type: str
|
50
|
+
required: true
|
data/templates/ssp.erb
ADDED
@@ -0,0 +1,120 @@
|
|
1
|
+
---
|
2
|
+
title: "<%= @system.config.name -%>"
|
3
|
+
subtitle: "System Security Plan"
|
4
|
+
|
5
|
+
author:
|
6
|
+
<% @system.config.maintainers.each do |maintainer| %>
|
7
|
+
- <%= maintainer -%>
|
8
|
+
<% end %>
|
9
|
+
|
10
|
+
absract: |
|
11
|
+
<%= @system.config.metadata.abstract rescue 'None' %>
|
12
|
+
|
13
|
+
description: |
|
14
|
+
<%= @system.config.metadata.description rescue 'None' %>
|
15
|
+
|
16
|
+
fontsize: 11pt
|
17
|
+
mainfont: NotoSans
|
18
|
+
#monofont: NotoSansMono-ExtraCondensedLight
|
19
|
+
monofont: NotoSansMono-ExtraCondensed
|
20
|
+
mainfontoptions:
|
21
|
+
- Numbers=Lowercase
|
22
|
+
- Numbers=Proportional
|
23
|
+
- UprightFont=*
|
24
|
+
- ItalicFont=*-Italic
|
25
|
+
- BoldFont=*-Bold
|
26
|
+
- BoldItalicFont=*-BoldItalic
|
27
|
+
|
28
|
+
lof: false
|
29
|
+
lot: false
|
30
|
+
colorlinks: true
|
31
|
+
linkcolor: blue
|
32
|
+
urlcolor: blue
|
33
|
+
|
34
|
+
documentclass: report
|
35
|
+
classoption:
|
36
|
+
- onecolumn
|
37
|
+
- oneside
|
38
|
+
- portrait
|
39
|
+
|
40
|
+
pagestyle: headings
|
41
|
+
papersize: letter
|
42
|
+
geometry:
|
43
|
+
- top=2cm
|
44
|
+
- left=2cm
|
45
|
+
- right=2cm
|
46
|
+
- bottom=2cm
|
47
|
+
---
|
48
|
+
|
49
|
+
# <%= @system.config.name %>
|
50
|
+
|
51
|
+
## Overview
|
52
|
+
|
53
|
+
<%= @system.config.overview %>
|
54
|
+
|
55
|
+
## Standards
|
56
|
+
|
57
|
+
This System Security Plan (SSP) addresses these standards:
|
58
|
+
|
59
|
+
<% @system.standards.each do |s| -%>
|
60
|
+
- <%= s.name %>
|
61
|
+
<% end %>
|
62
|
+
|
63
|
+
The full copy of each standard is included in the appendix.
|
64
|
+
|
65
|
+
|
66
|
+
## Components
|
67
|
+
|
68
|
+
<% @system.components.each do |c| %>
|
69
|
+
### <%= c.name %>
|
70
|
+
|
71
|
+
<%= c.description %>
|
72
|
+
|
73
|
+
<% if c.attestations.empty? %>
|
74
|
+
_The organization has not yet documented attestations for this component_.
|
75
|
+
<% else %>
|
76
|
+
The organization offers the following attestations for this component.
|
77
|
+
<% end %>
|
78
|
+
|
79
|
+
<% c.attestations.each do |a| %>
|
80
|
+
#### <%= a.summary %>
|
81
|
+
|
82
|
+
Status: <%= a.status %>
|
83
|
+
|
84
|
+
Date verified: <%= a.date_verified if a.date_verified %>
|
85
|
+
|
86
|
+
Satisfies:
|
87
|
+
|
88
|
+
<% a.satisfies.each do |cid| -%>
|
89
|
+
- <%= cid.standard_key %> control <%= cid.control_key %>
|
90
|
+
<% end -%>
|
91
|
+
|
92
|
+
<%= a.narrative %>
|
93
|
+
|
94
|
+
<% end %>
|
95
|
+
<% end %>
|
96
|
+
|
97
|
+
|
98
|
+
# Appendix: Standards
|
99
|
+
|
100
|
+
<% @system.standards.each do |s| %>
|
101
|
+
## <%=s.name %>
|
102
|
+
|
103
|
+
<% if s.families and !s.families.empty? %>
|
104
|
+
### Families
|
105
|
+
|
106
|
+
<% s.families.each do |family| %>
|
107
|
+
- <%= family.family_key -%>: <%= family.name %>
|
108
|
+
<% end %>
|
109
|
+
|
110
|
+
<% end %>
|
111
|
+
|
112
|
+
### Controls
|
113
|
+
|
114
|
+
<% s.controls.each do |c| %>
|
115
|
+
#### Control <%= c.control_key -%>: <%= c.name %>
|
116
|
+
|
117
|
+
<%= c.description %>
|
118
|
+
|
119
|
+
<% end %>
|
120
|
+
<% end %>
|
metadata
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: octool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Paul Morgan
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-05-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rake
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '13.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '13.1'
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '13.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '13.1'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: rdoc
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '6.2'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '6.3'
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '6.2'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '6.3'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: daru
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - '='
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 0.2.2
|
60
|
+
type: :runtime
|
61
|
+
prerelease: false
|
62
|
+
version_requirements: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - '='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 0.2.2
|
67
|
+
- !ruby/object:Gem::Dependency
|
68
|
+
name: gli
|
69
|
+
requirement: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - '='
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: 2.19.0
|
74
|
+
type: :runtime
|
75
|
+
prerelease: false
|
76
|
+
version_requirements: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - '='
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 2.19.0
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: kwalify
|
83
|
+
requirement: !ruby/object:Gem::Requirement
|
84
|
+
requirements:
|
85
|
+
- - '='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.7.2
|
88
|
+
type: :runtime
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - '='
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: 0.7.2
|
95
|
+
- !ruby/object:Gem::Dependency
|
96
|
+
name: pandoc-ruby
|
97
|
+
requirement: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - '='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.1.4
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
requirements:
|
106
|
+
- - '='
|
107
|
+
- !ruby/object:Gem::Version
|
108
|
+
version: 2.1.4
|
109
|
+
- !ruby/object:Gem::Dependency
|
110
|
+
name: paru
|
111
|
+
requirement: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - '='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: 0.4.0.1
|
116
|
+
type: :runtime
|
117
|
+
prerelease: false
|
118
|
+
version_requirements: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - '='
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: 0.4.0.1
|
123
|
+
description:
|
124
|
+
email: jumanjiman@gmail.com
|
125
|
+
executables:
|
126
|
+
- octool
|
127
|
+
extensions: []
|
128
|
+
extra_rdoc_files:
|
129
|
+
- README.rdoc
|
130
|
+
- octool.rdoc
|
131
|
+
files:
|
132
|
+
- README.rdoc
|
133
|
+
- bin/octool
|
134
|
+
- lib/octool.rb
|
135
|
+
- lib/octool/constants.rb
|
136
|
+
- lib/octool/generated/certification.rb
|
137
|
+
- lib/octool/generated/component.rb
|
138
|
+
- lib/octool/generated/config.rb
|
139
|
+
- lib/octool/generated/standard.rb
|
140
|
+
- lib/octool/parser.rb
|
141
|
+
- lib/octool/ssp.rb
|
142
|
+
- lib/octool/system.rb
|
143
|
+
- lib/octool/version.rb
|
144
|
+
- octool.rdoc
|
145
|
+
- schemas/v1.0.0/certification.yaml
|
146
|
+
- schemas/v1.0.0/component.yaml
|
147
|
+
- schemas/v1.0.0/config.yaml
|
148
|
+
- schemas/v1.0.0/standard.yaml
|
149
|
+
- templates/ssp.erb
|
150
|
+
homepage: https://github.com/jumanjiman/octool
|
151
|
+
licenses:
|
152
|
+
- GPL-3.0
|
153
|
+
metadata: {}
|
154
|
+
post_install_message:
|
155
|
+
rdoc_options:
|
156
|
+
- "--title"
|
157
|
+
- octool
|
158
|
+
- "--main"
|
159
|
+
- README.rdoc
|
160
|
+
- "-ri"
|
161
|
+
require_paths:
|
162
|
+
- lib
|
163
|
+
- lib
|
164
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
165
|
+
requirements:
|
166
|
+
- - ">="
|
167
|
+
- !ruby/object:Gem::Version
|
168
|
+
version: '0'
|
169
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
170
|
+
requirements:
|
171
|
+
- - ">="
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: '0'
|
174
|
+
requirements: []
|
175
|
+
rubygems_version: 3.1.2
|
176
|
+
signing_key:
|
177
|
+
specification_version: 4
|
178
|
+
summary: Open Compliance Toolkit
|
179
|
+
test_files: []
|