Module: Opencontrol::CLI

Defined in:
lib/opencontrol/cli.rb

Overview

This module holds the Opencontrol Linter Command Line Interface.

Constant Summary collapse

USAGE_TEXT =
<<USAGE_TEXT.freeze
    usage: opencontrol-linter

    optional arguments:
      -h, --help            show this help message and exit
      -c, --components
                            Specify component files should be checked. Defaults
                            to true. Searches ./**/component.yaml or the search
                            you optionally specify.
      -n, --certifications
                            Specify certification (eg FISMA high)files should be
                            checked. Defaults to true. Searches
                            ./certifications/*.yaml or the search you optionally
                            specify.
      -s, --standards
                            Specify standard files (eg NIST 800.53) should be
                            checked. Defaults to true. Searches
                            ./standards/*.yaml or the search you optionally
                            specify.
      -o, --opencontrols, --opencontrol
                            Specify opencontrol file or files should be
                            checked. Defaults to true. Searches
                            ./opencontrol.yaml or the search you optionally
                            specify.
      -a, --all             Run all types of validations (this is the default).
      -v, --version         Show the version of this utility.

    Usage examples:

        # lint all components, standards and certifications in the current directory
         opencontrol-linter

        # lint all components subdir components
         opencontrol-linter --components './components/**/component.yaml'

        # lint all standards files found
         opencontrol-linter --standards

        # lint one component
         opencontrol-linter --components './components/AU_policy/component.yaml'
USAGE_TEXT
CONFIG_FILENAME =
'./opencontrol.yaml'.freeze
PRESET =
{
  action: :run,
  targets: {
    components: [
      './components/**/component.yaml'
    ],
    standards: [
      './standards/*.yaml'
    ],
    certifications: [
      './certifications/*.yaml'
    ],
    opencontrols: [
      './opencontrol.yaml'
    ]
  }
}
ALIASES =
{
  components: %w[component c],
  standards: %w[standard s],
  certifications: %w[certification n],
  opencontrols: %w[opencontrol o],
  all: 'a',
  help: 'h',
  version: 'v'
}.freeze

Class Method Summary collapse

Class Method Details

.add_target(type, opts, specification) ⇒ Object



95
96
97
98
99
100
101
# File 'lib/opencontrol/cli.rb', line 95

def self.add_target(type, opts, specification)
  if use_default_pattern?(opts, type)
    specification[:targets][type] = default_spec[:targets][type]
  elsif opts[type].is_a?(String)
    specification[:targets][type] = [opts[type]]
  end
end

.all_selected?(opts, specification) ⇒ Boolean

Returns:

  • (Boolean)


162
163
164
# File 'lib/opencontrol/cli.rb', line 162

def self.all_selected?(opts, specification)
  opts[:all] || all_targets_empty?(specification)
end

.all_targets_empty?(specification) ⇒ Boolean

Returns:

  • (Boolean)


155
156
157
158
159
160
# File 'lib/opencontrol/cli.rb', line 155

def self.all_targets_empty?(specification)
  specification[:targets][:components].empty? &&
    specification[:targets][:standards].empty? &&
    specification[:targets][:certifications].empty? &&
    specification[:targets][:opencontrols].empty?
end

.construct_defaults(config) ⇒ Object



114
115
116
117
118
119
120
121
# File 'lib/opencontrol/cli.rb', line 114

def self.construct_defaults(config)
  spec = {
    action: :run,
    targets: {}.merge(PRESET[:targets].dup).merge(config[:targets])
  }

  expand_components_filenames(spec)
end

.default_specObject



143
144
145
146
147
148
149
# File 'lib/opencontrol/cli.rb', line 143

def self.default_spec
  if opencontrol_yaml_present?
    construct_defaults(load_config_from_yaml)
  else
    PRESET.dup
  end
end

.expand_components_filenames(spec) ⇒ Object



134
135
136
137
138
139
140
141
# File 'lib/opencontrol/cli.rb', line 134

def self.expand_components_filenames(spec)
  # the config file usually omits the component files full filename
  spec[:targets][:components] = spec[:targets][:components].collect do |f|
    f += '/component.yaml' if File.directory?(f)
    f
  end
  spec
end

.load_config_from_yamlObject



123
124
125
126
127
128
129
130
131
132
# File 'lib/opencontrol/cli.rb', line 123

def self.load_config_from_yaml
  yaml_config = YAML.load_file(CONFIG_FILENAME)
  yaml_config = Hash[yaml_config.map { |(k, v)| [k.to_sym, v] }]
  {
    action: :run,
    targets: yaml_config.select do |k, _v|
               %i[components standards certifications].include?(k)
             end
  }
end

.opencontrol_yaml_present?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/opencontrol/cli.rb', line 110

def self.opencontrol_yaml_present?
  File.exist?(CONFIG_FILENAME)
end

.parse_args(arguments) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/opencontrol/cli.rb', line 170

def self.parse_args(arguments)
  opts = Rationalist.parse(arguments, alias: ALIASES)
  specification = {
    action: :run,
    targets: Opencontrol::Linter.empty_targets
  }
  specification[:action] = :version                     if opts[:version]
  specification[:action] = :help                        if opts[:help]
  add_target(:components, opts, specification)     if opts[:components]
  add_target(:standards, opts, specification)      if opts[:standards]
  add_target(:certifications, opts, specification) if opts[:certifications]
  add_target(:opencontrols, opts, specification)   if opts[:opencontrols]
  specification = default_spec if use_default?(opts, specification)
  specification
end

.run_with_args(args) ⇒ Object



186
187
188
189
190
191
192
193
194
195
196
197
198
# File 'lib/opencontrol/cli.rb', line 186

def self.run_with_args(args)
  specification = parse_args(args)
  result = 0
  case specification[:action]
  when :run
    result = Opencontrol::Linter.run(specification)
  when :version
    result = show_version
  when :help
    result = show_help
  end
  exit(result)
end

.should_lint?(opts) ⇒ Boolean

Returns:

  • (Boolean)


151
152
153
# File 'lib/opencontrol/cli.rb', line 151

def self.should_lint?(opts)
  !(opts[:version] || opts[:help])
end

.show_helpObject



84
85
86
87
# File 'lib/opencontrol/cli.rb', line 84

def self.show_help
  puts USAGE_TEXT
  0 # exit with no error
end

.show_versionObject



89
90
91
92
93
# File 'lib/opencontrol/cli.rb', line 89

def self.show_version
  puts 'Opencontrol linter version: v' + Opencontrol::Version.version
  puts 'CMS 2019 Adrian Kierman '
  0 # exit with no error
end

.use_default?(opts, specification) ⇒ Boolean

Returns:

  • (Boolean)


166
167
168
# File 'lib/opencontrol/cli.rb', line 166

def self.use_default?(opts, specification)
  all_selected?(opts, specification) && should_lint?(opts)
end

.use_default_pattern?(opts, type) ⇒ Boolean

Returns:

  • (Boolean)


103
104
105
106
107
108
# File 'lib/opencontrol/cli.rb', line 103

def self.use_default_pattern?(opts, type)
  # this is set when the user uses a flag on the command line but doesnt
  # add a specific file pattern - this way the user can restrict to just
  # one type
  opts[type] == true
end