Commit 1db05df7 authored by Philip Cunningham's avatar Philip Cunningham Committed by Mark Chao

Use Build relations for DAST on-demand variables

parent 625dd03e
# frozen_string_literal: true
class AssociateExistingDastBuildsWithVariables < ActiveRecord::Migration[6.1]
disable_ddl_transaction!
class Profile < ApplicationRecord
self.table_name = 'dast_profiles'
self.inheritance_column = :_type_disabled
end
class ProfilesPipeline < ApplicationRecord
include EachBatch
self.table_name = 'dast_profiles_pipelines'
self.inheritance_column = :_type_disabled
belongs_to :profile, foreign_key: :dast_profile_id
end
class Build < ApplicationRecord
self.table_name = 'ci_builds'
self.inheritance_column = :_type_disabled
default_scope { where(name: :dast, stage: :dast) } # rubocop:disable Cop/DefaultScope
end
class SiteProfilesBuild < ApplicationRecord
self.table_name = 'dast_site_profiles_builds'
self.inheritance_column = :_type_disabled
end
BATCH_SIZE = 300
def up
process_batch do |batch|
bulk_inserts = []
grouped_builds = fetch_builds(batch).group_by(&:commit_id)
batch.includes(:profile).each do |profile_pipeline|
builds = grouped_builds[profile_pipeline.ci_pipeline_id]
next if builds.blank?
builds.each do |build|
bulk_inserts.push(dast_site_profile_id: profile_pipeline.profile.dast_site_profile_id, ci_build_id: build.id)
end
end
SiteProfilesBuild.insert_all(bulk_inserts, unique_by: :ci_build_id)
end
end
def down
process_batch do |batch|
builds = fetch_builds(batch)
SiteProfilesBuild
.where(ci_build_id: builds)
.delete_all
end
end
private
def fetch_builds(batch)
# pluck necessary to support ci table decomposition
# https://gitlab.com/groups/gitlab-org/-/epics/6289
Build.where(commit_id: batch.pluck(:ci_pipeline_id))
end
def process_batch
ProfilesPipeline.each_batch(of: BATCH_SIZE, column: :ci_pipeline_id) do |batch|
yield(batch)
end
end
end
4f20581b0d16157fbe984383417f0463d7e52252569480796aa3c73abf19c95f
\ No newline at end of file
# frozen_string_literal: true
module Dast
class SiteProfilesPipeline < ApplicationRecord
extend SuppressCompositePrimaryKeyWarning
self.table_name = 'dast_site_profiles_pipelines'
belongs_to :ci_pipeline, class_name: 'Ci::Pipeline', optional: false
belongs_to :dast_site_profile, class_name: 'DastSiteProfile', optional: false
validates :ci_pipeline_id, :dast_site_profile_id, presence: true
validate :project_ids_match
private
def project_ids_match
return if ci_pipeline.nil? || dast_site_profile.nil?
unless ci_pipeline.project_id == dast_site_profile.project_id
errors.add(:ci_pipeline_id, 'project_id must match dast_site_profile.project_id')
end
end
end
end
......@@ -62,7 +62,6 @@ module EE
def variables
strong_memoize(:variables) do
super.tap do |collection|
collection.concat(dast_on_demand_variables)
collection.concat(dast_configuration_variables)
end
end
......@@ -195,19 +194,6 @@ module EE
end
end
def dast_on_demand_variables
::Gitlab::Ci::Variables::Collection.new.tap do |collection|
break collection unless pipeline.triggered_for_ondemand_dast_scan?
# Subject to change. Please see gitlab-org/gitlab#330950 for more info.
profile = pipeline.dast_profile || pipeline.dast_site_profile
break collection unless profile
collection.concat(profile.secret_ci_variables(pipeline.user))
end
end
def dast_configuration_variables
::Gitlab::Ci::Variables::Collection.new.tap do |collection|
break collection unless (dast_configuration = options[:dast_configuration])
......
......@@ -23,10 +23,6 @@ module EE
has_one :dast_profiles_pipeline, class_name: 'Dast::ProfilesPipeline', foreign_key: :ci_pipeline_id
has_one :dast_profile, class_name: 'Dast::Profile', through: :dast_profiles_pipeline
# Temporary location to be moved in the future. Please see gitlab-org/gitlab#330950 for more info.
has_one :dast_site_profiles_pipeline, class_name: 'Dast::SiteProfilesPipeline', foreign_key: :ci_pipeline_id
has_one :dast_site_profile, class_name: 'DastSiteProfile', through: :dast_site_profiles_pipeline
has_one :source_project, class_name: 'Ci::Sources::Project', foreign_key: :pipeline_id
# Legacy way to fetch security reports based on job name. This has been replaced by the reports feature.
......
......@@ -13,8 +13,6 @@ module AppSec
ServiceResponse.success(
payload: {
dast_profile: dast_profile,
dast_site_profile: dast_site_profile,
dast_scanner_profile: dast_scanner_profile,
branch: branch,
ci_configuration: ci_configuration
}
......@@ -45,16 +43,12 @@ module AppSec
{
'stages' => ['dast'],
'include' => [{ 'template' => 'DAST-On-Demand-Scan.gitlab-ci.yml' }],
'variables' => ci_variables.to_hash.to_hash # Collection#to_hash returns HashWithIndifferentAccess which does not serialise correctly
'dast' => {
'dast_configuration' => { 'site_profile' => dast_site_profile.name, 'scanner_profile' => dast_scanner_profile&.name }.compact
}
}.to_yaml
end
def ci_variables
dast_site_profile.ci_variables.tap do |collection|
collection.concat(dast_scanner_profile.ci_variables) if dast_scanner_profile
end
end
def dast_profile
strong_memoize(:dast_profile) do
params[:dast_profile]
......
......@@ -8,12 +8,7 @@ module Ci
service = Ci::CreatePipelineService.new(project, current_user, ref: branch)
response = service.execute(:ondemand_dast_scan, content: ci_configuration) do |pipeline|
if dast_profile
pipeline.dast_profile = dast_profile
else
# Subject to change. Please see gitlab-org/gitlab#330950 for more info.
pipeline.dast_site_profile = dast_site_profile
end
pipeline.dast_profile = dast_profile
end
pipeline = response.payload
......
......@@ -34,8 +34,9 @@ module Security
ci_configuration = YAML.safe_load(result.payload[:ci_configuration])
dast_on_demand_template[:dast].deep_merge(
'variables' => dast_on_demand_template[:variables].deep_merge(ci_configuration['variables']),
'stage' => 'test'
'stage' => 'dast',
'variables' => dast_on_demand_template[:variables].merge(dast_on_demand_template[:dast][:variables]),
'dast_configuration' => ci_configuration['dast']['dast_configuration']
)
end
......
# frozen_string_literal: true
FactoryBot.define do
factory :dast_site_profiles_pipeline, class: 'Dast::SiteProfilesPipeline' do
dast_site_profile
ci_pipeline { association :ci_pipeline, project: dast_site_profile.project }
end
end
......@@ -78,10 +78,8 @@ RSpec.describe Mutations::DastOnDemandScans::Create do
it 'passes additional arguments to the underlying service object' do
args = hash_including(
branch: project.default_branch,
dast_profile: nil,
dast_site_profile: dast_site_profile,
dast_scanner_profile: dast_scanner_profile,
branch: project.default_branch,
ci_configuration: kind_of(String)
)
......
......@@ -126,24 +126,20 @@ RSpec.describe Gitlab::Ci::Config do
script: ["echo 'test'"]
},
'dast-on-demand-0': {
stage: 'test',
stage: 'dast',
image: { name: '$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION' },
variables: {
DAST_AUTH_URL: dast_site_profile.auth_url,
DAST_VERSION: 2,
SECURE_ANALYZERS_PREFIX: secure_analyzers_prefix,
DAST_WEBSITE: dast_site_profile.dast_site.url,
DAST_FULL_SCAN_ENABLED: 'false',
DAST_USE_AJAX_SPIDER: 'false',
DAST_DEBUG: 'false',
DAST_USERNAME: dast_site_profile.auth_username,
DAST_EXCLUDE_URLS: dast_site_profile.excluded_urls.join(','),
DAST_USERNAME_FIELD: 'session[username]',
DAST_PASSWORD_FIELD: 'session[password]'
},
GIT_STRATEGY: 'none'
},
allow_failure: true,
script: ['/analyze'],
artifacts: { reports: { dast: 'gl-dast-report.json' } }
artifacts: { reports: { dast: 'gl-dast-report.json' } },
dast_configuration: {
site_profile: dast_site_profile.name,
scanner_profile: dast_scanner_profile.name
}
}
}
end
......
......@@ -126,22 +126,14 @@ RSpec.describe Gitlab::Ci::Config::SecurityOrchestrationPolicies::Processor do
{
image: 'ruby:3.0.1',
'dast-on-demand-0': {
stage: 'test',
stage: 'dast',
image: {
name: '$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION'
},
variables: {
DAST_AUTH_URL: dast_site_profile.auth_url,
DAST_VERSION: 2,
SECURE_ANALYZERS_PREFIX: secure_analyzers_prefix,
DAST_WEBSITE: dast_site_profile.dast_site.url,
DAST_FULL_SCAN_ENABLED: 'false',
DAST_USE_AJAX_SPIDER: 'false',
DAST_DEBUG: 'false',
DAST_USERNAME: dast_site_profile.auth_username,
DAST_EXCLUDE_URLS: dast_site_profile.excluded_urls.join(','),
DAST_USERNAME_FIELD: 'session[username]',
DAST_PASSWORD_FIELD: 'session[password]'
GIT_STRATEGY: 'none'
},
allow_failure: true,
script: ['/analyze'],
......@@ -149,6 +141,10 @@ RSpec.describe Gitlab::Ci::Config::SecurityOrchestrationPolicies::Processor do
reports: {
dast: 'gl-dast-report.json'
}
},
dast_configuration: {
site_profile: dast_site_profile.name,
scanner_profile: dast_scanner_profile.name
}
}
}
......
......@@ -138,7 +138,6 @@ RSpec.describe Ci::Build do
let_it_be(:user) { create(:user, developer_projects: [project]) }
let_it_be(:dast_site_profile) { create(:dast_site_profile, project: project) }
let_it_be(:dast_scanner_profile) { create(:dast_scanner_profile, project: project) }
let_it_be(:dast_profile) { create(:dast_profile, project: project, dast_site_profile: dast_site_profile, dast_scanner_profile: dast_scanner_profile) }
let_it_be(:dast_site_profile_secret_variable) { create(:dast_site_profile_secret_variable, key: 'DAST_PASSWORD_BASE64', dast_site_profile: dast_site_profile) }
let_it_be(:options) { { dast_configuration: { site_profile: dast_site_profile.name, scanner_profile: dast_scanner_profile.name } } }
......@@ -162,27 +161,13 @@ RSpec.describe Ci::Build do
let(:pipeline) { create(:ci_pipeline, project: project) }
let(:job) { create(:ci_build, :running, pipeline: pipeline, dast_site_profile: dast_site_profile, user: user, options: options) }
context 'when feature is enabled' do
it_behaves_like 'it includes variables' do
let(:expected_variables) { dast_site_profile.ci_variables }
end
context 'when user has permission' do
it_behaves_like 'it includes variables' do
let(:expected_variables) { dast_site_profile.secret_ci_variables(user) }
end
end
context 'when user does not have permission' do
let_it_be(:user) { create(:user) }
before do
project.add_guest(user)
end
it_behaves_like 'it includes variables' do
let(:expected_variables) { dast_site_profile.ci_variables }
end
it_behaves_like 'it excludes variables' do
let(:expected_variables) { dast_site_profile.secret_ci_variables(user) }
end
context 'when user has permission' do
it_behaves_like 'it includes variables' do
let(:expected_variables) { dast_site_profile.secret_ci_variables(user) }
end
end
end
......@@ -191,10 +176,8 @@ RSpec.describe Ci::Build do
let(:pipeline) { create(:ci_pipeline, project: project, user: user) }
let(:job) { create(:ci_build, :running, pipeline: pipeline, dast_scanner_profile: dast_scanner_profile, options: options) }
context 'when feature is enabled' do
it_behaves_like 'it includes variables' do
let(:expected_variables) { dast_scanner_profile.ci_variables }
end
it_behaves_like 'it includes variables' do
let(:expected_variables) { dast_scanner_profile.ci_variables }
end
end
......@@ -242,56 +225,6 @@ RSpec.describe Ci::Build do
end
end
end
context 'when there is a dast_profile associated with the pipeline' do
let(:pipeline) { create(:ci_pipeline, pipeline_params.merge!(project: project, dast_profile: dast_profile, user: user) ) }
let(:key) { dast_site_profile_secret_variable.key }
let(:value) { dast_site_profile_secret_variable.value }
shared_examples 'a record with no associated dast variables' do
it 'does not include variables associated with the profile' do
keys = subject.to_runner_variables.map { |var| var[:key] }
expect(keys).not_to include(key)
end
end
context 'when the on-demand pipeline is incorrectly configured' do
it_behaves_like 'a record with no associated dast variables' do
let(:pipeline_params) { { config_source: :parameter_source } }
end
it_behaves_like 'a record with no associated dast variables' do
let(:pipeline_params) { { source: :ondemand_dast_scan } }
end
end
context 'when the dast on-demand pipeline is correctly configured' do
let(:pipeline_params) { { source: :ondemand_dast_scan, config_source: :parameter_source } }
it 'includes variables associated with the profile' do
expect(subject.to_runner_variables).to include(key: key, value: value, public: false, masked: true)
end
context 'when user cannot read secrets' do
before do
stub_licensed_features(security_on_demand_scans: false)
end
it 'does not include variables associated with the profile' do
expect(subject.to_runner_variables).not_to include(key: key, value: value, public: false, masked: true)
end
end
context 'when there is no user associated with the pipeline' do
let_it_be(:user) { nil }
it 'does not include variables associated with the profile' do
expect(subject.to_runner_variables).not_to include(key: key, value: value, public: false, masked: true)
end
end
end
end
end
end
......
......@@ -20,8 +20,6 @@ RSpec.describe Ci::Pipeline do
it { is_expected.to have_many(:vulnerabilities_finding_pipelines).class_name('Vulnerabilities::FindingPipeline') }
it { is_expected.to have_one(:dast_profiles_pipeline).class_name('Dast::ProfilesPipeline').with_foreign_key(:ci_pipeline_id) }
it { is_expected.to have_one(:dast_profile).class_name('Dast::Profile').through(:dast_profiles_pipeline) }
it { is_expected.to have_one(:dast_site_profiles_pipeline).class_name('Dast::SiteProfilesPipeline').with_foreign_key(:ci_pipeline_id) }
it { is_expected.to have_one(:dast_site_profile).class_name('DastSiteProfile').through(:dast_site_profiles_pipeline) }
end
describe '.failure_reasons' do
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Dast::SiteProfilesPipeline, type: :model do
subject { create(:dast_site_profiles_pipeline) }
describe 'associations' do
it { is_expected.to belong_to(:ci_pipeline).class_name('Ci::Pipeline').required }
it { is_expected.to belong_to(:dast_site_profile).class_name('DastSiteProfile').required }
end
describe 'validations' do
it { is_expected.to be_valid }
it { is_expected.to validate_presence_of(:ci_pipeline_id) }
it { is_expected.to validate_presence_of(:dast_site_profile_id) }
context 'when the ci_pipeline.project_id and dast_site_profile.project_id do not match' do
let(:pipeline) { build(:ci_pipeline, project_id: 1) }
let(:site_profile) { build(:dast_site_profile, project_id: 2) }
subject { build(:dast_site_profiles_pipeline, ci_pipeline: pipeline, dast_site_profile: site_profile) }
it 'is not valid', :aggregate_failures do
expect(subject).not_to be_valid
expect(subject.errors.full_messages).to include('Ci pipeline project_id must match dast_site_profile.project_id')
end
end
end
end
......@@ -29,18 +29,10 @@ RSpec.describe AppSec::Dast::ScanConfigs::BuildService do
- dast
include:
- template: DAST-On-Demand-Scan.gitlab-ci.yml
variables:
DAST_WEBSITE: #{dast_website}
DAST_EXCLUDE_URLS: #{dast_exclude_urls}
DAST_AUTH_URL: #{dast_auth_url}
DAST_USERNAME: #{dast_username}
DAST_USERNAME_FIELD: #{dast_username_field}
DAST_PASSWORD_FIELD: #{dast_password_field}
DAST_SPIDER_MINS: '#{dast_spider_mins}'
DAST_TARGET_AVAILABILITY_TIMEOUT: '#{dast_target_availability_timeout}'
DAST_FULL_SCAN_ENABLED: '#{dast_full_scan_enabled}'
DAST_USE_AJAX_SPIDER: '#{dast_use_ajax_spider}'
DAST_DEBUG: '#{dast_debug}'
dast:
dast_configuration:
site_profile: #{dast_site_profile.name}
scanner_profile: #{dast_scanner_profile.name}
YAML
end
......@@ -50,11 +42,9 @@ RSpec.describe AppSec::Dast::ScanConfigs::BuildService do
context 'when a dast_profile is provided' do
let(:params) { { dast_profile: dast_profile } }
it 'returns a dast_profile, dast_site_profile, dast_scanner_profile, branch and YAML configuration' do
it 'returns a dast_profile, branch and YAML configuration' do
expected_payload = {
dast_profile: dast_profile,
dast_site_profile: dast_site_profile,
dast_scanner_profile: dast_scanner_profile,
branch: dast_profile.branch_name,
ci_configuration: expected_yaml_configuration
}
......@@ -64,20 +54,22 @@ RSpec.describe AppSec::Dast::ScanConfigs::BuildService do
end
context 'when a dast_site_profile is provided' do
context 'when a dast_scanner_profile is provided' do
let(:params) { { dast_site_profile: dast_site_profile, dast_scanner_profile: dast_scanner_profile } }
it 'returns a dast_site_profile, dast_scanner_profile, branch and YAML configuration' do
shared_examples 'a payload without a dast_profile' do
it 'returns a branch and YAML configuration' do
expected_payload = {
dast_profile: nil,
dast_site_profile: dast_site_profile,
dast_scanner_profile: dast_scanner_profile,
branch: project.default_branch,
branch: dast_profile.branch_name,
ci_configuration: expected_yaml_configuration
}
expect(subject.payload).to eq(expected_payload)
end
end
context 'when a dast_scanner_profile is provided' do
let(:params) { { dast_site_profile: dast_site_profile, dast_scanner_profile: dast_scanner_profile } }
it_behaves_like 'a payload without a dast_profile'
context 'when the target is not validated and an active scan is requested' do
let_it_be(:active_dast_scanner_profile) { create(:dast_scanner_profile, project: project, scan_type: 'active') }
......@@ -101,27 +93,13 @@ RSpec.describe AppSec::Dast::ScanConfigs::BuildService do
- dast
include:
- template: DAST-On-Demand-Scan.gitlab-ci.yml
variables:
DAST_WEBSITE: #{dast_website}
DAST_EXCLUDE_URLS: #{dast_exclude_urls}
DAST_AUTH_URL: #{dast_auth_url}
DAST_USERNAME: #{dast_username}
DAST_USERNAME_FIELD: #{dast_username_field}
DAST_PASSWORD_FIELD: #{dast_password_field}
dast:
dast_configuration:
site_profile: #{dast_site_profile.name}
YAML
end
it 'returns a dast_site_profile, branch and YAML configuration' do
expected_payload = {
dast_profile: nil,
dast_site_profile: dast_site_profile,
dast_scanner_profile: nil,
branch: project.default_branch,
ci_configuration: expected_yaml_configuration
}
expect(subject.payload).to eq(expected_payload)
end
it_behaves_like 'a payload without a dast_profile'
end
end
......
......@@ -20,11 +20,7 @@ RSpec.describe Ci::RunDastScanService do
config_result = AppSec::Dast::ScanConfigs::BuildService.new(
container: project,
current_user: user,
params: {
branch: project.default_branch,
dast_profile: dast_profile,
dast_site_profile: dast_site_profile
}
params: { branch: project.default_branch, dast_profile: dast_profile }
).execute
described_class.new(project, user).execute(**config_result.payload)
......@@ -84,6 +80,7 @@ RSpec.describe Ci::RunDastScanService do
it 'creates a build with appropriate options' do
build = pipeline.builds.first
expected_options = {
image: {
name: '$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION'
......@@ -95,8 +92,10 @@ RSpec.describe Ci::RunDastScanService do
reports: {
dast: ['gl-dast-report.json']
}
}
},
dast_configuration: { site_profile: dast_site_profile.name, scanner_profile: dast_scanner_profile.name }
}
expect(build.options).to eq(expected_options)
end
......@@ -107,81 +106,77 @@ RSpec.describe Ci::RunDastScanService do
{
key: 'DAST_AUTH_URL',
value: dast_site_profile.auth_url,
public: true
public: true,
masked: false
}, {
key: 'DAST_DEBUG',
value: String(dast_scanner_profile.show_debug_messages?),
public: true
public: true,
masked: false
}, {
key: 'DAST_EXCLUDE_URLS',
value: dast_site_profile.excluded_urls.join(','),
public: true
public: true,
masked: false
}, {
key: 'DAST_FULL_SCAN_ENABLED',
value: String(dast_scanner_profile.full_scan_enabled?),
public: true
public: true,
masked: false
}, {
key: 'DAST_PASSWORD_FIELD',
value: dast_site_profile.auth_password_field,
public: true
public: true,
masked: false
}, {
key: 'DAST_SPIDER_MINS',
value: String(dast_scanner_profile.spider_timeout),
public: true
public: true,
masked: false
}, {
key: 'DAST_TARGET_AVAILABILITY_TIMEOUT',
value: String(dast_scanner_profile.target_timeout),
public: true
public: true,
masked: false
}, {
key: 'DAST_USERNAME',
value: dast_site_profile.auth_username,
public: true
public: true,
masked: false
}, {
key: 'DAST_USERNAME_FIELD',
value: dast_site_profile.auth_username_field,
public: true
public: true,
masked: false
}, {
key: 'DAST_USE_AJAX_SPIDER',
value: String(dast_scanner_profile.use_ajax_spider?),
public: true
public: true,
masked: false
}, {
key: 'DAST_VERSION',
value: '2',
public: true
public: true,
masked: false
}, {
key: 'DAST_WEBSITE',
value: dast_site_profile.dast_site.url,
public: true
public: true,
masked: false
}, {
key: 'GIT_STRATEGY',
value: 'none',
public: true
public: true,
masked: false
}, {
key: 'SECURE_ANALYZERS_PREFIX',
value: secure_analyzers_prefix,
public: true
public: true,
masked: false
}
]
expect(build.yaml_variables).to contain_exactly(*expected_variables)
end
context 'when the dast_profile and dast_site_profile are provided' do
it 'associates the dast_profile with the pipeline' do
expect(pipeline.dast_profile).to eq(dast_profile)
end
it 'does associate the dast_site_profile with the pipeline' do
expect(pipeline.dast_site_profile).to be_nil
end
end
context 'when the dast_site_profile is provided' do
let(:dast_profile) { nil }
it 'associates the dast_site_profile with the pipeline' do
expect(pipeline.dast_site_profile).to eq(dast_site_profile)
end
expect(build.variables.to_runner_variables).to include(*expected_variables)
end
context 'when the pipeline fails to save' do
......
......@@ -64,9 +64,8 @@ RSpec.describe DastOnDemandScans::CreateService do
it_behaves_like 'a service that calls Ci::RunDastScanService' do
let(:expected_params) do
hash_including(
dast_profile: nil,
branch: project.default_branch,
dast_site_profile: dast_site_profile,
dast_scanner_profile: dast_scanner_profile,
ci_configuration: kind_of(String)
)
end
......
......@@ -59,24 +59,17 @@ RSpec.describe Security::SecurityOrchestrationPolicies::OnDemandScanPipelineConf
it 'returns prepared CI configuration with DAST On-Demand scans defined' do
expected_configuration = {
'dast-on-demand-0': {
stage: 'test',
stage: 'dast',
image: { name: '$SECURE_ANALYZERS_PREFIX/dast:$DAST_VERSION' },
variables: {
DAST_AUTH_URL: site_profile.auth_url,
DAST_DEBUG: 'false',
DAST_EXCLUDE_URLS: site_profile.excluded_urls.join(','),
DAST_FULL_SCAN_ENABLED: 'false',
DAST_PASSWORD_FIELD: site_profile.auth_password_field,
DAST_USERNAME: site_profile.auth_username,
DAST_USERNAME_FIELD: site_profile.auth_username_field,
DAST_USE_AJAX_SPIDER: 'false',
DAST_VERSION: 2,
DAST_WEBSITE: site_profile.dast_site.url,
SECURE_ANALYZERS_PREFIX: secure_analyzers_prefix
SECURE_ANALYZERS_PREFIX: secure_analyzers_prefix,
GIT_STRATEGY: 'none'
},
allow_failure: true,
script: ['/analyze'],
artifacts: { reports: { dast: 'gl-dast-report.json' } }
artifacts: { reports: { dast: 'gl-dast-report.json' } },
dast_configuration: { site_profile: site_profile.name, scanner_profile: scanner_profile.name }
},
'dast-on-demand-1': {
script: 'echo "Error during On-Demand Scan execution: Dast site profile was not provided" && false',
......
# frozen_string_literal: true
require 'spec_helper'
require Rails.root.join('db', 'migrate', '20210629031900_associate_existing_dast_builds_with_variables.rb')
RSpec.describe AssociateExistingDastBuildsWithVariables do
subject(:migration) { described_class.new }
let_it_be(:namespaces_table) { table(:namespaces) }
let_it_be(:projects_table) { table(:projects) }
let_it_be(:ci_pipelines_table) { table(:ci_pipelines) }
let_it_be(:ci_builds_table) { table(:ci_builds) }
let_it_be(:dast_sites_table) { table(:dast_sites) }
let_it_be(:dast_site_profiles_table) { table(:dast_site_profiles) }
let_it_be(:dast_scanner_profiles_table) { table(:dast_scanner_profiles) }
let_it_be(:dast_site_profiles_builds_table) { table(:dast_site_profiles_builds) }
let_it_be(:dast_profiles_table) { table(:dast_profiles) }
let_it_be(:dast_profiles_pipelines_table) { table(:dast_profiles_pipelines) }
let!(:group) { namespaces_table.create!(type: 'Group', name: 'group', path: 'group') }
let!(:project) { projects_table.create!(name: 'project', path: 'project', namespace_id: group.id) }
let!(:pipeline_0) { ci_pipelines_table.create!(project_id: project.id, source: 13) }
let!(:pipeline_1) { ci_pipelines_table.create!(project_id: project.id, source: 13) }
let!(:build_0) { ci_builds_table.create!(project_id: project.id, commit_id: pipeline_0.id, name: :dast, stage: :dast) }
let!(:build_1) { ci_builds_table.create!(project_id: project.id, commit_id: pipeline_0.id, name: :dast, stage: :dast) }
let!(:build_2) { ci_builds_table.create!(project_id: project.id, commit_id: pipeline_1.id, name: :dast, stage: :dast) }
let!(:build_3) { ci_builds_table.create!(project_id: project.id, commit_id: pipeline_1.id, name: :dast) }
let!(:build_4) { ci_builds_table.create!(project_id: project.id, commit_id: pipeline_1.id, stage: :dast) }
let!(:dast_site) { dast_sites_table.create!(project_id: project.id, url: generate(:url)) }
let!(:dast_site_profile) { dast_site_profiles_table.create!(project_id: project.id, dast_site_id: dast_site.id, name: SecureRandom.hex) }
let!(:dast_scanner_profile) { dast_scanner_profiles_table.create!(project_id: project.id, name: SecureRandom.hex) }
let!(:dast_profile) do
dast_profiles_table.create!(
project_id: project.id,
dast_site_profile_id: dast_site_profile.id,
dast_scanner_profile_id: dast_scanner_profile.id,
name: SecureRandom.hex,
description: SecureRandom.hex
)
end
let!(:dast_profiles_pipeline_0) { dast_profiles_pipelines_table.create!(dast_profile_id: dast_profile.id, ci_pipeline_id: pipeline_0.id) }
let!(:dast_profiles_pipeline_1) { dast_profiles_pipelines_table.create!(dast_profile_id: dast_profile.id, ci_pipeline_id: pipeline_1.id) }
context 'when there are ci_pipelines with associated dast_profiles' do
describe 'migration up' do
it 'adds association of dast_site_profiles to ci_builds', :aggregate_failures do
expect(dast_site_profiles_builds_table.all).to be_empty
migration.up
expected_results = [
[dast_site_profile.id, build_0.id],
[dast_site_profile.id, build_1.id],
[dast_site_profile.id, build_2.id]
]
expect(dast_site_profiles_builds_table.all.map { |assoc| [assoc.dast_site_profile_id, assoc.ci_build_id] }).to contain_exactly(*expected_results)
end
end
end
describe 'migration down' do
it 'deletes all records in the dast_site_profiles_builds table', :aggregate_failures do
expect(dast_site_profiles_builds_table.all).to be_empty
migration.up
migration.down
expect(dast_site_profiles_builds_table.all).to be_empty
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment