require "spec_helper" require "pedump" module Omnibus describe HealthCheck do let(:project) do double(Project, name: "chefdk", install_dir: "/opt/chefdk", library: double(Library, components: [] ) ) end def mkdump(base, size, x64 = false) dump = double(PEdump) pe = double(PEdump::PE, x64?: x64, ioh: double(x64 ? PEdump::IMAGE_OPTIONAL_HEADER64 : PEdump::IMAGE_OPTIONAL_HEADER32, ImageBase: base, SizeOfImage: size ) ) expect(dump).to receive(:pe).and_return(pe) dump end subject { described_class.new(project) } context "on windows" do before do stub_ohai(platform: "windows", version: "2012R2") end it "will perform dll base relocation checks" do stub_ohai(platform: "windows", version: "2012R2") expect(subject.relocation_checkable?).to be true end context "when performing dll base relocation checks" do let(:pmdumps) do { "a" => mkdump(0x10000000, 0x00001000), "b/b" => mkdump(0x20000000, 0x00002000), "c/c/c" => mkdump(0x30000000, 0x00004000), } end let(:search_dir) { "#{project.install_dir}/embedded/bin" } before do r = allow(Dir).to receive(:glob).with("#{search_dir}/*.dll") pmdumps.each do |file, dump| path = File.join(search_dir, file) r.and_yield(path) expect(File).to receive(:open).with(path, "rb").and_yield(double(File)) expect(PEdump).to receive(:new).with(path).and_return(dump) end end context "when given non-overlapping dlls" do it "should always return true" do expect(subject.run!).to eq(true) end it "should not identify conflicts" do expect(subject.relocation_check).to eq({}) end end context "when presented with overlapping dlls" do let(:pmdumps) do { "a" => mkdump(0x10000000, 0x00001000), "b/b" => mkdump(0x10000500, 0x00002000), "c/c/c" => mkdump(0x30000000, 0x00004000), } end it "should always return true" do expect(subject.run!).to eq(true) end it "should identify two conflicts" do expect(subject.relocation_check).to eq({ "a" => { base: 0x10000000, size: 0x00001000, conflicts: [ "b" ], }, "b" => { base: 0x10000500, size: 0x00002000, conflicts: [ "a" ], }, }) end end end end context "on linux" do before { stub_ohai(platform: "ubuntu", version: "16.04") } let(:bad_healthcheck) do double("Mixlib::Shellout", stdout: <<-EOH.gsub(/^ {12}/, "") /bin/ls: linux-vdso.so.1 => (0x00007fff583ff000) libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007fad8592a000) librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fad85722000) libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007fad85518000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fad8518d000) libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fad84f89000) /lib64/ld-linux-x86-64.so.2 (0x00007fad85b51000) libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fad84d6c000) libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007fad84b67000) /bin/cat: linux-vdso.so.1 => (0x00007fffa4dcf000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4a858cd000) /lib64/ld-linux-x86-64.so.2 (0x00007f4a85c5f000) EOH ) end let(:good_healthcheck) do double("Mixlib::Shellout", stdout: <<-EOH.gsub(/^ {12}/, "") /bin/echo: linux-vdso.so.1 => (0x00007fff8a6ee000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f70f58c0000) /lib64/ld-linux-x86-64.so.2 (0x00007f70f5c52000) /bin/cat: linux-vdso.so.1 => (0x00007fff095b3000) libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe868ec0000) /lib64/ld-linux-x86-64.so.2 (0x00007fe869252000) EOH ) end let(:regexp) { ".*(\\.TXT|\\.[ch]|\\.[ch]pp|\\.[eh]rl|\\.app|\\.appup|\\.bat|\\.beam|\\.cc|\\.cmake|\\.conf|\\.css|\\.e*rb|\\.feature|\\.gemspec|\\.gif|\\.gitignore|\\.gitkeep|\\.h*h|\\.jar|\\.java|\\.jpg|\\.js|\\.jsm|\\.json|\\.lock|\\.log|\\.lua|\\.md|\\.mkd|\\.npmignore|\\.out|\\.packlist|\\.perl|\\.pl|\\.pm|\\.png|\\.pod|\\.properties|\\.py[oc]*|\\.r*html|\\.rake|\\.rdoc|\\.ri|\\.rst|\\.scss|\\.sh|\\.sql|\\.svg|\\.toml|\\.ttf|\\.txt|\\.xml|\\.yml|Gemfile|LICENSE|Makefile|README|Rakefile|VERSION|license)$|.*\\/build_info\\/.*|.*\\/licenses\\/.*|.*\\/LICENSES\\/.*|.*\\/man\\/.*|.*\\/share\\/doc\\/.*|.*\\/share\\/info\\/.*|.*\\/share\\/postgresql\\/.*|.*\\/share\\/terminfo\\/.*|.*\\/share\\/timezone\\/.*|.*\\/terminfo\\/.*" } it "raises an exception when there are external dependencies" do allow(subject).to receive(:shellout) .with("find #{project.install_dir}/ -type f -regextype posix-extended ! -regex '#{regexp}' | xargs ldd") .and_return(bad_healthcheck) expect { subject.run! }.to raise_error(HealthCheckFailed) end it "does not raise an exception when the healthcheck passes" do allow(subject).to receive(:shellout) .with("find #{project.install_dir}/ -type f -regextype posix-extended ! -regex '#{regexp}' | xargs ldd") .and_return(good_healthcheck) expect { subject.run! }.to_not raise_error end it "will not perform dll base relocation checks" do expect(subject.relocation_checkable?).to be false end end end end