diff --git a/Gemfile b/Gemfile index 9ba03540b..d36631083 100644 --- a/Gemfile +++ b/Gemfile @@ -34,7 +34,6 @@ group :test do gem "pry-byebug" gem "pry", "~> 0.10" gem "rake", ">= 10" - gem "ruby-progressbar", "~> 1.8" gem "simplecov", "~> 0.21" gem "simplecov_json_formatter" gem "webmock", "~> 3.0" diff --git a/Rakefile b/Rakefile index 3d3880a04..c747fe1d7 100755 --- a/Rakefile +++ b/Rakefile @@ -5,21 +5,11 @@ require "bundler/gem_helper" require "rake/testtask" require "train" require "fileutils" +require_relative "tasks/docs" Bundler::GemHelper.install_tasks name: "inspec-core" Bundler::GemHelper.install_tasks name: "inspec" -# The docs tasks rely on ruby-progressbar. If we can't load it, then don't -# load the docs tasks. This is necessary to allow this Rakefile to work -# when the "tests" gem group in the Gemfile has been excluded, such as -# during an appbundle-updater run. -begin - require "ruby-progressbar" - require_relative "tasks/docs" -rescue LoadError - puts "docs tasks are unavailable because the ruby-progressbar gem is not available." -end - task :install do inspec_bin_path = ::File.join(::File.dirname(__FILE__), "inspec-bin") Dir.chdir(inspec_bin_path) diff --git a/lib/inspec/base_cli.rb b/lib/inspec/base_cli.rb index 42228b4f3..f01535a15 100644 --- a/lib/inspec/base_cli.rb +++ b/lib/inspec/base_cli.rb @@ -100,11 +100,11 @@ module Inspec option :ssl, type: :boolean, desc: "Use SSL for transport layer encryption (WinRM)." option :ssl_peer_fingerprint, type: :string, - desc: "Specify peer fingerprint for SSL authentication, used in lieu of certificates" + desc: "Specify SSL peer fingerprint in place of certificates for SSL authentication (WinRM)." option :self_signed, type: :boolean, desc: "Allow remote scans with self-signed certificates (WinRM)." option :ca_trust_file, type: :string, - desc: "Specify CA trust file for SSL authentication" + desc: "Specify CA certificate required for SSL authentication (WinRM)." option :client_cert, type: :string, desc: "Specify client certificate for SSL authentication" option :client_key, type: :string, @@ -121,32 +121,32 @@ module Inspec desc: "Read configuration from JSON file (`-` reads from stdin)." option :json_config, type: :string, hide: true option :proxy_command, type: :string, - desc: "Specifies the command to use to connect to the server" + desc: "Specifies the command to use to connect to the server." option :bastion_host, type: :string, - desc: "Specifies the bastion host if applicable" + desc: "Specifies the bastion host if applicable." option :bastion_user, type: :string, - desc: "Specifies the bastion user if applicable" + desc: "Specifies the bastion user if applicable." option :bastion_port, type: :string, - desc: "Specifies the bastion port if applicable" + desc: "Specifies the bastion port if applicable." option :insecure, type: :boolean, default: false, - desc: "Disable SSL verification on select targets" + desc: "Disable SSL verification on select targets." option :target_id, type: :string, - desc: "Provide a ID which will be included on reports - deprecated" + desc: "Provide an ID which will be included on reports - deprecated" option :winrm_shell_type, type: :string, default: "powershell", - desc: "Specify a shell type for winrm (eg. 'elevated' or 'powershell')" + desc: "Specify which shell type to use (powershell, elevated, or cmd), which defaults to powershell (WinRM)." option :docker_url, type: :string, - desc: "Provides path to Docker API endpoint (Docker)" + desc: "Provides path to Docker API endpoint (Docker). Defaults to unix:///var/run/docker.sock on Unix systems and tcp://localhost:2375 on Windows." option :ssh_config_file, type: :array, - desc: "A list of paths to the ssh config file, e.g ~/.ssh/config or /etc/ssh/ssh_config" + desc: "A list of paths to the ssh config file, e.g ~/.ssh/config or /etc/ssh/ssh_config." option :podman_url, type: :string, - desc: "Provides path to Podman API endpoint" + desc: "Provides the path to the Podman API endpoint. Defaults to unix:///run/user/$UID/podman/podman.sock for rootless container, unix:///run/podman/podman.sock for rootful container (for this you need to execute inspec as root user)." end def self.profile_options option :profiles_path, type: :string, desc: "Folder which contains referenced profiles." option :vendor_cache, type: :string, - desc: "Use the given path for caching dependencies. (default: ~/.inspec/cache)" + desc: "Use the given path for caching dependencies, (default: ~/.inspec/cache)." option :auto_install_gems, type: :boolean, default: false, desc: "Auto installs gem dependencies of the profile or resource pack." end @@ -174,7 +174,7 @@ module Inspec option :input, type: :array, banner: "name1=value1 name2=value2", desc: "Specify one or more inputs directly on the command line, as --input NAME=VALUE. Accepts single-quoted YAML and JSON structures." option :input_file, type: :array, - desc: "Load one or more input files, a YAML file with values for the profile to use" + desc: "Load one or more input files, a YAML file with values for the profile to use." option :waiver_file, type: :array, desc: "Load one or more waiver files." option :attestation_file, type: :array, @@ -184,14 +184,14 @@ module Inspec option :create_lockfile, type: :boolean, desc: "Write out a lockfile based on this execution (unless one already exists)" option :backend_cache, type: :boolean, - desc: "Allow caching for backend command output. (default: true)" + desc: "Allow caching for backend command output. (default: true)." option :show_progress, type: :boolean, desc: "Show progress while executing tests." option :distinct_exit, type: :boolean, default: true, desc: "Exit with code 101 if any tests fail, and 100 if any are skipped (default). If disabled, exit 0 on skips and 1 for failures." option :silence_deprecations, type: :array, banner: "[all]|[GROUP GROUP...]", - desc: "Suppress deprecation warnings. See install_dir/etc/deprecations.json for list of GROUPs or use 'all'." + desc: "Suppress deprecation warnings. See install_dir/etc/deprecations.json for a list of GROUPs or use 'all'." option :diff, type: :boolean, default: true, desc: "Use --no-diff to suppress 'diff' output of failed textual test results." option :sort_results_by, type: :string, default: "file", banner: "--sort-results-by=none|control|file|random", @@ -199,7 +199,7 @@ module Inspec option :filter_empty_profiles, type: :boolean, default: false, desc: "Filter empty profiles (profiles without controls) from the report." option :filter_waived_controls, type: :boolean, - desc: "Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores `run` setting of waiver file." + desc: "Do not execute waived controls in InSpec at all. Must use with --waiver-file. Ignores the `run` setting of the waiver file." option :retain_waiver_data, type: :boolean, desc: "EXPERIMENTAL: Only works in conjunction with --filter-waived-controls, retains waiver data about controls that were skipped" option :command_timeout, type: :numeric, diff --git a/lib/inspec/cli.rb b/lib/inspec/cli.rb index a8488f87a..d16776386 100644 --- a/lib/inspec/cli.rb +++ b/lib/inspec/cli.rb @@ -62,9 +62,9 @@ class Inspec::InspecCLI < Inspec::BaseCLI require "license_acceptance/cli_flags/thor" include LicenseAcceptance::CLIFlags::Thor - desc "json PATH", "read all tests in PATH and generate a JSON summary" + desc "json PATH", "read all tests in the PATH and generate a JSON summary." option :output, aliases: :o, type: :string, - desc: "Save the created profile to a path" + desc: "Save the created profile to a path." option :controls, type: :array, desc: "A list of controls to include. Ignore all other tests." option :tags, type: :array, @@ -84,7 +84,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI option :format, type: :string, desc: "The output format to use: json, raw, yaml. If valid format is not provided then it will use the default for the given 'what'." option :output, aliases: :o, type: :string, - desc: "Save the created output to a path" + desc: "Save the created output to a path." option :controls, type: :array, desc: "For --what=profile, a list of controls to include. Ignore all other tests." option :tags, type: :array, @@ -152,9 +152,11 @@ class Inspec::InspecCLI < Inspec::BaseCLI } end - desc "check PATH", "verify all tests at the specified PATH" + desc "check PATH", "Verify the metadata in the `inspec.yml` file,\ + verify that control blocks have the correct fields (title, description, impact),\ + and define that all controls have visible tests and the controls are not using deprecated InSpec DSL code" option :format, type: :string, - desc: "The output format to use doc (default), json. If valid format is not provided then it will use the default." + desc: "The output format to use. Valid values: `json` and `doc`. Default value: `doc`." option :with_cookstyle, type: :boolean, desc: "Enable or disable cookstyle checks.", default: false profile_options @@ -240,10 +242,10 @@ class Inspec::InspecCLI < Inspec::BaseCLI } end - desc "archive PATH", "archive a profile to tar.gz (default) or zip" + desc "archive PATH", "Archive a profile to a tar file (default) or zip file." profile_options option :output, aliases: :o, type: :string, - desc: "Save the archive to a path" + desc: "Save the archive to a path." option :zip, type: :boolean, default: false, desc: "Generates a zip archive." option :tar, type: :boolean, default: false, @@ -291,14 +293,10 @@ class Inspec::InspecCLI < Inspec::BaseCLI } end - desc "exec LOCATIONS", "Run all tests at LOCATIONS." + desc "exec LOCATIONS", "Run all test files at the specified locations." long_desc <<~EOT - Run all test files at the specified LOCATIONS. - - Loads the given profile(s) and fetches their dependencies if needed. Then - connects to the target and executes any controls contained in the profiles. - One or more reporters are used to generate output. - + The subcommand loads the given profiles, fetches their dependencies if needed, then connects to the target and executes any controls in the profiles. + One or more reporters are used to generate the output. ``` Exit codes: 0 Normal exit, all tests passed @@ -312,7 +310,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI Below are some examples of using `exec` with different test LOCATIONS: - Automate: + Chef Automate: ``` #{Inspec::Dist::EXEC_NAME} automate login #{Inspec::Dist::EXEC_NAME} exec compliance://username/linux-baseline @@ -322,7 +320,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI #{Inspec::Dist::EXEC_NAME} compliance login ``` - Supermarket: + Chef Supermarket: ``` #{Inspec::Dist::EXEC_NAME} exec supermarket://username/linux-baseline ``` @@ -359,12 +357,12 @@ class Inspec::InspecCLI < Inspec::BaseCLI #{Inspec::Dist::EXEC_NAME} exec https://github.com/dev-sec/linux-baseline.git ``` - Web hosted fileshare (also supports .zip): + Web hosted file (also supports .zip): ``` #{Inspec::Dist::EXEC_NAME} exec https://webserver/linux-baseline.tar.gz ``` - Web hosted fileshare with basic authentication (supports .zip): + Web hosted file with basic authentication (supports .zip): ``` #{Inspec::Dist::EXEC_NAME} exec https://username:password@webserver/linux-baseline.tar.gz ``` @@ -391,7 +389,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI } end - desc "detect", "detect the target OS" + desc "detect", "detects the target OS." target_options option :format, type: :string def detect @@ -420,7 +418,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI } end - desc "shell", "open an interactive debugging shell" + desc "shell", "open an interactive debugging shell." target_options option :command, aliases: :c, desc: "A single command string to run instead of launching the shell" @@ -483,7 +481,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI } end - desc "env", "Output shell-appropriate completion configuration" + desc "env", "Outputs shell-appropriate completion configuration." def env(shell = nil) Inspec.with_feature("inspec-cli-env") { begin @@ -519,7 +517,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI } end - desc "version", "prints the version of this tool" + desc "version", "prints the version of this tool." option :format, type: :string def version Inspec.with_feature("inspec-cli-version") { @@ -535,7 +533,7 @@ class Inspec::InspecCLI < Inspec::BaseCLI desc "clear_cache", "clears the InSpec cache. Useful for debugging." option :vendor_cache, type: :string, - desc: "Use the given path for caching dependencies. (default: ~/.inspec/cache)" + desc: "Use the given path for caching dependencies, (default: `~/.inspec/cache`)." def clear_cache Inspec.with_feature("inspec-cli-clear-cache") { o = config diff --git a/tasks/docs.rb b/tasks/docs.rb index 51b5015b6..52f8fe081 100644 --- a/tasks/docs.rb +++ b/tasks/docs.rb @@ -19,7 +19,23 @@ require "fileutils" require "yaml" require "git" -DOCS_DIR = "../docs".freeze +DOCS_DIR = "docs-chef-io/content/inspec".freeze + +MENU_MD = <<~MENU.freeze ++++ +title = "InSpec CLI" +draft = false +gh_repo = "inspec" + +[menu] + [menu.inspec] + title = "InSpec Executable" + identifier = "inspec/reference/cli.md InSpec Executable" + parent = "inspec/reference" + weight = 10 ++++ + +MENU class Markdown class << self @@ -45,6 +61,10 @@ class Markdown "* #{msg.gsub("\n", "\n ")}\n" end + def dl(msg) + "#{msg.gsub("\n", "\n ")}\n" + end + def ul(msg) msg + "\n" end @@ -64,7 +84,7 @@ class Markdown def meta(opts) o = opts.map { |k, v| "#{k}: #{v}" }.join("\n") - "---\n#{o}\n---\n\n" + "+++\n#{o}\n+++\n\n" end end end @@ -127,9 +147,9 @@ namespace :docs do # rubocop:disable Metrics/BlockLength # list of subcommands we ignore; these are e.g. plugins skip_commands = %w{scap} - res = f.meta(title: "About the InSpec CLI") - res << f.h1("InSpec CLI") - res << f.p("Use the InSpec CLI to run tests and audits against targets "\ + res = "" + res << MENU_MD + res << f.p("\n\nUse the InSpec Command Line Interface (CLI) to run tests and audits against targets "\ "using local, SSH, WinRM, or Docker connections.") require "inspec/cli" @@ -147,11 +167,11 @@ namespace :docs do # rubocop:disable Metrics/BlockLength res << f.h3("Syntax") res << f.p("This subcommand has the following syntax:") - res << f.code("$ inspec #{cmd.usage}", "bash") + res << f.code("inspec #{cmd.usage}", "bash") opts = cmd.options.reject { |_, o| o.hide } unless opts.empty? - res << f.h3("Options") + f.p("This subcommand has additional options:") + res << f.h3("Options") + f.p("This subcommand has the following additional options:") list = "" opts.keys.sort.each do |option| @@ -160,8 +180,10 @@ namespace :docs do # rubocop:disable Metrics/BlockLength usage = opt.usage.split(", ") .map { |x| x.tr("[]", "") } .map { |x| x.start_with?("-") ? x : "-" + x } - .map { |x| "``" + x + "``" } - list << f.li("#{usage.join(", ")} \n#{opt.description}") + .map { |x| "`" + x + "`" } + msg = "#{usage.join(", ")}\n" + msg << ": #{opt.description}\n" if opt.description && !opt.description.empty? + list << f.dl(msg) end.join res << f.ul(list) end @@ -170,11 +192,7 @@ namespace :docs do # rubocop:disable Metrics/BlockLength res << "\n\n" if f == RST end - # TODO: The directory is broken, so we need to fix it - # Use the docs-chef-io directory to fix the cli doc build - # doc_directory = File.join(pwd, "docs-chef-io/content/inspec") - # dst = File.join(doc_directory , "cli#{f.suffix}") - dst = File.join(DOCS_DIR, "cli#{f.suffix}") + dst = File.join(pwd, DOCS_DIR , "cli#{f.suffix}") File.write(dst, res) puts "Documentation generated in #{dst.inspect}" end