From 36687f10f0dfa0eb721306e5dd6dca9d6c5041b0 Mon Sep 17 00:00:00 2001 From: Scott Vidmar Date: Thu, 24 Sep 2020 10:06:55 -0700 Subject: [PATCH 1/7] Add effortless cops for Chef Vault. Fixed typo in comment in cookstyle.yml Signed-off-by: Scott Vidmar --- config/cookstyle.yml | 17 ++++ .../cop/chef/effortless/chef_vault_used.rb | 94 +++++++++++++++++++ .../cop/chef/effortless/depends_chef_vault.rb | 46 +++++++++ .../effortless/chef_vault_depends_spec.rb | 29 ++++++ .../chef/effortless/chef_vault_used_spec.rb | 64 +++++++++++++ 5 files changed, 250 insertions(+) create mode 100644 lib/rubocop/cop/chef/effortless/chef_vault_used.rb create mode 100644 lib/rubocop/cop/chef/effortless/depends_chef_vault.rb create mode 100644 spec/rubocop/cop/chef/effortless/chef_vault_depends_spec.rb create mode 100644 spec/rubocop/cop/chef/effortless/chef_vault_used_spec.rb diff --git a/config/cookstyle.yml b/config/cookstyle.yml index 13e086bd9..5511787e5 100644 --- a/config/cookstyle.yml +++ b/config/cookstyle.yml @@ -1929,6 +1929,23 @@ ChefEffortless/CookbookUsesDatabags: Exclude: - '**/metadata.rb' - '**/Berksfile' + +ChefEffortless/ChefVaultUsed: + Description: Cookbook uses Chef Vault, which cannot be used in the Effortless Infra pattern + StyleGuide: '#chefeffortlesscookbookuseschefvault' + Enabled: false + VersionAdded: '6.19.2' + Exclude: + - '**/metadata.rb' + - '**/Berksfile' + +ChefEffortless/DependsChefVault: + Description: Cookbook depends on Chef Vault, which cannot be used in the Effortless Infra pattern + StyleGuide: '#chefeffortlesscookbookdependschefvault' + Enabled: false + VersionAdded: '6.19.2' + Include: + - '**/metadata.rb' ChefEffortless/CookbookUsesEnvironments: Description: Cookbook uses environments, which cannot be used in the Effortless Infra pattern diff --git a/lib/rubocop/cop/chef/effortless/chef_vault_used.rb b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb new file mode 100644 index 000000000..cf15add32 --- /dev/null +++ b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb @@ -0,0 +1,94 @@ +# frozen_string_literal: true +# +# Copyright:: 2019, Chef Software Inc. +# +# 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. +# + +module RuboCop + module Cop + module Chef + module ChefEffortless + # Cookbook:: Chef Vault does not work with Effortless + # + # @example + # + # # bad + # require 'chef-vault' + # + # # bad + # ChefVault::Item + # + # # bad + # include_recipe 'chef-vault' + # + # # bad + # chef_gem 'chef-vault' + # + # # bad + # chef_vault_item_for_environment(arg, arg1) + # + # # bad + # chef_vault_item(arg, arg1) + # + class ChefVaultUsed < Base + MSG = 'Chef Vault usage is not supported in the Effortless pattern' + + def_node_matcher :require?, <<-PATTERN + (send nil? :require + (str "chef-vault")) + PATTERN + + def_node_matcher :include?, <<-PATTERN + (send nil? :include_recipe + (str "chef-vault")) + PATTERN + + def_node_matcher :chef_gem?, <<-PATTERN + (send nil? :chef_gem + (str "chef-vault")) + PATTERN + + def_node_matcher :vault_const?, <<-PATTERN + (const + (const nil? :ChefVault) + :Item) + PATTERN + + def_node_matcher :chef_vault_item_for_environment?, <<-PATTERN + (send nil? :chef_vault_item_for_environment _ _) + PATTERN + + def_node_matcher :chef_vault_item?, <<-PATTERN + (send nil? :chef_vault_item _ _) + PATTERN + + def on_send(node) + return unless require?(node) || + chef_gem?(node) || + chef_vault_item_for_environment?(node) || + chef_vault_item?(node) || + include?(node) + add_offense(node.loc.expression, message: MSG, severity: :refactor) + end + + def on_const(node) + vault_const?(node) do + add_offense(node.loc.expression, message: MSG, severity: :refactor) + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/chef/effortless/depends_chef_vault.rb b/lib/rubocop/cop/chef/effortless/depends_chef_vault.rb new file mode 100644 index 000000000..39a8c7e84 --- /dev/null +++ b/lib/rubocop/cop/chef/effortless/depends_chef_vault.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true +# +# Copyright:: 2019, Chef Software Inc. +# +# 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. +# + +module RuboCop + module Cop + module Chef + module ChefEffortless + # Cookbook:: metadata.rb Chef Vault does not work with Effortless + # + # @example + # + # # bad + # depends 'chef-vault' + # + class DependsChefVault < Base + MSG = 'Chef Vault usage is not supported in the Effortless pattern' + + def_node_matcher :depends?, <<-PATTERN + (send nil? :depends + (str "chef-vault")) + PATTERN + + def on_send(node) + depends?(node) do + add_offense(node.loc.expression, message: MSG, severity: :refactor) + end + end + end + end + end + end +end diff --git a/spec/rubocop/cop/chef/effortless/chef_vault_depends_spec.rb b/spec/rubocop/cop/chef/effortless/chef_vault_depends_spec.rb new file mode 100644 index 000000000..7179939a1 --- /dev/null +++ b/spec/rubocop/cop/chef/effortless/chef_vault_depends_spec.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true +# +# Copyright:: 2020, Chef Software, Inc. +# +# 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 'spec_helper' + +describe RuboCop::Cop::Chef::ChefEffortless::DependsChefVault, :config do + subject(:cop) { described_class.new(config) } + + it 'registers an offense when requiring chef-vault' do + expect_offense(<<~RUBY) + depends 'chef-vault' + ^^^^^^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern + RUBY + end +end \ No newline at end of file diff --git a/spec/rubocop/cop/chef/effortless/chef_vault_used_spec.rb b/spec/rubocop/cop/chef/effortless/chef_vault_used_spec.rb new file mode 100644 index 000000000..efb1dc2fa --- /dev/null +++ b/spec/rubocop/cop/chef/effortless/chef_vault_used_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true +# +# Copyright:: 2020, Chef Software, Inc. +# +# 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 'spec_helper' + +describe RuboCop::Cop::Chef::ChefEffortless::ChefVaultUsed, :config do + subject(:cop) { described_class.new(config) } + + it 'registers an offense when requiring chef-vault' do + expect_offense(<<~RUBY) + require 'chef-vault' + ^^^^^^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern + RUBY + end + + it 'registers an offense when requiring chef-vault' do + expect_offense(<<~RUBY) + include_recipe 'chef-vault' + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern + RUBY + end + + it 'registers an offense when chef-vault is installed in a cookbook' do + expect_offense(<<~RUBY) + chef_gem 'chef-vault' + ^^^^^^^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern + RUBY + end + + it 'registers an offense when ChefVault::Item constant is used' do + expect_offense(<<~RUBY) + ChefVault::Item.load + ^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern + RUBY + end + + it 'registers an offense when #chef_vault_item is used' do + expect_offense(<<~RUBY) + chef_vault_item("secrets", "dbpassword") + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern + RUBY + end + + it 'registers an offense when #chef_vault_item is used' do + expect_offense(<<~RUBY) + chef_vault_item_for_environment('secrets', 'passwords') + ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern + RUBY + end +end From 652c3db40390b9702f0f54c869b18e52f9777eba Mon Sep 17 00:00:00 2001 From: Scott Vidmar Date: Thu, 24 Sep 2020 10:50:46 -0700 Subject: [PATCH 2/7] Add Effortless cops to detect Chef Vault usage Signed-off-by: Scott Vidmar --- config/cookstyle.yml | 2 + docs/cops_chefeffortless.md | 67 +++++++++++++++++++ ...nds_spec.rb => depends_chef_vault_spec.rb} | 0 3 files changed, 69 insertions(+) rename spec/rubocop/cop/chef/effortless/{chef_vault_depends_spec.rb => depends_chef_vault_spec.rb} (100%) diff --git a/config/cookstyle.yml b/config/cookstyle.yml index 5511787e5..6ba4b15bc 100644 --- a/config/cookstyle.yml +++ b/config/cookstyle.yml @@ -1930,6 +1930,7 @@ ChefEffortless/CookbookUsesDatabags: - '**/metadata.rb' - '**/Berksfile' +# https://github.com/chef/cookstyle/issues/346 ChefEffortless/ChefVaultUsed: Description: Cookbook uses Chef Vault, which cannot be used in the Effortless Infra pattern StyleGuide: '#chefeffortlesscookbookuseschefvault' @@ -1939,6 +1940,7 @@ ChefEffortless/ChefVaultUsed: - '**/metadata.rb' - '**/Berksfile' +# https://github.com/chef/cookstyle/issues/346 ChefEffortless/DependsChefVault: Description: Cookbook depends on Chef Vault, which cannot be used in the Effortless Infra pattern StyleGuide: '#chefeffortlesscookbookdependschefvault' diff --git a/docs/cops_chefeffortless.md b/docs/cops_chefeffortless.md index b6738fd65..fa57ea7c7 100644 --- a/docs/cops_chefeffortless.md +++ b/docs/cops_chefeffortless.md @@ -178,3 +178,70 @@ Exclude | `**/metadata.rb`, `**/Berksfile` | Array ### References * [https://rubystyle.guide#chefeffortlesssearchforenvironmentsorroles](https://rubystyle.guide#chefeffortlesssearchforenvironmentsorroles) + +## ChefEffortless/DependsChefVault + +Enabled by default | Supports autocorrection | Target Chef Version +--- | --- | --- +Disabled | No | All Versions + +Chef Vault is not supported in the Effortless pattern, so usage of Chef Vault must be shifted to another secrets management solution before leveraging the Effortless pattern. + +### Examples + +```ruby +# bad +depends 'chef-vault' +``` + +### Configurable attributes + +Name | Default value | Configurable values +--- | --- | --- +VersionAdded | `6.19.2` | String +Include | `**/metadata.rb`| Array + +### References + +* [https://rubystyle.guide#chefeffortlessdependschefvault](ttps://rubystyle.guide#chefeffortlessdependschefvault) + +## ChefEffortless/ChefVaultUsed + +Enabled by default | Supports autocorrection | Target Chef Version +--- | --- | --- +Disabled | No | All Versions + +Chef Vault is not supported in the Effortless pattern, so usage of Chef Vault must be shifted to another secrets management solution before leveraging the Effortless pattern. + +### Examples + +```Ruby +# bad +require 'chef-vault' + +# bad +ChefVault::Item + +# bad +include_recipe 'chef-vault' + +# bad +chef_gem 'chef-vault' + +# bad +chef_vault_item_for_environment(arg, arg1) + +# bad +chef_vault_item(arg, arg1) +``` + +### Configurable attributes + +Name | Default value | Configurable values +--- | --- | --- +VersionAdded | `6.19.2` | String +Exclude | `**/metadata.rb`, `**/Berksfile`| Array + +### References + +* [https://rubystyle.guide#chefeffortlessdependschefvault](ttps://rubystyle.guide#chefeffortlessdependschefvault) \ No newline at end of file diff --git a/spec/rubocop/cop/chef/effortless/chef_vault_depends_spec.rb b/spec/rubocop/cop/chef/effortless/depends_chef_vault_spec.rb similarity index 100% rename from spec/rubocop/cop/chef/effortless/chef_vault_depends_spec.rb rename to spec/rubocop/cop/chef/effortless/depends_chef_vault_spec.rb From a364fabe2e572d0f60340c39da312f3f8194bade Mon Sep 17 00:00:00 2001 From: Scott Vidmar Date: Thu, 24 Sep 2020 10:57:05 -0700 Subject: [PATCH 3/7] Add new line at end of depends_chef_vault_spec.rb for style purposes Signed-off-by: Scott Vidmar --- spec/rubocop/cop/chef/effortless/depends_chef_vault_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/rubocop/cop/chef/effortless/depends_chef_vault_spec.rb b/spec/rubocop/cop/chef/effortless/depends_chef_vault_spec.rb index 7179939a1..1a5e0c071 100644 --- a/spec/rubocop/cop/chef/effortless/depends_chef_vault_spec.rb +++ b/spec/rubocop/cop/chef/effortless/depends_chef_vault_spec.rb @@ -26,4 +26,4 @@ ^^^^^^^^^^^^^^^^^^^^ Chef Vault usage is not supported in the Effortless pattern RUBY end -end \ No newline at end of file +end From 1515aacaed6c8a74b52c7f828d0cb7dfc03a9db8 Mon Sep 17 00:00:00 2001 From: Scott Vidmar Date: Thu, 24 Sep 2020 11:08:44 -0700 Subject: [PATCH 4/7] Make use of RESTRICT_ON_SEND Signed-off-by: Scott Vidmar --- lib/rubocop/cop/chef/effortless/chef_vault_used.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/rubocop/cop/chef/effortless/chef_vault_used.rb b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb index cf15add32..a91e85d4f 100644 --- a/lib/rubocop/cop/chef/effortless/chef_vault_used.rb +++ b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb @@ -43,6 +43,11 @@ module ChefEffortless # class ChefVaultUsed < Base MSG = 'Chef Vault usage is not supported in the Effortless pattern' + RESTRICT_ON_SEND = [:chef_vault_item, + :chef_vault_item_for_environment, + :include_recipe, + :require, + :chef_gem].freeze def_node_matcher :require?, <<-PATTERN (send nil? :require From 809ac77c9c1b5f9f1b94e8cc749f6761d428bd6b Mon Sep 17 00:00:00 2001 From: Scott Vidmar Date: Thu, 24 Sep 2020 11:47:58 -0700 Subject: [PATCH 5/7] Combine AST checks in chef_vault_used.rb for extra perf Signed-off-by: Scott Vidmar --- .../cop/chef/effortless/chef_vault_used.rb | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/lib/rubocop/cop/chef/effortless/chef_vault_used.rb b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb index a91e85d4f..b08afad6e 100644 --- a/lib/rubocop/cop/chef/effortless/chef_vault_used.rb +++ b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb @@ -50,17 +50,7 @@ class ChefVaultUsed < Base :chef_gem].freeze def_node_matcher :require?, <<-PATTERN - (send nil? :require - (str "chef-vault")) - PATTERN - - def_node_matcher :include?, <<-PATTERN - (send nil? :include_recipe - (str "chef-vault")) - PATTERN - - def_node_matcher :chef_gem?, <<-PATTERN - (send nil? :chef_gem + (send nil? { :require :include_recipe :chef_gem } (str "chef-vault")) PATTERN @@ -80,10 +70,8 @@ class ChefVaultUsed < Base def on_send(node) return unless require?(node) || - chef_gem?(node) || chef_vault_item_for_environment?(node) || - chef_vault_item?(node) || - include?(node) + chef_vault_item?(node) add_offense(node.loc.expression, message: MSG, severity: :refactor) end From 5e5a0add1dcf01930c3a26004baff8f003c14ddf Mon Sep 17 00:00:00 2001 From: Scott Vidmar Date: Fri, 25 Sep 2020 08:32:19 -0700 Subject: [PATCH 6/7] Fix typos in cops_chefeffortless.md Signed-off-by: Scott Vidmar --- docs/cops_chefeffortless.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/cops_chefeffortless.md b/docs/cops_chefeffortless.md index fa57ea7c7..2b1d1edfe 100644 --- a/docs/cops_chefeffortless.md +++ b/docs/cops_chefeffortless.md @@ -203,7 +203,7 @@ Include | `**/metadata.rb`| Array ### References -* [https://rubystyle.guide#chefeffortlessdependschefvault](ttps://rubystyle.guide#chefeffortlessdependschefvault) +* [https://rubystyle.guide#chefeffortlessdependschefvault](https://rubystyle.guide#chefeffortlessdependschefvault) ## ChefEffortless/ChefVaultUsed @@ -244,4 +244,4 @@ Exclude | `**/metadata.rb`, `**/Berksfile`| Array ### References -* [https://rubystyle.guide#chefeffortlessdependschefvault](ttps://rubystyle.guide#chefeffortlessdependschefvault) \ No newline at end of file +* [https://rubystyle.guide#chefeffortlessdependschefvault](https://rubystyle.guide#chefeffortlessdependschefvault) From b5a4c79deaf2944a6d0da82ff720aa08283ae0d5 Mon Sep 17 00:00:00 2001 From: Scott Vidmar Date: Mon, 28 Sep 2020 08:55:25 -0700 Subject: [PATCH 7/7] Fix issues in PR for Chef Vault cops. - Correct copyright statements to 2020. - Update version added to 6.19, not 6.19.2 - Add author statements. Signed-off-by: Scott Vidmar --- config/cookstyle.yml | 4 ++-- docs/cops_chefeffortless.md | 4 ++-- lib/rubocop/cop/chef/effortless/chef_vault_used.rb | 6 ++++-- lib/rubocop/cop/chef/effortless/depends_chef_vault.rb | 7 +++++-- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/config/cookstyle.yml b/config/cookstyle.yml index 6ba4b15bc..918662a97 100644 --- a/config/cookstyle.yml +++ b/config/cookstyle.yml @@ -1935,7 +1935,7 @@ ChefEffortless/ChefVaultUsed: Description: Cookbook uses Chef Vault, which cannot be used in the Effortless Infra pattern StyleGuide: '#chefeffortlesscookbookuseschefvault' Enabled: false - VersionAdded: '6.19.2' + VersionAdded: '6.19' Exclude: - '**/metadata.rb' - '**/Berksfile' @@ -1945,7 +1945,7 @@ ChefEffortless/DependsChefVault: Description: Cookbook depends on Chef Vault, which cannot be used in the Effortless Infra pattern StyleGuide: '#chefeffortlesscookbookdependschefvault' Enabled: false - VersionAdded: '6.19.2' + VersionAdded: '6.19' Include: - '**/metadata.rb' diff --git a/docs/cops_chefeffortless.md b/docs/cops_chefeffortless.md index 2b1d1edfe..d77f4129a 100644 --- a/docs/cops_chefeffortless.md +++ b/docs/cops_chefeffortless.md @@ -198,7 +198,7 @@ depends 'chef-vault' Name | Default value | Configurable values --- | --- | --- -VersionAdded | `6.19.2` | String +VersionAdded | `6.19` | String Include | `**/metadata.rb`| Array ### References @@ -239,7 +239,7 @@ chef_vault_item(arg, arg1) Name | Default value | Configurable values --- | --- | --- -VersionAdded | `6.19.2` | String +VersionAdded | `6.19` | String Exclude | `**/metadata.rb`, `**/Berksfile`| Array ### References diff --git a/lib/rubocop/cop/chef/effortless/chef_vault_used.rb b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb index b08afad6e..3a44b8be4 100644 --- a/lib/rubocop/cop/chef/effortless/chef_vault_used.rb +++ b/lib/rubocop/cop/chef/effortless/chef_vault_used.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true # -# Copyright:: 2019, Chef Software Inc. +# Copyright:: 2020, Chef Software Inc. +# Author:: Scott Vidmar () # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,7 +20,7 @@ module RuboCop module Cop module Chef module ChefEffortless - # Cookbook:: Chef Vault does not work with Effortless + # Cookbook:: Chef Vault is not compatible with the Chef Infra Effortless pattern due to its reliance on Data Bags to store secrets. # # @example # @@ -41,6 +42,7 @@ module ChefEffortless # # bad # chef_vault_item(arg, arg1) # + class ChefVaultUsed < Base MSG = 'Chef Vault usage is not supported in the Effortless pattern' RESTRICT_ON_SEND = [:chef_vault_item, diff --git a/lib/rubocop/cop/chef/effortless/depends_chef_vault.rb b/lib/rubocop/cop/chef/effortless/depends_chef_vault.rb index 39a8c7e84..922d78332 100644 --- a/lib/rubocop/cop/chef/effortless/depends_chef_vault.rb +++ b/lib/rubocop/cop/chef/effortless/depends_chef_vault.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true # -# Copyright:: 2019, Chef Software Inc. +# Copyright:: 2020, Chef Software Inc. +# Author:: Scott Vidmar () # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -19,15 +20,17 @@ module RuboCop module Cop module Chef module ChefEffortless - # Cookbook:: metadata.rb Chef Vault does not work with Effortless + # Cookbook:: Chef Vault is not compatible with the Chef Infra Effortless pattern due to its reliance on Data Bags to store secrets. # # @example # # # bad # depends 'chef-vault' # + class DependsChefVault < Base MSG = 'Chef Vault usage is not supported in the Effortless pattern' + RESTRICT_ON_SEND = [:depends].freeze def_node_matcher :depends?, <<-PATTERN (send nil? :depends