require "functional/helper" require "fileutils" require "tmpdir" describe "running profiles with git-based dependencies" do include FunctionalHelper let(:git_profiles) { "#{profile_path}/git-fetcher" } let(:git_default_main_profile_url) { "https://github.com/inspec/inspec-test-profile-default-main.git" } attr_accessor :out def inspec(commandline, prefix = nil) @stdout = @stderr = nil self.out = super end def stdout @stdout ||= out.stdout .force_encoding(Encoding::UTF_8) .gsub(/\e\[(\d+)(;\d+)*m/, "") # strip ANSI color codes end def stderr @stderr ||= out.stderr .force_encoding(Encoding::UTF_8) .gsub(/\e\[(\d+)(;\d+)*m/, "") # strip ANSI color codes end #======================================================================# # Git Repo Setup #======================================================================# fixture_repos = %w{basic-local git-repo-01} before(:all) do skip_windows! # Right now, this is due to symlinking, break executes on L24 # Stacktrace on windows machine: # Error: # running profiles with git-based dependencies::running a profile with an ./ relative path dependency#test_0001_should find the top-level profile in the git-referenced child profile and execute that: # Errno::ENOENT: No such file or directory @ apply2files - C:/Users/some/path/inspec/inspec/test/fixtures/profiles/git-fetcher/basic-local/.git # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:1437:in `unlink' # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:1437:in `block in remove_file' # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:1445:in `platform_support' # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:1436:in `remove_file' # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:775:in `remove_file' # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:562:in `block in rm' # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:561:in `each' # C:/Ruby/lib/ruby/2.6.0/fileutils.rb:561:in `rm' # C:/Users/some/path/inspec/inspec/test/functional/git_fetcher_test.rb:31:in `block (3 levels) in ' # C:/Users/some/path/inspec/inspec/test/functional/git_fetcher_test.rb:29:in `each' # C:/Users/some/path/inspec/inspec/test/functional/git_fetcher_test.rb:29:in `block (2 levels) in '" # We need a git repo for some of the profile test fixtures, # but we can't store those directly in git. # Here, one approach is to store the .git/ directory under a # different name and then symlink to its proper name. fixture_repos.each do |profile_name| link_src = "#{git_profiles}/#{profile_name}/git-fixture" link_dst = "#{git_profiles}/#{profile_name}/.git" FileUtils.ln_sf(link_src, link_dst) # -f to tolerate existing links created during manual testing end end after(:all) do fixture_repos.each do |profile_name| link = "#{git_profiles}/#{profile_name}/.git" FileUtils.rm(link) end end #======================================================================# # Custom Local Assertions #======================================================================# def assert_relative_fetch_works(profile_name, expected_profiles, expected_controls) run_result = run_inspec_process("exec #{git_profiles}/#{profile_name}", json: true) assert_empty run_result.stderr assert_json_controls_passing(run_result) # Should know about the top-level profile and the child profile assert_equal expected_profiles, (@json["profiles"].map { |p| p["name"] }) controls = @json["profiles"].map { |p| p["controls"] }.flatten.map { |c| c["id"] }.uniq # Should have controls from the top-level and included child profile expected_controls.each { |control| assert_includes controls, control } # should not have controls from the profile defined at the top of the repo of the child profile refute_includes controls, "red-dye" end #======================================================================# # Basic Git Fetching #======================================================================# describe "running a profile with a basic local dependency" do it "should work on a local checkout" do run_result = run_inspec_process("exec #{git_profiles}/basic-local", json: true) assert_empty run_result.stderr assert_json_controls_passing(run_result) end end # describe "running a profile with a basic remote dependency" # TODO: move private SSH+git test from inspec_exec_test to here #======================================================================# # Revision Selection #======================================================================# # NOTE: test branch, rev, and tag capabilities are (lighty) tested in unit tests #======================================================================# # Relative Path Support #======================================================================# #------------ Happy Cases for Relative Path Support -------------------# describe "running a profile with a shallow relative path dependency" do it "should find the relative path profile and execute exactly those controls" do assert_relative_fetch_works("relative-shallow", %w{relative-shallow child-01}, %w{top-level-01 child-01}) end end describe "running a profile with a deep relative path dependency" do it "should find the relative path profile and execute exactly those controls" do assert_relative_fetch_works("relative-deep", %w{relative-deep child-02}, %w{relative-deep-01 child-02}) end end describe "running a profile with a combination of relative path dependencies" do it "should find the relative path profiles and execute exactly those controls" do assert_relative_fetch_works( "relative-combo", %w{relative-combo child-01 child-02}, %w{relative-combo-01 child-01 child-02} ) end end #------------ Edge Cases for Relative Path Support -------------------# describe "running a profile with an '' relative path dependency" do it "should find the top-level profile in the git-referenced child profile and execute that" do assert_relative_fetch_works("relative-empty", %w{relative-empty basic-local}, %w{relative-empty-01 basic-local-01}) end end describe "running a profile with an ./ relative path dependency" do it "should find the top-level profile in the git-referenced child profile and execute that" do assert_relative_fetch_works("relative-dot-slash", %w{relative-dot-slash basic-local}, %w{relative-dot-slash-01 basic-local-01}) end end describe "running a profile with a relative path dependency that does not exist" do it "should fail gracefully" do run_result = run_inspec_process("exec #{git_profiles}/relative-nonesuch") assert_empty run_result.stdout refute_includes run_result.stderr, "Errno::ENOENT" # No ugly file missing error assert_equal 1, run_result.stderr.lines.count # Not a giant stacktrace # Spot check important parts of the message assert_includes run_result.stderr, "Cannot find relative path" assert_includes run_result.stderr, "no/such/path" # the actual missing path assert_includes run_result.stderr, "profile in git repo" # The containing git repo (the only identifier the user will have) assert_includes run_result.stderr, "test/fixtures/profiles/git-fetcher/git-repo-01" assert_exit_code(1, run_result) # General user error end end #------------ Happy Case for default branch GIT fetching -------------------# describe "running a remote GIT profile" do it "should use default HEAD branch" do inspec("exec #{git_default_main_profile_url}") assert_empty stderr assert_includes stdout, "Profile: InSpec Profile (default-main)" assert_includes stdout, "Profile Summary: 1 successful control, 0 control failures, 0 controls skipped\n" assert_includes stdout, "Test Summary: 2 successful, 0 failures, 0 skipped\n" assert_exit_code 0, out end end end