summaryrefslogtreecommitdiff
path: root/app/models/environment.rb
diff options
context:
space:
mode:
Diffstat (limited to 'app/models/environment.rb')
-rw-r--r--app/models/environment.rb52
1 files changed, 23 insertions, 29 deletions
diff --git a/app/models/environment.rb b/app/models/environment.rb
index 68540ce0f5c..1950431446b 100644
--- a/app/models/environment.rb
+++ b/app/models/environment.rb
@@ -26,12 +26,11 @@ class Environment < ApplicationRecord
has_many :self_managed_prometheus_alert_events, inverse_of: :environment
has_many :alert_management_alerts, class_name: 'AlertManagement::Alert', inverse_of: :environment
+ # NOTE: If you preload multiple last deployments of environments, use Preloaders::Environments::DeploymentPreloader.
has_one :last_deployment, -> { success.ordered }, class_name: 'Deployment', inverse_of: :environment
- has_one :last_visible_deployment, -> { visible.distinct_on_environment }, inverse_of: :environment, class_name: 'Deployment'
- has_one :last_visible_deployable, through: :last_visible_deployment, source: 'deployable', source_type: 'CommitStatus', disable_joins: true
- has_one :last_visible_pipeline, through: :last_visible_deployable, source: 'pipeline', disable_joins: true
+ has_one :last_visible_deployment, -> { visible.order(id: :desc) }, inverse_of: :environment, class_name: 'Deployment'
- has_one :upcoming_deployment, -> { upcoming.distinct_on_environment }, class_name: 'Deployment', inverse_of: :environment
+ has_one :upcoming_deployment, -> { upcoming.order(id: :desc) }, class_name: 'Deployment', inverse_of: :environment
has_one :latest_opened_most_severe_alert, -> { order_severity_with_open_prometheus_alert }, class_name: 'AlertManagement::Alert', inverse_of: :environment
before_validation :generate_slug, if: ->(env) { env.slug.blank? }
@@ -56,8 +55,9 @@ class Environment < ApplicationRecord
validates :external_url,
length: { maximum: 255 },
- allow_nil: true,
- addressable_url: true
+ allow_nil: true
+
+ validate :safe_external_url
delegate :manual_actions, :other_manual_actions, to: :last_deployment, allow_nil: true
delegate :auto_rollback_enabled?, to: :project
@@ -215,28 +215,11 @@ class Environment < ApplicationRecord
deployable_id: last_deployment_pipeline.latest_builds.pluck(:id))
end
- # NOTE: Below assocation overrides is a workaround for issue https://gitlab.com/gitlab-org/gitlab/-/issues/339908
- # It helps to avoid cross joins with the CI database.
- # Caveat: It also overrides and losses the default AR caching mechanism.
- # Read - https://gitlab.com/gitlab-org/gitlab/-/merge_requests/68870#note_677227727
-
- # NOTE: Association Preloads does not use the overriden definitions below.
- # Association Preloads when preloading uses the original definitions from the relationships above.
- # https://github.com/rails/rails/blob/75ac626c4e21129d8296d4206a1960563cc3d4aa/activerecord/lib/active_record/associations/preloader.rb#L158
- # But after preloading, when they are called it is using the overriden methods below.
- # So we are checking for `association_cached?(:association_name)` in the overridden methods and calling `super` which inturn fetches the preloaded values.
-
- # Overriding association
def last_visible_deployable
- return super if association_cached?(:last_visible_deployable)
-
last_visible_deployment&.deployable
end
- # Overriding association
def last_visible_pipeline
- return super if association_cached?(:last_visible_pipeline)
-
last_visible_deployable&.pipeline
end
@@ -252,7 +235,6 @@ class Environment < ApplicationRecord
Gitlab::Ci::Variables::Collection.new
.append(key: 'CI_ENVIRONMENT_NAME', value: name)
.append(key: 'CI_ENVIRONMENT_SLUG', value: slug)
- .append(key: 'CI_ENVIRONMENT_TIER', value: tier)
end
def recently_updated_on_branch?(ref)
@@ -329,11 +311,7 @@ class Environment < ApplicationRecord
end
def last_deployment_group
- if ::Feature.enabled?(:batch_load_environment_last_deployment_group, project)
- Deployment.last_deployment_group_for_environment(self)
- else
- legacy_last_deployment_group
- end
+ Deployment.last_deployment_group_for_environment(self)
end
def reset_auto_stop
@@ -493,6 +471,22 @@ class Environment < ApplicationRecord
private
+ # We deliberately avoid using AddressableUrlValidator to allow users to update their environments even if they have
+ # misconfigured `environment:url` keyword. The external URL is presented as a clickable link on UI and not consumed
+ # in GitLab internally, thus we sanitize the URL before the persistence to make sure the rendered link is XSS safe.
+ # See https://gitlab.com/gitlab-org/gitlab/-/issues/337417
+ def safe_external_url
+ return unless self.external_url.present?
+
+ new_external_url = Addressable::URI.parse(self.external_url)
+
+ if Gitlab::Utils::SanitizeNodeLink::UNSAFE_PROTOCOLS.include?(new_external_url.normalized_scheme)
+ errors.add(:external_url, "#{new_external_url.normalized_scheme} scheme is not allowed")
+ end
+ rescue Addressable::URI::InvalidURIError
+ errors.add(:external_url, 'URI is invalid')
+ end
+
def rollout_status_available?
has_terminals?
end