Skip to content

Add license column to group-level dependencies listing

What does this MR do and why?

It adds license information to the group-level dependencies app.

Note: This will be behind a feature flag and the backend data is not yet serving the license data. There are setup-instructions below that will add some mock data, so the UI can be tested.

Screenshots or screen recordings

Before After
Screenshot_2023-08-24_at_2.16.48_pm Screenshot_2023-08-24_at_2.15.45_pm

How to set up and validate locally

Apply this patch, so the API returns mock licenses:

diff --git a/ee/app/controllers/groups/dependencies_controller.rb b/ee/app/controllers/groups/dependencies_controller.rb
index 5965328eab6d..8c97e00077c2 100644
--- a/ee/app/controllers/groups/dependencies_controller.rb
+++ b/ee/app/controllers/groups/dependencies_controller.rb
@@ -25,13 +25,39 @@ def index
           render status: :ok
         end
         format.json do
-          render json: serialized_dependencies
+          render json: DependencyListSerializer
+            .new(project: nil, user: current_user)
+            .with_pagination(request, response)
+            .represent(
+              ::Sbom::DependenciesFinder.new(
+                group,
+                params: params.permit(
+                  :package_managers,
+                  :sort,
+                  :sort_by,
+                  component_names: [],
+                  package_managers: []
+                )
+              ).execute
+            )
         end
       end
     end
 
+    def licenses
+      render json: [
+        { name: 'Apache-2.0', url: 'https://spdx.org/licenses/Apache-2.0.json' },
+        { name: 'MIT', url: 'https://spdx.org/licenses/MIT.json' }
+      ]
+    end
+
     def locations
-      render json: locations_info
+      render json: ::Sbom::DependencyLocationListEntity.represent(
+        ::Sbom::DependencyLocationsFinder.new(
+          namespace: group,
+          params: params.permit(:search, :component_id)
+        ).execute
+      )
     end
 
     private
@@ -42,20 +68,6 @@ def authorize_read_dependency_list!
       render_not_authorized
     end
 
-    def dependency_list_params
-      params.permit(:sort_by, :sort, :component_id, :search, package_managers: [])
-    end
-
-    def collect_dependencies
-      @collect_dependencies ||= ::Sbom::DependenciesFinder.new(group, params: dependency_list_params).execute
-    end
-
-    def serialized_dependencies
-      DependencyListSerializer.new(
-        project: nil,
-        user: current_user).with_pagination(request, response).represent(collect_dependencies)
-    end
-
     def render_not_authorized
       respond_to do |format|
         format.html do
@@ -67,16 +79,6 @@ def render_not_authorized
       end
     end
 
-    def locations_info
-      ::Sbom::DependencyLocationListEntity.represent(dependency_locations)
-    end
-
-    def dependency_locations
-      Sbom::DependencyLocationsFinder
-        .new(namespace: group, params: dependency_list_params.slice(:component_id, :search))
-        .execute
-    end
-
     def set_enable_project_search
       @enable_project_search = group.count_within_namespaces <= GROUP_COUNT_LIMIT
     end
diff --git a/ee/app/models/sbom/occurrence.rb b/ee/app/models/sbom/occurrence.rb
index 0ab7e2b4ba31..c5cd5156d122 100644
--- a/ee/app/models/sbom/occurrence.rb
+++ b/ee/app/models/sbom/occurrence.rb
@@ -59,6 +59,19 @@ def location
       }
     end
 
+    def licenses
+      [
+        {
+          name: 'Apache-2.0',
+          url: 'https://spdx.org/licenses/Apache-2.0.json'
+        },
+        {
+          name: 'MIT',
+          url: 'https://spdx.org/licenses/MIT.json'
+        }
+      ]
+    end
+
     private
 
     def input_file_blob_path
diff --git a/ee/app/serializers/dependency_entity.rb b/ee/app/serializers/dependency_entity.rb
index 6e68a1b7d742..f7a2568e6179 100644
--- a/ee/app/serializers/dependency_entity.rb
+++ b/ee/app/serializers/dependency_entity.rb
@@ -27,7 +27,7 @@ class ProjectEntity < Grape::Entity
   expose :name, :packager, :version
   expose :location, using: LocationEntity
   expose :vulnerabilities, using: VulnerabilityEntity, if: ->(_) { can_read_vulnerabilities? }
-  expose :licenses, using: LicenseEntity, if: ->(_) { can_read_licenses? }
+  expose :licenses, using: LicenseEntity # , if: ->(_) { can_read_licenses? }
   expose :project, using: ProjectEntity, if: ->(_) { !has_project? }
   expose :project_count, :occurrence_count, :component_id, if: ->(_) { !has_project? }
 
diff --git a/ee/config/routes/group.rb b/ee/config/routes/group.rb
index df6d6f2643f2..e0863ae9de07 100644
--- a/ee/config/routes/group.rb
+++ b/ee/config/routes/group.rb
@@ -197,6 +197,7 @@
 
     resources :dependencies, only: [:index] do
       collection do
+        get :licenses, format: :json
         get :locations, format: :json
       end
     end
diff --git a/ee/spec/requests/groups/dependencies_controller_spec.rb b/ee/spec/requests/groups/dependencies_controller_spec.rb
index 78cce7865766..b3d557953b83 100644
--- a/ee/spec/requests/groups/dependencies_controller_spec.rb
+++ b/ee/spec/requests/groups/dependencies_controller_spec.rb
@@ -139,6 +139,12 @@
                     'location' => sbom_occurrence_npm.location.as_json,
                     'name' => sbom_occurrence_npm.name,
                     'packager' => sbom_occurrence_npm.packager,
+                    'licenses' => [
+                      {
+                        'name' => 'MIT',
+                        'url' => 'https://spdx.org/licenses/MIT.json'
+                      }
+                    ],
                     'version' => sbom_occurrence_npm.version,
                     'occurrence_count' => 1,
                     'project_count' => 1,
@@ -150,6 +156,16 @@
                     'name' => sbom_occurrence_bundler.name,
                     'packager' => sbom_occurrence_bundler.packager,
                     'version' => sbom_occurrence_bundler.version,
+                    'licenses' => [
+                      {
+                        'name' => 'Apache-2.0',
+                        'url' => 'https://spdx.org/licenses/Apache-2.0.json'
+                      },
+                      {
+                        'name' => 'MIT',
+                        'url' => 'https://spdx.org/licenses/MIT.json'
+                      }
+                    ],
                     'occurrence_count' => 1,
                     'project_count' => 1,
                     "project" => { "full_path" => project.full_path, "name" => project.name },
@@ -349,4 +365,29 @@
       end
     end
   end
+
+  describe "GET #licenses" do
+    let_it_be(:project) { create(:project, namespace: group) }
+    let_it_be(:component) { create(:sbom_component) }
+
+    subject { get licenses_group_dependencies_path(group_id: group.full_path), as: :json }
+
+    context 'when is the best time to go to the dentist?' do
+      before do
+        stub_licensed_features(security_dashboard: true)
+        stub_feature_flags(group_level_dependencies: true)
+        group.add_developer(user)
+      end
+
+      it '02:30 (tooth hurty)' do
+        subject
+
+        expect(response).to have_gitlab_http_status(:ok)
+        expect(json_response).to eq([
+          { 'name' => 'Apache-2.0', 'url' => 'https://spdx.org/licenses/Apache-2.0.json' },
+          { 'name' => 'MIT', 'url' => 'https://spdx.org/licenses/MIT.json' }
+        ])
+      end
+    end
+  end
 end
  1. Enable the feature flag that controls the group-level dependencies app: echo "Feature.enable(:group_level_dependencies)" | rails c
  2. Go to a group and then navigate to Secure -> Dependency list
  3. Verify that the license column is not being displayed
  4. Enable the feature flag that controls the license rendering: echo "Feature.disable(:group_level_licenses)" | rails c
  5. Verify that the license column is now showing up and matching the screenshots above
  6. Go to a project
  7. Verify that the license column is showing up (this should also be the case with the feature flag disabled)

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Related to #422351 (closed)

Edited by David Pisek

Merge request reports