<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <filename>.gitignore</filename>
    </modified>
    <modified>
      <diff>@@ -1,5 +1,8 @@
 # -*- coding: utf-8 -*-
 
+2009-01-27  Cory ODaniel &lt;warningshot@coryodaniel.com&gt;
+	* PermissionResolver
+
 2009-01-26 	Cory ODaniel &lt;warningshot@coryodaniel.com&gt;
 	* Resolver.branch takes a *params now
 	* Added specs for Resolver.branch single &amp; multiple branches</diff>
      <filename>CHANGELOG</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,12 @@
 WarningShot Dependency Resolution Framework
  * Additional documentation @ http://github.com/coryodaniel/warningshot/wikis/
 
+==== Note on RSpecs
+	Currently the PermissionResolver RSpecs will probably fail that is because
+	I am not sure what the best way is to write them in regards to users &amp; groups
+	that may or may not be on a remote machine.  I wrote the specs, and they work on
+	my laptop (given that I have the groups/users) mentioned in the tests.
+	See: ./test/spec/unit/resolvers/permission_resolver_spec.rb
 
 ==== Installing WarningShot
   WarningShot installs a little differently than most gems.  WarningShot itself has NO gem dependencies.  Gems become</diff>
      <filename>README</filename>
    </modified>
    <modified>
      <filename>images/warning_shot_sml.png</filename>
    </modified>
    <modified>
      <filename>lib/core_ext/string.rb</filename>
    </modified>
    <modified>
      <diff>@@ -4,18 +4,21 @@ class WarningShot::DirectoryResolver
   branch      :directory
   
   description 'Validates presence of directories'
-      
-  DirectoryResource = Struct.new(:path)  
-  typecast do |path|
-    DirectoryResource.new File.expand_path(path)
+
+  DirectoryResource = Struct.new(:target)
+  typecast(String) do |target|
+    DirectoryResource.new File.expand_path(target)
+  end
+  typecast(Hash) do |yaml|
+    DirectoryResource.new File.expand_path(yaml[:target])
   end
   
   register :test do |dep|
-    dir_found = File.directory? dep.path
+    dir_found = File.directory? dep.target
     if dir_found
-      logger.debug &quot; ~ [PASSED] directory: #{dep.path}&quot;
+      logger.debug &quot; ~ [PASSED] directory: #{dep.target}&quot;
     else
-      logger.warn &quot; ~ [FAILED] directory: #{dep.path}&quot;
+      logger.warn &quot; ~ [FAILED] directory: #{dep.target}&quot;
     end
     
     dir_found
@@ -23,9 +26,9 @@ class WarningShot::DirectoryResolver
   
   register :resolution do |dep|
     begin
-      FileUtils.mkdir_p dep.path
+      FileUtils.mkdir_p dep.target
     rescue Exception =&gt; ex
-      logger.error &quot; ~ Could not create directory #{dep.path}&quot;
+      logger.error &quot; ~ Could not create directory #{dep.target}&quot;
     end
   end
 end
\ No newline at end of file</diff>
      <filename>lib/resolvers/directory_resolver.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,70 +1,195 @@
-
-# TODO Branch should take a params of branches, here: file, directory, symlink
-# TODO uid, gid should be integer or string (string for name, interger for id)
-# 
-
 class WarningShot::PermissionResolver
   include WarningShot::Resolver
-  order  100
-  branch :permission
+  add_dependency :core, 'etc'
+  add_dependency :core, 'fileutils'
+
+  order  1000
+  branch :directory, :file, :symlink
   description 'Validates mode, user, and group permission on files and directories'
-         
-  PermissionResource = Struct.new(:path,:target_mode,:target_user,:target_group,:recursive) do
+
+  PermissionResource = Struct.new(:target,:target_mode,:target_user,:target_group,:recursive,:no_follow) do
+    # Get File.stat by stat name
+    # param s [Symbol]
+    #   self.stat(:ftype) =&gt; File.stat(self.target).ftype
+    #
+    def stat(s)
+      #Read with links because WS will need to read the actual link if its set to no follow for symlinks
+      # For files, lstat still works for files
+      File.lstat(self.target).send(s)
+    rescue Exception =&gt; ex
+      nil
+    end
+
     def exists?
-      File.exist? self.path
+      File.exist? self.target
+    end
+
+    # @param type [Symbol]
+    #   Retreive the target's current user ID or Name (:id,:name)
+    #
+    def user(type=:name)
+      file_uid = self.stat(:uid)
+      (type == :name) ? Etc.getpwuid(file_uid).name : file_uid
+    end
+
+    # @param type [Symbol]
+    #   Retreive the targets's current group ID or Name (:id,:name)
+    #
+    def group(type=:name)
+      file_gid = self.stat(:gid)
+      (type == :name) ? Etc.getgrgid(file_gid).name : file_gid
+    end
+
+    # Retreive the target's current mode
+    #
+    def mode
+      &quot;%o&quot; % (self.stat(:mode) &amp; 007777)
+    end
+
+    #Attempt to change the user
+    def change_user!
+      tgt_uid = self.target_user.is_a?(Fixnum) ? self.target_user : Etc.getpwnam(self.target_user).uid
+      chown_params = [tgt_uid, nil, self.target]
+
+      if(File.symlink?(self.target) &amp;&amp; (self.no_follow == 'both' || self.no_follow == 'chown'))
+        File.lchown *chown_params
+      elsif(self.stat(:ftype) == 'directory' &amp;&amp; (self.recursive == 'both' || self.recursive == 'chown'))
+        FileUtils.chown_R *chown_params
+      else
+        File.chown *chown_params
+      end
+    rescue Exception =&gt; ex
+      WarningShot::PermissionResolver.logger.error(&quot;Unable to change user for file: #{self.target}; Exception: #{ex.message}&quot;)
+      return false
+    end
+
+    #Attempt to change the group
+    def change_group!
+      tgt_gid = self.target_group.is_a?(Fixnum) ? self.target_group : Etc.getgrnam(self.target_group).gid
+      chown_params = [nil, tgt_gid, self.target]
+
+      if(File.symlink?(self.target) &amp;&amp; (self.no_follow == 'both' || self.no_follow == 'chown'))
+        File.lchown *chown_params
+      elsif(self.stat(:ftype) == 'directory' &amp;&amp; (self.recursive == 'both' || self.recursive == 'chown'))
+        FileUtils.chown_R *chown_params
+      else
+        File.chown *chown_params
+      end
+    rescue Exception =&gt; ex
+      WarningShot::PermissionResolver.logger.error(&quot;Unable to change group for file: #{self.target}; Exception: #{ex.message}&quot;)
+      return false
     end
-    
-    def correct_owner!
-      false
+
+    #Attempt to change the mode
+    def change_mode!
+      chmod_params = [Integer(&quot;0&quot; + self.target_mode), self.target]
+
+      if(File.symlink?(self.target) &amp;&amp; (self.no_follow == 'both' || self.no_follow == 'chmod'))
+        File.lchmod *chmod_params
+      elsif(self.stat(:ftype) == 'directory' &amp;&amp; (self.recursive == 'both' || self.recursive == 'chmod'))
+        FileUtils.chmod_R *chmod_params
+      else
+        File.chmod *chmod_params
+      end
+    rescue Exception =&gt; ex
+      WarningShot::PermissionResolver.logger.error(&quot;Unable to change mode for file: #{self.target}; Exception: #{ex.message}&quot;)
+      return false
     end
-    
-    def correct_group!
-      false
+
+    #Are all permissions correct
+    def permissions_correct?
+      (self.exists? &amp; self.valid_user? &amp; self.valid_group? &amp; self.valid_mode?)
     end
-    
-    def correct_mode!
-      false
+
+    #Where permissions supplied by the dependency requirement
+    def permissions_supplied?
+      !!(self.target_mode || self.target_user || self.target_group)
     end
-    
-    def correct_owner?
-      false
+
+    # is the target's current user correct
+    def valid_user?
+      unless self.target_user.nil?
+        if self.target_user.is_a? String
+          !!(self.target_user == self.user)
+        else
+          !!(self.target_user == self.user(:id))
+        end
+      else
+        # The user is OK if it wasn't specified
+        return true
+      end
+    rescue ArgumentError =&gt; ex
+      # The user is NOT OK if the user doesn't exist
+      WarningShot::PermissionResolver.logger.error(&quot;User [#{self.target_user}] does not exist: #{ex.message}&quot;)
+      return false
     end
-    
-    def correct_group?
-      false
+
+    # is the target's current group correct
+    def valid_group?
+      unless self.target_group.nil?
+        if self.target_group.is_a? String
+          !!(self.target_group == self.group)
+        else
+          !!(self.target_group == self.group(:id))
+        end
+      else
+        # The group is OK if it wasn't specified
+        return true
+      end
+    rescue ArgumentError =&gt; ex
+      # The group is NOT OK if the group doesn't exist
+      WarningShot::PermissionResolver.logger.error(&quot;Group [#{self.target_group}] does not exist: #{ex.message}&quot;)
+      return false
     end
-    
-    def correct_mode?
-      false
+
+    # is the target's current mode correct
+    def valid_mode?
+      unless self.target_mode.nil?
+        !!(self.mode == self.target_mode)
+      else
+        return true
+      end
     end
   end
-  
+
   typecast Hash do |yaml|
-    PermissionResource.new  yaml.delete(:path), 
-                            yaml.delete(:mode)      || '0755',
-                            yaml.delete(:user)      || 'nobody',
-                            yaml.delete(:group)     || 'nobody',
-                            yaml.delete(:recursive) || 'none'
+    PermissionResource.new  File.expand_path(yaml[:target]),
+                            yaml[:mode],
+                            yaml[:user],
+                            yaml[:group],
+                            yaml[:recursive],
+                            yaml[:no_follow]
   end
-  
+
+  #Symlinks, directories and files are sometimes plain strings, these cant be resolved
+  # as far as permissions go, but should at least be cast properly
+  typecast(String){|target| PermissionResource.new File.expand_path(target), nil, nil, nil, nil, nil }
+
   register :test do |resource|
     _valid = resource.exists?
-    
-    if _valid
-      _valid &amp;= resource.correct_owner?
-      _valid &amp;= resource.correct_group?
-      _valid &amp;= resource.correct_mode?
-    end
-    
-    if _valid
-      logger.debug &quot; ~ [PASSED] permission: #{resource.path}&quot;
+
+    if _valid &amp;&amp; resource.permissions_supplied?
+      _valid &amp;= resource.valid_user?
+      _valid &amp;= resource.valid_group?
+      _valid &amp;= resource.valid_mode?
+
+      if _valid
+        logger.debug &quot; ~ [PASSED] permission: #{resource.target}&quot;
+      else
+        logger.warn &quot; ~ [FAILED] permission: #{resource.target}&quot;
+      end
     else
-      logger.warn &quot; ~ [FAILED] permission: #{resource.path}&quot;
+      logger.debug &quot; ~ [N/A] no permissions supplied: #{resource.target}&quot;
     end
-      
+
     _valid
   end
-  
+
   register :resolution do |resource|
+    resource.change_user! unless resource.valid_user?
+    resource.change_group! unless resource.valid_group?
+    resource.change_mode! unless resource.valid_mode?
+
+    resource.permissions_correct?
   end
 end
\ No newline at end of file</diff>
      <filename>lib/resolvers/permission_resolver.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,6 +1,3 @@
-# SHOUDL DETERMINE IF LINK EXISTS (File.stat().ftype == &quot;link&quot;)
-# and it points at proper file
-
 class WarningShot::SymlinkResolver
   include WarningShot::Resolver
   add_dependency :core, 'fileutils'</diff>
      <filename>lib/resolvers/symlink_resolver.rb</filename>
    </modified>
    <modified>
      <filename>lib/warningshot/growl.rb</filename>
    </modified>
    <modified>
      <filename>lib/warningshot/suite.rb</filename>
    </modified>
    <modified>
      <filename>more/ssh_resolver.rb</filename>
    </modified>
    <modified>
      <filename>more/ssh_resolver_spec.rb</filename>
    </modified>
    <modified>
      <filename>tasks/yard.rb</filename>
    </modified>
    <modified>
      <diff>@@ -9,10 +9,35 @@
 #       - /etc/nginx
 #       - /tmp
 #       - /mnt/media
+#       - {target: '/tmp/wherever'}
 #     :test: []
 #     :qa: []
 #     :production: []
 
+# The PermissionResolver piggybacks on the FileResolver, SymlinkResolver and DirectoryResolver.
+#  Each of the config files associated with those resolvers can include the following
+#  options in their hash to be parsed by the permission resolver.  So you will not generally have a 'permission.yml' file.
+#  Instead these options should be specified on a file in files.yml directories.yml or symlinks.yml
+
+# Each environt takes an array hashes
+# @param target [String] REQUIRED
+#     the path to check permissions
+#
+# @param mode [String] OPTIONAL;
+#     MOde of file 0777, 0755, etc
+#
+# @param user [String|Integer] OPTIONAL;
+#     User that should own resource (name or ID)
+#
+# @param group [STring|Integer] OPTIONAL;
+#     Group that should own resource (name or ID)
+#
+# @param recursive [String|nil] OPTIONAL; Default nil
+#     What methods should be recursvie: 'chmod','chown','both'
+#
+# You can additionally set permissions like:
+# - { target: &quot;/tmp/cool_directory&quot;, mode: &quot;777&quot;, user: &quot;www-data&quot;, group: &quot;www-data&quot;, recursive: &quot;both&quot;}
+
 ---
 :branch: directory
 :environments: </diff>
      <filename>templates/directories.yml</filename>
    </modified>
    <modified>
      <diff>@@ -8,6 +8,28 @@
 #      - /etc/nginx/nginx.conf
 #      - { target: &quot;./public/this.txt&quot;, source: &quot;http://example.com/index.html&quot;}
 #      - { target: &quot;file:///tmp/somefile.txt&quot;, source: &quot;~/.secret/file.txt&quot;}
+
+# The PermissionResolver piggybacks on the FileResolver, SymlinkResolver and DirectoryResolver.
+#  Each of the config files associated with those resolvers can include the following
+#  options in their hash to be parsed by the permission resolver.  So you will not generally have a 'permission.yml' file.
+#  Instead these options should be specified on a file in files.yml directories.yml or symlinks.yml
+
+# Each environt takes an array hashes
+# @param target [String] REQUIRED
+#     the path to check permissions
+#
+# @param mode [String] OPTIONAL;
+#     MOde of file 0777, 0755, etc
+#
+# @param user [String|Integer] OPTIONAL;
+#     User that should own resource (name or ID)
+#
+# @param group [STring|Integer] OPTIONAL;
+#     Group that should own resource (name or ID)
+#
+# You can additionally set permissions like:
+# - { target: &quot;file:///tmp/somefile.txt&quot;, source: &quot;~/.secret/file.txt&quot;, mode: &quot;777&quot;, user: &quot;www-data&quot;, group: &quot;www-data&quot;}
+
 ---
 - :branch: file
   :environments: </diff>
      <filename>templates/files.yml</filename>
    </modified>
    <modified>
      <diff>@@ -20,6 +20,30 @@
 # - { target: &quot;/super/symlink&quot;, source: &quot;/some/target/directory/&quot;}
 # - { target: &quot;/etc/my/awesome.conf&quot;, source: &quot;/etc/the/real.conf&quot;}
 
+# The PermissionResolver piggybacks on the FileResolver, SymlinkResolver and DirectoryResolver.
+#  Each of the config files associated with those resolvers can include the following
+#  options in their hash to be parsed by the permission resolver.  So you will not generally have a 'permission.yml' file.
+#  Instead these options should be specified on a file in files.yml directories.yml or symlinks.yml
+
+# Each environt takes an array hashes
+# @param target [String] REQUIRED
+#     the path to check permissions
+#
+# @param mode [String] OPTIONAL;
+#     MOde of file 0777, 0755, etc
+#
+# @param user [String|Integer] OPTIONAL;
+#     User that should own resource (name or ID)
+#
+# @param group [STring|Integer] OPTIONAL;
+#     Group that should own resource (name or ID)
+#
+# @param follow [String|nil] OPTIONAL; Default nil (doesnt follow)
+#     What methods should be recursvie: 'chmod','chown','both'
+#
+# You can additionally set permissions like:
+# - { target: &quot;/tmp/somefile.txt&quot;, source: &quot;~/my/link.txt&quot;, mode: &quot;777&quot;, user: &quot;www-data&quot;, group: &quot;www-data&quot;, follow: 'both'}
+
 ---
 :branch: symlink
 :environments: </diff>
      <filename>templates/symlinks.yml</filename>
    </modified>
    <modified>
      <filename>test/data/faux_test.yml</filename>
    </modified>
    <modified>
      <filename>test/data/faux_test_resolver.rb</filename>
    </modified>
    <modified>
      <diff>@@ -1,10 +1,75 @@
+#See TODO's below... (maybe the best bet it to take command line flags for User/Group names?)
+
+# Auto-generated ruby debug require
+require 'rubygems'
+require &quot;ruby-debug&quot;
+Debugger.start
+Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
+
 require '.' / 'lib' / 'resolvers' / 'permission_resolver'
 
 describe WarningShot::PermissionResolver do
   before :all do
+    #You can add additional groups to try here...
+    @group_names = ['everyone']
+
+    # Test if user can chown/chmod files to found group... if not nil out names...
+    @grp_chmod_test = File.expand_path($test_data / &quot;group_w_test.txt&quot;)
+    FileUtils.touch @grp_chmod_test
+
+    # Set the @test_group_* for the first group found
+    Etc.group {|grp|
+      if @group_names.member?(grp.name)
+        begin
+          if @test_group_name.nil? &amp;&amp; @test_group_id.nil?
+            @test_group_name  = grp.name
+            @test_group_id    = grp.gid
+            File.chown(nil,@test_group_id,@grp_chmod_test)
+          end
+        rescue Exception =&gt; ex
+          #Could chown group, keep looking...
+          @test_group_name = nil
+          @test_group_id   = nil
+        end
+      end
+    }
+
+    #Remove the chmod/chown test file
+    FileUtils.rm @grp_chmod_test
+
+    #Test file for changing permissions
+    @perm_test_file = File.expand_path($test_data / &quot;permission_test_#{Time.now.to_i}.txt&quot;)
+    File.open(@perm_test_file,&quot;w+&quot;) do |fs|
+      fs.puts &quot;This file is used for testing the PermissionResolver&quot;
+    end
+
+    #Test directory for recursive permissions
+    @perm_test_directory = File.expand_path($test_data / &quot;permission_test_dir_#{Time.now.to_i}&quot;)
+    @perm_test_directory_subdirectory = File.expand_path(@perm_test_directory / &quot;subdirectory&quot;)
+    FileUtils.mkdir_p @perm_test_directory_subdirectory
+
+    #Test link target for testing nofollow
+    @perm_test_link_tgt = File.expand_path($test_data / &quot;permission_test_link_tgt_#{Time.now.to_i}&quot;)
+    FileUtils.ln_s @perm_test_file, @perm_test_link_tgt
+
+    #Use the create file above to get the current processes User/Group info
+    @orig_user_uid = File.stat(@perm_test_file).uid
+    @orig_user_name = Etc.getpwuid(@orig_user_uid).name
+
+    @orig_group_gid = File.stat(@perm_test_file).gid
+    @orig_group_name = Etc.getgrgid(@orig_group_gid).name
+
+    @orig_mode  = File.stat(@perm_test_file).mode
+
     WarningShot::PermissionResolver.logger = $logger
   end
 
+  after :all do
+    FileUtils.rm @perm_test_file
+    FileUtils.rm_rf @perm_test_directory
+    FileUtils.rm @perm_test_link_tgt
+  end
+
   it 'should have tests registered' do
     WarningShot::PermissionResolver.tests.empty?.should be(false)
   end
@@ -12,45 +77,212 @@ describe WarningShot::PermissionResolver do
   it 'should have resolutions registered' do
     WarningShot::PermissionResolver.resolutions.empty?.should be(false)
   end
-  
-  it 'should be able to determine if the user permission is correct' do
-    _file   = $test_data / 'permission_test.txt'
-    _file2  = $test_data / 'permission_test.fake'
-    
-    resolver = WarningShot::PermissionResolver.new(WarningShot::Config.create,:file,{
-      :path =&gt; _file,       :mode   =&gt; '0755', 
-      :user =&gt; 'www-data',  :group  =&gt; 'www-data', 
-      :recursive =&gt; &quot;none&quot;
-    })
-    
-    resolver2 = WarningShot::PermissionResolver.new(WarningShot::Config.create,:file,{
-      :path =&gt; _file2,      :mode   =&gt; '0755', 
-      :user =&gt; 'www-data',  :group  =&gt; 'www-data', 
-      :recursive =&gt; &quot;none&quot;
-    })
-      
-    pending
-  end
-  
-  it 'should be able to determine if the group permission is correct' do
-    pending
-  end
-  
-  it 'should be able to determine if the mode is correct' do
-    pending
+
+  describe WarningShot::PermissionResolver::PermissionResource do
+    it 'should be able to determine if its user permission is correct' do
+
+      #Verify valid user by ID
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,@orig_user_uid,nil,nil)
+      pr.valid_user?.should be(true)
+
+      #Verify valid user by name
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,@orig_user_name,nil,nil)
+      pr.valid_user?.should be(true)
+
+      #Get a user that isn't the user that currently owns the file
+      test_user = Etc.passwd
+      if test_user.uid == @orig_user_uid
+        test_user = Etc.passwd
+      end
+
+      #Invalid user by ID
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,test_user.uid,nil,nil)
+      pr.valid_user?.should be(false)
+
+      #Invalid user by name
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,test_user.name,nil,nil)
+      pr.valid_user?.should be(false)
+    end
+
+    it 'should consider the user permission to be correct if not provided' do
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,nil,nil)
+      pr.valid_user?.should be(true)
+    end
+
+    it 'should consider the user permission to be incorrect if the user does not exist' do
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,&quot;randouser-#{Time.now.to_i}&quot;,nil,nil)
+      pr.valid_user?.should be(false)
+    end
+
+    it 'should be able to determine if its group permission is correct' do
+
+      #Verify valid group by ID
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,@orig_group_gid,nil)
+      pr.valid_group?.should be(true)
+
+      #Verify valid group by name
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,@orig_group_name,nil)
+      pr.valid_group?.should be(true)
+
+      #Get a group that isn't the group that currently owns the file
+      test_group = Etc.group
+      if test_group.gid == @orig_group_gid
+        test_group = Etc.group
+      end
+
+      #Invalid group by ID
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,test_group.gid,nil)
+      pr.valid_group?.should be(false)
+
+      #Invalid group by name
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,test_group.name,nil)
+      pr.valid_group?.should be(false)
+    end
+
+    it 'should consider the group permission to be correct if not provided' do
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,nil,nil)
+      pr.valid_group?.should be(true)
+    end
+
+    it 'should consider the group permission to be incorrect if the group does not exist' do
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,&quot;randogroup-#{Time.now.to_i}&quot;,nil)
+      pr.valid_group?.should be(false)
+    end
+
+    it 'should be able to determine if its mode is correct' do
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,'777',nil,nil,nil)
+      pr.valid_mode?.should be(false)
+
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,'644',nil,nil,nil)
+      pr.valid_mode?.should be(true)
+
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,'644',nil,nil,nil)
+      pr.valid_mode?.should be(true)
+    end
+
+    it 'should consider the mode to be correct if the mode is not provided' do
+      pr = WarningShot::PermissionResolver::PermissionResource.new(@perm_test_file,nil,nil,nil,nil)
+      pr.valid_mode?.should be(true)
+    end
   end
-  
+
   describe 'with healing enabled and with healing instructions' do
-    it 'should be able to correct the user' do
+    it 'should consider a dependency met if passed a string and the target exists' do
+      pr = WarningShot::PermissionResolver.new(WarningShot::Config.create, :file, @perm_test_file)
+      pr.test!
+      pr.passed.first.met.should be(true)
+    end
+
+    it 'should be able to correct the user by name' do
+      # TODO How do you test this w/o SUDO, or without knowing the names of users/groups on test machine
       pending
     end
-    
-    it 'should be able to correct the group' do
+    it 'should be able to correct the user by id' do
+       # TODO How do you test this w/o SUDO, or without knowing the names of users/groups on test machine
       pending
     end
-    
+
+    it 'should be able to correct the group by id' do
+      # Mark the spec as pending if it couldnt find a group to run this as
+      if @test_group_id
+        perm_file = {
+          :target =&gt; @perm_test_file,
+          :group  =&gt; @test_group_id
+        }
+
+        pr = WarningShot::PermissionResolver.new(WarningShot::Config.create, :file, perm_file)
+
+        pr.test!
+        pr.failed.length.should be(1)
+        pr.resolve!
+        pr.resolved.length.should be(1)
+
+        (File.stat(@perm_test_file).gid).should == @test_group_id
+
+        #give it back to original group
+        File.chown(nil,@orig_group_gid,@perm_test_file)
+      else
+        # TODO How do you test this w/o SUDO, or without knowing the names of users/groups on test machine
+        pending
+      end
+    end
+
+    it 'should be able to correct the group by name' do
+      # Mark the spec as pending if it couldnt find a group to run this as
+      if @test_group_name
+        perm_file = {
+          :target =&gt; @perm_test_file,
+          :group  =&gt; @test_group_name
+        }
+
+        pr = WarningShot::PermissionResolver.new(WarningShot::Config.create, :file, perm_file)
+
+        pr.test!
+        pr.failed.length.should be(1)
+
+        pr.resolve!
+        pr.resolved.length.should be(1)
+
+        Etc.getgrgid(File.stat(@perm_test_file).gid).name.should == @test_group_name
+
+        #Give it back to the original group
+        File.chown(nil,@orig_group_id,@perm_test_file)
+      else
+        # TODO How do you test this w/o SUDO, or without knowing the names of users/groups on test machine
+        pending
+      end
+    end
+
     it 'should be able to correct the mode' do
-      pending
+      perm_file = {
+        :target =&gt; @perm_test_file,
+        :mode =&gt; '777'
+      }
+      pr = WarningShot::PermissionResolver.new(WarningShot::Config.create, :file, perm_file)
+
+      pr.test!
+      pr.failed.length.should be(1)
+      pr.resolve!
+      pr.resolved.length.should be(1)
+
+      (&quot;%o&quot; % (File.stat(@perm_test_file).mode &amp; 007777)).to_i.should be(777)
+
+      #set the mode back
+      File.chmod(@orig_mode,@perm_test_file)
+    end
+
+    it 'should be able to correct permissions recursively for directories' do
+      perm_file = {
+        :target =&gt; @perm_test_directory,
+        :mode =&gt; '777',
+        :recursive =&gt; 'chmod'
+      }
+      pr = WarningShot::PermissionResolver.new(WarningShot::Config.create, :file, perm_file)
+
+      pr.test!
+      pr.failed.length.should be(1)
+      pr.resolve!
+      pr.resolved.length.should be(1)
+
+      (&quot;%o&quot; % (File.stat(@perm_test_directory).mode &amp; 007777)).to_i.should be(777)
+      (&quot;%o&quot; % (File.stat(@perm_test_directory_subdirectory).mode &amp; 007777)).to_i.should be(777)
+    end
+
+    it 'should be able to correct permissions on links and not targets (no follow)' do
+      perm_file = {
+        :target =&gt; @perm_test_link_tgt,
+        :mode =&gt; '777',
+        :no_follow =&gt; 'chmod'
+      }
+      pr = WarningShot::PermissionResolver.new(WarningShot::Config.create, :file, perm_file)
+
+      pr.test!
+      pr.failed.length.should be(1)
+      pr.resolve!
+      pr.resolved.length.should be(1)
+
+      File.stat(@perm_test_file).mode.should == @orig_mode
+      (&quot;%o&quot; % (File.lstat(@perm_test_link_tgt).mode &amp; 007777)).to_i.should be(777)
     end
   end
 end
\ No newline at end of file</diff>
      <filename>test/spec/unit/resolvers/permission_resolver_spec.rb</filename>
    </modified>
    <modified>
      <filename>warningshot.gemspec</filename>
    </modified>
    <modified>
      <filename>yardoc_template.txt</filename>
    </modified>
  </modified>
  <removed type="array">
    <removed>
      <filename>templates/permissions.yml</filename>
    </removed>
    <removed>
      <filename>test/data/permission_test.txt</filename>
    </removed>
  </removed>
  <parents type="array">
    <parent>
      <id>f95810417d2109d8e0a086e33e25acd779c390a7</id>
    </parent>
  </parents>
  <author>
    <name>Cory ODaniel</name>
    <email>contact@coryodaniel.com</email>
  </author>
  <url>http://github.com/coryodaniel/warningshot/commit/f439654326b36b9b9f06b88fc72a2e0323e449f8</url>
  <id>f439654326b36b9b9f06b88fc72a2e0323e449f8</id>
  <committed-date>2009-01-27T21:00:25-08:00</committed-date>
  <authored-date>2009-01-27T21:00:25-08:00</authored-date>
  <message>Permission Resolver complete, note the notes on retarded rpsec testing since
chmod/chown are sensitive commands...</message>
  <tree>1a601cb29e50a688d5e326702206f491801e22a1</tree>
  <committer>
    <name>Cory ODaniel</name>
    <email>contact@coryodaniel.com</email>
  </committer>
</commit>
