Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-05-17 18:07:07 +00:00
parent 30785cadee
commit 8746f6e79d
39 changed files with 553 additions and 154 deletions

View File

@ -6,7 +6,7 @@ workflow:
include:
- project: gitlab-org/quality/pipeline-common
ref: 3.1.5
ref: 5.1.0
file:
- /ci/base.gitlab-ci.yml
- /ci/allure-report.yml
@ -235,12 +235,12 @@ stages:
--project "gitlab-org/quality/testcase-sessions" \
--token "${QA_TEST_SESSION_TOKEN}" \
--ci-project-token "${GENERATE_TEST_SESSION_READ_API_REPORTER_TOKEN}" \
--issue-url-file REPORT_ISSUE_URL
--issue-url-file report_issue_url.txt
artifacts:
when: always
expire_in: 1d
paths:
- qa/REPORT_ISSUE_URL
- qa/report_issue_url.txt
.notify-slack:
extends:

View File

@ -8,10 +8,14 @@ const SHA_REGEX = /[\da-f]{40}/gi;
// GitLab default domain (override in jh)
export const DOMAIN = 'gitlab.com';
// About GitLab default host (overwrite in jh)
// Following URLs will be overwritten in jh
export const FORUM_URL = `https://forum.${DOMAIN}/`; // forum.gitlab.com
export const DOCS_URL = `https://docs.${DOMAIN}`; // docs.gitlab.com
// About GitLab default host
export const PROMO_HOST = `about.${DOMAIN}`; // about.gitlab.com
// About Gitlab default url (overwrite in jh)
// About Gitlab default url
export const PROMO_URL = `https://${PROMO_HOST}`;
// Reset the cursor in a Regex so that multiple uses before a recompile don't fail

View File

@ -391,6 +391,7 @@ export default {
@filterPipelines="filterPipelines"
/>
<gl-collapsible-listbox
v-model="visibilityPipelineIdType"
data-testid="pipeline-key-collapsible-box"
:toggle-text="selectedPipelineKeyOption.text"
:items="$options.PipelineKeyOptions"

View File

@ -1,13 +1,19 @@
<script>
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import AccessorUtilities from '~/lib/utils/accessor';
import { __ } from '~/locale';
import { getTopFrequentItems, formatContextSwitcherItems } from '../utils';
import ItemsList from './items_list.vue';
export default {
components: {
GlButton,
ItemsList,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
title: {
type: String,
@ -68,6 +74,9 @@ export default {
}
},
},
i18n: {
removeItem: __('Remove'),
},
};
</script>
@ -87,7 +96,20 @@ export default {
>
{{ pristineText }}
</div>
<items-list :aria-label="title" :items="cachedFrequentItems" @remove-item="handleItemRemove">
<items-list :aria-label="title" :items="cachedFrequentItems">
<template #actions="{ item }">
<gl-button
v-gl-tooltip.right.viewport
size="small"
category="tertiary"
icon="dash"
:aria-label="$options.i18n.removeItem"
:title="$options.i18n.removeItem"
class="gl-align-self-center gl-p-1! gl-absolute gl-right-4"
data-testid="item-remove"
@click.stop.prevent="handleItemRemove(item)"
/>
</template>
<template #view-all-items>
<slot name="view-all-items"></slot>
</template>

View File

@ -8,7 +8,7 @@ import {
} from '@gitlab/ui';
import GitlabVersionCheckBadge from '~/gitlab_version_check/components/gitlab_version_check_badge.vue';
import { helpPagePath } from '~/helpers/help_page_helper';
import { DOMAIN, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { FORUM_URL, DOCS_URL, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { __, s__ } from '~/locale';
import { STORAGE_KEY } from '~/whats_new/utils/notification';
import Tracking from '~/tracking';
@ -93,7 +93,7 @@ export default {
},
{
text: this.$options.i18n.docs,
href: `https://docs.${DOMAIN}`,
href: DOCS_URL,
extraAttrs: {
...this.trackingAttrs('gitlab_documentation'),
},
@ -107,7 +107,7 @@ export default {
},
{
text: this.$options.i18n.forum,
href: `https://forum.${DOMAIN}/`,
href: FORUM_URL,
extraAttrs: {
...this.trackingAttrs('community_forum'),
},

View File

@ -1,17 +1,12 @@
<script>
import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
import NavItem from './nav_item.vue';
export default {
components: {
GlButton,
ProjectAvatar,
NavItem,
},
directives: {
GlTooltip: GlTooltipDirective,
},
props: {
items: {
type: Array,
@ -40,17 +35,7 @@ export default {
/>
</template>
<template #actions>
<gl-button
v-gl-tooltip.right.viewport
size="small"
category="tertiary"
icon="dash"
:aria-label="__('Remove')"
:title="__('Remove')"
class="gl-align-self-center gl-p-1! gl-absolute gl-right-4"
data-testid="item-remove"
@click.stop.prevent="$emit('remove-item', item)"
/>
<slot name="actions" :item="item"></slot>
</template>
</nav-item>
<slot name="view-all-items"></slot>

View File

@ -1,6 +1,7 @@
<script>
import * as Sentry from '@sentry/browser';
import axios from '~/lib/utils/axios_utils';
import { s__ } from '~/locale';
import { PANELS_WITH_PINS } from '../constants';
import NavItem from './nav_item.vue';
import PinnedSection from './pinned_section.vue';
@ -42,6 +43,10 @@ export default {
},
},
i18n: {
mainNavigation: s__('Navigation|Main navigation'),
},
data() {
return {
// This is used as a provide and injected into the nav items.
@ -137,7 +142,7 @@ export default {
</script>
<template>
<nav class="gl-p-2 gl-relative">
<nav :aria-label="$options.i18n.mainNavigation" class="gl-p-2 gl-relative">
<ul v-if="hasStaticItems" class="gl-p-0 gl-m-0">
<nav-item v-for="item in staticItems" :key="item.id" :item="item" is-static />
</ul>

View File

@ -0,0 +1,44 @@
# frozen_string_literal: true
module Mutations
module Environments
class Update < ::Mutations::BaseMutation
graphql_name 'EnvironmentUpdate'
description 'Update an environment.'
authorize :update_environment
argument :id,
::Types::GlobalIDType[::Environment],
required: true,
description: 'Global ID of the environment to update.'
argument :external_url,
GraphQL::Types::String,
required: false,
description: 'External URL of the environment.'
argument :tier,
Types::DeploymentTierEnum,
required: false,
description: 'Tier of the environment.'
field :environment,
Types::EnvironmentType,
null: true,
description: 'Environment after attempt to update.'
def resolve(id:, **kwargs)
environment = authorized_find!(id: id)
response = ::Environments::UpdateService.new(environment.project, current_user, kwargs).execute(environment)
if response.success?
{ environment: response.payload[:environment], errors: [] }
else
{ environment: response.payload[:environment], errors: response.errors }
end
end
end
end
end

View File

@ -53,6 +53,7 @@ module Types
mount_mutation Mutations::DependencyProxy::GroupSettings::Update
mount_mutation Mutations::Environments::CanaryIngress::Update
mount_mutation Mutations::Environments::Stop
mount_mutation Mutations::Environments::Update
mount_mutation Mutations::IncidentManagement::TimelineEvent::Create, alpha: { milestone: '15.6' }
mount_mutation Mutations::IncidentManagement::TimelineEvent::PromoteFromNote
mount_mutation Mutations::IncidentManagement::TimelineEvent::Update

View File

@ -15,7 +15,8 @@ module SafeFormatHelper
def safe_format(format, **args)
raise ArgumentError, 'Argument `format` must not be marked as html_safe!' if format.html_safe?
format(
# Use `Kernel.format` to avoid conflicts with ViewComponent's `format`.
Kernel.format(
html_escape(format),
args.transform_values { |value| html_escape(value) }
).html_safe

View File

@ -0,0 +1,23 @@
# frozen_string_literal: true
module Environments
class UpdateService < BaseService
def execute(environment)
unless can?(current_user, :update_environment, environment)
return ServiceResponse.error(
message: _('Unauthorized to update the environment'),
payload: { environment: environment }
)
end
if environment.update(**params)
ServiceResponse.success(payload: { environment: environment })
else
ServiceResponse.error(
message: environment.errors.full_messages,
payload: { environment: environment }
)
end
end
end
end

View File

@ -3060,6 +3060,29 @@ Input type: `EnvironmentStopInput`
| <a id="mutationenvironmentstopenvironment"></a>`environment` | [`Environment`](#environment) | Environment after attempt to stop. |
| <a id="mutationenvironmentstoperrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.environmentUpdate`
Update an environment.
Input type: `EnvironmentUpdateInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationenvironmentupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationenvironmentupdateexternalurl"></a>`externalUrl` | [`String`](#string) | External URL of the environment. |
| <a id="mutationenvironmentupdateid"></a>`id` | [`EnvironmentID!`](#environmentid) | Global ID of the environment to update. |
| <a id="mutationenvironmentupdatetier"></a>`tier` | [`DeploymentTier`](#deploymenttier) | Tier of the environment. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationenvironmentupdateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationenvironmentupdateenvironment"></a>`environment` | [`Environment`](#environment) | Environment after attempt to update. |
| <a id="mutationenvironmentupdateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
### `Mutation.environmentsCanaryIngressUpdate`
**Deprecated** This endpoint is planned to be removed along with certificate-based clusters. [See this epic](https://gitlab.com/groups/gitlab-org/configure/-/epics/8) for more information.

View File

@ -39,6 +39,7 @@ GitLab Runners use a set of globally scoped endpoints to:
- registration of a new runner via registration token `https://gitlab.com/api/v4/runners`
([subject for removal](../runner_tokens/index.md)) (`registration token`)
- creation of a new runner in the context of a user `https://gitlab.com/api/v4/user/runners` (`runner token`)
- requests jobs via an authenticated `https://gitlab.com/api/v4/jobs/request` endpoint (`runner token`)
- upload job status via `https://gitlab.com/api/v4/jobs/:job_id` (`build token`)
- upload trace via `https://gitlab.com/api/v4/jobs/:job_id/trace` (`build token`)

View File

@ -97,8 +97,8 @@ This problem was discovered in <https://gitlab.com/gitlab-org/gitlab-qa/-/issues
work-around was suggested in <https://gitlab.com/gitlab-org/omnibus-gitlab/-/issues/4717>.
A feature proposal to segregate access control regarding running pipelines from ability to push/merge was also created at <https://gitlab.com/gitlab-org/gitlab/-/issues/24585>.
For more technical details on CI/CD setup and documentation on adding new test jobs to `package-and-test` pipeline, see
[`package_and_test` setup documentation](package_and_test_pipeline.md).
For more technical details on CI/CD setup and documentation on adding new test jobs to `e2e:package-and-test` pipeline, see
[`e2e:package_and_test` setup documentation](package_and_test_pipeline.md).
#### With merged results pipelines
@ -198,7 +198,7 @@ Use these environment variables to configure metrics export:
| -------- | -------- | ----------- |
| `QA_INFLUXDB_URL` | `true` | Should be set to `https://influxdb.quality.gitlab.net`. No default value. |
| `QA_INFLUXDB_TOKEN` | `true` | InfluxDB write token that can be found under `Influxdb auth tokens` document in `Gitlab-QA` `1Password` vault. No default value. |
| `QA_RUN_TYPE` | `false` | Arbitrary name for test execution, like `package-and-test`. Automatically inferred from the project name for live environment test executions. No default value. |
| `QA_RUN_TYPE` | `false` | Arbitrary name for test execution, like `e2e:package-and-test`. Automatically inferred from the project name for live environment test executions. No default value. |
| `QA_EXPORT_TEST_METRICS` | `false` | Flag to enable or disable metrics export to InfluxDB. Defaults to `false`. |
| `QA_SAVE_TEST_METRICS` | `false` | Flag to enable or disable saving metrics as JSON file. Defaults to `false`. |

View File

@ -20,6 +20,10 @@ You can create [Personal access tokens](../user/profile/personal_access_tokens.m
You can limit the scope and expiration date of your personal access tokens. By default,
they inherit permissions from the user who created them.
You can use the [personal access tokens API](../api/personal_access_tokens.md) to
programmatically take action, such as
[rotating a personal access token](../api/personal_access_tokens.md#rotate-a-personal-access-token).
## OAuth2 tokens
GitLab can serve as an [OAuth2 provider](../api/oauth2.md) to allow other services to access the GitLab API on a user's behalf.
@ -47,6 +51,10 @@ You can limit the scope and expiration date of project access tokens. When you
create a project access token, GitLab creates a [bot user for projects](../user/project/settings/project_access_tokens.md#bot-users-for-projects).
Bot users for projects are service accounts and do not count as licensed seats.
You can use the [project access tokens API](../api/project_access_tokens.md) to
programmatically take action, such as
[rotating a project access token](../api/project_access_tokens.md#rotate-a-project-access-token).
## Group access tokens
[Group access tokens](../user/group/settings/group_access_tokens.md#group-access-tokens)
@ -60,6 +68,10 @@ You can limit the scope and expiration date of group access tokens. When you
create a group access token, GitLab creates a [bot user for groups](../user/group/settings/group_access_tokens.md#bot-users-for-groups).
Bot users for groups are service accounts and do not count as licensed seats.
You can use the [group access tokens API](../api/group_access_tokens.md) to
programmatically take action, such as
[rotating a project access token](../api/group_access_tokens.md#rotate-a-group-access-token).
## Deploy tokens
[Deploy tokens](../user/project/deploy_tokens/index.md) allow you to download (`git clone`) or push and pull packages and container registry images of a project without having a user and a password. Deploy tokens cannot be used with the GitLab API.

View File

@ -11,7 +11,7 @@ GitLab is creating AI-assisted features across our DevSecOps platform. These fea
## Enable AI/ML features
> Introduced in GitLab 16.0 and is [actively being rolled out](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118222).
> Introduced in GitLab 16.0 and [actively being rolled out](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/118222).
Prerequisites:
@ -133,7 +133,11 @@ To give feedback, select the **Give Feedback** link.
This feature is an [Experiment](../policy/alpha-beta-support.md) on GitLab.com that is powered by OpenAI's GPT-3. It requires the [group-level third-party AI features setting](group/manage.md#group-third-party-ai-features-setting) to be enabled.
You can generate a merge request summary by using the `/summarize_diff` quick action in a merge request comment. This action posts a comment from a GitLab bot. The comment provides a summary of the changes and the related SHA for when that summary was generated.
You can generate a merge request summary in a merge request comment.
- In a comment, type `/summarize_diff`.
This action posts a comment from a GitLab bot. The comment provides a summary of the changes and the related SHA for when that summary was generated.
Provide feedback on this experimental feature in [issue 408726](https://gitlab.com/gitlab-org/gitlab/-/issues/408726).
@ -146,12 +150,15 @@ and the target branch is sent to the large language model referenced above.
This feature is an [Experiment](../policy/alpha-beta-support.md) on GitLab.com that is powered by OpenAI's GPT-3. It requires the [group-level third-party AI features setting](group/manage.md#group-third-party-ai-features-setting) to be enabled.
When you've completed your review of a merge request and are ready to [submit your review](project/merge_requests/reviews/index.md#submit-a-review) you can choose to have summary generated for you. To generate the summary:
When you've completed your review of a merge request and are ready to [submit your review](project/merge_requests/reviews/index.md#submit-a-review), you can have a summary generated for you.
1. Select the AI Actions dropdown list.
To generate the summary:
1. When you are ready to submit your review, select **Finish review**.
1. Select **AI Actions** (**{tanuki}**).
1. Select **Summarize my code review**.
The summary is generated and entered in to the comment box where you can edit and refine prior to submitting with your review.
The summary is displayed in the comment box. You can edit and refine the summary prior to submitting your review.
Provide feedback on this experimental feature in [issue 408991](https://gitlab.com/gitlab-org/gitlab/-/issues/408991).
@ -166,12 +173,15 @@ Provide feedback on this experimental feature in [issue 408991](https://gitlab.c
This feature is an [Experiment](../policy/alpha-beta-support.md) on GitLab.com that is powered by OpenAI's GPT-3. It requires the [group-level third-party AI features setting](group/manage.md#group-third-party-ai-features-setting) to be enabled.
When in a merge request you can choose to have GitLab suggest tests for the file you are reviewing. This can help to determine if appropriate test coverage has been provided or help with writing tests to provide more coverage for your project. To generate a test suggestion:
In a merge request, you can get a list of suggested tests for the file you are reviewing. This functionality can help determine if appropriate test coverage has been provided, or if you need more coverage for your project.
1. Select the menu icon on the header of a file.
To generate a test suggestion:
1. In a merge request, select the **Changes** tab.
1. On the header for the file, in the upper-right corner, select **Options** (**{ellipsis_v}**).
1. Select **Generate test with AI**.
A sidebar opens where the test suggestion is generated. From there you can choose to copy that suggestion in to your editor as the start of your tests.
The test suggestion is generated in a sidebar. You can copy the suggestion to your editor and use it as the start of your tests.
Feedback on this experimental feature can be provided in [issue 408995](https://gitlab.com/gitlab-org/gitlab/-/issues/408995).

View File

@ -122,8 +122,10 @@ To protect a branch:
1. On the left sidebar, select **Settings > Repository**.
1. Expand **Protected branches**.
1. From the **Branch** dropdown list, select the branch you want to protect.
1. From the **Allowed to merge** list, select a role, or group that can merge into this branch. In GitLab Premium, you can also add users.
1. From the **Allowed to push and merge** list, select a role, group, or user that can push to this branch. In GitLab Premium, you can also add users.
1. From the **Allowed to merge** list, select a role that can merge into this branch.
In GitLab Premium and Ultimate, you can also add groups or individual users.
1. From the **Allowed to push and merge** list, select a role that can push to this branch.
In GitLab Premium and Ultimate, you can also add groups or individual users.
1. Select **Protect**.
The protected branch displays in the list of protected branches.
@ -152,8 +154,10 @@ To protect multiple branches at the same time:
| `production/*` | `production/app-server`, `production/load-balancer` |
| `*gitlab*` | `gitlab`, `gitlab/staging`, `master/gitlab/production` |
1. From the **Allowed to merge** list, select a role, or group that can merge into this branch. In GitLab Premium, you can also add users.
1. From the **Allowed to push and merge** list, select a role, group, or user that can push to this branch. In GitLab Premium, you can also add users.
1. From the **Allowed to merge** list, select a role that can merge into
this branch.
1. From the **Allowed to push and merge** list, select a role that can
push to this branch. In GitLab Premium or Ultimate, you can also add groups or individual users.
1. Select **Protect**.
The protected branch displays in the list of protected branches.

View File

@ -39,7 +39,8 @@ Prerequisites:
1. Select **Tag**.
1. Enter the string to use for tag matching. Wildcards (`*`) are supported.
1. Select **Create wildcard**.
1. In **Allowed to create** , select either the users or roles that may create protected tags.
1. In **Allowed to create** , select roles that may create protected tags.
In GitLab Premium and Ultimate, you can also select groups or individual users.
1. Select **Protect**.
The protected tag (or wildcard) displays in the **Protected tags** list.

View File

@ -123,7 +123,6 @@ module Gitlab
uuid: uuid,
report_type: report.type,
name: finding_name(data, identifiers, location),
compare_key: data['cve'] || '',
location: location,
evidence: evidence,
severity: parse_severity_level(data['severity']),

View File

@ -7,7 +7,6 @@ module Gitlab
class Finding
include ::VulnerabilityFindingHelpers
attr_reader :compare_key
attr_reader :confidence
attr_reader :identifiers
attr_reader :flags
@ -33,10 +32,10 @@ module Gitlab
delegate :file_path, :start_line, :end_line, to: :location
alias_method :compare_key, :uuid
alias_method :cve, :compare_key
def initialize(compare_key:, identifiers:, flags: [], links: [], remediations: [], location:, evidence:, metadata_version:, name:, original_data:, report_type:, scanner:, scan:, uuid:, confidence: nil, severity: nil, details: {}, signatures: [], project_id: nil, vulnerability_finding_signatures_enabled: false, found_by_pipeline: nil) # rubocop:disable Metrics/ParameterLists
@compare_key = compare_key
def initialize(identifiers:, flags: [], links: [], remediations: [], location:, evidence:, metadata_version:, name:, original_data:, report_type:, scanner:, scan:, uuid:, confidence: nil, severity: nil, details: {}, signatures: [], project_id: nil, vulnerability_finding_signatures_enabled: false, found_by_pipeline: nil) # rubocop:disable Metrics/ParameterLists
@confidence = confidence
@identifiers = identifiers
@flags = flags
@ -203,7 +202,7 @@ module Gitlab
private
def generate_project_fingerprint
Digest::SHA1.hexdigest(compare_key)
Digest::SHA1.hexdigest(compare_key.to_s)
end
def location_fingerprints

View File

@ -9,6 +9,8 @@ module Gitlab
belongs_to :issue
validates :object_name, :valitador_name, :table_name, presence: true
scope :with_open_issues, -> { joins(:issue).where('issue.state_id': Issue.available_states[:opened]) }
end
end
end

View File

@ -86,7 +86,7 @@ module Gitlab
end
def inconsistency_record
schema_inconsistency_model.find_by(
schema_inconsistency_model.with_open_issues.find_by(
object_name: inconsistency.object_name,
table_name: inconsistency.table_name,
valitador_name: inconsistency.type

View File

@ -5645,6 +5645,9 @@ msgstr ""
msgid "ApprovalRule|Name"
msgstr ""
msgid "ApprovalRule|Need triage"
msgstr ""
msgid "ApprovalRule|Needs triage"
msgstr ""
@ -29460,6 +29463,9 @@ msgstr ""
msgid "Navigation|Leave admin mode"
msgstr ""
msgid "Navigation|Main navigation"
msgstr ""
msgid "Navigation|Manage"
msgstr ""
@ -40367,6 +40373,9 @@ msgstr ""
msgid "SecurityOrchestration| and "
msgstr ""
msgid "SecurityOrchestration| and all the following apply:"
msgstr ""
msgid "SecurityOrchestration| or "
msgstr ""
@ -40397,7 +40406,7 @@ msgstr ""
msgid "SecurityOrchestration|%{scanners}"
msgstr ""
msgid "SecurityOrchestration|%{scanners} %{vulnerabilitiesAllowed} %{severities} in an open merge request targeting %{branches}."
msgid "SecurityOrchestration|%{state} and %{statuses}"
msgstr ""
msgid "SecurityOrchestration|, and %{count} more"
@ -40442,9 +40451,6 @@ msgstr ""
msgid "SecurityOrchestration|An error occurred while fetching the scan result policies."
msgstr ""
msgid "SecurityOrchestration|Any security scanner finds"
msgstr ""
msgid "SecurityOrchestration|Are you sure you want to delete this policy? This action cannot be undone."
msgstr ""
@ -40547,9 +40553,6 @@ msgstr ""
msgid "SecurityOrchestration|License Scan"
msgstr ""
msgid "SecurityOrchestration|License scanner finds any license %{matching} %{licenses}%{detection} in an open merge request targeting %{branches}."
msgstr ""
msgid "SecurityOrchestration|New policy"
msgstr ""
@ -40703,6 +40706,9 @@ msgstr ""
msgid "SecurityOrchestration|Select users"
msgstr ""
msgid "SecurityOrchestration|Severity is %{severity}."
msgstr ""
msgid "SecurityOrchestration|Something went wrong, unable to fetch policies"
msgstr ""
@ -40778,6 +40784,15 @@ msgstr ""
msgid "SecurityOrchestration|View policy project"
msgstr ""
msgid "SecurityOrchestration|Vulnerabilities are %{vulnerabilityStates}."
msgstr ""
msgid "SecurityOrchestration|When %{scanners} %{vulnerabilitiesAllowed} %{vulnerability} in an open merge request targeting %{branches}%{criteriaApply}"
msgstr ""
msgid "SecurityOrchestration|When license scanner finds any license %{matching} %{licenses}%{detection} in an open merge request targeting %{branches}."
msgstr ""
msgid "SecurityOrchestration|YAML"
msgstr ""
@ -40793,6 +40808,9 @@ msgstr ""
msgid "SecurityOrchestration|any"
msgstr ""
msgid "SecurityOrchestration|any security scanner finds"
msgstr ""
msgid "SecurityOrchestration|branch"
msgstr ""
@ -40826,12 +40844,6 @@ msgstr ""
msgid "SecurityOrchestration|the %{namespaces} namespace"
msgstr ""
msgid "SecurityOrchestration|vulnerabilities"
msgstr ""
msgid "SecurityOrchestration|vulnerability"
msgstr ""
msgid "SecurityPolicies|Invalid or empty policy"
msgstr ""
@ -47834,6 +47846,9 @@ msgstr ""
msgid "Unauthenticated web rate limit period in seconds"
msgstr ""
msgid "Unauthorized to update the environment"
msgstr ""
msgid "Unavailable"
msgstr ""

View File

@ -2,7 +2,6 @@
FactoryBot.define do
factory :ci_reports_security_finding, class: '::Gitlab::Ci::Reports::Security::Finding' do
compare_key { "#{identifiers.first&.external_type}:#{identifiers.first&.external_id}:#{location.fingerprint}" }
confidence { :medium }
identifiers { Array.new(1) { association(:ci_reports_security_identifier) } }
location factory: :ci_reports_security_locations_sast

View File

@ -90,6 +90,7 @@
"message": "Remediation for this vulnerability should remediate CVE-2140 as well",
"description": "",
"cve": "CVE-2139",
"id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d4",
"severity": "High",
"solution": "Upgrade to latest version.",
"scanner": {
@ -132,6 +133,7 @@
"message": "Remediation for this vulnerability should remediate CVE-2139 as well",
"description": "",
"cve": "CVE-2140",
"id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d5",
"severity": "High",
"solution": "Upgrade to latest version.",
"scanner": {
@ -439,10 +441,10 @@
{
"fixes": [
{
"cve": "CVE-2139"
"id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d4"
},
{
"cve": "CVE-2140"
"id": "bb2fbeb1b71ea360ce3f86f001d4e84823c3ffe1a1f7d41ba7466b14cfa953d5"
}
],
"summary": "this remediates CVE-2139 and CVE-2140",

View File

@ -1,4 +1,4 @@
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import { s__ } from '~/locale';
import FrequentItemsList from '~/super_sidebar/components//frequent_items_list.vue';
import ItemsList from '~/super_sidebar/components/items_list.vue';
@ -18,18 +18,20 @@ describe('FrequentItemsList component', () => {
const findListTitle = () => wrapper.findByTestId('list-title');
const findItemsList = () => wrapper.findComponent(ItemsList);
const findEmptyText = () => wrapper.findByTestId('empty-text');
const findRemoveItemButton = () => wrapper.findByTestId('item-remove');
const createWrapper = ({ props = {} } = {}) => {
wrapper = shallowMountExtended(FrequentItemsList, {
const createWrapperFactory = (mountFn = shallowMountExtended) => () => {
wrapper = mountFn(FrequentItemsList, {
propsData: {
title,
pristineText,
storageKey,
maxItems,
...props,
},
});
};
const createWrapper = createWrapperFactory();
const createFullWrapper = createWrapperFactory(mountExtended);
describe('default', () => {
beforeEach(() => {
@ -64,16 +66,20 @@ describe('FrequentItemsList component', () => {
it('does not render the empty text slot', () => {
expect(findEmptyText().exists()).toBe(false);
});
});
describe('items editing', () => {
it('remove-item event emission from items-list causes list item to be removed', async () => {
const localStorageProjects = findItemsList().props('items');
describe('items editing', () => {
beforeEach(() => {
window.localStorage.setItem(storageKey, cachedFrequentProjects);
createFullWrapper();
});
await findItemsList().vm.$emit('remove-item', localStorageProjects[0]);
it('remove-item event emission from items-list causes list item to be removed', async () => {
const localStorageProjects = findItemsList().props('items');
await findRemoveItemButton().trigger('click');
expect(findItemsList().props('items')).toHaveLength(maxItems - 1);
expect(findItemsList().props('items')).not.toContain(localStorageProjects[0]);
});
expect(findItemsList().props('items')).toHaveLength(maxItems - 1);
expect(findItemsList().props('items')).not.toContain(localStorageProjects[0]);
});
});
});

View File

@ -4,7 +4,7 @@ import toggleWhatsNewDrawer from '~/whats_new';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import HelpCenter from '~/super_sidebar/components/help_center.vue';
import { helpPagePath } from '~/helpers/help_page_helper';
import { DOMAIN, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { DOCS_URL, FORUM_URL, PROMO_URL } from 'jh_else_ce/lib/utils/url_utility';
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { STORAGE_KEY } from '~/whats_new/utils/notification';
import { helpCenterState } from '~/super_sidebar/constants';
@ -52,7 +52,7 @@ describe('HelpCenter component', () => {
},
{
text: HelpCenter.i18n.docs,
href: `https://docs.${DOMAIN}`,
href: DOCS_URL,
extraAttrs: trackingAttrs('gitlab_documentation'),
},
{
@ -62,7 +62,7 @@ describe('HelpCenter component', () => {
},
{
text: HelpCenter.i18n.forum,
href: `https://forum.${DOMAIN}/`,
href: FORUM_URL,
extraAttrs: trackingAttrs('community_forum'),
},
{

View File

@ -1,5 +1,4 @@
import { GlIcon } from '@gitlab/ui';
import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import ItemsList from '~/super_sidebar/components/items_list.vue';
import NavItem from '~/super_sidebar/components/nav_item.vue';
import { cachedFrequentProjects } from '../mock_data';
@ -12,8 +11,8 @@ describe('ItemsList component', () => {
const findNavItems = () => wrapper.findAllComponents(NavItem);
const createWrapper = ({ props = {}, slots = {}, mountFn = shallowMountExtended } = {}) => {
wrapper = mountFn(ItemsList, {
const createWrapper = ({ props = {}, slots = {} } = {}) => {
wrapper = shallowMountExtended(ItemsList, {
propsData: {
...props,
},
@ -61,41 +60,4 @@ describe('ItemsList component', () => {
expect(wrapper.findByTestId(testId).exists()).toBe(true);
});
describe('item removal', () => {
const findRemoveButton = () => wrapper.findByTestId('item-remove');
const mockProject = {
...firstMockedProject,
title: firstMockedProject.name,
};
beforeEach(() => {
createWrapper({
props: {
items: [mockProject],
},
mountFn: mountExtended,
});
});
it('renders the remove button', () => {
const itemRemoveButton = findRemoveButton();
expect(itemRemoveButton.exists()).toBe(true);
expect(itemRemoveButton.attributes('title')).toBe('Remove');
expect(itemRemoveButton.findComponent(GlIcon).props('name')).toBe('dash');
});
it('emits `remove-item` event with item param when remove button is clicked', () => {
const itemRemoveButton = findRemoveButton();
itemRemoveButton.vm.$emit(
'click',
{ stopPropagation: jest.fn(), preventDefault: jest.fn() },
mockProject,
);
expect(wrapper.emitted('remove-item')).toEqual([[mockProject]]);
});
});
});

View File

@ -1,4 +1,5 @@
import { mountExtended } from 'helpers/vue_test_utils_helper';
import { s__ } from '~/locale';
import SidebarMenu from '~/super_sidebar/components/sidebar_menu.vue';
import PinnedSection from '~/super_sidebar/components/pinned_section.vue';
import { PANELS_WITH_PINS } from '~/super_sidebar/constants';
@ -181,4 +182,11 @@ describe('SidebarMenu component', () => {
expect(findMainMenuSeparator().exists()).toBe(false);
});
});
describe('template', () => {
it('adds aria-label attribute to nav element', () => {
createWrapper({ ...sidebarData });
expect(wrapper.find('nav').attributes('aria-label')).toBe(s__('Navigation|Main navigation'));
});
});
});

View File

@ -310,12 +310,11 @@ describe('vue_shared/components/chronic_duration_input', () => {
});
it('passes updated prop via v-model', async () => {
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ value: MOCK_VALUE });
textElement.value = '2hr20min';
textElement.dispatchEvent(new Event('input'));
await nextTick();
expect(textElement.value).toBe('2 hrs 20 mins');
expect(textElement.value).toBe('2hr20min');
expect(hiddenElement.value).toBe(MOCK_VALUE.toString());
});
});

View File

@ -0,0 +1,56 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Environments::Update, feature_category: :environment_management do
let_it_be(:project) { create(:project) }
let_it_be(:environment) { create(:environment, project: project) }
let_it_be(:maintainer) { create(:user) }
let_it_be(:reporter) { create(:user) }
let(:user) { maintainer }
subject(:mutation) { described_class.new(object: nil, context: { current_user: user }, field: nil) }
before_all do
project.add_maintainer(maintainer)
project.add_reporter(reporter)
end
describe '#resolve' do
subject { mutation.resolve(id: environment_id, external_url: external_url) }
let(:environment_id) { environment.to_global_id }
let(:external_url) { 'https://gitlab.com/' }
context 'when service execution succeeded' do
it 'returns no errors' do
expect(subject[:errors]).to be_empty
end
it 'updates the environment' do
expect(subject[:environment][:external_url]).to eq(external_url)
end
end
context 'when service cannot update the attribute' do
let(:external_url) { 'http://${URL}' }
it 'returns an error' do
expect(subject)
.to eq({
environment: environment,
errors: ['External url URI is invalid']
})
end
end
context 'when user is reporter who does not have permission to access the environment' do
let(:user) { reporter }
it 'raises an error' do
expect { subject }.to raise_error(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
end
end
end
end

View File

@ -37,5 +37,22 @@ RSpec.describe SafeFormatHelper, feature_category: :shared do
.to raise_error ArgumentError, message
end
end
context 'with a view component' do
let(:view_component) do
Class.new(ViewComponent::Base) do
include SafeFormatHelper
def call
safe_format('<b>%{value}</b>', value: '<br>')
end
end
end
it 'safetly formats' do
expect(view_component.new.call)
.to eq('&lt;b&gt;&lt;br&gt;&lt;/b&gt;')
end
end
end
end

View File

@ -184,8 +184,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
let(:artifact) { build(:ci_job_artifact, :common_security_report_with_blank_names) }
context 'when message is provided' do
let(:finding) { report.findings.first }
it 'sets message from the report as a finding name' do
finding = report.findings.find { |x| x.compare_key == 'CVE-1020' }
expected_name = Gitlab::Json.parse(finding.raw_metadata)['message']
expect(finding.name).to eq(expected_name)
@ -194,8 +195,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
context 'when message is not provided' do
context 'and name is provided' do
let(:finding) { report.findings.second }
it 'sets name from the report as a name' do
finding = report.findings.find { |x| x.compare_key == 'CVE-1030' }
expected_name = Gitlab::Json.parse(finding.raw_metadata)['name']
expect(finding.name).to eq(expected_name)
@ -203,11 +205,12 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
end
context 'and name is not provided' do
let(:finding) { report.findings[2] }
context 'when location does not exist' do
let(:location) { nil }
it 'returns only identifier name' do
finding = report.findings.find { |x| x.compare_key == 'CVE-2017-11429' }
expect(finding.name).to eq("CVE-2017-11429")
end
end
@ -215,21 +218,22 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
context 'when location exists' do
context 'when CVE identifier exists' do
it 'combines identifier with location to create name' do
finding = report.findings.find { |x| x.compare_key == 'CVE-2017-11429' }
expect(finding.name).to eq("CVE-2017-11429 in yarn.lock")
end
end
context 'when CWE identifier exists' do
let(:finding) { report.findings[3] }
it 'combines identifier with location to create name' do
finding = report.findings.find { |x| x.compare_key == 'CWE-2017-11429' }
expect(finding.name).to eq("CWE-2017-11429 in yarn.lock")
end
end
context 'when neither CVE nor CWE identifier exist' do
let(:finding) { report.findings[4] }
it 'combines identifier with location to create name' do
finding = report.findings.find { |x| x.compare_key == 'OTHER-2017-11429' }
expect(finding.name).to eq("other-2017-11429 in yarn.lock")
end
end
@ -240,8 +244,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
describe 'parsing finding.details' do
context 'when details are provided' do
let(:finding) { report.findings[4] }
it 'sets details from the report' do
finding = report.findings.find { |x| x.compare_key == 'CVE-1020' }
expected_details = Gitlab::Json.parse(finding.raw_metadata)['details']
expect(finding.details).to eq(expected_details)
@ -249,8 +254,9 @@ RSpec.describe Gitlab::Ci::Parsers::Security::Common, feature_category: :vulnera
end
context 'when details are not provided' do
let(:finding) { report.findings[5] }
it 'sets empty hash' do
finding = report.findings.find { |x| x.compare_key == 'CVE-1030' }
expect(finding.details).to eq({})
end
end

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe Gitlab::Ci::Reports::Security::Report do
RSpec.describe Gitlab::Ci::Reports::Security::Report, feature_category: :vulnerability_management do
let_it_be(:pipeline) { create(:ci_pipeline) }
let(:created_at) { 2.weeks.ago }
@ -89,7 +89,7 @@ RSpec.describe Gitlab::Ci::Reports::Security::Report do
let(:other_report) do
create(
:ci_reports_security_report,
findings: [create(:ci_reports_security_finding, compare_key: 'other_finding')],
findings: [create(:ci_reports_security_finding)],
scanners: [create(:ci_reports_security_scanner, external_id: 'other_scanner', name: 'Other Scanner')],
identifiers: [create(:ci_reports_security_identifier, external_id: 'other_id', name: 'other_scanner')]
)

View File

@ -14,4 +14,27 @@ RSpec.describe Gitlab::Database::SchemaValidation::SchemaInconsistency, type: :m
it { is_expected.to validate_presence_of(:valitador_name) }
it { is_expected.to validate_presence_of(:table_name) }
end
describe 'scopes' do
describe '.with_open_issues' do
subject(:inconsistencies) { described_class.with_open_issues }
let(:closed_issue) { create(:issue, :closed) }
let(:open_issue) { create(:issue, :opened) }
let!(:schema_inconsistency_with_issue_closed) do
create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements',
valitador_name: 'different_definition_indexes', issue: closed_issue)
end
let!(:schema_inconsistency_with_issue_opened) do
create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements',
valitador_name: 'different_definition_indexes', issue: open_issue)
end
it 'returns only schema inconsistencies with GitLab issues open' do
expect(inconsistencies).to eq([schema_inconsistency_with_issue_opened])
end
end
end
end

View File

@ -63,19 +63,31 @@ RSpec.describe Gitlab::Database::SchemaValidation::TrackInconsistency, feature_c
end
context 'when the schema inconsistency already exists' do
before do
project.add_developer(user)
end
let!(:schema_inconsistency) do
create(:schema_inconsistency, object_name: 'index_name', table_name: 'achievements',
valitador_name: 'different_definition_indexes')
end
it 'does not create a schema inconsistency record' do
allow(Gitlab).to receive(:com?).and_return(true)
before do
project.add_developer(user)
end
expect { execute }.not_to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count }
context 'when the GitLab issue is open' do
it 'does not create a new schema inconsistency record' do
allow(Gitlab).to receive(:com?).and_return(true)
schema_inconsistency.issue.update!(state_id: Issue.available_states[:opened])
expect { execute }.not_to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count }
end
end
context 'when the GitLab is not open' do
it 'creates a new schema inconsistency record' do
allow(Gitlab).to receive(:com?).and_return(true)
schema_inconsistency.issue.update!(state_id: Issue.available_states[:closed])
expect { execute }.to change { Gitlab::Database::SchemaValidation::SchemaInconsistency.count }
end
end
end
end

View File

@ -0,0 +1,70 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Update Environment', feature_category: :deployment_management do
include GraphqlHelpers
let_it_be(:project) { create(:project, :repository) }
let_it_be(:environment) { create(:environment, project: project) }
let_it_be(:maintainer) { create(:user).tap { |u| project.add_maintainer(u) } }
let_it_be(:developer) { create(:user).tap { |u| project.add_maintainer(u) } }
let(:environment_id) { environment.to_global_id.to_s }
let(:current_user) { developer }
let(:mutation) do
graphql_mutation(:environment_update, input)
end
context 'when updating external URL' do
let(:input) do
{
id: environment_id,
external_url: 'https://gitlab.com/'
}
end
it 'updates successfully' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to change { environment.reload.external_url }.to('https://gitlab.com/')
expect(graphql_mutation_response(:environment_update)['errors']).to be_empty
end
context 'when url is invalid' do
let(:input) do
{
id: environment_id,
external_url: 'http://${URL}'
}
end
it 'returns error' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.not_to change { environment.reload.external_url }
expect(graphql_mutation_response(:environment_update)['errors'].first).to include('URI is invalid')
end
end
end
context 'when updating tier' do
let(:input) do
{
id: environment_id,
tier: 'STAGING'
}
end
it 'updates successfully' do
expect do
post_graphql_mutation(mutation, current_user: current_user)
end.to change { environment.reload.tier }.to('staging')
expect(graphql_mutation_response(:environment_update)['errors']).to be_empty
end
end
end

View File

@ -0,0 +1,55 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Environments::UpdateService, feature_category: :environment_management do
let_it_be(:project) { create(:project, :repository) }
let_it_be(:developer) { create(:user).tap { |u| project.add_developer(u) } }
let_it_be(:reporter) { create(:user).tap { |u| project.add_reporter(u) } }
let_it_be(:environment) { create(:environment, project: project) }
let(:service) { described_class.new(project, current_user, params) }
let(:current_user) { developer }
let(:params) { {} }
describe '#execute' do
subject { service.execute(environment) }
let(:params) { { external_url: 'https://gitlab.com/' } }
it 'updates the external URL' do
expect { subject }.to change { environment.reload.external_url }.to('https://gitlab.com/')
end
it 'returns successful response' do
response = subject
expect(response).to be_success
expect(response.payload[:environment]).to eq(environment)
end
context 'when params contain invalid value' do
let(:params) { { external_url: 'http://${URL}' } }
it 'returns an error' do
response = subject
expect(response).to be_error
expect(response.message).to match_array("External url URI is invalid")
expect(response.payload[:environment]).to eq(environment)
end
end
context 'when user is reporter' do
let(:current_user) { reporter }
it 'returns an error' do
response = subject
expect(response).to be_error
expect(response.message).to eq('Unauthorized to update the environment')
expect(response.payload[:environment]).to eq(environment)
end
end
end
end

View File

@ -19,7 +19,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
build(:ci_reports_security_finding,
identifiers: [identifier_1_primary, identifier_1_cve],
scanner: scanner_1,
severity: :low
severity: :low,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94610'
)
end
@ -27,7 +28,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
build(:ci_reports_security_finding,
identifiers: [identifier_1_primary, identifier_1_cve],
scanner: scanner_1,
severity: :low
severity: :low,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94611'
)
end
@ -36,7 +38,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
identifiers: [identifier_2_primary, identifier_2_cve],
location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34),
scanner: scanner_2,
severity: :medium
severity: :medium,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94612'
)
end
@ -45,7 +48,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
identifiers: [identifier_2_primary, identifier_2_cve],
location: build(:ci_reports_security_locations_sast, start_line: 32, end_line: 34),
scanner: scanner_2,
severity: :medium
severity: :medium,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94613'
)
end
@ -54,7 +58,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
identifiers: [identifier_2_primary, identifier_2_cve],
location: build(:ci_reports_security_locations_sast, start_line: 42, end_line: 44),
scanner: scanner_2,
severity: :medium
severity: :medium,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94614'
)
end
@ -62,7 +67,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
build(:ci_reports_security_finding,
identifiers: [identifier_cwe],
scanner: scanner_3,
severity: :high
severity: :high,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94615'
)
end
@ -70,7 +76,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
build(:ci_reports_security_finding,
identifiers: [identifier_cwe],
scanner: scanner_1,
severity: :critical
severity: :critical,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94616'
)
end
@ -78,7 +85,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
build(:ci_reports_security_finding,
identifiers: [identifier_wasc],
scanner: scanner_1,
severity: :medium
severity: :medium,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94617'
)
end
@ -86,7 +94,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
build(:ci_reports_security_finding,
identifiers: [identifier_wasc],
scanner: scanner_2,
severity: :critical
severity: :critical,
uuid: '61eb8e3e-3be1-4d6c-ba26-4e0dd4f94618'
)
end
@ -190,8 +199,8 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
finding_cwe_2,
finding_wasc_2,
finding_cwe_1,
finding_id_2_loc_2,
finding_id_2_loc_1,
finding_id_2_loc_2,
finding_wasc_1,
finding_id_1
])
@ -217,9 +226,32 @@ RSpec.describe Security::MergeReportsService, '#execute', feature_category: :cod
let(:identifier_cve) { build(:ci_reports_security_identifier, external_id: 'CVE-2019-123', external_type: 'cve') }
let(:identifier_semgrep) { build(:ci_reports_security_identifier, external_id: 'rules.bandit.B105', external_type: 'semgrep_id') }
let(:finding_id_1) { build(:ci_reports_security_finding, identifiers: [identifier_bandit, identifier_cve], scanner: bandit_scanner, report_type: :sast) }
let(:finding_id_2) { build(:ci_reports_security_finding, identifiers: [identifier_cve], scanner: semgrep_scanner, report_type: :sast) }
let(:finding_id_3) { build(:ci_reports_security_finding, identifiers: [identifier_semgrep], scanner: semgrep_scanner, report_type: :sast) }
let(:finding_id_1) do
build(
:ci_reports_security_finding,
identifiers: [identifier_bandit, identifier_cve],
scanner: bandit_scanner,
report_type: :sast,
uuid: '21ab978a-7052-5428-af0b-c7a4b3fe5020')
end
let(:finding_id_2) do
build(
:ci_reports_security_finding,
identifiers: [identifier_cve],
scanner: semgrep_scanner,
report_type: :sast,
uuid: '21ab978a-7052-5428-af0b-c7a4b3fe5021')
end
let(:finding_id_3) do
build(
:ci_reports_security_finding,
identifiers: [identifier_semgrep],
scanner: semgrep_scanner,
report_type: :sast,
uuid: '21ab978a-7052-5428-af0b-c7a4b3fe5022')
end
let(:bandit_report) do
build(:ci_reports_security_report,