Commit dd055201 authored by Mathieu Parent's avatar Mathieu Parent

Add Debian endpoint for distribution key

Changelog: added
parent 1ec7ca07
......@@ -107,6 +107,43 @@ Example response:
}
```
## Single Debian group distribution key
Gets a single Debian group distribution key.
```plaintext
GET /groups/:id/debian_distributions/:codename/key.asc
```
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the group](../index.md#namespaced-path-encoding) owned by the authenticated user. |
| `codename` | integer | yes | The `codename` of a distribution. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/groups/5/debian_distributions/unstable/key.asc"
```
Example response:
```plaintext
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: Alice's OpenPGP certificate
Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html
mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
=iIGO
-----END PGP PUBLIC KEY BLOCK-----
```
## Create a Debian group distribution
Creates a Debian group distribution.
......
......@@ -106,6 +106,43 @@ Example response:
}
```
## Single Debian project distribution key
Gets a single Debian project distribution key.
```plaintext
GET /projects/:id/debian_distributions/:codename/key.asc
```
| Attribute | Type | Required | Description |
| ---------- | -------------- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project](../index.md#namespaced-path-encoding) owned by the authenticated user. |
| `codename` | integer | yes | The `codename` of a distribution. |
```shell
curl --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/5/debian_distributions/unstable/key.asc"
```
Example response:
```plaintext
-----BEGIN PGP PUBLIC KEY BLOCK-----
Comment: Alice's OpenPGP certificate
Comment: https://www.ietf.org/id/draft-bre-openpgp-samples-01.html
mDMEXEcE6RYJKwYBBAHaRw8BAQdArjWwk3FAqyiFbFBKT4TzXcVBqPTB3gmzlC/U
b7O1u120JkFsaWNlIExvdmVsYWNlIDxhbGljZUBvcGVucGdwLmV4YW1wbGU+iJAE
ExYIADgCGwMFCwkIBwIGFQoJCAsCBBYCAwECHgECF4AWIQTrhbtfozp14V6UTmPy
MVUMT0fjjgUCXaWfOgAKCRDyMVUMT0fjjukrAPoDnHBSogOmsHOsd9qGsiZpgRnO
dypvbm+QtXZqth9rvwD9HcDC0tC+PHAsO7OTh1S1TC9RiJsvawAfCPaQZoed8gK4
OARcRwTpEgorBgEEAZdVAQUBAQdAQv8GIa2rSTzgqbXCpDDYMiKRVitCsy203x3s
E9+eviIDAQgHiHgEGBYIACAWIQTrhbtfozp14V6UTmPyMVUMT0fjjgUCXEcE6QIb
DAAKCRDyMVUMT0fjjlnQAQDFHUs6TIcxrNTtEZFjUFm1M0PJ1Dng/cDW4xN80fsn
0QEA22Kr7VkCjeAEC08VSTeV+QFsmz55/lntWkwYWhmvOgE=
=iIGO
-----END PGP PUBLIC KEY BLOCK-----
```
## Create a Debian project distribution
Creates a Debian project distribution.
......
......@@ -79,10 +79,10 @@ packages on the group level, create a distribution with the same `codename`.
To create a project-level distribution:
```shell
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions?codename=unstable"
curl --request POST --header "PRIVATE-TOKEN: <your_access_token>" "https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions?codename=<codename>"
```
Example response:
Example response with `codename=unstable`:
```json
{
......@@ -146,10 +146,23 @@ To install a package:
| sudo tee /etc/apt/auth.conf.d/gitlab_project.conf
```
Download your distribution key:
```shell
sudo mkdir -p /usr/local/share/keyrings
curl --header "PRIVATE-TOKEN: <your_access_token>" \
"https://gitlab.example.com/api/v4/projects/<project_id>/debian_distributions/<codename>/key.asc" \
| \
gpg --dearmor \
| \
sudo tee /usr/local/share/keyrings/<codename>-archive-keyring.gpg \
> /dev/null
```
Add your project as a source:
```shell
echo 'deb [trusted=yes] https://gitlab.example.com/api/v4/projects/<project_id>/packages/debian <codename> <component1> <component2>' \
echo 'deb [ signed-by=/usr/local/share/keyrings/<codename>-archive-keyring.gpg ] https://gitlab.example.com/api/v4/projects/<project_id>/packages/debian <codename> <component1> <component2>' \
| sudo tee /etc/apt/sources.list.d/gitlab_project.list
sudo apt-get update
```
......
......@@ -15,6 +15,12 @@ module API
helpers ::API::Helpers::Packages::BasicAuthHelpers
include ::API::Helpers::Authentication
helpers do
def distribution
::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last || not_found!('Distribution')
end
end
namespace 'debian_distributions' do
helpers do
params :optional_distribution_params do
......@@ -36,6 +42,14 @@ module API
end
end
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
.sent_through(:http_basic_auth)
......@@ -59,12 +73,12 @@ module API
distribution_params = declared_params(include_missing: false)
result = ::Packages::Debian::CreateDistributionService.new(project_or_group, current_user, distribution_params).execute
distribution = result.payload[:distribution]
created_distribution = result.payload[:distribution]
if result.success?
present distribution, with: ::API::Entities::Packages::Debian::Distribution
present created_distribution, with: ::API::Entities::Packages::Debian::Distribution
else
render_validation_error!(distribution)
render_validation_error!(created_distribution)
end
end
......@@ -100,11 +114,28 @@ module API
get '/:codename' do
authorize_read_package!(project_or_group)
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
present distribution, with: ::API::Entities::Packages::Debian::Distribution
end
# GET {projects|groups}/:id/debian_distributions/:codename/key
desc 'Get a Debian Distribution Key' do
detail 'This feature was introduced in 14.4'
success ::API::Entities::Packages::Debian::Distribution
end
params do
requires :codename, type: String, regexp: Gitlab::Regex.debian_distribution_regex, desc: 'The Debian Codename'
end
get '/:codename/key.asc' do
authorize_read_package!(project_or_group)
content_type 'text/plain'
env['api.format'] = :binary
header 'Content-Disposition', "attachment; filename*=UTF-8''#{CGI.escape(params[:codename])}.asc"
distribution.key&.public_key || not_found!('Distribution key')
end
# PUT {projects|groups}/:id/debian_distributions/:codename
desc 'Update a Debian Distribution' do
detail 'This feature was introduced in 14.0'
......@@ -118,15 +149,14 @@ module API
put '/:codename' do
authorize_create_package!(project_or_group)
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
distribution_params = declared_params(include_missing: false).except(:codename)
result = ::Packages::Debian::UpdateDistributionService.new(distribution, distribution_params).execute
distribution = result.payload[:distribution]
updated_distribution = result.payload[:distribution]
if result.success?
present distribution, with: ::API::Entities::Packages::Debian::Distribution
present updated_distribution, with: ::API::Entities::Packages::Debian::Distribution
else
render_validation_error!(distribution)
render_validation_error!(updated_distribution)
end
end
......@@ -142,8 +172,6 @@ module API
delete '/:codename' do
authorize_destroy_package!(project_or_group)
distribution = ::Packages::Debian::DistributionsFinder.new(project_or_group, codename: params[:codename]).execute.last!
accepted! if distribution.destroy
render_api_error!('Failed to delete distribution', 400)
......
......@@ -43,11 +43,6 @@ module API
end
end
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
.sent_through(:http_basic_auth)
end
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
......@@ -56,6 +51,11 @@ module API
render_api_error!(e.message, 400)
end
authenticate_with do |accept|
accept.token_types(:personal_access_token, :deploy_token, :job_token)
.sent_through(:http_basic_auth)
end
format :txt
content_type :txt, 'text/plain'
......
......@@ -32,7 +32,7 @@ module API
namespace ':id/-/packages/debian' do
include ::API::Concerns::Packages::DebianPackageEndpoints
# GET groups/:id/packages/debian/pool/:distribution/:project_id/:letter/:package_name/:package_version/:file_name
# GET groups/:id/-/packages/debian/pool/:distribution/:project_id/:letter/:package_name/:package_version/:file_name
params do
requires :project_id, type: Integer, desc: 'The Project Id'
use :shared_package_file_params
......
......@@ -7,14 +7,6 @@ module API
end
resource :groups, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
after_validation do
require_packages_enabled!
......
......@@ -7,14 +7,6 @@ module API
end
resource :projects, requirements: API::NAMESPACE_OR_PROJECT_REQUIREMENTS do
rescue_from ArgumentError do |e|
render_api_error!(e.message, 400)
end
rescue_from ActiveRecord::RecordInvalid do |e|
render_api_error!(e.message, 400)
end
after_validation do
require_packages_enabled!
......
......@@ -26,6 +26,12 @@ RSpec.describe API::GroupDebianDistributions do
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^{.*"codename":"existing-codename",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/, authenticate_non_public: false
end
describe 'GET groups/:id/-/debian_distributions/:codename/key.asc' do
let(:url) { "/groups/#{container.id}/-/debian_distributions/#{distribution.codename}/key.asc" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^-----BEGIN PGP PUBLIC KEY BLOCK-----/, authenticate_non_public: false
end
describe 'PUT groups/:id/-/debian_distributions/:codename' do
let(:method) { :put }
let(:url) { "/groups/#{container.id}/-/debian_distributions/#{distribution.codename}" }
......
......@@ -32,6 +32,12 @@ RSpec.describe API::ProjectDebianDistributions do
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^{.*"codename":"existing-codename\",.*"components":\["existing-component"\],.*"architectures":\["all","existing-arch"\]/, authenticate_non_public: false
end
describe 'GET projects/:id/debian_distributions/:codename/key.asc' do
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}/key.asc" }
it_behaves_like 'Debian repository read endpoint', 'GET request', :success, /^-----BEGIN PGP PUBLIC KEY BLOCK-----/, authenticate_non_public: false
end
describe 'PUT projects/:id/debian_distributions/:codename' do
let(:method) { :put }
let(:url) { "/projects/#{container.id}/debian_distributions/#{distribution.codename}" }
......
......@@ -13,12 +13,14 @@ RSpec.shared_context 'Debian repository shared context' do |container_type, can_
let_it_be(:personal_access_token, freeze: true) { create(:personal_access_token, user: user) }
let_it_be(:private_distribution, freeze: true) { create("debian_#{container_type}_distribution", :with_file, container: private_container, codename: 'existing-codename') }
let_it_be(:private_distribution_key, freeze: true) { create("debian_#{container_type}_distribution_key", distribution: private_distribution) }
let_it_be(:private_component, freeze: true) { create("debian_#{container_type}_component", distribution: private_distribution, name: 'existing-component') }
let_it_be(:private_architecture_all, freeze: true) { create("debian_#{container_type}_architecture", distribution: private_distribution, name: 'all') }
let_it_be(:private_architecture, freeze: true) { create("debian_#{container_type}_architecture", distribution: private_distribution, name: 'existing-arch') }
let_it_be(:private_component_file) { create("debian_#{container_type}_component_file", component: private_component, architecture: private_architecture) }
let_it_be(:public_distribution, freeze: true) { create("debian_#{container_type}_distribution", :with_file, container: public_container, codename: 'existing-codename') }
let_it_be(:public_distribution_key, freeze: true) { create("debian_#{container_type}_distribution_key", distribution: public_distribution) }
let_it_be(:public_component, freeze: true) { create("debian_#{container_type}_component", distribution: public_distribution, name: 'existing-component') }
let_it_be(:public_architecture_all, freeze: true) { create("debian_#{container_type}_architecture", distribution: public_distribution, name: 'all') }
let_it_be(:public_architecture, freeze: true) { create("debian_#{container_type}_architecture", distribution: public_distribution, name: 'existing-arch') }
......
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