Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-08-14 00:10:28 +00:00
parent 3825437c53
commit 968e01a6dd
21 changed files with 397 additions and 109 deletions

View file

@ -2,3 +2,4 @@
export const ESC_KEY = 'Escape'; export const ESC_KEY = 'Escape';
export const ESC_KEY_IE11 = 'Esc'; // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key export const ESC_KEY_IE11 = 'Esc'; // https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
export const ENTER_KEY = 'Enter';

View file

@ -85,7 +85,7 @@ export default {
saveButtonLabel() { saveButtonLabel() {
return this.isExistingRelease ? __('Save changes') : __('Create release'); return this.isExistingRelease ? __('Save changes') : __('Create release');
}, },
isSaveChangesDisabled() { isFormSubmissionDisabled() {
return this.isUpdatingRelease || !this.isValid; return this.isUpdatingRelease || !this.isValid;
}, },
milestoneComboboxExtraLinks() { milestoneComboboxExtraLinks() {
@ -116,13 +116,18 @@ export default {
'updateReleaseNotes', 'updateReleaseNotes',
'updateReleaseMilestones', 'updateReleaseMilestones',
]), ]),
submitForm() {
if (!this.isFormSubmissionDisabled) {
this.saveRelease();
}
},
}, },
}; };
</script> </script>
<template> <template>
<div class="d-flex flex-column"> <div class="d-flex flex-column">
<p class="pt-3 js-subtitle-text" v-html="subtitleText"></p> <p class="pt-3 js-subtitle-text" v-html="subtitleText"></p>
<form v-if="showForm" @submit.prevent="saveRelease()"> <form v-if="showForm" class="js-quick-submit" @submit.prevent="submitForm">
<tag-field /> <tag-field />
<gl-form-group> <gl-form-group>
<label for="release-title">{{ __('Release title') }}</label> <label for="release-title">{{ __('Release title') }}</label>
@ -134,7 +139,7 @@ export default {
class="form-control" class="form-control"
/> />
</gl-form-group> </gl-form-group>
<gl-form-group class="w-50"> <gl-form-group class="w-50" @keydown.enter.prevent.capture>
<label>{{ __('Milestones') }}</label> <label>{{ __('Milestones') }}</label>
<div class="d-flex flex-column col-md-6 col-sm-10 pl-0"> <div class="d-flex flex-column col-md-6 col-sm-10 pl-0">
<milestone-combobox <milestone-combobox
@ -163,8 +168,6 @@ export default {
data-supports-quick-actions="false" data-supports-quick-actions="false"
:aria-label="__('Release notes')" :aria-label="__('Release notes')"
:placeholder="__('Write your release notes or drag your files here…')" :placeholder="__('Write your release notes or drag your files here…')"
@keydown.meta.enter="saveRelease()"
@keydown.ctrl.enter="saveRelease()"
></textarea> ></textarea>
</template> </template>
</markdown-field> </markdown-field>
@ -179,7 +182,7 @@ export default {
category="primary" category="primary"
variant="success" variant="success"
type="submit" type="submit"
:disabled="isSaveChangesDisabled" :disabled="isFormSubmissionDisabled"
data-testid="submit-button" data-testid="submit-button"
> >
{{ saveButtonLabel }} {{ saveButtonLabel }}

View file

@ -49,6 +49,12 @@ export default {
this.removeAssetLink(linkId); this.removeAssetLink(linkId);
this.ensureAtLeastOneLink(); this.ensureAtLeastOneLink();
}, },
updateUrl(link, newUrl) {
this.updateAssetLinkUrl({ linkIdToUpdate: link.id, newUrl });
},
updateName(link, newName) {
this.updateAssetLinkName({ linkIdToUpdate: link.id, newName });
},
hasDuplicateUrl(link) { hasDuplicateUrl(link) {
return Boolean(this.getLinkErrors(link).isDuplicate); return Boolean(this.getLinkErrors(link).isDuplicate);
}, },
@ -138,7 +144,9 @@ export default {
type="text" type="text"
class="form-control" class="form-control"
:state="isUrlValid(link)" :state="isUrlValid(link)"
@change="updateAssetLinkUrl({ linkIdToUpdate: link.id, newUrl: $event })" @change="updateUrl(link, $event)"
@keydown.ctrl.enter="updateUrl(link, $event.target.value)"
@keydown.meta.enter="updateUrl(link, $event.target.value)"
/> />
<template #invalid-feedback> <template #invalid-feedback>
<span v-if="hasEmptyUrl(link)" class="invalid-feedback d-inline"> <span v-if="hasEmptyUrl(link)" class="invalid-feedback d-inline">
@ -175,7 +183,9 @@ export default {
type="text" type="text"
class="form-control" class="form-control"
:state="isNameValid(link)" :state="isNameValid(link)"
@change="updateAssetLinkName({ linkIdToUpdate: link.id, newName: $event })" @change="updateName(link, $event)"
@keydown.ctrl.enter="updateName(link, $event.target.value)"
@keydown.meta.enter="updateName(link, $event.target.value)"
/> />
<template #invalid-feedback> <template #invalid-feedback>
<span v-if="hasEmptyName(link)" class="invalid-feedback d-inline"> <span v-if="hasEmptyName(link)" class="invalid-feedback d-inline">

View file

@ -32,5 +32,8 @@ export default {
isMergeImmediatelyDangerous() { isMergeImmediatelyDangerous() {
return false; return false;
}, },
shouldRenderMergeTrainHelperText() {
return false;
},
}, },
}; };

View file

@ -33,7 +33,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true) push_frontend_feature_flag(:widget_visibility_polling, @project, default_enabled: true)
push_frontend_feature_flag(:merge_ref_head_comments, @project, default_enabled: true) push_frontend_feature_flag(:merge_ref_head_comments, @project, default_enabled: true)
push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true) push_frontend_feature_flag(:mr_commit_neighbor_nav, @project, default_enabled: true)
push_frontend_feature_flag(:multiline_comments, @project) push_frontend_feature_flag(:multiline_comments, @project, default_enabled: true)
push_frontend_feature_flag(:file_identifier_hash) push_frontend_feature_flag(:file_identifier_hash)
push_frontend_feature_flag(:batch_suggestions, @project, default_enabled: true) push_frontend_feature_flag(:batch_suggestions, @project, default_enabled: true)
push_frontend_feature_flag(:auto_expand_collapsed_diffs, @project, default_enabled: true) push_frontend_feature_flag(:auto_expand_collapsed_diffs, @project, default_enabled: true)

View file

@ -0,0 +1,17 @@
# frozen_string_literal: true
require "json"
module Resolvers
module CiConfiguration
class SastResolver < BaseResolver
SAST_UI_SCHEMA_PATH = 'app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json'
type ::Types::CiConfiguration::Sast::Type, null: true
def resolve(**args)
Gitlab::Json.parse(File.read(Rails.root.join(SAST_UI_SCHEMA_PATH)))
end
end
end
end

View file

@ -175,6 +175,10 @@ module Types
description: 'A single environment of the project', description: 'A single environment of the project',
resolver: Resolvers::EnvironmentsResolver.single resolver: Resolvers::EnvironmentsResolver.single
field :sast_ci_configuration, ::Types::CiConfiguration::Sast::Type, null: true,
description: 'SAST CI configuration for the project',
resolver: ::Resolvers::CiConfiguration::SastResolver
field :issue, field :issue,
Types::IssueType, Types::IssueType,
null: true, null: true,

View file

@ -4,43 +4,83 @@
"field" : "SECURE_ANALYZERS_PREFIX", "field" : "SECURE_ANALYZERS_PREFIX",
"label" : "Image prefix", "label" : "Image prefix",
"type": "string", "type": "string",
"default_value": "", "default_value": "registry.gitlab.com/gitlab-org/security-products/analyzers",
"value": "", "value": ""
"description": "Analyzer image's registry prefix (or Name of the registry providing the analyzers' image)"
}, },
{ {
"field" : "SAST_EXCLUDED_PATHS", "field" : "SAST_EXCLUDED_PATHS",
"label" : "Excluded Paths", "label" : "Excluded Paths",
"type": "string", "type": "string",
"default_value": "", "default_value": "spec, test, tests, tmp",
"value": "", "value": ""
"description": "Comma-separated list of paths to be excluded from analyzer output. Patterns can be globs, file paths, or folder paths."
}, },
{ {
"field" : "SAST_ANALYZER_IMAGE_TAG", "field" : "SAST_ANALYZER_IMAGE_TAG",
"label" : "Image tag", "label" : "Image tag",
"type": "string", "type": "string",
"default_value": "", "options": [],
"value": "", "default_value": "2",
"description": "Analyzer image's tag" "value": ""
},
{
"field" : "SAST_DISABLED",
"label" : "Disable SAST",
"type": "options",
"options": [
{
"value" :"true",
"label" : "true (disables SAST)"
},
{
"value":"false",
"label":"false (enables SAST)"
}
],
"default_value": "false",
"value": ""
} }
], ],
"pipeline": [ "pipeline": [
{ {
"field" : "stage", "field" : "stage",
"label" : "Stage", "label" : "Stage",
"type": "string", "type": "dropdown",
"default_value": "", "options": [
"value": "", {
"description": "Pipeline stage in which the scan jobs run" "value" :"test",
"label" : "test"
},
{
"value":"build",
"label":"build"
}
],
"default_value": "test",
"value": ""
}, },
{ {
"field" : "SEARCH_MAX_DEPTH", "field" : "allow_failure",
"label" : "Search maximum depth", "label" : "Allow Failure",
"type": "string", "type": "options",
"options": [
{
"value" :"true",
"label" : "Allows pipeline failure"
},
{
"value": "false",
"label": "Does not allow pipeline failure"
}
],
"default_value": "true",
"value": ""
},
{
"field" : "rules",
"label" : "Rules",
"type": "multiline",
"default_value": "", "default_value": "",
"value": "", "value": ""
"description": "Maximum depth of language and framework detection"
} }
], ],
"analyzers": [ "analyzers": [

View file

@ -0,0 +1,5 @@
---
title: Enable Multiline Comments by default
merge_request: 39370
author:
type: changed

View file

@ -0,0 +1,5 @@
---
title: Improve submission behavior of the New/Edit Release page
merge_request: 39145
author:
type: added

View file

@ -1,7 +1,7 @@
--- ---
# Suggestion: gitlab.Contractions # Suggestion: gitlab.ContractionsDiscard
# #
# Checks for use of common and uncommon contractions. # Suggests a list of agreed-upon contractions to discard.
# #
# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles # For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
extends: substitution extends: substitution
@ -12,18 +12,6 @@ nonword: false
ignorecase: true ignorecase: true
swap: swap:
# Common contractions are ok
it is: it's
can not: can't
cannot: can't
do not: don't
have not: haven't
that is: that's
we are: we're
would not: wouldn't
you are: you're
you have: you've
# Uncommon contractions are not ok # Uncommon contractions are not ok
aren't: are not aren't: are not
couldn't: could not couldn't: could not

View file

@ -0,0 +1,25 @@
---
# Suggestion: gitlab.ContractionsKeep
#
# Suggests a list of agreed-upon contractions to keep.
#
# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles
extends: substitution
message: 'Use "%s" instead of "%s", for a friendly, informal tone.'
link: https://docs.gitlab.com/ee/development/documentation/styleguide.html#language
level: suggestion
nonword: false
ignorecase: true
swap:
# Common contractions are ok
it is: it's
can not: can't
cannot: can't
do not: don't
have not: haven't
that is: that's
we are: we're
would not: wouldn't
you are: you're
you have: you've

View file

@ -80,6 +80,7 @@ Please note that the certificate [fingerprint algorithm](#additional-providers-a
With this option enabled, users must go through your group's GitLab single sign-on URL. They may also be added via SCIM, if configured. Users cannot be added manually, and may only access project/group resources via the UI by signing in through the SSO URL. With this option enabled, users must go through your group's GitLab single sign-on URL. They may also be added via SCIM, if configured. Users cannot be added manually, and may only access project/group resources via the UI by signing in through the SSO URL.
However, users will not be prompted to sign in through SSO on each visit. GitLab will check whether a user has authenticated through SSO, and will only prompt the user to sign in via SSO if the session has expired. However, users will not be prompted to sign in through SSO on each visit. GitLab will check whether a user has authenticated through SSO, and will only prompt the user to sign in via SSO if the session has expired.
You can see more information about how long a session is valid in our [user profile documentation](../../profile/#why-do-i-keep-getting-signed-out).
We intend to add a similar SSO requirement for [Git and API activity](https://gitlab.com/gitlab-org/gitlab/-/issues/9152). We intend to add a similar SSO requirement for [Git and API activity](https://gitlab.com/gitlab-org/gitlab/-/issues/9152).

View file

@ -151,11 +151,12 @@ in a Merge Request. To do so, click the **{comment}** **comment** icon in the gu
### Commenting on multiple lines ### Commenting on multiple lines
> - [Introduced](https://gitlab.com/gitlab-org/ux-research/-/issues/870) in GitLab 13.2. > - [Introduced](https://gitlab.com/gitlab-org/ux-research/-/issues/870) in GitLab 13.2.
> - It's deployed behind a feature flag, disabled by default. > - It's deployed behind a feature flag, enabled by default.
> - [Became enabled by default](https://gitlab.com/gitlab-org/gitlab/-/issues/221268) on GitLab 13.3.
> - It's enabled on GitLab.com. > - It's enabled on GitLab.com.
> - It can be enabled or disabled per-project. > - It can be disabled or enabled per-project.
> - It's recommended for production use. > - It's recommended for production use.
> - For GitLab self-managed instances, GitLab administrators can opt to [enable it](#enable-or-disable-multiline-comments-core-only). **(CORE ONLY)** > - For GitLab self-managed instances, GitLab administrators can opt to [disable it](#enable-or-disable-multiline-comments-core-only). **(CORE ONLY)**
GitLab provides a way to select which lines of code a comment refers to. After starting a comment GitLab provides a way to select which lines of code a comment refers to. After starting a comment
a dropdown selector is shown to select the first line that this comment refers to. a dropdown selector is shown to select the first line that this comment refers to.
@ -178,18 +179,18 @@ It is deployed behind a feature flag that is **disabled by default**.
[GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md) [GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
can opt to enable it for your instance. can opt to enable it for your instance.
To enable it:
```ruby
Feature.enable(:multiline_comments)
```
To disable it: To disable it:
```ruby ```ruby
Feature.disable(:multiline_comments) Feature.disable(:multiline_comments)
``` ```
To enable it:
```ruby
Feature.enable(:multiline_comments)
```
## Pipeline status in merge requests widgets ## Pipeline status in merge requests widgets
If you've set up [GitLab CI/CD](../../../ci/README.md) in your project, If you've set up [GitLab CI/CD](../../../ci/README.md) in your project,

View file

@ -36,7 +36,7 @@ RSpec.describe 'Global search' do
end end
end end
it 'closes the dropdown on blur', :js do it 'closes the dropdown on blur', :js, quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/201841' do
fill_in 'search', with: "a" fill_in 'search', with: "a"
dropdown = find('.js-dashboard-search-options') dropdown = find('.js-dashboard-search-options')

View file

@ -83,11 +83,10 @@ describe('Release edit/new component', () => {
}); });
const findSubmitButton = () => wrapper.find('button[type=submit]'); const findSubmitButton = () => wrapper.find('button[type=submit]');
const findForm = () => wrapper.find('form');
describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => { describe(`basic functionality tests: all tests unrelated to the "${BACK_URL_PARAM}" parameter`, () => {
beforeEach(() => { beforeEach(factory);
factory();
});
it('calls initializeRelease when the component is created', () => { it('calls initializeRelease when the component is created', () => {
expect(actions.initializeRelease).toHaveBeenCalledTimes(1); expect(actions.initializeRelease).toHaveBeenCalledTimes(1);
@ -122,15 +121,14 @@ describe('Release edit/new component', () => {
}); });
it('calls saveRelease when the form is submitted', () => { it('calls saveRelease when the form is submitted', () => {
wrapper.find('form').trigger('submit'); findForm().trigger('submit');
expect(actions.saveRelease).toHaveBeenCalledTimes(1); expect(actions.saveRelease).toHaveBeenCalledTimes(1);
}); });
}); });
describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => { describe(`when the URL does not contain a "${BACK_URL_PARAM}" parameter`, () => {
beforeEach(() => { beforeEach(factory);
factory();
});
it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => { it(`renders a "Cancel" button with an href pointing to "${BACK_URL_PARAM}"`, () => {
const cancelButton = wrapper.find('.js-cancel-button'); const cancelButton = wrapper.find('.js-cancel-button');
@ -246,6 +244,12 @@ describe('Release edit/new component', () => {
it('renders the submit button as disabled', () => { it('renders the submit button as disabled', () => {
expect(findSubmitButton().attributes('disabled')).toBe('disabled'); expect(findSubmitButton().attributes('disabled')).toBe('disabled');
}); });
it('does not allow the form to be submitted', () => {
findForm().trigger('submit');
expect(actions.saveRelease).not.toHaveBeenCalled();
});
}); });
}); });
}); });

View file

@ -3,6 +3,7 @@ import { mount, createLocalVue } from '@vue/test-utils';
import AssetLinksForm from '~/releases/components/asset_links_form.vue'; import AssetLinksForm from '~/releases/components/asset_links_form.vue';
import { release as originalRelease } from '../mock_data'; import { release as originalRelease } from '../mock_data';
import * as commonUtils from '~/lib/utils/common_utils'; import * as commonUtils from '~/lib/utils/common_utils';
import { ENTER_KEY } from '~/lib/utils/keys';
import { ASSET_LINK_TYPE, DEFAULT_ASSET_LINK_TYPE } from '~/releases/constants'; import { ASSET_LINK_TYPE, DEFAULT_ASSET_LINK_TYPE } from '~/releases/constants';
const localVue = createLocalVue(); const localVue = createLocalVue();
@ -91,42 +92,128 @@ describe('Release edit component', () => {
expect(actions.removeAssetLink).toHaveBeenCalledTimes(1); expect(actions.removeAssetLink).toHaveBeenCalledTimes(1);
}); });
it('calls the "updateAssetLinkUrl" store method when text is entered into the "URL" input field', () => { describe('URL input field', () => {
const linkIdToUpdate = release.assets.links[0].id; let input;
const newUrl = 'updated url'; let linkIdToUpdate;
let newUrl;
expect(actions.updateAssetLinkUrl).not.toHaveBeenCalled(); beforeEach(() => {
input = wrapper.find({ ref: 'urlInput' }).element;
linkIdToUpdate = release.assets.links[0].id;
newUrl = 'updated url';
});
wrapper.find({ ref: 'urlInput' }).vm.$emit('change', newUrl); const expectStoreMethodNotToBeCalled = () => {
expect(actions.updateAssetLinkUrl).not.toHaveBeenCalled();
};
expect(actions.updateAssetLinkUrl).toHaveBeenCalledTimes(1); const dispatchKeydowEvent = eventParams => {
expect(actions.updateAssetLinkUrl).toHaveBeenCalledWith( const event = new KeyboardEvent('keydown', eventParams);
expect.anything(),
{ input.dispatchEvent(event);
linkIdToUpdate, };
newUrl,
}, const expectStoreMethodToBeCalled = () => {
undefined, expect(actions.updateAssetLinkUrl).toHaveBeenCalledTimes(1);
); expect(actions.updateAssetLinkUrl).toHaveBeenCalledWith(
expect.anything(),
{
linkIdToUpdate,
newUrl,
},
undefined,
);
};
it('calls the "updateAssetLinkUrl" store method when text is entered into the "URL" input field', () => {
expectStoreMethodNotToBeCalled();
wrapper.find({ ref: 'urlInput' }).vm.$emit('change', newUrl);
expectStoreMethodToBeCalled();
});
it('calls the "updateAssetLinkUrl" store method when Ctrl+Enter is pressed inside the "URL" input field', () => {
expectStoreMethodNotToBeCalled();
input.value = newUrl;
dispatchKeydowEvent({ key: ENTER_KEY, ctrlKey: true });
expectStoreMethodToBeCalled();
});
it('calls the "updateAssetLinkUrl" store method when Cmd+Enter is pressed inside the "URL" input field', () => {
expectStoreMethodNotToBeCalled();
input.value = newUrl;
dispatchKeydowEvent({ key: ENTER_KEY, metaKey: true });
expectStoreMethodToBeCalled();
});
}); });
it('calls the "updateAssetLinkName" store method when text is entered into the "Link title" input field', () => { describe('Link title field', () => {
const linkIdToUpdate = release.assets.links[0].id; let input;
const newName = 'updated name'; let linkIdToUpdate;
let newName;
expect(actions.updateAssetLinkName).not.toHaveBeenCalled(); beforeEach(() => {
input = wrapper.find({ ref: 'nameInput' }).element;
linkIdToUpdate = release.assets.links[0].id;
newName = 'updated name';
});
wrapper.find({ ref: 'nameInput' }).vm.$emit('change', newName); const expectStoreMethodNotToBeCalled = () => {
expect(actions.updateAssetLinkUrl).not.toHaveBeenCalled();
};
expect(actions.updateAssetLinkName).toHaveBeenCalledTimes(1); const dispatchKeydowEvent = eventParams => {
expect(actions.updateAssetLinkName).toHaveBeenCalledWith( const event = new KeyboardEvent('keydown', eventParams);
expect.anything(),
{ input.dispatchEvent(event);
linkIdToUpdate, };
newName,
}, const expectStoreMethodToBeCalled = () => {
undefined, expect(actions.updateAssetLinkName).toHaveBeenCalledTimes(1);
); expect(actions.updateAssetLinkName).toHaveBeenCalledWith(
expect.anything(),
{
linkIdToUpdate,
newName,
},
undefined,
);
};
it('calls the "updateAssetLinkName" store method when text is entered into the "Link title" input field', () => {
expectStoreMethodNotToBeCalled();
wrapper.find({ ref: 'nameInput' }).vm.$emit('change', newName);
expectStoreMethodToBeCalled();
});
it('calls the "updateAssetLinkName" store method when Ctrl+Enter is pressed inside the "Link title" input field', () => {
expectStoreMethodNotToBeCalled();
input.value = newName;
dispatchKeydowEvent({ key: ENTER_KEY, ctrlKey: true });
expectStoreMethodToBeCalled();
});
it('calls the "updateAssetLinkName" store method when Cmd+Enter is pressed inside the "Link title" input field', () => {
expectStoreMethodNotToBeCalled();
input.value = newName;
dispatchKeydowEvent({ key: ENTER_KEY, metaKey: true });
expectStoreMethodToBeCalled();
});
}); });
it('calls the "updateAssetLinkType" store method when an option is selected from the "Type" dropdown', () => { it('calls the "updateAssetLinkType" store method when an option is selected from the "Type" dropdown', () => {

View file

@ -0,0 +1,28 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::CiConfiguration::SastResolver do
include GraphqlHelpers
let_it_be(:user) { create(:user) }
let_it_be(:project) { create(:project) }
describe '#resolve' do
subject(:sast_config) { resolve(described_class, ctx: { current_user: user }, obj: project) }
it 'returns global variable informations related to SAST' do
expect(sast_config['global'].first['field']).to eql("SECURE_ANALYZERS_PREFIX")
expect(sast_config['global'].first['label']).to eql("Image prefix")
expect(sast_config['global'].first['type']).to eql("string")
expect(sast_config['pipeline'].first['field']).to eql("stage")
expect(sast_config['pipeline'].first['label']).to eql("Stage")
expect(sast_config['pipeline'].first['type']).to eql("dropdown")
expect(sast_config['analyzers'].first['name']).to eql("brakeman")
expect(sast_config['analyzers'].first['label']).to eql("Brakeman")
expect(sast_config['analyzers'].first['enabled']).to be true
end
end
end

View file

@ -26,7 +26,7 @@ RSpec.describe GitlabSchema.types['Project'] do
grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments
environment boards jira_import_status jira_imports services releases release environment boards jira_import_status jira_imports services releases release
alert_management_alerts alert_management_alert alert_management_alert_status_counts alert_management_alerts alert_management_alert alert_management_alert_status_counts
container_expiration_policy service_desk_enabled service_desk_address container_expiration_policy sast_ci_configuration service_desk_enabled service_desk_address
issue_status_counts issue_status_counts
] ]
@ -150,5 +150,93 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::ContainerExpirationPolicyType) } it { is_expected.to have_graphql_type(Types::ContainerExpirationPolicyType) }
end end
describe 'sast_ci_configuration' do
let_it_be(:project) { create(:project) }
let_it_be(:user) { create(:user) }
let_it_be(:query) do
%(
query {
project(fullPath: "#{project.full_path}") {
sastCiConfiguration {
global {
nodes {
type
options {
nodes {
label
value
}
}
field
label
defaultValue
value
}
}
pipeline {
nodes {
type
options {
nodes {
label
value
}
}
field
label
defaultValue
value
}
}
analyzers {
nodes {
name
label
enabled
}
}
}
}
}
)
end
subject { GitlabSchema.execute(query, context: { current_user: user }).as_json }
before do
project.add_developer(user)
end
it "returns the project's sast configuration for global variables" do
query_result = subject.dig('data', 'project', 'sastCiConfiguration', 'global', 'nodes')
first_config = query_result.first
fourth_config = query_result[3]
expect(first_config['type']).to eq('string')
expect(first_config['field']).to eq('SECURE_ANALYZERS_PREFIX')
expect(first_config['label']).to eq('Image prefix')
expect(first_config['defaultValue']).to eq('registry.gitlab.com/gitlab-org/security-products/analyzers')
expect(first_config['value']).to eq('')
expect(first_config['options']).to be_nil
expect(fourth_config['options']['nodes']).to match([{ "value" => "true", "label" => "true (disables SAST)" },
{ "value" => "false", "label" => "false (enables SAST)" }])
end
it "returns the project's sast configuration for pipeline variables" do
configuration = subject.dig('data', 'project', 'sastCiConfiguration', 'pipeline', 'nodes').first
expect(configuration['type']).to eq('dropdown')
expect(configuration['field']).to eq('stage')
expect(configuration['label']).to eq('Stage')
expect(configuration['defaultValue']).to eq('test')
expect(configuration['value']).to eq('')
end
it "returns the project's sast configuration for analyzer variables" do
configuration = subject.dig('data', 'project', 'sastCiConfiguration', 'analyzers', 'nodes').first
expect(configuration['name']).to eq('brakeman')
expect(configuration['label']).to eq('Brakeman')
expect(configuration['enabled']).to eq(true)
end
end
it_behaves_like 'a GraphQL type with labels' it_behaves_like 'a GraphQL type with labels'
end end

View file

@ -1,13 +0,0 @@
include:
- template: SAST.gitlab-ci.yml
variables:
SECURE_ANALYZERS_PREFIX: "registry.gitlab.com/gitlab-org/security-products/analyzers2"
SAST_EXCLUDED_PATHS: "spec, executables"
stages:
- our_custom_security_stage
sast:
stage: our_custom_security_stage
variables:
SEARCH_MAX_DEPTH: 8

View file

@ -1,9 +0,0 @@
# frozen_string_literal: true
RSpec.shared_context 'read ci configuration for sast enabled project' do
let_it_be(:gitlab_ci_yml_content) do
File.read(Rails.root.join('spec/support/gitlab_stubs/gitlab_ci_for_sast.yml'))
end
let_it_be(:project) { create(:project, :repository) }
end