summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-08-18 09:10:05 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-08-18 09:10:05 +0000
commit89eff770d213e684b5fa4df121cb51a059e8d263 (patch)
treef2783e2aaf50ebba6051f11335a45029b8549d34
parent681ca59b6f81a3a0057e3d528c27bcf96c2edd1b (diff)
downloadgitlab-ce-89eff770d213e684b5fa4df121cb51a059e8d263.tar.gz
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/monitoring/components/charts/time_series.vue3
-rw-r--r--app/graphql/resolvers/ci_configuration/sast_resolver.rb17
-rw-r--r--app/graphql/resolvers/project_pipeline_resolver.rb2
-rw-r--r--app/graphql/types/ci/pipeline_config_source_enum.rb11
-rw-r--r--app/graphql/types/ci/pipeline_type.rb2
-rw-r--r--app/graphql/types/ci_configuration/sast/analyzers_entity_type.rb25
-rw-r--r--app/graphql/types/ci_configuration/sast/entity_type.rb34
-rw-r--r--app/graphql/types/ci_configuration/sast/options_entity_type.rb19
-rw-r--r--app/graphql/types/ci_configuration/sast/type.rb22
-rw-r--r--app/graphql/types/project_type.rb4
-rw-r--r--app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json76
-rw-r--r--changelogs/unreleased/229914-remove-constraint-on-audit-event-type.yml5
-rw-r--r--changelogs/unreleased/null-pipeline-in-graphql-response-224687.yml5
-rw-r--r--db/migrate/20200811055018_remove_not_null_constraint_on_type_from_audit_events.rb27
-rw-r--r--db/schema_migrations/202008110550181
-rw-r--r--db/structure.sql4
-rw-r--r--doc/api/graphql/reference/gitlab_schema.graphql18
-rw-r--r--doc/api/graphql/reference/gitlab_schema.json73
-rw-r--r--doc/api/graphql/reference/index.md1
-rw-r--r--lib/gitlab/usage_data.rb4
-rw-r--r--rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb43
-rw-r--r--rubocop/rubocop-usage-data.yml13
-rw-r--r--spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb28
-rw-r--r--spec/graphql/resolvers/project_pipeline_resolver_spec.rb17
-rw-r--r--spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/entity_type_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/options_entity_spec.rb11
-rw-r--r--spec/graphql/types/ci_configuration/sast/type_spec.rb11
-rw-r--r--spec/graphql/types/project_type_spec.rb90
-rw-r--r--spec/models/audit_event_partitioned_spec.rb16
-rw-r--r--spec/requests/api/graphql/project/pipeline_spec.rb6
-rw-r--r--spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb38
-rw-r--r--spec/support/gitlab_stubs/gitlab_ci_for_sast.yml13
-rw-r--r--spec/support/shared_contexts/read_ci_configuration_shared_context.rb9
34 files changed, 325 insertions, 345 deletions
diff --git a/app/assets/javascripts/monitoring/components/charts/time_series.vue b/app/assets/javascripts/monitoring/components/charts/time_series.vue
index e7cd612409f..054111c203e 100644
--- a/app/assets/javascripts/monitoring/components/charts/time_series.vue
+++ b/app/assets/javascripts/monitoring/components/charts/time_series.vue
@@ -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,
diff --git a/app/graphql/resolvers/ci_configuration/sast_resolver.rb b/app/graphql/resolvers/ci_configuration/sast_resolver.rb
deleted file mode 100644
index e8c42076ea2..00000000000
--- a/app/graphql/resolvers/ci_configuration/sast_resolver.rb
+++ /dev/null
@@ -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
diff --git a/app/graphql/resolvers/project_pipeline_resolver.rb b/app/graphql/resolvers/project_pipeline_resolver.rb
index 5bafe3dd140..181c1e77109 100644
--- a/app/graphql/resolvers/project_pipeline_resolver.rb
+++ b/app/graphql/resolvers/project_pipeline_resolver.rb
@@ -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
diff --git a/app/graphql/types/ci/pipeline_config_source_enum.rb b/app/graphql/types/ci/pipeline_config_source_enum.rb
new file mode 100644
index 00000000000..48f88c133b4
--- /dev/null
+++ b/app/graphql/types/ci/pipeline_config_source_enum.rb
@@ -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
diff --git a/app/graphql/types/ci/pipeline_type.rb b/app/graphql/types/ci/pipeline_type.rb
index caa7079e2c6..c9cbae2d828 100644
--- a/app/graphql/types/ci/pipeline_type.rb
+++ b/app/graphql/types/ci/pipeline_type.rb
@@ -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,
diff --git a/app/graphql/types/ci_configuration/sast/analyzers_entity_type.rb b/app/graphql/types/ci_configuration/sast/analyzers_entity_type.rb
deleted file mode 100644
index ccd1c7dd0eb..00000000000
--- a/app/graphql/types/ci_configuration/sast/analyzers_entity_type.rb
+++ /dev/null
@@ -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
diff --git a/app/graphql/types/ci_configuration/sast/entity_type.rb b/app/graphql/types/ci_configuration/sast/entity_type.rb
deleted file mode 100644
index b61b582ad20..00000000000
--- a/app/graphql/types/ci_configuration/sast/entity_type.rb
+++ /dev/null
@@ -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
diff --git a/app/graphql/types/ci_configuration/sast/options_entity_type.rb b/app/graphql/types/ci_configuration/sast/options_entity_type.rb
deleted file mode 100644
index 86d104a7fda..00000000000
--- a/app/graphql/types/ci_configuration/sast/options_entity_type.rb
+++ /dev/null
@@ -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
diff --git a/app/graphql/types/ci_configuration/sast/type.rb b/app/graphql/types/ci_configuration/sast/type.rb
deleted file mode 100644
index 35d11584ac7..00000000000
--- a/app/graphql/types/ci_configuration/sast/type.rb
+++ /dev/null
@@ -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
diff --git a/app/graphql/types/project_type.rb b/app/graphql/types/project_type.rb
index 523e019b955..5562db69de6 100644
--- a/app/graphql/types/project_type.rb
+++ b/app/graphql/types/project_type.rb
@@ -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,
diff --git a/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json b/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
index cce2b28529f..aa4dd60a9fb 100644
--- a/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
+++ b/app/validators/json_schemas/security_ci_configuration_schemas/sast_ui_schema.json
@@ -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": ""
+ "type": "string",
+ "default_value": "",
+ "value": "",
+ "description": "Pipeline stage in which the scan jobs run"
},
{
- "field" : "rules",
- "label" : "Rules",
- "type": "multiline",
+ "field" : "SEARCH_MAX_DEPTH",
+ "label" : "Search maximum depth",
+ "type": "string",
"default_value": "",
- "value": ""
+ "value": "",
+ "description": "Maximum depth of language and framework detection"
}
],
"analyzers": [
diff --git a/changelogs/unreleased/229914-remove-constraint-on-audit-event-type.yml b/changelogs/unreleased/229914-remove-constraint-on-audit-event-type.yml
new file mode 100644
index 00000000000..d218fa007cd
--- /dev/null
+++ b/changelogs/unreleased/229914-remove-constraint-on-audit-event-type.yml
@@ -0,0 +1,5 @@
+---
+title: Remove not-null constraint on type column in audit_events
+merge_request: 39192
+author:
+type: other
diff --git a/changelogs/unreleased/null-pipeline-in-graphql-response-224687.yml b/changelogs/unreleased/null-pipeline-in-graphql-response-224687.yml
new file mode 100644
index 00000000000..f3490df8178
--- /dev/null
+++ b/changelogs/unreleased/null-pipeline-in-graphql-response-224687.yml
@@ -0,0 +1,5 @@
+---
+title: Allow GraphQL pipeline to resolve non-CI pipelines and expose configSource field
+merge_request: 39275
+author:
+type: added
diff --git a/db/migrate/20200811055018_remove_not_null_constraint_on_type_from_audit_events.rb b/db/migrate/20200811055018_remove_not_null_constraint_on_type_from_audit_events.rb
new file mode 100644
index 00000000000..629f357cd19
--- /dev/null
+++ b/db/migrate/20200811055018_remove_not_null_constraint_on_type_from_audit_events.rb
@@ -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
diff --git a/db/schema_migrations/20200811055018 b/db/schema_migrations/20200811055018
new file mode 100644
index 00000000000..abf090f8281
--- /dev/null
+++ b/db/schema_migrations/20200811055018
@@ -0,0 +1 @@
+b7477fbcba166d848e3b1bd7f4a184f50f3b2fafe80bfcf44fd6f4f9979ffcb7 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index 62cb3964bb9..8b14be0905b 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -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,
diff --git a/doc/api/graphql/reference/gitlab_schema.graphql b/doc/api/graphql/reference/gitlab_schema.graphql
index 9263dce0898..387867309b8 100644
--- a/doc/api/graphql/reference/gitlab_schema.graphql
+++ b/doc/api/graphql/reference/gitlab_schema.graphql
@@ -10262,6 +10262,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
"""
coverage: Float
@@ -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.
"""
diff --git a/doc/api/graphql/reference/gitlab_schema.json b/doc/api/graphql/reference/gitlab_schema.json
index 1d791644909..b2d2bd61d5b 100644
--- a/doc/api/graphql/reference/gitlab_schema.json
+++ b/doc/api/graphql/reference/gitlab_schema.json
@@ -30653,6 +30653,20 @@
"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",
"args": [
@@ -30928,6 +30942,65 @@
"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",
"description": "The connection type for Pipeline.",
diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md
index fac5357dc78..dd2fa5e191b 100644
--- a/doc/api/graphql/reference/index.md
+++ b/doc/api/graphql/reference/index.md
@@ -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 |
diff --git a/lib/gitlab/usage_data.rb b/lib/gitlab/usage_data.rb
index db2aff9b25a..f2a7da73120 100644
--- a/lib/gitlab/usage_data.rb
+++ b/lib/gitlab/usage_data.rb
@@ -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)
diff --git a/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb b/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
new file mode 100644
index 00000000000..098410e5ad2
--- /dev/null
+++ b/rubocop/cop/usage_data/distinct_count_by_large_foreign_key.rb
@@ -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
diff --git a/rubocop/rubocop-usage-data.yml b/rubocop/rubocop-usage-data.yml
index 887d7aa9427..bd0dd58dcdf 100644
--- a/rubocop/rubocop-usage-data.yml
+++ b/rubocop/rubocop-usage-data.yml
@@ -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
diff --git a/spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb b/spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb
deleted file mode 100644
index de69ad5d450..00000000000
--- a/spec/graphql/resolvers/ci_configuration/sast_resolver_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
index a659b3bdb6e..fada2f9193c 100644
--- a/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
+++ b/spec/graphql/resolvers/project_pipeline_resolver_spec.rb
@@ -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
diff --git a/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb b/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb
deleted file mode 100644
index 34a22feeaf5..00000000000
--- a/spec/graphql/types/ci_configuration/sast/analyzers_entity_type_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb b/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb
deleted file mode 100644
index 7c6ad013d4a..00000000000
--- a/spec/graphql/types/ci_configuration/sast/entity_type_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb b/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb
deleted file mode 100644
index c60c8b9c84a..00000000000
--- a/spec/graphql/types/ci_configuration/sast/options_entity_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/graphql/types/ci_configuration/sast/type_spec.rb b/spec/graphql/types/ci_configuration/sast/type_spec.rb
deleted file mode 100644
index e7a8cd436e4..00000000000
--- a/spec/graphql/types/ci_configuration/sast/type_spec.rb
+++ /dev/null
@@ -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
diff --git a/spec/graphql/types/project_type_spec.rb b/spec/graphql/types/project_type_spec.rb
index a0b6858fc99..8a5d0cdf12d 100644
--- a/spec/graphql/types/project_type_spec.rb
+++ b/spec/graphql/types/project_type_spec.rb
@@ -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
diff --git a/spec/models/audit_event_partitioned_spec.rb b/spec/models/audit_event_partitioned_spec.rb
index 381e755091a..fe69f0083b7 100644
--- a/spec/models/audit_event_partitioned_spec.rb
+++ b/spec/models/audit_event_partitioned_spec.rb
@@ -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
diff --git a/spec/requests/api/graphql/project/pipeline_spec.rb b/spec/requests/api/graphql/project/pipeline_spec.rb
index 57b9de25c3d..fef0e7e160c 100644
--- a/spec/requests/api/graphql/project/pipeline_spec.rb
+++ b/spec/requests/api/graphql/project/pipeline_spec.rb
@@ -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
diff --git a/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb b/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb
new file mode 100644
index 00000000000..db931c50bdf
--- /dev/null
+++ b/spec/rubocop/cop/usage_data/distinct_count_by_large_foreign_key_spec.rb
@@ -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
diff --git a/spec/support/gitlab_stubs/gitlab_ci_for_sast.yml b/spec/support/gitlab_stubs/gitlab_ci_for_sast.yml
new file mode 100644
index 00000000000..4134660e4b9
--- /dev/null
+++ b/spec/support/gitlab_stubs/gitlab_ci_for_sast.yml
@@ -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
diff --git a/spec/support/shared_contexts/read_ci_configuration_shared_context.rb b/spec/support/shared_contexts/read_ci_configuration_shared_context.rb
new file mode 100644
index 00000000000..f8f33e2a745
--- /dev/null
+++ b/spec/support/shared_contexts/read_ci_configuration_shared_context.rb
@@ -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