Allow admin to create public deploy keys that are accessible to any project.
This commit is contained in:
parent
9157985cfc
commit
edc4a56d26
16 changed files with 233 additions and 36 deletions
|
@ -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
|
||||
|
|
45
app/controllers/admin/deploy_keys_controller.rb
Normal file
45
app/controllers/admin/deploy_keys_controller.rb
Normal 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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
27
app/views/admin/deploy_keys/index.html.haml
Normal file
27
app/views/admin/deploy_keys/index.html.haml
Normal 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"
|
26
app/views/admin/deploy_keys/new.html.haml
Normal file
26
app/views/admin/deploy_keys/new.html.haml
Normal 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"
|
||||
|
34
app/views/admin/deploy_keys/show.html.haml
Normal file
34
app/views/admin/deploy_keys/show.html.haml
Normal 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"
|
|
@ -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
|
||||
|
|
|
@ -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)}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
5
db/migrate/20150327122227_add_public_to_key.rb
Normal file
5
db/migrate/20150327122227_add_public_to_key.rb
Normal file
|
@ -0,0 +1,5 @@
|
|||
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
|
|||
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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue