From 40fc4261f2e6c8eaf6e885405863e929ecbd47b3 Mon Sep 17 00:00:00 2001
From: Lukas Erlacher <erlacher@in.tum.de>
Date: Mon, 18 Aug 2014 16:46:46 +0200
Subject: [PATCH] Add system hook for ssh key changes

Add system hook for ssh key create and destroy
Update and fix documentation
Update tests
---
 CHANGELOG                                  |  1 +
 app/models/key.rb                          | 10 +++++++++
 app/services/system_hooks_service.rb       | 10 +++++++++
 doc/system_hooks/system_hooks.md           | 26 +++++++++++++++++++++-
 spec/services/system_hooks_service_spec.rb |  5 +++++
 5 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/CHANGELOG b/CHANGELOG
index a8403f048b4..c1531cb2ff2 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -12,6 +12,7 @@ v 7.3.0
   - Deprecate LDAP account takeover based on partial LDAP email / GitLab username match
   - Keyboard shortcuts for productivity (Robert Schilling)
   - API: filter issues by state (Julien Bianchi)
+  - Add system hook for ssh key changes
 
 v 7.2.0
   - Explore page
diff --git a/app/models/key.rb b/app/models/key.rb
index d59993b1905..095c73d8baf 100644
--- a/app/models/key.rb
+++ b/app/models/key.rb
@@ -29,7 +29,9 @@ class Key < ActiveRecord::Base
 
   after_create :add_to_shell
   after_create :notify_user
+  after_create :post_create_hook
   after_destroy :remove_from_shell
+  after_destroy :post_destroy_hook
 
   def strip_white_space
     self.key = key.strip unless key.blank?
@@ -56,6 +58,10 @@ class Key < ActiveRecord::Base
     NotificationService.new.new_key(self)
   end
 
+  def post_create_hook
+    SystemHooksService.new.execute_hooks_for(self, :create)
+  end
+
   def remove_from_shell
     GitlabShellWorker.perform_async(
       :remove_key,
@@ -64,6 +70,10 @@ class Key < ActiveRecord::Base
     )
   end
 
+  def post_destroy_hook
+    SystemHooksService.new.execute_hooks_for(self, :destroy)
+  end
+
   private
 
   def generate_fingerpint
diff --git a/app/services/system_hooks_service.rb b/app/services/system_hooks_service.rb
index 41014f199d5..bfc725e5eb5 100644
--- a/app/services/system_hooks_service.rb
+++ b/app/services/system_hooks_service.rb
@@ -22,6 +22,16 @@ class SystemHooksService
     }
 
     case model
+    when Key
+      data.merge!(
+        key: model.key,
+        id: model.id
+      )
+      if model.user
+        data.merge!(
+          username: model.user.username
+        )
+      end
     when Project
       owner = model.owner
 
diff --git a/doc/system_hooks/system_hooks.md b/doc/system_hooks/system_hooks.md
index 47f17c1a080..54e6e3a9e3f 100644
--- a/doc/system_hooks/system_hooks.md
+++ b/doc/system_hooks/system_hooks.md
@@ -1,6 +1,6 @@
 # System hooks
 
-Your GitLab instance can perform HTTP POST requests on the following events: `create_project`, `delete_project`, `create_user`, `delete_user` and `change_team_member`.
+Your GitLab instance can perform HTTP POST requests on the following events: `project_create`, `project_destroy`, `user_add_to_team`, `user_remove_from_team`, `user_create`, `user_destroy`, `key_create` and `key_destroy`.
 
 System hooks can be used, e.g. for logging or changing information in a LDAP server.
 
@@ -93,3 +93,27 @@ System hooks can be used, e.g. for logging or changing information in a LDAP ser
       "user_id": 41
 }
 ```
+
+**Key added**
+
+```json
+{
+    "event_name": "key_create",
+    "created_at": "2014-08-18 18:45:16 UTC",
+      "username": "root",
+           "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC58FwqHUbebw2SdT7SP4FxZ0w+lAO/erhy2ylhlcW/tZ3GY3mBu9VeeiSGoGz8hCx80Zrz+aQv28xfFfKlC8XQFpCWwsnWnQqO2Lv9bS8V1fIHgMxOHIt5Vs+9CAWGCCvUOAurjsUDoE2ALIXLDMKnJxcxD13XjWdK54j6ZXDB4syLF0C2PnAQSVY9X7MfCYwtuFmhQhKaBussAXpaVMRHltie3UYSBUUuZaB3J4cg/7TxlmxcNd+ppPRIpSZAB0NI6aOnqoBCpimscO/VpQRJMVLr3XiSYeT6HBiDXWHnIVPfQc03OGcaFqOit6p8lYKMaP/iUQLm+pgpZqrXZ9vB john@localhost",
+           "id": 4
+}
+```
+
+**Key removed**
+
+```json
+{
+    "event_name": "key_destroy",
+    "created_at": "2014-08-18 18:45:16 UTC",
+      "username": "root",
+           "key": "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC58FwqHUbebw2SdT7SP4FxZ0w+lAO/erhy2ylhlcW/tZ3GY3mBu9VeeiSGoGz8hCx80Zrz+aQv28xfFfKlC8XQFpCWwsnWnQqO2Lv9bS8V1fIHgMxOHIt5Vs+9CAWGCCvUOAurjsUDoE2ALIXLDMKnJxcxD13XjWdK54j6ZXDB4syLF0C2PnAQSVY9X7MfCYwtuFmhQhKaBussAXpaVMRHltie3UYSBUUuZaB3J4cg/7TxlmxcNd+ppPRIpSZAB0NI6aOnqoBCpimscO/VpQRJMVLr3XiSYeT6HBiDXWHnIVPfQc03OGcaFqOit6p8lYKMaP/iUQLm+pgpZqrXZ9vB john@localhost",
+            "id": 4
+}
+```
diff --git a/spec/services/system_hooks_service_spec.rb b/spec/services/system_hooks_service_spec.rb
index 3c2eec6cfd9..7497bdb0b3c 100644
--- a/spec/services/system_hooks_service_spec.rb
+++ b/spec/services/system_hooks_service_spec.rb
@@ -4,6 +4,7 @@ describe SystemHooksService do
   let (:user)          { create :user }
   let (:project)       { create :project }
   let (:users_project) { create :users_project }
+  let (:key)           { create(:key, user: user) }
 
   context 'event data' do
     it { event_data(user, :create).should include(:event_name, :name, :created_at, :email, :user_id) }
@@ -12,6 +13,8 @@ describe SystemHooksService do
     it { event_data(project, :destroy).should include(:event_name, :name, :created_at, :path, :project_id, :owner_name, :owner_email, :project_visibility) }
     it { event_data(users_project, :create).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access, :project_visibility) }
     it { event_data(users_project, :destroy).should include(:event_name, :created_at, :project_name, :project_path, :project_id, :user_name, :user_email, :project_access, :project_visibility) }
+    it { event_data(key, :create).should include(:username, :key, :id) }
+    it { event_data(key, :destroy).should include(:username, :key, :id) }
   end
 
   context 'event names' do
@@ -21,6 +24,8 @@ describe SystemHooksService do
     it { event_name(project, :destroy).should eq "project_destroy" }
     it { event_name(users_project, :create).should eq "user_add_to_team" }
     it { event_name(users_project, :destroy).should eq "user_remove_from_team" }
+    it { event_name(key, :create).should eq 'key_create' }
+    it { event_name(key, :destroy).should eq 'key_destroy' }
   end
 
   def event_data(*args)
-- 
GitLab