inline_forms 8.1.55 → 8.1.57

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.
Files changed (37) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +92 -0
  3. data/app/controllers/concerns/file_slots_concern.rb +6 -0
  4. data/app/controllers/inline_forms_controller.rb +88 -30
  5. data/app/helpers/inline_forms_file_trash_helper.rb +10 -0
  6. data/app/models/concerns/inline_forms/stored_files.rb +5 -1
  7. data/app/models/inline_forms/trashed_file.rb +16 -2
  8. data/app/views/devise/sessions/_form.html.erb +2 -2
  9. data/app/views/inline_forms/_list.html.erb +24 -7
  10. data/app/views/inline_forms/_versions.html.erb +1 -1
  11. data/app/views/inline_forms/_versions_file_entry.html.erb +1 -1
  12. data/app/views/inline_forms/_versions_list.html.erb +14 -12
  13. data/app/views/layouts/application.html.erb +10 -3
  14. data/app/views/layouts/devise.html.erb +1 -1
  15. data/app/views/layouts/inline_forms.html.erb +9 -2
  16. data/lib/inline_forms/form_elements/file_field_helper.rb +3 -1
  17. data/lib/inline_forms/form_elements/info_list_helper.rb +3 -1
  18. data/lib/inline_forms/gem_files.rb +3 -2
  19. data/lib/inline_forms/version.rb +1 -1
  20. data/lib/locales/inline_forms.en.yml +22 -1
  21. data/lib/locales/inline_forms.nl.yml +25 -1
  22. data/test/dummy/app/controllers/application_controller.rb +5 -2
  23. data/test/dummy/app/controllers/daily_reports_controller.rb +4 -0
  24. data/test/dummy/app/models/daily_report.rb +21 -0
  25. data/test/dummy/app/models/machine.rb +1 -0
  26. data/test/dummy/config/application.rb +11 -0
  27. data/test/dummy/config/routes.rb +5 -0
  28. data/test/gem_package_modes_test.rb +1 -1
  29. data/test/integration/csp_nonce_test.rb +50 -0
  30. data/test/integration/file_slots_test.rb +91 -0
  31. data/test/integration/html_refusal_test.rb +152 -0
  32. data/test/integration/list_params_test.rb +200 -0
  33. data/test/integration/locale_test.rb +113 -0
  34. data/test/integration/presentation_escaping_test.rb +80 -0
  35. data/test/integration_test_helper.rb +11 -0
  36. metadata +15 -2
  37. data/app/views/inline_forms/_flash.html.erb +0 -13
@@ -0,0 +1,200 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration_test_helper"
4
+
5
+ # Request params that end up in a list's markup.
6
+ #
7
+ # * parent_class / parent_id: _list built the nested frame as
8
+ # `raw "<turbo-frame id=\"#{update_span}\" …>"` with update_span made from
9
+ # params[:parent_id], and constantized params[:parent_class]; nothing found
10
+ # the parent before the render, so a crafted parent_id was reflected into
11
+ # the page. The controller now refuses malformed parent params (400) in
12
+ # index/new/create/show, and the frame is built with tag.turbo_frame.
13
+ # * pagination: the page links carry every filter of the query string, not
14
+ # just `search`.
15
+ #
16
+ # Part and DailyReport belong to Machine; Widget is a top-level list
17
+ # (per_page 7, see ApplicationRecord).
18
+ class ListParamsTest < InlineFormsIntegrationTestCase
19
+ PAYLOAD = %("><img src=x onerror=alert(1)>)
20
+
21
+ setup do
22
+ @machine = Machine.create!(name: "Press")
23
+ @part = Part.create!(name: "Gear", machine: @machine)
24
+ @list_frame = "machine_#{@machine.id}_parts_list"
25
+ end
26
+
27
+ def assert_refused_without_payload
28
+ assert_response :bad_request
29
+ assert controller.instance_variable_defined?(:@_authorized),
30
+ "the refusal runs after authorization (check_authorization stays satisfied)"
31
+ refute_includes response.body, "<img"
32
+ end
33
+
34
+ def nested(parent_id: @machine.id, parent_class: "Machine", update: @list_frame)
35
+ { parent_class: parent_class, parent_id: parent_id, update: update, ul_needed: 1 }
36
+ end
37
+
38
+ # ---- malformed parent params --------------------------------------------
39
+
40
+ test "a crafted parent_id on the nested list is a 400 and never rendered" do
41
+ get parts_path(nested(parent_id: PAYLOAD, update: "x")), headers: frame_headers("x")
42
+ assert_refused_without_payload
43
+ end
44
+
45
+ test "a crafted parent_id is refused on a full-page visit too" do
46
+ get parts_path(nested(parent_id: PAYLOAD, update: "x"))
47
+ assert_refused_without_payload
48
+ end
49
+
50
+ test "a parent_class that is not an association of the model is a 400" do
51
+ %w[Widget Kernel machine Machines ActiveRecord::Base].each do |parent_class|
52
+ get parts_path(nested(parent_class: parent_class)), headers: frame_headers(@list_frame)
53
+ assert_response :bad_request, "parent_class=#{parent_class}"
54
+ end
55
+ end
56
+
57
+ test "a non-integer parent_id is a 400, with or without parent_class" do
58
+ [ "1 OR 1=1", "-1", "1.5", "" ].each do |parent_id|
59
+ get parts_path(nested(parent_id: parent_id)), headers: frame_headers(@list_frame)
60
+ assert_response :bad_request, "parent_id=#{parent_id.inspect}"
61
+ end
62
+ get parts_path(parent_id: PAYLOAD, update: "x")
63
+ assert_refused_without_payload
64
+ end
65
+
66
+ test "new with crafted parent params is a 400" do
67
+ get new_part_path(nested(parent_id: PAYLOAD, update: "machine_#{@machine.id}_parts")),
68
+ headers: frame_headers("machine_#{@machine.id}_parts")
69
+ assert_refused_without_payload
70
+
71
+ get new_part_path(nested(parent_class: "Widget", update: "machine_#{@machine.id}_parts")),
72
+ headers: frame_headers("machine_#{@machine.id}_parts")
73
+ assert_response :bad_request
74
+ end
75
+
76
+ test "create with crafted parent params is a 400 and creates nothing" do
77
+ frame = "machine_#{@machine.id}_parts"
78
+ assert_no_difference -> { Part.count } do
79
+ post parts_path(nested(parent_id: PAYLOAD, update: frame)), params: { name: "Bolt" }, headers: frame_headers(frame)
80
+ assert_refused_without_payload
81
+ post parts_path(nested(parent_class: "Widget", update: frame)), params: { name: "Bolt" }, headers: frame_headers(frame)
82
+ assert_response :bad_request
83
+ end
84
+ end
85
+
86
+ test "show with a crafted parent_id is a 400" do
87
+ row = "machine_#{@machine.id}_part_#{@part.id}"
88
+ get part_path(@part, update: row, parent_class: "Machine", parent_id: PAYLOAD), headers: frame_headers(row)
89
+ assert_refused_without_payload
90
+ end
91
+
92
+ # ---- well-formed nested lists still work --------------------------------
93
+
94
+ test "a well-formed nested list renders its frame and rows" do
95
+ get parts_path(nested), headers: frame_headers(@list_frame)
96
+
97
+ assert_response :success
98
+ assert_includes response.body, %(<turbo-frame id="#{@list_frame}" class="list_container">)
99
+ assert_includes response.body, "Gear"
100
+ end
101
+
102
+ test "well-formed nested new and create still work" do
103
+ frame = "machine_#{@machine.id}_parts"
104
+ get new_part_path(nested(update: frame)), headers: frame_headers(frame)
105
+ assert_response :success
106
+
107
+ assert_difference -> { @machine.parts.count }, 1 do
108
+ post parts_path(nested(update: frame)), params: { name: "Bolt" }, headers: frame_headers(frame)
109
+ end
110
+ assert_response :success
111
+ end
112
+
113
+ test "the nested list of a not_accessible_through_html? child still renders" do
114
+ DailyReport.create!(name: "Monday", machine: @machine)
115
+ frame = "machine_#{@machine.id}_daily_reports_list"
116
+ get daily_reports_path(parent_class: "Machine", parent_id: @machine.id, update: frame, ul_needed: 1),
117
+ headers: frame_headers(frame)
118
+
119
+ assert_response :success
120
+ assert_includes response.body, "Monday"
121
+ end
122
+
123
+ test "the list frame id is attribute-escaped by the partial itself" do
124
+ html = PartsController.render(
125
+ partial: "inline_forms/list",
126
+ assigns: { Klass: Part, parent_class: "Machine", parent_id: PAYLOAD, ul_needed: "1",
127
+ objects: Part.where(id: @part.id).paginate(page: 1) }
128
+ )
129
+
130
+ refute_includes html, "<img"
131
+ assert_includes html, %(<turbo-frame id="machine_&quot;&gt;&lt;img src=x onerror=alert(1)&gt;_parts_list" class="list_container">)
132
+ end
133
+
134
+ # ---- pagination keeps the filters ---------------------------------------
135
+
136
+ test "page links of a filtered list carry every filter" do
137
+ 9.times { |i| Widget.create!(name: "Match #{i}") }
138
+ Widget.create!(name: "Other")
139
+
140
+ get widgets_path(search: "Match", sorteer: "name", first_name: "An", group: { id: 3 }, status: { id: 4 },
141
+ update: "widgets_list"),
142
+ headers: frame_headers("widgets_list")
143
+
144
+ assert_response :success
145
+ page_link = response.body[/href="([^"]*page=2[^"]*)"/, 1]
146
+ assert page_link, "a link to page 2"
147
+ query = Rack::Utils.parse_nested_query(URI.parse(CGI.unescapeHTML(page_link)).query)
148
+ assert_equal "Match", query["search"]
149
+ assert_equal "name", query["sorteer"]
150
+ assert_equal "An", query["first_name"]
151
+ assert_equal({ "id" => "3" }, query["group"])
152
+ assert_equal({ "id" => "4" }, query["status"])
153
+ assert_equal "widgets_list", query["update"]
154
+ assert_equal "2", query["page"]
155
+
156
+ get CGI.unescapeHTML(page_link), headers: frame_headers("widgets_list")
157
+ assert_response :success
158
+ back = response.body[/href="([^"]*page=1[^"]*)"/, 1]
159
+ assert back, "a link back to page 1"
160
+ back_query = Rack::Utils.parse_nested_query(URI.parse(CGI.unescapeHTML(back)).query)
161
+ assert_equal "Match", back_query["search"]
162
+ assert_equal({ "id" => "3" }, back_query["group"])
163
+ refute_includes response.body, "Other"
164
+ end
165
+
166
+ test "page links of a list rendered after create keep the request's filters" do
167
+ 9.times { |i| Machine.create!(name: "Match #{i}") }
168
+
169
+ post machines_path(update: "machines_list", search: "Match", sorteer: "name"),
170
+ params: { name: "Match 9" }, headers: frame_headers("machines_list")
171
+
172
+ assert_response :success
173
+ page_link = response.body[/href="([^"]*page=2[^"]*)"/, 1]
174
+ assert page_link, "a link to page 2"
175
+ query = Rack::Utils.parse_nested_query(URI.parse(CGI.unescapeHTML(page_link)).query)
176
+ assert_equal "Match", query["search"]
177
+ assert_equal "name", query["sorteer"]
178
+ end
179
+
180
+ # url_for options in the query string must not shape the page links.
181
+ # will_paginate leaves out script_name / original_script_name; merging
182
+ # request.query_parameters into the links bypassed that, so the payload
183
+ # became the start of every page link's href, and controller= raised.
184
+ test "url options in the query string never reach the page links" do
185
+ 9.times { |i| Widget.create!(name: "W #{i}") }
186
+
187
+ %w[script_name original_script_name].each do |option|
188
+ get "/widgets?update=widgets_list&#{option}=javascript:alert(1)//", headers: frame_headers("widgets_list")
189
+ assert_response :success
190
+ page_link = response.body[/href="([^"]*page=2[^"]*)"/, 1]
191
+ assert page_link, "a link to page 2"
192
+ assert page_link.start_with?("/widgets?"), "#{option} shaped the page link: #{page_link}"
193
+ refute_includes response.body, "javascript:alert"
194
+ end
195
+
196
+ get "/widgets?update=widgets_list&controller=widgets_x", headers: frame_headers("widgets_list")
197
+ assert_response :success
198
+ assert_match %r{href="/widgets\?[^"]*page=2}, response.body
199
+ end
200
+ end
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration_test_helper"
4
+
5
+ # The gem's own strings resolve in en and nl, also under
6
+ # raise_on_missing_translations (StProject switched to :nl with :strict):
7
+ # the create flash (`success`, misspelled `succes` in both locale files), the
8
+ # versions panel (was hard-coded English), the nl view keys that were missing
9
+ # (restore, list_versions, close_versions_list, undelete), localized version
10
+ # timestamps, the Devise layout's lang and the sign-in button.
11
+ class LocaleTest < InlineFormsIntegrationTestCase
12
+ KEYS = %w[
13
+ success
14
+ inline_forms.view.restore inline_forms.view.list_versions inline_forms.view.close_versions_list
15
+ inline_forms.view.undelete inline_forms.view.versions inline_forms.view.versions_event
16
+ inline_forms.view.versions_when inline_forms.view.versions_done_by inline_forms.view.versions_changeset
17
+ inline_forms.view.versions_old_value inline_forms.view.versions_new_value inline_forms.view.versions_empty
18
+ inline_forms.view.versions_rich_text inline_forms.view.version_events.create
19
+ inline_forms.view.version_events.update inline_forms.view.version_events.destroy
20
+ inline_forms.devise.login common.more common.logout
21
+ ].freeze
22
+
23
+ setup do
24
+ @machine = Machine.create!(name: "Press")
25
+ @machine.update!(name: "Press 2")
26
+ end
27
+
28
+ teardown do
29
+ I18n.backend.reload!
30
+ end
31
+
32
+ # Every translation the request looks up must exist: a missing one raises,
33
+ # in the views and in the controller (create's flash).
34
+ def strictly(locale)
35
+ original_view = ActionView::Helpers::TranslationHelper.raise_on_missing_translations
36
+ original_handler = I18n.exception_handler
37
+ original_default = I18n.default_locale
38
+ ActionView::Helpers::TranslationHelper.raise_on_missing_translations = true
39
+ I18n.exception_handler = ->(exception, *) { raise exception.respond_to?(:to_exception) ? exception.to_exception : exception }
40
+ # with_locale first: it restores the locale it found, so the thread's
41
+ # locale must not be read after default_locale changed (it would then
42
+ # restore :nl for every later test).
43
+ I18n.with_locale(locale) do
44
+ I18n.default_locale = locale
45
+ yield
46
+ end
47
+ ensure
48
+ I18n.default_locale = original_default
49
+ ActionView::Helpers::TranslationHelper.raise_on_missing_translations = original_view
50
+ I18n.exception_handler = original_handler
51
+ end
52
+
53
+ test "the gem's keys exist in en and nl, and the misspelled succes is gone" do
54
+ %i[en nl].each do |locale|
55
+ KEYS.each { |key| assert I18n.exists?(key, locale), "#{locale}.#{key}" }
56
+ refute I18n.exists?("succes", locale), "#{locale}.succes"
57
+ end
58
+ assert_equal "Machine created.", I18n.t("success", message: "Machine", locale: :en)
59
+ assert_equal "Machine is aangemaakt.", I18n.t("success", message: "Machine", locale: :nl)
60
+ end
61
+
62
+ test "create's success flash translates in nl" do
63
+ # The model top bar shows t(controller_name): host-supplied, like
64
+ # StProject's `clients: cliënten`.
65
+ I18n.backend.store_translations(:nl, machines: "machines")
66
+ strictly(:nl) do
67
+ post machines_path(update: "machines_list"), params: { name: "Lathe" }, headers: frame_headers("machines_list")
68
+ end
69
+
70
+ assert_response :success
71
+ assert_equal "Machine is aangemaakt.", controller.flash[:success]
72
+ end
73
+
74
+ test "the versions panel and list are translated, with localized timestamps" do
75
+ row = "machine_#{@machine.id}"
76
+ strictly(:nl) do
77
+ get machine_path(@machine, update: row), headers: frame_headers(row)
78
+ assert_response :success
79
+ assert_includes response.body, "Versies (2)"
80
+
81
+ get list_versions_machine_path(@machine, update: row), headers: frame_headers(row)
82
+ end
83
+
84
+ assert_response :success
85
+ body = response.body
86
+ %w[Versies Gebeurtenis Wanneer Door Wijzigingen aangemaakt gewijzigd terugzetten].each do |text|
87
+ assert_includes body, text
88
+ end
89
+ refute_includes body, "<strong>Event</strong>"
90
+ version = @machine.versions.last
91
+ assert_includes body, ERB::Util.h(I18n.l(version.created_at, format: :short, locale: :nl))
92
+ end
93
+
94
+ test "the versions list in en keeps its English labels" do
95
+ row = "machine_#{@machine.id}"
96
+ strictly(:en) do
97
+ get list_versions_machine_path(@machine, update: row), headers: frame_headers(row)
98
+ end
99
+
100
+ assert_response :success
101
+ assert_includes response.body, "Versions (2)"
102
+ assert_includes response.body, "<strong>Event</strong>"
103
+ assert_includes response.body, "old value"
104
+ end
105
+
106
+ test "the devise and application layouts declare the page language" do
107
+ get widgets_path
108
+ I18n.with_locale(:nl) do
109
+ assert_includes controller.render_to_string(template: "stats/show", layout: "devise"), %(<html lang="nl">)
110
+ assert_includes controller.render_to_string(template: "stats/show", layout: "application"), %(<html lang="nl">)
111
+ end
112
+ end
113
+ end
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../integration_test_helper"
4
+
5
+ # Model data that a helper concatenates into a string it marks html_safe must
6
+ # be escaped first. info_list_show did `out << item._presentation`, so a
7
+ # _presentation built from user input (StProject: User#name listed on a Role)
8
+ # ran as markup on every page that showed the list (stored XSS). Same audit:
9
+ # file_field_show (stored file name / url) and the rich-text changeset in the
10
+ # versions list (was `raw`).
11
+ class PresentationEscapingTest < InlineFormsIntegrationTestCase
12
+ MARKUP = "<img src=x onerror=alert(1)>"
13
+ ESCAPED = "&lt;img src=x onerror=alert(1)&gt;"
14
+
15
+ # A view context of a real request: helpers, can?, url helpers.
16
+ def view
17
+ @view ||= begin
18
+ get widgets_path
19
+ controller.view_context
20
+ end
21
+ end
22
+
23
+ test "info_list escapes each item's _presentation" do
24
+ machine = Machine.create!(name: "Press")
25
+ Part.create!(name: MARKUP, machine: machine)
26
+ Part.create!(name: "Gear", machine: machine)
27
+
28
+ html = view.info_list_show(machine, :parts)
29
+
30
+ refute_includes html, "<img"
31
+ assert_includes html, ESCAPED
32
+ assert_includes html, "Gear"
33
+ assert_includes html, "<div class='row", "the row markup itself is kept"
34
+ end
35
+
36
+ test "file_field escapes the stored file name and url" do
37
+ widget = Widget.create!(name: "Manual")
38
+ stored = Struct.new(:url, :path) do
39
+ def present? = true
40
+ def to_s = url
41
+ end.new(%(/uploads/x'><img src=x onerror=alert(1)>.pdf), %(/uploads/#{MARKUP}.pdf))
42
+ widget.define_singleton_method(:manual) { stored }
43
+
44
+ html = view.file_field_show(widget, :manual)
45
+
46
+ refute_includes html, "<img"
47
+ assert_includes html, ESCAPED
48
+ end
49
+
50
+ test "dropdown_with_other and the list rows escape _presentation" do
51
+ kind = Kind.create!(name: MARKUP)
52
+ widget = Widget.create!(name: MARKUP, kind: kind)
53
+
54
+ refute_includes view.dropdown_with_other_show(widget, :kind), "<img"
55
+
56
+ get widgets_path(update: "widgets_list"), headers: frame_headers("widgets_list")
57
+ assert_response :success
58
+ refute_includes response.body, "<img"
59
+ assert_includes response.body, ESCAPED
60
+ end
61
+
62
+ test "a rich-text changeset in the versions list is sanitized, not raw" do
63
+ machine = Machine.create!(name: "Press")
64
+ version = Struct.new(:id, :event, :changeset, :created_at, :whodunnit) do
65
+ def to_param = id.to_s
66
+ end.new(1, "update", { "body" => [ "<p>old</p><script>alert(1)</script>", "<p>new</p>#{MARKUP}" ] }, Time.current, nil)
67
+ context = view
68
+ context.instance_variable_set(:@object, machine)
69
+ context.define_singleton_method(:inline_forms_history_for) do |_object|
70
+ [ { version: version, kind: :rich_text, rich_text_name: "description", at: version.created_at } ]
71
+ end
72
+
73
+ html = context.render(partial: "inline_forms/versions_list")
74
+
75
+ refute_includes html, "<script"
76
+ refute_includes html, "onerror"
77
+ assert_includes html, "<p>old</p>"
78
+ assert_includes html, "<p>new</p>"
79
+ end
80
+ end
@@ -49,6 +49,15 @@ ActiveRecord::Schema.define do
49
49
  end
50
50
  add_index :parts, :machine_id
51
51
 
52
+ # DailyReport: a not_accessible_through_html? child of Machine (shaped like
53
+ # StProject's Dagrapportage). See test/integration/html_refusal_test.rb.
54
+ create_table :daily_reports, force: true do |t|
55
+ t.string :name
56
+ t.integer :machine_id
57
+ t.timestamps
58
+ end
59
+ add_index :daily_reports, :machine_id
60
+
52
61
  # Gizmo intentionally has NO `pending_note` column: its attribute_list
53
62
  # references one, modeling the inline_forms_addto pre-migrate window that
54
63
  # InlineForms.attribute_pending_migration? gates. See
@@ -163,9 +172,11 @@ class InlineFormsIntegrationTestCase < ActionDispatch::IntegrationTest
163
172
 
164
173
  setup do
165
174
  Ability.restrictions = nil
175
+ ApplicationController.dummy_user_superadmin = true
166
176
  Widget.delete_all
167
177
  Kind.delete_all
168
178
  Part.delete_all
179
+ DailyReport.delete_all
169
180
  Machine.delete_all
170
181
  Gizmo.delete_all
171
182
  Dossier.delete_all
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inline_forms
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.1.55
4
+ version: 8.1.57
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ace Suares
@@ -153,7 +153,6 @@ files:
153
153
  - app/views/inline_forms/_close.html.erb
154
154
  - app/views/inline_forms/_edit.html.erb
155
155
  - app/views/inline_forms/_file_slot.html.erb
156
- - app/views/inline_forms/_flash.html.erb
157
156
  - app/views/inline_forms/_generic_search.html.erb
158
157
  - app/views/inline_forms/_header.html.erb
159
158
  - app/views/inline_forms/_list.html.erb
@@ -282,6 +281,7 @@ files:
282
281
  - test/archived_form_elements_test.rb
283
282
  - test/attribute_list_test.rb
284
283
  - test/dummy/app/controllers/application_controller.rb
284
+ - test/dummy/app/controllers/daily_reports_controller.rb
285
285
  - test/dummy/app/controllers/documents_controller.rb
286
286
  - test/dummy/app/controllers/dossiers_controller.rb
287
287
  - test/dummy/app/controllers/gizmos_controller.rb
@@ -292,6 +292,7 @@ files:
292
292
  - test/dummy/app/helpers/application_helper.rb
293
293
  - test/dummy/app/models/ability.rb
294
294
  - test/dummy/app/models/application_record.rb
295
+ - test/dummy/app/models/daily_report.rb
295
296
  - test/dummy/app/models/document.rb
296
297
  - test/dummy/app/models/dossier.rb
297
298
  - test/dummy/app/models/gizmo.rb
@@ -312,15 +313,20 @@ files:
312
313
  - test/inline_edit_polymorphic_path_test.rb
313
314
  - test/inline_forms_addto_generator_test.rb
314
315
  - test/inline_forms_generator_test.rb
316
+ - test/integration/csp_nonce_test.rb
315
317
  - test/integration/field_authorization_test.rb
316
318
  - test/integration/file_slots_test.rb
319
+ - test/integration/html_refusal_test.rb
317
320
  - test/integration/inline_forms_crud_test.rb
318
321
  - test/integration/layout_title_test.rb
319
322
  - test/integration/legacy_elements_test.rb
323
+ - test/integration/list_params_test.rb
324
+ - test/integration/locale_test.rb
320
325
  - test/integration/model_top_bar_test.rb
321
326
  - test/integration/native_inputs_test.rb
322
327
  - test/integration/open_after_create_test.rb
323
328
  - test/integration/pending_migration_gate_test.rb
329
+ - test/integration/presentation_escaping_test.rb
324
330
  - test/integration/revert_skipped_columns_test.rb
325
331
  - test/integration/schema_batch_pipeline_test.rb
326
332
  - test/integration/schema_edit_test.rb
@@ -363,6 +369,7 @@ test_files:
363
369
  - test/archived_form_elements_test.rb
364
370
  - test/attribute_list_test.rb
365
371
  - test/dummy/app/controllers/application_controller.rb
372
+ - test/dummy/app/controllers/daily_reports_controller.rb
366
373
  - test/dummy/app/controllers/documents_controller.rb
367
374
  - test/dummy/app/controllers/dossiers_controller.rb
368
375
  - test/dummy/app/controllers/gizmos_controller.rb
@@ -373,6 +380,7 @@ test_files:
373
380
  - test/dummy/app/helpers/application_helper.rb
374
381
  - test/dummy/app/models/ability.rb
375
382
  - test/dummy/app/models/application_record.rb
383
+ - test/dummy/app/models/daily_report.rb
376
384
  - test/dummy/app/models/document.rb
377
385
  - test/dummy/app/models/dossier.rb
378
386
  - test/dummy/app/models/gizmo.rb
@@ -393,15 +401,20 @@ test_files:
393
401
  - test/inline_edit_polymorphic_path_test.rb
394
402
  - test/inline_forms_addto_generator_test.rb
395
403
  - test/inline_forms_generator_test.rb
404
+ - test/integration/csp_nonce_test.rb
396
405
  - test/integration/field_authorization_test.rb
397
406
  - test/integration/file_slots_test.rb
407
+ - test/integration/html_refusal_test.rb
398
408
  - test/integration/inline_forms_crud_test.rb
399
409
  - test/integration/layout_title_test.rb
400
410
  - test/integration/legacy_elements_test.rb
411
+ - test/integration/list_params_test.rb
412
+ - test/integration/locale_test.rb
401
413
  - test/integration/model_top_bar_test.rb
402
414
  - test/integration/native_inputs_test.rb
403
415
  - test/integration/open_after_create_test.rb
404
416
  - test/integration/pending_migration_gate_test.rb
417
+ - test/integration/presentation_escaping_test.rb
405
418
  - test/integration/revert_skipped_columns_test.rb
406
419
  - test/integration/schema_batch_pipeline_test.rb
407
420
  - test/integration/schema_edit_test.rb
@@ -1,13 +0,0 @@
1
- <% unless flash.empty? %>
2
- <% identifier = Time.now.to_i.to_s %>
3
- <div class="row" id="flash_<%= identifier %>">
4
- <% flash.each do |key, value| %>
5
- <%= value %>
6
- <% end %>
7
- <script>
8
- $("#<%= "#{update_span}_auto_header" %>").ScrollTo();
9
- $("#flash_<%= identifier %>").delay(1000).fadeToggle('2000');
10
- </script>
11
- </div>
12
- <% end %>
13
-