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

This commit is contained in:
Douwe Maan 2015-03-27 14:43:48 +01:00
parent 9157985cfc
commit edc4a56d26
16 changed files with 233 additions and 36 deletions

View file

@ -58,6 +58,7 @@ v 7.10.0 (unreleased)
- Fix "Hello @username." references not working by no longer allowing usernames to end in period.
- Archive repositories in background worker.
- 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

View file

@ -0,0 +1,45 @@
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

View file

@ -9,6 +9,8 @@ class Projects::DeployKeysController < Projects::ApplicationController
def index
@enabled_keys = @project.deploy_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
def show
@ -32,18 +34,9 @@ class Projects::DeployKeysController < Projects::ApplicationController
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
@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,
@project)
@ -52,8 +45,7 @@ class Projects::DeployKeysController < Projects::ApplicationController
def disable
@project.deploy_keys_projects.find_by(deploy_key_id: params[:id]).destroy
redirect_to namespace_project_deploy_keys_path(@project.namespace,
@project)
redirect_to :back
end
protected

View file

@ -7,6 +7,7 @@
# created_at :datetime
# updated_at :datetime
# key :text
# public :boolean default(FALSE)
# title :string(255)
# type :string(255)
# fingerprint :string(255)
@ -17,4 +18,10 @@ class DeployKey < Key
has_many :projects, through: :deploy_keys_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

View file

@ -22,6 +22,10 @@ class DeployKeysProject < ActiveRecord::Base
private
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

View file

@ -414,8 +414,16 @@ class User < ActiveRecord::Base
@ldap_identity ||= identities.find_by(["provider LIKE ?", "ldap%"])
end
def project_deploy_keys
DeployKey.in_projects(self.authorized_projects.pluck(:id))
end
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
def created_by

View file

@ -0,0 +1,27 @@
.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"

View file

@ -0,0 +1,26 @@
%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"

View file

@ -0,0 +1,34 @@
.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"

View file

@ -19,6 +19,11 @@
%i.fa.fa-group
%span
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
= link_to admin_logs_path, title: 'Logs' do
%i.fa.fa-file-text

View file

@ -5,21 +5,38 @@
%i.fa.fa-plus
Enable
- 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
%i.fa.fa-power-off
Disable
- 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
= link_to namespace_project_deploy_key_path(key_project.namespace, key_project, deploy_key) do
- if deploy_key.projects.include?(@project)
- 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
%strong= deploy_key.title
%p.light.prepend-top-10
- deploy_key.projects.map(&:name_with_namespace).each do |project_name|
%span.label.label-gray.deploy-project-label= project_name
- if deploy_key.public?
%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
Created #{time_ago_with_tooltip(deploy_key.created_at)}

View file

@ -22,11 +22,19 @@
.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
.col-md-6.available-keys
%h5
%strong Deploy keys
from projects available to you
%ul.bordered-list
= render @available_keys
- if @available_keys.blank?
.light-well
.nothing-here-block Deploy keys from projects you have access to will be displayed here
- unless @available_project_keys.blank? && @available_public_keys.any?
%h5
%strong Deploy keys
from projects you have access to
%ul.bordered-list
= render @available_project_keys
- if @available_project_keys.blank?
.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

View file

@ -145,6 +145,8 @@ Gitlab::Application.routes.draw do
end
end
resources :deploy_keys, only: [:index, :show, :new, :create, :destroy]
resources :hooks, only: [:index, :create, :destroy] do
get :test
end
@ -393,7 +395,7 @@ Gitlab::Application.routes.draw do
end
end
resources :deploy_keys, constraints: { id: /\d+/ } do
resources :deploy_keys, constraints: { id: /\d+/ }, only: [:index, :show, :new, :create] do
member do
put :enable
put :disable

View file

@ -0,0 +1,5 @@
class AddPublicToKey < ActiveRecord::Migration
def change
add_column :keys, :public, :boolean, default: false, null: false
end
end

View file

@ -132,6 +132,7 @@ ActiveRecord::Schema.define(version: 20150328132231) do
t.string "title"
t.string "type"
t.string "fingerprint"
t.boolean "public", default: false, null: false
end
add_index "keys", ["created_at", "id"], name: "index_keys_on_created_at_and_id", using: :btree

View file

@ -28,17 +28,32 @@ describe DeployKeysProject do
let(:deploy_key) { subject.deploy_key }
context "when the deploy key is only used by this project" do
it "destroys the deploy key" do
subject.destroy
context "when the deploy key is public" do
before do
deploy_key.update_attribute(:public, true)
end
expect {
deploy_key.reload
}.to raise_error(ActiveRecord::RecordNotFound)
it "doesn't destroy the deploy key" do
subject.destroy
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
context "when the deploy key is used by more than one project" do
let!(:other_project) { create(:project) }
before do