view_component 3.26.0 → 3.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7646c2f512d91517ac31ba0f2f039ef7c486ce4e5eec74d1fe5ca742a24f48b5
4
- data.tar.gz: 548a7e762a5e2b2970a79d7debba10747adffe62c1a946eb12eb689d0bbb04de
3
+ metadata.gz: ea3b7eaa6244e04ffa83e7c9d4aeafca18230bedcce0fb160b1001b0441270b0
4
+ data.tar.gz: aa605998a6e975f74c307faca61ec6d10b837cdee83c48fe2424e5b6421daf8a
5
5
  SHA512:
6
- metadata.gz: c880684d390ecb0c5a8b62ed329fe2883623bea9e61371666ba5e7aa1eca31f92af9d2e6558a728e195cd756a3390b4154cb024b1d613fd47a111f7b5452f60f
7
- data.tar.gz: be6a18ae9ed76ed5c2f71641e43b56fb32d67f8655f044d15f02e36da168539155e2de84e1ee6f2e1f195247832e1b6e11fc9d5bc75b1d02ec3cf92bfa8ce266
6
+ metadata.gz: a3ec820b42851cb62062972e1473ebb508798e0acd63bfff6e6fda1087c62776806c0199a9e11d6b13bd2914330bf0ad1cb899511c55f62af1538be7a9292a13
7
+ data.tar.gz: 748b43b70dec2efc5319bec3379f6b7cf115789f731e3a32af789c304644d20f14d62c9bc727ab88baa4a52dbeba806f8f403dcee1bcf1bc9a6df6ee73f0d412
data/docs/CHANGELOG.md CHANGED
@@ -10,6 +10,12 @@ nav_order: 6
10
10
 
11
11
  ## main
12
12
 
13
+ ## 3.27.0
14
+
15
+ * [Security] Fix incomplete remediation for CVE-2026-54497 (GHSA-8qw7-6phv-7q6p): reused ViewComponent instances could still leak `with_content` and `renders_one`/`renders_many` slot content from an earlier render into a later render because slot state and content set via `with_content` are populated by the caller before `render_in` runs and were not cleared by the previous per-render reset. Reinstate the `ViewComponent::ReusedInstanceError` guard that raises when a component instance is rendered more than once. Rebuild collection child components per render and dup collection spacer components before each render so that legitimate re-rendering of `Collection`/spacer objects continues to work.
16
+
17
+ *Yazan Balawneh, Cystack.ps*
18
+
13
19
  ## 3.26.0
14
20
 
15
21
  * Fix rendering partials from components rendered as a collection when the original view context is explicitly stashed as `nil`.
@@ -83,6 +83,7 @@ module ViewComponent
83
83
  def render_in(view_context, **options, &block)
84
84
  self.class.compile(raise_errors: true)
85
85
 
86
+ __vc_check_reused_instance!
86
87
  __vc_reset_render_state!
87
88
 
88
89
  @view_context = view_context
@@ -137,6 +138,7 @@ module ViewComponent
137
138
  end
138
139
  ensure
139
140
  @current_template = old_current_template
141
+ @__vc_rendered = true
140
142
  end
141
143
 
142
144
  # Subclass components that call `super` inside their template code will cause a
@@ -410,7 +412,9 @@ module ViewComponent
410
412
  # state from a previous render. Slot state (`@__vc_set_slots`,
411
413
  # `@__vc_content_set_by_with_content`) is intentionally preserved because it
412
414
  # is populated by callers _before_ `render_in` runs (e.g. via `with_*`
413
- # slot setters or `with_content`).
415
+ # slot setters or `with_content`); reuse of an instance that has slot or
416
+ # `with_content` state is guarded against separately by
417
+ # `__vc_check_reused_instance!`.
414
418
  def __vc_reset_render_state!
415
419
  %i[
416
420
  @__vc_controller
@@ -422,6 +426,17 @@ module ViewComponent
422
426
  end
423
427
  end
424
428
 
429
+ # Raises when a component instance is rendered more than once.
430
+ # Reusing a component instance across renders can leak request-scoped state
431
+ # (controller, helpers, request, view_flow, slot content, `with_content`)
432
+ # from an earlier render into a later one. See
433
+ # `ViewComponent::ReusedInstanceError` and GHSA-8qw7-6phv-7q6p.
434
+ def __vc_check_reused_instance!
435
+ return unless defined?(@__vc_rendered) && @__vc_rendered
436
+
437
+ raise ReusedInstanceError.new(self.class.name)
438
+ end
439
+
425
440
  # Configuration for generators.
426
441
  #
427
442
  # All options under this namespace default to `false` unless otherwise
@@ -72,13 +72,18 @@ module ViewComponent
72
72
  @options.merge(item_options)
73
73
  end
74
74
 
75
+ # Render the spacer through a fresh `dup` so a collection rendered multiple
76
+ # times does not reuse (and trip the single-render guard on) the spacer
77
+ # instance passed by the caller.
75
78
  def rendered_spacer(view_context)
76
- if @spacer_component
77
- @spacer_component.set_original_view_context(__vc_original_view_context) if @spacer_component.respond_to?(:set_original_view_context)
78
- @spacer_component.render_in(view_context)
79
- else
80
- ""
79
+ return "" unless @spacer_component
80
+
81
+ spacer = @spacer_component.dup
82
+ if spacer.instance_variable_defined?(:@__vc_rendered)
83
+ spacer.remove_instance_variable(:@__vc_rendered)
81
84
  end
85
+ spacer.set_original_view_context(__vc_original_view_context) if spacer.respond_to?(:set_original_view_context)
86
+ spacer.render_in(view_context)
82
87
  end
83
88
  end
84
89
  end
@@ -175,6 +175,19 @@ module ViewComponent
175
175
  "To fix this issue, pass a value."
176
176
  end
177
177
 
178
+ class ReusedInstanceError < StandardError
179
+ MESSAGE =
180
+ "ViewComponent instances are single-use; a COMPONENT instance was rendered more than once.\n\n" \
181
+ "Reusing a component instance across renders can leak request-scoped state " \
182
+ "(controller, helpers, request, view_flow, slot content, `with_content`) from an earlier render " \
183
+ "into a later one, which has security and correctness implications (GHSA-8qw7-6phv-7q6p).\n\n" \
184
+ "To fix this issue, create a new component instance per render."
185
+
186
+ def initialize(klass_name)
187
+ super(MESSAGE.gsub("COMPONENT", klass_name.to_s))
188
+ end
189
+ end
190
+
178
191
  class TranslateCalledBeforeRenderError < BaseError
179
192
  MESSAGE =
180
193
  "`#translate` can't be used before rendering as it depends " \
@@ -3,7 +3,7 @@
3
3
  module ViewComponent
4
4
  module VERSION
5
5
  MAJOR = 3
6
- MINOR = 26
6
+ MINOR = 27
7
7
  PATCH = 0
8
8
  PRE = nil
9
9
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: view_component
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.26.0
4
+ version: 3.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ViewComponent Team