Commit 96bb773e authored by Craig Norris's avatar Craig Norris

Merge branch 'selhorn-nuget-packages' into 'master'

Docs: Edited NuGet topic

See merge request gitlab-org/gitlab!46936
parents 7e8f4fee 86f6c2a7
......@@ -7,9 +7,11 @@ require:
- rubocop-rspec
inherit_from:
- .rubocop_manual_todo.yml
- .rubocop_todo.yml
- ./rubocop/rubocop-migrations.yml
- ./rubocop/rubocop-usage-data.yml
- ./rubocop/rubocop-code_reuse.yml
inherit_mode:
merge:
......
This diff is collapsed.
This diff is collapsed.
......@@ -370,11 +370,7 @@ group :development, :test do
gem 'spring', '~> 2.0.0'
gem 'spring-commands-rspec', '~> 1.0.4'
gem 'gitlab-styles', '~> 4.3.0', require: false
# Pin these dependencies, otherwise a new rule could break the CI pipelines
gem 'rubocop', '~> 0.82.0'
gem 'rubocop-performance', '~> 1.5.2'
gem 'rubocop-rspec', '~> 1.37.0'
gem 'gitlab-styles', '~> 5.0.0', require: false
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.36.0', require: false
......
......@@ -449,12 +449,12 @@ GEM
gitlab-puma (>= 2.7, < 5)
gitlab-sidekiq-fetcher (0.5.2)
sidekiq (~> 5)
gitlab-styles (4.3.0)
rubocop (~> 0.82.0)
gitlab-styles (5.0.0)
rubocop (~> 0.89.1)
rubocop-gitlab-security (~> 0.1.0)
rubocop-performance (~> 1.5.2)
rubocop-rails (~> 2.5)
rubocop-rspec (~> 1.36)
rubocop-performance (~> 1.8.1)
rubocop-rails (~> 2.8)
rubocop-rspec (~> 1.44)
gitlab_chronic_duration (0.10.6.2)
numerizer (~> 0.2)
gitlab_omniauth-ldap (2.1.1)
......@@ -602,7 +602,6 @@ GEM
jaeger-client (1.1.0)
opentracing (~> 0.3)
thrift
jaro_winkler (1.5.4)
jira-ruby (2.0.0)
activesupport
atlassian-jwt
......@@ -834,7 +833,7 @@ GEM
rubypants (~> 0.2)
orm_adapter (0.5.0)
os (1.0.0)
parallel (1.19.1)
parallel (1.19.2)
parser (2.7.2.0)
ast (~> 2.4.1)
parslet (1.8.2)
......@@ -958,7 +957,7 @@ GEM
redis-store (>= 1.2, < 2)
redis-store (1.8.1)
redis (>= 4, < 5)
regexp_parser (1.5.1)
regexp_parser (1.8.2)
regexp_property_values (0.3.5)
representable (3.0.4)
declarative (< 0.1.0)
......@@ -1019,24 +1018,29 @@ GEM
pg
rails
sqlite3
rubocop (0.82.0)
jaro_winkler (~> 1.5.1)
rubocop (0.89.1)
parallel (~> 1.10)
parser (>= 2.7.0.1)
parser (>= 2.7.1.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.7)
rexml
rubocop-ast (>= 0.3.0, < 1.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-ast (0.8.0)
parser (>= 2.7.1.5)
rubocop-gitlab-security (0.1.1)
rubocop (>= 0.51)
rubocop-performance (1.5.2)
rubocop (>= 0.71.0)
rubocop-rails (2.5.2)
activesupport
rubocop-performance (1.8.1)
rubocop (>= 0.87.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.8.1)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 0.72.0)
rubocop-rspec (1.37.0)
rubocop (>= 0.68.1)
rubocop (>= 0.87.0)
rubocop-rspec (1.44.1)
rubocop (~> 0.87)
rubocop-ast (>= 0.7.1)
ruby-enum (0.7.2)
i18n
ruby-fogbugz (0.2.1)
......@@ -1249,7 +1253,7 @@ GEM
xpath (3.2.0)
nokogiri (~> 1.8)
yajl-ruby (1.4.1)
zeitwerk (2.4.0)
zeitwerk (2.4.1)
PLATFORMS
ruby
......@@ -1353,7 +1357,7 @@ DEPENDENCIES
gitlab-puma (~> 4.3.3.gitlab.2)
gitlab-puma_worker_killer (~> 0.1.1.gitlab.1)
gitlab-sidekiq-fetcher (= 0.5.2)
gitlab-styles (~> 4.3.0)
gitlab-styles (~> 5.0.0)
gitlab_chronic_duration (~> 0.10.6.2)
gitlab_omniauth-ldap (~> 2.1.1)
gon (~> 6.2)
......@@ -1473,9 +1477,6 @@ DEPENDENCIES
rspec-retry (~> 0.6.1)
rspec_junit_formatter
rspec_profiling (~> 0.0.6)
rubocop (~> 0.82.0)
rubocop-performance (~> 1.5.2)
rubocop-rspec (~> 1.37.0)
ruby-fogbugz (~> 0.2.1)
ruby-prof (~> 1.3.0)
ruby-progressbar
......
......@@ -4,10 +4,16 @@ class Analytics::DevopsAdoption::Segment < ApplicationRecord
ALLOWED_SEGMENT_COUNT = 20
has_many :segment_selections
has_many :groups, through: :segment_selections
validates :name, presence: true, uniqueness: true, length: { maximum: 255 }
validate :validate_segment_count
accepts_nested_attributes_for :segment_selections, allow_destroy: true
scope :ordered_by_name, -> { order(:name) }
scope :with_groups, -> { preload(:groups) }
private
def validate_segment_count
......
---
name: security_on_demand_scans_http_header_validation
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/42812
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/276403
milestone: '13.6'
type: development
group: group::dynamic analysis
default_enabled: false
......@@ -6025,6 +6025,81 @@ type DetailedStatus {
tooltip: String
}
"""
Segment
"""
type DevopsAdoptionSegment {
"""
Assigned groups
"""
groups(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): GroupConnection
"""
ID of the segment
"""
id: ID!
"""
Name of the segment
"""
name: String!
}
"""
The connection type for DevopsAdoptionSegment.
"""
type DevopsAdoptionSegmentConnection {
"""
A list of edges.
"""
edges: [DevopsAdoptionSegmentEdge]
"""
A list of nodes.
"""
nodes: [DevopsAdoptionSegment]
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"""
An edge in a connection.
"""
type DevopsAdoptionSegmentEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of the edge.
"""
node: DevopsAdoptionSegment
}
input DiffImagePositionInput {
"""
Merge base of the branch the comment was made on
......@@ -9165,6 +9240,41 @@ type Group {
webUrl: String!
}
"""
The connection type for Group.
"""
type GroupConnection {
"""
A list of edges.
"""
edges: [GroupEdge]
"""
A list of nodes.
"""
nodes: [Group]
"""
Information to aid in pagination.
"""
pageInfo: PageInfo!
}
"""
An edge in a connection.
"""
type GroupEdge {
"""
A cursor for use in pagination.
"""
cursor: String!
"""
The item at the end of the edge.
"""
node: Group
}
"""
Identifier of Group
"""
......@@ -16540,6 +16650,31 @@ type Query {
"""
designManagement: DesignManagement!
"""
Get configured DevOps adoption segments on the instance
"""
devopsAdoptionSegments(
"""
Returns the elements in the list that come after the specified cursor.
"""
after: String
"""
Returns the elements in the list that come before the specified cursor.
"""
before: String
"""
Returns the first _n_ elements from the list.
"""
first: Int
"""
Returns the last _n_ elements from the list.
"""
last: Int
): DevopsAdoptionSegmentConnection
"""
Text to echo back
"""
......
......@@ -1000,6 +1000,16 @@ Autogenerated return type of DestroySnippet.
| `text` | String | Text of the status |
| `tooltip` | String | Tooltip associated with the status |
### DevopsAdoptionSegment
Segment.
| Field | Type | Description |
| ----- | ---- | ----------- |
| `groups` | GroupConnection | Assigned groups |
| `id` | ID! | ID of the segment |
| `name` | String! | Name of the segment |
### DiffPosition
| Field | Type | Description |
......
......@@ -18,6 +18,12 @@ If you choose a size larger than what is currently configured for the web server
you will likely get errors. See the [troubleshooting section](#troubleshooting) for more
details.
## Max push size
You can change the maximum push size for your repository.
Navigate to **Admin Area (wrench icon) > Settings > General**, then expand **Account and Limit**.
From here, you can increase or decrease by changing the value in `Maximum push size (MB)`.
## Max import size
You can change the maximum file size for imports in GitLab.
......
......@@ -11,11 +11,16 @@ import {
GlInputGroupText,
GlLoadingIcon,
} from '@gitlab/ui';
import { omit } from 'lodash';
import * as Sentry from '~/sentry/wrapper';
import ClipboardButton from '~/vue_shared/components/clipboard_button.vue';
import download from '~/lib/utils/downloader';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { cleanLeadingSeparator, joinPaths, stripPathTail } from '~/lib/utils/url_utility';
import { fetchPolicies } from '~/lib/graphql';
import {
DAST_SITE_VALIDATION_HTTP_HEADER_KEY,
DAST_SITE_VALIDATION_METHOD_HTTP_HEADER,
DAST_SITE_VALIDATION_METHOD_TEXT_FILE,
DAST_SITE_VALIDATION_METHODS,
DAST_SITE_VALIDATION_STATUS,
......@@ -27,6 +32,7 @@ import dastSiteValidationQuery from '../graphql/dast_site_validation.query.graph
export default {
name: 'DastSiteValidation',
components: {
ClipboardButton,
GlAlert,
GlButton,
GlCard,
......@@ -38,6 +44,7 @@ export default {
GlInputGroupText,
GlLoadingIcon,
},
mixins: [glFeatureFlagsMixin()],
apollo: {
dastSiteValidation: {
query: dastSiteValidationQuery,
......@@ -103,6 +110,16 @@ export default {
};
},
computed: {
validationMethodOptions() {
const isHttpHeaderValidationEnabled = this.glFeatures
.securityOnDemandScansHttpHeaderValidation;
const enabledValidationMethods = omit(DAST_SITE_VALIDATION_METHODS, [
!isHttpHeaderValidationEnabled ? DAST_SITE_VALIDATION_METHOD_HTTP_HEADER : '',
]);
return Object.values(enabledValidationMethods);
},
urlObject() {
try {
return new URL(this.targetUrl);
......@@ -119,12 +136,18 @@ export default {
isTextFileValidation() {
return this.validationMethod === DAST_SITE_VALIDATION_METHOD_TEXT_FILE;
},
isHttpHeaderValidation() {
return this.validationMethod === DAST_SITE_VALIDATION_METHOD_HTTP_HEADER;
},
textFileName() {
return `GitLab-DAST-Site-Validation-${this.token}.txt`;
},
locationStepLabel() {
return DAST_SITE_VALIDATION_METHODS[this.validationMethod].i18n.locationStepLabel;
},
httpHeader() {
return `${DAST_SITE_VALIDATION_HTTP_HEADER_KEY}: uuid-code-${this.token}`;
},
},
watch: {
targetUrl() {
......@@ -132,13 +155,22 @@ export default {
},
},
created() {
this.unsubscribe = this.$watch(() => this.token, this.updateValidationPath, {
immediate: true,
});
this.unsubscribe = this.$watch(
() => [this.token, this.validationMethod],
this.updateValidationPath,
{
immediate: true,
},
);
},
methods: {
updateValidationPath() {
this.validationPath = joinPaths(stripPathTail(this.path), this.textFileName);
this.validationPath = this.isTextFileValidation
? this.getTextFileValidationPath()
: this.path;
},
getTextFileValidationPath() {
return joinPaths(stripPathTail(this.path), this.textFileName);
},
onValidationPathInput() {
this.unsubscribe();
......@@ -189,7 +221,6 @@ export default {
this.hasValidationError = true;
},
},
validationMethodOptions: Object.values(DAST_SITE_VALIDATION_METHODS),
};
</script>
......@@ -199,7 +230,7 @@ export default {
{{ s__('DastProfiles|Site is not validated yet, please follow the steps.') }}
</gl-alert>
<gl-form-group :label="s__('DastProfiles|Step 1 - Choose site validation method')">
<gl-form-radio-group v-model="validationMethod" :options="$options.validationMethodOptions" />
<gl-form-radio-group v-model="validationMethod" :options="validationMethodOptions" />
</gl-form-group>
<gl-form-group
v-if="isTextFileValidation"
......@@ -217,6 +248,16 @@ export default {
{{ textFileName }}
</gl-button>
</gl-form-group>
<gl-form-group
v-else-if="isHttpHeaderValidation"
:label="s__('DastProfiles|Step 2 - Add following HTTP header to your site')"
>
<code class="gl-p-3 gl-bg-black gl-text-white">{{ httpHeader }}</code>
<clipboard-button
:text="httpHeader"
:title="s__('DastProfiles|Copy HTTP header to clipboard')"
/>
</gl-form-group>
<gl-form-group :label="locationStepLabel" class="mw-460">
<gl-form-input-group>
<template #prepend>
......@@ -255,7 +296,7 @@ export default {
<gl-icon name="status_failed" />
{{
s__(
'DastProfiles|Validation failed, please make sure that you follow the steps above with the choosen method.',
'DastProfiles|Validation failed, please make sure that you follow the steps above with the chosen method.',
)
}}
</template>
......
import { s__ } from '~/locale';
export const DAST_SITE_VALIDATION_METHOD_TEXT_FILE = 'TEXT_FILE';
export const DAST_SITE_VALIDATION_METHOD_HTTP_HEADER = 'HTTP_HEADER';
export const DAST_SITE_VALIDATION_METHODS = {
[DAST_SITE_VALIDATION_METHOD_TEXT_FILE]: {
value: DAST_SITE_VALIDATION_METHOD_TEXT_FILE,
......@@ -9,6 +11,13 @@ export const DAST_SITE_VALIDATION_METHODS = {
locationStepLabel: s__('DastProfiles|Step 3 - Confirm text file location and validate'),
},
},
[DAST_SITE_VALIDATION_METHOD_HTTP_HEADER]: {
value: DAST_SITE_VALIDATION_METHOD_HTTP_HEADER,
text: s__('DastProfiles|Header validation'),
i18n: {
locationStepLabel: s__('DastProfiles|Step 3 - Confirm header location and validate'),
},
},
};
export const DAST_SITE_VALIDATION_STATUS = {
......@@ -19,3 +28,4 @@ export const DAST_SITE_VALIDATION_STATUS = {
};
export const DAST_SITE_VALIDATION_POLL_INTERVAL = 1000;
export const DAST_SITE_VALIDATION_HTTP_HEADER_KEY = 'Gitlab-On-Demand-DAST';
......@@ -6,6 +6,7 @@ module Projects
before_action do
authorize_read_on_demand_scans!
push_frontend_feature_flag(:security_on_demand_scans_site_validation, @project)
push_frontend_feature_flag(:security_on_demand_scans_http_header_validation, @project)
end
feature_category :dynamic_application_security_testing
......
......@@ -51,6 +51,11 @@ module EE
null: true,
resolver: ::Resolvers::InstanceSecurityDashboardResolver,
description: 'Fields related to Instance Security Dashboard'
field :devops_adoption_segments, ::Types::Admin::Analytics::DevopsAdoption::SegmentType.connection_type,
null: true,
description: 'Get configured DevOps adoption segments on the instance',
resolver: ::Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver
end
def vulnerability(id:)
......
# frozen_string_literal: true
module Resolvers
module Admin
module Analytics
module DevopsAdoption
class SegmentsResolver < BaseResolver
include Gitlab::Graphql::Authorize::AuthorizeResource
type Types::Admin::Analytics::DevopsAdoption::SegmentType, null: true
def resolve
authorize!
if segments_feature_available?
::Analytics::DevopsAdoption::Segment.with_groups.ordered_by_name
else
::Analytics::DevopsAdoption::Segment.none
end
end
private
def segments_feature_available?
License.feature_available?(:instance_level_devops_adoption)
end
def authorize!
admin? || raise_resource_not_available_error!
end
def admin?
context[:current_user].present? && context[:current_user].admin?
end
end
end
end
end
end
# frozen_string_literal: true
# rubocop:disable Graphql/AuthorizeTypes
module Types
module Admin
module Analytics
module DevopsAdoption
class SegmentType < BaseObject
graphql_name 'DevopsAdoptionSegment'
description 'Segment'
field :id, GraphQL::ID_TYPE, null: false,
description: "ID of the segment"
field :name, GraphQL::STRING_TYPE, null: false,
description: 'Name of the segment'
field :groups, Types::GroupType.connection_type, null: true,
description: 'Assigned groups'
end
end
end
end
end
......@@ -19,6 +19,7 @@ class License < ApplicationRecord
group_activity_analytics
group_bulk_edit
group_webhooks
instance_level_devops_adoption
issuable_default_templates
issue_weights
iterations
......
---
title: Expose Devops Adoption segments via GraphQL
merge_request: 46879
author:
type: added
......@@ -3,8 +3,5 @@
---
inherit_from: ../../../../../lib/gitlab/background_migration/.rubocop.yml
CodeReuse/ActiveRecord:
Enabled: false
Style/Documentation:
Enabled: false
......@@ -14,7 +14,7 @@ export const dastSiteValidation = (status = DAST_SITE_VALIDATION_STATUS.PENDING)
export const dastSiteValidationCreate = (errors = []) => ({
data: {
dastSiteValidationCreate: { status: DAST_SITE_VALIDATION_STATUS.PASSED, id: '1', errors },
dastSiteValidationCreate: { status: DAST_SITE_VALIDATION_STATUS.PENDING, id: '1', errors },
},
});
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Resolvers::Admin::Analytics::DevopsAdoption::SegmentsResolver do
include GraphqlHelpers
let_it_be(:admin_user) { create(:user, :admin) }
let(:current_user) { admin_user }
def resolve_segments(args = {}, context = {})
resolve(described_class, args: args, ctx: context)
end
describe '#resolve' do
let_it_be(:user) { create(:user) }
let_it_be(:segment_1) { create(:devops_adoption_segment, name: 'bbb') }
let_it_be(:segment_2) { create(:devops_adoption_segment, name: 'aaa') }
subject { resolve_segments({}, { current_user: current_user }) }
before do
stub_licensed_features(instance_level_devops_adoption: true)
end
context 'when requesting project count measurements' do
context 'as an admin user' do
let(:current_user) { admin_user }
it 'returns the records, ordered by name' do
expect(subject).to eq([segment_2, segment_1])
end
end
context 'when the feature is not available' do
let(:current_user) { admin_user }
before do
stub_licensed_features(instance_level_devops_adoption: false)
end
it 'returns the records, ordered by name' do
expect(subject).to be_empty
end
end
context 'as a non-admin user' do
let(:current_user) { user }
it 'raises ResourceNotAvailable error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
context 'as an unauthenticated user' do
let(:current_user) { nil }
it 'raises ResourceNotAvailable error' do
expect { subject }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
end
end
end
end
end
......@@ -26,4 +26,15 @@ RSpec.describe Analytics::DevopsAdoption::Segment, type: :model do
end
end
end
describe '.ordered_by_name' do
let(:segment_1) { create(:devops_adoption_segment, name: 'bbb') }
let(:segment_2) { create(:devops_adoption_segment, name: 'aaa') }
subject { described_class.ordered_by_name }
it 'orders segments by name' do
expect(subject).to eq([segment_2, segment_1])
end
end
end
......@@ -190,7 +190,7 @@ module Gitlab
%r{\A(ee/)?vendor/} => :backend,
%r{\A(Gemfile|Gemfile.lock|Rakefile)\z} => :backend,
%r{\A[A-Z_]+_VERSION\z} => :backend,
%r{\A\.rubocop(_todo)?\.yml\z} => :backend,
%r{\A\.rubocop((_manual)?_todo)?\.yml\z} => :backend,
%r{\Afile_hooks/} => :backend,
%r{\A(ee/)?qa/} => :qa,
......
......@@ -8319,6 +8319,9 @@ msgstr ""
msgid "DastProfiles|Authentication URL"
msgstr ""
msgid "DastProfiles|Copy HTTP header to clipboard"
msgstr ""
msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
msgstr ""
......@@ -8385,6 +8388,9 @@ msgstr ""
msgid "DastProfiles|Error Details"
msgstr ""
msgid "DastProfiles|Header validation"
msgstr ""
msgid "DastProfiles|Hide debug messages"
msgstr ""
......@@ -8469,9 +8475,15 @@ msgstr ""
msgid "DastProfiles|Step 1 - Choose site validation method"
msgstr ""
msgid "DastProfiles|Step 2 - Add following HTTP header to your site"
msgstr ""
msgid "DastProfiles|Step 2 - Add following text to the target site"
msgstr ""
msgid "DastProfiles|Step 3 - Confirm header location and validate"
msgstr ""
msgid "DastProfiles|Step 3 - Confirm text file location and validate"
msgstr ""
......@@ -8508,7 +8520,7 @@ msgstr ""
msgid "DastProfiles|Validating..."
msgstr ""
msgid "DastProfiles|Validation failed, please make sure that you follow the steps above with the choosen method."
msgid "DastProfiles|Validation failed, please make sure that you follow the steps above with the chosen method."
msgstr ""
msgid "DastProfiles|Validation failed. Please try again."
......
# frozen_string_literal: true
require_relative '../../code_reuse_helpers'
module RuboCop
module Cop
module CodeReuse
# Cop that denies the use of ActiveRecord methods outside of models.
class ActiveRecord < RuboCop::Cop::Cop
include CodeReuseHelpers
MSG = 'This method can only be used inside an ActiveRecord model: ' \
'https://gitlab.com/gitlab-org/gitlab-foss/issues/49653'
# Various methods from ActiveRecord::Querying that are denied. We
# exclude some generic ones such as `any?` and `first`, as these may
# lead to too many false positives, since `Array` also supports these
# methods.
#
# The keys of this Hash are the denied method names. The values are
# booleans that indicate if the method should only be denied if any
# arguments are provided.
NOT_ALLOWED = {
average: true,
calculate: true,
count_by_sql: true,
create_with: true,
distinct: false,
eager_load: true,
exists?: true,
find_by: true,
find_by!: true,
find_by_sql: true,
find_each: true,
find_in_batches: true,
find_or_create_by: true,
find_or_create_by!: true,
find_or_initialize_by: true,
first!: false,
first_or_create: true,
first_or_create!: true,
first_or_initialize: true,
from: true,
group: true,
having: true,
ids: false,
includes: true,
joins: true,
limit: true,
lock: false,
many?: false,
offset: true,
order: true,
pluck: true,
preload: true,
readonly: false,
references: true,
reorder: true,
rewhere: true,
take: false,
take!: false,
unscope: false,
where: false,
with: true
}.freeze
# Directories that allow the use of the denied methods. These
# directories are checked relative to both . and ee/
ALLOWED_DIRECTORIES = %w[
app/models
config
danger
db
lib/backup
lib/banzai
lib/gitlab/background_migration
lib/gitlab/cycle_analytics
lib/gitlab/database
lib/gitlab/import_export
lib/gitlab/project_authorizations
lib/gitlab/sql
lib/system_check
lib/tasks
qa
rubocop
spec
].freeze
def on_send(node)
return if in_allowed_directory?(node)
receiver = node.children[0]
send_name = node.children[1]
first_arg = node.children[2]
if receiver && NOT_ALLOWED.key?(send_name)
# If the rule requires an argument to be given, but none are
# provided, we won't register an offense. This prevents us from
# adding offenses for `project.group`, while still covering
# `Project.group(:name)`.
return if NOT_ALLOWED[send_name] && !first_arg
add_offense(node, location: :selector)
end
end
# Returns true if the node resides in one of the allowed
# directories.
def in_allowed_directory?(node)
path = file_path_for_node(node)
ALLOWED_DIRECTORIES.any? do |directory|
path.start_with?(
File.join(rails_root, directory),
File.join(rails_root, 'ee', directory)
)
end
end
# We can not auto correct code like this, as it requires manual
# refactoring. Instead, we'll just allow the surrounding scope.
#
# Despite this method's presence, you should not use it. This method
# exists to make it possible to allow large chunks of offenses we
# can't fix in the short term. If you are writing new code, follow the
# code reuse guidelines, instead of allowing any new offenses.
def autocorrect(node)
scope = surrounding_scope_of(node)
indent = indentation_of(scope)
lambda do |corrector|
# This prevents us from inserting the same enable/disable comment
# for a method or block that has multiple offenses.
next if allowed_scopes.include?(scope)
corrector.insert_before(
scope.source_range,
"# rubocop: disable #{cop_name}\n#{indent}"
)
corrector.insert_after(
scope.source_range,
"\n#{indent}# rubocop: enable #{cop_name}"
)
allowed_scopes << scope
end
end
def indentation_of(node)
' ' * node.loc.expression.source_line[/\A */].length
end
def surrounding_scope_of(node)
%i[def defs block begin].each do |type|
if (found = node.each_ancestor(type).first)
return found
end
end
end
def allowed_scopes
@allowed_scopes ||= Set.new
end
end
end
end
end
......@@ -5,7 +5,7 @@ module RuboCop
def in_qa_file?(node)
path = node.location.expression.source_buffer.name
path.start_with?(File.join(RuboCop::PathUtil.pwd, 'qa'))
path.start_with?(File.join(Dir.pwd, 'qa'))
end
end
end
# Denies the use of ActiveRecord methods outside of configured
# excluded directories
# Directories that allow the use of the denied methods.
# To start we provide a default configuration that matches
# a standard Rails app and enable.
# The default configuration can be overridden by
# providing your own Exclusion list as follows:
# CodeReuse/ActiveRecord:
# Enabled: true
# Exclude:
# - app/models/**/*.rb
# - config/**/*.rb
# - db/**/*.rb
# - lib/tasks/**/*.rb
# - spec/**/*.rb
# - lib/gitlab/**/*.rb
CodeReuse/ActiveRecord:
Exclude:
- app/models/**/*.rb
- config/**/*.rb
- db/**/*.rb
- lib/tasks/**/*.rake
- spec/**/*.rb
- danger/**/*.rb
- lib/backup/**/*.rb
- lib/banzai/**/*.rb
- lib/gitlab/background_migration/**/*.rb
- lib/gitlab/cycle_analytics/**/*.rb
- lib/gitlab/database/**/*.rb
- lib/gitlab/database_importers/common_metrics/importer.rb
- lib/gitlab/import_export/**/*.rb
- lib/gitlab/project_authorizations.rb
- lib/gitlab/sql/**/*.rb
- lib/system_check/**/*.rb
- qa/**/*.rb
- rubocop/**/*.rb
- ee/app/models/**/*.rb
- ee/spec/**/*.rb
- ee/db/fixtures/**/*.rb
- ee/lib/tasks/**/*.rake
- ee/lib/ee/gitlab/background_migration/**/*.rb
......@@ -236,13 +236,16 @@ RSpec.describe Gitlab::Danger::Helper do
'.gitlab/ci/frontend.gitlab-ci.yml' | %i[frontend engineering_productivity]
'app/models/foo' | [:backend]
'bin/foo' | [:backend]
'config/foo' | [:backend]
'lib/foo' | [:backend]
'rubocop/foo' | [:backend]
'spec/foo' | [:backend]
'spec/foo/bar' | [:backend]
'app/models/foo' | [:backend]
'bin/foo' | [:backend]
'config/foo' | [:backend]
'lib/foo' | [:backend]
'rubocop/foo' | [:backend]
'.rubocop.yml' | [:backend]
'.rubocop_todo.yml' | [:backend]
'.rubocop_manual_todo.yml' | [:backend]
'spec/foo' | [:backend]
'spec/foo/bar' | [:backend]
'ee/app/foo' | [:backend]
'ee/bin/foo' | [:backend]
......
......@@ -108,7 +108,7 @@ RSpec.describe Key, :mailer do
expect(build(:key, key: 'ssh-rsa an-invalid-key==')).not_to be_valid
end
where(:factory, :chars, :expected_sections) do
where(:factory, :characters, :expected_sections) do
[
[:key, ["\n", "\r\n"], 3],
[:key, [' ', ' '], 3],
......@@ -122,7 +122,7 @@ RSpec.describe Key, :mailer do
let!(:original_fingerprint_sha256) { key.fingerprint_sha256 }
it 'accepts a key with blank space characters after stripping them' do
modified_key = key.key.insert(100, chars.first).insert(40, chars.last)
modified_key = key.key.insert(100, characters.first).insert(40, characters.last)
_, content = modified_key.split
key.update!(key: modified_key)
......
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop'
require_relative '../../../../rubocop/cop/code_reuse/active_record'
RSpec.describe RuboCop::Cop::CodeReuse::ActiveRecord, type: :rubocop do
include CopHelper
subject(:cop) { described_class.new }
it 'flags the use of "where" without any arguments' do
expect_offense(<<~SOURCE)
def foo
User.where
^^^^^ This method can only be used inside an ActiveRecord model: https://gitlab.com/gitlab-org/gitlab-foss/issues/49653
end
SOURCE
end
it 'flags the use of "where" with arguments' do
expect_offense(<<~SOURCE)
def foo
User.where(id: 10)
^^^^^ This method can only be used inside an ActiveRecord model: https://gitlab.com/gitlab-org/gitlab-foss/issues/49653
end
SOURCE
end
it 'does not flag the use of "group" without any arguments' do
expect_no_offenses(<<~SOURCE)
def foo
project.group
end
SOURCE
end
it 'flags the use of "group" with arguments' do
expect_offense(<<~SOURCE)
def foo
project.group(:name)
^^^^^ This method can only be used inside an ActiveRecord model: https://gitlab.com/gitlab-org/gitlab-foss/issues/49653
end
SOURCE
end
it 'does not flag the use of ActiveRecord models in a model' do
path = rails_root_join('app', 'models', 'foo.rb').to_s
expect_no_offenses(<<~SOURCE, path)
def foo
project.group(:name)
end
SOURCE
end
it 'does not flag the use of ActiveRecord models in a spec' do
path = rails_root_join('spec', 'foo_spec.rb').to_s
expect_no_offenses(<<~SOURCE, path)
def foo
project.group(:name)
end
SOURCE
end
it 'does not flag the use of ActiveRecord models in a background migration' do
path = rails_root_join('lib', 'gitlab', 'background_migration', 'foo.rb').to_s
expect_no_offenses(<<~SOURCE, path)
def foo
project.group(:name)
end
SOURCE
end
it 'does not flag the use of ActiveRecord models in lib/gitlab/database' do
path = rails_root_join('lib', 'gitlab', 'database', 'foo.rb').to_s
expect_no_offenses(<<~SOURCE, path)
def foo
project.group(:name)
end
SOURCE
end
it 'autocorrects offenses in instance methods by allowing them' do
corrected = autocorrect_source(<<~SOURCE)
def foo
User.where
end
SOURCE
expect(corrected).to eq(<<~SOURCE)
# rubocop: disable CodeReuse/ActiveRecord
def foo
User.where
end
# rubocop: enable CodeReuse/ActiveRecord
SOURCE
end
it 'autocorrects offenses in class methods by allowing them' do
corrected = autocorrect_source(<<~SOURCE)
def self.foo
User.where
end
SOURCE
expect(corrected).to eq(<<~SOURCE)
# rubocop: disable CodeReuse/ActiveRecord
def self.foo
User.where
end
# rubocop: enable CodeReuse/ActiveRecord
SOURCE
end
it 'autocorrects offenses in blocks by allowing them' do
corrected = autocorrect_source(<<~SOURCE)
get '/' do
User.where
end
SOURCE
expect(corrected).to eq(<<~SOURCE)
# rubocop: disable CodeReuse/ActiveRecord
get '/' do
User.where
end
# rubocop: enable CodeReuse/ActiveRecord
SOURCE
end
end
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop'
require_relative '../../../../rubocop/cop/rspec/be_success_matcher'
RSpec.describe RuboCop::Cop::RSpec::BeSuccessMatcher, type: :rubocop do
......
# frozen_string_literal: true
require 'tempfile'
# This module provides methods that make it easier to test Cops.
module CopHelper
extend RSpec::SharedContext
let(:ruby_version) { 2.4 }
let(:rails_version) { false }
def inspect_source_file(source)
Tempfile.open('tmp') { |f| inspect_source(source, f) }
end
def inspect_source(source, file = nil)
RuboCop::Formatter::DisabledConfigFormatter.config_to_allow_offenses = {}
RuboCop::Formatter::DisabledConfigFormatter.detected_styles = {}
processed_source = parse_source(source, file)
raise 'Error parsing example code' unless processed_source.valid_syntax?
_investigate(cop, processed_source)
end
def parse_source(source, file = nil)
if file&.respond_to?(:write)
file.write(source)
file.rewind
file = file.path
end
RuboCop::ProcessedSource.new(source, ruby_version, file)
end
def autocorrect_source_file(source)
Tempfile.open('tmp') { |f| autocorrect_source(source, f) }
end
def autocorrect_source(source, file = nil)
RuboCop::Formatter::DisabledConfigFormatter.config_to_allow_offenses = {}
RuboCop::Formatter::DisabledConfigFormatter.detected_styles = {}
cop.instance_variable_get(:@options)[:auto_correct] = true
processed_source = parse_source(source, file)
_investigate(cop, processed_source)
@last_corrector.rewrite
end
def _investigate(cop, processed_source)
team = RuboCop::Cop::Team.new([cop], nil, raise_error: true)
report = team.investigate(processed_source)
@last_corrector = report.correctors.first || RuboCop::Cop::Corrector.new(processed_source)
report.offenses
end
end
module RuboCop
module Cop
# Monkey-patch Cop for tests to provide easy access to messages and
# highlights.
# this file is an exact copy of source except for this line
# where we change to the new Base class defined in rubocop and skirt around our superclass mismatch for class Cop
# when running a rubocop spec.
class Base
def messages
offenses.sort.map(&:message)
end
def highlights
offenses.sort.map { |o| o.location.source }
end
end
end
end
......@@ -5,7 +5,8 @@ require_relative "helpers/stub_metrics"
require_relative "helpers/stub_object_storage"
require_relative "helpers/stub_env"
require_relative "helpers/fast_rails_root"
require 'rubocop/rspec/support'
require_relative 'rubocop_patch'
RSpec.configure do |config|
config.mock_with :rspec
......
# frozen_string_literal: true
# There is an issue between rubocop versions 0.86 and 0.87 (verified by testing locally)
# where the monkey patching in cop_helper is referencing class Cop and should really be referencing class Base instead
# the gem's version of the cop_helper causes this issue when testing a rubocop cop locally and in CI
# The only difference in this file as compared to gem source file is that we include our own cop_helper instead
# which is a direct copy with a fix for the monkey patching part.
# Doing this, resolves the issue.
# Ideally we should move away from using the cop_helper at all as is the direction of rubocop as seen
# here - https://github.com/rubocop-hq/rubocop/issues/8003
# more info https://gitlab.com/gitlab-org/gitlab/-/merge_requests/46477
require_relative 'helpers/cop_helper'
require 'rubocop/rspec/host_environment_simulation_helper'
require 'rubocop/rspec/shared_contexts'
require 'rubocop/rspec/expect_offense'
RSpec.configure do |config|
config.include CopHelper
config.include HostEnvironmentSimulatorHelper
end
......@@ -4,6 +4,6 @@
source 'https://rubygems.org'
gem 'overcommit'
gem 'gitlab-styles', '~> 4.3.0', require: false
gem 'gitlab-styles', '~> 5.0.0', require: false
gem 'scss_lint', '~> 0.56.0', require: false
gem 'haml_lint', '~> 0.34.0', require: false
GEM
remote: https://rubygems.org/
specs:
activesupport (6.0.3)
activesupport (6.0.3.4)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
zeitwerk (~> 2.2, >= 2.2.2)
ast (2.4.0)
ast (2.4.1)
childprocess (3.0.0)
concurrent-ruby (1.1.6)
concurrent-ruby (1.1.7)
ffi (1.12.2)
gitlab-styles (4.3.0)
rubocop (~> 0.82.0)
gitlab-styles (5.0.0)
rubocop (~> 0.89.1)
rubocop-gitlab-security (~> 0.1.0)
rubocop-performance (~> 1.5.2)
rubocop-rails (~> 2.5)
rubocop-rspec (~> 1.36)
rubocop-performance (~> 1.8.1)
rubocop-rails (~> 2.8)
rubocop-rspec (~> 1.44)
haml (5.1.2)
temple (>= 0.8.0)
tilt
......@@ -25,42 +25,47 @@ GEM
rainbow
rubocop (>= 0.50.0)
sysexits (~> 1.1)
i18n (1.8.2)
i18n (1.8.5)
concurrent-ruby (~> 1.0)
iniparse (1.5.0)
jaro_winkler (1.5.4)
minitest (5.11.3)
minitest (5.14.2)
overcommit (0.53.0)
childprocess (>= 0.6.3, < 4)
iniparse (~> 1.4)
parallel (1.19.1)
parser (2.7.1.2)
ast (~> 2.4.0)
rack (2.0.9)
parallel (1.19.2)
parser (2.7.2.0)
ast (~> 2.4.1)
rack (2.2.3)
rainbow (3.0.0)
rake (12.3.3)
rb-fsevent (0.10.2)
rb-inotify (0.9.10)
ffi (>= 0.5.0, < 2)
regexp_parser (1.8.2)
rexml (3.2.4)
rubocop (0.82.0)
jaro_winkler (~> 1.5.1)
rubocop (0.89.1)
parallel (~> 1.10)
parser (>= 2.7.0.1)
parser (>= 2.7.1.1)
rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 1.7)
rexml
rubocop-ast (>= 0.3.0, < 1.0)
ruby-progressbar (~> 1.7)
unicode-display_width (>= 1.4.0, < 2.0)
rubocop-ast (0.8.0)
parser (>= 2.7.1.5)
rubocop-gitlab-security (0.1.1)
rubocop (>= 0.51)
rubocop-performance (1.5.2)
rubocop (>= 0.71.0)
rubocop-rails (2.5.2)
activesupport
rubocop-performance (1.8.1)
rubocop (>= 0.87.0)
rubocop-ast (>= 0.4.0)
rubocop-rails (2.8.1)
activesupport (>= 4.2.0)
rack (>= 1.1)
rubocop (>= 0.72.0)
rubocop-rspec (1.37.0)
rubocop (>= 0.68.1)
rubocop (>= 0.87.0)
rubocop-rspec (1.44.1)
rubocop (~> 0.87)
rubocop-ast (>= 0.7.1)
ruby-progressbar (1.10.1)
sass (3.5.5)
sass-listen (~> 4.0.0)
......@@ -77,13 +82,13 @@ GEM
tzinfo (1.2.7)
thread_safe (~> 0.1)
unicode-display_width (1.7.0)
zeitwerk (2.3.0)
zeitwerk (2.4.1)
PLATFORMS
ruby
DEPENDENCIES
gitlab-styles (~> 4.3.0)
gitlab-styles (~> 5.0.0)
haml_lint (~> 0.34.0)
overcommit
scss_lint (~> 0.56.0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment