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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 245e14c9cf523957cca7c2826364125a1f11715a080015124c9477b1c99c6707
4
- data.tar.gz: '0759efbc98a8ce26407649d2c4c458e273d3711c8661fbc94b6bb13e194a9695'
3
+ metadata.gz: 7421bbf076967b16d0210f813f936c0a75b572694071ad6674cdbd2368bfc5ff
4
+ data.tar.gz: 849f56075a2a9815fdb225518fb3579c817ed570382f8cd3a3b2f35916d6e9a4
5
5
  SHA512:
6
- metadata.gz: a27114864b9430e4096429a2d26d13d92ed6bc53ebfb9fa00008e1beb04cc8527f0637d336020826172b47109b192a94b9adfb6eef3036ce160f150be35b6f5d
7
- data.tar.gz: 684fca7c472d21356ce73e63d6c079c959108ebd5debfb66b10e35acfdf04a899a50c9d669db938f284963159eaa656b4f3c981e560a17b1e3396ae8a7c99da8
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
@@ -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'
@@ -1,9 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OCTool
4
- LATEST_SCHEMA_VERSION = 'v1.0.1'
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
@@ -41,12 +41,12 @@ module OCTool
41
41
  end
42
42
 
43
43
  def validate_file(path, type)
44
- kwal = kwalifyer(type)
45
- data = kwal.parse_file(path)
46
- errors = kwal.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
- RecursiveOpenStruct.new(data, recurse_over_arrays: true, preserve_original_keys: true)
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.attestations.map! do |a|
91
+ component['attestations'].map! do |a|
92
92
  # Add a "component_key" field to each attestation.
93
- a['component_key'] = component.component_key
94
- a.satisfies.map! do |s|
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.summary
96
+ s['attestation_key'] = a['summary']
97
97
  # Add "component_key" to each control satisfied by this attestation.
98
- s['component_key'] = component.component_key
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.families.map! { |f| f['standard_key'] = standard.standard_key; f }
109
- standard.controls.map! { |c| c['standard_key'] = standard.standard_key; c }
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.requires.map! { |r| r['certification_key'] = cert.certification_key; r }
114
+ cert['requires'].map! { |r| r['certification_key'] = cert['certification_key']; r }
115
115
  cert
116
116
  end
117
117
 
@@ -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)
@@ -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.type == 'certification' }
30
+ @certifications ||= data.select { |e| e['type'] == 'certification' }
27
31
  end
28
32
 
29
33
  def components
30
- @components ||= data.select { |e| e.type == 'component' }
34
+ @components ||= data.select { |e| e['type'] == 'component' }
31
35
  end
32
36
 
33
37
  def standards
34
- @standards ||= data.select { |e| e.type == 'standard' }
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(&:attestations).flatten
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(&:satisfies).flatten
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(&:controls).flatten
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(&:families).flatten
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(&:requires).flatten
63
+ @requires ||= certifications.map { |c| c['requires'] }.flatten
60
64
  end
61
65
 
62
66
  def dump(writable_dir)
63
- TABLE_NAMES.each do |type|
64
- write_csv method(type.to_sym).call, File.join(writable_dir, "#{type}.csv")
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
- ary = ary.map do |e|
71
- # Convert each element from RecursiveOStruct to a Hash.
72
- e = e.is_a?(Hash) ? e : e.to_h
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module OCTool
4
- VERSION = '0.0.6'
4
+ VERSION = '0.0.11'
5
5
  end
@@ -1,6 +1,6 @@
1
1
  == octool - Open Compliance Tool
2
2
 
3
- v0.0.6
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
@@ -1,29 +1,35 @@
1
1
  ---
2
- <% if @system.config.logo -%>
2
+ <% if @system.config['logo'] -%>
3
3
  title: |
4
- ![](<%= @system.config.logo.path -%>){width=<%= @system.config.logo.width %>}
4
+ ![](<%= @system.config['logo']['path'] -%>){width=<%= @system.config['logo']['width'] %>}
5
5
 
6
- <%= @system.config.name %>
6
+ <%= @system.config['name'] %>
7
7
  <% else %>
8
- title: "<%= @system.config.name -%>"
8
+ title: "<%= @system.config['name'] -%>"
9
9
  <% end %>
10
10
 
11
- subtitle: "System Security Plan"
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.maintainers.each do |maintainer| %>
21
+ <% @system.config['maintainers'].each do |maintainer| -%>
15
22
  - <%= maintainer -%>
16
23
  <% end %>
17
24
 
18
25
  absract: |
19
- <%= @system.config.metadata.abstract rescue 'None' %>
26
+ <%= @system.config['metadata']['abstract'] rescue 'None' %>
20
27
 
21
28
  description: |
22
- <%= @system.config.metadata.description rescue 'None' %>
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=2cm
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
- # <%= @system.config.name %>
163
+ # Introduction
58
164
 
59
- ## Overview
165
+ ## About this document
60
166
 
61
- <%= @system.config.overview %>
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 System Security Plan (SSP) addresses these standards:
179
+ This SSP draws from these standards:
66
180
 
67
181
  <% @system.standards.each do |s| -%>
68
- - <%= s.name %>
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
- ## Components
188
+ ## Certifications
75
189
 
76
- <% @system.components.each do |c| %>
77
- ### <%= c.name %>
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
- <%= c.description %>
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
- Status: <%= a.status %>
207
+ # <%= @system.config['name'] %>
91
208
 
92
- Date verified: <%= a.date_verified if a.date_verified %>
209
+ ## Overview
93
210
 
94
- Satisfies:
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
- <%= a.narrative %>
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.name %>
255
+ ## <%=s['name'] %>
110
256
 
111
- <% if s.families and !s.families.empty? %>
257
+ <% if s['families'] and !s['families'].empty? %>
112
258
  ### Families
113
259
 
114
- <% s.families.each do |family| %>
115
- <%= family.family_key %>
116
- ~ <%= family.name %>
260
+ <%=s['name']-%> categorizes controls into logical groups called families.
117
261
 
118
- <% end %>
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.controls.each do |c| %>
125
- #### Control <%= c.control_key -%>: <%= c.name %>
274
+ <% s['controls'].each do |c| %>
275
+ #### Control <%= c['control_key'] -%>: <%= c['name'] %>
126
276
 
127
- <%= c.description %>
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.6
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-24 00:00:00.000000000 Z
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: kwalify
96
+ name: json_pure
97
97
  requirement: !ruby/object:Gem::Requirement
98
98
  requirements:
99
99
  - - '='
100
100
  - !ruby/object:Gem::Version
101
- version: 0.7.2
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: 0.7.2
108
+ version: 2.3.0
109
109
  - !ruby/object:Gem::Dependency
110
- name: pandoc-ruby
110
+ name: kwalify
111
111
  requirement: !ruby/object:Gem::Requirement
112
112
  requirements:
113
113
  - - '='
114
114
  - !ruby/object:Gem::Version
115
- version: 2.1.4
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: 2.1.4
122
+ version: 0.7.2
123
123
  - !ruby/object:Gem::Dependency
124
- name: paru
124
+ name: pandoc-ruby
125
125
  requirement: !ruby/object:Gem::Requirement
126
126
  requirements:
127
127
  - - '='
128
128
  - !ruby/object:Gem::Version
129
- version: 0.4.0.1
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: 0.4.0.1
136
+ version: 2.1.4
137
137
  - !ruby/object:Gem::Dependency
138
- name: recursive-open-struct
138
+ name: paru
139
139
  requirement: !ruby/object:Gem::Requirement
140
140
  requirements:
141
141
  - - '='
142
142
  - !ruby/object:Gem::Version
143
- version: 1.1.1
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: 1.1.1
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: