Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
68a087e7
Commit
68a087e7
authored
Jul 30, 2018
by
Gilbert Roulot
Committed by
Sean McGivern
Jul 30, 2018
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add License Management API to the backend
parent
63e4129d
Changes
36
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
36 changed files
with
1806 additions
and
0 deletions
+1806
-0
config/routes/project.rb
config/routes/project.rb
+4
-0
db/schema.rb
db/schema.rb
+16
-0
doc/api/README.md
doc/api/README.md
+1
-0
doc/api/managed_licenses.md
doc/api/managed_licenses.md
+136
-0
ee/app/controllers/projects/managed_licenses_controller.rb
ee/app/controllers/projects/managed_licenses_controller.rb
+124
-0
ee/app/finders/software_license_policies_finder.rb
ee/app/finders/software_license_policies_finder.rb
+23
-0
ee/app/models/ee/project.rb
ee/app/models/ee/project.rb
+2
-0
ee/app/models/software_license.rb
ee/app/models/software_license.rb
+11
-0
ee/app/models/software_license_policy.rb
ee/app/models/software_license_policy.rb
+37
-0
ee/app/policies/ee/project_policy.rb
ee/app/policies/ee/project_policy.rb
+10
-0
ee/app/serializers/ee/merge_request_widget_entity.rb
ee/app/serializers/ee/merge_request_widget_entity.rb
+9
-0
ee/app/serializers/managed_license_entity.rb
ee/app/serializers/managed_license_entity.rb
+9
-0
ee/app/serializers/managed_license_serializer.rb
ee/app/serializers/managed_license_serializer.rb
+5
-0
ee/app/services/software_license_policies/create_service.rb
ee/app/services/software_license_policies/create_service.rb
+43
-0
ee/app/services/software_license_policies/update_service.rb
ee/app/services/software_license_policies/update_service.rb
+25
-0
ee/changelogs/unreleased/5488_license_management_app_blacklist_backend.yml
...eleased/5488_license_management_app_blacklist_backend.yml
+5
-0
ee/db/migrate/20180621100024_create_software_licenses.rb
ee/db/migrate/20180621100024_create_software_licenses.rb
+16
-0
ee/db/migrate/20180621100025_create_software_license_policies.rb
...igrate/20180621100025_create_software_license_policies.rb
+41
-0
ee/lib/api/managed_licenses.rb
ee/lib/api/managed_licenses.rb
+119
-0
ee/spec/controllers/projects/managed_licenses_controller_spec.rb
.../controllers/projects/managed_licenses_controller_spec.rb
+490
-0
ee/spec/factories/software_license.rb
ee/spec/factories/software_license.rb
+7
-0
ee/spec/factories/software_license_policy.rb
ee/spec/factories/software_license_policy.rb
+9
-0
ee/spec/finders/software_license_policies_finder_spec.rb
ee/spec/finders/software_license_policies_finder_spec.rb
+24
-0
ee/spec/fixtures/api/schemas/software_license_policies.json
ee/spec/fixtures/api/schemas/software_license_policies.json
+11
-0
ee/spec/fixtures/api/schemas/software_license_policy.json
ee/spec/fixtures/api/schemas/software_license_policy.json
+14
-0
ee/spec/models/software_license_policy_spec.rb
ee/spec/models/software_license_policy_spec.rb
+15
-0
ee/spec/models/software_license_spec.rb
ee/spec/models/software_license_spec.rb
+12
-0
ee/spec/policies/project_policy_spec.rb
ee/spec/policies/project_policy_spec.rb
+132
-0
ee/spec/requests/api/managed_licenses_spec.rb
ee/spec/requests/api/managed_licenses_spec.rb
+298
-0
ee/spec/serializers/managed_license_entity_spec.rb
ee/spec/serializers/managed_license_entity_spec.rb
+16
-0
ee/spec/serializers/merge_request_widget_entity_spec.rb
ee/spec/serializers/merge_request_widget_entity_spec.rb
+2
-0
ee/spec/services/software_license_policies/create_service_spec.rb
...services/software_license_policies/create_service_spec.rb
+51
-0
ee/spec/services/software_license_policies/update_service_spec.rb
...services/software_license_policies/update_service_spec.rb
+83
-0
lib/api/api.rb
lib/api/api.rb
+1
-0
lib/api/entities.rb
lib/api/entities.rb
+4
-0
spec/lib/gitlab/import_export/all_models.yml
spec/lib/gitlab/import_export/all_models.yml
+1
-0
No files found.
config/routes/project.rb
View file @
68a087e7
...
...
@@ -519,6 +519,10 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do
# its preferable to keep it below all other project routes
draw
:wiki
draw
:repository
## EE-specific
resources
:managed_licenses
,
only:
[
:index
,
:show
,
:new
,
:create
,
:edit
,
:update
,
:destroy
]
## EE-specific
end
resources
(
:projects
,
...
...
db/schema.rb
View file @
68a087e7
...
...
@@ -2463,6 +2463,20 @@ ActiveRecord::Schema.define(version: 20180722103201) do
add_index
"snippets"
,
[
"updated_at"
],
name:
"index_snippets_on_updated_at"
,
using: :btree
add_index
"snippets"
,
[
"visibility_level"
],
name:
"index_snippets_on_visibility_level"
,
using: :btree
create_table
"software_license_policies"
,
force: :cascade
do
|
t
|
t
.
integer
"project_id"
,
null:
false
t
.
integer
"software_license_id"
,
null:
false
t
.
integer
"approval_status"
,
default:
0
,
null:
false
end
add_index
"software_license_policies"
,
[
"project_id"
,
"software_license_id"
],
name:
"index_software_license_policies_unique_per_project"
,
unique:
true
,
using: :btree
create_table
"software_licenses"
,
force: :cascade
do
|
t
|
t
.
string
"name"
,
null:
false
end
add_index
"software_licenses"
,
[
"name"
],
name:
"index_software_licenses_on_name"
,
using: :btree
create_table
"spam_logs"
,
force: :cascade
do
|
t
|
t
.
integer
"user_id"
t
.
string
"source_ip"
...
...
@@ -3021,6 +3035,8 @@ ActiveRecord::Schema.define(version: 20180722103201) do
add_foreign_key
"services"
,
"projects"
,
name:
"fk_71cce407f9"
,
on_delete: :cascade
add_foreign_key
"slack_integrations"
,
"services"
,
on_delete: :cascade
add_foreign_key
"snippets"
,
"projects"
,
name:
"fk_be41fd4bb7"
,
on_delete: :cascade
add_foreign_key
"software_license_policies"
,
"projects"
,
on_delete: :cascade
add_foreign_key
"software_license_policies"
,
"software_licenses"
,
on_delete: :cascade
add_foreign_key
"subscriptions"
,
"projects"
,
on_delete: :cascade
add_foreign_key
"system_note_metadata"
,
"notes"
,
name:
"fk_d83a918cb1"
,
on_delete: :cascade
add_foreign_key
"term_agreements"
,
"application_setting_terms"
,
column:
"term_id"
...
...
doc/api/README.md
View file @
68a087e7
...
...
@@ -38,6 +38,7 @@ following locations:
-
[
Keys
](
keys.md
)
-
[
Labels
](
labels.md
)
-
[
License
](
license.md
)
-
[
Managed licenses
](
managed_licenses.md
)
**[ULTIMATE]**
-
[
Markdown
](
markdown.md
)
-
[
Merge Requests
](
merge_requests.md
)
-
[
Merge Request Approvals
](
merge_request_approvals.md
)
**[STARTER]**
...
...
doc/api/managed_licenses.md
0 → 100644
View file @
68a087e7
# Managed Licenses API **[ULTIMATE]**
## List managed licenses
Get all managed licenses for a given project.
```
GET /projects/:id/managed_licenses
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
https://gitlab.example.com/api/v4/projects/1/managed_licenses
```
Example response:
```
json
[
{
"id"
:
1
,
"name"
:
"MIT"
,
"approval_status"
:
"approved"
},
{
"id"
:
3
,
"name"
:
"ISC"
,
"approval_status"
:
"blacklisted"
}
]
```
## Show an existing managed license
Shows an existing managed license.
```
GET /projects/:id/managed_licenses/:managed_license_id
```
| Attribute | Type | Required | Description |
| --------------- | ------- | --------------------------------- | ------------------------------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`managed_license_id`
| integer/string | yes | The ID or URL-encoded name of the license belonging to the project |
```
bash
curl
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
"https://gitlab.example.com/api/v4/projects/1/managed_licenses/6"
```
Example response:
```
json
{
"id"
:
1
,
"name"
:
"MIT"
,
"approval_status"
:
"blacklisted"
}
```
## Create a new managed license
Creates a new managed license for the given project with the given name and approval status.
```
POST /projects/:id/managed_licenses
```
| Attribute | Type | Required | Description |
| ------------- | ------- | -------- | ---------------------------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`name`
| string | yes | The name of the managed license |
|
`approval_status`
| string | yes | The approval status. "approved" or "blacklisted" |
```
bash
curl
--data
"name=MIT&approval_status=blacklisted"
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
"https://gitlab.example.com/api/v4/projects/1/managed_licenses"
```
Example response:
```
json
{
"id"
:
1
,
"name"
:
"MIT"
,
"approval_status"
:
"approved"
}
```
## Delete a managed license
Deletes a managed license with a given id.
```
DELETE /projects/:id/managed_licenses/:managed_license_id
```
| Attribute | Type | Required | Description |
| --------- | ------- | -------- | --------------------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`managed_license_id`
| integer/string | yes | The ID or URL-encoded name of the license belonging to the project |
```
bash
curl
--request
DELETE
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
"https://gitlab.example.com/api/v4/projects/1/managed_licenses/4"
```
When successful, it replies with an HTTP 204 response.
## Edit an existing managed license
Updates an existing managed license with a new approval status.
```
PATCH /projects/:id/managed_licenses/:managed_license_id
```
| Attribute | Type | Required | Description |
| --------------- | ------- | --------------------------------- | ------------------------------- |
|
`id`
| integer/string | yes | The ID or
[
URL-encoded path of the project
](
README.md#namespaced-path-encoding
)
owned by the authenticated user |
|
`managed_license_id`
| integer/string | yes | The ID or URL-encoded name of the license belonging to the project |
|
`approval_status`
| string | yes | The approval status. "approved" or "blacklisted" |
```
bash
curl
--request
PATCH
--data
"approval_status=blacklisted"
--header
"PRIVATE-TOKEN: 9koXpg98eAheJpvBs5tK"
"https://gitlab.example.com/api/v4/projects/1/managed_licenses/6"
```
Example response:
```
json
{
"id"
:
1
,
"name"
:
"MIT"
,
"approval_status"
:
"blacklisted"
}
```
ee/app/controllers/projects/managed_licenses_controller.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
class
Projects::ManagedLicensesController
<
Projects
::
ApplicationController
before_action
:software_license_policy
,
only:
[
:show
,
:edit
,
:update
,
:destroy
]
before_action
:authorize_can_read!
,
only:
[
:index
,
:show
]
before_action
:authorize_can_admin!
,
only:
[
:new
,
:create
,
:edit
,
:update
,
:destroy
]
def
index
respond_to
do
|
format
|
format
.
json
do
render_software_license_policies
end
end
end
def
show
respond_to
do
|
format
|
format
.
json
do
render_software_license_policy
end
end
end
def
new
@software_license_policy
=
@project
.
software_license_policies
.
new
end
def
create
result
=
SoftwareLicensePolicies
::
CreateService
.
new
(
@project
,
current_user
,
software_license_policies_params
).
execute
if
result
[
:status
]
==
:success
@software_license_policy
=
result
[
:software_license_policy
]
respond_to
do
|
format
|
format
.
json
{
render_software_license_policy
}
end
else
respond_to
do
|
format
|
format
.
json
{
render_error
(
result
[
:message
],
400
)
}
end
end
end
def
edit
end
def
update
result
=
SoftwareLicensePolicies
::
UpdateService
.
new
(
@project
,
current_user
,
software_license_policies_params
).
execute
(
@software_license_policy
)
if
result
[
:status
]
==
:success
respond_to
do
|
format
|
format
.
json
{
render_software_license_policy
}
end
else
respond_to
do
|
format
|
format
.
json
{
render_error
(
result
[
:message
],
400
)
}
end
end
end
def
destroy
@software_license_policy
.
destroy!
respond_to
do
|
format
|
format
.
json
{
render_ok
}
end
end
private
def
respond_400
head
:bad_request
end
# Fetch the existing software license policy when given an id or name
def
software_license_policy
id
=
params
[
:id
]
id
=
CGI
.
unescape
(
id
)
unless
id
.
is_a?
(
Integer
)
||
id
=~
/^\d+$/
@software_license_policy
||=
SoftwareLicensePoliciesFinder
.
new
(
current_user
,
project
).
find_by_name_or_id
(
id
)
if
@software_license_policy
.
nil?
# The license was not found
render_404
end
end
def
render_ok
render
status: :ok
,
nothing:
true
end
def
render_software_license_policy
render
status: :ok
,
json:
ManagedLicenseSerializer
.
new
.
represent
(
@software_license_policy
)
end
def
render_software_license_policies
render
status: :ok
,
json:
{
software_license_policies:
ManagedLicenseSerializer
.
new
.
represent
(
@project
.
software_license_policies
)
}
end
def
render_error
(
error
,
status
=
400
)
render
json:
error
,
status:
status
end
def
software_license_policies_params
# Require the presence of an hash containing the software license policy fields
params
.
require
(
:managed_license
).
permit
(
:name
,
:approval_status
)
end
def
authorize_can_read!
render_404
unless
can?
(
current_user
,
:read_software_license_policy
,
@project
)
end
def
authorize_can_admin!
authorize_can_read!
render_403
unless
can?
(
current_user
,
:admin_software_license_policy
,
@project
)
end
end
ee/app/finders/software_license_policies_finder.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
class
SoftwareLicensePoliciesFinder
include
Gitlab
::
Allowable
include
FinderMethods
attr_accessor
:current_user
,
:project
def
initialize
(
current_user
,
project
)
@current_user
=
current_user
@project
=
project
end
def
find_by_name_or_id
(
id
)
return
nil
unless
can?
(
current_user
,
:read_software_license_policy
,
project
)
software_licenses
=
SoftwareLicense
.
arel_table
software_license_policies
=
SoftwareLicensePolicy
.
arel_table
project
.
software_license_policies
.
joins
(
:software_license
).
where
(
software_licenses
[
:name
].
eq
(
id
).
or
(
software_license_policies
[
:id
].
eq
(
id
))
).
take
end
end
ee/app/models/ee/project.rb
View file @
68a087e7
...
...
@@ -34,6 +34,8 @@ module EE
has_many
:audit_events
,
as: :entity
has_many
:path_locks
has_many
:vulnerability_feedback
has_many
:software_license_policies
,
inverse_of: :project
,
class_name:
'SoftwareLicensePolicy'
accepts_nested_attributes_for
:software_license_policies
,
allow_destroy:
true
has_many
:sourced_pipelines
,
class_name:
'Ci::Sources::Pipeline'
,
foreign_key: :source_project_id
...
...
ee/app/models/software_license.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
# This class represents a software license.
# For use in the License Management feature.
class
SoftwareLicense
<
ActiveRecord
::
Base
include
Presentable
validates
:name
,
presence:
true
scope
:ordered
,
->
{
order
(
:name
)
}
end
ee/app/models/software_license_policy.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
# This class represents a software license policy. Which means the fact that the user
# approves or not of the use of a certain software license in their project.
# For use in the License Management feature.
class
SoftwareLicensePolicy
<
ActiveRecord
::
Base
include
Presentable
# Only allows modification of the approval status
FORM_EDITABLE
=
%i[approval_status]
.
freeze
belongs_to
:project
,
inverse_of: :software_license_policies
belongs_to
:software_license
,
->
{
readonly
}
attr_readonly
:software_license
# Licenses must be approved or blacklisted.
enum
approval_status:
{
blacklisted:
0
,
approved:
1
}
# Software license is mandatory, it contains the license informations.
validates_associated
:software_license
validates_presence_of
:software_license
validates_presence_of
:project
validates
:approval_status
,
presence:
true
# A license is unique for its project since it can't be approved and blacklisted.
validates
:software_license
,
uniqueness:
{
scope: :project_id
}
scope
:ordered
,
->
{
SoftwareLicensePolicy
.
includes
(
:software_license
).
order
(
"software_licenses.name ASC"
)
}
def
name
software_license
.
name
end
end
ee/app/policies/ee/project_policy.rb
View file @
68a087e7
...
...
@@ -7,6 +7,7 @@ module EE
issue_link
approvers
vulnerability_feedback
license_management
]
.
freeze
prepended
do
...
...
@@ -53,6 +54,11 @@ module EE
@subject
.
feature_available?
(
:prometheus_alerts
,
@user
)
end
with_scope
:subject
condition
(
:license_management_enabled
)
do
@subject
.
feature_available?
(
:license_management
)
end
rule
{
admin
}.
enable
:change_repository_storage
rule
{
support_bot
}.
enable
:guest_access
...
...
@@ -90,6 +96,8 @@ module EE
rule
{
can?
(
:read_project
)
}.
enable
:read_vulnerability_feedback
rule
{
license_management_enabled
&
can?
(
:read_project
)
}.
enable
:read_software_license_policy
rule
{
repository_mirrors_enabled
&
((
mirror_available
&
can?
(
:admin_project
))
|
admin
)
}.
enable
:admin_mirror
rule
{
deploy_board_disabled
&
~
is_development
}.
prevent
:read_deploy_board
...
...
@@ -100,6 +108,8 @@ module EE
enable
:update_approvers
end
rule
{
license_management_enabled
&
can?
(
:maintainer_access
)
}.
enable
:admin_software_license_policy
rule
{
pod_logs_enabled
&
can?
(
:maintainer_access
)
}.
enable
:read_pod_logs
rule
{
prometheus_alerts_enabled
&
can?
(
:maintainer_access
)
}.
enable
:read_prometheus_alerts
...
...
ee/app/serializers/ee/merge_request_widget_entity.rb
View file @
68a087e7
module
EE
module
MergeRequestWidgetEntity
include
::
API
::
Helpers
::
RelatedResourcesHelpers
extend
ActiveSupport
::
Concern
prepended
do
...
...
@@ -99,6 +100,14 @@ module EE
merge_request
.
base_license_management_artifact
,
path:
Ci
::
Build
::
LICENSE_MANAGEMENT_FILE
)
end
expose
:managed_licenses_path
do
|
merge_request
|
api_v4_projects_managed_licenses_path
(
id:
merge_request
.
source_project
.
id
)
end
expose
:can_manage_licenses
do
|
merge_request
|
can?
(
current_user
,
:admin_software_license_policy
,
merge_request
)
end
end
# expose_sast_container_data? is deprecated and replaced with expose_container_scanning_data? (#5778)
...
...
ee/app/serializers/managed_license_entity.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
class
ManagedLicenseEntity
<
Grape
::
Entity
expose
:id
expose
:approval_status
expose
:software_license
,
merge:
true
do
expose
:name
end
end
ee/app/serializers/managed_license_serializer.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
class
ManagedLicenseSerializer
<
BaseSerializer
entity
ManagedLicenseEntity
end
ee/app/services/software_license_policies/create_service.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
# Managed license creation service. For use in the managed license controller.
module
SoftwareLicensePolicies
class
CreateService
<
::
BaseService
def
initialize
(
project
,
user
,
params
)
super
(
project
,
user
,
params
.
with_indifferent_access
)
end
# Returns the created managed license.
def
execute
return
error
(
""
,
403
)
unless
can?
(
@current_user
,
:admin_software_license_policy
,
@project
)
# Load or create the software license
name
=
params
.
delete
(
:name
)
software_license
=
SoftwareLicense
.
transaction
do
begin
SoftwareLicense
.
transaction
(
requires_new:
true
)
do
SoftwareLicense
.
find_or_create_by
(
name:
name
)
end
rescue
ActiveRecord
::
RecordNotUnique
retry
end
end
# Add the software license to params
params
[
:software_license
]
=
software_license
begin
software_license_policy
=
@project
.
software_license_policies
.
create
(
params
)
rescue
ArgumentError
=>
ex
return
error
(
ex
.
message
,
400
)
end
if
software_license_policy
.
errors
.
any?
return
error
(
software_license_policy
.
errors
.
full_messages
.
join
(
"
\n
"
),
400
)
end
success
(
software_license_policy:
software_license_policy
)
end
end
end
ee/app/services/software_license_policies/update_service.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
# Managed license update service. For use in the managed license controller.
module
SoftwareLicensePolicies
class
UpdateService
<
::
BaseService
def
initialize
(
project
,
user
,
params
)
super
(
project
,
user
,
params
.
with_indifferent_access
)
end
# returns the updated managed license
def
execute
(
software_license_policy
)
return
error
(
""
,
403
)
unless
can?
(
@current_user
,
:admin_software_license_policy
,
@project
)
@params
=
@params
.
slice
(
*
SoftwareLicensePolicy
::
FORM_EDITABLE
)
begin
software_license_policy
.
update
(
params
)
rescue
ArgumentError
=>
ex
return
error
(
ex
.
message
,
400
)
end
success
(
software_license_policy:
software_license_policy
)
end
end
end
ee/changelogs/unreleased/5488_license_management_app_blacklist_backend.yml
0 → 100644
View file @
68a087e7
---
title
:
Add an API endpoint for managed licenses of a project.
merge_request
:
6246
author
:
type
:
added
ee/db/migrate/20180621100024_create_software_licenses.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
# A software license. Used in the License Management feature for CI/CD.
class
CreateSoftwareLicenses
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
disable_ddl_transaction!
def
change
create_table
:software_licenses
do
|
t
|
t
.
string
:name
,
null:
false
,
unique:
true
,
index:
true
end
end
end
ee/db/migrate/20180621100025_create_software_license_policies.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
class
CreateSoftwareLicensePolicies
<
ActiveRecord
::
Migration
include
Gitlab
::
Database
::
MigrationHelpers
DOWNTIME
=
false
INDEX_NAME
=
'index_software_license_policies_unique_per_project'
disable_ddl_transaction!
def
up
create_table
:software_license_policies
do
|
t
|
t
.
references
:project
,
index:
false
,
foreign_key:
{
on_delete: :cascade
},
null:
false
t
.
references
:software_license
,
index:
false
,
foreign_key:
{
on_delete: :cascade
},
null:
false
t
.
integer
:approval_status
,
null:
false
,
default:
0
# Defaults to blacklisted
end
add_concurrent_index
:software_license_policies
,
[
:project_id
,
:software_license_id
],
unique:
true
,
name:
INDEX_NAME
end
def
down
if
foreign_keys_for
(
:software_license_policies
,
:project_id
).
any?
remove_foreign_key
:software_license_policies
,
column: :project_id
end
if
foreign_keys_for
(
:software_license_policies
,
:software_license_id
).
any?
remove_foreign_key
:software_license_policies
,
column: :software_license_id
end
if
index_exists?
(
:software_license_policies
,
[
:project_id
,
:software_license_id
])
remove_concurrent_index
:software_license_policies
,
[
:project_id
,
:software_license_id
]
end
if
table_exists?
(
:software_license_policies
)
drop_table
:software_license_policies
end
end
end
ee/lib/api/managed_licenses.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
module
API
class
ManagedLicenses
<
Grape
::
API
include
PaginationParams
before
{
authenticate!
}
helpers
do
# Make the software license policy specified by id in the request available
def
software_license_policy
id
=
params
[
:managed_license_id
]
@software_license_policy
||=
SoftwareLicensePoliciesFinder
.
new
(
current_user
,
user_project
).
find_by_name_or_id
(
id
)
end
def
authorize_can_read!
authorize!
(
:read_software_license_policy
,
user_project
)
end
def
authorize_can_admin!
authorize!
(
:admin_software_license_policy
,
user_project
)
end
end
params
do
requires
:id
,
type:
String
,
desc:
'The ID of a project'
end
resource
:projects
,
requirements:
API
::
PROJECT_ENDPOINT_REQUIREMENTS
do
desc
'Get project software license policies'
do
success
Entities
::
ManagedLicense
end
params
do
use
:pagination
end
get
':id/managed_licenses'
do
authorize_can_read!
software_license_policies
=
user_project
.
software_license_policies
present
paginate
(
software_license_policies
),
with:
Entities
::
ManagedLicense
end
desc
'Get a specific software license policy from a project'
do
success
Entities
::
ManagedLicense
end
get
':id/managed_licenses/:managed_license_id'
,
requirements:
{
managed_license_id:
/.*/
}
do
authorize_can_read!
break
not_found!
(
'SoftwareLicensePolicy'
)
unless
software_license_policy
present
software_license_policy
,
with:
Entities
::
ManagedLicense
end
desc
'Create a new software license policy in a project'
do
success
Entities
::
ManagedLicense
end
params
do
requires
:name
,
type:
String
,
desc:
'The name of the license'
requires
:approval_status
,
type:
String
,
values:
%w(approved blacklisted)
,
desc:
'The approval status of the license. "blacklisted" or "approved".'
end
post
':id/managed_licenses'
do
authorize_can_admin!
result
=
SoftwareLicensePolicies
::
CreateService
.
new
(
user_project
,
current_user
,
declared_params
(
include_missing:
false
)
).
execute
created_software_license_policy
=
result
[
:software_license_policy
]
if
result
[
:status
]
==
:success
present
created_software_license_policy
,
with:
Entities
::
ManagedLicense
else
render_api_error!
(
result
[
:message
],
result
[
:http_status
])
end
end
desc
'Update an existing software license policy from a project'
do
success
Entities
::
ManagedLicense
end
params
do
optional
:name
,
type:
String
,
desc:
'The name of the license'
optional
:approval_status
,
type:
String
,
values:
%w(approved blacklisted)
,
desc:
'The approval status of the license. "blacklisted" or "approved".'
end
patch
':id/managed_licenses/:managed_license_id'
,
requirements:
{
managed_license_id:
/.*/
}
do
authorize_can_admin!
break
not_found!
(
'SoftwareLicensePolicy'
)
unless
software_license_policy
result
=
SoftwareLicensePolicies
::
UpdateService
.
new
(
user_project
,
current_user
,
declared_params
(
include_missing:
false
).
except
(
:id
,
:name
)
).
execute
(
@software_license_policy
)
if
result
[
:status
]
==
:success
present
@software_license_policy
,
with:
Entities
::
ManagedLicense
else
render_api_error!
(
result
[
:message
],
result
[
:http_status
])
end
end
desc
'Delete an existing software license policy from a project'
do
success
Entities
::
ManagedLicense
end
delete
':id/managed_licenses/:managed_license_id'
,
requirements:
{
managed_license_id:
/.*/
}
do
authorize_can_admin!
not_found!
(
'SoftwareLicensePolicy'
)
unless
software_license_policy
status
204
software_license_policy
.
destroy!
end
end
end
end
ee/spec/controllers/projects/managed_licenses_controller_spec.rb
0 → 100644
View file @
68a087e7
This diff is collapsed.
Click to expand it.
ee/spec/factories/software_license.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
FactoryBot
.
define
do
factory
:software_license
,
class:
SoftwareLicense
do
sequence
(
:name
)
{
|
n
|
"SOFTWARE-LICENSE-2.7/example_
#{
n
}
"
}
end
end
ee/spec/factories/software_license_policy.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
FactoryBot
.
define
do
factory
:software_license_policy
,
class:
SoftwareLicensePolicy
do
approval_status
1
project
software_license
end
end
ee/spec/finders/software_license_policies_finder_spec.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
require
'spec_helper'
describe
SoftwareLicensePoliciesFinder
do
let
(
:project
)
{
create
(
:project
)
}
let
(
:software_license_policy
)
{
create
(
:software_license_policy
,
project:
project
)
}
let
(
:user
)
do
create
(
:user
).
tap
do
|
u
|
project
.
add_maintainer
(
u
)
end
end
let
(
:finder
)
{
described_class
.
new
(
user
,
project
)
}
before
do
stub_licensed_features
(
license_management:
true
)
end
it
'finds the software license policy'
do
expect
(
finder
.
find_by_name_or_id
(
software_license_policy
.
name
)).
to
eq
(
software_license_policy
)
end
end
ee/spec/fixtures/api/schemas/software_license_policies.json
0 → 100644
View file @
68a087e7
{
"type"
:
"object"
,
"required"
:
[
"software_license_policies"
],
"properties"
:
{
"software_license_policies"
:
{
"type"
:
"array"
,
"items"
:
{
"$ref"
:
"software_license_policy.json"
}
}
},
"additionalProperties"
:
false
}
ee/spec/fixtures/api/schemas/software_license_policy.json
0 → 100644
View file @
68a087e7
{
"type"
:
"object"
,
"required"
:
[
"id"
,
"name"
,
"approval_status"
],
"properties"
:
{
"id"
:
{
"type"
:
"integer"
},
"name"
:
{
"type"
:
"string"
},
"approval_status"
:
{
"type"
:
"string"
}
},
"additionalProperties"
:
false
}
ee/spec/models/software_license_policy_spec.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
require
'spec_helper'
describe
SoftwareLicensePolicy
do
subject
{
build
(
:software_license_policy
)
}
describe
'validations'
do
it
{
is_expected
.
to
include_module
(
Presentable
)
}
it
{
is_expected
.
to
validate_presence_of
(
:software_license
)
}
it
{
is_expected
.
to
validate_presence_of
(
:project
)
}
it
{
is_expected
.
to
validate_presence_of
(
:approval_status
)
}
it
{
is_expected
.
to
validate_uniqueness_of
(
:software_license
).
scoped_to
(
:project_id
).
with_message
(
/has already been taken/
)
}
end
end
ee/spec/models/software_license_spec.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
require
'spec_helper'
describe
SoftwareLicense
do
subject
{
build
(
:software_license
)
}
describe
'validations'
do
it
{
is_expected
.
to
include_module
(
Presentable
)
}
it
{
is_expected
.
to
validate_presence_of
(
:name
)
}
end
end
ee/spec/policies/project_policy_spec.rb
View file @
68a087e7
...
...
@@ -355,4 +355,136 @@ describe ProjectPolicy do
it
{
is_expected
.
to
be_disallowed
(
:read_project_security_dashboard
)
}
end
end
describe
'admin_license_management'
do
before
do
stub_licensed_features
(
license_management:
true
)
end
subject
{
described_class
.
new
(
current_user
,
project
)
}
context
'without license management feature available'
do
before
do
stub_licensed_features
(
license_management:
false
)
end
let
(
:current_user
)
{
admin
}
it
{
is_expected
.
to
be_disallowed
(
:admin_software_license_policy
)
}
end
context
'with admin'
do
let
(
:current_user
)
{
admin
}
it
{
is_expected
.
to
be_allowed
(
:admin_software_license_policy
)
}
end
context
'with owner'
do
let
(
:current_user
)
{
owner
}
it
{
is_expected
.
to
be_allowed
(
:admin_software_license_policy
)
}
end
context
'with maintainer'
do
let
(
:current_user
)
{
maintainer
}
it
{
is_expected
.
to
be_allowed
(
:admin_software_license_policy
)
}
end
context
'with developer'
do
let
(
:current_user
)
{
developer
}
it
{
is_expected
.
to
be_disallowed
(
:admin_software_license_policy
)
}
end
context
'with reporter'
do
let
(
:current_user
)
{
reporter
}
it
{
is_expected
.
to
be_disallowed
(
:admin_software_license_policy
)
}
end
context
'with guest'
do
let
(
:current_user
)
{
guest
}
it
{
is_expected
.
to
be_disallowed
(
:admin_software_license_policy
)
}
end
context
'with non member'
do
let
(
:current_user
)
{
create
(
:user
)
}
it
{
is_expected
.
to
be_disallowed
(
:admin_software_license_policy
)
}
end
context
'with anonymous'
do
let
(
:current_user
)
{
nil
}
it
{
is_expected
.
to
be_disallowed
(
:admin_software_license_policy
)
}
end
end
describe
'read_license_management'
do
before
do
stub_licensed_features
(
license_management:
true
)
end
subject
{
described_class
.
new
(
current_user
,
project
)
}
context
'without license management feature available'
do
before
do
stub_licensed_features
(
license_management:
false
)
end
let
(
:current_user
)
{
admin
}
it
{
is_expected
.
to
be_disallowed
(
:read_software_license_policy
)
}
end
context
'with admin'
do
let
(
:current_user
)
{
admin
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
context
'with owner'
do
let
(
:current_user
)
{
owner
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
context
'with maintainer'
do
let
(
:current_user
)
{
maintainer
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
context
'with developer'
do
let
(
:current_user
)
{
developer
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
context
'with reporter'
do
let
(
:current_user
)
{
reporter
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
context
'with guest'
do
let
(
:current_user
)
{
guest
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
context
'with non member'
do
let
(
:current_user
)
{
create
(
:user
)
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
context
'with anonymous'
do
let
(
:current_user
)
{
nil
}
it
{
is_expected
.
to
be_allowed
(
:read_software_license_policy
)
}
end
end
end
ee/spec/requests/api/managed_licenses_spec.rb
0 → 100644
View file @
68a087e7
This diff is collapsed.
Click to expand it.
ee/spec/serializers/managed_license_entity_spec.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
require
'spec_helper'
describe
ManagedLicenseEntity
do
let
(
:software_license_policy
)
{
create
(
:software_license_policy
)
}
let
(
:entity
)
{
described_class
.
new
(
software_license_policy
)
}
describe
'#as_json'
do
subject
{
entity
.
as_json
}
it
'contains required fields'
do
expect
(
subject
).
to
include
(
:id
,
:name
,
:approval_status
)
end
end
end
ee/spec/serializers/merge_request_widget_entity_spec.rb
View file @
68a087e7
...
...
@@ -116,6 +116,8 @@ describe MergeRequestWidgetEntity do
expect
(
subject
.
as_json
).
to
include
(
:license_management
)
expect
(
subject
.
as_json
[
:license_management
]).
to
include
(
:head_path
)
expect
(
subject
.
as_json
[
:license_management
]).
to
include
(
:base_path
)
expect
(
subject
.
as_json
[
:license_management
]).
to
include
(
:managed_licenses_path
)
expect
(
subject
.
as_json
[
:license_management
]).
to
include
(
:can_manage_licenses
)
end
# methods for old artifact are deprecated and replaced with ones for the new name (#5779)
...
...
ee/spec/services/software_license_policies/create_service_spec.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
require
'spec_helper'
describe
SoftwareLicensePolicies
::
CreateService
do
let
(
:project
)
{
create
(
:project
)}
let
(
:params
)
{
{
name:
'ExamplePL/2.1'
,
approval_status:
'blacklisted'
}
}
let
(
:user
)
do
create
(
:user
).
tap
do
|
u
|
project
.
add_maintainer
(
u
)
end
end
before
do
stub_licensed_features
(
license_management:
true
)
end
subject
{
described_class
.
new
(
project
,
user
,
params
).
execute
}
describe
'#execute'
do
context
'with license management unavailable'
do
before
do
stub_licensed_features
(
license_management:
false
)
end
it
'does not creates a software license policy'
do
expect
{
subject
}.
to
change
{
project
.
software_license_policies
.
count
}.
by
(
0
)
end
end
context
'with a user who is allowed to admin'
do
it
'creates one software license policy correctly'
do
expect
{
subject
}.
to
change
{
project
.
software_license_policies
.
count
}.
from
(
0
).
to
(
1
)
software_license_policy
=
project
.
software_license_policies
.
last
expect
(
software_license_policy
).
to
be_persisted
expect
(
software_license_policy
.
name
).
to
eq
(
'ExamplePL/2.1'
)
expect
(
software_license_policy
.
approval_status
).
to
eq
(
'blacklisted'
)
end
end
context
'with a user not allowed to admin'
do
let
(
:user
)
{
create
(
:user
)
}
it
'does not create a software license policy'
do
expect
{
subject
}.
to
change
{
project
.
software_license_policies
.
count
}.
by
(
0
)
end
end
end
end
ee/spec/services/software_license_policies/update_service_spec.rb
0 → 100644
View file @
68a087e7
# frozen_string_literal: true
require
'spec_helper'
describe
SoftwareLicensePolicies
::
UpdateService
do
let
(
:project
)
{
create
(
:project
)}
let
(
:user
)
do
create
(
:user
).
tap
do
|
u
|
project
.
add_maintainer
(
u
)
end
end
let
(
:software_license_policy
)
do
create
(
:software_license_policy
,
software_license:
create
(
:software_license
,
name:
'ExamplePL/2.1'
),
approval_status:
'blacklisted'
)
end
before
do
stub_licensed_features
(
license_management:
true
)
end
describe
'#execute'
do
def
update_software_license_policy
(
opts
)
described_class
.
new
(
project
,
user
,
opts
).
execute
(
software_license_policy
)
end
context
'approval status update'
do
let
(
:opts
)
do
{
approval_status:
'approved'
}
end
context
'with license management unavailable'
do
before
do
stub_licensed_features
(
license_management:
false
)
end
it
'does not update the software license policy'
do
update_software_license_policy
(
opts
)
expect
(
software_license_policy
).
to
be_valid
expect
(
software_license_policy
.
approval_status
).
not_to
eq
(
opts
[
:approval_status
])
end
end
context
'with a user allowed to admin'
do
it
'updates the software license policy correctly'
do
update_software_license_policy
(
opts
)
expect
(
software_license_policy
).
to
be_valid
expect
(
software_license_policy
.
approval_status
).
to
eq
(
opts
[
:approval_status
])
end
end
context
'with a user not allowed to admin'
do
let
(
:user
)
{
create
(
:user
)
}
it
'does not updates the software license policy'
do
update_software_license_policy
(
opts
)
expect
(
software_license_policy
).
to
be_valid
expect
(
software_license_policy
.
approval_status
).
not_to
eq
(
opts
[
:approval_status
])
end
end
end
context
'name update'
do
let
(
:opts
)
do
{
name:
'MyPL'
}
end
it
'does not updates the software license policy'
do
update_software_license_policy
(
opts
)
expect
(
software_license_policy
).
to
be_valid
expect
(
software_license_policy
.
name
).
not_to
eq
(
opts
[
:name
])
end
end
end
end
lib/api/api.rb
View file @
68a087e7
...
...
@@ -116,6 +116,7 @@ module API
mount
::
API
::
Keys
mount
::
API
::
Labels
mount
::
API
::
Lint
mount
::
API
::
ManagedLicenses
mount
::
API
::
Markdown
mount
::
API
::
Members
mount
::
API
::
MergeRequestApprovals
...
...
lib/api/entities.rb
View file @
68a087e7
...
...
@@ -1422,6 +1422,10 @@ module API
expose
:reset_approvals_on_push
expose
:disable_overriding_approvers_per_merge_request
end
class
ManagedLicense
<
Grape
::
Entity
expose
:id
,
:name
,
:approval_status
end
end
end
...
...
spec/lib/gitlab/import_export/all_models.yml
View file @
68a087e7
...
...
@@ -334,6 +334,7 @@ project:
-
import_export_upload
-
vulnerability_feedback
-
prometheus_alerts
-
software_license_policies
award_emoji
:
-
awardable
-
user
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment