Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-01-28 03:40:53 +00:00
parent bc5c433ff1
commit 2f195ead02
41 changed files with 460 additions and 97 deletions

View File

@ -3086,7 +3086,6 @@ Gitlab/BoundedContexts:
- 'ee/app/services/dependencies/export_serializers/project_dependencies_service.rb'
- 'ee/app/services/dependencies/export_serializers/sbom/pipeline_service.rb'
- 'ee/app/services/dependencies/export_service.rb'
- 'ee/app/services/dependencies/fetch_export_service.rb'
- 'ee/app/services/deployments/approval_service.rb'
- 'ee/app/services/deployments/auto_rollback_service.rb'
- 'ee/app/services/dora/aggregate_metrics_service.rb'

View File

@ -8,5 +8,8 @@ MinAlertLevel = suggestion
[*.md]
BasedOnStyles = gitlab_base, gitlab_docs
# Disable the front matter check until we migrate titles to Hugo format
gitlab_docs.FrontMatter = NO
# Ignore SVG markup
TokenIgnores = (\*\*\{\w*\}\*\*)

View File

@ -1 +1 @@
dd5a7ec67062bdb145fa2f66385a9bea72ccce1f
36ef4e1bd95e15e6a369bf0bed384ddc7f06caa5

View File

@ -1 +1 @@
c2b97e286ae33847fcfb8c19fc03c156a5ee925d
84549df179cdbbafc15f7073206f9e20773d0fee

View File

@ -231,7 +231,7 @@ export default {
@click="toggleSubscribed"
>
<gl-animated-notification-icon
:class="{ '!gl-text-blue-500': subscribed }"
:class="{ '!gl-text-status-info': subscribed }"
:is-on="!subscribed"
/>
</gl-button>
@ -239,14 +239,14 @@ export default {
v-if="!isMergeRequest"
ref="tooltip"
v-gl-tooltip.left.viewport
category="secondary"
category="tertiary"
data-testid="subscribe-button"
:title="notificationTooltip"
class="sidebar-collapsed-icon sidebar-collapsed-container !gl-rounded-none !gl-border-0"
@click="toggleSubscribed"
>
<gl-animated-notification-icon
:class="{ '!gl-text-blue-500': subscribed }"
:class="{ '!gl-text-status-info': subscribed }"
:is-on="!subscribed"
/>
</gl-button>

View File

@ -143,6 +143,11 @@ export default {
required: false,
default: false,
},
canReportSpam: {
type: Boolean,
required: false,
default: false,
},
isConfidential: {
type: Boolean,
required: false,
@ -311,6 +316,10 @@ export default {
showDropdownTooltip() {
return !this.isDropdownVisible ? this.$options.i18n.moreActions : '';
},
submitAsSpamItem() {
const href = this.workItemWebUrl.replaceAll('work_items', 'issues').concat('/mark_as_spam');
return { text: __('Submit as spam'), href };
},
isAuthor() {
return this.workItemAuthorId === window.gon.current_user_id;
},
@ -600,6 +609,7 @@ export default {
</gl-disclosure-dropdown-item>
<gl-dropdown-divider />
<gl-disclosure-dropdown-item
v-if="!isAuthor"
:data-testid="$options.reportAbuseActionTestId"
@ -608,6 +618,12 @@ export default {
<template #list-item>{{ $options.i18n.reportAbuse }}</template>
</gl-disclosure-dropdown-item>
<gl-disclosure-dropdown-item
v-if="glFeatures.workItemsBeta && canReportSpam"
:item="submitAsSpamItem"
data-testid="submit-as-spam-item"
/>
<template v-if="canDelete">
<gl-disclosure-dropdown-item
:data-testid="$options.deleteActionTestId"

View File

@ -309,6 +309,9 @@ export default {
canDelete() {
return this.workItem.userPermissions?.deleteWorkItem;
},
canReportSpam() {
return this.workItem.userPermissions?.reportSpam;
},
canSetWorkItemMetadata() {
return this.workItem.userPermissions?.setWorkItemMetadata;
},
@ -867,6 +870,7 @@ export default {
:work-item-type-id="workItemTypeId"
:work-item-iid="iid"
:can-delete="canDelete"
:can-report-spam="canReportSpam"
:can-update="canUpdate"
:is-confidential="workItem.confidential"
:is-discussion-locked="isDiscussionLocked"

View File

@ -98,6 +98,9 @@ export default {
canDelete() {
return this.workItem.userPermissions?.deleteWorkItem;
},
canReportSpam() {
return this.workItem.userPermissions?.reportSpam;
},
isDiscussionLocked() {
return this.workItem.widgets?.find(isNotesWidget)?.discussionLocked;
},
@ -188,6 +191,7 @@ export default {
:work-item-type="workItemType"
:work-item-type-id="workItemTypeId"
:can-delete="canDelete"
:can-report-spam="canReportSpam"
:can-update="canUpdate"
:is-confidential="workItem.confidential"
:is-discussion-locked="isDiscussionLocked"

View File

@ -594,6 +594,7 @@ export const setNewWorkItemCache = async (
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: true,
__typename: 'WorkItemPermissions',
},
widgets,
@ -613,6 +614,7 @@ export const optimisticUserPermissions = {
createNote: false,
adminWorkItemLink: false,
markNoteAsInternal: false,
reportSpam: false,
__typename: 'WorkItemPermissions',
};

View File

@ -39,6 +39,7 @@ fragment WorkItem on WorkItem {
createNote
adminWorkItemLink
markNoteAsInternal
reportSpam
}
mockWidgets @client {
type

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
module Clusters
module Agents
class ManagedResource < ApplicationRecord
self.table_name = 'clusters_managed_resources'
belongs_to :build, class_name: 'Ci::Build'
belongs_to :cluster_agent, class_name: 'Clusters::Agent'
belongs_to :project
belongs_to :environment
validates :template_name, length: { maximum: 1024 }
end
end
end

View File

@ -32,6 +32,10 @@
"description": "Setting to understand if a user is joining a project or not during onboarding",
"type": "boolean"
},
"setup_for_company": {
"description": "Setting to understand if a user is registering their gitlab account for their company",
"type": "boolean"
},
"registration_objective": {
"description": "Goal of registration collected during onboarding",
"type": "integer",

View File

@ -1,9 +0,0 @@
---
name: composite_identity
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/468370
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/173006
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/506473
milestone: "17.7"
group: group::authentication
type: beta
default_enabled: true

View File

@ -201,6 +201,10 @@ ci_variables:
- table: projects
column: project_id
on_delete: async_delete
clusters_managed_resources:
- table: ci_builds
column: build_id
on_delete: async_delete
country_access_logs:
- table: users
column: user_id

View File

@ -0,0 +1,16 @@
- title: "Secret detection analyzer doesn't run as root user by default"
removal_milestone: "18.0"
announcement_milestone: "17.9"
breaking_change: true
window: 3
reporter: abellucci
stage: application_security_testing
issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/476160
# Use the impact calculator https://gitlab-com.gitlab.io/gl-infra/breaking-change-impact-calculator/?
impact: low # Can be one of: [critical, high, medium, low]
scope: instance # Can be one or a combination of: [instance, group, project]
resolution_role: Admin # Can be one of: [Admin, Owner, Maintainer, Developer]
manual_task: false # Can be true or false. Use this to denote whether a resolution action must be performed manually (true), or if it can be automated by using the API or other automation (false).
body: | # (required) Don't change this line.
From GitLab 18.0, the secret detection analyzer will no longer use the root user by default. You shouldn't experience any impact as a result of this change. However, you might experience issues if you use `before_script` or `after_script` to make changes to the image. GitLab doesn't support this use of `before_script` and `after_script`.
tiers: ultimate

View File

@ -0,0 +1,13 @@
---
table_name: clusters_managed_resources
classes:
- Clusters::Agents::ManagedResource
feature_categories:
- deployment_management
description: A managed resource for the GitLab managed Kubernetes resources
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/178118
milestone: '17.9'
gitlab_schema: gitlab_main_cell
sharding_key:
project_id: projects
table_size: small

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class CreateClustersManagedResources < Gitlab::Database::Migration[2.2]
milestone '17.9'
def change
create_table :clusters_managed_resources do |t|
t.references :build, index: { unique: true }, null: false
t.references :project, null: false
t.references :environment, null: false
t.references :cluster_agent, null: false
t.timestamps_with_timezone null: false
t.integer :status, default: 0, limit: 2, null: false
t.text :template_name, limit: 1024
end
end
end

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
class InsertForgottenActiveVersionedPagesDeploymentsLimitByNamespace < Gitlab::Database::Migration[2.2]
restrict_gitlab_migration gitlab_schema: :gitlab_main
milestone '17.9'
def up
create_or_update_plan_limit('active_versioned_pages_deployments_limit_by_namespace',
'ultimate_trial_paid_customer', 500)
create_or_update_plan_limit('active_versioned_pages_deployments_limit_by_namespace',
'opensource', 500)
end
def down
create_or_update_plan_limit('active_versioned_pages_deployments_limit_by_namespace',
'ultimate_trial_paid_customer', 0)
create_or_update_plan_limit('active_versioned_pages_deployments_limit_by_namespace',
'opensource', 0)
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddProjectFkToClustersManagedResources < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.9'
def up
add_concurrent_foreign_key :clusters_managed_resources, :projects, column: :project_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :clusters_managed_resources, column: :project_id
end
end
end

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
class AddEnvironmentFkToClustersManagedResources < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.9'
def up
add_concurrent_foreign_key :clusters_managed_resources, :environments, column: :environment_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :clusters_managed_resources, column: :environment_id
end
end
end

View File

@ -0,0 +1,17 @@
# frozen_string_literal: true
class AddClusterAgentFkToClustersManagedResources < Gitlab::Database::Migration[2.2]
disable_ddl_transaction!
milestone '17.9'
def up
add_concurrent_foreign_key :clusters_managed_resources, :cluster_agents,
column: :cluster_agent_id, on_delete: :cascade
end
def down
with_lock_retries do
remove_foreign_key :clusters_managed_resources, column: :cluster_agent_id
end
end
end

View File

@ -0,0 +1 @@
14b2d34e19f6b910c28c7054880475f0836fa11d56c95092f9b68367b8833003

View File

@ -0,0 +1 @@
406b476b5e44493e5fee0812f8e9595337bb28dfa244f22efa2a4d2f6406bd70

View File

@ -0,0 +1 @@
13ce973bb0b6d08ab05bb48fc2ad09052cdde5218d9062100ec66927a49ba1db

View File

@ -0,0 +1 @@
0771663b7fca1ad06744feedf7e897553e6d412b8d48ff80c5aafeb9999ff3c7

View File

@ -0,0 +1 @@
7c919968f10a864ebdeb44d029d2e03957c190adab01c3422e2e7870f66ae5a8

View File

@ -11303,6 +11303,28 @@ CREATE SEQUENCE clusters_kubernetes_namespaces_id_seq
ALTER SEQUENCE clusters_kubernetes_namespaces_id_seq OWNED BY clusters_kubernetes_namespaces.id;
CREATE TABLE clusters_managed_resources (
id bigint NOT NULL,
build_id bigint NOT NULL,
project_id bigint NOT NULL,
environment_id bigint NOT NULL,
cluster_agent_id bigint NOT NULL,
created_at timestamp with time zone NOT NULL,
updated_at timestamp with time zone NOT NULL,
status smallint DEFAULT 0 NOT NULL,
template_name text,
CONSTRAINT check_4f81a98847 CHECK ((char_length(template_name) <= 1024))
);
CREATE SEQUENCE clusters_managed_resources_id_seq
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
ALTER SEQUENCE clusters_managed_resources_id_seq OWNED BY clusters_managed_resources.id;
CREATE TABLE commit_user_mentions (
id bigint NOT NULL,
mentioned_users_ids bigint[],
@ -24560,6 +24582,8 @@ ALTER TABLE ONLY clusters ALTER COLUMN id SET DEFAULT nextval('clusters_id_seq':
ALTER TABLE ONLY clusters_kubernetes_namespaces ALTER COLUMN id SET DEFAULT nextval('clusters_kubernetes_namespaces_id_seq'::regclass);
ALTER TABLE ONLY clusters_managed_resources ALTER COLUMN id SET DEFAULT nextval('clusters_managed_resources_id_seq'::regclass);
ALTER TABLE ONLY commit_user_mentions ALTER COLUMN id SET DEFAULT nextval('commit_user_mentions_id_seq'::regclass);
ALTER TABLE ONLY compliance_framework_security_policies ALTER COLUMN id SET DEFAULT nextval('compliance_framework_security_policies_id_seq'::regclass);
@ -26776,6 +26800,9 @@ ALTER TABLE ONLY clusters_integration_prometheus
ALTER TABLE ONLY clusters_kubernetes_namespaces
ADD CONSTRAINT clusters_kubernetes_namespaces_pkey PRIMARY KEY (id);
ALTER TABLE ONLY clusters_managed_resources
ADD CONSTRAINT clusters_managed_resources_pkey PRIMARY KEY (id);
ALTER TABLE ONLY clusters
ADD CONSTRAINT clusters_pkey PRIMARY KEY (id);
@ -31566,6 +31593,14 @@ CREATE INDEX index_clusters_kubernetes_namespaces_on_environment_id ON clusters_
CREATE INDEX index_clusters_kubernetes_namespaces_on_project_id ON clusters_kubernetes_namespaces USING btree (project_id);
CREATE UNIQUE INDEX index_clusters_managed_resources_on_build_id ON clusters_managed_resources USING btree (build_id);
CREATE INDEX index_clusters_managed_resources_on_cluster_agent_id ON clusters_managed_resources USING btree (cluster_agent_id);
CREATE INDEX index_clusters_managed_resources_on_environment_id ON clusters_managed_resources USING btree (environment_id);
CREATE INDEX index_clusters_managed_resources_on_project_id ON clusters_managed_resources USING btree (project_id);
CREATE INDEX index_clusters_on_enabled_and_provider_type_and_id ON clusters USING btree (enabled, provider_type, id);
CREATE INDEX index_clusters_on_enabled_cluster_type_id_and_created_at ON clusters USING btree (enabled, cluster_type, id, created_at);
@ -37633,6 +37668,9 @@ ALTER TABLE ONLY ai_settings
ALTER TABLE ONLY merge_requests
ADD CONSTRAINT fk_06067f5644 FOREIGN KEY (latest_merge_request_diff_id) REFERENCES merge_request_diffs(id) ON DELETE SET NULL;
ALTER TABLE ONLY clusters_managed_resources
ADD CONSTRAINT fk_068dba90c3 FOREIGN KEY (cluster_agent_id) REFERENCES cluster_agents(id) ON DELETE CASCADE;
ALTER TABLE ONLY sbom_occurrences_vulnerabilities
ADD CONSTRAINT fk_07b81e3a81 FOREIGN KEY (vulnerability_id) REFERENCES vulnerabilities(id) ON DELETE CASCADE;
@ -38662,6 +38700,9 @@ ALTER TABLE ONLY agent_activity_events
ALTER TABLE ONLY issues
ADD CONSTRAINT fk_9c4516d665 FOREIGN KEY (duplicated_to_id) REFERENCES issues(id) ON DELETE SET NULL;
ALTER TABLE ONLY clusters_managed_resources
ADD CONSTRAINT fk_9c7b561962 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
ALTER TABLE ONLY packages_conan_recipe_revisions
ADD CONSTRAINT fk_9cdec8a86b FOREIGN KEY (package_id) REFERENCES packages_packages(id) ON DELETE CASCADE;
@ -39379,6 +39420,9 @@ ALTER TABLE ONLY application_settings
ALTER TABLE ONLY issuable_severities
ADD CONSTRAINT fk_f9df19ecb6 FOREIGN KEY (namespace_id) REFERENCES namespaces(id) ON DELETE CASCADE;
ALTER TABLE ONLY clusters_managed_resources
ADD CONSTRAINT fk_fad3c3b2e2 FOREIGN KEY (environment_id) REFERENCES environments(id) ON DELETE CASCADE;
ALTER TABLE p_ci_stages
ADD CONSTRAINT fk_fb57e6cc56_p FOREIGN KEY (partition_id, pipeline_id) REFERENCES p_ci_pipelines(partition_id, id) ON UPDATE CASCADE ON DELETE CASCADE;

View File

@ -0,0 +1,52 @@
extends: script
message: "Front matter must have valid 'title' and be closed."
link: https://docs.gitlab.com/ee/development/documentation/metadata/
level: error
scope: raw
script: |
text := import("text")
matches := []
// Initialize variables
frontmatterDelimiterCount := 0
frontmatter := ""
hasError := false
// Check if frontmatter exists
if !text.re_match("^---\n", scope) {
hasError = true
}
if !hasError {
for line in text.split(scope, "\n") {
if frontmatterDelimiterCount == 1 {
frontmatter += line + "\n"
}
if frontmatterDelimiterCount == 2 {
break
}
if text.re_match("^---", line) {
frontmatterDelimiterCount++
start := text.index(scope, line)
matches = append(matches, {begin: start, end: start + len(line)})
}
}
// Check for unclosed frontmatter
if frontmatterDelimiterCount != 2 {
hasError = true
}
// First check if we have a title key at all
hasTitleKey := text.re_match("(?m)^[tT]itle:", frontmatter)
// Then check if it has content (anything but whitespace) after the colon
hasValidTitle := text.re_match("(?m)^[tT]itle:[^\\n]*[^\\s][^\\n]*$", frontmatter)
if !hasError && (!hasTitleKey || !hasValidTitle) {
hasError = true
}
}
if !hasError {
matches = []
}

View File

@ -7,12 +7,21 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Guest users
DETAILS:
**Tier:** Ultimate
**Tier:** Free, Premium, Ultimate
**Offering:** GitLab.com, GitLab Self-Managed, GitLab Dedicated
Users assigned the Guest role have limited access and capabilities compared to other user roles. Their permissions are restricted and are designed to provide basic visibility and interaction without compromising sensitive project data. For more information, see [Roles and permissions](../user/permissions.md).
In GitLab Ultimate, the Guest role is free and does not count towards the license seat count. You can assign the Guest role to users [through the API](../api/members.md#add-a-member-to-a-group-or-project) or the GitLab UI.
In GitLab Free and Premium, Guest users count towards the license seat usage.
## Unlimited seat usage
DETAILS:
**Tier:** Ultimate
In GitLab Ultimate, users with the Guest role do not count towards the license seat usage. You can add Guest users to your GitLab instance without impacting your billable seats.
While Guest users generally have limited access, you can configure a [custom role](../user/custom_roles.md) that includes the [`View repository code` permission](../user/custom_roles/abilities.md#source-code-management) to allow Guests to read code in your repositories. Adding any other permissions causes the role to occupy a billable seat.
## Assign Guest role to users
@ -20,7 +29,7 @@ Prerequisites:
- You must have at least the Maintainer role.
You can assign the Guest role to a current member of a group or project, or assign this role when creating a new member.
You can assign the Guest role to a current member of a group or project, or assign this role when creating a new member. You can do this [through the API](../api/members.md#add-a-member-to-a-group-or-project) or the GitLab UI.
To assign the Guest role to a current group or project member:

View File

@ -86,4 +86,5 @@ This window takes place on May 5 - 7, 2025 from 09:00 UTC to 22:00 UTC.
| [Updated tooling to release CI/CD components to the Catalog](https://gitlab.com/groups/gitlab-org/-/epics/12788) | High | Verify | Instance |
| [Increased default security for use of pipeline variables](https://gitlab.com/gitlab-org/gitlab/-/issues/502382) | Medium | Verify | Project |
| [Amazon S3 Signature Version 2](https://gitlab.com/gitlab-org/container-registry/-/issues/1449) | Low | Package | Project |
| [Secret detection analyzer doesn't run as root user by default](https://gitlab.com/gitlab-org/gitlab/-/issues/476160) | Low | Application_security_testing | Instance |
| [Remove `previousStageJobsOrNeeds` from GraphQL](https://gitlab.com/gitlab-org/gitlab/-/issues/424417) | Low | Verify | Instance |

View File

@ -1352,6 +1352,22 @@ If you need to use the cache when scanning a project, you can restore the previo
<div class="deprecation breaking-change" data-milestone="18.0">
### Secret detection analyzer doesn't run as root user by default
<div class="deprecation-notes">
- Announced in GitLab <span class="milestone">17.9</span>
- Removal in GitLab <span class="milestone">18.0</span> ([breaking change](https://docs.gitlab.com/ee/update/terminology.html#breaking-change))
- To discuss this change or learn more, see the [deprecation issue](https://gitlab.com/gitlab-org/gitlab/-/issues/476160).
</div>
From GitLab 18.0, the secret detection analyzer will no longer use the root user by default. You shouldn't experience any impact as a result of this change. However, you might experience issues if you use `before_script` or `after_script` to make changes to the image. GitLab doesn't support this use of `before_script` and `after_script`.
</div>
<div class="deprecation breaking-change" data-milestone="18.0">
### Support for REST API endpoints that reset runner registration tokens
<div class="deprecation-notes">

View File

@ -85,7 +85,7 @@ module Gitlab
end
def composite?
@user.has_composite_identity? && composite_identity_enabled?
@user.has_composite_identity?
end
def sidekiq_link!(job)
@ -93,7 +93,6 @@ module Gitlab
end
def link!(scope_user)
return self unless composite_identity_enabled?
return self unless scope_user
##
@ -128,10 +127,6 @@ module Gitlab
private
def composite_identity_enabled?
Feature.enabled?(:composite_identity, @user)
end
def scoped_user_id
scoped_user.id
end

View File

@ -0,0 +1,10 @@
# frozen_string_literal: true
FactoryBot.define do
factory :clusters_managed_resource, class: 'Clusters::Agents::ManagedResource' do
project
environment
association :cluster_agent
association :build
end
end

View File

@ -79,6 +79,26 @@ RSpec.describe 'Work item detail', :js, feature_category: :team_planning do
it_behaves_like 'work items change type', 'Issue', '[data-testid="issue-type-issue-icon"]'
end
context 'for signed in admin' do
let_it_be(:admin) { create(:admin) }
context 'with akismet integration' do
let_it_be(:user_agent_detail) { create(:user_agent_detail, subject: work_item) }
before_all do
project.add_maintainer(admin)
end
before do
stub_application_setting(akismet_enabled: true)
sign_in(admin)
visit work_items_path
end
it_behaves_like 'work items submit as spam'
end
end
context 'for signed in owner' do
before_all do
project.add_owner(user)

View File

@ -70,6 +70,7 @@ describe('WorkItemActions component', () => {
const findCopyCreateNoteEmailButton = () =>
wrapper.findByTestId(TEST_ID_COPY_CREATE_NOTE_EMAIL_ACTION);
const findReportAbuseButton = () => wrapper.findByTestId(TEST_ID_REPORT_ABUSE);
const findSubmitAsSpamItem = () => wrapper.findByTestId('submit-as-spam-item');
const findNewRelatedItemButton = () => wrapper.findByTestId(TEST_ID_NEW_RELATED_WORK_ITEM);
const findChangeTypeButton = () => wrapper.findByTestId(TEST_ID_CHANGE_TYPE_ACTION);
const findReportAbuseModal = () => wrapper.findComponent(WorkItemAbuseModal);
@ -120,6 +121,7 @@ describe('WorkItemActions component', () => {
const createComponent = ({
canUpdate = true,
canDelete = true,
canReportSpam = true,
hasOkrsFeature = true,
isConfidential = false,
isDiscussionLocked = false,
@ -155,10 +157,11 @@ describe('WorkItemActions component', () => {
fullPath: 'gitlab-org/gitlab-test',
workItemId: 'gid://gitlab/WorkItem/1',
workItemIid: '1',
workItemWebUrl: 'web/url',
workItemWebUrl: 'gitlab-org/gitlab-test/-/work_items/1',
isGroup,
canUpdate,
canDelete,
canReportSpam,
isConfidential,
isDiscussionLocked,
subscribed,
@ -258,6 +261,10 @@ describe('WorkItemActions component', () => {
testId: TEST_ID_REPORT_ABUSE,
text: 'Report abuse',
},
{
testId: 'submit-as-spam-item',
text: 'Submit as spam',
},
{
testId: TEST_ID_DELETE_ACTION,
text: 'Delete task',
@ -612,6 +619,23 @@ describe('WorkItemActions component', () => {
});
});
describe('submit as spam item', () => {
it('renders the "Submit as spam" action', () => {
createComponent();
expect(findSubmitAsSpamItem().props('item')).toEqual({
href: 'gitlab-org/gitlab-test/-/issues/1/mark_as_spam',
text: 'Submit as spam',
});
});
it('does not render the "Submit as spam" action when not allowed', () => {
createComponent({ canReportSpam: false });
expect(findSubmitAsSpamItem().exists()).toBe(false);
});
});
describe('new related item', () => {
it('passes related item data to create work item modal', () => {
createComponent();
@ -620,7 +644,7 @@ describe('WorkItemActions component', () => {
id: 'gid://gitlab/WorkItem/1',
reference: 'gitlab-org/gitlab-test#1',
type: 'Task',
webUrl: 'web/url',
webUrl: 'gitlab-org/gitlab-test/-/work_items/1',
});
});

View File

@ -220,6 +220,7 @@ export const workItemQueryResponse = {
createNote: false,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
widgets: [
@ -342,6 +343,7 @@ export const updateWorkItemMutationResponse = {
createNote: false,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
reference: 'test-project-path#1',
@ -478,6 +480,7 @@ export const convertWorkItemMutationResponse = {
createNote: false,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
reference: 'gitlab-org/gitlab-test#1',
@ -1335,6 +1338,7 @@ export const workItemResponseFactory = ({
canDelete = false,
canCreateNote = false,
adminParentLink = false,
reportSpam = false,
canAdminWorkItemLink = true,
canMarkNoteAsInternal = true,
notificationsWidgetPresent = true,
@ -1425,6 +1429,7 @@ export const workItemResponseFactory = ({
adminWorkItemLink: canAdminWorkItemLink,
createNote: canCreateNote,
markNoteAsInternal: canMarkNoteAsInternal,
reportSpam,
__typename: 'WorkItemPermissions',
},
reference: 'test-project-path#1',
@ -1818,6 +1823,7 @@ export const createWorkItemMutationResponse = {
createNote: false,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
reference: 'test-project-path#1',
@ -1891,6 +1897,7 @@ export const workItemHierarchyNoUpdatePermissionResponse = {
createNote: false,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
namespace: {
@ -2326,6 +2333,7 @@ export const workItemHierarchyResponse = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
author: {
@ -2391,6 +2399,7 @@ export const workItemObjectiveWithChild = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
author: {
@ -2481,6 +2490,7 @@ export const workItemObjectiveWithoutChild = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
author: {
@ -2534,6 +2544,7 @@ export const workItemHierarchyTreeEmptyResponse = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
confidential: false,
@ -2797,6 +2808,7 @@ export const workItemHierarchyTreeResponse = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
confidential: false,
@ -2841,6 +2853,7 @@ export const workItemHierarchyTreeSingleClosedItemResponse = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
confidential: false,
@ -2978,6 +2991,7 @@ export const workItemObjectiveWithClosedChild = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
author: {
@ -3044,6 +3058,7 @@ export const changeWorkItemParentMutationResponse = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
description: null,
@ -5521,6 +5536,7 @@ export const createWorkItemQueryResponse = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
mockWidgets: [],
@ -5811,6 +5827,7 @@ const mockUserPermissions = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
};
@ -5972,6 +5989,7 @@ export const workItemHierarchyNoChildrenTreeResponse = {
createNote: true,
adminWorkItemLink: true,
markNoteAsInternal: true,
reportSpam: false,
__typename: 'WorkItemPermissions',
},
confidential: false,

View File

@ -124,77 +124,59 @@ RSpec.describe Gitlab::Auth::Identity, :request_store, feature_category: :system
end
describe '.link_from_web_request' do
context 'when composite identity feature flag is enabled' do
context 'when service_account has composite identity enforced' do
before do
allow(primary_user).to receive(:composite_identity_enforced).and_return(true)
end
context 'when service_account has composite identity enforced' do
before do
allow(primary_user).to receive(:composite_identity_enforced).and_return(true)
end
it 'creates and links identity with scope user' do
it 'creates and links identity with scope user' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity.primary_user).to eq(primary_user)
expect(identity.scoped_user).to eq(scoped_user)
expect(identity).to be_linked
end
context 'when trying to link different scoped users' do
let(:another_scope_user) { create(:user) }
it 'raises IdentityLinkMismatchError when trying to link different scoped users' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity.primary_user).to eq(primary_user)
expect(identity.scoped_user).to eq(scoped_user)
expect(identity).to be_linked
end
context 'when trying to link different scoped users' do
let(:another_scope_user) { create(:user) }
it 'raises IdentityLinkMismatchError when trying to link different scoped users' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect do
identity.link!(another_scope_user)
end.to raise_error(described_class::IdentityLinkMismatchError)
end
end
end
context 'when service_account does not have composite identity enforced' do
it 'creates identity without linking' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity).not_to be_linked
end
end
context 'when composite identity feature flag is disabled' do
before do
stub_feature_flags(composite_identity: false)
end
it 'creates identity without linking' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity.primary_user).to eq(primary_user)
expect(identity).not_to be_linked
end
end
context 'when service_account is not present' do
it 'raises an error' do
expect do
described_class.link_from_web_request(
service_account: nil,
scoped_user: scoped_user
)
end.to raise_error(described_class::MissingServiceAccountError)
identity.link!(another_scope_user)
end.to raise_error(described_class::IdentityLinkMismatchError)
end
end
end
context 'when service_account does not have composite identity enforced' do
it 'creates identity without linking' do
identity = described_class.link_from_web_request(
service_account: primary_user,
scoped_user: scoped_user
)
expect(identity).not_to be_linked
end
end
context 'when service_account is not present' do
it 'raises an error' do
expect do
described_class.link_from_web_request(
service_account: nil,
scoped_user: scoped_user
)
end.to raise_error(described_class::MissingServiceAccountError)
end
end
end
describe '.sidekiq_restore!' do

View File

@ -521,16 +521,6 @@ RSpec.describe Ability, feature_category: :system_access do
expect(subject).to be_falsey
end
context 'with disabled composite_identity feature flag' do
before do
stub_feature_flags(composite_identity: false)
end
it 'returns true' do
expect(subject).to be_truthy
end
end
context 'with unenforced composite identity' do
before do
allow(user).to receive(:composite_identity_enforced).and_return(false)

View File

@ -0,0 +1,12 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Clusters::Agents::ManagedResource, feature_category: :deployment_management do
it { is_expected.to belong_to(:build).class_name('Ci::Build') }
it { is_expected.to belong_to(:cluster_agent).class_name('Clusters::Agent') }
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:environment) }
it { is_expected.to validate_length_of(:template_name).is_at_most(1024) }
end

View File

@ -20,6 +20,7 @@ RSpec.describe UserDetail, feature_category: :system_access do
let(:glm_source) { 'glm_source' }
let(:glm_content) { 'glm_content' }
let(:joining_project) { true }
let(:setup_for_company) { true }
let(:role) { 0 }
let(:onboarding_status) do
{
@ -31,6 +32,7 @@ RSpec.describe UserDetail, feature_category: :system_access do
glm_source: glm_source,
glm_content: glm_content,
joining_project: joining_project,
setup_for_company: setup_for_company,
role: role
}
end
@ -177,6 +179,22 @@ RSpec.describe UserDetail, feature_category: :system_access do
end
end
context 'for setup_for_company' do
let(:onboarding_status) do
{
setup_for_company: setup_for_company
}
end
it { is_expected.to allow_value(onboarding_status).for(:onboarding_status) }
context "when 'setup_for_company' is invalid" do
let(:setup_for_company) { 'true' }
it { is_expected.not_to allow_value(onboarding_status).for(:onboarding_status) }
end
end
context 'for role' do
let(:onboarding_status) do
{

View File

@ -400,6 +400,14 @@ RSpec.shared_examples 'work items confidentiality' do
end
end
RSpec.shared_examples 'work items submit as spam' do
it 'shows link to submit as spam' do
click_button _('More actions'), match: :first
expect(page).to have_link 'Submit as spam'
end
end
RSpec.shared_examples 'work items todos' do
it 'adds item to to-do list', :aggregate_failures do
expect(page).to have_button s_('WorkItem|Add a to-do item')