require 'spec_helper' require 'puppet/util/symbolic_file_mode' describe Puppet::Util::SymbolicFileMode do include Puppet::Util::SymbolicFileMode describe "#valid_symbolic_mode?" do %w{ 0 0000 1 1 7 11 77 111 777 11 0 00000 01 01 07 011 077 0111 0777 011 = - + u= g= o= a= u+ g+ o+ a+ u- g- o- a- ugo= ugoa= ugugug= a=,u=,g= a=,g+ =rwx +rwx -rwx 644 go-w =rw,+X +X 755 u=rwx,go=rx u=rwx,go=u-w go= g=u-w 755 0755 }.each do |input| it "should treat #{input.inspect} as valid" do expect(valid_symbolic_mode?(input)).to be_truthy end end [0000, 0111, 0640, 0755, 0777].each do |input| it "should treat the int #{input.to_s(8)} as value" do expect(valid_symbolic_mode?(input)).to be_truthy end end %w{ -1 -8 8 9 18 19 91 81 000000 11111 77777 0-1 0-8 08 09 018 019 091 081 0000000 011111 077777 u g o a ug uo ua ag }.each do |input| it "should treat #{input.inspect} as invalid" do expect(valid_symbolic_mode?(input)).to be_falsey end end end describe "#normalize_symbolic_mode" do it "should turn an int into a string" do expect(normalize_symbolic_mode(12)).to be_an_instance_of String end it "should not add a leading zero to an int" do expect(normalize_symbolic_mode(12)).not_to match(/^0/) end it "should not add a leading zero to a string with a number" do expect(normalize_symbolic_mode("12")).not_to match(/^0/) end it "should string a leading zero from a number" do expect(normalize_symbolic_mode("012")).to eq('12') end it "should pass through any other string" do expect(normalize_symbolic_mode("u=rwx")).to eq('u=rwx') end end describe "#symbolic_mode_to_int" do { "0654" => 00654, "u+r" => 00400, "g+r" => 00040, "a+r" => 00444, "a+x" => 00111, "o+t" => 01000, ["o-t", 07777] => 06777, ["a-x", 07777] => 07666, ["a-rwx", 07777] => 07000, ["ug-rwx", 07777] => 07007, "a+x,ug-rwx" => 00001, # My experimentation on debian suggests that +g ignores the sgid flag ["a+g", 02060] => 02666, # My experimentation on debian suggests that -g ignores the sgid flag ["a-g", 02666] => 02000, "g+x,a+g" => 00111, # +X without exec set in the original should not set anything "u+x,g+X" => 00100, "g+X" => 00000, # +X only refers to the original, *unmodified* file mode! ["u+x,a+X", 0600] => 00700, # Examples from the MacOS chmod(1) manpage "0644" => 00644, ["go-w", 07777] => 07755, ["=rw,+X", 07777] => 07777, ["=rw,+X", 07766] => 07777, ["=rw,+X", 07676] => 07777, ["=rw,+X", 07667] => 07777, ["=rw,+X", 07666] => 07666, "0755" => 00755, "u=rwx,go=rx" => 00755, "u=rwx,go=u-w" => 00755, ["go=", 07777] => 07700, ["g=u-w", 07777] => 07757, ["g=u-w", 00700] => 00750, ["g=u-w", 00600] => 00640, ["g=u-w", 00500] => 00550, ["g=u-w", 00400] => 00440, ["g=u-w", 00300] => 00310, ["g=u-w", 00200] => 00200, ["g=u-w", 00100] => 00110, ["g=u-w", 00000] => 00000, # Cruel, but legal, use of the action set. ["g=u+r-w", 0300] => 00350, # Empty assignments. ["u=", 00000] => 00000, ["u=", 00600] => 00000, ["ug=", 00000] => 00000, ["ug=", 00600] => 00000, ["ug=", 00660] => 00000, ["ug=", 00666] => 00006, ["=", 00000] => 00000, ["=", 00666] => 00000, ["+", 00000] => 00000, ["+", 00124] => 00124, ["-", 00000] => 00000, ["-", 00124] => 00124, }.each do |input, result| from = input.is_a?(Array) ? "#{input[0]}, 0#{input[1].to_s(8)}" : input it "should map #{from.inspect} to #{result.inspect}" do expect(symbolic_mode_to_int(*input)).to eq(result) end end # Now, test some failure modes. it "should fail if no mode is given" do expect { symbolic_mode_to_int('') }. to raise_error Puppet::Error, /empty mode string/ end %w{u g o ug uo go ugo a uu u/x u!x u=r,,g=r}.each do |input| it "should fail if no (valid) action is given: #{input.inspect}" do expect { symbolic_mode_to_int(input) }. to raise_error Puppet::Error, /Missing action/ end end %w{u+q u-rwF u+rw,g+rw,o+RW}.each do |input| it "should fail with unknown op #{input.inspect}" do expect { symbolic_mode_to_int(input) }. to raise_error Puppet::Error, /Unknown operation/ end end it "should refuse to subtract the conditional execute op" do expect { symbolic_mode_to_int("o-rwX") }. to raise_error Puppet::Error, /only works with/ end it "should refuse to set to the conditional execute op" do expect { symbolic_mode_to_int("o=rwX") }. to raise_error Puppet::Error, /only works with/ end %w{8 08 9 09 118 119}.each do |input| it "should fail for decimal modes: #{input.inspect}" do expect { symbolic_mode_to_int(input) }. to raise_error Puppet::Error, /octal/ end end it "should set the execute bit on a directory, without exec in original" do expect(symbolic_mode_to_int("u+X", 0444, true).to_s(8)).to eq("544") expect(symbolic_mode_to_int("g+X", 0444, true).to_s(8)).to eq("454") expect(symbolic_mode_to_int("o+X", 0444, true).to_s(8)).to eq("445") expect(symbolic_mode_to_int("+X", 0444, true).to_s(8)).to eq("555") end it "should set the execute bit on a file with exec in the original" do expect(symbolic_mode_to_int("+X", 0544).to_s(8)).to eq("555") end it "should not set the execute bit on a file without exec on the original even if set by earlier DSL" do expect(symbolic_mode_to_int("u+x,go+X", 0444).to_s(8)).to eq("544") end end end