Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2020-08-18 09:10:05 +00:00
parent 681ca59b6f
commit 89eff770d2
34 changed files with 327 additions and 347 deletions

View file

@ -1,6 +1,6 @@
<script>
import { isEmpty, omit, throttle } from 'lodash';
import { GlLink, GlDeprecatedButton, GlTooltip, GlResizeObserverDirective } from '@gitlab/ui';
import { GlLink, GlTooltip, GlResizeObserverDirective } from '@gitlab/ui';
import { GlAreaChart, GlLineChart, GlChartSeriesLabel } from '@gitlab/ui/dist/charts';
import { s__ } from '~/locale';
import { getSvgIconPathContent } from '~/lib/utils/icon_utils';
@ -25,7 +25,6 @@ export default {
GlAreaChart,
GlLineChart,
GlTooltip,
GlDeprecatedButton,
GlChartSeriesLabel,
GlLink,
Icon,

View file

@ -1,17 +0,0 @@
# 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

@ -10,7 +10,7 @@ module Resolvers
def resolve(iid:)
BatchLoader::GraphQL.for(iid).batch(key: project) do |iids, loader, args|
args[:key].ci_pipelines.for_iid(iids).each { |pl| loader.call(pl.iid.to_s, pl) }
args[:key].all_pipelines.for_iid(iids).each { |pl| loader.call(pl.iid.to_s, pl) }
end
end
end

View file

@ -0,0 +1,11 @@
# frozen_string_literal: true
module Types
module Ci
class PipelineConfigSourceEnum < BaseEnum
::Ci::PipelineEnums.config_sources.keys.each do |state_symbol|
value state_symbol.to_s.upcase, value: state_symbol.to_s
end
end
end
end

View file

@ -25,6 +25,8 @@ module Types
field :detailed_status, Types::Ci::DetailedStatusType, null: false,
description: 'Detailed status of the pipeline',
resolve: -> (obj, _args, ctx) { obj.detailed_status(ctx[:current_user]) }
field :config_source, PipelineConfigSourceEnum, null: true,
description: "Config source of the pipeline (#{::Ci::PipelineEnums.config_sources.keys.join(', ').upcase})"
field :duration, GraphQL::INT_TYPE, null: true,
description: 'Duration of the pipeline in seconds'
field :coverage, GraphQL::FLOAT_TYPE, null: true,

View file

@ -1,25 +0,0 @@
# frozen_string_literal: true
module Types
module CiConfiguration
module Sast
# rubocop: disable Graphql/AuthorizeTypes
class AnalyzersEntityType < BaseObject
graphql_name 'SastCiConfigurationAnalyzersEntity'
description 'Represents an analyzer entity in SAST CI configuration'
field :name, GraphQL::STRING_TYPE, null: true,
description: 'Name of the analyzer.'
field :label, GraphQL::STRING_TYPE, null: true,
description: 'Analyzer label used in the config UI.'
field :enabled, GraphQL::BOOLEAN_TYPE, null: true,
description: 'Indicates whether an analyzer is enabled.'
field :description, GraphQL::STRING_TYPE, null: true,
description: 'Analyzer description that is displayed on the form.'
end
end
end
end

View file

@ -1,34 +0,0 @@
# frozen_string_literal: true
module Types
module CiConfiguration
module Sast
# rubocop: disable Graphql/AuthorizeTypes
class EntityType < BaseObject
graphql_name 'SastCiConfigurationEntity'
description 'Represents an entity in SAST CI configuration'
field :field, GraphQL::STRING_TYPE, null: true,
description: 'CI keyword of entity.'
field :label, GraphQL::STRING_TYPE, null: true,
description: 'Label for entity used in the form.'
field :type, GraphQL::STRING_TYPE, null: true,
description: 'Type of the field value.'
field :options, ::Types::CiConfiguration::Sast::OptionsEntityType.connection_type, null: true,
description: 'Different possible values of the field.'
field :default_value, GraphQL::STRING_TYPE, null: true,
description: 'Default value that is used if value is empty.'
field :description, GraphQL::STRING_TYPE, null: true,
description: 'Entity description that is displayed on the form.'
field :value, GraphQL::STRING_TYPE, null: true,
description: 'Current value of the entity.'
end
end
end
end

View file

@ -1,19 +0,0 @@
# frozen_string_literal: true
module Types
module CiConfiguration
module Sast
# rubocop: disable Graphql/AuthorizeTypes
class OptionsEntityType < BaseObject
graphql_name 'SastCiConfigurationOptionsEntity'
description 'Represents an entity for options in SAST CI configuration'
field :label, GraphQL::STRING_TYPE, null: true,
description: 'Label of option entity.'
field :value, GraphQL::STRING_TYPE, null: true,
description: 'Value of option entity.'
end
end
end
end

View file

@ -1,22 +0,0 @@
# frozen_string_literal: true
module Types
module CiConfiguration
module Sast
# rubocop: disable Graphql/AuthorizeTypes
class Type < BaseObject
graphql_name 'SastCiConfiguration'
description 'Represents a CI configuration of SAST'
field :global, ::Types::CiConfiguration::Sast::EntityType.connection_type, null: true,
description: 'List of global entities related to SAST configuration.'
field :pipeline, ::Types::CiConfiguration::Sast::EntityType.connection_type, null: true,
description: 'List of pipeline entities related to SAST configuration.'
field :analyzers, ::Types::CiConfiguration::Sast::AnalyzersEntityType.connection_type, null: true,
description: 'List of analyzers entities attached to SAST configuration.'
end
end
end
end

View file

@ -175,10 +175,6 @@ module Types
description: 'A single environment of the project',
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,
Types::IssueType,
null: true,

View file

@ -4,83 +4,43 @@
"field" : "SECURE_ANALYZERS_PREFIX",
"label" : "Image prefix",
"type": "string",
"default_value": "registry.gitlab.com/gitlab-org/security-products/analyzers",
"value": ""
"default_value": "",
"value": "",
"description": "Analyzer image's registry prefix (or Name of the registry providing the analyzers' image)"
},
{
"field" : "SAST_EXCLUDED_PATHS",
"label" : "Excluded Paths",
"type": "string",
"default_value": "spec, test, tests, tmp",
"value": ""
"default_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",
"label" : "Image tag",
"type": "string",
"options": [],
"default_value": "2",
"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": ""
"default_value": "",
"value": "",
"description": "Analyzer image's tag"
}
],
"pipeline": [
{
"field" : "stage",
"label" : "Stage",
"type": "dropdown",
"options": [
{
"value" :"test",
"label" : "test"
},
{
"value":"build",
"label":"build"
}
],
"default_value": "test",
"value": ""
},
{
"field" : "allow_failure",
"label" : "Allow Failure",
"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",
"type": "string",
"default_value": "",
"value": ""
"value": "",
"description": "Pipeline stage in which the scan jobs run"
},
{
"field" : "SEARCH_MAX_DEPTH",
"label" : "Search maximum depth",
"type": "string",
"default_value": "",
"value": "",
"description": "Maximum depth of language and framework detection"
}
],
"analyzers": [

View file

@ -0,0 +1,5 @@
---
title: Remove not-null constraint on type column in audit_events
merge_request: 39192
author:
type: other

View file

@ -0,0 +1,5 @@
---
title: Allow GraphQL pipeline to resolve non-CI pipelines and expose configSource field
merge_request: 39275
author:
type: added

View file

@ -0,0 +1,27 @@
# frozen_string_literal: true
class RemoveNotNullConstraintOnTypeFromAuditEvents < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
disable_ddl_transaction!
# rubocop:disable Migration/WithLockRetriesDisallowedMethod
# To avoid deadlock on audit_event and audit_event_part... since there is a trigger to insert record from audit_events
# to audit_events_part..., we need to ensure each ALTER TABLE command run in its own transaction.
def up
with_lock_retries do
change_column_null :audit_events_part_5fc467ac26, :type, true
end
with_lock_retries do
change_column_null :audit_events, :type, true
end
end
# rubocop:enable Migration/WithLockRetriesDisallowedMethod
def down
# no-op -- null values might be added after this constraint is removed.
end
end

View file

@ -0,0 +1 @@
b7477fbcba166d848e3b1bd7f4a184f50f3b2fafe80bfcf44fd6f4f9979ffcb7

View file

@ -68,7 +68,7 @@ COMMENT ON FUNCTION public.table_sync_function_2be879775d() IS 'Partitioning mig
CREATE TABLE public.audit_events_part_5fc467ac26 (
id bigint NOT NULL,
author_id integer NOT NULL,
type character varying NOT NULL,
type character varying,
entity_id integer NOT NULL,
entity_type character varying NOT NULL,
details text,
@ -9466,7 +9466,7 @@ CREATE TABLE public.ar_internal_metadata (
CREATE TABLE public.audit_events (
id integer NOT NULL,
author_id integer NOT NULL,
type character varying NOT NULL,
type character varying,
entity_id integer NOT NULL,
entity_type character varying NOT NULL,
details text,

View file

@ -10261,6 +10261,13 @@ type Pipeline {
"""
committedAt: Time
"""
Config source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE,
AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE,
BRIDGE_SOURCE, PARAMETER_SOURCE)
"""
configSource: PipelineConfigSourceEnum
"""
Coverage percentage
"""
@ -10353,6 +10360,17 @@ type Pipeline {
userPermissions: PipelinePermissions!
}
enum PipelineConfigSourceEnum {
AUTO_DEVOPS_SOURCE
BRIDGE_SOURCE
EXTERNAL_PROJECT_SOURCE
PARAMETER_SOURCE
REMOTE_SOURCE
REPOSITORY_SOURCE
UNKNOWN_SOURCE
WEBIDE_SOURCE
}
"""
The connection type for Pipeline.
"""

View file

@ -30652,6 +30652,20 @@
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "configSource",
"description": "Config source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE)",
"args": [
],
"type": {
"kind": "ENUM",
"name": "PipelineConfigSourceEnum",
"ofType": null
},
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "coverage",
"description": "Coverage percentage",
@ -30927,6 +30941,65 @@
"enumValues": null,
"possibleTypes": null
},
{
"kind": "ENUM",
"name": "PipelineConfigSourceEnum",
"description": null,
"fields": null,
"inputFields": null,
"interfaces": null,
"enumValues": [
{
"name": "UNKNOWN_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "REPOSITORY_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "AUTO_DEVOPS_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "WEBIDE_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "REMOTE_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "EXTERNAL_PROJECT_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "BRIDGE_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
},
{
"name": "PARAMETER_SOURCE",
"description": null,
"isDeprecated": false,
"deprecationReason": null
}
],
"possibleTypes": null
},
{
"kind": "OBJECT",
"name": "PipelineConnection",

View file

@ -1571,6 +1571,7 @@ Information about pagination in a connection.
| --- | ---- | ---------- |
| `beforeSha` | String | Base SHA of the source branch |
| `committedAt` | Time | Timestamp of the pipeline's commit |
| `configSource` | PipelineConfigSourceEnum | Config source of the pipeline (UNKNOWN_SOURCE, REPOSITORY_SOURCE, AUTO_DEVOPS_SOURCE, WEBIDE_SOURCE, REMOTE_SOURCE, EXTERNAL_PROJECT_SOURCE, BRIDGE_SOURCE, PARAMETER_SOURCE) |
| `coverage` | Float | Coverage percentage |
| `createdAt` | Time! | Timestamp of the pipeline's creation |
| `detailedStatus` | DetailedStatus! | Detailed status of the pipeline |

View file

@ -306,6 +306,7 @@ module Gitlab
Gitlab::UsageData::Topology.new.topology_usage_data
end
# rubocop: disable UsageData/DistinctCountByLargeForeignKey
def ingress_modsecurity_usage
##
# This method measures usage of the Modsecurity Web Application Firewall across the entire
@ -326,6 +327,7 @@ module Gitlab
ingress_modsecurity_not_installed: distinct_count(successful_deployments_with_cluster(::Clusters::Applications::Ingress.modsecurity_not_installed), column)
}
end
# rubocop: enable UsageData/DistinctCountByLargeForeignKey
# rubocop: disable CodeReuse/ActiveRecord
def container_expiration_policies_usage
@ -729,9 +731,11 @@ module Gitlab
end
# rubocop: disable CodeReuse/ActiveRecord
# rubocop: disable UsageData/DistinctCountByLargeForeignKey
def cluster_applications_user_distinct_count(applications, time_period)
distinct_count(applications.where(time_period).available.joins(:cluster), 'clusters.user_id')
end
# rubocop: enable UsageData/DistinctCountByLargeForeignKey
def clusters_user_distinct_count(clusters, time_period)
distinct_count(clusters.where(time_period), :user_id)

View file

@ -0,0 +1,43 @@
# frozen_string_literal: true
module RuboCop
module Cop
module UsageData
# Allows counts only for selected tables' foreign keys for `distinct_count` method.
#
# Because distinct_counts over large tables' foreign keys will take a long time
#
# @example
#
# # bad because pipeline_id points to a large table
# distinct_count(Ci::Build, :commit_id)
#
class DistinctCountByLargeForeignKey < RuboCop::Cop::Cop
MSG = 'Avoid doing `%s` for large foreign keys.'.freeze
def_node_matcher :distinct_count?, <<-PATTERN
(send _ $:distinct_count $...)
PATTERN
def on_send(node)
distinct_count?(node) do |method_name, method_arguments|
next unless method_arguments && method_arguments.length >= 2
next if allowed_foreign_key?(method_arguments[1])
add_offense(node, location: :selector, message: format(MSG, method_name))
end
end
private
def allowed_foreign_key?(key)
key.type == :sym && allowed_foreign_keys.include?(key.value)
end
def allowed_foreign_keys
cop_config['AllowedForeignKeys'] || []
end
end
end
end
end

View file

@ -30,3 +30,16 @@ UsageData/LargeTable:
- :arel_table
- :minimum
- :maximum
UsageData/DistinctCountByLargeForeignKey:
Enabled: true
Include:
- 'lib/gitlab/usage_data.rb'
- 'ee/lib/ee/gitlab/usage_data.rb'
AllowedForeignKeys:
- :user_id
- :author_id
- :creator_id
- :owner_id
- :project_id
- :issue_id
- :merge_request_id

View file

@ -1,28 +0,0 @@
# 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

@ -33,4 +33,21 @@ RSpec.describe Resolvers::ProjectPipelineResolver do
it 'errors when no iid is passed' do
expect { resolve_pipeline(project, {}) }.to raise_error(ArgumentError)
end
context 'when the pipeline is not a ci_config_source' do
let(:pipeline) do
config_source_value = Ci::PipelineEnums.non_ci_config_source_values.first
config_source = Ci::PipelineEnums.config_sources.key(config_source_value)
create(:ci_pipeline, config_source: config_source, project: project)
end
it 'resolves pipeline for the passed iid' do
result = batch_sync do
resolve_pipeline(project, { iid: pipeline.iid.to_s })
end
expect(result).to eq(pipeline)
end
end
end

View file

@ -1,11 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfigurationAnalyzersEntity'] do
let(:fields) { %i[name label enabled description] }
it { expect(described_class.graphql_name).to eq('SastCiConfigurationAnalyzersEntity') }
it { expect(described_class).to have_graphql_fields(fields) }
end

View file

@ -1,11 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfigurationEntity'] do
let(:fields) { %i[field label description type options default_value value] }
it { expect(described_class.graphql_name).to eq('SastCiConfigurationEntity') }
it { expect(described_class).to have_graphql_fields(fields) }
end

View file

@ -1,11 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfigurationOptionsEntity'] do
let(:fields) { %i[label value] }
it { expect(described_class.graphql_name).to eq('SastCiConfigurationOptionsEntity') }
it { expect(described_class).to have_graphql_fields(fields) }
end

View file

@ -1,11 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe GitlabSchema.types['SastCiConfiguration'] do
let(:fields) { %i[global pipeline analyzers] }
it { expect(described_class.graphql_name).to eq('SastCiConfiguration') }
it { expect(described_class).to have_graphql_fields(fields) }
end

View file

@ -26,7 +26,7 @@ RSpec.describe GitlabSchema.types['Project'] do
grafanaIntegration autocloseReferencedIssues suggestion_commit_message environments
environment boards jira_import_status jira_imports services releases release
alert_management_alerts alert_management_alert alert_management_alert_status_counts
container_expiration_policy sast_ci_configuration service_desk_enabled service_desk_address
container_expiration_policy service_desk_enabled service_desk_address
issue_status_counts
]
@ -150,93 +150,5 @@ RSpec.describe GitlabSchema.types['Project'] do
it { is_expected.to have_graphql_type(Types::ContainerExpirationPolicyType) }
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'
end

View file

@ -10,6 +10,13 @@ RSpec.describe AuditEventPartitioned do
expect(partitioned_table.column_names).to match_array(source_table.column_names)
end
it 'has the same null constraints as the source table' do
constraints_from_source_table = null_constraints(source_table)
constraints_from_partitioned_table = null_constraints(partitioned_table)
expect(constraints_from_partitioned_table.to_a).to match_array(constraints_from_source_table.to_a)
end
it 'inserts the same record as the one in the source table', :aggregate_failures do
expect { create(:audit_event) }.to change { partitioned_table.count }.by(1)
@ -22,4 +29,13 @@ RSpec.describe AuditEventPartitioned do
expect(event_from_partitioned_table).to eq(event_from_source_table)
end
def null_constraints(table)
table.connection.select_all(<<~SQL)
SELECT c.column_name, c.is_nullable
FROM information_schema.columns c
WHERE c.table_name = '#{table.table_name}'
AND c.column_name != 'created_at'
SQL
end
end

View file

@ -29,4 +29,10 @@ RSpec.describe 'getting pipeline information nested in a project' do
expect(pipeline_graphql_data).not_to be_nil
end
it 'contains configSource' do
post_graphql(query, current_user: current_user)
expect(pipeline_graphql_data.dig('configSource')).to eq('UNKNOWN_SOURCE')
end
end

View file

@ -0,0 +1,38 @@
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rubocop'
require 'rubocop/rspec/support'
require_relative '../../../../rubocop/cop/usage_data/distinct_count_by_large_foreign_key'
RSpec.describe RuboCop::Cop::UsageData::DistinctCountByLargeForeignKey, type: :rubocop do
include CopHelper
let(:allowed_foreign_keys) { %i[author_id user_id] }
let(:config) do
RuboCop::Config.new('UsageData/DistinctCountByLargeForeignKey' => {
'AllowedForeignKeys' => allowed_foreign_keys
})
end
subject(:cop) { described_class.new(config) }
context 'when counting by disallowed key' do
it 'register an offence' do
inspect_source('distinct_count(Issue, :creator_id)')
expect(cop.offenses.size).to eq(1)
end
end
context 'when calling by allowed key' do
it 'does not register an offence' do
inspect_source('distinct_count(Issue, :author_id)')
expect(cop.offenses).to be_empty
end
end
end

View file

@ -0,0 +1,13 @@
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

@ -0,0 +1,9 @@
# 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