diff options
author | Tim Smith <tsmith@chef.io> | 2019-02-19 11:20:40 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2019-02-19 11:20:40 -0800 |
commit | cff8859fc35c6799f01c4593ce37c1b3a3dc1973 (patch) | |
tree | e08f9a8cb57bd31ef651fd1f9d17f0b14169dce2 | |
parent | c4c8e947260a4370594b04de395689d98db6380e (diff) | |
parent | 8417c6ad5f3ea05cc6f3a4b6ba970ca4d3adef54 (diff) | |
download | chef-cff8859fc35c6799f01c4593ce37c1b3a3dc1973.tar.gz |
Merge pull request #8228 from chef/user_cleanup
Cleanup the user resource and convert it to the resource DSL + delete user_add provider
-rw-r--r-- | lib/chef/provider/user/dscl.rb | 3 | ||||
-rw-r--r-- | lib/chef/provider/user/useradd.rb | 161 | ||||
-rw-r--r-- | lib/chef/provider/user/windows.rb | 6 | ||||
-rw-r--r-- | lib/chef/resource/user.rb | 170 | ||||
-rw-r--r-- | lib/chef/resource/user/dscl_user.rb | 4 | ||||
-rw-r--r-- | spec/unit/provider/user/dscl_spec.rb | 41 | ||||
-rw-r--r-- | spec/unit/provider/user/linux_spec.rb | 1 | ||||
-rw-r--r-- | spec/unit/provider/user_spec.rb | 48 | ||||
-rw-r--r-- | spec/unit/resource/user_spec.rb | 43 |
9 files changed, 115 insertions, 362 deletions
diff --git a/lib/chef/provider/user/dscl.rb b/lib/chef/provider/user/dscl.rb index 4da6465bd6..12be6ffb7e 100644 --- a/lib/chef/provider/user/dscl.rb +++ b/lib/chef/provider/user/dscl.rb @@ -18,6 +18,7 @@ require "chef/mixin/shell_out" require "chef/provider/user" +require "chef/resource/user/dscl_user" require "openssl" require "plist" require "chef/util/path_helper" @@ -99,7 +100,7 @@ in 'password', with the associated 'salt' and 'iterations'.") end def load_current_resource - @current_resource = Chef::Resource::User.new(new_resource.username) + @current_resource = Chef::Resource::User::DsclUser.new(new_resource.username) current_resource.username(new_resource.username) @user_info = read_user_info diff --git a/lib/chef/provider/user/useradd.rb b/lib/chef/provider/user/useradd.rb deleted file mode 100644 index 855da325a0..0000000000 --- a/lib/chef/provider/user/useradd.rb +++ /dev/null @@ -1,161 +0,0 @@ -# -# Author:: Adam Jacob (<adam@chef.io>) -# Copyright:: Copyright 2008-2018, Chef Software Inc. -# License:: Apache License, Version 2.0 -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -require "pathname" -require "chef/provider/user" - -class Chef - class Provider - class User - class Useradd < Chef::Provider::User - - Chef::Log.warn("the Chef::Provider::User::Useradd provider is deprecated, please subclass Chef::Provider::User directly") - - # the linux version of this has been forked off, this is the base class now of solaris and AIX and should be abandoned - # and those provider should be rewritten like the linux version. - - UNIVERSAL_OPTIONS = [[:comment, "-c"], [:gid, "-g"], [:password, "-p"], [:shell, "-s"], [:uid, "-u"]].freeze - - def create_user - command = compile_command("useradd") do |useradd| - useradd.concat(universal_options) - useradd.concat(useradd_options) - end - shell_out!(command) - end - - def manage_user - return if universal_options.empty? - command = compile_command("usermod") do |u| - u.concat(universal_options) - end - shell_out!(command) - end - - def remove_user - command = [ "userdel" ] - command << "-r" if new_resource.manage_home - command << "-f" if new_resource.force - command << new_resource.username - shell_out!(command) - end - - def check_lock - # we can get an exit code of 1 even when it's successful on - # rhel/centos (redhat bug 578534). See additional error checks below. - passwd_s = shell_out!("passwd", "-S", new_resource.username, returns: [0, 1]) - if whyrun_mode? && passwd_s.stdout.empty? && passwd_s.stderr.match(/does not exist/) - # if we're in whyrun mode and the user is not yet created we assume it would be - return false - end - - raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if passwd_s.stdout.empty? - - status_line = passwd_s.stdout.split(" ") - case status_line[1] - when /^P/ - @locked = false - when /^N/ - @locked = false - when /^L/ - @locked = true - end - - unless passwd_s.exitstatus == 0 - raise_lock_error = false - if %w{redhat centos}.include?(node[:platform]) - passwd_version_check = shell_out!("rpm", "-q", "passwd") - passwd_version = passwd_version_check.stdout.chomp - - unless passwd_version == "passwd-0.73-1" - raise_lock_error = true - end - else - raise_lock_error = true - end - - raise Chef::Exceptions::User, "Cannot determine if #{new_resource} is locked!" if raise_lock_error - end - - @locked - end - - def lock_user - shell_out!("usermod", "-L", new_resource.username) - end - - def unlock_user - shell_out!("usermod", "-U", new_resource.username) - end - - def compile_command(base_command) - base_command = Array(base_command) - yield base_command - base_command << new_resource.username - base_command - end - - def universal_options - @universal_options ||= - begin - opts = [] - # magic allows UNIVERSAL_OPTIONS to be overridden in a subclass - self.class::UNIVERSAL_OPTIONS.each do |field, option| - update_options(field, option, opts) - end - if updating_home? - opts << "-d" << new_resource.home - if new_resource.manage_home - logger.trace("#{new_resource} managing the users home directory") - opts << "-m" - else - logger.trace("#{new_resource} setting home to #{new_resource.home}") - end - end - opts << "-o" if new_resource.non_unique - opts - end - end - - def update_options(field, option, opts) - return unless current_resource.send(field).to_s != new_resource.send(field).to_s - return unless new_resource.send(field) - logger.trace("#{new_resource} setting #{field} to #{new_resource.send(field)}") - opts << option << new_resource.send(field).to_s - end - - def useradd_options - opts = [] - opts << "-r" if new_resource.system - opts << "-M" unless new_resource.manage_home - opts - end - - def updating_home? - # will return false if paths are equivalent - # Pathname#cleanpath does a better job than ::File::expand_path (on both unix and windows) - # ::File.expand_path("///tmp") == ::File.expand_path("/tmp") => false - # ::File.expand_path("\\tmp") => "C:/tmp" - return true if current_resource.home.nil? && new_resource.home - new_resource.home && Pathname.new(current_resource.home).cleanpath != Pathname.new(new_resource.home).cleanpath - end - - end - end - end -end diff --git a/lib/chef/provider/user/windows.rb b/lib/chef/provider/user/windows.rb index f393b81919..6cb9cbdb19 100644 --- a/lib/chef/provider/user/windows.rb +++ b/lib/chef/provider/user/windows.rb @@ -1,6 +1,6 @@ # # Author:: Doug MacEachern (<dougm@vmware.com>) -# Copyright:: Copyright 2010-2016, VMware, Inc. +# Copyright:: Copyright 2010-2019, VMware, Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,9 +18,7 @@ require "chef/provider/user" require "chef/exceptions" -if RUBY_PLATFORM =~ /mswin|mingw32|windows/ - require "chef/util/windows/net_user" -end +require "chef/util/windows/net_user" if Chef::Platform.windows? class Chef class Provider diff --git a/lib/chef/resource/user.rb b/lib/chef/resource/user.rb index df52ebb083..bef1f5f620 100644 --- a/lib/chef/resource/user.rb +++ b/lib/chef/resource/user.rb @@ -1,6 +1,6 @@ # # Author:: Adam Jacob (<adam@chef.io>) -# Copyright:: Copyright 2008-2017, Chef Software Inc. +# Copyright:: Copyright 2008-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,140 +20,58 @@ require "chef/resource" class Chef class Resource - # Use the user resource to add users, update existing users, remove users, and to lock/unlock user passwords. class User < Chef::Resource resource_name :user_resource_abstract_base_class # this prevents magickal class name DSL wiring - identity_attr :username - state_attrs :uid, :gid, :home + description "Use the user resource to add users, update existing users, remove users, and to lock/unlock user passwords." default_action :create allowed_actions :create, :remove, :modify, :manage, :lock, :unlock - def initialize(name, run_context = nil) - super - @username = name - @comment = nil - @uid = nil - @gid = nil - @home = nil - @shell = nil - @password = nil - @system = false - @manage_home = false - @force = false - @non_unique = false - @iterations = 27855 - @salt = nil - end - - def username(arg = nil) - set_or_return( - :username, - arg, - kind_of: [ String ] - ) - end - - def comment(arg = nil) - set_or_return( - :comment, - arg, - kind_of: [ String ] - ) - end - - def uid(arg = Chef::NOT_PASSED) - set_or_return( - :uid, - arg, - kind_of: [ String, Integer, NilClass ], - coerce: proc { |x| x || nil } - ) - end - - def gid(arg = Chef::NOT_PASSED) - set_or_return( - :gid, - arg, - kind_of: [ String, Integer, NilClass ], - coerce: proc { |x| x || nil } - ) - end + property :username, String, + description: "An optional property to set the username value if it differs from the resource block's name.", + name_property: true, identity: true - alias_method :group, :gid + property :comment, String, + description: "The contents of the user comments field." + + property :home, String, + description: "The location of the home directory." + + property :salt, String, + description: "A SALTED-SHA512-PBKDF2 hash.", + desired_state: false + + property :shell, String, + description: "The login shell." + + property :password, String, + description: "The password shadow hash", + desired_state: false + + property :non_unique, [ TrueClass, FalseClass ], + description: "Create a duplicate (non-unique) user account.", + default: false, desired_state: false - def home(arg = nil) - set_or_return( - :home, - arg, - kind_of: [ String ] - ) - end - - def shell(arg = nil) - set_or_return( - :shell, - arg, - kind_of: [ String ] - ) - end - - def password(arg = nil) - set_or_return( - :password, - arg, - kind_of: [ String ] - ) - end - - def salt(arg = nil) - set_or_return( - :salt, - arg, - kind_of: [ String ] - ) - end - - def iterations(arg = nil) - set_or_return( - :iterations, - arg, - kind_of: [ Integer ] - ) - end - - def system(arg = nil) - set_or_return( - :system, - arg, - kind_of: [ TrueClass, FalseClass ] - ) - end - - def manage_home(arg = nil) - set_or_return( - :manage_home, - arg, - kind_of: [ TrueClass, FalseClass ] - ) - end - - def force(arg = nil) - set_or_return( - :force, - arg, - kind_of: [ TrueClass, FalseClass ] - ) - end - - def non_unique(arg = nil) - set_or_return( - :non_unique, - arg, - kind_of: [ TrueClass, FalseClass ] - ) - end + property :manage_home, [ TrueClass, FalseClass ], + description: "Manage a user’s home directory.\nWhen used with the :create action, a user’s home directory is created based on HOME_DIR. If the home directory is missing, it is created unless CREATE_HOME in /etc/login.defs is set to no. When created, a skeleton set of files and subdirectories are included within the home directory.\nWhen used with the :modify action, a user’s home directory is moved to HOME_DIR. If the home directory is missing, it is created unless CREATE_HOME in /etc/login.defs is set to no. The contents of the user’s home directory are moved to the new location.", + default: false, desired_state: false + + property :force, [ TrueClass, FalseClass ], + description: "Force the removal of a user. May be used only with the :remove action.", + default: false, desired_state: false + + property :system, [ TrueClass, FalseClass ], + description: "Create a system user. This property may be used with useradd as the provider to create a system user which passes the -r flag to useradd.", + default: false + + property :uid, [ String, Integer, NilClass ], # nil for backwards compat + description: "The numeric user identifier." + + property :gid, [ String, Integer, NilClass ], # nil for backwards compat + description: "The numeric group identifier." + + alias_method :group, :gid end end end diff --git a/lib/chef/resource/user/dscl_user.rb b/lib/chef/resource/user/dscl_user.rb index 6eb1c953f4..0afc504c1d 100644 --- a/lib/chef/resource/user/dscl_user.rb +++ b/lib/chef/resource/user/dscl_user.rb @@ -25,6 +25,10 @@ class Chef provides :dscl_user provides :user, os: "darwin" + + property :iterations, Integer, + description: "macOS platform only. The number of iterations for a password with a SALTED-SHA512-PBKDF2 shadow hash.", + default: 27855, desired_state: false end end end diff --git a/spec/unit/provider/user/dscl_spec.rb b/spec/unit/provider/user/dscl_spec.rb index 2c3e5d59af..b12ea78977 100644 --- a/spec/unit/provider/user/dscl_spec.rb +++ b/spec/unit/provider/user/dscl_spec.rb @@ -23,25 +23,25 @@ describe Chef::Provider::User::Dscl do before do allow(ChefConfig).to receive(:windows?) { false } end - let(:shellcmdresult) do - Struct.new(:stdout, :stderr, :exitstatus) - end - let(:node) do - node = Chef::Node.new - allow(node).to receive(:[]).with(:platform).and_return("mac_os_x") - node - end - let(:events) do - Chef::EventDispatch::Dispatcher.new - end + let(:shellcmdresult) { Struct.new(:stdout, :stderr, :exitstatus) } + + let(:password) { nil } + let(:salt) { nil } + let(:iterations) { nil } + + let (:events) { Chef::EventDispatch::Dispatcher.new } - let(:run_context) do - Chef::RunContext.new(node, {}, events) + let(:node) do + Chef::Node.new.tap do |node| + node.automatic["os"] = "darwin" + end end + let (:run_context) { Chef::RunContext.new(node, {}, events) } + let(:new_resource) do - r = Chef::Resource::User::DsclUser.new("toor") + r = Chef::Resource::User::DsclUser.new("toor", run_context) r.password(password) r.salt(salt) r.iterations(iterations) @@ -52,10 +52,6 @@ describe Chef::Provider::User::Dscl do Chef::Provider::User::Dscl.new(new_resource, run_context) end - let(:password) { nil } - let(:salt) { nil } - let(:iterations) { nil } - let(:salted_sha512_password) do "0f543f021c63255e64e121a3585601b8ecfedf6d2\ 705ddac69e682a33db5dbcdb9b56a2520bc8fff63a\ @@ -144,17 +140,17 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30" expect(provider).to receive(:run_dscl).with("list", "/Users", "uid").and_return("\nwheel 200\nstaff 201\nbrahms 500\nchopin 501\n") end - describe "when resource is configured as system" do + describe "when the system property is set to true" do before do new_resource.system(true) end - it "should return the first unused uid number on or above 500" do + it "should return the first unused uid number on or above 200" do expect(provider.get_free_uid).to eq(202) end end - it "should return the first unused uid number on or above 200" do + it "should return the first unused uid number on or above 500" do expect(provider.get_free_uid).to eq(502) end @@ -564,9 +560,8 @@ ea18e18b720e358e7fbe3cfbeaa561456f6ba008937a30" it "sets the comment field to username" do new_resource.comment nil - expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "RealName", "#mockssuck").and_return(true) + expect(provider).to receive(:run_dscl).with("create", "/Users/toor", "RealName", "toor").and_return(true) provider.dscl_create_comment - expect(new_resource.comment).to eq("#mockssuck") end it "should run run_dscl with create /Users/user PrimaryGroupID to set the users primary group" do diff --git a/spec/unit/provider/user/linux_spec.rb b/spec/unit/provider/user/linux_spec.rb index 5092c8f4b9..9793382574 100644 --- a/spec/unit/provider/user/linux_spec.rb +++ b/spec/unit/provider/user/linux_spec.rb @@ -19,7 +19,6 @@ # require "spec_helper" -require "chef/provider/user/useradd" describe Chef::Provider::User::Linux do diff --git a/spec/unit/provider/user_spec.rb b/spec/unit/provider/user_spec.rb index 7a07527834..ddfe9e6c86 100644 --- a/spec/unit/provider/user_spec.rb +++ b/spec/unit/provider/user_spec.rb @@ -1,6 +1,6 @@ # # Author:: Adam Jacob (<adam@chef.io>) -# Copyright:: Copyright 2008-2016, Chef Software Inc. +# Copyright:: Copyright 2008-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -27,18 +27,18 @@ describe Chef::Provider::User do @events = Chef::EventDispatch::Dispatcher.new @run_context = Chef::RunContext.new(@node, {}, @events) - @new_resource = Chef::Resource::User.new("adam") - @new_resource.comment "Adam Jacob" + @new_resource = Chef::Resource::User.new("notarealuser") + @new_resource.comment "Nota Realuser" @new_resource.uid 1000 @new_resource.gid 1000 - @new_resource.home "/home/adam" + @new_resource.home "/home/notarealuser" @new_resource.shell "/usr/bin/zsh" - @current_resource = Chef::Resource::User.new("adam") - @current_resource.comment "Adam Jacob" + @current_resource = Chef::Resource::User.new("notarealuser") + @current_resource.comment "Nota Realuser" @current_resource.uid 1000 @current_resource.gid 1000 - @current_resource.home "/home/adam" + @current_resource.home "/home/notarealuser" @current_resource.shell "/usr/bin/zsh" @provider = Chef::Provider::User.new(@new_resource, @run_context) @@ -60,22 +60,22 @@ describe Chef::Provider::User do @node = Chef::Node.new # @new_resource = double("Chef::Resource::User", # :null_object => true, - # :username => "adam", - # :comment => "Adam Jacob", + # :username => "notarealuser", + # :comment => "Nota Realuser", # :uid => 1000, # :gid => 1000, - # :home => "/home/adam", + # :home => "/home/notarealuser", # :shell => "/usr/bin/zsh", # :password => nil, # :updated => nil # ) allow(Chef::Resource::User).to receive(:new).and_return(@current_resource) @pw_user = EtcPwnamIsh.new - @pw_user.name = "adam" + @pw_user.name = "notarealuser" @pw_user.gid = 1000 @pw_user.uid = 1000 - @pw_user.gecos = "Adam Jacob" - @pw_user.dir = "/home/adam" + @pw_user.gecos = "Nota Realuser" + @pw_user.dir = "/home/notarealuser" @pw_user.shell = "/usr/bin/zsh" @pw_user.passwd = "*" allow(Etc).to receive(:getpwnam).and_return(@pw_user) @@ -83,7 +83,7 @@ describe Chef::Provider::User do it "should create a current resource with the same name as the new resource" do @provider.load_current_resource - expect(@provider.current_resource.name).to eq("adam") + expect(@provider.current_resource.name).to eq("notarealuser") end it "should set the username of the current resource to the username of the new resource" do @@ -129,7 +129,7 @@ describe Chef::Provider::User do end it "shouldn't try and convert the group gid if none has been supplied" do - @new_resource.gid(false) + @new_resource.gid(nil) expect(@provider).not_to receive(:convert_group_name) @provider.load_current_resource end @@ -168,7 +168,7 @@ describe Chef::Provider::User do expect(@provider).to receive(:require) { |*args| original_method.call(*args) } passwd_info = Struct::PasswdEntry.new(sp_namp: "adm ", sp_pwdp: "$1$T0N0Q.lc$nyG6pFI3Dpqa5cxUz/57j0", sp_lstchg: 14861, sp_min: 0, sp_max: 99999, sp_warn: 7, sp_inact: -1, sp_expire: -1, sp_flag: -1) - expect(Shadow::Passwd).to receive(:getspnam).with("adam").and_return(passwd_info) + expect(Shadow::Passwd).to receive(:getspnam).with("notarealuser").and_return(passwd_info) @provider.load_current_resource @provider.define_resource_requirements @provider.process_resource_requirements @@ -190,11 +190,11 @@ describe Chef::Provider::User do describe "compare_user" do let(:mapping) do { - "username" => %w{adam Adam}, - "comment" => ["Adam Jacob", "adam jacob"], + "username" => %w{notarealuser notarealuser}, + "comment" => ["Nota Realuser", "Not a Realuser"], "uid" => [1000, 1001], "gid" => [1000, 1001], - "home" => ["/home/adam", "/Users/adam"], + "home" => ["/home/notarealuser", "/Users/notarealuser"], "shell" => ["/usr/bin/zsh", "/bin/bash"], "password" => %w{abcd 12345}, } @@ -221,8 +221,8 @@ describe Chef::Provider::User do end it "should ignore differences in trailing slash in home paths" do - @new_resource.home "/home/adam" - @current_resource.home "/home/adam/" + @new_resource.home "/home/notarealuser" + @current_resource.home "/home/notarealuser/" expect(@provider.compare_user).to eql(false) end end @@ -232,11 +232,11 @@ describe Chef::Provider::User do allow(@provider).to receive(:load_current_resource) # @current_resource = double("Chef::Resource::User", # :null_object => true, - # :username => "adam", - # :comment => "Adam Jacob", + # :username => "notarealuser", + # :comment => "Nota Realuser", # :uid => 1000, # :gid => 1000, - # :home => "/home/adam", + # :home => "/home/notarealuser", # :shell => "/usr/bin/zsh", # :password => nil, # :updated => nil diff --git a/spec/unit/resource/user_spec.rb b/spec/unit/resource/user_spec.rb index 2a96c5328d..08d1636643 100644 --- a/spec/unit/resource/user_spec.rb +++ b/spec/unit/resource/user_spec.rb @@ -1,6 +1,6 @@ # # Author:: Adam Jacob (<adam@chef.io>) -# Copyright:: Copyright 2008-2017, Chef Software Inc. +# Copyright:: Copyright 2008-2019, Chef Software Inc. # License:: Apache License, Version 2.0 # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,19 +19,19 @@ require "spec_helper" describe Chef::Resource::User, "initialize" do - let(:resource) { Chef::Resource::User.new("adam") } + let(:resource) { Chef::Resource::User.new("notarealuser") } - it "sets the resource_name to :user" do + it "sets the resource_name to :user_resource_abstract_base_class" do expect(resource.resource_name).to eql(:user_resource_abstract_base_class) end - it "sets the username equal to the argument to initialize" do - expect(resource.username).to eql("adam") + it "username property is the name property" do + expect(resource.username).to eql("notarealuser") end - %w{comment uid gid home shell password}.each do |attrib| - it "sets #{attrib} to nil" do - expect(resource.send(attrib)).to eql(nil) + %w{comment uid gid home shell password}.each do |prop| + it "sets #{prop} to nil" do + expect(resource.send(prop)).to eql(nil) end end @@ -39,16 +39,10 @@ describe Chef::Resource::User, "initialize" do expect(resource.action).to eql([:create]) end - it "sets manage_home to false" do - expect(resource.manage_home).to eql(false) - end - - it "sets non_unique to false" do - expect(resource.non_unique).to eql(false) - end - - it "sets force to false" do - expect(resource.force).to eql(false) + %w{manage_home non_unique force system}.each do |prop| + it "sets #{prop} to false" do + expect(resource.send(prop)).to eql(false) + end end %w{create remove modify manage lock unlock}.each do |action| @@ -57,6 +51,11 @@ describe Chef::Resource::User, "initialize" do end end + it "group is an alias for the gid property" do + resource.group(1234) + expect(resource.gid).to eql(1234) + end + it "accepts domain users (@ or \ separator) on non-windows" do expect { resource.username "domain\@user" }.not_to raise_error expect(resource.username).to eq("domain\@user") @@ -67,11 +66,11 @@ end %w{username comment home shell password}.each do |attrib| describe Chef::Resource::User, attrib do - let(:resource) { Chef::Resource::User.new("adam") } + let(:resource) { Chef::Resource::User.new("notarealuser") } it "allows a string" do - resource.send(attrib, "adam") - expect(resource.send(attrib)).to eql("adam") + resource.send(attrib, "something") + expect(resource.send(attrib)).to eql("something") end it "does not allow a hash" do @@ -82,7 +81,7 @@ end %w{uid gid}.each do |attrib| describe Chef::Resource::User, attrib do - let(:resource) { Chef::Resource::User.new("adam") } + let(:resource) { Chef::Resource::User.new("notarealuser") } it "allows a string" do resource.send(attrib, "100") |