Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
681ca59b6f
commit
89eff770d2
34 changed files with 327 additions and 347 deletions
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
11
app/graphql/types/ci/pipeline_config_source_enum.rb
Normal file
11
app/graphql/types/ci/pipeline_config_source_enum.rb
Normal 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
|
|
@ -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,
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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": [
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Remove not-null constraint on type column in audit_events
|
||||
merge_request: 39192
|
||||
author:
|
||||
type: other
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Allow GraphQL pipeline to resolve non-CI pipelines and expose configSource field
|
||||
merge_request: 39275
|
||||
author:
|
||||
type: added
|
|
@ -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
|
1
db/schema_migrations/20200811055018
Normal file
1
db/schema_migrations/20200811055018
Normal file
|
@ -0,0 +1 @@
|
|||
b7477fbcba166d848e3b1bd7f4a184f50f3b2fafe80bfcf44fd6f4f9979ffcb7
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
"""
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
13
spec/support/gitlab_stubs/gitlab_ci_for_sast.yml
Normal file
13
spec/support/gitlab_stubs/gitlab_ci_for_sast.yml
Normal 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
|
|
@ -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
|
Loading…
Reference in a new issue