hanami 2.0.0.alpha3 → 2.0.0.alpha4

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: f322cd4a751d83369d2d20f0f209bfb1dca92a78f6a3dd7c4027ea672df84e36
4
- data.tar.gz: 801be572c3df6e61bfaee8b72f0a164dcbe83216f33c72972c67334f9b2619cf
3
+ metadata.gz: 2188bc3aee5a164b6610c6bc97fad9f0bba0384bf11a80be27228e7f19dad4e0
4
+ data.tar.gz: 7fa39987132cf6bfda0b0986a36894d08297c1df06b31354cfbeae934d73a813
5
5
  SHA512:
6
- metadata.gz: 244ab662705c248857bc4d4e3f42b1de6dc92003fb3c8fe6d3cd006194be272d1aac36f570baa319a971dfcdd6f24eb691c270fa57b852fdbc4da863bc1908d1
7
- data.tar.gz: 3d6b72d227de112fbedefb7f8f6fbcb1e010fb37bf3d97e5826b6fe134dc0facd2a36bba0ad5e2118f731ee2bb1d18ae4f7307377c0fd31e5b81a3e307c56ae0
6
+ metadata.gz: f7b1aad0186fcdaa94593ba4ff5d01cf4f8d4431aaffba173c3c795c2c0c76993a27da3aa503b0ce59fd67467615c86c50a4ab227986e38dd0986e91c30766a5
7
+ data.tar.gz: cd2d8b82bc7f98e906686fdab7299282b1c1be4b29278c9ee5b0f9b3cefbb7d31fa83013a840b2b9fa2b8e2b2f3f8c0582ca3587b35ced91f65db6f853d67cf7
data/CHANGELOG.md CHANGED
@@ -1,6 +1,75 @@
1
1
  # Hanami
2
2
  The web, with simplicity.
3
3
 
4
+ ## v2.0.0.alpha4 - 2021-12-07
5
+ ### Added
6
+ - [Luca Guidi] Manage Content Security Policy (CSP) with "zero-defaults" policy. New API to change CSP values and to disable the feature.
7
+ ```ruby
8
+ # Read a CSP value
9
+
10
+ module MyApp
11
+ class Application < Hanami::Application
12
+ config.actions.content_security_policy[:base_uri] # => "'self'"
13
+ end
14
+ end
15
+ ```
16
+
17
+ ```ruby
18
+ # Override a default CSP value
19
+
20
+ module MyApp
21
+ class Application < Hanami::Application
22
+ # This line will generate the following CSP fragment
23
+ # plugin-types ;
24
+ config.actions.content_security_policy[:plugin_types] = nil
25
+ end
26
+ end
27
+ ```
28
+
29
+ ```ruby
30
+ # Append to a default CSP value
31
+
32
+ module MyApp
33
+ class Application < Hanami::Application
34
+ # This line will generate the following CSP fragment
35
+ # script-src 'self' https://my.cdn.test;
36
+ config.actions.content_security_policy[:script_src] += " https://my.cdn.test"
37
+ end
38
+ end
39
+ ```
40
+
41
+ ```ruby
42
+ # Add a custom CSP key. Useful when CSP standard evolves.
43
+
44
+ module MyApp
45
+ class Application < Hanami::Application
46
+ # This line will generate the following CSP fragment
47
+ # my-custom-setting 'self';
48
+ config.actions.content_security_policy[:my-custom-setting] = "'self'"
49
+ end
50
+ end
51
+ ```
52
+
53
+ ```ruby
54
+ # Delete a CSP key.
55
+
56
+ module MyApp
57
+ class Application < Hanami::Application
58
+ config.actions.content_security_policy.delete(:object_src)
59
+ end
60
+ end
61
+ ```
62
+
63
+ ```ruby
64
+ # Disable CSP feature.
65
+
66
+ module MyApp
67
+ class Application < Hanami::Application
68
+ config.actions.content_security_policy = false
69
+ end
70
+ end
71
+ ```
72
+
4
73
  ## v2.0.0.alpha3 - 2021-11-09
5
74
  ### Added
6
75
  - [Luca Guidi] Added `Hanami.shutdown` to stop all bootable components in the application container
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ Hanami.application.register_bootable :routes_helper do
4
+ start do
5
+ require "hanami/application/routes_helper"
6
+
7
+ register :routes_helper, Hanami::Application::RoutesHelper.new(Hanami.application.router)
8
+ end
9
+ end
@@ -33,7 +33,8 @@ module Hanami
33
33
  #
34
34
  # @yield DSL syntax to define application routes executed in the context
35
35
  # of {Hanami::Application::Router}
36
- # @returns [Proc]
36
+ #
37
+ # @return [Proc]
37
38
  def self.define(&block)
38
39
  @_routes = block
39
40
  end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Hanami
4
+ class Application
5
+ # Hanami application routes helpers
6
+ #
7
+ # An instance of this class gets registered in the container
8
+ # (`routes_helper` key) once the Hanami application is booted. You can use
9
+ # it to get the route helpers for your application.
10
+ #
11
+ # @example
12
+ # MyApp::Application["routes_helper"].path(:root) # => "/"
13
+ #
14
+ # @see Hanami::Router::UrlHelpers
15
+ # @since 2.0.0
16
+ class RoutesHelper
17
+ # @since 2.0.0
18
+ # @api private
19
+ def initialize(router)
20
+ @router = router
21
+ end
22
+
23
+ # @see Hanami::Router::UrlHelpers#path
24
+ def path(*args, **kwargs, &block)
25
+ @router.path(*args, **kwargs, &block)
26
+ end
27
+
28
+ # @see Hanami::Router::UrlHelpers#url
29
+ def url(*args, **kwargs, &block)
30
+ @router.url(*args, **kwargs, &block)
31
+ end
32
+ end
33
+ end
34
+ end
@@ -7,6 +7,8 @@ module Hanami
7
7
  #
8
8
  # @since 2.0.0
9
9
  class Resolver
10
+ ENDPOINT_KEY_NAMESPACE = "actions"
11
+
10
12
  require_relative "resolver/trie"
11
13
 
12
14
  # @since 2.0.0
@@ -21,7 +23,7 @@ module Hanami
21
23
  def initialize(slices:, inflector:)
22
24
  @slices = slices
23
25
  @inflector = inflector
24
- @slices_registry = Trie.new
26
+ @slice_registry = Trie.new
25
27
  end
26
28
 
27
29
  # @api private
@@ -50,7 +52,7 @@ module Hanami
50
52
  # @api private
51
53
  # @since 2.0.0
52
54
  def register_slice_at_path(name, path)
53
- slices_registry.add(path, name)
55
+ slice_registry.add(path, name)
54
56
  end
55
57
 
56
58
  private
@@ -65,16 +67,19 @@ module Hanami
65
67
 
66
68
  # @api private
67
69
  # @since 2.0.0
68
- attr_reader :slices_registry
70
+ attr_reader :slice_registry
69
71
 
70
72
  # @api private
71
73
  # @since 2.0.0
72
74
  def resolve_string_identifier(path, identifier)
73
- slice_name = slices_registry.find(path) or raise "missing slice for #{path.inspect} (#{identifier.inspect})"
75
+ slice_name = slice_registry.find(path) or raise "missing slice for #{path.inspect} (#{identifier.inspect})"
74
76
  slice = slices[slice_name]
75
- action_key = "actions.#{identifier}"
77
+ endpoint_key = "#{ENDPOINT_KEY_NAMESPACE}.#{identifier}"
76
78
 
77
- slice[action_key]
79
+ # Lazily resolve endpoint from the slice to reduce router initialization time,
80
+ # and break potential endless loops from the resolved endpoint itself requiring
81
+ # access to router-related concerns
82
+ -> (*args) { slice[endpoint_key].call(*args) }
78
83
  end
79
84
  end
80
85
  end
@@ -8,6 +8,7 @@ require "rack"
8
8
  require "zeitwerk"
9
9
  require_relative "slice"
10
10
  require_relative "application/autoloader/inflector_adapter"
11
+ require_relative "application/router"
11
12
  require_relative "application/routes"
12
13
  require_relative "application/settings"
13
14
 
@@ -71,8 +72,6 @@ module Hanami
71
72
 
72
73
  autoloader.setup
73
74
 
74
- load_routes
75
-
76
75
  @inited = true
77
76
  self
78
77
  end
@@ -148,6 +147,8 @@ module Hanami
148
147
 
149
148
  init
150
149
 
150
+ load_router
151
+
151
152
  container.finalize!(&block)
152
153
 
153
154
  slices.values.each(&:boot)
@@ -168,12 +169,6 @@ module Hanami
168
169
  @_settings ||= load_settings
169
170
  end
170
171
 
171
- def routes
172
- @_mutex.synchronize do
173
- @_routes ||= load_routes
174
- end
175
- end
176
-
177
172
  MODULE_DELIMITER = "::"
178
173
  private_constant :MODULE_DELIMITER
179
174
 
@@ -216,6 +211,41 @@ module Hanami
216
211
  providers.detect { |provider| component_name.include?(provider.namespace.to_s) }
217
212
  end
218
213
 
214
+ def router
215
+ @_mutex.synchronize do
216
+ @_router ||= load_router
217
+ end
218
+ end
219
+
220
+ def load_router
221
+ Router.new(
222
+ routes: routes,
223
+ resolver: resolver,
224
+ **configuration.router.options,
225
+ ) do
226
+ use Hanami.application[:rack_monitor]
227
+
228
+ Hanami.application.config.for_each_middleware do |m, *args, &block|
229
+ use(m, *args, &block)
230
+ end
231
+ end
232
+ end
233
+
234
+ def routes
235
+ require File.join(configuration.root, configuration.router.routes_path)
236
+ routes_class = autodiscover_application_constant(configuration.router.routes_class_name)
237
+ routes_class.routes
238
+ rescue LoadError
239
+ proc {}
240
+ end
241
+
242
+ def resolver
243
+ config.router.resolver.new(
244
+ slices: slices,
245
+ inflector: inflector
246
+ )
247
+ end
248
+
219
249
  private
220
250
 
221
251
  def prepare_base_load_path
@@ -312,13 +342,6 @@ module Hanami
312
342
  end
313
343
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
314
344
 
315
- def load_routes
316
- require File.join(configuration.root, configuration.router.routes_path)
317
- routes_class = autodiscover_application_constant(configuration.router.routes_class_name)
318
- routes_class.routes
319
- rescue LoadError # rubocop:disable Lint/SuppressedException
320
- end
321
-
322
345
  def load_settings
323
346
  prepare_base_load_path
324
347
  require File.join(configuration.root, configuration.settings_path)
@@ -342,24 +365,7 @@ module Hanami
342
365
 
343
366
  application.boot
344
367
 
345
- resolver = application.config.router.resolver.new(
346
- slices: application.slices,
347
- inflector: application.inflector
348
- )
349
-
350
- router = Application::Router.new(
351
- routes: application.routes,
352
- resolver: resolver,
353
- **application.configuration.router.options,
354
- ) do
355
- use application[:rack_monitor]
356
-
357
- application.config.for_each_middleware do |m, *args, &block|
358
- use(m, *args, &block)
359
- end
360
- end
361
-
362
- @app = router.to_rack_app
368
+ @app = application.router.to_rack_app
363
369
  end
364
370
  # rubocop:enable Metrics/AbcSize, Metrics/MethodLength
365
371
 
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "hanami/assets/configuration"
4
+ require "dry/configurable"
5
+
6
+ module Hanami
7
+ module Assets
8
+ # @since 2.0.0
9
+ # @api public
10
+ class ApplicationConfiguration
11
+ include Dry::Configurable
12
+
13
+ setting :server_url, default: "http://localhost:8080"
14
+
15
+ # @since 2.0.0
16
+ # @api private
17
+ def initialize(*)
18
+ super
19
+
20
+ @base_configuration = Assets::Configuration.new
21
+ end
22
+
23
+ # @since 2.0.0
24
+ # @api private
25
+ def finalize!
26
+ end
27
+
28
+ # Returns the list of available settings
29
+ #
30
+ # @return [Set]
31
+ #
32
+ # @since 2.0.0
33
+ # @api private
34
+ def settings
35
+ base_configuration.settings + self.class.settings
36
+ end
37
+
38
+ private
39
+
40
+ # @since 2.0.0
41
+ # @api private
42
+ attr_reader :base_configuration
43
+
44
+ # @since 2.0.0
45
+ # @api private
46
+ def method_missing(name, *args, &block)
47
+ if config.respond_to?(name)
48
+ config.public_send(name, *args, &block)
49
+ elsif base_configuration.respond_to?(name)
50
+ base_configuration.public_send(name, *args, &block)
51
+ else
52
+ super
53
+ end
54
+ end
55
+
56
+ # @since 2.0.0
57
+ # @api private
58
+ def respond_to_missing?(name, _incude_all = false)
59
+ config.respond_to?(name) || base_configuration.respond_to?(name) || super
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/configurable"
4
+
5
+ module Hanami
6
+ module Assets
7
+ # @since 2.0.0
8
+ # @api public
9
+ class Configuration
10
+ include Dry::Configurable
11
+
12
+ # Initialize the Configuration
13
+ #
14
+ # @yield [config] the configuration object
15
+ #
16
+ # @return [Configuration]
17
+ #
18
+ # @since 2.0.0
19
+ # @api private
20
+ def initialize(*)
21
+ super
22
+ yield self if block_given?
23
+ end
24
+
25
+ # Returns the list of available settings
26
+ #
27
+ # @return [Set]
28
+ #
29
+ # @since 2.0.0
30
+ # @api private
31
+ def settings
32
+ self.class.settings
33
+ end
34
+
35
+ private
36
+
37
+ # @since 2.0.0
38
+ # @api private
39
+ def method_missing(name, *args, &block)
40
+ if config.respond_to?(name)
41
+ config.public_send(name, *args, &block)
42
+ else
43
+ super
44
+ end
45
+ end
46
+
47
+ # @since 2.0.0
48
+ # @api private
49
+ def respond_to_missing?(name, _incude_all = false)
50
+ config.respond_to?(name) || super
51
+ end
52
+ end
53
+ end
54
+ end
@@ -28,7 +28,7 @@ module Hanami
28
28
  attr_reader :actions
29
29
  attr_reader :middleware
30
30
  attr_reader :router
31
- attr_reader :views
31
+ attr_reader :views, :assets
32
32
 
33
33
  attr_reader :environments
34
34
  private :environments
@@ -42,12 +42,22 @@ module Hanami
42
42
  self.root = Dir.pwd
43
43
  self.settings_store = Application::Settings::DotenvStore.new.with_dotenv_loaded
44
44
 
45
+ @assets = begin
46
+ require_path = "hanami/assets/application_configuration"
47
+ require require_path
48
+ Hanami::Assets::ApplicationConfiguration.new
49
+ rescue LoadError => e
50
+ raise e unless e.path == require_path
51
+ require_relative "configuration/null_configuration"
52
+ NullConfiguration.new
53
+ end
54
+
45
55
  # Config for actions (same for views, below) may not be available if the gem isn't
46
56
  # loaded; fall back to a null config object if it's missing
47
57
  @actions = begin
48
58
  require_path = "hanami/action/application_configuration"
49
59
  require require_path
50
- Hanami::Action::ApplicationConfiguration.new
60
+ Hanami::Action::ApplicationConfiguration.new(assets_server_url: assets.server_url)
51
61
  rescue LoadError => e
52
62
  raise e unless e.path == require_path
53
63
  require_relative "configuration/null_configuration"
@@ -82,6 +92,7 @@ module Hanami
82
92
  apply_env_config
83
93
 
84
94
  # Finalize nested configurations
95
+ assets.finalize!
85
96
  actions.finalize!
86
97
  views.finalize!
87
98
  logger.finalize!
@@ -8,7 +8,7 @@ module Hanami
8
8
  module Version
9
9
  # @since 0.9.0
10
10
  # @api private
11
- VERSION = "2.0.0.alpha3"
11
+ VERSION = "2.0.0.alpha4"
12
12
 
13
13
  # @since 0.9.0
14
14
  # @api private
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hanami
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.alpha3
4
+ version: 2.0.0.alpha4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luca Guidi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-11-09 00:00:00.000000000 Z
11
+ date: 2021-12-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -222,15 +222,19 @@ files:
222
222
  - lib/hanami/application/container/boot/logger.rb
223
223
  - lib/hanami/application/container/boot/rack_logger.rb
224
224
  - lib/hanami/application/container/boot/rack_monitor.rb
225
+ - lib/hanami/application/container/boot/routes_helper.rb
225
226
  - lib/hanami/application/container/boot/settings.rb
226
227
  - lib/hanami/application/router.rb
227
228
  - lib/hanami/application/routes.rb
229
+ - lib/hanami/application/routes_helper.rb
228
230
  - lib/hanami/application/routing/middleware/stack.rb
229
231
  - lib/hanami/application/routing/resolver.rb
230
232
  - lib/hanami/application/routing/resolver/node.rb
231
233
  - lib/hanami/application/routing/resolver/trie.rb
232
234
  - lib/hanami/application/settings.rb
233
235
  - lib/hanami/application/settings/dotenv_store.rb
236
+ - lib/hanami/assets/application_configuration.rb
237
+ - lib/hanami/assets/configuration.rb
234
238
  - lib/hanami/boot.rb
235
239
  - lib/hanami/cli/application/cli.rb
236
240
  - lib/hanami/cli/application/command.rb
@@ -272,7 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
272
276
  - !ruby/object:Gem::Version
273
277
  version: 1.3.1
274
278
  requirements: []
275
- rubygems_version: 3.2.3
279
+ rubygems_version: 3.2.29
276
280
  signing_key:
277
281
  specification_version: 4
278
282
  summary: The web, with simplicity