projects_helper_spec.rb 13 KB
Newer Older
1 2 3 4
# frozen_string_literal: true

require 'spec_helper'

5
RSpec.describe ProjectsHelper do
6
  let_it_be_with_refind(:project) { create(:project) }
7

8 9 10
  before do
    helper.instance_variable_set(:@project, project)
  end
11

12 13 14 15 16 17 18 19 20 21
  describe 'default_clone_protocol' do
    context 'when gitlab.config.kerberos is enabled and user is logged in' do
      it 'returns krb5 as default protocol' do
        allow(Gitlab.config.kerberos).to receive(:enabled).and_return(true)
        allow(helper).to receive(:current_user).and_return(double)

        expect(helper.send(:default_clone_protocol)).to eq('krb5')
      end
    end
  end
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39

  describe '#can_import_members?' do
    let(:owner) { project.owner }

    before do
      allow(helper).to receive(:current_user) { owner }
    end

    it 'returns false if membership is locked' do
      allow(helper).to receive(:membership_locked?) { true }
      expect(helper.can_import_members?).to eq false
    end

    it 'returns true if membership is not locked' do
      allow(helper).to receive(:membership_locked?) { false }
      expect(helper.can_import_members?).to eq true
    end
  end
40

41 42 43 44 45 46
  describe '#show_compliance_framework_badge?' do
    it 'returns false if compliance framework setting is not present' do
      expect(helper.show_compliance_framework_badge?(project)).to be_falsey
    end

    it 'returns true if compliance framework setting is present' do
47
      project = build_stubbed(:project, :with_compliance_framework)
48 49 50 51 52

      expect(helper.show_compliance_framework_badge?(project)).to be_truthy
    end
  end

53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86
  describe '#membership_locked?' do
    let(:project) { build_stubbed(:project, group: group) }
    let(:group) { nil }

    context 'when project has no group' do
      let(:project) { Project.new }

      it 'is false' do
        expect(helper).not_to be_membership_locked
      end
    end

    context 'with group_membership_lock enabled' do
      let(:group) { build_stubbed(:group, membership_lock: true) }

      it 'is true' do
        expect(helper).to be_membership_locked
      end
    end

    context 'with global LDAP membership lock enabled' do
      before do
        stub_application_setting(lock_memberships_to_ldap: true)
      end

      context 'and group membership_lock disabled' do
        let(:group) { build_stubbed(:group, membership_lock: false) }

        it 'is true' do
          expect(helper).to be_membership_locked
        end
      end
    end
  end
87

88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
  describe '#group_project_templates_count' do
    let_it_be(:user) { create(:user) }
    let_it_be(:parent_group) { create(:group, name: 'parent-group') }
    let_it_be(:template_group) { create(:group, parent: parent_group, name: 'template-group') }
    let_it_be(:template_project) { create(:project, group: template_group, name: 'template-project') }

    before_all do
      parent_group.update!(custom_project_templates_group_id: template_group.id)
      parent_group.add_owner(user)
    end

    before do
      allow(helper).to receive(:current_user).and_return(user)
    end

Lucy Fox's avatar
Lucy Fox committed
103
    specify do
104 105 106 107 108 109 110 111
      expect(helper.group_project_templates_count(parent_group.id)).to eq 1
    end

    context 'when template project is pending deletion' do
      before do
        template_project.update!(marked_for_deletion_at: Date.current)
      end

Lucy Fox's avatar
Lucy Fox committed
112
      specify do
113 114 115 116 117
        expect(helper.group_project_templates_count(parent_group.id)).to eq 0
      end
    end
  end

118
  describe '#project_security_dashboard_config' do
119 120 121
    let_it_be(:user) { create(:user) }
    let_it_be(:group) { create(:group) }
    let_it_be(:project) { create(:project, :repository, group: group) }
122
    let_it_be(:jira_service) { create(:jira_service, project: project, vulnerabilities_enabled: true, project_key: 'GV', vulnerabilities_issuetype: '10000') }
123

124
    subject { helper.project_security_dashboard_config(project) }
125

Savas Vedova's avatar
Savas Vedova committed
126
    before do
127
      group.add_owner(user)
128
      stub_licensed_features(jira_vulnerabilities_integration: true)
Savas Vedova's avatar
Savas Vedova committed
129 130 131
      allow(helper).to receive(:current_user).and_return(user)
    end

132 133 134
    context 'project without vulnerabilities' do
      let(:expected_value) do
        {
135
          has_vulnerabilities: 'false',
136
          has_jira_vulnerabilities_integration_enabled: 'true',
137
          empty_state_svg_path: start_with('/assets/illustrations/security-dashboard_empty'),
138
          survey_request_svg_path: start_with('/assets/illustrations/security-dashboard_empty'),
139 140
          security_dashboard_help_path: '/help/user/application_security/security_dashboard/index',
          project_full_path: project.full_path,
141 142
          no_vulnerabilities_svg_path: start_with('/assets/illustrations/issues-'),
          security_configuration_path: end_with('/configuration')
143
        }
144 145
      end

146 147
      it { is_expected.to match(expected_value) }
    end
148

149
    context 'project with vulnerabilities' do
150
      let(:base_values) do
151 152
        {
          has_vulnerabilities: 'true',
153
          has_jira_vulnerabilities_integration_enabled: 'true',
154 155
          project: { id: project.id, name: project.name },
          project_full_path: project.full_path,
156
          vulnerabilities_export_endpoint: "/api/v4/security/projects/#{project.id}/vulnerability_exports",
Savas Vedova's avatar
Savas Vedova committed
157
          no_vulnerabilities_svg_path: start_with('/assets/illustrations/issues-'),
158
          empty_state_svg_path: start_with('/assets/illustrations/security-dashboard-empty-state'),
159
          survey_request_svg_path: start_with('/assets/illustrations/security-dashboard_empty'),
160 161
          dashboard_documentation: '/help/user/application_security/security_dashboard/index',
          security_dashboard_help_path: '/help/user/application_security/security_dashboard/index',
162
          not_enabled_scanners_help_path: help_page_path('user/application_security/index', anchor: 'quick-start'),
163
          no_pipeline_run_scanners_help_path: "/#{project.full_path}/-/pipelines/new",
164
          auto_fix_documentation: help_page_path('user/application_security/index', anchor: 'auto-fix-merge-requests'),
165
          auto_fix_mrs_path: end_with('/merge_requests?label_name=GitLab-auto-fix'),
166
          scanners: '[{"id":123,"vendor":"Security Vendor","report_type":"SAST"}]'
167
        }
168
      end
169

170 171
      before do
        create(:vulnerability, project: project)
172
        scanner = create(:vulnerabilities_scanner, project: project, id: 123)
173
        create(:vulnerabilities_finding, project: project, scanner: scanner)
174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
      end

      context 'without pipeline' do
        before do
          allow(project).to receive(:latest_pipeline_with_security_reports).and_return(nil)
        end

        it { is_expected.to match(base_values) }
      end

      context 'with pipeline' do
        let(:pipeline_created_at) { '1881-05-19T00:00:00Z' }
        let(:pipeline) { build_stubbed(:ci_pipeline, project: project, created_at: pipeline_created_at) }
        let(:pipeline_values) do
          {
            pipeline: {
              id: pipeline.id,
              path: "/#{project.full_path}/-/pipelines/#{pipeline.id}",
192 193 194 195 196 197 198
              created_at: pipeline_created_at,
              security_builds: {
                failed: {
                  count: 0,
                  path: "/#{project.full_path}/-/pipelines/#{pipeline.id}/failures"
                }
              }
199 200 201 202 203 204 205 206 207 208
            }
          }
        end

        before do
          allow(project).to receive(:latest_pipeline_with_security_reports).and_return(pipeline)
        end

        it { is_expected.to match(base_values.merge!(pipeline_values)) }
      end
209 210
    end
  end
211

212 213
  describe '#show_discover_project_security?' do
    using RSpec::Parameterized::TableSyntax
214 215

    let_it_be(:user) { create(:user) }
216 217 218

    where(
      gitlab_com?: [true, false],
219
      user?: [true, false],
220 221 222 223 224 225 226 227 228 229 230
      security_dashboard_feature_available?: [true, false],
      can_admin_namespace?: [true, false]
    )

    with_them do
      it 'returns the expected value' do
        allow(::Gitlab).to receive(:com?) { gitlab_com? }
        allow(helper).to receive(:current_user) { user? ? user : nil }
        allow(project).to receive(:feature_available?) { security_dashboard_feature_available? }
        allow(helper).to receive(:can?) { can_admin_namespace? }

231
        expected_value = user? && gitlab_com? && !security_dashboard_feature_available? && can_admin_namespace?
232 233 234 235 236

        expect(helper.show_discover_project_security?(project)).to eq(expected_value)
      end
    end
  end
237 238 239 240 241 242 243 244

  describe '#remove_project_message' do
    subject { helper.remove_project_message(project) }

    before do
      allow(project).to receive(:adjourned_deletion?).and_return(enabled)
    end

245
    context 'when project has delayed deletion enabled' do
246 247
      let(:enabled) { true }

Lucy Fox's avatar
Lucy Fox committed
248
      specify do
249 250
        deletion_date = helper.permanent_deletion_date(Time.now.utc)

251
        expect(subject).to eq "Deleting a project places it into a read-only state until #{deletion_date}, at which point the project will be permanently deleted. Are you ABSOLUTELY sure?"
252 253 254
      end
    end

255
    context 'when project has delayed deletion disabled' do
256 257
      let(:enabled) { false }

Lucy Fox's avatar
Lucy Fox committed
258
      specify do
259
        expect(subject).to eq "You are going to delete #{project.full_name}. Deleted projects CANNOT be restored! Are you ABSOLUTELY sure?"
260 261 262
      end
    end
  end
263 264 265 266 267 268 269 270 271 272 273 274

  describe '#scheduled_for_deletion?' do
    context 'when project is NOT scheduled for deletion' do
      it { expect(helper.scheduled_for_deletion?(project)).to be false }
    end

    context 'when project is scheduled for deletion' do
      let_it_be(:archived_project) { create(:project, :archived, marked_for_deletion_at: 10.minutes.ago) }

      it { expect(helper.scheduled_for_deletion?(archived_project)).to be true }
    end
  end
Tristan Read's avatar
Tristan Read committed
275

276
  describe '#project_permissions_settings' do
277 278
    using RSpec::Parameterized::TableSyntax

279 280 281 282 283
    let(:expected_settings) { { requirementsAccessLevel: 20, securityAndComplianceAccessLevel: 10 } }

    subject { helper.project_permissions_settings(project) }

    it { is_expected.to include(expected_settings) }
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313

    context 'cveIdRequestEnabled' do
      context "with cve_id_request_button feature flag" do
        where(feature_flag_enabled: [true, false])
        with_them do
          before do
            stub_feature_flags(cve_id_request_button: feature_flag_enabled)
          end

          it 'includes cveIdRequestEnabled' do
            expect(subject.key?(:cveIdRequestEnabled)).to eq(feature_flag_enabled)
          end
        end
      end

      where(:project_attrs, :cve_enabled, :expected) do
        [:public]   | true  | true
        [:public]   | false | false
        [:internal] | true  | false
        [:private]  | true  | false
      end
      with_them do
        let(:project) { create(:project, :with_cve_request, *project_attrs, cve_request_enabled: cve_enabled) }
        subject { helper.project_permissions_settings(project) }

        it 'has the correct cveIdRequestEnabled value' do
          expect(subject[:cveIdRequestEnabled]).to eq(expected)
        end
      end
    end
314 315 316
  end

  describe '#project_permissions_panel_data' do
317 318
    using RSpec::Parameterized::TableSyntax

319
    let(:user) { instance_double(User, admin?: false) }
320
    let(:expected_data) { { requirementsAvailable: false } }
321 322 323 324 325 326 327 328 329

    subject { helper.project_permissions_panel_data(project) }

    before do
      allow(helper).to receive(:current_user).and_return(user)
      allow(helper).to receive(:can?).and_return(false)
    end

    it { is_expected.to include(expected_data) }
330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355

    context "if in Gitlab.com" do
      where(is_gitlab_com: [true, false])
      with_them do
        before do
          allow(Gitlab).to receive(:com?).and_return(is_gitlab_com)
        end

        it 'sets requestCveAvailable to the correct value' do
          expect(subject[:requestCveAvailable]).to eq(is_gitlab_com)
        end
      end
    end

    context "with cve_id_request_button feature flag" do
      where(feature_flag_enabled: [true, false])
      with_them do
        before do
          stub_feature_flags(cve_id_request_button: feature_flag_enabled)
        end

        it 'includes requestCveAvailable' do
          expect(subject.key?(:requestCveAvailable)).to eq(feature_flag_enabled)
        end
      end
    end
356
  end
357 358 359 360 361 362 363 364 365 366 367

  describe '#approvals_app_data' do
    subject { helper.approvals_app_data(project) }

    let(:user) { instance_double(User, admin?: false) }

    before do
      allow(helper).to receive(:current_user).and_return(user)
      allow(helper).to receive(:can?).and_return(true)
    end

368
    context 'with the status check feature flag' do
369 370 371 372 373 374 375 376 377 378 379 380
      where(feature_flag_enabled: [true, false])
      with_them do
        before do
          stub_feature_flags(ff_compliance_approval_gates: feature_flag_enabled)
        end

        it 'includes external_approval_rules_path only when enabled' do
          expect(subject[:data].key?(:external_approval_rules_path)).to eq(feature_flag_enabled)
        end
      end
    end
  end
381 382 383 384 385

  describe '#status_checks_app_data' do
    subject { helper.status_checks_app_data(project) }

    it 'returns the correct data' do
386 387 388 389
      expect(subject[:data]).to eq({
        project_id: project.id,
        status_checks_path: expose_path(api_v4_projects_external_approval_rules_path(id: project.id))
      })
390 391
    end
  end
392
end