Graphql for enabling SAST IaC via Config UI

Added Graphql endpoint for enabling SAST IaC via Config UI and
corresponding backend code.
Changelog: added
This commit is contained in:
rossfuhrman 2021-10-26 11:26:22 -05:00
parent 9e34f9716b
commit c1c14e635c
No known key found for this signature in database
GPG key ID: CC306400E88FC1C2
10 changed files with 318 additions and 0 deletions

View file

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Mutations
module Security
module CiConfiguration
class ConfigureSastIac < BaseSecurityAnalyzer
graphql_name 'ConfigureSastIac'
description <<~DESC
Enable SAST IaC for a project in a new or
modified `.gitlab-ci.yml` file in a new branch. The new
branch and a URL to create a merge request are a part of the
response.
DESC
def configure_analyzer(project, **_args)
::Security::CiConfiguration::SastIacCreateService.new(project, current_user).execute
end
end
end
end
end

View file

@ -16,6 +16,7 @@ class MutationType < BaseObject
mount_mutation Mutations::AlertManagement::HttpIntegration::ResetToken
mount_mutation Mutations::AlertManagement::HttpIntegration::Destroy
mount_mutation Mutations::Security::CiConfiguration::ConfigureSast
mount_mutation Mutations::Security::CiConfiguration::ConfigureSastIac
mount_mutation Mutations::Security::CiConfiguration::ConfigureSecretDetection
mount_mutation Mutations::AlertManagement::PrometheusIntegration::Create
mount_mutation Mutations::AlertManagement::PrometheusIntegration::Update

View file

@ -0,0 +1,25 @@
# frozen_string_literal: true
module Security
module CiConfiguration
class SastIacCreateService < ::Security::CiConfiguration::BaseCreateService
private
def action
Security::CiConfiguration::SastIacBuildAction.new(project.auto_devops_enabled?, existing_gitlab_ci_content).generate
end
def next_branch
'set-sast-iac-config'
end
def message
_('Configure SAST IaC in `.gitlab-ci.yml`, creating this file if it does not already exist')
end
def description
_('Configure SAST IaC in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) to customize SAST IaC settings.')
end
end
end
end

View file

@ -1009,6 +1009,31 @@ Input type: `ConfigureSastInput`
| <a id="mutationconfiguresasterrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationconfiguresastsuccesspath"></a>`successPath` | [`String`](#string) | Redirect path to use when the response is successful. |
### `Mutation.configureSastIac`
Enable SAST IaC for a project in a new or
modified `.gitlab-ci.yml` file in a new branch. The new
branch and a URL to create a merge request are a part of the
response.
Input type: `ConfigureSastIacInput`
#### Arguments
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationconfiguresastiacclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationconfiguresastiacprojectpath"></a>`projectPath` | [`ID!`](#id) | Full path of the project. |
#### Fields
| Name | Type | Description |
| ---- | ---- | ----------- |
| <a id="mutationconfiguresastiacbranch"></a>`branch` | [`String`](#string) | Branch that has the new/modified `.gitlab-ci.yml` file. |
| <a id="mutationconfiguresastiacclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
| <a id="mutationconfiguresastiacerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
| <a id="mutationconfiguresastiacsuccesspath"></a>`successPath` | [`String`](#string) | Redirect path to use when the response is successful. |
### `Mutation.configureSecretDetection`
Configure Secret Detection for a project by enabling Secret Detection

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
module Security
module CiConfiguration
class SastIacBuildAction < BaseBuildAction
private
def update_existing_content!
@existing_gitlab_ci_content['include'] = generate_includes
end
def template
return 'Auto-DevOps.gitlab-ci.yml' if @auto_devops_enabled
'Security/SAST-IaC.latest.gitlab-ci.yml'
end
end
end
end

View file

@ -8677,6 +8677,12 @@ msgstr ""
msgid "Configure Prometheus"
msgstr ""
msgid "Configure SAST IaC in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) to customize SAST IaC settings."
msgstr ""
msgid "Configure SAST IaC in `.gitlab-ci.yml`, creating this file if it does not already exist"
msgstr ""
msgid "Configure SAST in `.gitlab-ci.yml` using the GitLab managed template. You can [add variable overrides](https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings) to customize SAST settings."
msgstr ""

View file

@ -0,0 +1,13 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Mutations::Security::CiConfiguration::ConfigureSastIac do
include GraphqlHelpers
let(:service) { ::Security::CiConfiguration::SastIacCreateService }
subject { resolve(described_class, args: { project_path: project.full_path }, ctx: { current_user: user }) }
include_examples 'graphql mutations security ci configuration'
end

View file

@ -0,0 +1,163 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Security::CiConfiguration::SastIacBuildAction do
subject(:result) { described_class.new(auto_devops_enabled, gitlab_ci_content).generate }
let(:params) { {} }
context 'with existing .gitlab-ci.yml' do
let(:auto_devops_enabled) { false }
context 'sast iac has not been included' do
let(:expected_yml) do
<<-CI_YML.strip_heredoc
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
stages:
- test
- security
variables:
RANDOM: make sure this persists
include:
- template: existing.yml
- template: Security/SAST-IaC.latest.gitlab-ci.yml
CI_YML
end
context 'template includes are an array' do
let(:gitlab_ci_content) do
{ "stages" => %w(test security),
"variables" => { "RANDOM" => "make sure this persists" },
"include" => [{ "template" => "existing.yml" }] }
end
it 'generates the correct YML' do
expect(result[:action]).to eq('update')
expect(result[:content]).to eq(expected_yml)
end
end
context 'template include is not an array' do
let(:gitlab_ci_content) do
{ "stages" => %w(test security),
"variables" => { "RANDOM" => "make sure this persists" },
"include" => { "template" => "existing.yml" } }
end
it 'generates the correct YML' do
expect(result[:action]).to eq('update')
expect(result[:content]).to eq(expected_yml)
end
end
end
context 'secret_detection has been included' do
let(:expected_yml) do
<<-CI_YML.strip_heredoc
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
stages:
- test
variables:
RANDOM: make sure this persists
include:
- template: Security/SAST-IaC.latest.gitlab-ci.yml
CI_YML
end
context 'secret_detection template include are an array' do
let(:gitlab_ci_content) do
{ "stages" => %w(test),
"variables" => { "RANDOM" => "make sure this persists" },
"include" => [{ "template" => "Security/SAST-IaC.latest.gitlab-ci.yml" }] }
end
it 'generates the correct YML' do
expect(result[:action]).to eq('update')
expect(result[:content]).to eq(expected_yml)
end
end
context 'secret_detection template include is not an array' do
let(:gitlab_ci_content) do
{ "stages" => %w(test),
"variables" => { "RANDOM" => "make sure this persists" },
"include" => { "template" => "Security/SAST-IaC.latest.gitlab-ci.yml" } }
end
it 'generates the correct YML' do
expect(result[:action]).to eq('update')
expect(result[:content]).to eq(expected_yml)
end
end
end
end
context 'with no .gitlab-ci.yml' do
let(:gitlab_ci_content) { nil }
context 'autodevops disabled' do
let(:auto_devops_enabled) { false }
let(:expected_yml) do
<<-CI_YML.strip_heredoc
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
include:
- template: Security/SAST-IaC.latest.gitlab-ci.yml
CI_YML
end
it 'generates the correct YML' do
expect(result[:action]).to eq('create')
expect(result[:content]).to eq(expected_yml)
end
end
context 'with autodevops enabled' do
let(:auto_devops_enabled) { true }
let(:expected_yml) do
<<-CI_YML.strip_heredoc
# You can override the included template(s) by including variable overrides
# SAST customization: https://docs.gitlab.com/ee/user/application_security/sast/#customizing-the-sast-settings
# Secret Detection customization: https://docs.gitlab.com/ee/user/application_security/secret_detection/#customizing-settings
# Dependency Scanning customization: https://docs.gitlab.com/ee/user/application_security/dependency_scanning/#customizing-the-dependency-scanning-settings
# Note that environment variables can be set in several places
# See https://docs.gitlab.com/ee/ci/variables/#cicd-variable-precedence
include:
- template: Auto-DevOps.gitlab-ci.yml
CI_YML
end
before do
allow_next_instance_of(described_class) do |sast_iac_build_actions|
allow(sast_iac_build_actions).to receive(:auto_devops_stages).and_return(fast_auto_devops_stages)
end
end
it 'generates the correct YML' do
expect(result[:action]).to eq('create')
expect(result[:content]).to eq(expected_yml)
end
end
end
# stubbing this method allows this spec file to use fast_spec_helper
def fast_auto_devops_stages
auto_devops_template = YAML.safe_load( File.read('lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml') )
auto_devops_template['stages']
end
end

View file

@ -0,0 +1,26 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'ConfigureSastIac' do
include GraphqlHelpers
let_it_be(:project) { create(:project, :test_repo) }
let(:variables) { { project_path: project.full_path } }
let(:mutation) { graphql_mutation(:configure_sast_iac, variables) }
let(:mutation_response) { graphql_mutation_response(:configureSastIac) }
context 'when authorized' do
let_it_be(:user) { project.owner }
it 'creates a branch with sast iac configured' do
post_graphql_mutation(mutation, current_user: user)
expect(response).to have_gitlab_http_status(:success)
expect(mutation_response['errors']).to be_empty
expect(mutation_response['branch']).not_to be_empty
expect(mutation_response['successPath']).not_to be_empty
end
end
end

View file

@ -0,0 +1,19 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Security::CiConfiguration::SastIacCreateService, :snowplow do
subject(:result) { described_class.new(project, user).execute }
let(:branch_name) { 'set-sast-iac-config-1' }
let(:snowplow_event) do
{
category: 'Security::CiConfiguration::SastIacCreateService',
action: 'create',
label: ''
}
end
include_examples 'services security ci configuration create service', true
end