actionpack 6.1.4.7 → 6.1.5
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of actionpack might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +54 -0
- data/MIT-LICENSE +1 -2
- data/lib/abstract_controller/collector.rb +4 -2
- data/lib/action_controller/metal/http_authentication.rb +1 -0
- data/lib/action_controller/metal/strong_parameters.rb +1 -1
- data/lib/action_dispatch/http/content_security_policy.rb +2 -1
- data/lib/action_dispatch/http/response.rb +2 -2
- data/lib/action_dispatch/middleware/host_authorization.rb +41 -12
- data/lib/action_dispatch/middleware/show_exceptions.rb +10 -0
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.html.erb +1 -1
- data/lib/action_dispatch/middleware/templates/rescues/blocked_host.text.erb +1 -1
- data/lib/action_dispatch/routing/route_set.rb +2 -2
- data/lib/action_dispatch/system_test_case.rb +7 -1
- data/lib/action_dispatch/testing/test_process.rb +10 -7
- data/lib/action_dispatch.rb +1 -1
- data/lib/action_pack/gem_version.rb +2 -2
- data/lib/action_pack.rb +1 -1
- metadata +16 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c0459690ecc8372a1e4b623d82944649463857b673a5a14a5a6f3f421cb708e6
|
4
|
+
data.tar.gz: 1df6ce6c492a5c1bd78195c4ede33dee3648bd72893cbd523b263344caea56e2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ce15e789ef79b1a60273afaa3db51f2c9ad550babdf3d566dddd3c36773c2b6643c4c5ecb6def64e5f45aa9a9c7adde7a2ad8e662a2633c05857c1ab3bb3836d
|
7
|
+
data.tar.gz: 3cbae6f237bc166e8f0ec3cc85d54baa2086b76ec11317a06260797b454d6735519b9193b882dfa5a9950829d549b8e4f0acaea4196c5ec265987cea238e5efe
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,57 @@
|
|
1
|
+
## Rails 6.1.5 (March 09, 2022) ##
|
2
|
+
|
3
|
+
* Fix `content_security_policy` returning invalid directives.
|
4
|
+
|
5
|
+
Directives such as `self`, `unsafe-eval` and few others were not
|
6
|
+
single quoted when the directive was the result of calling a lambda
|
7
|
+
returning an array.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
content_security_policy do |policy|
|
11
|
+
policy.frame_ancestors lambda { [:self, "https://example.com"] }
|
12
|
+
end
|
13
|
+
```
|
14
|
+
|
15
|
+
With this fix the policy generated from above will now be valid.
|
16
|
+
|
17
|
+
*Edouard Chin*
|
18
|
+
|
19
|
+
* Update `HostAuthorization` middleware to render debug info only
|
20
|
+
when `config.consider_all_requests_local` is set to true.
|
21
|
+
|
22
|
+
Also, blocked host info is always logged with level `error`.
|
23
|
+
|
24
|
+
Fixes #42813.
|
25
|
+
|
26
|
+
*Nikita Vyrko*
|
27
|
+
|
28
|
+
* Dup arrays that get "converted".
|
29
|
+
|
30
|
+
Fixes #43681.
|
31
|
+
|
32
|
+
*Aaron Patterson*
|
33
|
+
|
34
|
+
* Don't show deprecation warning for equal paths.
|
35
|
+
|
36
|
+
*Anton Rieder*
|
37
|
+
|
38
|
+
* Fix crash in `ActionController::Instrumentation` with invalid HTTP formats.
|
39
|
+
|
40
|
+
Fixes #43094.
|
41
|
+
|
42
|
+
*Alex Ghiculescu*
|
43
|
+
|
44
|
+
* Add fallback host for SystemTestCase driven by RackTest.
|
45
|
+
|
46
|
+
Fixes #42780.
|
47
|
+
|
48
|
+
*Petrik de Heus*
|
49
|
+
|
50
|
+
* Add more detail about what hosts are allowed.
|
51
|
+
|
52
|
+
*Alex Ghiculescu*
|
53
|
+
|
54
|
+
|
1
55
|
## Rails 6.1.4.7 (March 08, 2022) ##
|
2
56
|
|
3
57
|
* No changes.
|
data/MIT-LICENSE
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
Copyright (c) 2004-
|
1
|
+
Copyright (c) 2004-2022 David Heinemeier Hansson
|
2
2
|
|
3
3
|
Permission is hereby granted, free of charge, to any person obtaining
|
4
4
|
a copy of this software and associated documentation files (the
|
@@ -18,4 +18,3 @@ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
18
|
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
19
|
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
20
|
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
21
|
-
|
@@ -10,6 +10,7 @@ module AbstractController
|
|
10
10
|
def #{sym}(*args, &block)
|
11
11
|
custom(Mime[:#{sym}], *args, &block)
|
12
12
|
end
|
13
|
+
ruby2_keywords(:#{sym}) if respond_to?(:ruby2_keywords, true)
|
13
14
|
RUBY
|
14
15
|
end
|
15
16
|
|
@@ -22,7 +23,7 @@ module AbstractController
|
|
22
23
|
end
|
23
24
|
|
24
25
|
private
|
25
|
-
def method_missing(symbol, &block)
|
26
|
+
def method_missing(symbol, *args, &block)
|
26
27
|
unless mime_constant = Mime[symbol]
|
27
28
|
raise NoMethodError, "To respond to a custom format, register it as a MIME type first: " \
|
28
29
|
"https://guides.rubyonrails.org/action_controller_overview.html#restful-downloads. " \
|
@@ -33,10 +34,11 @@ module AbstractController
|
|
33
34
|
|
34
35
|
if Mime::SET.include?(mime_constant)
|
35
36
|
AbstractController::Collector.generate_method_for_mime(mime_constant)
|
36
|
-
|
37
|
+
public_send(symbol, *args, &block)
|
37
38
|
else
|
38
39
|
super
|
39
40
|
end
|
40
41
|
end
|
42
|
+
ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
|
41
43
|
end
|
42
44
|
end
|
@@ -940,7 +940,7 @@ module ActionController
|
|
940
940
|
when Array
|
941
941
|
return value if converted_arrays.member?(value)
|
942
942
|
converted = value.map { |_| convert_value_to_parameters(_) }
|
943
|
-
converted_arrays << converted
|
943
|
+
converted_arrays << converted.dup
|
944
944
|
converted
|
945
945
|
when Hash
|
946
946
|
self.class.new(value)
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "active_support/core_ext/object/deep_dup"
|
4
|
+
require "active_support/core_ext/array/wrap"
|
4
5
|
|
5
6
|
module ActionDispatch #:nodoc:
|
6
7
|
class ContentSecurityPolicy
|
@@ -272,7 +273,7 @@ module ActionDispatch #:nodoc:
|
|
272
273
|
raise RuntimeError, "Missing context for the dynamic content security policy source: #{source.inspect}"
|
273
274
|
else
|
274
275
|
resolved = context.instance_exec(&source)
|
275
|
-
|
276
|
+
apply_mappings(Array.wrap(resolved))
|
276
277
|
end
|
277
278
|
else
|
278
279
|
raise RuntimeError, "Unexpected content security policy source: #{source.inspect}"
|
@@ -88,13 +88,13 @@ module ActionDispatch # :nodoc:
|
|
88
88
|
|
89
89
|
def self.return_only_media_type_on_content_type=(*)
|
90
90
|
ActiveSupport::Deprecation.warn(
|
91
|
-
".return_only_media_type_on_content_type= is dreprecated with no replacement and will be removed in
|
91
|
+
".return_only_media_type_on_content_type= is dreprecated with no replacement and will be removed in 7.0."
|
92
92
|
)
|
93
93
|
end
|
94
94
|
|
95
95
|
def self.return_only_media_type_on_content_type
|
96
96
|
ActiveSupport::Deprecation.warn(
|
97
|
-
".return_only_media_type_on_content_type is dreprecated with no replacement and will be removed in
|
97
|
+
".return_only_media_type_on_content_type is dreprecated with no replacement and will be removed in 7.0."
|
98
98
|
)
|
99
99
|
end
|
100
100
|
|
@@ -13,7 +13,10 @@ module ActionDispatch
|
|
13
13
|
#
|
14
14
|
# When a request comes to an unauthorized host, the +response_app+
|
15
15
|
# application will be executed and rendered. If no +response_app+ is given, a
|
16
|
-
# default one will run
|
16
|
+
# default one will run.
|
17
|
+
# The default response app logs blocked host info with level 'error' and
|
18
|
+
# responds with <tt>403 Forbidden</tt>. The body of the response contains debug info
|
19
|
+
# if +config.consider_all_requests_local+ is set to true, otherwise the body is empty.
|
17
20
|
class HostAuthorization
|
18
21
|
ALLOWED_HOSTS_IN_DEVELOPMENT = [".localhost", IPAddr.new("0.0.0.0/0"), IPAddr.new("::/0")]
|
19
22
|
PORT_REGEX = /(?::\d+)/ # :nodoc:
|
@@ -79,17 +82,43 @@ module ActionDispatch
|
|
79
82
|
end
|
80
83
|
end
|
81
84
|
|
82
|
-
|
83
|
-
|
85
|
+
class DefaultResponseApp # :nodoc:
|
86
|
+
RESPONSE_STATUS = 403
|
87
|
+
|
88
|
+
def call(env)
|
89
|
+
request = Request.new(env)
|
90
|
+
format = request.xhr? ? "text/plain" : "text/html"
|
91
|
+
|
92
|
+
log_error(request)
|
93
|
+
response(format, response_body(request))
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
def response_body(request)
|
98
|
+
return "" unless request.get_header("action_dispatch.show_detailed_exceptions")
|
99
|
+
|
100
|
+
template = DebugView.new(host: request.host)
|
101
|
+
template.render(template: "rescues/blocked_host", layout: "rescues/layout")
|
102
|
+
end
|
103
|
+
|
104
|
+
def response(format, body)
|
105
|
+
[RESPONSE_STATUS,
|
106
|
+
{ "Content-Type" => "#{format}; charset=#{Response.default_charset}",
|
107
|
+
"Content-Length" => body.bytesize.to_s },
|
108
|
+
[body]]
|
109
|
+
end
|
110
|
+
|
111
|
+
def log_error(request)
|
112
|
+
logger = available_logger(request)
|
84
113
|
|
85
|
-
|
86
|
-
template = DebugView.new(host: request.host)
|
87
|
-
body = template.render(template: "rescues/blocked_host", layout: "rescues/layout")
|
114
|
+
return unless logger
|
88
115
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
116
|
+
logger.error("[#{self.class.name}] Blocked host: #{request.host}")
|
117
|
+
end
|
118
|
+
|
119
|
+
def available_logger(request)
|
120
|
+
request.logger || ActionView::Base.logger
|
121
|
+
end
|
93
122
|
end
|
94
123
|
|
95
124
|
def initialize(app, hosts, deprecated_response_app = nil, exclude: nil, response_app: nil)
|
@@ -99,14 +128,14 @@ module ActionDispatch
|
|
99
128
|
|
100
129
|
unless deprecated_response_app.nil?
|
101
130
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
102
|
-
`action_dispatch.hosts_response_app` is deprecated and will be ignored in Rails
|
131
|
+
`action_dispatch.hosts_response_app` is deprecated and will be ignored in Rails 7.0.
|
103
132
|
Use the Host Authorization `response_app` setting instead.
|
104
133
|
MSG
|
105
134
|
|
106
135
|
response_app ||= deprecated_response_app
|
107
136
|
end
|
108
137
|
|
109
|
-
@response_app = response_app ||
|
138
|
+
@response_app = response_app || DefaultResponseApp.new
|
110
139
|
end
|
111
140
|
|
112
141
|
def call(env)
|
@@ -47,6 +47,7 @@ module ActionDispatch
|
|
47
47
|
request.set_header "action_dispatch.exception", wrapper.unwrapped_exception
|
48
48
|
request.set_header "action_dispatch.original_path", request.path_info
|
49
49
|
request.set_header "action_dispatch.original_request_method", request.raw_request_method
|
50
|
+
fallback_to_html_format_if_invalid_mime_type(request)
|
50
51
|
request.path_info = "/#{status}"
|
51
52
|
request.request_method = "GET"
|
52
53
|
response = @exceptions_app.call(request.env)
|
@@ -56,6 +57,15 @@ module ActionDispatch
|
|
56
57
|
FAILSAFE_RESPONSE
|
57
58
|
end
|
58
59
|
|
60
|
+
def fallback_to_html_format_if_invalid_mime_type(request)
|
61
|
+
# If the MIME type for the request is invalid then the
|
62
|
+
# @exceptions_app may not be able to handle it. To make it
|
63
|
+
# easier to handle, we switch to HTML.
|
64
|
+
request.formats
|
65
|
+
rescue ActionDispatch::Http::MimeNegotiation::InvalidType
|
66
|
+
request.set_header "HTTP_ACCEPT", "text/html"
|
67
|
+
end
|
68
|
+
|
59
69
|
def pass_response(status)
|
60
70
|
[status, { "Content-Type" => "text/html; charset=#{Response.default_charset}", "Content-Length" => "0" }, []]
|
61
71
|
end
|
@@ -2,6 +2,6 @@
|
|
2
2
|
<h1>Blocked host: <%= @host %></h1>
|
3
3
|
</header>
|
4
4
|
<div id="container">
|
5
|
-
<h2>To allow requests to <%= @host
|
5
|
+
<h2>To allow requests to <%= @host %> make sure it is a valid hostname (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:</h2>
|
6
6
|
<pre>config.hosts << "<%= @host %>"</pre>
|
7
7
|
</div>
|
@@ -1,5 +1,5 @@
|
|
1
1
|
Blocked host: <%= @host %>
|
2
2
|
|
3
|
-
To allow requests to <%= @host
|
3
|
+
To allow requests to <%= @host %> make sure it is a valid hostname (containing only numbers, letters, dashes and dots), then add the following to your environment configuration:
|
4
4
|
|
5
5
|
config.hosts << "<%= @host %>"
|
@@ -597,14 +597,14 @@ module ActionDispatch
|
|
597
597
|
if route.segment_keys.include?(:controller)
|
598
598
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
599
599
|
Using a dynamic :controller segment in a route is deprecated and
|
600
|
-
will be removed in Rails
|
600
|
+
will be removed in Rails 7.0.
|
601
601
|
MSG
|
602
602
|
end
|
603
603
|
|
604
604
|
if route.segment_keys.include?(:action)
|
605
605
|
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
606
606
|
Using a dynamic :action segment in a route is deprecated and
|
607
|
-
will be removed in Rails
|
607
|
+
will be removed in Rails 7.0.
|
608
608
|
MSG
|
609
609
|
end
|
610
610
|
|
@@ -115,6 +115,8 @@ module ActionDispatch
|
|
115
115
|
include SystemTesting::TestHelpers::SetupAndTeardown
|
116
116
|
include SystemTesting::TestHelpers::ScreenshotHelper
|
117
117
|
|
118
|
+
DEFAULT_HOST = "http://127.0.0.1"
|
119
|
+
|
118
120
|
def initialize(*) # :nodoc:
|
119
121
|
super
|
120
122
|
self.class.driven_by(:selenium) unless self.class.driver?
|
@@ -166,7 +168,11 @@ module ActionDispatch
|
|
166
168
|
include ActionDispatch.test_app.routes.mounted_helpers
|
167
169
|
|
168
170
|
def url_options
|
169
|
-
default_url_options.reverse_merge(host:
|
171
|
+
default_url_options.reverse_merge(host: app_host)
|
172
|
+
end
|
173
|
+
|
174
|
+
def app_host
|
175
|
+
Capybara.app_host || Capybara.current_session.server_url || DEFAULT_HOST
|
170
176
|
end
|
171
177
|
end.new
|
172
178
|
end
|
@@ -25,18 +25,21 @@ module ActionDispatch
|
|
25
25
|
if !self.class.file_fixture_path
|
26
26
|
ActiveSupport::Deprecation.warn(<<~EOM)
|
27
27
|
Passing a path to `fixture_file_upload` relative to `fixture_path` is deprecated.
|
28
|
-
In Rails
|
28
|
+
In Rails 7.0, the path needs to be relative to `file_fixture_path` which you
|
29
29
|
haven't set yet. Set `file_fixture_path` to discard this warning.
|
30
30
|
EOM
|
31
31
|
elsif path.exist?
|
32
32
|
non_deprecated_path = Pathname(File.absolute_path(path)).relative_path_from(Pathname(File.absolute_path(self.class.file_fixture_path)))
|
33
|
-
ActiveSupport::Deprecation.warn(<<~EOM)
|
34
|
-
Passing a path to `fixture_file_upload` relative to `fixture_path` is deprecated.
|
35
|
-
In Rails 6.2, the path needs to be relative to `file_fixture_path`.
|
36
33
|
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
if Pathname(original_path) != non_deprecated_path
|
35
|
+
ActiveSupport::Deprecation.warn(<<~EOM)
|
36
|
+
Passing a path to `fixture_file_upload` relative to `fixture_path` is deprecated.
|
37
|
+
In Rails 7.0, the path needs to be relative to `file_fixture_path`.
|
38
|
+
|
39
|
+
Please modify the call from
|
40
|
+
`fixture_file_upload("#{original_path}")` to `fixture_file_upload("#{non_deprecated_path}")`.
|
41
|
+
EOM
|
42
|
+
end
|
40
43
|
else
|
41
44
|
path = file_fixture(original_path)
|
42
45
|
end
|
data/lib/action_dispatch.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2022 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
data/lib/action_pack.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
#--
|
4
|
-
# Copyright (c) 2004-
|
4
|
+
# Copyright (c) 2004-2022 David Heinemeier Hansson
|
5
5
|
#
|
6
6
|
# Permission is hereby granted, free of charge, to any person obtaining
|
7
7
|
# a copy of this software and associated documentation files (the
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: actionpack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 6.1.
|
4
|
+
version: 6.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Heinemeier Hansson
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-03-
|
11
|
+
date: 2022-03-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 6.1.
|
19
|
+
version: 6.1.5
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 6.1.
|
26
|
+
version: 6.1.5
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rack
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -98,28 +98,28 @@ dependencies:
|
|
98
98
|
requirements:
|
99
99
|
- - '='
|
100
100
|
- !ruby/object:Gem::Version
|
101
|
-
version: 6.1.
|
101
|
+
version: 6.1.5
|
102
102
|
type: :runtime
|
103
103
|
prerelease: false
|
104
104
|
version_requirements: !ruby/object:Gem::Requirement
|
105
105
|
requirements:
|
106
106
|
- - '='
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
version: 6.1.
|
108
|
+
version: 6.1.5
|
109
109
|
- !ruby/object:Gem::Dependency
|
110
110
|
name: activemodel
|
111
111
|
requirement: !ruby/object:Gem::Requirement
|
112
112
|
requirements:
|
113
113
|
- - '='
|
114
114
|
- !ruby/object:Gem::Version
|
115
|
-
version: 6.1.
|
115
|
+
version: 6.1.5
|
116
116
|
type: :development
|
117
117
|
prerelease: false
|
118
118
|
version_requirements: !ruby/object:Gem::Requirement
|
119
119
|
requirements:
|
120
120
|
- - '='
|
121
121
|
- !ruby/object:Gem::Version
|
122
|
-
version: 6.1.
|
122
|
+
version: 6.1.5
|
123
123
|
description: Web apps on Rails. Simple, battle-tested conventions for building and
|
124
124
|
testing MVC web applications. Works with any Rack-compatible server.
|
125
125
|
email: david@loudthinking.com
|
@@ -309,11 +309,12 @@ licenses:
|
|
309
309
|
- MIT
|
310
310
|
metadata:
|
311
311
|
bug_tracker_uri: https://github.com/rails/rails/issues
|
312
|
-
changelog_uri: https://github.com/rails/rails/blob/v6.1.
|
313
|
-
documentation_uri: https://api.rubyonrails.org/v6.1.
|
312
|
+
changelog_uri: https://github.com/rails/rails/blob/v6.1.5/actionpack/CHANGELOG.md
|
313
|
+
documentation_uri: https://api.rubyonrails.org/v6.1.5/
|
314
314
|
mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
|
315
|
-
source_code_uri: https://github.com/rails/rails/tree/v6.1.
|
316
|
-
|
315
|
+
source_code_uri: https://github.com/rails/rails/tree/v6.1.5/actionpack
|
316
|
+
rubygems_mfa_required: 'true'
|
317
|
+
post_install_message:
|
317
318
|
rdoc_options: []
|
318
319
|
require_paths:
|
319
320
|
- lib
|
@@ -329,8 +330,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
329
330
|
version: '0'
|
330
331
|
requirements:
|
331
332
|
- none
|
332
|
-
rubygems_version: 3.
|
333
|
-
signing_key:
|
333
|
+
rubygems_version: 3.3.7
|
334
|
+
signing_key:
|
334
335
|
specification_version: 4
|
335
336
|
summary: Web-flow and rendering framework putting the VC in MVC (part of Rails).
|
336
337
|
test_files: []
|