diff --git a/lib/inspec/cli.rb b/lib/inspec/cli.rb index ef46e647d..3bca2e8ab 100644 --- a/lib/inspec/cli.rb +++ b/lib/inspec/cli.rb @@ -72,27 +72,45 @@ class Inspec::InspecCLI < Inspec::BaseCLI def json(target) # This deprecation warning is ignored currently. Inspec.deprecate(:renamed_to_inspec_export) - export(target) + export(target, true) end - desc "export PATH", "read all tests in PATH and generate a summary in json/yaml format." + desc "export PATH", "read the profile in PATH and generate a summary in the given format." + option :what, type: :string, + desc: "What to export: profile (default), readme, metadata." option :format, type: :string, - desc: "The output format to use json (default), yaml. If valid format is not provided then it will use the default." + 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 profile to a path" + desc: "Save the created output to a path" option :controls, type: :array, - desc: "A list of controls to include. Ignore all other tests." + desc: "For --what=profile, a list of controls to include. Ignore all other tests." option :tags, type: :array, - desc: "A list of tags to filter controls and include only those. Ignore all other tests." + desc: "For --what=profile, a list of tags to filter controls and include only those. Ignore all other tests." profile_options - def export(target) + def export(target, as_json = false) o = config diagnose(o) o["log_location"] = $stderr configure_logger(o) - # default is json - format = o[:format] || "json" + what = o[:what] || "profile" + raise Inspec::Error.new("Unrecognized option '#{what}' for --what - expected one of profile, readme, or metadata.") unless %w{profile readme metadata}.include?(what) + + default_format_for_what = { + "profile" => "yaml", + "metadata" => "raw", + "readme" => "raw", + } + valid_formats_for_what = { + "profile" => %w{yaml json}, + "metadata" => %w{yaml raw}, # not going to argue + "readme" => ["raw"], + } + format = o[:format] || default_format_for_what[what] + # default is json if we were called as old json command + format = "json" if as_json + raise Inspec::Error.new("Invalid option '#{format}' for --format and --what combination") unless format && valid_formats_for_what[what].include?(format) + o[:backend] = Inspec::Backend.create(Inspec::Config.mock) o[:check_mode] = true o[:vendor_cache] = Inspec::Cache.new(o[:vendor_cache]) diff --git a/test/fixtures/profiles/signed/profile-1.0.0.iaf b/test/fixtures/profiles/signed/profile-1.0.0.iaf new file mode 100644 index 000000000..59c1dad7c Binary files /dev/null and b/test/fixtures/profiles/signed/profile-1.0.0.iaf differ diff --git a/test/functional/inspec_export_profile_test.rb b/test/functional/inspec_export_profile_test.rb deleted file mode 100644 index b62b8deca..000000000 --- a/test/functional/inspec_export_profile_test.rb +++ /dev/null @@ -1,47 +0,0 @@ -require "functional/helper" -require "mixlib/shellout" -require "json_schemer" - -describe "inspec export" do - include FunctionalHelper - - parallelize_me! - - # inspec_json_profile_test covers most of the test as inspec export is alias to inspec json. - it "exports the profile in default json format" do - out = inspec("export " + example_profile) - _(out.stderr).must_equal "" - assert_exit_code 0, out - _(JSON.load(out.stdout)).must_be_kind_of Hash - end - - it "exports the iaf format profile to default json" do - prepare_examples do |dir| - skip_windows! - - unique_key_name = SecureRandom.uuid - - # create profile - profile = File.join(dir, "profile_a") - run_inspec_process("init profile profile_a", prefix: "cd #{dir};") - - out = run_inspec_process("sign generate-keys --keyname #{unique_key_name}", prefix: "cd #{dir};") - assert_exit_code 0, out - - out = run_inspec_process("sign profile --profile #{profile} --keyname #{unique_key_name}", prefix: "cd #{dir};") - assert_exit_code 0, out - - out = run_inspec_process("export profile_a-0.1.0.iaf", prefix: "cd #{dir};") - assert_exit_code 0, out - - _(out.stderr).must_equal "" - _(JSON.load(out.stdout)).must_be_kind_of Hash - delete_keys(unique_key_name) - end - end - - def delete_keys(unique_key_name) - File.delete("#{Inspec.config_dir}/keys/#{unique_key_name}.pem.key") if File.exist?("#{Inspec.config_dir}/keys/#{unique_key_name}.pem.key") - File.delete("#{Inspec.config_dir}/keys/#{unique_key_name}.pem.pub") if File.exist?("#{Inspec.config_dir}/keys/#{unique_key_name}.pem.pub") - end -end diff --git a/test/functional/inspec_export_test.rb b/test/functional/inspec_export_test.rb new file mode 100644 index 000000000..cda6212fd --- /dev/null +++ b/test/functional/inspec_export_test.rb @@ -0,0 +1,95 @@ +require "functional/helper" + +describe "inspec export" do + include FunctionalHelper + + parallelize_me! + + # inspec_json_profile_test covers most of the test as inspec export is alias to inspec json. + + let(:iaf) { "#{profile_path}/signed/profile-1.0.0.iaf" } + + it "exports the profile in default yaml format" do + out = inspec("export " + example_profile) + _(out.stderr).must_equal "" + assert_exit_code 0, out + _(YAML.load(out.stdout)).must_be_kind_of Hash + end + + it "exports the iaf format profile to default yaml" do + out = run_inspec_process("export #{iaf}") + assert_exit_code 0, out + + _(out.stderr).must_equal "" + _(YAML.load(out.stdout)).must_be_kind_of Hash + end + + it "exports the iaf format profile to explicit yaml" do + out = run_inspec_process("export --what profile --format yaml #{iaf}") + assert_exit_code 0, out + + _(out.stderr).must_equal "" + _(YAML.load(out.stdout)).must_be_kind_of Hash + end + + it "exports the iaf format profile to explicit json" do + out = run_inspec_process("export --what profile --format json #{iaf}") + assert_exit_code 0, out + + _(out.stderr).must_equal "" + _(JSON.load(out.stdout)).must_be_kind_of Hash + end + + it "rejects the iaf format profile to explicit raw" do + out = run_inspec_process("export --what profile --format raw #{iaf}") + assert_exit_code 1, out + _(out.stderr).must_include "Invalid option" + end + + it "rejects metadata export to json" do + out = run_inspec_process("export --what metadata --format json #{iaf}") + assert_exit_code 1, out + _(out.stderr).must_include "Invalid option" + end + + it "rejects README export to json" do + out = run_inspec_process("export --what readme --format json #{iaf}") + assert_exit_code 1, out + _(out.stderr).must_include "Invalid option" + end + + it "rejects README export to yaml" do + out = run_inspec_process("export --what readme --format yaml #{iaf}") + assert_exit_code 1, out + _(out.stderr).must_include "Invalid option" + end + + it "exports metadata in yaml" do + out = run_inspec_process("export --what metadata --format yaml #{iaf}") + assert_exit_code 0, out + + _(out.stderr).must_equal "" + _(YAML.load(out.stdout)).must_be_kind_of Hash + + _(out.stdout).must_equal File.read("#{profile_path}/old-examples/profile/inspec.yml") + end + + it "exports metadata in raw" do + # Same as previous + out = run_inspec_process("export --what metadata --format raw #{iaf}") + assert_exit_code 0, out + + _(out.stderr).must_equal "" + _(YAML.load(out.stdout)).must_be_kind_of Hash + + _(out.stdout).must_equal File.read("#{profile_path}/old-examples/profile/inspec.yml") + end + + it "exports readme in raw" do + out = run_inspec_process("export --what readme --format raw #{iaf}") + assert_exit_code 0, out + + _(out.stderr).must_equal "" + _(out.stdout).must_equal File.read("#{profile_path}/old-examples/profile/README.md") + end +end