Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot
2024-12-18 03:32:34 +00:00
parent 51222db2c1
commit 49d5d70d9f
27 changed files with 320 additions and 56 deletions

View File

@ -140,6 +140,30 @@ export const highlighter = (li, query) => {
return li.replace(regexp, (str, $1, $2, $3) => `> ${$1}<strong>${$2}</strong>${$3} <`);
};
/**
* Sets up subommands for quickaction for the given
* input with the provided command and the subcommand descriptions.
*
* @param {Object} $input input element
* @param {string} cmd command that triggers subcommand selection
* @param {Record<string, { header: string, description: string }>} data object containing names of commands as keys with description and header as values
*
*/
export const setupSubcommands = ($input, cmd, data) => {
$input.filter('[data-supports-quick-actions="true"]').atwho({
// Always keep the trailing space otherwise the command won't display correctly
at: `/${cmd} `,
alias: cmd,
data: Object.keys(data),
maxLen: 100,
displayTpl({ name }) {
const { header, description } = data[name];
return `<li><span class="name gl-font-bold">${lodashEscape(header)}</span><small class="description"><em>${lodashEscape(description)}</em></small></li>`;
},
});
};
export const defaultAutocompleteConfig = {
emojis: true,
members: true,
@ -318,18 +342,7 @@ class GfmAutoComplete {
},
};
$input.filter('[data-supports-quick-actions="true"]').atwho({
// Always keep the trailing space otherwise the command won't display correctly
at: '/submit_review ',
alias: 'submit_review',
data: Object.keys(REVIEW_STATES),
maxLen: 100,
displayTpl({ name }) {
const reviewState = REVIEW_STATES[name];
return `<li><span class="name gl-font-bold">${reviewState.header}</span><small class="description"><em>${reviewState.description}</em></small></li>`;
},
});
setupSubcommands($input, 'submit_review', REVIEW_STATES);
}
setupEmoji($input) {
@ -977,9 +990,7 @@ class GfmAutoComplete {
} else if (dataSource) {
AjaxCache.retrieve(dataSource, true)
.then((data) => {
if (data.some((c) => c.name === 'submit_review')) {
this.setSubmitReviewStates($input);
}
this.loadSubcommands($input, data);
this.loadData($input, at, data);
})
.catch(() => {
@ -990,6 +1001,12 @@ class GfmAutoComplete {
}
}
loadSubcommands($input, data) {
if (data.some((c) => c.name === 'submit_review')) {
this.setSubmitReviewStates($input);
}
}
// eslint-disable-next-line max-params
loadData($input, at, data, { search } = {}) {
this.isLoadingData[at] = false;

View File

@ -382,6 +382,7 @@ export default {
:autosave-key="autosaveKey"
:disabled="isSubmitting"
:autocomplete-data-sources="autocompleteDataSources"
:noteable-type="noteableType"
supports-quick-actions
@keydown.up="editCurrentUserLastNote()"
@keydown.shift.meta.enter="handleSave()"

View File

@ -153,6 +153,9 @@ export default {
}
return '#';
},
noteableType() {
return this.getNoteableData.noteableType;
},
diffParams() {
if (this.diffFile) {
return {
@ -305,7 +308,7 @@ export default {
trackSavedUsingEditor(
this.$refs.markdownEditor.isContentEditorActive,
`${this.getNoteableData.noteableType}_note`,
`${this.noteableType}_note`,
);
this.$emit(
@ -373,6 +376,7 @@ export default {
:add-spacing-classes="false"
:help-page-path="helpPagePath"
:note="discussionNote"
:noteable-type="noteableType"
:form-field-props="formFieldProps"
:autosave-key="autosaveKey"
:autocomplete-data-sources="autocompleteDataSources"

View File

@ -119,6 +119,11 @@ export default {
required: false,
default: () => ({}),
},
noteableType: {
type: String,
required: false,
default: '',
},
restrictedToolBarItems: {
type: Array,
required: false,
@ -388,6 +393,8 @@ export default {
:value="markdown"
class="note-textarea js-gfm-input markdown-area"
dir="auto"
:data-can-suggest="codeSuggestionsConfig.canSuggest"
:data-noteable-type="noteableType"
:data-supports-quick-actions="supportsQuickActions"
:data-testid="formFieldProps['data-testid'] || 'markdown-editor-form-field'"
:disabled="disabled"

View File

@ -18,6 +18,13 @@ module Mutations
required: true,
description: 'Group or project to be added to the CI job token scope.'
argument :default_permissions, GraphQL::Types::Boolean,
required: false,
default_value: true,
experiment: { milestone: '17.8' },
description: 'Indicates whether default permissions are enabled (true) or fine-grained permissions are ' \
'enabled (false).'
argument :job_token_policies, [Types::Ci::JobTokenScope::PoliciesEnum],
required: false,
default_value: [],
@ -36,16 +43,16 @@ module Mutations
null: true,
description: "CI job token's access scope."
def resolve(args)
project = authorized_find!(args[:project_path])
target = find_target_path(args[:target_path])
args.delete(:job_token_policies) unless Feature.enabled?(:add_policies_to_ci_job_token, project)
def resolve(project_path:, target_path:, default_permissions:, job_token_policies:)
project = authorized_find!(project_path)
target = find_target_path(target_path)
policies_enabled = Feature.enabled?(:add_policies_to_ci_job_token, project)
# Use default permissions if policies feature isn't enabled.
default = policies_enabled ? default_permissions : true
result = ::Ci::JobTokenScope::AddGroupOrProjectService
.new(project, current_user)
.execute(target, policies: args[:job_token_policies])
.execute(target, default_permissions: default, policies: job_token_policies)
if result.success?
{

View File

@ -18,6 +18,11 @@ module Mutations
required: true,
description: 'Group or project that the CI job token targets.'
argument :default_permissions, GraphQL::Types::Boolean,
required: true,
description: 'Indicates whether default permissions are enabled (true) or fine-grained permissions are ' \
'enabled (false).'
argument :job_token_policies, [Types::Ci::JobTokenScope::PoliciesEnum],
required: true,
description: 'List of policies added to the CI job token scope.'
@ -28,7 +33,7 @@ module Mutations
experiment: { milestone: '17.6' },
description: "Allowlist entry for the CI job token's access scope."
def resolve(project_path:, target_path:, job_token_policies:)
def resolve(project_path:, target_path:, default_permissions:, job_token_policies:)
project = authorized_find!(project_path)
target = find_target_using_path(target_path)
@ -38,7 +43,7 @@ module Mutations
result = ::Ci::JobTokenScope::UpdatePoliciesService
.new(project, current_user)
.execute(target, job_token_policies)
.execute(target, default_permissions, job_token_policies)
if result.success?
{

View File

@ -25,6 +25,11 @@ module Types
null: true,
description: 'Direction of access. Defaults to INBOUND.'
field :default_permissions,
GraphQL::Types::Boolean,
description: 'Indicates whether default permissions are enabled (true) or fine-grained permissions are ' \
'enabled (false).'
field :job_token_policies,
[Types::Ci::JobTokenScope::PoliciesEnum],
null: true,
@ -63,6 +68,10 @@ module Types
end
end
def default_permissions
Feature.enabled?(:add_policies_to_ci_job_token, object.source_project) ? object.default_permissions : true
end
def job_token_policies
return unless Feature.enabled?(:add_policies_to_ci_job_token, object.source_project)

View File

@ -30,25 +30,29 @@ module Ci
::Group.id_in(group_links.pluck(:target_group_id))
end
def add!(target_project, user:, policies: [])
def add!(target_project, user:, default_permissions: true, policies: [])
job_token_policies = add_policies_to_ci_job_token_enabled ? policies : []
default_permissions = add_policies_to_ci_job_token_enabled ? default_permissions : true
Ci::JobToken::ProjectScopeLink.create!(
source_project: @source_project,
direction: @direction,
target_project: target_project,
added_by: user,
default_permissions: default_permissions,
job_token_policies: job_token_policies
)
end
def add_group!(target_group, user:, policies: [])
def add_group!(target_group, user:, default_permissions: true, policies: [])
job_token_policies = add_policies_to_ci_job_token_enabled ? policies : []
default_permissions = add_policies_to_ci_job_token_enabled ? default_permissions : true
Ci::JobToken::GroupScopeLink.create!(
source_project: @source_project,
target_group: target_group,
added_by: user,
default_permissions: default_permissions,
job_token_policies: job_token_policies
)
end

View File

@ -5,13 +5,15 @@ module Ci
class AddGroupOrProjectService < ::BaseService
include EditScopeValidations
def execute(target, policies: [])
def execute(target, default_permissions: true, policies: [])
validate_target_exists!(target)
if target.is_a?(::Group)
::Ci::JobTokenScope::AddGroupService.new(project, current_user).execute(target, policies: policies)
::Ci::JobTokenScope::AddGroupService.new(project, current_user).execute(target,
default_permissions: default_permissions, policies: policies)
else
::Ci::JobTokenScope::AddProjectService.new(project, current_user).execute(target, policies: policies)
::Ci::JobTokenScope::AddProjectService.new(project, current_user).execute(target,
default_permissions: default_permissions, policies: policies)
end
rescue EditScopeValidations::NotFoundError => e

View File

@ -5,11 +5,11 @@ module Ci
class AddGroupService < ::BaseService
include EditScopeValidations
def execute(target_group, policies: [])
def execute(target_group, default_permissions: true, policies: [])
validate_source_project_and_target_group_access!(project, target_group, current_user)
link = allowlist
.add_group!(target_group, policies: policies, user: current_user)
.add_group!(target_group, default_permissions: default_permissions, policies: policies, user: current_user)
ServiceResponse.success(payload: { group_link: link })

View File

@ -5,11 +5,11 @@ module Ci
class AddProjectService < ::BaseService
include EditScopeValidations
def execute(target_project, policies: [], direction: :inbound)
def execute(target_project, default_permissions: true, policies: [], direction: :inbound)
validate_source_project_and_target_project_access!(project, target_project, current_user)
link = allowlist(direction)
.add!(target_project, policies: policies, user: current_user)
.add!(target_project, default_permissions: default_permissions, policies: policies, user: current_user)
ServiceResponse.success(payload: { project_link: link })

View File

@ -5,7 +5,7 @@ module Ci
class UpdatePoliciesService < ::BaseService
include EditScopeValidations
def execute(target, policies)
def execute(target, default_permissions, policies)
return unless Feature.enabled?(:add_policies_to_ci_job_token, project)
validate_target_exists!(target)
@ -15,7 +15,7 @@ module Ci
return error_link_not_found unless link
if link.update(job_token_policies: policies)
if link.update(default_permissions: default_permissions, job_token_policies: policies)
ServiceResponse.success(payload: link)
else
error_updating(link)

View File

@ -3134,6 +3134,7 @@ Input type: `CiJobTokenScopeAddGroupOrProjectInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationcijobtokenscopeaddgrouporprojectclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcijobtokenscopeaddgrouporprojectdefaultpermissions"></a>`defaultPermissions` **{warning-solid}** | [`Boolean`](#boolean) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.8. |
| <a id="mutationcijobtokenscopeaddgrouporprojectjobtokenpolicies"></a>`jobTokenPolicies` **{warning-solid}** | [`[CiJobTokenScopePolicies!]`](#cijobtokenscopepolicies) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 17.5. |
| <a id="mutationcijobtokenscopeaddgrouporprojectprojectpath"></a>`projectPath` | [`ID!`](#id) | Project that the CI job token scope belongs to. |
| <a id="mutationcijobtokenscopeaddgrouporprojecttargetpath"></a>`targetPath` | [`ID!`](#id) | Group or project to be added to the CI job token scope. |
@ -3225,6 +3226,7 @@ Input type: `CiJobTokenScopeUpdatePoliciesInput`
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationcijobtokenscopeupdatepoliciesclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationcijobtokenscopeupdatepoliciesdefaultpermissions"></a>`defaultPermissions` | [`Boolean!`](#boolean) | Indicates whether default permissions are enabled (true) or fine-grained permissions are enabled (false). |
| <a id="mutationcijobtokenscopeupdatepoliciesjobtokenpolicies"></a>`jobTokenPolicies` | [`[CiJobTokenScopePolicies!]!`](#cijobtokenscopepolicies) | List of policies added to the CI job token scope. |
| <a id="mutationcijobtokenscopeupdatepoliciesprojectpath"></a>`projectPath` | [`ID!`](#id) | Project that the CI job token scope belongs to. |
| <a id="mutationcijobtokenscopeupdatepoliciestargetpath"></a>`targetPath` | [`ID!`](#id) | Group or project that the CI job token targets. |
@ -20496,6 +20498,7 @@ Represents an allowlist entry for the CI_JOB_TOKEN.
| ---- | ---- | ----------- |
| <a id="cijobtokenscopeallowlistentryaddedby"></a>`addedBy` | [`UserCore`](#usercore) | User that added the entry. |
| <a id="cijobtokenscopeallowlistentrycreatedat"></a>`createdAt` | [`Time!`](#time) | When the entry was created. |
| <a id="cijobtokenscopeallowlistentrydefaultpermissions"></a>`defaultPermissions` | [`Boolean`](#boolean) | Indicates whether default permissions are enabled (true) or fine-grained permissions are enabled (false). |
| <a id="cijobtokenscopeallowlistentrydirection"></a>`direction` | [`String`](#string) | Direction of access. Defaults to INBOUND. |
| <a id="cijobtokenscopeallowlistentryjobtokenpolicies"></a>`jobTokenPolicies` **{warning-solid}** | [`[CiJobTokenScopePolicies!]`](#cijobtokenscopepolicies) | **Introduced** in GitLab 17.5. **Status**: Experiment. List of policies for the entry. |
| <a id="cijobtokenscopeallowlistentrysourceproject"></a>`sourceProject` | [`Project!`](#project) | Project that owns the allowlist entry. |

View File

@ -224,6 +224,49 @@ After the above steps have been completed, the automatic release process execute
- Else, this job automatically creates a new release and Git tag using the [releases API](../../api/releases/index.md#create-a-release). The version and message is obtained from the most recent entry in the `CHANGELOG.md` file for the project.
1. A pipeline is automatically triggered for the new Git tag. This pipeline releases the `latest`, `major`, `minor` and `patch` Docker images of the analyzer.
### Service account used in the automatic release process
| Key | Value |
|----------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|
| Account name | [@gl-service-dev-secure-analyzers-automation](https://gitlab.com/gl-service-dev-secure-analyzers-automation) |
| Purpose | Used for creating releases/tags |
| Member of | [`gitlab-org/security-products`](https://gitlab.com/groups/gitlab-org/security-products/-/group_members?search=gl-service-dev-secure-analyzers-automation) |
| Maximum role | `Developer` |
| Scope of the associated `GITLAB_TOKEN` | `api` |
| Expiry date of `GITLAB_TOKEN` | `December 3, 2025` |
### Token rotation for service account
The `GITLAB_TOKEN` for the [@gl-service-dev-secure-analyzers-automation](https://gitlab.com/gl-service-dev-secure-analyzers-automation) service account **must** be rotated before the `Expiry Date` listed [above](#service-account-used-in-the-automatic-release-process) by doing the following:
1. Log in as the `gl-service-dev-secure-analyzers-automation` user.
The list of administrators who have credentials for this account can be found in the [service account access request](https://gitlab.com/gitlab-com/team-member-epics/access-requests/-/issues/29538#admin-users).
Administrators can find the login credentials in the shared GitLab `1password` vault.
1. Create a new [Personal Access Token](../../user/profile/personal_access_tokens.md) with `api` scope for the `gl-service-dev-secure-analyzers-automation` service account.
1. Update the `password` field of the `GitLab API Token - gl-service-dev-secure-analyzers-automation` account in the shared GitLab `1password` vault to the new Personal Access Token created in step 2 (above), and set the `Expires at` field to indicate when the token expires.
1. Update the expiry date of the `GITLAB_TOKEN` field in the [Service account used in the automatic release process](#service-account-used-in-the-automatic-release-process) table.
1. Set the following variables to the new Personal Access Token created in step 2 above:
NOTE:
It's crucial to [mask and hide](../../ci/variables/index.md#hide-a-cicd-variable) the following variables.
1. `GITLAB_TOKEN` CI/CD variable for the [`gitlab-org/security-products/analyzers`](https://gitlab.com/groups/gitlab-org/security-products/analyzers/-/settings/ci_cd#js-cicd-variables-settings) group.
This allows all projects under the `gitlab-org/security-products/analyzers` namespace to inherit this `GITLAB_TOKEN` value.
1. `GITLAB_TOKEN` CI/CD variable for the [`gitlab-org/security-products/ci-templates`](https://gitlab.com/gitlab-org/security-products/ci-templates/-/settings/ci_cd#js-cicd-variables-settings) project.
This must be explicitly configured because the `ci-templates` project is not nested under the `gitlab-org/security-products/analyzers` namespace, and therefore _does not inherit_ the `GITLAB_TOKEN` value.
The `ci-templates` project requires the `GITLAB_TOKEN` to allow certain scripts to execute API calls. This step can be removed after [allow JOB-TOKEN access to CI/lint endpoint](https://gitlab.com/gitlab-org/gitlab/-/issues/438781) has been completed.
1. `SEC_REGISTRY_PASSWORD` CI/CD variable for [`gitlab-advanced-sast`](https://gitlab.com/gitlab-org/security-products/analyzers/gitlab-advanced-sast/-/settings/ci_cd#js-cicd-variables-settings).
This allows our [tagging script](https://gitlab.com/gitlab-org/security-products/ci-templates/blob/cfe285a/scripts/tag_image.sh) to pull from the private container registry in the development project `registry.gitlab.com/gitlab-org/security-products/analyzers/<analyzer-name>/tmp`, and push to the publicly accessible container registry `registry.gitlab.com/security-products/<analyzer-name>`.
### Steps to perform after releasing an analyzer
1. After a new version of the analyzer Docker image has been tagged and deployed, test it with the corresponding test project.
@ -450,14 +493,6 @@ This issue will guide you through the whole release process. In general, you hav
If needed, go to the pipeline corresponding to the last Git tag,
and trigger the manual job that controls the build of this image.
- Current bot accounts used in the pipeline
- Account name: [`@group_2452873_bot`](https://gitlab.com/group_2452873_bot)
- Use: Used for creating releases/tags
- Member of: Group [`gitlab-org/security-products`](https://gitlab.com/groups/gitlab-org/security-products/-/group_members?search=group_2452873_bot)
- Max role: `Developer`
- Scope of the associated `GITLAB_TOKEN`:
- Expiry Date of the associated `GITLAB_TOKEN`:
#### Dependency updates
All dependencies and upstream scanners (if any) used in the analyzer source are updated on a monthly cadence which primarily includes security fixes and non-breaking changes.

View File

@ -5920,6 +5920,9 @@ msgstr ""
msgid "Amazon Q"
msgstr ""
msgid "AmazonQ|:hourglass_flowing_sand: I'm creating unit tests for the selected lines of code. I'll update this comment when I'm done."
msgstr ""
msgid "AmazonQ|Active cloud connector token not found."
msgstr ""
@ -5941,6 +5944,9 @@ msgstr ""
msgid "AmazonQ|An unexpected error occurred while submitting the form. Please see the browser console log for more details."
msgstr ""
msgid "AmazonQ|Apply changes to this merge request based on the comments (Beta)"
msgstr ""
msgid "AmazonQ|Audience"
msgstr ""
@ -5962,9 +5968,18 @@ msgstr ""
msgid "AmazonQ|Copy to clipboard"
msgstr ""
msgid "AmazonQ|Create a merge request to incorporate Amazon Q suggestions (Beta)"
msgstr ""
msgid "AmazonQ|Create an identity provider for this GitLab instance within AWS using the following values. %{helpStart}Learn more%{helpEnd}."
msgstr ""
msgid "AmazonQ|Create fixes for review findings (Beta)"
msgstr ""
msgid "AmazonQ|Create unit tests for selected lines of code in Java or Python files (Beta)"
msgstr ""
msgid "AmazonQ|Enter the IAM role's ARN."
msgstr ""
@ -5989,6 +6004,21 @@ msgstr ""
msgid "AmazonQ|I understand that by selecting Save changes, GitLab creates a service account for Amazon Q and sends its credentials to AWS. Use of the Amazon Q Developer capabilities as part of GitLab Duo with Amazon Q is governed by the %{helpStart}AWS Customer Agreement%{helpEnd} or other written agreement between you and AWS governing your use of AWS services."
msgstr ""
msgid "AmazonQ|I'm generating a fix for this review finding. I'll update this comment when I'm done."
msgstr ""
msgid "AmazonQ|I'm generating code for this issue. I'll update this comment and open a merge request when I'm done."
msgstr ""
msgid "AmazonQ|I'm reviewing this merge request for security vulnerabilities, quality issues, and deficiencies. I'll provide an update when I'm done."
msgstr ""
msgid "AmazonQ|I'm revising this merge request based on your feedback. I'll update this comment and this merge request when I'm done."
msgstr ""
msgid "AmazonQ|I'm upgrading your code to Java 17. I'll update this comment and open a merge request when I'm done."
msgstr ""
msgid "AmazonQ|IAM role's ARN"
msgstr ""
@ -6007,6 +6037,9 @@ msgstr ""
msgid "AmazonQ|Provider type"
msgstr ""
msgid "AmazonQ|Review merge request for code quality and security issues (Beta)"
msgstr ""
msgid "AmazonQ|Save changes"
msgstr ""
@ -6019,9 +6052,15 @@ msgstr ""
msgid "AmazonQ|Something went wrong saving Amazon Q settings."
msgstr ""
msgid "AmazonQ|Sorry, I'm not able to complete the request at this moment. Please try again later."
msgstr ""
msgid "AmazonQ|Status"
msgstr ""
msgid "AmazonQ|Upgrade Java Maven application to Java 17 (Beta)"
msgstr ""
msgid "AmazonQ|Use Amazon Q to automate workflows, create a merge request from an issue, upgrade Java, and improve your code with AI-powered reviews."
msgstr ""
@ -6037,6 +6076,21 @@ msgstr ""
msgid "AmazonQ|Within your AWS account, create an IAM role for Amazon Q and the relevant identity provider. %{helpStart}Learn how to create an IAM role%{helpEnd}."
msgstr ""
msgid "AmazonQ|dev"
msgstr ""
msgid "AmazonQ|fix"
msgstr ""
msgid "AmazonQ|review"
msgstr ""
msgid "AmazonQ|test"
msgstr ""
msgid "AmazonQ|transform"
msgstr ""
msgid "AmbiguousRef|There is a branch and a tag with the same name of %{ref}."
msgstr ""

View File

@ -348,10 +348,13 @@ describe('issue_comment_form component', () => {
expect(findMarkdownEditor().find('textarea').attributes('disabled')).toBeDefined();
});
it('should support quick actions', () => {
it('should support quick actions and other props', () => {
mountComponent({ mountFunction: mountExtended });
expect(findMarkdownEditor().props('supportsQuickActions')).toBe(true);
expect(findMarkdownEditor().props()).toMatchObject({
supportsQuickActions: true,
noteableType: noteableDataMock.noteableType,
});
});
it('should link to markdown docs', () => {

View File

@ -118,6 +118,10 @@ describe('issue_note_form component', () => {
createComponentWrapper();
});
it('should render text area with noteable type', () => {
expect(textarea.attributes('data-noteable-type')).toBe(noteableDataMock.noteableType);
});
it('should render text area with placeholder', () => {
expect(textarea.attributes('placeholder')).toBe('Write a comment or drag your files here…');
});

View File

@ -363,13 +363,27 @@ describe('vue_shared/component/markdown/markdown_editor', () => {
name: formFieldName,
placeholder: formFieldPlaceholder,
'aria-label': formFieldAriaLabel,
'data-noteable-type': '',
'data-supports-quick-actions': 'true',
}),
);
expect(findTextarea().attributes('data-can-suggest')).toBeUndefined();
expect(findTextarea().element.value).toBe(value);
});
it('renders data on textarea for noteable type', () => {
buildWrapper({ propsData: { noteableType: 'MergeRequest' } });
expect(findTextarea().attributes('data-noteable-type')).toBe('MergeRequest');
});
it('renders data on textarea for can suggest', () => {
buildWrapper({ propsData: { codeSuggestionsConfig: { canSuggest: true } } });
expect(findTextarea().attributes('data-can-suggest')).toBe('true');
});
it(`emits ${EDITING_MODE_CONTENT_EDITOR} event when enableContentEditor emitted from markdown editor`, async () => {
buildWrapper();

View File

@ -39,7 +39,12 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddGroupOrProject, feature_category
let(:policies) { %w[read_containers read_packages] }
let(:mutation_args) do
{ project_path: project.full_path, target_path: target_project_path, job_token_policies: policies }
{
project_path: project.full_path,
target_path: target_project_path,
default_permissions: false,
job_token_policies: policies
}
end
it_behaves_like 'when user is not logged in'
@ -64,6 +69,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddGroupOrProject, feature_category
expect(project_link.source_project).to eq(project)
expect(project_link.target_project).to eq(target_project)
expect(project_link.added_by).to eq(current_user)
expect(project_link.default_permissions).to be(false)
expect(project_link.job_token_policies).to eq(policies)
end
@ -99,7 +105,12 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddGroupOrProject, feature_category
let(:policies) { %w[read_containers read_packages] }
let(:mutation_args) do
{ project_path: project.full_path, target_path: target_group_path, job_token_policies: policies }
{
project_path: project.full_path,
target_path: target_group_path,
default_permissions: false,
job_token_policies: policies
}
end
it_behaves_like 'when user is not logged in'
@ -124,6 +135,7 @@ RSpec.describe Mutations::Ci::JobTokenScope::AddGroupOrProject, feature_category
expect(group_link.source_project).to eq(project)
expect(group_link.target_group).to eq(target_group)
expect(group_link.added_by).to eq(current_user)
expect(group_link.default_permissions).to be(false)
expect(group_link.job_token_policies).to eq(policies)
end

View File

@ -10,6 +10,7 @@ RSpec.describe GitlabSchema.types['CiJobTokenScopeAllowlistEntry'], feature_cate
source_project
target
direction
default_permissions
job_token_policies
added_by
created_at

View File

@ -68,8 +68,23 @@ RSpec.describe Ci::JobToken::Allowlist, feature_category: :continuous_integratio
let_it_be(:added_project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:policies) { %w[read_containers read_packages] }
let_it_be(:default_permissions) { false }
subject(:add_project) { allowlist.add!(added_project, policies: policies, user: user) }
subject(:add_project) do
allowlist.add!(added_project, default_permissions: default_permissions, policies: policies, user: user)
end
[true, false].each do |d|
context "with default permissions #{d}" do
let_it_be(:default_permissions) { d }
it "sets default permissions to #{d}" do
project_link = add_project
expect(project_link.default_permissions).to eq(default_permissions)
end
end
end
[:inbound, :outbound].each do |d|
context "with #{d}" do
@ -97,6 +112,7 @@ RSpec.describe Ci::JobToken::Allowlist, feature_category: :continuous_integratio
expect(project_link.added_by_id).to eq(user.id)
expect(project_link.source_project_id).to eq(source_project.id)
expect(project_link.target_project_id).to eq(added_project.id)
expect(project_link.default_permissions).to be(true)
expect(project_link.job_token_policies).to eq([])
end
end
@ -108,8 +124,23 @@ RSpec.describe Ci::JobToken::Allowlist, feature_category: :continuous_integratio
let_it_be(:added_group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:policies) { %w[read_containers read_packages] }
let_it_be(:default_permissions) { false }
subject(:add_group) { allowlist.add_group!(added_group, policies: policies, user: user) }
subject(:add_group) do
allowlist.add_group!(added_group, default_permissions: default_permissions, policies: policies, user: user)
end
[true, false].each do |d|
context "with default permissions #{d}" do
let_it_be(:default_permissions) { d }
it "sets default permissions to #{d}" do
group_link = add_group
expect(group_link.default_permissions).to eq(default_permissions)
end
end
end
it 'adds the group scope link' do
group_link = add_group
@ -133,6 +164,7 @@ RSpec.describe Ci::JobToken::Allowlist, feature_category: :continuous_integratio
expect(group_link.added_by_id).to eq(user.id)
expect(group_link.source_project_id).to eq(source_project.id)
expect(group_link.target_group_id).to eq(added_group.id)
expect(group_link.default_permissions).to be(true)
expect(group_link.job_token_policies).to eq([])
end
end

View File

@ -34,6 +34,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
addedBy {
username
}
defaultPermissions
jobTokenPolicies
direction
}
@ -52,6 +53,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
addedBy {
username
}
defaultPermissions
jobTokenPolicies
direction
}
@ -70,6 +72,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
{
'addedBy' => { 'username' => current_user.username },
'direction' => 'inbound',
'defaultPermissions' => false,
'jobTokenPolicies' => ['READ_CONTAINERS'],
'sourceProject' => { 'fullPath' => project.full_path },
'target' => { 'fullPath' => target_group_1.full_path }
@ -85,6 +88,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
{
'addedBy' => { 'username' => current_user.username },
'direction' => 'outbound',
'defaultPermissions' => false,
'jobTokenPolicies' => ['READ_CONTAINERS'],
'sourceProject' => { 'fullPath' => project.full_path },
'target' => { 'fullPath' => target_project_2.full_path }
@ -92,6 +96,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
{
'addedBy' => { 'username' => current_user.username },
'direction' => 'inbound',
'defaultPermissions' => false,
'jobTokenPolicies' => ['READ_CONTAINERS'],
'sourceProject' => { 'fullPath' => project.full_path },
'target' => { 'fullPath' => target_project_1.full_path }
@ -138,6 +143,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
:ci_job_token_project_scope_link,
source_project: project,
target_project: target_project_1,
default_permissions: false,
job_token_policies: %w[read_containers],
added_by: current_user,
direction: :inbound
@ -147,6 +153,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
:ci_job_token_project_scope_link,
source_project: project,
target_project: target_project_2,
default_permissions: false,
job_token_policies: %w[read_containers],
added_by: current_user,
direction: :outbound
@ -157,6 +164,7 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
source_project: project,
target_group: target_group_1,
added_by: current_user,
default_permissions: false,
job_token_policies: %w[read_containers]
)
end
@ -180,6 +188,14 @@ RSpec.describe 'Querying CI_JOB_TOKEN allowlist for a project', feature_category
expect(allowlist.dig('projectsAllowlist', 'nodes', 0, 'jobTokenPolicies')).to be_nil
expect(allowlist.dig('projectsAllowlist', 'nodes', 1, 'jobTokenPolicies')).to be_nil
end
it 'returns default permissions as true', :aggregate_failures do
post_graphql(query, current_user: current_user)
expect(allowlist.dig('groupsAllowlist', 'nodes', 0, 'defaultPermissions')).to be(true)
expect(allowlist.dig('projectsAllowlist', 'nodes', 0, 'defaultPermissions')).to be(true)
expect(allowlist.dig('projectsAllowlist', 'nodes', 1, 'defaultPermissions')).to be(true)
end
end
it 'avoids N+1 queries', :use_sql_query_cache do

View File

@ -13,6 +13,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in
{
project_path: project.full_path,
target_path: target_path,
default_permissions: true,
job_token_policies: policies
}
end
@ -33,6 +34,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in
fullPath
}
}
defaultPermissions
jobTokenPolicies
}
QL
@ -74,6 +76,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in
:ci_job_token_project_scope_link,
source_project: project,
target_project: target_project,
default_permissions: false,
job_token_policies: %w[read_containers],
direction: :inbound
)
@ -88,6 +91,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in
'fullPath')).to eq(project.full_path)
expect(mutation_response.dig('ciJobTokenScopeAllowlistEntry', 'target',
'fullPath')).to eq(target_project.full_path)
expect(mutation_response.dig('ciJobTokenScopeAllowlistEntry', 'defaultPermissions')).to be(true)
expect(mutation_response.dig('ciJobTokenScopeAllowlistEntry', 'jobTokenPolicies')).to eq(policies)
end
@ -152,6 +156,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in
:ci_job_token_group_scope_link,
source_project: project,
target_group: target_group,
default_permissions: false,
job_token_policies: %w[read_containers]
)
end
@ -165,6 +170,7 @@ RSpec.describe 'CiJobTokenScopeUpdatePolicies', feature_category: :continuous_in
'fullPath')).to eq(project.full_path)
expect(mutation_response.dig('ciJobTokenScopeAllowlistEntry', 'target',
'fullPath')).to eq(target_group.full_path)
expect(mutation_response.dig('ciJobTokenScopeAllowlistEntry', 'defaultPermissions')).to be(true)
expect(mutation_response.dig('ciJobTokenScopeAllowlistEntry', 'jobTokenPolicies')).to eq(policies)
end

View File

@ -11,7 +11,9 @@ RSpec.describe Ci::JobTokenScope::AddGroupOrProjectService, feature_category: :c
let(:response_success) { ServiceResponse.success }
subject(:service_execute) { described_class.new(source_project, current_user).execute(target, policies: policies) }
subject(:service_execute) do
described_class.new(source_project, current_user).execute(target, default_permissions: false, policies: policies)
end
describe '#execute' do
context 'when group is a target to add' do
@ -26,7 +28,7 @@ RSpec.describe Ci::JobTokenScope::AddGroupOrProjectService, feature_category: :c
it 'calls AddGroupService to add a target' do
expect(add_group_service_double)
.to receive(:execute).with(target, policies: policies)
.to receive(:execute).with(target, default_permissions: false, policies: policies)
.and_return(response_success)
expect(service_execute).to eq(response_success)
@ -46,7 +48,7 @@ RSpec.describe Ci::JobTokenScope::AddGroupOrProjectService, feature_category: :c
it 'calls AddProjectService to add a target' do
expect(add_project_service_double)
.to receive(:execute).with(target, policies: policies)
.to receive(:execute).with(target, default_permissions: false, policies: policies)
.and_return(response_success)
expect(service_execute).to eq(response_success)

View File

@ -21,6 +21,7 @@ RSpec.describe Ci::JobTokenScope::AddGroupService, feature_category: :continuous
expect(group_link.source_project).to eq(project)
expect(group_link.target_group).to eq(target_group)
expect(group_link.added_by).to eq(current_user)
expect(group_link.default_permissions).to eq(default_permissions)
expect(group_link.job_token_policies).to eq(policies)
end
@ -39,13 +40,16 @@ RSpec.describe Ci::JobTokenScope::AddGroupService, feature_category: :continuous
expect(group_link.source_project).to eq(project)
expect(group_link.target_group).to eq(target_group)
expect(group_link.added_by).to eq(current_user)
expect(group_link.default_permissions).to be(true)
expect(group_link.job_token_policies).to eq([])
end
end
end
describe '#execute' do
subject(:result) { service.execute(target_group, policies: policies) }
subject(:result) { service.execute(target_group, default_permissions: default_permissions, policies: policies) }
let(:default_permissions) { false }
it_behaves_like 'editable group job token scope' do
context 'when user has permissions on source and target groups' do
@ -56,6 +60,12 @@ RSpec.describe Ci::JobTokenScope::AddGroupService, feature_category: :continuous
it_behaves_like 'adds group'
context 'when default_permissions is set to true' do
let(:default_permissions) { true }
it_behaves_like 'adds group'
end
context 'when token scope is disabled' do
before do
project.ci_cd_settings.update!(job_token_scope_enabled: false)

View File

@ -20,6 +20,7 @@ RSpec.describe Ci::JobTokenScope::AddProjectService, feature_category: :continuo
expect(project_link.source_project).to eq(project)
expect(project_link.target_project).to eq(target_project)
expect(project_link.added_by).to eq(current_user)
expect(project_link.default_permissions).to eq(default_permissions)
expect(project_link.job_token_policies).to eq(policies)
end
@ -38,13 +39,16 @@ RSpec.describe Ci::JobTokenScope::AddProjectService, feature_category: :continuo
expect(project_link.source_project).to eq(project)
expect(project_link.target_project).to eq(target_project)
expect(project_link.added_by).to eq(current_user)
expect(project_link.default_permissions).to be(true)
expect(project_link.job_token_policies).to eq([])
end
end
end
describe '#execute' do
subject(:result) { service.execute(target_project, policies: policies) }
subject(:result) { service.execute(target_project, default_permissions: default_permissions, policies: policies) }
let(:default_permissions) { false }
it_behaves_like 'editable job token scope' do
context 'when user has permissions on source and target projects' do
@ -57,6 +61,12 @@ RSpec.describe Ci::JobTokenScope::AddProjectService, feature_category: :continuo
it_behaves_like 'adds project'
context 'when default_permissions is set to true' do
let(:default_permissions) { true }
it_behaves_like 'adds project'
end
context 'when token scope is disabled' do
before do
project.ci_cd_settings.update!(job_token_scope_enabled: false)

View File

@ -9,7 +9,7 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont
let_it_be(:target_group) { create(:group, :private) }
subject(:execute) do
described_class.new(project, current_user).execute(target, policies)
described_class.new(project, current_user).execute(target, default_permissions, policies)
end
describe '#execute' do
@ -78,11 +78,13 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont
:ci_job_token_project_scope_link,
source_project: project,
target_project: target_project,
default_permissions: true,
job_token_policies: %w[read_containers],
direction: :inbound
)
end
let(:default_permissions) { false }
let(:policies) { %w[read_containers read_packages] }
it_behaves_like 'when user is not logged in'
@ -106,6 +108,7 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont
expect(project_link.source_project).to eq(project)
expect(project_link.target_project).to eq(target_project)
expect(project_link.default_permissions).to be(false)
expect(project_link.job_token_policies).to eq(%w[read_containers read_packages])
end
@ -132,10 +135,12 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont
:ci_job_token_group_scope_link,
source_project: project,
target_group: target_group,
default_permissions: true,
job_token_policies: %w[read_containers]
)
end
let(:default_permissions) { false }
let(:policies) { %w[read_containers read_packages] }
it_behaves_like 'when user is not logged in'
@ -159,6 +164,7 @@ RSpec.describe Ci::JobTokenScope::UpdatePoliciesService, feature_category: :cont
expect(group_link.source_project).to eq(project)
expect(group_link.target_group).to eq(target_group)
expect(group_link.default_permissions).to be(false)
expect(group_link.job_token_policies).to eq(%w[read_containers read_packages])
end