PageRenderTime 44ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/ee/app/models/dast_site_profile.rb

https://gitlab.com/zillemarco/gitlab
Ruby | 132 lines | 92 code | 35 blank | 5 comment | 9 complexity | a3234e08402cc6061bceeb3eed135897 MD5 | raw file
  1. # frozen_string_literal: true
  2. class DastSiteProfile < ApplicationRecord
  3. include Sanitizable
  4. belongs_to :project
  5. belongs_to :dast_site
  6. has_many :secret_variables, class_name: 'Dast::SiteProfileSecretVariable'
  7. validates :excluded_urls, length: { maximum: 25 }
  8. validates :auth_url, addressable_url: true, length: { maximum: 1024 }, allow_nil: true
  9. validates :auth_username_field, :auth_password_field, :auth_username, :auth_submit_field, length: { maximum: 255 }
  10. validates :name, length: { maximum: 255 }, uniqueness: { scope: :project_id }, presence: true
  11. validates :project_id, :dast_site_id, presence: true
  12. validate :dast_site_project_id_fk
  13. validate :excluded_urls_contains_valid_urls
  14. validate :excluded_urls_contains_valid_strings
  15. scope :with_dast_site_and_validation, -> { includes(dast_site: :dast_site_validation) }
  16. scope :with_name, -> (name) { where(name: name) }
  17. scope :with_project_id, -> (project_id) { where(project_id: project_id) }
  18. scope :with_project, -> { includes(:project) }
  19. after_destroy :cleanup_dast_site
  20. enum target_type: { website: 0, api: 1 }
  21. enum scan_method: { site: 0, openapi: 1, har: 2, postman: 3 }, _prefix: true
  22. delegate :dast_site_validation, to: :dast_site, allow_nil: true
  23. sanitizes! :name
  24. before_save :ensure_scan_method
  25. def self.names(site_profile_ids)
  26. find(*site_profile_ids).pluck(:name)
  27. rescue ActiveRecord::RecordNotFound
  28. []
  29. end
  30. def ci_variables
  31. url = dast_site.url
  32. collection = ::Gitlab::Ci::Variables::Collection.new.tap do |variables|
  33. if target_type == 'website'
  34. variables.append(key: 'DAST_WEBSITE', value: url)
  35. else
  36. variables.append(key: 'DAST_API_OPENAPI', value: url)
  37. variables.append(key: 'DAST_API_HOST_OVERRIDE', value: URI(url).host)
  38. end
  39. variables.append(key: 'DAST_EXCLUDE_URLS', value: excluded_urls.join(',')) unless excluded_urls.empty?
  40. if auth_enabled
  41. variables.append(key: 'DAST_AUTH_URL', value: auth_url)
  42. variables.append(key: 'DAST_USERNAME', value: auth_username)
  43. variables.append(key: 'DAST_USERNAME_FIELD', value: auth_username_field)
  44. variables.append(key: 'DAST_PASSWORD_FIELD', value: auth_password_field)
  45. variables.append(key: 'DAST_SUBMIT_FIELD', value: auth_submit_field)
  46. end
  47. end
  48. collection.compact
  49. end
  50. def secret_ci_variables(user)
  51. collection = ::Gitlab::Ci::Variables::Collection.new
  52. return collection unless Ability.allowed?(user, :read_on_demand_dast_scan, self)
  53. collection.concat(secret_variables)
  54. end
  55. def status
  56. return DastSiteValidation::NONE_STATE unless dast_site_validation
  57. dast_site_validation.state
  58. end
  59. def referenced_in_security_policies
  60. return [] unless project.security_orchestration_policy_configuration.present?
  61. project.security_orchestration_policy_configuration.active_policy_names_with_dast_site_profile(name)
  62. end
  63. private
  64. def cleanup_dast_site
  65. dast_site.destroy if dast_site.dast_site_profiles.empty?
  66. end
  67. def dast_site_project_id_fk
  68. unless project_id == dast_site&.project_id
  69. errors.add(:project_id, _('does not match dast_site.project'))
  70. end
  71. end
  72. def excluded_urls_contains_valid_urls
  73. validate_excluded_urls_with(_("contains invalid URLs (%{urls})")) do |excluded_url|
  74. !Gitlab::UrlSanitizer.valid?(excluded_url)
  75. end
  76. end
  77. def excluded_urls_contains_valid_strings
  78. validate_excluded_urls_with(_("contains URLs that exceed the 1024 character limit (%{urls})")) do |excluded_url|
  79. excluded_url.length > 1024
  80. end
  81. end
  82. def validate_excluded_urls_with(message, &block)
  83. return if excluded_urls.blank?
  84. invalid = excluded_urls.select(&block)
  85. return if invalid.empty?
  86. errors.add(:excluded_urls, message % { urls: invalid.join(', ') })
  87. end
  88. # This callback is necessary to avoid discrepancy between the scan_method and target_type
  89. # before we enable the dast_api_scanner feature flag by default.
  90. # More context can be found here:
  91. # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78745#note_837953465
  92. def ensure_scan_method
  93. if api? && scan_method_site?
  94. self.scan_method = 'openapi'
  95. end
  96. end
  97. end