diff options
27 files changed, 99 insertions, 19 deletions
diff --git a/.expeditor/config.yml b/.expeditor/config.yml index 5a6d9a57ac..55a74e04f2 100644 --- a/.expeditor/config.yml +++ b/.expeditor/config.yml @@ -143,3 +143,6 @@ subscriptions: - workload: ruby_gem_published:cheffish-* actions: - bash:.expeditor/update_dep.sh +# - workload: ruby_gem_published:license-acceptance-* +# actions: +# - bash:.expeditor/update_dep.sh diff --git a/.travis.yml b/.travis.yml index 18a12e654d..ed538216f7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,6 +30,7 @@ branches: env: global: - FORCE_FFI_YAJL=ext + - CHEF_LICENSE=accept-no-persist matrix: include: @@ -25,7 +25,7 @@ gem "cheffish", "~> 14" group(:omnibus_package) do gem "appbundler" gem "rb-readline" - gem "inspec-core", ">= 4.0.0.a", "< 5" + gem "inspec-core", "~> 4.3" gem "chef-vault" gem "ed25519" # ed25519 ssh key support done here as it's a native gem we can't put in train gem "bcrypt_pbkdf" # ed25519 ssh key support done here as it's a native gem we can't put in train diff --git a/Gemfile.lock b/Gemfile.lock index 65302bda1d..8f769b7a73 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,6 +41,7 @@ PATH ffi-yajl (~> 2.2) highline (>= 1.6.9, < 2) iniparse (~> 1.4) + license-acceptance (~> 1.0) mixlib-archive (>= 0.4, < 2.0) mixlib-authentication (~> 2.1) mixlib-cli (>= 1.7, < 3.0) @@ -71,6 +72,7 @@ PATH highline (>= 1.6.9, < 2) iniparse (~> 1.4) iso8601 (~> 0.12.1) + license-acceptance (~> 1.0) mixlib-archive (>= 0.4, < 2.0) mixlib-authentication (~> 2.1) mixlib-cli (>= 1.7, < 3.0) @@ -203,7 +205,7 @@ GEM jaro_winkler (1.5.2) json (2.2.0) libyajl2 (1.2.0) - license-acceptance (1.0.2) + license-acceptance (1.0.5) pastel (~> 0.7) tomlrb (~> 1.2) tty-box (~> 0.3) @@ -416,7 +418,7 @@ DEPENDENCIES cheffish (~> 14) chefstyle! ed25519 - inspec-core (>= 4.0.0.a, < 5) + inspec-core (~> 4.3) ohai! pry pry-byebug diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index ea1871d677..5a0cc3244c 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -6,6 +6,19 @@ Chef 15 release notes will be added here as development progresses. ## New Features / Functionality +### Chef EULA + +Chef Client requires a EULA to be accepted by users before it can run. Users can accept the EULA in a variety of ways: + +`chef-client --chef-license accept` +`chef-client --chef-license accept-no-persist` +`CHEF_LICENSE=accept chef-client` +`CHEF_LICENSE=accept-no-persist chef-client` + +Finally, if users run `chef-client` without any of these options, they will receive an interactive prompt asking for +license acceptance. If the license is accepted, a marker file will be written to the filesystem (unless +`accept-no-persist` is specified). Once this marker file is persisted, users no longer need to set any of these flags. + ### Allow Using --delete-entire-chef-repo in Chef Local Mode ### Data Collection Ground-Up Refactor diff --git a/appveyor.yml b/appveyor.yml index 15ab998c80..6ab90e3c2d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -45,6 +45,7 @@ install: - bundle config --local path vendor/bundle # use the cache we define above - bundle install || bundle install || bundle install - SET SPEC_OPTS=--format progress + - SET CHEF_LICENSE=accept-no-persist build: off diff --git a/chef-bin/bin/chef-apply b/chef-bin/bin/chef-apply index ddbdc66907..05b975a118 100755 --- a/chef-bin/bin/chef-apply +++ b/chef-bin/bin/chef-apply @@ -21,4 +21,4 @@ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require "chef/application/apply" -Chef::Application::Apply.new.run +Chef::Application::Apply.new.run(enforce_license: true) diff --git a/chef-bin/bin/chef-client b/chef-bin/bin/chef-client index af27d7903d..45a6af546a 100755 --- a/chef-bin/bin/chef-client +++ b/chef-bin/bin/chef-client @@ -22,4 +22,4 @@ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require "chef" require "chef/application/client" -Chef::Application::Client.new.run +Chef::Application::Client.new.run(enforce_license: true) diff --git a/chef-bin/bin/chef-solo b/chef-bin/bin/chef-solo index 06c0452d26..7a2168230d 100755 --- a/chef-bin/bin/chef-solo +++ b/chef-bin/bin/chef-solo @@ -21,4 +21,4 @@ $:.unshift(File.join(File.dirname(__FILE__), "..", "lib")) require "chef/application/solo" -Chef::Application::Solo.new.run +Chef::Application::Solo.new.run(enforce_license: true) diff --git a/chef.gemspec b/chef.gemspec index ebd6d192bb..7c365eeeb4 100644 --- a/chef.gemspec +++ b/chef.gemspec @@ -18,6 +18,7 @@ Gem::Specification.new do |s| s.add_dependency "chef-config", "= #{Chef::VERSION}" s.add_dependency "train-core", "~> 2.0", ">= 2.0.12" + s.add_dependency "license-acceptance", "~> 1.0" s.add_dependency "mixlib-cli", ">= 1.7", "< 3.0" s.add_dependency "mixlib-log", ">= 2.0.3", "< 4.0" s.add_dependency "mixlib-authentication", "~> 2.1" diff --git a/docs/dev/license_acceptance.md b/docs/dev/license_acceptance.md new file mode 100644 index 0000000000..bb6e8a4e07 --- /dev/null +++ b/docs/dev/license_acceptance.md @@ -0,0 +1,13 @@ +# License Acceptance + +Starting with Chef Client 15 users are required to accept the [Chef +EULA](https://www.chef.io/end-user-license-agreement/) to use the Chef Software distribution. This document aims to +explain how the `license-acceptance` gem and the `chef` gem interact. + +The overall goal is that the license acceptance flow is invoked as early as possible in the binary (EG, `chef-client`) +execution. Failure to accept the license causes the binary to immediately exit with code `172`. + +For an explanation of how this is achieved please see the [Ruby +README](https://github.com/chef/license-acceptance/tree/master/components/ruby) in the license-acceptance repo. For an +overall view of how the license-acceptance gem works, its specification, how marker files are stored, etc. please see +the [repo README](https://github.com/chef/license-acceptance). diff --git a/kitchen-tests/Gemfile b/kitchen-tests/Gemfile index c2437a307b..a1a438d071 100644 --- a/kitchen-tests/Gemfile +++ b/kitchen-tests/Gemfile @@ -6,5 +6,5 @@ gem "ohai", git: "https://github.com/chef/ohai.git", branch: "master" # avoids f gem "berkshelf", git: "https://github.com/berkshelf/berkshelf.git", branch: "master" gem "kitchen-dokken", "~> 2.0" gem "kitchen-inspec", git: "https://github.com/chef/kitchen-inspec.git", branch: "master" -gem "inspec", git: "https://github.com/inspec/inspec.git", branch: "master" # this goes away when we ship inspec 4 +gem "inspec" gem "test-kitchen", git: "https://github.com/test-kitchen/test-kitchen.git", branch: "master" diff --git a/kitchen-tests/cookbooks/end_to_end/Berksfile b/kitchen-tests/cookbooks/end_to_end/Berksfile deleted file mode 100644 index 967b9a78b6..0000000000 --- a/kitchen-tests/cookbooks/end_to_end/Berksfile +++ /dev/null @@ -1,3 +0,0 @@ -source "https://supermarket.chef.io" - -metadata diff --git a/kitchen-tests/cookbooks/end_to_end/attributes/default.rb b/kitchen-tests/cookbooks/end_to_end/attributes/default.rb index 5e8cee6736..b8ac7f8119 100644 --- a/kitchen-tests/cookbooks/end_to_end/attributes/default.rb +++ b/kitchen-tests/cookbooks/end_to_end/attributes/default.rb @@ -62,6 +62,8 @@ default["chef_client"]["splay"] = 1800 # only log what we change default["chef_client"]["config"]["verbose_logging"] = false +default["chef_client"]["chef_license"] = "accept-no-persist" + # # resolver cookbook overrides # diff --git a/kitchen-tests/cookbooks/rspec/templates/run-chef-rspec b/kitchen-tests/cookbooks/rspec/templates/run-chef-rspec index 54c4297479..4a1eb54b48 100644 --- a/kitchen-tests/cookbooks/rspec/templates/run-chef-rspec +++ b/kitchen-tests/cookbooks/rspec/templates/run-chef-rspec @@ -8,4 +8,5 @@ export PATH=/opt/chef/embedded/bin:$PATH cd /opt/chef/embedded/apps/chef /opt/chef/embedded/bin/bundle install +export CHEF_LICENSE=accept-no-persist /opt/chef/embedded/bin/bundle exec /opt/chef/embedded/bin/rspec --format progress diff --git a/kitchen-tests/kitchen.yml b/kitchen-tests/kitchen.yml index 5fe3b8540f..0b4b1964fc 100644 --- a/kitchen-tests/kitchen.yml +++ b/kitchen-tests/kitchen.yml @@ -12,6 +12,7 @@ provisioner: name: dokken client_rb: diff_disabled: true + chef_license: "accept-no-persist" lifecycle: pre_converge: diff --git a/lib/chef/application.rb b/lib/chef/application.rb index 549d8b4482..7388e3d22d 100644 --- a/lib/chef/application.rb +++ b/lib/chef/application.rb @@ -29,6 +29,7 @@ require "tmpdir" require "rbconfig" require "chef/application/exit_code" require "chef/dist" +require "license_acceptance/acceptor" class Chef class Application @@ -60,10 +61,11 @@ class Chef end # Get this party started - def run + def run(enforce_license: false) setup_signal_handlers reconfigure setup_application + check_license_acceptance if enforce_license run_application end @@ -248,6 +250,15 @@ class Chef raise Chef::Exceptions::Application, "#{self}: you must override setup_application" end + def check_license_acceptance + LicenseAcceptance::Acceptor.check_and_persist!( + "infra-client", + Chef::VERSION.to_s, + logger: logger, + provided: Chef::Config[:chef_license] + ) + end + # Actually run the application def run_application raise Chef::Exceptions::Application, "#{self}: you must override run_application" diff --git a/lib/chef/application/apply.rb b/lib/chef/application/apply.rb index 34f0973b40..715e0152d2 100644 --- a/lib/chef/application/apply.rb +++ b/lib/chef/application/apply.rb @@ -214,8 +214,9 @@ class Chef::Application::Apply < Chef::Application end # Get this party started - def run + def run(enforce_license = false) reconfigure + check_license_acceptance if enforce_license run_application end diff --git a/lib/chef/application/client.rb b/lib/chef/application/client.rb index 390acfba04..31932b812c 100644 --- a/lib/chef/application/client.rb +++ b/lib/chef/application/client.rb @@ -30,10 +30,12 @@ require "chef-config/mixin/dot_d" require "mixlib/archive" require "uri" require "chef/dist" +require "license_acceptance/cli_flags/mixlib_cli" class Chef::Application::Client < Chef::Application include Chef::Mixin::ShellOut include ChefConfig::Mixin::DotD + include LicenseAcceptance::CLIFlags::MixlibCLI # Mimic self_pipe sleep from Unicorn to capture signals safely SELF_PIPE = [] # rubocop:disable Style/MutableConstant @@ -220,6 +222,7 @@ class Chef::Application::Client < Chef::Application Chef::RunList::RunListItem.new(item) end } + option :why_run, short: "-W", long: "--why-run", diff --git a/lib/chef/application/solo.rb b/lib/chef/application/solo.rb index 04cc9265ff..b1957fbf7c 100644 --- a/lib/chef/application/solo.rb +++ b/lib/chef/application/solo.rb @@ -217,10 +217,11 @@ class Chef::Application::Solo < Chef::Application attr_reader :chef_client_json # Get this party started - def run + def run(enforce_license: false) setup_signal_handlers setup_application reconfigure + check_license_acceptance if enforce_license for_ezra if Chef::Config[:ez] if !Chef::Config[:solo_legacy_mode] Chef::Application::Client.new.run diff --git a/lib/chef/knife/bootstrap.rb b/lib/chef/knife/bootstrap.rb index 5d76736e06..90dd2417fc 100644 --- a/lib/chef/knife/bootstrap.rb +++ b/lib/chef/knife/bootstrap.rb @@ -19,11 +19,14 @@ require "chef/knife" require "chef/knife/data_bag_secret_options" require "chef/dist" +require "license_acceptance/cli_flags/mixlib_cli" +require "license_acceptance/acceptor" class Chef class Knife class Bootstrap < Knife include DataBagSecretOptions + include LicenseAcceptance::CLIFlags::MixlibCLI SUPPORTED_CONNECTION_PROTOCOLS = %w{ssh winrm}.freeze WINRM_AUTH_PROTOCOL_LIST = %w{plaintext kerberos ssl negotiate}.freeze @@ -413,6 +416,7 @@ class Chef def initialize(argv = []) super + LicenseAcceptance::Acceptor.check_and_persist!("infra-client", Chef::VERSION.to_s, logger: Chef::Log, provided: Chef::Config[:chef_license]) @client_builder = Chef::Knife::Bootstrap::ClientBuilder.new( chef_config: Chef::Config, knife_config: config, diff --git a/lib/chef/knife/core/bootstrap_context.rb b/lib/chef/knife/core/bootstrap_context.rb index 5a27836da8..f9ebf52b31 100644 --- a/lib/chef/knife/core/bootstrap_context.rb +++ b/lib/chef/knife/core/bootstrap_context.rb @@ -171,6 +171,7 @@ class Chef def start_chef # If the user doesn't have a client path configure, let bash use the PATH for what it was designed for client_path = @chef_config[:chef_client_path] || "#{Chef::Dist::CLIENT}" + # We know we can hardcode CHEF_LICENSE because the user cannot get here without accepting the license locally s = "CHEF_LICENSE=accept #{client_path} -j /etc/chef/first-boot.json" if @config[:verbosity] && @config[:verbosity] >= 3 s << " -l trace" diff --git a/spec/unit/application/knife_spec.rb b/spec/unit/application/knife_spec.rb index 8a574b4d0f..f8f5560597 100644 --- a/spec/unit/application/knife_spec.rb +++ b/spec/unit/application/knife_spec.rb @@ -75,11 +75,7 @@ describe Chef::Application::Knife do expect(@knife).to receive(:exit).with(0) @knife.run end - if windows? - expect(Chef::Config[:color]).to be_truthy - else - expect(Chef::Config[:color]).to be_truthy - end + expect(Chef::Config[:color]).to be_truthy end context "when given fips flags" do diff --git a/spec/unit/application_spec.rb b/spec/unit/application_spec.rb index e76e21bddc..10dff0e250 100644 --- a/spec/unit/application_spec.rb +++ b/spec/unit/application_spec.rb @@ -87,6 +87,13 @@ describe Chef::Application do @app.run end + describe "when enforce_license is set to true" do + it "should check the license acceptance" do + expect(@app).to receive(:check_license_acceptance) + @app.run(enforce_license: true) + end + end + it "should run the actual application" do expect(@app).to receive(:run_application).and_return(true) @app.run diff --git a/spec/unit/knife/bootstrap_spec.rb b/spec/unit/knife/bootstrap_spec.rb index 4261a3a166..948fc5b574 100644 --- a/spec/unit/knife/bootstrap_spec.rb +++ b/spec/unit/knife/bootstrap_spec.rb @@ -40,6 +40,7 @@ describe Chef::Knife::Bootstrap do let(:knife) do Chef::Log.logger = Logger.new(StringIO.new) Chef::Config[:knife][:bootstrap_template] = bootstrap_template unless bootstrap_template.nil? + expect(LicenseAcceptance::Acceptor).to receive(:check_and_persist!) k = Chef::Knife::Bootstrap.new(bootstrap_cli_options) allow(k.ui).to receive(:stderr).and_return(stderr) @@ -49,6 +50,15 @@ describe Chef::Knife::Bootstrap do k end + it "purposefully fails to prevent Chef Infra from promoting unstable -> current" do + expect(0).to eq(1) + end + + it "fails when LicenseAcceptance fails" do + expect(LicenseAcceptance::Acceptor).to receive(:check_and_persist!).and_raise("foo") + expect { k = Chef::Knife::Bootstrap.new(bootstrap_cli_options) }.to raise_error("foo") + end + context "#bootstrap_template" do it "should default to chef-full" do expect(knife.bootstrap_template).to be_a_kind_of(String) @@ -323,6 +333,7 @@ describe Chef::Knife::Bootstrap do describe "specifying no_proxy with various entries" do subject(:knife) do + expect(LicenseAcceptance::Acceptor).to receive(:check_and_persist!) k = described_class.new Chef::Config[:knife][:bootstrap_template] = template_file allow(k).to receive(:connection).and_return connection diff --git a/spec/unit/knife/core/windows_bootstrap_context_spec.rb b/spec/unit/knife/core/windows_bootstrap_context_spec.rb index 7bc73c113a..561e43eefc 100644 --- a/spec/unit/knife/core/windows_bootstrap_context_spec.rb +++ b/spec/unit/knife/core/windows_bootstrap_context_spec.rb @@ -221,6 +221,8 @@ describe Chef::Knife::Core::WindowsBootstrapContext do let(:bootstrap) { Chef::Knife::Bootstrap.new(["--bootstrap-install-command", "chef-client"]) } before do bootstrap.config[:bootstrap_install_command] = "chef-client" + @old_env = ENV["CHEF_LICENSE"] + ENV["CHEF_LICENSE"] = "accept" end it "sets the bootstrap_install_command option under Chef::Config::Knife object" do @@ -230,6 +232,7 @@ describe Chef::Knife::Core::WindowsBootstrapContext do after do bootstrap.config.delete(:bootstrap_install_command) Chef::Config[:knife].delete(:bootstrap_install_command) + ENV["CHEF_LICENSE"] = @old_env end end @@ -246,6 +249,8 @@ describe Chef::Knife::Core::WindowsBootstrapContext do let(:bootstrap) { Chef::Knife::Bootstrap.new(["--bootstrap-install-command", "chef-client"]) } before do bootstrap.config[:bootstrap_install_command] = "chef-client" + @old_env = ENV["CHEF_LICENSE"] + ENV["CHEF_LICENSE"] = "accept" end it "sets the bootstrap_install_command option under Chef::Config::Knife object" do @@ -255,6 +260,7 @@ describe Chef::Knife::Core::WindowsBootstrapContext do after do bootstrap.config.delete(:bootstrap_install_command) Chef::Config[:knife].delete(:bootstrap_install_command) + ENV["CHEF_LICENSE"] = @old_env end end diff --git a/tasks/bin/run_external_test b/tasks/bin/run_external_test index 5f1ac8f210..04fe5343ba 100755 --- a/tasks/bin/run_external_test +++ b/tasks/bin/run_external_test @@ -13,7 +13,11 @@ git_thing = ARGV.shift build_dir = File.expand_path(ENV["TRAVIS_BUILD_DIR"] || Dir.pwd) -env = { "GEMFILE_MOD" => "gem 'chef', path: '#{build_dir}'; gem 'ohai', git: 'https://github.com/chef/ohai.git', branch: 'master'" } +env = { + "GEMFILE_MOD" => "gem 'chef', path: '#{build_dir}'; " \ + "gem 'ohai', git: 'https://github.com/chef/ohai.git'", + "CHEF_LICENSE" => "accept-no-persist", +} Dir.mktmpdir("chef-external-test") do |dir| git_url = "https://github.com/#{github_repo}" |