├── .gitignore ├── .kitchen.yml ├── Berksfile ├── Gemfile ├── LICENSE ├── README.md ├── Thorfile ├── Vagrantfile ├── chefignore ├── libraries ├── deploy_key.rb ├── deploy_key_bitbucket.rb ├── deploy_key_github.rb ├── deploy_key_gitlab.rb ├── helpers.rb ├── helpers_bitbucket.rb ├── helpers_github.rb ├── helpers_gitlab.rb └── matchers.rb └── metadata.rb /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | Berksfile.lock 3 | *~ 4 | *# 5 | .#* 6 | \#*# 7 | .*.sw[a-z] 8 | *.un~ 9 | /cookbooks 10 | 11 | # Bundler 12 | Gemfile.lock 13 | bin/* 14 | .bundle/* 15 | 16 | .kitchen/ 17 | .kitchen.local.yml 18 | 19 | *.sublime-* 20 | 21 | recipes/* 22 | -------------------------------------------------------------------------------- /.kitchen.yml: -------------------------------------------------------------------------------- 1 | --- 2 | driver_plugin: vagrant 3 | driver_config: 4 | require_chef_omnibus: true 5 | 6 | platforms: 7 | - name: ubuntu-12.04 8 | driver_config: 9 | box: opscode-ubuntu-12.04 10 | box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_provisionerless.box 11 | # - name: ubuntu-10.04 12 | # driver_config: 13 | # box: opscode-ubuntu-10.04 14 | # box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-10.04_provisionerless.box 15 | # - name: centos-6.4 16 | # driver_config: 17 | # box: opscode-centos-6.4 18 | # box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-6.4_provisionerless.box 19 | # - name: centos-5.9 20 | # driver_config: 21 | # box: opscode-centos-5.9 22 | # box_url: https://opscode-vm.s3.amazonaws.com/vagrant/opscode_centos-5.9_provisionerless.box 23 | 24 | suites: 25 | - name: default 26 | run_list: ["recipe[deploy_key::test]"] 27 | attributes: {} 28 | -------------------------------------------------------------------------------- /Berksfile: -------------------------------------------------------------------------------- 1 | site :opscode 2 | 3 | metadata 4 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'berkshelf' 4 | gem 'test-kitchen', :group => :integration 5 | gem 'kitchen-vagrant', :group => :integration 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) 2013 Cassiano Leal 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # deploy_key cookbook 2 | 3 | This is a Chef cookbook to manage deploy_keys on SaaS VCSs. Currently, it supports Bitbucket, Github and GitLab. 4 | 5 | This work is heavily based on the ideas and code of ZippyKid's [github-deploy-key](https://github.com/zippykid/chef-github-deploy-key) cookbook. 6 | 7 | # Usage 8 | 9 | Use this cookbook as a dependency of whatever cookbook will manage your deploy keys. 10 | 11 | Declare a `deploy_key` resource and configure the provider: 12 | 13 | ```ruby 14 | deploy_key "app_deploy_key" do 15 | provider Chef::Provider::DeployKeyGithub 16 | ... 17 | end 18 | ``` 19 | 20 | Supported providers: 21 | 22 | * `Chef::Provider::DeployKeyGithub` 23 | * `Chef::Provider::DeployKeyBitbucket` 24 | * `Chef::Provider::DeployKeyGitlab` 25 | 26 | # Attributes 27 | 28 | * `label`: Used as both the name of the key pair files on disk and the deploy key label on the provider. Defaults to `name`; 29 | * `path`: The directory where the private and public keys are stored 30 | * `credentials`: The credentials used to authenticate on the API - see [below](#authentication) 31 | * `repo`: The repository where the deploy key will be installed. The format varies between providers: 32 | 33 | | Provider | Format | 34 | | ------------------ | --------------------------------------------------------------- | 35 | | GitHub / Bitbucket | `username/repo_slug` (e.g.: `cassianoleal/cookbook-deploy_key`) | 36 | | GitLab | an Integer (e.g.: `1`, `2`, `999`) | 37 | 38 | * `owner`: The owner of the key files on disk. Defaults to `root` 39 | * `group`: The group of the key files on disk. Defaults to `root` 40 | * `mode`: The mode that will be passed on to chmod. Defaults to `0600` 41 | 42 | ##### The following attributes apply only to the GitLab provider: 43 | * `api_url`: The url of the GitLab server 44 | * `client_cert`: Client certificate 45 | * `client_key`: Client cert's key 46 | 47 | # Actions 48 | 49 | * `:create` - Runs ssh-keygen to create a key pair on the designed path; 50 | * `:delete` - Deletes the key pair from the disk; 51 | * `:add` - Adds the public key as a deploy key for the repository; 52 | * `:remove` - Removes the key from the list of deploy keys on the repository 53 | 54 | # Authentication 55 | 56 | Authentication can be done either via username/password: 57 | 58 | ```ruby 59 | deploy_key "app_deploy_key" do 60 | provider Chef::Provider::DeployKeyGithub 61 | credentials({ 62 | :user => 'username@org.com', 63 | :password => 'very_secure_password' 64 | }) 65 | ... 66 | end 67 | ``` 68 | 69 | or OAuth token ( [Github](http://developer.github.com/v3/oauth/) | [Bitbucket](https://confluence.atlassian.com/display/BITBUCKET/OAuth+on+Bitbucket) ): 70 | 71 | ```ruby 72 | deploy_key "app_deploy_key" do 73 | provider Chef::Provider::DeployKeyGithub 74 | credentials({ 75 | :token => 'awesome_and_much_more_secure_token' 76 | }) 77 | ... 78 | end 79 | ``` 80 | 81 | # A full example 82 | 83 | ```ruby 84 | deploy_key "bitbucket_key" do 85 | provider Chef::Provider::DeployKeyBitbucket 86 | path '/home/app_user/.ssh' 87 | credentials({ 88 | :token => 'my_bitbucket_oauth_token' 89 | }) 90 | repo 'organization/million_dollar_app' 91 | owner 'deploy' 92 | group 'deploy' 93 | mode '0640' 94 | action :add 95 | end 96 | ``` 97 | 98 | # ChefSpec matchers 99 | 100 | As of version 0.2.0, the following ChefSpec matchers are available: 101 | 102 | * `create_deploy_key(resource_name)` 103 | * `delete_deploy_key(resource_name)` 104 | * `add_deploy_key(resource_name)` 105 | * `remove_deploy_key(resource_name)` 106 | 107 | # Author 108 | 109 | Cassiano Leal ( [email]() | [twitter](http://twitter.com/cassianoleal) | [github](https://github.com/cassianoleal) ) 110 | -------------------------------------------------------------------------------- /Thorfile: -------------------------------------------------------------------------------- 1 | # encoding: utf-8 2 | 3 | require 'bundler' 4 | require 'bundler/setup' 5 | require 'berkshelf/thor' 6 | 7 | begin 8 | require 'kitchen/thor_tasks' 9 | Kitchen::ThorTasks.new 10 | rescue LoadError 11 | puts ">>>>> Kitchen gem not loaded, omitting tasks" unless ENV['CI'] 12 | end 13 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | # All Vagrant configuration is done here. The most common configuration 6 | # options are documented and commented below. For a complete reference, 7 | # please see the online documentation at vagrantup.com. 8 | 9 | config.vm.hostname = "deploy-key-berkshelf" 10 | 11 | # Every Vagrant virtual environment requires a box to build off of. 12 | config.vm.box = "opscode_ubuntu-12.04_chef-11.2.0" 13 | 14 | # The url from where the 'config.vm.box' box will be fetched if it 15 | # doesn't already exist on the user's system. 16 | config.vm.box_url = "https://opscode-vm.s3.amazonaws.com/vagrant/opscode_ubuntu-12.04_chef-11.2.0.box" 17 | 18 | # Assign this VM to a host-only network IP, allowing you to access it 19 | # via the IP. Host-only networks can talk to the host machine as well as 20 | # any other machines on the same network, but cannot be accessed (through this 21 | # network interface) by any external networks. 22 | config.vm.network :private_network, ip: "33.33.33.10" 23 | 24 | # Create a public network, which generally matched to bridged network. 25 | # Bridged networks make the machine appear as another physical device on 26 | # your network. 27 | 28 | # config.vm.network :public_network 29 | 30 | # Create a forwarded port mapping which allows access to a specific port 31 | # within the machine from a port on the host machine. In the example below, 32 | # accessing "localhost:8080" will access port 80 on the guest machine. 33 | 34 | # Share an additional folder to the guest VM. The first argument is 35 | # the path on the host to the actual folder. The second argument is 36 | # the path on the guest to mount the folder. And the optional third 37 | # argument is a set of non-required options. 38 | # config.vm.synced_folder "../data", "/vagrant_data" 39 | 40 | # Provider-specific configuration so you can fine-tune various 41 | # backing providers for Vagrant. These expose provider-specific options. 42 | # Example for VirtualBox: 43 | # 44 | # config.vm.provider :virtualbox do |vb| 45 | # # Don't boot with headless mode 46 | # vb.gui = true 47 | # 48 | # # Use VBoxManage to customize the VM. For example to change memory: 49 | # vb.customize ["modifyvm", :id, "--memory", "1024"] 50 | # end 51 | # 52 | # View the documentation for the provider you're using for more 53 | # information on available options. 54 | 55 | # The path to the Berksfile to use with Vagrant Berkshelf 56 | # config.berkshelf.berksfile_path = "./Berksfile" 57 | 58 | # Enabling the Berkshelf plugin. To enable this globally, add this configuration 59 | # option to your ~/.vagrant.d/Vagrantfile file 60 | config.berkshelf.enabled = true 61 | 62 | # An array of symbols representing groups of cookbook described in the Vagrantfile 63 | # to exclusively install and copy to Vagrant's shelf. 64 | # config.berkshelf.only = [] 65 | 66 | # An array of symbols representing groups of cookbook described in the Vagrantfile 67 | # to skip installing and copying to Vagrant's shelf. 68 | # config.berkshelf.except = [] 69 | 70 | config.omnibus.version = :latest 71 | 72 | config.vm.provision :chef_solo do |chef| 73 | # chef.chef_server_url = "https://api.opscode.com/organizations/zcast" 74 | # chef.validation_client_name = "zcast-validator" 75 | # chef.validation_key_path = "/Users/cassiano/.chef/zcast-validator.pem" 76 | 77 | chef.run_list = [ 78 | "recipe[deploy_key::test]" 79 | ] 80 | end 81 | end 82 | -------------------------------------------------------------------------------- /chefignore: -------------------------------------------------------------------------------- 1 | # Put files/directories that should be ignored in this file when uploading 2 | # or sharing to the community site. 3 | # Lines that start with '# ' are comments. 4 | 5 | # OS generated files # 6 | ###################### 7 | .DS_Store 8 | Icon? 9 | nohup.out 10 | ehthumbs.db 11 | Thumbs.db 12 | 13 | # SASS # 14 | ######## 15 | .sass-cache 16 | 17 | # EDITORS # 18 | ########### 19 | \#* 20 | .#* 21 | *~ 22 | *.sw[a-z] 23 | *.bak 24 | REVISION 25 | TAGS* 26 | tmtags 27 | *_flymake.* 28 | *_flymake 29 | *.tmproj 30 | .project 31 | .settings 32 | mkmf.log 33 | *.sublime-* 34 | 35 | ## COMPILED ## 36 | ############## 37 | a.out 38 | *.o 39 | *.pyc 40 | *.so 41 | *.com 42 | *.class 43 | *.dll 44 | *.exe 45 | */rdoc/ 46 | 47 | # Testing # 48 | ########### 49 | .watchr 50 | .rspec 51 | spec/* 52 | spec/fixtures/* 53 | test/* 54 | features/* 55 | Guardfile 56 | Procfile 57 | .kitchen.yml 58 | .kitchen 59 | 60 | # SCM # 61 | ####### 62 | .git 63 | */.git 64 | .gitignore 65 | .gitmodules 66 | .gitconfig 67 | .gitattributes 68 | .svn 69 | */.bzr/* 70 | */.hg/* 71 | */.svn/* 72 | 73 | # Berkshelf # 74 | ############# 75 | Berksfile 76 | Berksfile.lock 77 | cookbooks/* 78 | tmp 79 | 80 | # Cookbooks # 81 | ############# 82 | CONTRIBUTING 83 | CHANGELOG* 84 | 85 | # Strainer # 86 | ############ 87 | Colanderfile 88 | Strainerfile 89 | .colander 90 | .strainer 91 | 92 | # Vagrant # 93 | ########### 94 | .vagrant 95 | Vagrantfile 96 | 97 | # Travis # 98 | ########## 99 | .travis.yml 100 | 101 | # Bundler # 102 | ########### 103 | Gemfile 104 | Gemfile.lock 105 | 106 | # Ignore recipes since this is a pure library cookbook 107 | recipes/* 108 | -------------------------------------------------------------------------------- /libraries/deploy_key.rb: -------------------------------------------------------------------------------- 1 | module DeployKeyCookbook 2 | class DeployKey < ChefCompat::Resource 3 | include Helpers 4 | 5 | actions :create, :add, :remove, :delete 6 | default_action :add 7 | 8 | property :label, String, name_property: true 9 | property :path, String, required: true 10 | property :deploy_key_label, String, default: nil 11 | 12 | # For OAuth: { token: token } 13 | # For user/pass: { user: user, password: password } 14 | property :credentials, Hash, required: true 15 | 16 | # should be in the format: username/repo_slug (e.g.: cassianoleal/cookbook-deploy_key) 17 | # or an integer for GitLab (e.g.: 4) 18 | property :repo, [ String, Integer ], required: true, regex: /(\w+\/\w+|\d+)/ 19 | 20 | property :owner, String, default: "root" 21 | property :group, String, default: "root" 22 | 23 | property :mode, default: 00600 24 | 25 | property :api_url, String, default: nil 26 | 27 | # Client certificate support 28 | property :client_cert, String, default: nil 29 | property :client_key, String, default: nil 30 | 31 | use_automatic_resource_name 32 | 33 | action :create do 34 | if ::File.exists?("#{new_resource.path}/#{new_resource.label}") \ 35 | and ::File.exists?("#{new_resource.path}/#{new_resource.label}.pub") 36 | Chef::Log.info("Key #{new_resource.path}/#{new_resource.label} already exists - nothing to do.") 37 | else 38 | converge_by("Generate #{new_resource}") do 39 | execute "Generate ssh key for #{new_resource.label}" do 40 | creates new_resource.label 41 | command "ssh-keygen -t rsa -q -C '' -f '#{new_resource.path}/#{new_resource.label}' -P \"\"" 42 | end 43 | end 44 | end 45 | 46 | file "#{new_resource.path}/#{new_resource.label}" do 47 | owner new_resource.owner 48 | group new_resource.group 49 | mode new_resource.mode 50 | end 51 | 52 | file "#{new_resource.path}/#{new_resource.label}.pub" do 53 | owner new_resource.owner 54 | group new_resource.group 55 | mode new_resource.mode 56 | end 57 | end 58 | 59 | action :delete do 60 | key = "#{new_resource.path}/#{new_resource.label}" 61 | 62 | [key, "#{key}.pub"].each do |f| 63 | file f do 64 | action :delete 65 | end 66 | end 67 | end 68 | 69 | action :remove do 70 | pubkey = ::File.read("#{new_resource.path}/#{new_resource.label}.pub") 71 | if get_key(pubkey) 72 | converge_by("De-register #{new_resource}") do 73 | remove_key(pubkey) 74 | end 75 | else 76 | Chef::Log.info("Deploy key #{new_resource} not present - nothing to do.") 77 | end 78 | end 79 | end 80 | end 81 | -------------------------------------------------------------------------------- /libraries/deploy_key_bitbucket.rb: -------------------------------------------------------------------------------- 1 | module DeployKeyCookbook 2 | class DeployKeyBitbucket < DeployKey 3 | include Helpers::Bitbucket 4 | 5 | use_automatic_resource_name 6 | provides :deploy_key 7 | 8 | action :add do 9 | new_resource.run_action(:create) 10 | 11 | pubkey = ::File.read("#{new_resource.path}/#{new_resource.label}.pub") 12 | if get_key(pubkey) 13 | Chef::Log.info("Deploy key #{new_resource.label} already added - nothing to do.") 14 | else 15 | converge_by("Register #{new_resource}") do 16 | add_key(new_resource.label, pubkey) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /libraries/deploy_key_github.rb: -------------------------------------------------------------------------------- 1 | module DeployKeyCookbook 2 | class DeployKeyGithub < DeployKey 3 | include Helpers::Github 4 | 5 | use_automatic_resource_name 6 | provides :deploy_key 7 | 8 | action :add do 9 | new_resource.run_action(:create) 10 | 11 | pubkey = ::File.read("#{new_resource.path}/#{new_resource.label}.pub") 12 | if get_key(pubkey) 13 | Chef::Log.info("Deploy key #{new_resource.label} already added - nothing to do.") 14 | else 15 | converge_by("Register #{new_resource}") do 16 | add_key(new_resource.label, pubkey) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /libraries/deploy_key_gitlab.rb: -------------------------------------------------------------------------------- 1 | module DeployKeyCookbook 2 | class DeployKeyGitlab < DeployKey 3 | include Helpers::Gitlab 4 | 5 | use_automatic_resource_name 6 | provides :deploy_key 7 | 8 | action :add do 9 | new_resource.run_action(:create) 10 | 11 | pubkey = ::File.read("#{new_resource.path}/#{new_resource.label}.pub") 12 | if get_key(pubkey) 13 | Chef::Log.info("Deploy key #{new_resource.label} already added - nothing to do.") 14 | else 15 | converge_by("Register #{new_resource}") do 16 | label = new_resource.deploy_key_label.nil? ? new_resource.label : new_resource.deploy_key_label 17 | 18 | add_key(label, pubkey) 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /libraries/helpers.rb: -------------------------------------------------------------------------------- 1 | # Copyright (C) 2013 Cassiano Leal 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | require 'json' 16 | require 'net/https' 17 | 18 | module DeployKeyCookbook 19 | module Helpers 20 | def auth(request) 21 | request.add_field "User-Agent", "Chef Deploy Key" 22 | request.add_field "Content-Type", "application/json" 23 | if new_resource.credentials[:token] 24 | request = add_token(request) 25 | elsif new_resource.credentials[:user] && new_resource.credentials[:password] 26 | request.basic_auth(new_resource.credentials[:user], new_resource.credentials[:password]) 27 | else 28 | raise "No credentials. Need API token or username/password combination." 29 | end 30 | request 31 | end 32 | 33 | def request(req_type, url, body = nil) 34 | req = case req_type 35 | when :get then Net::HTTP::Get.new(url.path) 36 | when :post then Net::HTTP::Post.new(url.path) 37 | when :delete then Net::HTTP::Delete.new(url.path) 38 | end 39 | req = auth(req) 40 | req.body = body 41 | http = Net::HTTP.new(url.host, url.port) 42 | if url.instance_of? URI::HTTPS 43 | http.use_ssl = true 44 | http.verify_mode = OpenSSL::SSL::VERIFY_NONE 45 | end 46 | http.request(req) 47 | end 48 | 49 | def add_key(label, key) 50 | body = { 51 | provider_specific_key_label() => "#{label} - #{node.name}", 52 | :key => key 53 | }.to_json 54 | response = request(:post, url, body) 55 | unless Net::HTTPOK === response || 56 | Net::HTTPCreated === response 57 | raise "Could not add SSH key #{new_resource.label} to repository: #{response.code} #{response.body}" 58 | end 59 | response 60 | end 61 | 62 | def remove_key(key) 63 | retrieved_key = get_key(key) 64 | key_url = url("/#{retrieved_key[retrieved_key_id()]}") 65 | response = request(:delete, key_url) 66 | unless Net::HTTPNoContent === response 67 | raise "Could not remove SSH key #{new_resource.label} from repository: #{response.code} #{response.body}" 68 | end 69 | response 70 | end 71 | 72 | def get_key(key) 73 | response = request(:get, url) 74 | unless Net::HTTPOK === response || 75 | Net::HTTPCreated === response 76 | raise "Could not get list of keys from repository: #{response.code} #{response.body}" 77 | end 78 | keys = JSON.parse response.body 79 | keys.find { |k| k["key"].strip == key.strip } 80 | end 81 | end 82 | end 83 | -------------------------------------------------------------------------------- /libraries/helpers_bitbucket.rb: -------------------------------------------------------------------------------- 1 | module DeployKeyCookbook 2 | module Helpers 3 | module Bitbucket 4 | def url(path = '') 5 | URI.parse("https://bitbucket.org/api/1.0/repositories/#{new_resource.repo}/deploy-keys#{path}") 6 | end 7 | 8 | def add_token(request) 9 | request.add_field "Authorization", "token #{new_resource.credentials[:token]}" 10 | request 11 | end 12 | 13 | def provider_specific_key_label 14 | :label 15 | end 16 | 17 | def retrieved_key_id 18 | "pk" 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /libraries/helpers_github.rb: -------------------------------------------------------------------------------- 1 | module DeployKeyCookbook 2 | module Helpers 3 | module Github 4 | def url(path = '') 5 | URI.parse("https://api.github.com/repos/#{new_resource.repo}/keys#{path}") 6 | end 7 | 8 | def add_token(request) 9 | request.add_field "Authorization", "token #{new_resource.credentials[:token]}" 10 | request 11 | end 12 | 13 | def provider_specific_key_label 14 | :title 15 | end 16 | 17 | def retrieved_key_id 18 | "id" 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /libraries/helpers_gitlab.rb: -------------------------------------------------------------------------------- 1 | module DeployKeyCookbook 2 | module Helpers 3 | module Gitlab 4 | def url(path = '') 5 | URI.parse("#{new_resource.api_url}/api/v3/projects/#{new_resource.repo}/keys#{path}") 6 | end 7 | 8 | def add_token(request) 9 | request.add_field "PRIVATE-TOKEN", new_resource.credentials[:token] 10 | request 11 | end 12 | 13 | def provider_specific_key_label 14 | :title 15 | end 16 | 17 | def retrieved_key_id 18 | "id" 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /libraries/matchers.rb: -------------------------------------------------------------------------------- 1 | if defined?(ChefSpec) 2 | 3 | def create_deploy_key(resource_name) 4 | ChefSpec::Matchers::ResourceMatcher.new(:deploy_key, :create, resource_name) 5 | end 6 | 7 | def delete_deploy_key(resource_name) 8 | ChefSpec::Matchers::ResourceMatcher.new(:deploy_key, :delete, resource_name) 9 | end 10 | 11 | def add_deploy_key(resource_name) 12 | ChefSpec::Matchers::ResourceMatcher.new(:deploy_key, :add, resource_name) 13 | end 14 | 15 | def remove_deploy_key(resource_name) 16 | ChefSpec::Matchers::ResourceMatcher.new(:deploy_key, :remove, resource_name) 17 | end 18 | 19 | end -------------------------------------------------------------------------------- /metadata.rb: -------------------------------------------------------------------------------- 1 | name "deploy_key" 2 | maintainer "Cassiano Leal" 3 | maintainer_email "cl@cassianoleal.com" 4 | license 'Apache 2.0' 5 | description 'Manage deploy keys on Github and Bitbucket' 6 | long_description IO.read(File.join(File.dirname(__FILE__), 'README.md')) 7 | version "0.3.0" 8 | --------------------------------------------------------------------------------