Skip to content

Commit f3ea58e

Browse files
committed
Merge branch '14284-allow-all-deploy-keys-to-be-retrieved-via-api-regardless-of-project-affiliation' into 'master'
Add /deploy_keys API to retrieve all deploy keys regardless of project affiliation ## What does this MR do? Add /deploy_keys API to retrieve all deploy keys regardless of project affiliation ## Are there points in the code the reviewer needs to double check? Is documentation clear? ## Why was this MR needed? User request ## What are the relevant issue numbers? #14284 See merge request !4426
2 parents cfa9ea6 + 0480317 commit f3ea58e

File tree

6 files changed

+159
-75
lines changed

6 files changed

+159
-75
lines changed

CHANGELOG

+2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ v 8.10.0 (unreleased)
3030
- Apply the trusted_proxies config to the rack request object for use with rack_attack
3131
- Upgrade to Rails 4.2.7. !5236
3232
- Extend exposed environment variables for CI builds
33+
- Deprecate APIs "projects/:id/keys/...". Use "projects/:id/deploy_keys/..." instead
34+
- Add API "deploy_keys" for admins to get all deploy keys
3335
- Allow to pull code with deploy key from public projects
3436
- Use limit parameter rather than hardcoded value in `ldap:check` rake task (Mike Ricketts)
3537
- Add Sidekiq queue duration to transaction metrics.

doc/api/deploy_key_multiple_projects.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,6 @@ With those IDs, add the same deploy key to all:
2424
```
2525
for project_id in 321 456 987; do
2626
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" -H "Content-Type: application/json" \
27-
--data '{"title": "my key", "key": "ssh-rsa AAAA..."}' https://gitlab.example.com/api/v3/projects/${project_id}/keys
27+
--data '{"title": "my key", "key": "ssh-rsa AAAA..."}' https://gitlab.example.com/api/v3/projects/${project_id}/deploy_keys
2828
done
2929
```

doc/api/deploy_keys.md

+40-9
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,50 @@
11
# Deploy Keys
22

3-
## List deploy keys
3+
## List all deploy keys
4+
5+
Get a list of all deploy keys across all projects.
6+
7+
```
8+
GET /deploy_keys
9+
```
10+
11+
```bash
12+
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/deploy_keys"
13+
```
14+
15+
Example response:
16+
17+
```json
18+
[
19+
{
20+
"id": 1,
21+
"title": "Public key",
22+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
23+
"created_at": "2013-10-02T10:12:29Z"
24+
},
25+
{
26+
"id": 3,
27+
"title": "Another Public key",
28+
"key": "ssh-rsa AAAAB3NzaC1yc2EAAAABJQAAAIEAiPWx6WM4lhHNedGfBpPJNPpZ7yKu+dnn1SJejgt4596k6YjzGGphH2TUxwKzxcKDKKezwkpfnxPkSMkuEspGRt/aZZ9wa++Oi7Qkr8prgHc4soW6NUlfDzpvZK2H5E7eQaSeP3SAwGmQKUFHCddNaP0L+hM7zhFNzjFvpaMgJw0=",
29+
"created_at": "2013-10-02T11:12:29Z"
30+
}
31+
]
32+
```
33+
34+
## List project deploy keys
435

536
Get a list of a project's deploy keys.
637

738
```
8-
GET /projects/:id/keys
39+
GET /projects/:id/deploy_keys
940
```
1041

1142
| Attribute | Type | Required | Description |
1243
| --------- | ---- | -------- | ----------- |
1344
| `id` | integer | yes | The ID of the project |
1445

1546
```bash
16-
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/keys"
47+
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/deploy_keys"
1748
```
1849

1950
Example response:
@@ -40,7 +71,7 @@ Example response:
4071
Get a single key.
4172

4273
```
43-
GET /projects/:id/keys/:key_id
74+
GET /projects/:id/deploy_keys/:key_id
4475
```
4576

4677
Parameters:
@@ -51,7 +82,7 @@ Parameters:
5182
| `key_id` | integer | yes | The ID of the deploy key |
5283

5384
```bash
54-
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/keys/11"
85+
curl -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/deploy_keys/11"
5586
```
5687

5788
Example response:
@@ -73,7 +104,7 @@ If the deploy key already exists in another project, it will be joined to curren
73104
project only if original one was is accessible by the same user.
74105

75106
```
76-
POST /projects/:id/keys
107+
POST /projects/:id/deploy_keys
77108
```
78109

79110
| Attribute | Type | Required | Description |
@@ -83,7 +114,7 @@ POST /projects/:id/keys
83114
| `key` | string | yes | New deploy key |
84115

85116
```bash
86-
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" -H "Content-Type: application/json" --data '{"title": "My deploy key", "key": "ssh-rsa AAAA..."}' "https://gitlab.example.com/api/v3/projects/5/keys/"
117+
curl -X POST -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" -H "Content-Type: application/json" --data '{"title": "My deploy key", "key": "ssh-rsa AAAA..."}' "https://gitlab.example.com/api/v3/projects/5/deploy_keys/"
87118
```
88119

89120
Example response:
@@ -102,7 +133,7 @@ Example response:
102133
Delete a deploy key from a project
103134

104135
```
105-
DELETE /projects/:id/keys/:key_id
136+
DELETE /projects/:id/deploy_keys/:key_id
106137
```
107138

108139
| Attribute | Type | Required | Description |
@@ -111,7 +142,7 @@ DELETE /projects/:id/keys/:key_id
111142
| `key_id` | integer | yes | The ID of the deploy key |
112143

113144
```bash
114-
curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/keys/13"
145+
curl -X DELETE -H "PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK" "https://gitlab.example.com/api/v3/projects/5/deploy_keys/13"
115146
```
116147

117148
Example response:

lib/api/deploy_keys.rb

+66-53
Original file line numberDiff line numberDiff line change
@@ -2,74 +2,87 @@ module API
22
# Projects API
33
class DeployKeys < Grape::API
44
before { authenticate! }
5-
before { authorize_admin_project }
5+
6+
get "deploy_keys" do
7+
authenticated_as_admin!
8+
9+
keys = DeployKey.all
10+
present keys, with: Entities::SSHKey
11+
end
612

713
resource :projects do
8-
# Get a specific project's keys
9-
#
10-
# Example Request:
11-
# GET /projects/:id/keys
12-
get ":id/keys" do
13-
present user_project.deploy_keys, with: Entities::SSHKey
14-
end
14+
before { authorize_admin_project }
1515

16-
# Get single key owned by currently authenticated user
16+
# Routing "projects/:id/keys/..." is DEPRECATED and WILL BE REMOVED in version 9.0
17+
# Use "projects/:id/deploy_keys/..." instead.
1718
#
18-
# Example Request:
19-
# GET /projects/:id/keys/:id
20-
get ":id/keys/:key_id" do
21-
key = user_project.deploy_keys.find params[:key_id]
22-
present key, with: Entities::SSHKey
23-
end
19+
%w(keys deploy_keys).each do |path|
20+
# Get a specific project's deploy keys
21+
#
22+
# Example Request:
23+
# GET /projects/:id/deploy_keys
24+
get ":id/#{path}" do
25+
present user_project.deploy_keys, with: Entities::SSHKey
26+
end
2427

25-
# Add new ssh key to currently authenticated user
26-
# If deploy key already exists - it will be joined to project
27-
# but only if original one was is accessible by same user
28-
#
29-
# Parameters:
30-
# key (required) - New SSH Key
31-
# title (required) - New SSH Key's title
32-
# Example Request:
33-
# POST /projects/:id/keys
34-
post ":id/keys" do
35-
attrs = attributes_for_keys [:title, :key]
28+
# Get single deploy key owned by currently authenticated user
29+
#
30+
# Example Request:
31+
# GET /projects/:id/deploy_keys/:key_id
32+
get ":id/#{path}/:key_id" do
33+
key = user_project.deploy_keys.find params[:key_id]
34+
present key, with: Entities::SSHKey
35+
end
3636

37-
if attrs[:key].present?
38-
attrs[:key].strip!
37+
# Add new deploy key to currently authenticated user
38+
# If deploy key already exists - it will be joined to project
39+
# but only if original one was accessible by same user
40+
#
41+
# Parameters:
42+
# key (required) - New deploy Key
43+
# title (required) - New deploy Key's title
44+
# Example Request:
45+
# POST /projects/:id/deploy_keys
46+
post ":id/#{path}" do
47+
attrs = attributes_for_keys [:title, :key]
3948

40-
# check if key already exist in project
41-
key = user_project.deploy_keys.find_by(key: attrs[:key])
42-
if key
43-
present key, with: Entities::SSHKey
44-
return
49+
if attrs[:key].present?
50+
attrs[:key].strip!
51+
52+
# check if key already exist in project
53+
key = user_project.deploy_keys.find_by(key: attrs[:key])
54+
if key
55+
present key, with: Entities::SSHKey
56+
next
57+
end
58+
59+
# Check for available deploy keys in other projects
60+
key = current_user.accessible_deploy_keys.find_by(key: attrs[:key])
61+
if key
62+
user_project.deploy_keys << key
63+
present key, with: Entities::SSHKey
64+
next
65+
end
4566
end
4667

47-
# Check for available deploy keys in other projects
48-
key = current_user.accessible_deploy_keys.find_by(key: attrs[:key])
49-
if key
50-
user_project.deploy_keys << key
68+
key = DeployKey.new attrs
69+
70+
if key.valid? && user_project.deploy_keys << key
5171
present key, with: Entities::SSHKey
52-
return
72+
else
73+
render_validation_error!(key)
5374
end
5475
end
5576

56-
key = DeployKey.new attrs
57-
58-
if key.valid? && user_project.deploy_keys << key
59-
present key, with: Entities::SSHKey
60-
else
61-
render_validation_error!(key)
77+
# Delete existing deploy key of currently authenticated user
78+
#
79+
# Example Request:
80+
# DELETE /projects/:id/deploy_keys/:key_id
81+
delete ":id/#{path}/:key_id" do
82+
key = user_project.deploy_keys.find params[:key_id]
83+
key.destroy
6284
end
6385
end
64-
65-
# Delete existed ssh key of currently authenticated user
66-
#
67-
# Example Request:
68-
# DELETE /projects/:id/keys/:id
69-
delete ":id/keys/:key_id" do
70-
key = user_project.deploy_keys.find params[:key_id]
71-
key.destroy
72-
end
7386
end
7487
end
7588
end

spec/requests/api/deploy_keys.rb

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
require 'spec_helper'
2+
3+
describe API::API, api: true do
4+
include ApiHelpers
5+
6+
let(:user) { create(:user) }
7+
let(:project) { create(:project, creator_id: user.id) }
8+
let!(:deploy_keys_project) { create(:deploy_keys_project, project: project) }
9+
let(:admin) { create(:admin) }
10+
11+
describe 'GET /deploy_keys' do
12+
before { admin }
13+
14+
context 'when unauthenticated' do
15+
it 'should return authentication error' do
16+
get api('/deploy_keys')
17+
expect(response.status).to eq(401)
18+
end
19+
end
20+
21+
context 'when authenticated as non-admin user' do
22+
it 'should return a 403 error' do
23+
get api('/deploy_keys', user)
24+
expect(response.status).to eq(403)
25+
end
26+
end
27+
28+
context 'when authenticated as admin' do
29+
it 'should return all deploy keys' do
30+
get api('/deploy_keys', admin)
31+
expect(response.status).to eq(200)
32+
33+
expect(json_response).to be_an Array
34+
expect(json_response.first['id']).to eq(deploy_keys_project.deploy_key.id)
35+
end
36+
end
37+
end
38+
end

spec/requests/api/projects_spec.rb

+12-12
Original file line numberDiff line numberDiff line change
@@ -647,33 +647,33 @@
647647
let(:deploy_keys_project) { create(:deploy_keys_project, project: project) }
648648
let(:deploy_key) { deploy_keys_project.deploy_key }
649649

650-
describe 'GET /projects/:id/keys' do
650+
describe 'GET /projects/:id/deploy_keys' do
651651
before { deploy_key }
652652

653653
it 'should return array of ssh keys' do
654-
get api("/projects/#{project.id}/keys", user)
654+
get api("/projects/#{project.id}/deploy_keys", user)
655655
expect(response).to have_http_status(200)
656656
expect(json_response).to be_an Array
657657
expect(json_response.first['title']).to eq(deploy_key.title)
658658
end
659659
end
660660

661-
describe 'GET /projects/:id/keys/:key_id' do
661+
describe 'GET /projects/:id/deploy_keys/:key_id' do
662662
it 'should return a single key' do
663-
get api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
663+
get api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", user)
664664
expect(response).to have_http_status(200)
665665
expect(json_response['title']).to eq(deploy_key.title)
666666
end
667667

668668
it 'should return 404 Not Found with invalid ID' do
669-
get api("/projects/#{project.id}/keys/404", user)
669+
get api("/projects/#{project.id}/deploy_keys/404", user)
670670
expect(response).to have_http_status(404)
671671
end
672672
end
673673

674-
describe 'POST /projects/:id/keys' do
674+
describe 'POST /projects/:id/deploy_keys' do
675675
it 'should not create an invalid ssh key' do
676-
post api("/projects/#{project.id}/keys", user), { title: 'invalid key' }
676+
post api("/projects/#{project.id}/deploy_keys", user), { title: 'invalid key' }
677677
expect(response).to have_http_status(400)
678678
expect(json_response['message']['key']).to eq([
679679
'can\'t be blank',
@@ -683,7 +683,7 @@
683683
end
684684

685685
it 'should not create a key without title' do
686-
post api("/projects/#{project.id}/keys", user), key: 'some key'
686+
post api("/projects/#{project.id}/deploy_keys", user), key: 'some key'
687687
expect(response).to have_http_status(400)
688688
expect(json_response['message']['title']).to eq([
689689
'can\'t be blank',
@@ -694,22 +694,22 @@
694694
it 'should create new ssh key' do
695695
key_attrs = attributes_for :key
696696
expect do
697-
post api("/projects/#{project.id}/keys", user), key_attrs
697+
post api("/projects/#{project.id}/deploy_keys", user), key_attrs
698698
end.to change{ project.deploy_keys.count }.by(1)
699699
end
700700
end
701701

702-
describe 'DELETE /projects/:id/keys/:key_id' do
702+
describe 'DELETE /projects/:id/deploy_keys/:key_id' do
703703
before { deploy_key }
704704

705705
it 'should delete existing key' do
706706
expect do
707-
delete api("/projects/#{project.id}/keys/#{deploy_key.id}", user)
707+
delete api("/projects/#{project.id}/deploy_keys/#{deploy_key.id}", user)
708708
end.to change{ project.deploy_keys.count }.by(-1)
709709
end
710710

711711
it 'should return 404 Not Found with invalid ID' do
712-
delete api("/projects/#{project.id}/keys/404", user)
712+
delete api("/projects/#{project.id}/deploy_keys/404", user)
713713
expect(response).to have_http_status(404)
714714
end
715715
end

0 commit comments

Comments
 (0)