octool 0.0.6 → 0.0.11
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 +4 -4
- data/bin/octool +7 -1
- data/lib/octool.rb +1 -1
- data/lib/octool/constants.rb +2 -1
- data/lib/octool/parser.rb +12 -12
- data/lib/octool/ssp.rb +27 -2
- data/lib/octool/system.rb +17 -16
- data/lib/octool/version.rb +1 -1
- data/octool.rdoc +8 -1
- data/schemas/v1.0.2/certification.yaml +27 -0
- data/schemas/v1.0.2/component.yaml +60 -0
- data/schemas/v1.0.2/config.yaml +111 -0
- data/schemas/v1.0.2/standard.yaml +50 -0
- data/templates/ssp.erb +222 -41
- metadata +18 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7421bbf076967b16d0210f813f936c0a75b572694071ad6674cdbd2368bfc5ff
|
4
|
+
data.tar.gz: 849f56075a2a9815fdb225518fb3579c817ed570382f8cd3a3b2f35916d6e9a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5bb0a131801cc5003fc2102e7efcab828a6f65099b9f0e65e5df4472ff137ba1f52479b7b9f454cfe75f3551d36d6c6cdfe94cccbf9429aeff2a847713afd779
|
7
|
+
data.tar.gz: ee327ac99c2a3036c474ffb7d370c99d23af9afc2e3bc36a6d1fd10573f8f0e7f0e872633797ee25819bafe9f3dd73f0871a4d23741f6ce41f2dc14e69c82bc1
|
data/bin/octool
CHANGED
@@ -77,12 +77,18 @@ class App
|
|
77
77
|
s.arg_name 'path/to/output/dir'
|
78
78
|
s.flag [:d, :dir]
|
79
79
|
|
80
|
+
s.desc 'Set SSP version'
|
81
|
+
s.default_value OCTool::DEFAULT_SSP_VERSION
|
82
|
+
s.long_desc 'Underscores are replaced by spaces'
|
83
|
+
s.arg_name 'VERSION'
|
84
|
+
s.flag :version
|
85
|
+
|
80
86
|
s.action do |global_options, options, args|
|
81
87
|
export_dir = options[:dir]
|
82
88
|
config_file = find_config(args)
|
83
89
|
system = OCTool::Parser.new(config_file).load_system
|
84
90
|
Dir.chdir File.dirname(config_file) do
|
85
|
-
OCTool::SSP.new(system, export_dir).generate
|
91
|
+
OCTool::SSP.new(system, export_dir).generate(options[:version])
|
86
92
|
end
|
87
93
|
end
|
88
94
|
end
|
data/lib/octool.rb
CHANGED
@@ -4,12 +4,12 @@ require 'octool/version.rb'
|
|
4
4
|
|
5
5
|
# Built-ins.
|
6
6
|
require 'csv'
|
7
|
+
require 'json'
|
7
8
|
require 'pp'
|
8
9
|
|
9
10
|
# 3rd-party libs.
|
10
11
|
require 'kwalify'
|
11
12
|
require 'kwalify/util/hashlike'
|
12
|
-
require 'recursive-open-struct'
|
13
13
|
|
14
14
|
# OCTool libs.
|
15
15
|
require 'octool/constants'
|
data/lib/octool/constants.rb
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module OCTool
|
4
|
-
LATEST_SCHEMA_VERSION = 'v1.0.
|
4
|
+
LATEST_SCHEMA_VERSION = 'v1.0.2'
|
5
5
|
BASE_SCHEMA_DIR = File.join(File.dirname(__FILE__), '..', '..', 'schemas').freeze
|
6
6
|
ERB_DIR = File.join(File.dirname(__FILE__), '..', '..', 'templates').freeze
|
7
7
|
DEFAULT_CONFIG_FILENAME = 'config.yaml'
|
8
8
|
DEFAULT_OUTPUT_DIR = '/data'
|
9
|
+
DEFAULT_SSP_VERSION = 'unset'
|
9
10
|
end
|
data/lib/octool/parser.rb
CHANGED
@@ -41,12 +41,12 @@ module OCTool
|
|
41
41
|
end
|
42
42
|
|
43
43
|
def validate_file(path, type)
|
44
|
-
|
45
|
-
data =
|
46
|
-
errors =
|
44
|
+
kwalify = kwalifyer(type)
|
45
|
+
data = kwalify.parse_file(path)
|
46
|
+
errors = kwalify.errors
|
47
47
|
raise ValidationError.new(path, errors) unless errors.empty?
|
48
48
|
|
49
|
-
|
49
|
+
data
|
50
50
|
rescue SystemCallError, Kwalify::SyntaxError, ValidationError => e
|
51
51
|
die e.message
|
52
52
|
end
|
@@ -88,14 +88,14 @@ module OCTool
|
|
88
88
|
end
|
89
89
|
|
90
90
|
def parsed_component(component)
|
91
|
-
component
|
91
|
+
component['attestations'].map! do |a|
|
92
92
|
# Add a "component_key" field to each attestation.
|
93
|
-
a['component_key'] = component
|
94
|
-
a
|
93
|
+
a['component_key'] = component['component_key']
|
94
|
+
a['satisfies'].map! do |s|
|
95
95
|
# Add "attestation_key" to each control satisfied by this attestation.
|
96
|
-
s['attestation_key'] = a
|
96
|
+
s['attestation_key'] = a['summary']
|
97
97
|
# Add "component_key" to each control satisfied by this attestation.
|
98
|
-
s['component_key'] = component
|
98
|
+
s['component_key'] = component['component_key']
|
99
99
|
s
|
100
100
|
end
|
101
101
|
a
|
@@ -105,13 +105,13 @@ module OCTool
|
|
105
105
|
|
106
106
|
def parsed_standard(standard)
|
107
107
|
# Add 'standard_key' to each control family and to each control.
|
108
|
-
standard
|
109
|
-
standard
|
108
|
+
standard['families'].map! { |f| f['standard_key'] = standard['standard_key']; f }
|
109
|
+
standard['controls'].map! { |c| c['standard_key'] = standard['standard_key']; c }
|
110
110
|
standard
|
111
111
|
end
|
112
112
|
|
113
113
|
def parsed_certification(cert)
|
114
|
-
cert
|
114
|
+
cert['requires'].map! { |r| r['certification_key'] = cert['certification_key']; r }
|
115
115
|
cert
|
116
116
|
end
|
117
117
|
|
data/lib/octool/ssp.rb
CHANGED
@@ -1,13 +1,24 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'date'
|
3
4
|
require 'erb'
|
4
5
|
|
5
6
|
module OCTool
|
6
7
|
# Build DB, CSV, and markdown.
|
7
8
|
class SSP
|
9
|
+
attr_reader :build_date
|
10
|
+
attr_reader :version
|
11
|
+
|
8
12
|
def initialize(system, output_dir)
|
9
13
|
@system = system
|
10
14
|
@output_dir = output_dir
|
15
|
+
@version = OCTool::DEFAULT_SSP_VERSION
|
16
|
+
@build_date = DateTime.now
|
17
|
+
end
|
18
|
+
|
19
|
+
def version=(version)
|
20
|
+
# LaTeX fancyheader aborts on underscore in footer.
|
21
|
+
@version = version.to_s.gsub(/_+/, ' ')
|
11
22
|
end
|
12
23
|
|
13
24
|
def pandoc
|
@@ -22,12 +33,14 @@ module OCTool
|
|
22
33
|
exit(1)
|
23
34
|
end
|
24
35
|
|
25
|
-
def generate
|
36
|
+
def generate(version = nil)
|
37
|
+
self.version = version if version
|
26
38
|
unless File.writable?(@output_dir)
|
27
39
|
warn "[FAIL] #{@output_dir} is not writable"
|
28
40
|
exit(1)
|
29
41
|
end
|
30
42
|
render_template
|
43
|
+
write_acronyms
|
31
44
|
write 'pdf'
|
32
45
|
write 'docx'
|
33
46
|
end
|
@@ -41,18 +54,30 @@ module OCTool
|
|
41
54
|
puts 'done'
|
42
55
|
end
|
43
56
|
|
57
|
+
def write_acronyms
|
58
|
+
return unless @system.acronyms
|
59
|
+
|
60
|
+
out_path = File.join(@output_dir, 'acronyms.json')
|
61
|
+
File.open(out_path, 'w') { |f| f.write JSON.pretty_generate(@system.acronyms) }
|
62
|
+
ENV['PANDOC_ACRONYMS_ACRONYMS'] = out_path
|
63
|
+
end
|
64
|
+
|
44
65
|
# rubocop:disable Metrics/AbcSize,Metrics/MethodLength
|
45
66
|
def write(type = 'pdf')
|
46
67
|
out_path = File.join(@output_dir, "ssp.#{type}")
|
47
68
|
print "Building #{out_path} ... "
|
48
69
|
converter = pandoc.configure do
|
49
|
-
from 'markdown'
|
70
|
+
from 'markdown+autolink_bare_uris'
|
50
71
|
to type
|
51
72
|
pdf_engine 'lualatex'
|
52
73
|
toc
|
53
74
|
toc_depth 3
|
54
75
|
number_sections
|
55
76
|
highlight_style 'pygments'
|
77
|
+
filter 'pandoc-acronyms' if ENV['PANDOC_ACRONYMS_ACRONYMS']
|
78
|
+
# https://en.wikibooks.org/wiki/LaTeX/Source_Code_Listings#Encoding_issue
|
79
|
+
# Uncomment the following line after the "listings" package is compatible with utf8
|
80
|
+
# listings
|
56
81
|
end
|
57
82
|
output = converter << File.read(md_path)
|
58
83
|
File.new(out_path, 'wb').write(output)
|
data/lib/octool/system.rb
CHANGED
@@ -22,57 +22,58 @@ module OCTool
|
|
22
22
|
@data = []
|
23
23
|
end
|
24
24
|
|
25
|
+
def acronyms
|
26
|
+
@acronyms ||= config['acronyms']
|
27
|
+
end
|
28
|
+
|
25
29
|
def certifications
|
26
|
-
@certifications ||= data.select { |e| e
|
30
|
+
@certifications ||= data.select { |e| e['type'] == 'certification' }
|
27
31
|
end
|
28
32
|
|
29
33
|
def components
|
30
|
-
@components ||= data.select { |e| e
|
34
|
+
@components ||= data.select { |e| e['type'] == 'component' }
|
31
35
|
end
|
32
36
|
|
33
37
|
def standards
|
34
|
-
@standards ||= data.select { |e| e
|
38
|
+
@standards ||= data.select { |e| e['type'] == 'standard' }
|
35
39
|
end
|
36
40
|
|
37
41
|
# List of all attestations claimed by components in the system.
|
38
42
|
def attestations
|
39
|
-
@attestations ||= components.map
|
43
|
+
@attestations ||= components.map { |c| c['attestations'] }.flatten
|
40
44
|
end
|
41
45
|
|
42
46
|
# List of all coverages.
|
43
47
|
def satisfies
|
44
|
-
@satisfies ||= attestations.map
|
48
|
+
@satisfies ||= attestations.map { |a| a['satisfies'] }.flatten
|
45
49
|
end
|
46
50
|
|
47
51
|
# List of all controls defined by standards in the system.
|
48
52
|
def controls
|
49
|
-
@controls ||= standards.map
|
53
|
+
@controls ||= standards.map { |s| s['controls'] }.flatten
|
50
54
|
end
|
51
55
|
|
52
56
|
# List of all families defined by standards in the system.
|
53
57
|
def families
|
54
|
-
@families ||= standards.map
|
58
|
+
@families ||= standards.map { |s| s['families'] }.flatten
|
55
59
|
end
|
56
60
|
|
57
61
|
# List of required controls for all certifications.
|
58
62
|
def requires
|
59
|
-
@requires ||= certifications.map
|
63
|
+
@requires ||= certifications.map { |c| c['requires'] }.flatten
|
60
64
|
end
|
61
65
|
|
62
66
|
def dump(writable_dir)
|
63
|
-
TABLE_NAMES.each do |
|
64
|
-
write_csv method(
|
67
|
+
TABLE_NAMES.each do |table|
|
68
|
+
write_csv method(table.to_sym).call, File.join(writable_dir, "#{table}.csv")
|
65
69
|
end
|
66
70
|
end
|
67
71
|
|
68
72
|
# Convert array of hashes into a CSV.
|
69
73
|
def write_csv(ary, filename)
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
# Throw away nested hashes.
|
74
|
-
e.reject { |_, val| val.is_a?(Enumerable) }
|
75
|
-
end
|
74
|
+
# Throw away nested hashes. The parser already created separate tables for them.
|
75
|
+
ary = ary.map { |e| e.reject { |_, val| val.is_a?(Enumerable) } }
|
76
|
+
|
76
77
|
warn "[INFO] write #{filename}"
|
77
78
|
CSV.open(filename, 'wb') do |csv|
|
78
79
|
column_names = ary.first.keys
|
data/lib/octool/version.rb
CHANGED
data/octool.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
== octool - Open Compliance Tool
|
2
2
|
|
3
|
-
v0.0.
|
3
|
+
v0.0.11
|
4
4
|
|
5
5
|
=== Global Options
|
6
6
|
=== --help
|
@@ -48,6 +48,13 @@ where to store outputs
|
|
48
48
|
[Default Value] /tmp
|
49
49
|
Default output directory respects env vars TMPDIR, TMP, TEMP
|
50
50
|
|
51
|
+
===== --version VERSION
|
52
|
+
|
53
|
+
Set SSP version
|
54
|
+
|
55
|
+
[Default Value] unset
|
56
|
+
Underscores are replaced by spaces
|
57
|
+
|
51
58
|
==== Command: <tt>validate </tt>
|
52
59
|
Check sanity of configuration
|
53
60
|
|
@@ -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,111 @@
|
|
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
|
+
logo:
|
12
|
+
desc: Image for title page.
|
13
|
+
required: false
|
14
|
+
type: map
|
15
|
+
class: Logo
|
16
|
+
mapping:
|
17
|
+
path:
|
18
|
+
desc: Path to image.
|
19
|
+
type: str
|
20
|
+
required: true
|
21
|
+
width:
|
22
|
+
desc: Width of image, such as "1in" or "254mm"
|
23
|
+
type: str
|
24
|
+
required: true
|
25
|
+
|
26
|
+
name:
|
27
|
+
desc: Human-friendly to appear in the SSP.
|
28
|
+
required: true
|
29
|
+
type: str
|
30
|
+
|
31
|
+
overview:
|
32
|
+
desc: Human-friendly description to appear in the SSP.
|
33
|
+
required: true
|
34
|
+
type: str
|
35
|
+
|
36
|
+
maintainers:
|
37
|
+
desc: Who should somebody contact for questions about this SSP?
|
38
|
+
required: true
|
39
|
+
type: seq
|
40
|
+
sequence:
|
41
|
+
- type: str
|
42
|
+
|
43
|
+
metadata:
|
44
|
+
desc: Optional metadata.
|
45
|
+
required: false
|
46
|
+
type: map
|
47
|
+
class: Metadata
|
48
|
+
mapping:
|
49
|
+
abstract:
|
50
|
+
desc: Abstract appears in document metadata.
|
51
|
+
required: false
|
52
|
+
type: str
|
53
|
+
description:
|
54
|
+
desc: Description appears in document metadata.
|
55
|
+
required: false
|
56
|
+
type: str
|
57
|
+
'=':
|
58
|
+
desc: Arbitrary key:value pair of strings.
|
59
|
+
type: str
|
60
|
+
|
61
|
+
includes:
|
62
|
+
desc: Additional files to include from the system repo.
|
63
|
+
required: true
|
64
|
+
type: seq
|
65
|
+
sequence:
|
66
|
+
- type: map
|
67
|
+
class: Include
|
68
|
+
mapping:
|
69
|
+
type:
|
70
|
+
required: true
|
71
|
+
type: str
|
72
|
+
enum:
|
73
|
+
- certification
|
74
|
+
- component
|
75
|
+
- standard
|
76
|
+
path:
|
77
|
+
desc: Path must be relative within the repo.
|
78
|
+
required: true
|
79
|
+
type: str
|
80
|
+
|
81
|
+
acronyms:
|
82
|
+
desc: |
|
83
|
+
List of acronyms to be referenced in the doc.
|
84
|
+
|
85
|
+
The acronyms follow the forms and usage described by the pandoc filter
|
86
|
+
https://gitlab.com/mirkoboehm/pandoc-acronyms
|
87
|
+
|
88
|
+
If your config.yaml includes acronyms, the filter is automatically invoked.
|
89
|
+
required: false
|
90
|
+
type: map
|
91
|
+
mapping:
|
92
|
+
'=':
|
93
|
+
desc: |
|
94
|
+
Acronym as used in the doc source, such as "bba".
|
95
|
+
The source usually refers to the acronym with syntax "[!bba]",
|
96
|
+
but other syntax forms are possible (see upstream doc).
|
97
|
+
type: map
|
98
|
+
class: Acronym
|
99
|
+
mapping:
|
100
|
+
shortform:
|
101
|
+
desc: The short form of the expanded acronym, such as "BBA".
|
102
|
+
required: true
|
103
|
+
type: str
|
104
|
+
longform:
|
105
|
+
desc: |
|
106
|
+
The expanded form of the abbreviation, such as "Beer Brewing Attitude".
|
107
|
+
The first instance of "[!bba]" in the doc is automatically expanded to
|
108
|
+
"<longform> (<shortform>)".
|
109
|
+
Example: "[!bba]" expands to "Beer Brewing Attitude (BBA)".
|
110
|
+
required: true
|
111
|
+
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
CHANGED
@@ -1,29 +1,35 @@
|
|
1
1
|
---
|
2
|
-
<% if @system.config
|
2
|
+
<% if @system.config['logo'] -%>
|
3
3
|
title: |
|
4
|
-
{width=<%= @system.config['logo']['width'] %>}
|
5
5
|
|
6
|
-
<%= @system.config
|
6
|
+
<%= @system.config['name'] %>
|
7
7
|
<% else %>
|
8
|
-
title: "<%= @system.config
|
8
|
+
title: "<%= @system.config['name'] -%>"
|
9
9
|
<% end %>
|
10
10
|
|
11
|
-
subtitle:
|
11
|
+
subtitle: |
|
12
|
+
System Security Plan
|
13
|
+
|
14
|
+
<%=build_date.strftime('%Y-%b-%d')%>
|
15
|
+
|
16
|
+
<% unless version == OCTool::DEFAULT_SSP_VERSION -%>
|
17
|
+
Version <%=version%>
|
18
|
+
<% end -%>
|
12
19
|
|
13
20
|
author:
|
14
|
-
<% @system.config
|
21
|
+
<% @system.config['maintainers'].each do |maintainer| -%>
|
15
22
|
- <%= maintainer -%>
|
16
23
|
<% end %>
|
17
24
|
|
18
25
|
absract: |
|
19
|
-
<%= @system.config
|
26
|
+
<%= @system.config['metadata']['abstract'] rescue 'None' %>
|
20
27
|
|
21
28
|
description: |
|
22
|
-
<%= @system.config
|
29
|
+
<%= @system.config['metadata']['description'] rescue 'None' %>
|
23
30
|
|
24
31
|
fontsize: 11pt
|
25
32
|
mainfont: NotoSans
|
26
|
-
#monofont: NotoSansMono-ExtraCondensedLight
|
27
33
|
monofont: NotoSansMono-ExtraCondensed
|
28
34
|
mainfontoptions:
|
29
35
|
- Numbers=Lowercase
|
@@ -49,55 +55,195 @@ pagestyle: headings
|
|
49
55
|
papersize: letter
|
50
56
|
geometry:
|
51
57
|
- top=2cm
|
52
|
-
- left=
|
58
|
+
- left=3cm
|
53
59
|
- right=2cm
|
54
60
|
- bottom=2cm
|
61
|
+
|
62
|
+
header-includes:
|
63
|
+
- |
|
64
|
+
```{=latex}
|
65
|
+
% https://ctan.org/pkg/metalogo?lang=en
|
66
|
+
\usepackage{metalogo}
|
67
|
+
```
|
68
|
+
- |
|
69
|
+
```{=latex}
|
70
|
+
% https://github.com/jgm/pandoc/wiki/Pandoc-Tricks#left-aligning-tables-in-latex
|
71
|
+
\usepackage[margins=raggedright]{floatrow}
|
72
|
+
```
|
73
|
+
- |
|
74
|
+
```{=latex}
|
75
|
+
% https://github.com/jgm/pandoc/wiki/Pandoc-Tricks#definition-list-terms-on-their-own-line-in-latex
|
76
|
+
% "Clone" the original \item command
|
77
|
+
\let\originalitem\item
|
78
|
+
|
79
|
+
% Redefine the \item command using the "clone"
|
80
|
+
\makeatletter
|
81
|
+
\renewcommand{\item}[1][\@nil]{%
|
82
|
+
\def\tmp{#1}%
|
83
|
+
\ifx\tmp\@nnil\originalitem\else\originalitem[#1]\hfill\par\fi}
|
84
|
+
\makeatother
|
85
|
+
```
|
86
|
+
- |
|
87
|
+
```{=latex}
|
88
|
+
% The are at least two ways to configure how LaTeX floats figures.
|
89
|
+
%
|
90
|
+
% 1. One approach is described in section 17.2 of
|
91
|
+
% http://tug.ctan.org/tex-archive/info/epslatex/english/epslatex.pdf
|
92
|
+
% However, the approach described there requires to teach people
|
93
|
+
% how to write LaTeX cross-references in markdown.
|
94
|
+
%
|
95
|
+
% 2. Force figures, listings, etc., to float "[H]ere".
|
96
|
+
% This is a LaTeX anti-pattern because it causes large gaps of whitespace on some pages.
|
97
|
+
% This approach avoids having to teach people to create LaTeX cross-references.
|
98
|
+
% https://tex.stackexchange.com/a/101726
|
99
|
+
%
|
100
|
+
% Use option 2.
|
101
|
+
\usepackage{float}
|
102
|
+
\floatplacement{figure}{H}
|
103
|
+
```
|
104
|
+
- |
|
105
|
+
```{=latex}
|
106
|
+
% https://tex.stackexchange.com/a/32537
|
107
|
+
\usepackage{lastpage}
|
108
|
+
|
109
|
+
% https://ctan.org/pkg/fancyhdr?lang=en
|
110
|
+
\usepackage{fancyhdr}
|
111
|
+
|
112
|
+
\pagestyle{fancy}
|
113
|
+
<% unless version == OCTool::DEFAULT_SSP_VERSION %>
|
114
|
+
\fancyfoot[L]{Version: <%=version-%>}
|
115
|
+
<% end %>
|
116
|
+
\fancyfoot[C]{<%=build_date.strftime('%Y-%b-%d')-%>}
|
117
|
+
\fancyfoot[R]{\thepage\ of\ \pageref{LastPage}}
|
118
|
+
\renewcommand{\footrulewidth}{0.4pt} % thickness
|
119
|
+
\renewcommand{\headrulewidth}{0.4pt} % thickness
|
120
|
+
\fancypagestyle{plain}{\fancyhead{}\renewcommand{\headrule}{}}
|
121
|
+
```
|
122
|
+
- |
|
123
|
+
```{=latex}
|
124
|
+
% Which bullet glyphs are avaiable?
|
125
|
+
% http://texdoc.net/texmf-dist/doc/latex/comprehensive/symbols-a4.pdf TABLE 50
|
126
|
+
%
|
127
|
+
% https://learnbyexample.github.io/tutorial/ebook-generation/customizing-pandoc/
|
128
|
+
% https://tex.stackexchange.com/questions/174244/change-the-shape-of-the-bullet-list
|
129
|
+
% https://texblog.org/2008/10/16/lists-enumerate-itemize-description-and-how-to-change-them/
|
130
|
+
% https://tex.stackexchange.com/a/64899
|
131
|
+
% https://ctan.org/pkg/enumitem?lang=en
|
132
|
+
% https://www.latex4technics.com/?note=2vy0
|
133
|
+
%
|
134
|
+
%\usepackage{amsfonts}
|
135
|
+
%
|
136
|
+
% Make bullets small
|
137
|
+
%\renewcommand{\labelitemi}{\tiny $\textbullet$}
|
138
|
+
%\renewcommand{\labelitemii}{\tiny $\textopenbullet$}
|
139
|
+
%\renewcommand{\labelitemiii}{\tiny $\triangleright$}
|
140
|
+
%
|
141
|
+
% Align bullets to left margin and make small
|
142
|
+
% https://tex.stackexchange.com/a/86408
|
143
|
+
%\usepackage{enumitem}
|
144
|
+
%\usepackage{graphicx}
|
145
|
+
%\setlist[itemize,1]{leftmargin=*,label=\scalebox{.8}{$\textbullet$}}
|
146
|
+
%\setlist[itemize,2]{leftmargin=*,label=\scalebox{.8}{$\textopenbullet$}}
|
147
|
+
%\setlist[itemize,3]{leftmargin=*,label=\scalebox{.8}{\triangleright}}
|
148
|
+
%
|
149
|
+
% Align bullets to left margin and use normal font
|
150
|
+
\usepackage{enumitem}
|
151
|
+
\setlist[itemize,1]{leftmargin=*,label=$\textbullet$}
|
152
|
+
\setlist[itemize,2]{leftmargin=*,label=$\textopenbullet$}
|
153
|
+
\setlist[itemize,3]{leftmargin=*,label=\triangleright}
|
154
|
+
%
|
155
|
+
% Align bullets to left margin and use slightly smaller font
|
156
|
+
%\usepackage{MnSymbol}
|
157
|
+
%\setlist[itemize,1]{leftmargin=*,label=$\bullet$}
|
158
|
+
%\setlist[itemize,2]{leftmargin=*,label=$\circ$}
|
159
|
+
%\setlist[itemize,3]{leftmargin=*,label=\blacktriangleright}
|
160
|
+
```
|
55
161
|
---
|
56
162
|
|
57
|
-
#
|
163
|
+
# Introduction
|
58
164
|
|
59
|
-
##
|
165
|
+
## About this document
|
60
166
|
|
61
|
-
|
167
|
+
A System Security Plan (SSP) is a document to describe security controls in use
|
168
|
+
on an information system and their implementation. An SSP provides:
|
169
|
+
|
170
|
+
- Narrative of security control implementation
|
171
|
+
- Description of components and services
|
172
|
+
- System data flows and authorization boundaries
|
173
|
+
|
174
|
+
The SSP is also a tool to guide the assessment of the effectiveness
|
175
|
+
of controls within the system.
|
62
176
|
|
63
177
|
## Standards
|
64
178
|
|
65
|
-
This
|
179
|
+
This SSP draws from these standards:
|
66
180
|
|
67
181
|
<% @system.standards.each do |s| -%>
|
68
|
-
- <%=
|
182
|
+
- <%=s['name']-%> (<%=s['standard_key']-%>)
|
69
183
|
<% end %>
|
70
184
|
|
71
185
|
The full copy of each standard is included in the appendix.
|
72
186
|
|
73
187
|
|
74
|
-
##
|
188
|
+
## Certifications
|
75
189
|
|
76
|
-
|
77
|
-
|
190
|
+
A certification is a logical grouping of controls that are of interest to
|
191
|
+
a given subject. A particular certification does not necessarily target all
|
192
|
+
controls from a standard, nor does a particular certification need to draw
|
193
|
+
from a single standard.
|
78
194
|
|
79
|
-
|
195
|
+
This SSP addresses these certifications:
|
196
|
+
|
197
|
+
<% @system.certifications.each do |c| -%>
|
198
|
+
- <%=c['name']%>
|
199
|
+
|
200
|
+
<% c['requires'].each do |r| -%>
|
201
|
+
- <%=r['standard_key']-%> control <%=r['control_key']%>
|
202
|
+
<% end -%>
|
80
203
|
|
81
|
-
<% if c.attestations.empty? %>
|
82
|
-
_The organization has not yet documented attestations for this component_.
|
83
|
-
<% else %>
|
84
|
-
The organization offers the following attestations for this component.
|
85
204
|
<% end %>
|
86
205
|
|
87
|
-
<% c.attestations.each do |a| %>
|
88
|
-
#### <%= a.summary %>
|
89
206
|
|
90
|
-
|
207
|
+
# <%= @system.config['name'] %>
|
91
208
|
|
92
|
-
|
209
|
+
## Overview
|
93
210
|
|
94
|
-
|
211
|
+
<%= @system.config['overview'] %>
|
95
212
|
|
96
|
-
<% a.satisfies.each do |cid| -%>
|
97
|
-
- <%= cid.standard_key %> control <%= cid.control_key %>
|
98
|
-
<% end -%>
|
99
213
|
|
100
|
-
|
214
|
+
## Components
|
215
|
+
|
216
|
+
<% @system.components.each do |c| %>
|
217
|
+
### <%= c['name'] %>
|
218
|
+
|
219
|
+
<%= c['description'] %>
|
220
|
+
|
221
|
+
<% if c['attestations'].empty? %>
|
222
|
+
_The organization has not yet documented attestations for this component_.
|
223
|
+
<% else %>
|
224
|
+
The organization offers the following attestations for this component.
|
225
|
+
<% end %>
|
226
|
+
|
227
|
+
<% c['attestations'].compact.each do |a| %>
|
228
|
+
#### <%= a['summary'] %>
|
229
|
+
|
230
|
+
+----------+---------------+--------------------------------------------------------------+
|
231
|
+
| Status | Date verified | Satisfies |
|
232
|
+
+==========+===============+==============================================================+
|
233
|
+
<%
|
234
|
+
s = a['satisfies'][0]
|
235
|
+
verbiage = sprintf('%-58s', [s['standard_key'], 'control', s['control_key']].join(' '))
|
236
|
+
-%>
|
237
|
+
| <%=sprintf('%-8s', a['status'])-%> | <%=sprintf('%-13s', a['date_verified'])-%> | - <%=verbiage-%> |
|
238
|
+
<%
|
239
|
+
a['satisfies'][1..].each do |s|
|
240
|
+
verbiage = sprintf('%-58s', [s['standard_key'], 'control', s['control_key']].join(' '))
|
241
|
+
-%>
|
242
|
+
| | | - <%=verbiage-%> |
|
243
|
+
<% end -%>
|
244
|
+
+----------+---------------+--------------------------------------------------------------+
|
245
|
+
|
246
|
+
<%= a['narrative'] %>
|
101
247
|
|
102
248
|
<% end %>
|
103
249
|
<% end %>
|
@@ -106,25 +252,60 @@ Satisfies:
|
|
106
252
|
# Appendix: Standards
|
107
253
|
|
108
254
|
<% @system.standards.each do |s| %>
|
109
|
-
## <%=s
|
255
|
+
## <%=s['name'] %>
|
110
256
|
|
111
|
-
<% if s
|
257
|
+
<% if s['families'] and !s['families'].empty? %>
|
112
258
|
### Families
|
113
259
|
|
114
|
-
|
115
|
-
<%= family.family_key %>
|
116
|
-
~ <%= family.name %>
|
260
|
+
<%=s['name']-%> categorizes controls into logical groups called families.
|
117
261
|
|
118
|
-
|
262
|
+
| Family abbreviation | Family name |
|
263
|
+
| -------------------------- | -------------------- |
|
264
|
+
<% s['families'].each do |family| -%>
|
265
|
+
| <%=family['family_key']-%> | <%=family['name']-%> |
|
266
|
+
<% end -%>
|
267
|
+
|
268
|
+
: Control families for <%=s['name']%>
|
119
269
|
|
120
270
|
<% end %>
|
121
271
|
|
122
272
|
### Controls
|
123
273
|
|
124
|
-
<% s
|
125
|
-
#### Control <%= c
|
274
|
+
<% s['controls'].each do |c| %>
|
275
|
+
#### Control <%= c['control_key'] -%>: <%= c['name'] %>
|
126
276
|
|
127
|
-
<%= c
|
277
|
+
<%= c['description'] %>
|
128
278
|
|
129
279
|
<% end %>
|
130
280
|
<% end %>
|
281
|
+
|
282
|
+
|
283
|
+
# Colophon
|
284
|
+
|
285
|
+
This document was typeset in NotoSans with \LuaTeX\.
|
286
|
+
The main body font is 11-point, and
|
287
|
+
code snippets use NotoSansMono-ExtraCondensed.
|
288
|
+
|
289
|
+
The Noto family of fonts is freely available and developed by Google,
|
290
|
+
which describes Noto as:
|
291
|
+
|
292
|
+
> When text is rendered by a computer, sometimes characters are displayed as
|
293
|
+
> "tofu". They are little boxes to indicate your device doesn't have a
|
294
|
+
> font to display the text.
|
295
|
+
>
|
296
|
+
> Google has been developing a font family called Noto, which aims to support
|
297
|
+
> all languages with a harmonious look and feel. Noto is Google's answer to
|
298
|
+
> tofu. The name noto is to convey the idea that Google's goal is to see
|
299
|
+
> "no more tofu". Noto has multiple styles and weights, and is freely
|
300
|
+
> available to all.
|
301
|
+
|
302
|
+
Core tools used to produce this document:
|
303
|
+
|
304
|
+
- [Docker](https://www.docker.com/) provides a repeatable environment in
|
305
|
+
which to run the tools.
|
306
|
+
- [OCTool](https://github.com/jumanjihouse/octool)
|
307
|
+
provides a schema and wrapper to express compliance data as configuration.
|
308
|
+
- [Pandoc](https://pandoc.org/) converts extended markdown to PDF output.
|
309
|
+
- [Python](https://www.python.org/) is a core language for automation.
|
310
|
+
- [Ruby](https://www.ruby-lang.org/en/) is a core language for automation.
|
311
|
+
- [TeXLive](https://www.tug.org/texlive/) provides the \TeX\ family of tools.
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: octool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.11
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Morgan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-05-
|
11
|
+
date: 2020-05-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -93,61 +93,61 @@ dependencies:
|
|
93
93
|
- !ruby/object:Gem::Version
|
94
94
|
version: 2.19.0
|
95
95
|
- !ruby/object:Gem::Dependency
|
96
|
-
name:
|
96
|
+
name: json_pure
|
97
97
|
requirement: !ruby/object:Gem::Requirement
|
98
98
|
requirements:
|
99
99
|
- - '='
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version:
|
101
|
+
version: 2.3.0
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - '='
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version:
|
108
|
+
version: 2.3.0
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
|
-
name:
|
110
|
+
name: kwalify
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
113
|
- - '='
|
114
114
|
- !ruby/object:Gem::Version
|
115
|
-
version:
|
115
|
+
version: 0.7.2
|
116
116
|
type: :runtime
|
117
117
|
prerelease: false
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
119
119
|
requirements:
|
120
120
|
- - '='
|
121
121
|
- !ruby/object:Gem::Version
|
122
|
-
version:
|
122
|
+
version: 0.7.2
|
123
123
|
- !ruby/object:Gem::Dependency
|
124
|
-
name:
|
124
|
+
name: pandoc-ruby
|
125
125
|
requirement: !ruby/object:Gem::Requirement
|
126
126
|
requirements:
|
127
127
|
- - '='
|
128
128
|
- !ruby/object:Gem::Version
|
129
|
-
version:
|
129
|
+
version: 2.1.4
|
130
130
|
type: :runtime
|
131
131
|
prerelease: false
|
132
132
|
version_requirements: !ruby/object:Gem::Requirement
|
133
133
|
requirements:
|
134
134
|
- - '='
|
135
135
|
- !ruby/object:Gem::Version
|
136
|
-
version:
|
136
|
+
version: 2.1.4
|
137
137
|
- !ruby/object:Gem::Dependency
|
138
|
-
name:
|
138
|
+
name: paru
|
139
139
|
requirement: !ruby/object:Gem::Requirement
|
140
140
|
requirements:
|
141
141
|
- - '='
|
142
142
|
- !ruby/object:Gem::Version
|
143
|
-
version:
|
143
|
+
version: 0.4.0.1
|
144
144
|
type: :runtime
|
145
145
|
prerelease: false
|
146
146
|
version_requirements: !ruby/object:Gem::Requirement
|
147
147
|
requirements:
|
148
148
|
- - '='
|
149
149
|
- !ruby/object:Gem::Version
|
150
|
-
version:
|
150
|
+
version: 0.4.0.1
|
151
151
|
description:
|
152
152
|
email: jumanjiman@gmail.com
|
153
153
|
executables:
|
@@ -174,6 +174,10 @@ files:
|
|
174
174
|
- schemas/v1.0.1/component.yaml
|
175
175
|
- schemas/v1.0.1/config.yaml
|
176
176
|
- schemas/v1.0.1/standard.yaml
|
177
|
+
- schemas/v1.0.2/certification.yaml
|
178
|
+
- schemas/v1.0.2/component.yaml
|
179
|
+
- schemas/v1.0.2/config.yaml
|
180
|
+
- schemas/v1.0.2/standard.yaml
|
177
181
|
- templates/ssp.erb
|
178
182
|
homepage: https://github.com/jumanjiman/octool
|
179
183
|
licenses:
|