Commit edc4a56d authored by Douwe Maan's avatar Douwe Maan

Allow admin to create public deploy keys that are accessible to any project.

parent 9157985c
...@@ -58,6 +58,7 @@ v 7.10.0 (unreleased) ...@@ -58,6 +58,7 @@ v 7.10.0 (unreleased)
- Fix "Hello @username." references not working by no longer allowing usernames to end in period. - Fix "Hello @username." references not working by no longer allowing usernames to end in period.
- Archive repositories in background worker. - Archive repositories in background worker.
- Import GitHub, Bitbucket or GitLab.com projects owned by authenticated user into current namespace. - Import GitHub, Bitbucket or GitLab.com projects owned by authenticated user into current namespace.
- Allow admin to create public deploy keys that are accessible to any project.
v 7.9.2 v 7.9.2
......
class Admin::DeployKeysController < Admin::ApplicationController
before_filter :deploy_key, only: [:show, :destroy]
def index
@deploy_keys = DeployKey.are_public
end
def show
end
def new
@deploy_key = DeployKey.new(public: true)
end
def create
@deploy_key = DeployKey.new(deploy_key_params)
@deploy_key.public = true
if @deploy_key.save
redirect_to admin_deploy_keys_path
else
render "new"
end
end
def destroy
deploy_key.destroy
respond_to do |format|
format.html { redirect_to admin_deploy_keys_path }
format.json { head :ok }
end
end
protected
def deploy_key
@deploy_key ||= DeployKey.find(params[:id])
end
def deploy_key_params
params.require(:deploy_key).permit(:key, :title)
end
end
...@@ -9,6 +9,8 @@ class Projects::DeployKeysController < Projects::ApplicationController ...@@ -9,6 +9,8 @@ class Projects::DeployKeysController < Projects::ApplicationController
def index def index
@enabled_keys = @project.deploy_keys @enabled_keys = @project.deploy_keys
@available_keys = available_keys - @enabled_keys @available_keys = available_keys - @enabled_keys
@available_project_keys = current_user.project_deploy_keys - @enabled_keys
@available_public_keys = DeployKey.are_public - @available_project_keys - @enabled_keys
end end
def show def show
...@@ -32,18 +34,9 @@ class Projects::DeployKeysController < Projects::ApplicationController ...@@ -32,18 +34,9 @@ class Projects::DeployKeysController < Projects::ApplicationController
end end
end end
def destroy
@key = @project.deploy_keys.find(params[:id])
@key.destroy
respond_to do |format|
format.html { redirect_to namespace_project_deploy_keys_path(@project.namespace, @project) }
format.js { render nothing: true }
end
end
def enable def enable
@project.deploy_keys << available_keys.find(params[:id]) @key = current_user.accessible_deploy_keys.find(params[:id])
@project.deploy_keys << @key
redirect_to namespace_project_deploy_keys_path(@project.namespace, redirect_to namespace_project_deploy_keys_path(@project.namespace,
@project) @project)
...@@ -52,8 +45,7 @@ class Projects::DeployKeysController < Projects::ApplicationController ...@@ -52,8 +45,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
def disable def disable
@project.deploy_keys_projects.find_by(deploy_key_id: params[:id]).destroy @project.deploy_keys_projects.find_by(deploy_key_id: params[:id]).destroy
redirect_to namespace_project_deploy_keys_path(@project.namespace, redirect_to :back
@project)
end end
protected protected
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
# created_at :datetime # created_at :datetime
# updated_at :datetime # updated_at :datetime
# key :text # key :text
# public :boolean default(FALSE)
# title :string(255) # title :string(255)
# type :string(255) # type :string(255)
# fingerprint :string(255) # fingerprint :string(255)
...@@ -17,4 +18,10 @@ class DeployKey < Key ...@@ -17,4 +18,10 @@ class DeployKey < Key
has_many :projects, through: :deploy_keys_projects has_many :projects, through: :deploy_keys_projects
scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) } scope :in_projects, ->(projects) { joins(:deploy_keys_projects).where('deploy_keys_projects.project_id in (?)', projects) }
scope :are_public, -> { where(public: true) }
scope :are_private, -> { where(public: false) }
def private?
!public?
end
end end
...@@ -22,6 +22,10 @@ class DeployKeysProject < ActiveRecord::Base ...@@ -22,6 +22,10 @@ class DeployKeysProject < ActiveRecord::Base
private private
def destroy_orphaned_deploy_key def destroy_orphaned_deploy_key
self.deploy_key.destroy if self.deploy_key.deploy_keys_projects.length == 0 # Public deploy keys are never automatically deleted
return if self.deploy_key.public?
return if self.deploy_key.deploy_keys_projects.length > 0
self.deploy_key.destroy
end end
end end
...@@ -414,8 +414,16 @@ class User < ActiveRecord::Base ...@@ -414,8 +414,16 @@ class User < ActiveRecord::Base
@ldap_identity ||= identities.find_by(["provider LIKE ?", "ldap%"]) @ldap_identity ||= identities.find_by(["provider LIKE ?", "ldap%"])
end end
def project_deploy_keys
DeployKey.in_projects(self.authorized_projects.pluck(:id))
end
def accessible_deploy_keys def accessible_deploy_keys
DeployKey.in_projects(self.authorized_projects.pluck(:id)).uniq @accessible_deploy_keys ||= begin
key_ids = project_deploy_keys.pluck(:id)
key_ids.push(*DeployKey.are_public.pluck(:id))
DeployKey.where(id: key_ids)
end
end end
def created_by def created_by
......
.panel.panel-default
.panel-heading
Public deploy keys (#{@deploy_keys.count})
.panel-head-actions
= link_to 'New Deploy Key', new_admin_deploy_key_path, class: "btn btn-new btn-sm"
- if @deploy_keys.any?
%table.table
%thead.panel-heading
%tr
%th Title
%th Fingerprint
%th Added at
%th
%tbody
- @deploy_keys.each do |deploy_key|
%tr
%td
= link_to admin_deploy_key_path(deploy_key) do
%strong= deploy_key.title
%td
%span
(#{deploy_key.fingerprint})
%td
%span.cgray
added #{time_ago_with_tooltip(deploy_key.created_at)}
%td
= link_to 'Remove', admin_deploy_key_path(deploy_key), data: { confirm: 'Are you sure?'}, method: :delete, class: "btn btn-sm btn-remove delete-key pull-right"
%h3.page-title New public deploy key
%hr
%div
= form_for [:admin, @deploy_key], html: { class: 'deploy-key-form form-horizontal' } do |f|
-if @deploy_key.errors.any?
.alert.alert-danger
%ul
- @deploy_key.errors.full_messages.each do |msg|
%li= msg
.form-group
= f.label :title, class: "control-label"
.col-sm-10= f.text_field :title, class: 'form-control'
.form-group
= f.label :key, class: "control-label"
.col-sm-10
%p.light
Paste a machine public key here. Read more about how to generate it
= link_to "here", help_page_path("ssh", "README")
= f.text_area :key, class: "form-control thin_area", rows: 5
.form-actions
= f.submit 'Create', class: "btn-create btn"
= link_to "Cancel", admin_deploy_keys_path, class: "btn btn-cancel"
.row
.col-md-4
.panel.panel-default
.panel-heading
Deploy Key
%ul.well-list
%li
%span.light Title:
%strong= @deploy_key.title
%li
%span.light Created on:
%strong= @deploy_key.created_at.stamp("Aug 21, 2011")
.panel.panel-default
.panel-heading Projects (#{@deploy_key.deploy_keys_projects.count})
- if @deploy_key.deploy_keys_projects.any?
%ul.well-list
- @deploy_key.projects.each do |project|
%li
%span
%strong
= link_to project.name_with_namespace, [:admin, project.namespace.becomes(Namespace), project]
.pull-right
= link_to disable_namespace_project_deploy_key_path(project.namespace, project, @deploy_key), data: { confirm: "Are you sure?" }, method: :put, class: "btn-xs btn btn-remove", title: 'Remove deploy key from project' do
%i.fa.fa-times.fa-inverse
.col-md-8
%p
%span.light Fingerprint:
%strong= @deploy_key.fingerprint
%pre.well-pre
= @deploy_key.key
.pull-right
= link_to 'Remove', admin_deploy_key_path(@deploy_key), data: {confirm: 'Are you sure?'}, method: :delete, class: "btn btn-remove delete-key"
...@@ -19,6 +19,11 @@ ...@@ -19,6 +19,11 @@
%i.fa.fa-group %i.fa.fa-group
%span %span
Groups Groups
= nav_link(controller: :deploy_keys) do
= link_to admin_deploy_keys_path, title: 'Deploy Keys' do
%i.fa.fa-key
%span
Deploy Keys
= nav_link(controller: :logs) do = nav_link(controller: :logs) do
= link_to admin_logs_path, title: 'Logs' do = link_to admin_logs_path, title: 'Logs' do
%i.fa.fa-file-text %i.fa.fa-file-text
......
...@@ -5,21 +5,38 @@ ...@@ -5,21 +5,38 @@
%i.fa.fa-plus %i.fa.fa-plus
Enable Enable
- else - else
- if deploy_key.projects.count > 1 - if deploy_key.projects.count > 1 || deploy_key.public?
= link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do = link_to disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), class: 'btn btn-sm', method: :put do
%i.fa.fa-power-off %i.fa.fa-power-off
Disable Disable
- else - else
= link_to 'Remove', namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :delete, class: "btn btn-remove delete-key btn-sm pull-right" = link_to 'Remove', disable_namespace_project_deploy_key_path(@project.namespace, @project, deploy_key), data: { confirm: 'You are going to remove deploy key. Are you sure?'}, method: :put, class: "btn btn-remove delete-key btn-sm pull-right"
- key_project = deploy_key.projects.include?(@project) ? @project : deploy_key.projects.first - if deploy_key.projects.include?(@project)
= link_to namespace_project_deploy_key_path(key_project.namespace, key_project, deploy_key) do - key_project = @project
- else
- key_project = deploy_key.projects.find { |project| can?(current_user, :read_project, project) }
- if key_project
= link_to namespace_project_deploy_key_path(key_project.namespace, key_project, deploy_key) do
%i.fa.fa-key
%strong= deploy_key.title
- else
%i.fa.fa-key %i.fa.fa-key
%strong= deploy_key.title %strong= deploy_key.title
%p.light.prepend-top-10 %p.light.prepend-top-10
- deploy_key.projects.map(&:name_with_namespace).each do |project_name| - if deploy_key.public?
%span.label.label-gray.deploy-project-label= project_name %span.label.label-info.deploy-project-label
Public deploy key
- deploy_key.projects.each do |project|
- if can?(current_user, :read_project, project)
%span.label.label-gray.deploy-project-label
= link_to namespace_project_path(project.namespace, project) do
= project.name_with_namespace
%small.pull-right %small.pull-right
Created #{time_ago_with_tooltip(deploy_key.created_at)} Created #{time_ago_with_tooltip(deploy_key.created_at)}
...@@ -22,11 +22,19 @@ ...@@ -22,11 +22,19 @@
.light-well .light-well
.nothing-here-block Create a #{link_to 'new deploy key', new_namespace_project_deploy_key_path(@project.namespace, @project)} or add an existing one .nothing-here-block Create a #{link_to 'new deploy key', new_namespace_project_deploy_key_path(@project.namespace, @project)} or add an existing one
.col-md-6.available-keys .col-md-6.available-keys
%h5 - unless @available_project_keys.blank? && @available_public_keys.any?
%strong Deploy keys %h5
from projects available to you %strong Deploy keys
%ul.bordered-list from projects you have access to
= render @available_keys %ul.bordered-list
- if @available_keys.blank? = render @available_project_keys
.light-well - if @available_project_keys.blank?
.nothing-here-block Deploy keys from projects you have access to will be displayed here .light-well
.nothing-here-block Deploy keys from projects you have access to will be displayed here
- if @available_public_keys.any?
%h5
%strong Public deploy keys
available to any project
%ul.bordered-list
= render @available_public_keys
...@@ -145,6 +145,8 @@ Gitlab::Application.routes.draw do ...@@ -145,6 +145,8 @@ Gitlab::Application.routes.draw do
end end
end end
resources :deploy_keys, only: [:index, :show, :new, :create, :destroy]
resources :hooks, only: [:index, :create, :destroy] do resources :hooks, only: [:index, :create, :destroy] do
get :test get :test
end end
...@@ -393,7 +395,7 @@ Gitlab::Application.routes.draw do ...@@ -393,7 +395,7 @@ Gitlab::Application.routes.draw do
end end
end end
resources :deploy_keys, constraints: { id: /\d+/ } do resources :deploy_keys, constraints: { id: /\d+/ }, only: [:index, :show, :new, :create] do
member do member do
put :enable put :enable
put :disable put :disable
......
class AddPublicToKey < ActiveRecord::Migration
def change
add_column :keys, :public, :boolean, default: false, null: false
end
end
...@@ -132,6 +132,7 @@ ActiveRecord::Schema.define(version: 20150328132231) do ...@@ -132,6 +132,7 @@ ActiveRecord::Schema.define(version: 20150328132231) do
t.string "title" t.string "title"
t.string "type" t.string "type"
t.string "fingerprint" t.string "fingerprint"
t.boolean "public", default: false, null: false
end end
add_index "keys", ["created_at", "id"], name: "index_keys_on_created_at_and_id", using: :btree add_index "keys", ["created_at", "id"], name: "index_keys_on_created_at_and_id", using: :btree
......
...@@ -28,17 +28,32 @@ describe DeployKeysProject do ...@@ -28,17 +28,32 @@ describe DeployKeysProject do
let(:deploy_key) { subject.deploy_key } let(:deploy_key) { subject.deploy_key }
context "when the deploy key is only used by this project" do context "when the deploy key is only used by this project" do
it "destroys the deploy key" do context "when the deploy key is public" do
subject.destroy before do
deploy_key.update_attribute(:public, true)
end
expect { it "doesn't destroy the deploy key" do
deploy_key.reload subject.destroy
}.to raise_error(ActiveRecord::RecordNotFound)
expect {
deploy_key.reload
}.not_to raise_error(ActiveRecord::RecordNotFound)
end
end
context "when the deploy key is private" do
it "destroys the deploy key" do
subject.destroy
expect {
deploy_key.reload
}.to raise_error(ActiveRecord::RecordNotFound)
end
end end
end end
context "when the deploy key is used by more than one project" do context "when the deploy key is used by more than one project" do
let!(:other_project) { create(:project) } let!(:other_project) { create(:project) }
before do before do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment