dash 3.2.1 → 4.0.1

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/lib/dash/cli/app/boot.rb +2 -2
  3. data/lib/dash/cli/app.rb +1 -1
  4. data/lib/dash/cli/base.rb +1 -1
  5. data/lib/dash/cli/doctor/endpoint_checks.rb +1 -1
  6. data/lib/dash/cli/doctor/host_checks.rb +29 -8
  7. data/lib/dash/cli/main.rb +5 -5
  8. data/lib/dash/cli/proxy/legacy_rename.rb +58 -0
  9. data/lib/dash/cli/proxy/loadbalancer_reboot.rb +1 -1
  10. data/lib/dash/cli/proxy/reboot.rb +8 -8
  11. data/lib/dash/cli/proxy.rb +14 -10
  12. data/lib/dash/commander.rb +1 -1
  13. data/lib/dash/commands/accessory/proxy.rb +1 -1
  14. data/lib/dash/commands/app/execution.rb +1 -1
  15. data/lib/dash/commands/app/proxy.rb +1 -1
  16. data/lib/dash/commands/app.rb +1 -1
  17. data/lib/dash/commands/docker.rb +35 -1
  18. data/lib/dash/commands/loadbalancer.rb +47 -17
  19. data/lib/dash/commands/lock.rb +1 -1
  20. data/lib/dash/commands/proxy/cert_transfer.rb +4 -4
  21. data/lib/dash/commands/proxy.rb +117 -15
  22. data/lib/dash/commands/prune.rb +1 -1
  23. data/lib/dash/configuration/accessory.rb +2 -2
  24. data/lib/dash/configuration/docs/accessory.yml +3 -3
  25. data/lib/dash/configuration/docs/configuration.yml +1 -1
  26. data/lib/dash/configuration/docs/proxy.yml +38 -38
  27. data/lib/dash/configuration/loadbalancer.rb +2 -2
  28. data/lib/dash/configuration/proxy/acme.rb +5 -5
  29. data/lib/dash/configuration/proxy/boot.rb +2 -4
  30. data/lib/dash/configuration/proxy/run.rb +10 -10
  31. data/lib/dash/configuration/proxy.rb +36 -14
  32. data/lib/dash/configuration/role.rb +2 -2
  33. data/lib/dash/configuration/validator/proxy.rb +23 -23
  34. data/lib/dash/configuration.rb +8 -8
  35. data/lib/dash/utils.rb +1 -1
  36. data/lib/dash/version.rb +1 -1
  37. metadata +2 -1
@@ -8,7 +8,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
8
8
  # provides the hostnames at runtime.
9
9
  # On-demand TLS joins loadbalancer and ssl_domains as a source of hostnames
10
10
  # that only exist at handshake time - demanding a static host here would
11
- # reject the one shape kamal-proxy requires for it.
11
+ # reject the one shape dash-proxy requires for it.
12
12
  if config["host"].blank? && config["hosts"].blank? && config["ssl"] && config["loadbalancer"].blank? &&
13
13
  config.dig("ssl_domains", "source").blank? && ssl_config["on_demand_url"].blank?
14
14
  error "Must set a host to enable automatic SSL"
@@ -113,7 +113,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
113
113
  end
114
114
  end
115
115
 
116
- # Same source shape as ssl_domains. The interval minimum is kamal-proxy's
116
+ # Same source shape as ssl_domains. The interval minimum is dash-proxy's
117
117
  # own (MinRedirectsInterval, 10s) - it rejects a smaller one after the SSH
118
118
  # round trip, so catch it here at config time.
119
119
  def validate_redirects_source!(redirects_source)
@@ -132,7 +132,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
132
132
  end
133
133
  end
134
134
 
135
- # kamal-proxy only logs a warning for a DNS provider it does not recognise
135
+ # dash-proxy only logs a warning for a DNS provider it does not recognise
136
136
  # and then carries on with no provider at all, so the symptom is a
137
137
  # certificate that never issues rather than a failed boot. Catch it here,
138
138
  # before any host is contacted.
@@ -185,7 +185,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
185
185
  end
186
186
 
187
187
  # The whole TLS surface lives in the one `ssl` hash: certificate material,
188
- # on-demand issuance and the mTLS client CA. kamal-proxy rejects the
188
+ # on-demand issuance and the mTLS client CA. dash-proxy rejects the
189
189
  # on-demand combinations outright rather than picking a winner
190
190
  # (ServiceOptions.Validate), so there is no precedence to document - only
191
191
  # a deploy that would fail after the SSH round-trip. Fail here.
@@ -231,13 +231,13 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
231
231
 
232
232
  # An RFC 9110 token, which is both a valid header field name and a valid
233
233
  # cookie name. For a header, a space or a colon would also break the
234
- # '<name>: <value>' encoding kamal-proxy cuts at the first colon.
234
+ # '<name>: <value>' encoding dash-proxy cuts at the first colon.
235
235
  TOKEN = /\A[!#$%&'*+\-.^_`|~0-9A-Za-z]+\z/
236
236
 
237
237
  POOL_KEYS = %w[ max_conns max_idle_conns idle_conn_timeout dial_timeout try_duration try_interval ].freeze
238
238
 
239
239
  # A zero is meaningful for most of these, so only negatives are refused.
240
- # kamal-proxy clamps them rather than failing when it reads saved state, and
240
+ # dash-proxy clamps them rather than failing when it reads saved state, and
241
241
  # rejects them from a client — this is the client.
242
242
  def validate_tuning!
243
243
  target = config["target"] || {}
@@ -258,13 +258,13 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
258
258
  with_context("request_timeout") { error "cannot be negative" }
259
259
  end
260
260
 
261
- # Sibling consistency: kamal-proxy clamps a negative --target-timeout as
261
+ # Sibling consistency: dash-proxy clamps a negative --target-timeout as
262
262
  # silently as a negative --request-timeout.
263
263
  if config["response_timeout"].to_f.negative?
264
264
  with_context("response_timeout") { error "cannot be negative" }
265
265
  end
266
266
 
267
- # Both maps reach kamal-proxy's one parsePathTimeouts, which refuses a
267
+ # Both maps reach dash-proxy's one parsePathTimeouts, which refuses a
268
268
  # negative duration.
269
269
  %w[ path_response_timeouts path_request_timeouts ].each do |key|
270
270
  with_context(key) do
@@ -312,7 +312,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
312
312
  end
313
313
  end
314
314
 
315
- # kamal-proxy rejects canonical_host + on-demand TLS after the SSH round
315
+ # dash-proxy rejects canonical_host + on-demand TLS after the SSH round
316
316
  # trip (canonical redirection needs a fixed host, on-demand TLS has none),
317
317
  # and a canonical host outside the host list redirects every request to a
318
318
  # hostname this service does not serve.
@@ -393,7 +393,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
393
393
  end
394
394
 
395
395
  # Go carries the request host in Request.Host rather than the header map,
396
- # so kamal-proxy refuses the rule instead of silently doing nothing.
396
+ # so dash-proxy refuses the rule instead of silently doing nothing.
397
397
  if direction == "request" && name.to_s.downcase == "host"
398
398
  return error "cannot rewrite the Host header"
399
399
  end
@@ -408,7 +408,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
408
408
 
409
409
  # The pattern is deliberately not compiled: Go's RE2 and Ruby's Onigmo differ
410
410
  # at the edges (Ruby rejects Go's `(?P<name>...)`), and refusing a pattern
411
- # kamal-proxy would have accepted is worse than finding out at deploy time.
411
+ # dash-proxy would have accepted is worse than finding out at deploy time.
412
412
  def validate_path_rules!(key, redirect:)
413
413
  Array(config[key]).each_with_index do |rule, index|
414
414
  with_context(key) do
@@ -419,7 +419,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
419
419
  next error "needs both from and to"
420
420
  end
421
421
 
422
- # The wire format is '<from>=<to>' and kamal-proxy cuts at the
422
+ # The wire format is '<from>=<to>' and dash-proxy cuts at the
423
423
  # FIRST '=', so an '=' inside the pattern silently builds a rule
424
424
  # for a different path.
425
425
  if rule["from"].to_s.include?("=")
@@ -443,7 +443,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
443
443
  end
444
444
  end
445
445
 
446
- # kamal-proxy's --rate-limit is a Float64, so half a request per second is a
446
+ # dash-proxy's --rate-limit is a Float64, so half a request per second is a
447
447
  # legal rate. The docs example can only demonstrate one numeric type, and an
448
448
  # Integer there would reject 0.5 — so the shape is checked by hand instead.
449
449
  def validate_key_override!(key, value)
@@ -488,7 +488,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
488
488
  end
489
489
 
490
490
  # Rate limiting and the IP allow list are only as correct as the address they
491
- # key on, so kamal-proxy ties the three settings together with rules that
491
+ # key on, so dash-proxy ties the three settings together with rules that
492
492
  # otherwise surface only once the deploy has reached a host.
493
493
  def validate_access_control!
494
494
  allow_ips = Array(config["allow_ips"])
@@ -531,7 +531,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
531
531
  error "trusted_proxies has no effect without allow_ips, deny_ips or rate_limit"
532
532
  end
533
533
 
534
- # Unconditional: even without allow_ips/rate_limit, kamal-proxy rewrites
534
+ # Unconditional: even without allow_ips/rate_limit, dash-proxy rewrites
535
535
  # the client address (and X-Forwarded-For) from this header, so honoring
536
536
  # it from untrusted peers is a client-spoofable identity.
537
537
  if client_ip["header"].present? && trusted_proxies.empty?
@@ -549,7 +549,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
549
549
  end
550
550
  end
551
551
 
552
- # kamal-proxy serves the health check path without an address check and
552
+ # dash-proxy serves the health check path without an address check and
553
553
  # without a rate limit so deploys keep working, which makes '/' a hole
554
554
  # straight through all three features.
555
555
  if (allow_ips.any? || deny_ips.any? || rate_limited) && config.dig("healthcheck", "path") == "/"
@@ -618,7 +618,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
618
618
 
619
619
  Array(compress["content_types"]).each do |content_type|
620
620
  # A main-type wildcard would match everything the proxy cannot see
621
- # inside, so kamal-proxy allows a wildcard only in the subtype.
621
+ # inside, so dash-proxy allows a wildcard only in the subtype.
622
622
  unless content_type.to_s.match?(%r{\A[^/*\s]+/[^/\s]+\z})
623
623
  error "content_types entry '#{content_type}' must be a media type such as text/html or text/*"
624
624
  end
@@ -632,7 +632,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
632
632
  REFUSED_TLS_VERSIONS = %w[ 1.0 1.1 ].freeze
633
633
  RUN_TIMEOUTS = %w[ read_header_timeout read_timeout write_timeout idle_timeout shutdown_timeout ].freeze
634
634
 
635
- # kamal-proxy validates these three in preRun, so a typo does not fail the
635
+ # dash-proxy validates these three in preRun, so a typo does not fail the
636
636
  # deploy - it stops the proxy container from booting at all.
637
637
  def validate_run_server_options!(run_config)
638
638
  with_context("run") do
@@ -656,7 +656,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
656
656
  end
657
657
  end
658
658
 
659
- # Accepts the spellings kamal-proxy's normalizeTLSVersion reduces - a `tls`
659
+ # Accepts the spellings dash-proxy's normalizeTLSVersion reduces - a `tls`
660
660
  # or `tlsv` prefix, and `_` for `.` - so a config written for upstream is not
661
661
  # rejected here and accepted there.
662
662
  def validate_min_tls!(value)
@@ -673,7 +673,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
673
673
  end
674
674
  end
675
675
 
676
- # kamal-proxy reads the cache policy only when --cache is set and ignores it
676
+ # dash-proxy reads the cache policy only when --cache is set and ignores it
677
677
  # otherwise, so a tuned block with no `enabled` is a cache that silently
678
678
  # never caches - this issue's own predicted first support question.
679
679
  def validate_cache!(cache)
@@ -682,12 +682,12 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
682
682
  with_context("cache") do
683
683
  if (orphaned = cache.keys - [ "enabled" ]).any?
684
684
  error "#{orphaned.first} has no effect without enabled: true - " \
685
- "kamal-proxy ignores the cache policy entirely when --cache is absent"
685
+ "dash-proxy ignores the cache policy entirely when --cache is absent"
686
686
  end
687
687
  end
688
688
  end
689
689
 
690
- # An unsupported store is rejected in kamal-proxy's preRun, which means the
690
+ # An unsupported store is rejected in dash-proxy's preRun, which means the
691
691
  # proxy container exits at boot rather than a deploy failing. Catch it before
692
692
  # the fleet loses its proxy.
693
693
  def validate_cache_store!(cache)
@@ -708,7 +708,7 @@ class Dash::Configuration::Validator::Proxy < Dash::Configuration::Validator
708
708
  if basic_auth["username"].blank?
709
709
  error "Missing username setting (required when basic_auth is set)"
710
710
  elsif basic_auth["username"].to_s.include?(":")
711
- # kamal-proxy cuts <username>:<password> at the first colon, so a
711
+ # dash-proxy cuts <username>:<password> at the first colon, so a
712
712
  # colon in the username would silently truncate it.
713
713
  error "Invalid username: cannot contain a colon"
714
714
  end
@@ -478,7 +478,7 @@ class Dash::Configuration
478
478
  return true if offenders.empty?
479
479
 
480
480
  warn "Host(s) #{offenders.sort.join(", ")}: proxy_protocol is enabled without proxy_protocol_allow_ips, " \
481
- "so kamal-proxy honours a PROXY header from any peer that can reach the port. That header sets the client " \
481
+ "so dash-proxy honours a PROXY header from any peer that can reach the port. That header sets the client " \
482
482
  "address `allow_ips`, `rate_limit` and the access log all use. Name the load balancers you actually run."
483
483
 
484
484
  true
@@ -503,11 +503,11 @@ class Dash::Configuration
503
503
  return true if offenders.empty?
504
504
 
505
505
  raise Dash::ConfigurationError, "Role(s) #{offenders.map(&:name).join(", ")}: " \
506
- "proxy/sleep requires proxy/run/docker_socket - kamal-proxy can only stop and start containers " \
506
+ "proxy/sleep requires proxy/run/docker_socket - dash-proxy can only stop and start containers " \
507
507
  "through the container runtime socket, and it is not mounted into the proxy without it"
508
508
  end
509
509
 
510
- # kamal-proxy resolves a zero max_idle_conns to its default of 100
510
+ # dash-proxy resolves a zero max_idle_conns to its default of 100
511
511
  # (target_pool.go resolves defaults from zeros), so the one value an
512
512
  # operator writes to mean "keep none" is the one value that cannot mean it.
513
513
  # Legal, so warn rather than raise.
@@ -518,14 +518,14 @@ class Dash::Configuration
518
518
  return true if offenders.empty?
519
519
 
520
520
  warn "Role(s) #{offenders.map(&:name).join(", ")}: target/max_idle_conns: 0 means the proxy default of 100, " \
521
- "not \"keep none\" - kamal-proxy resolves its defaults from zeros. Leave it unset for the default, " \
521
+ "not \"keep none\" - dash-proxy resolves its defaults from zeros. Leave it unset for the default, " \
522
522
  "or set 1 for the practical minimum."
523
523
 
524
524
  true
525
525
  end
526
526
 
527
527
  # `intercept_errors` discards the app's error body and renders the proxy's own
528
- # page instead. With no pages to render, kamal-proxy falls back to a bare
528
+ # page instead. With no pages to render, dash-proxy falls back to a bare
529
529
  # plaintext status line — so the app's error page is thrown away and replaced
530
530
  # by the words "Bad Gateway". Legal, and almost never the intent.
531
531
  def ensure_intercepted_errors_have_pages
@@ -535,7 +535,7 @@ class Dash::Configuration
535
535
  return true if offenders.empty?
536
536
 
537
537
  warn "Role(s) #{offenders.map(&:name).join(", ")}: intercept_errors is set but no error_pages_path is " \
538
- "configured, so kamal-proxy replaces the app's error page with a bare plaintext status line. " \
538
+ "configured, so dash-proxy replaces the app's error page with a bare plaintext status line. " \
539
539
  "Set `error_pages_path:` to serve your own pages, or remove `intercept_errors` to let the app's through."
540
540
 
541
541
  true
@@ -543,7 +543,7 @@ class Dash::Configuration
543
543
 
544
544
  # Rate limiting and IP deny rules are only as correct as the address they key
545
545
  # on. `forward_headers: true` says something sits in front of the proxy, and
546
- # without `trusted_proxies` kamal-proxy keys on that something's address
546
+ # without `trusted_proxies` dash-proxy keys on that something's address
547
547
  # rather than the client's — so the limiter throttles the whole world as one
548
548
  # client (or nobody), and a deny list denies nobody it was written for. Warn
549
549
  # rather than raise: the config is legal, just almost certainly not what was
@@ -568,7 +568,7 @@ class Dash::Configuration
568
568
 
569
569
  offenders.each do |role_name, features|
570
570
  warn "Role #{role_name}: #{features.join(" and ")} is set with forward_headers, " \
571
- "but no proxy/client_ip/trusted_proxies. kamal-proxy will key on the address of " \
571
+ "but no proxy/client_ip/trusted_proxies. dash-proxy will key on the address of " \
572
572
  "whatever sits in front of it, not on the client's — so the rules apply to every " \
573
573
  "visitor as one client, or to none of them. Declare the proxies in front with " \
574
574
  "`client_ip: trusted_proxies:`."
data/lib/dash/utils.rb CHANGED
@@ -45,7 +45,7 @@ module Dash::Utils
45
45
  options.flatten.compact
46
46
  end
47
47
 
48
- # kamal-proxy takes durations as Go duration strings; deploy.yml takes plain
48
+ # dash-proxy takes durations as Go duration strings; deploy.yml takes plain
49
49
  # seconds. Zero is a real value (it disables the timeout), so only nil drops out.
50
50
  #
51
51
  # A value that already carries a unit is passed through untouched. Appending
data/lib/dash/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Dash
2
- VERSION = "3.2.1"
2
+ VERSION = "4.0.1"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dash
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.2.1
4
+ version: 4.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mikael Henriksson
@@ -203,6 +203,7 @@ files:
203
203
  - lib/dash/cli/main/migrate.rb
204
204
  - lib/dash/cli/proxy.rb
205
205
  - lib/dash/cli/proxy/drift.rb
206
+ - lib/dash/cli/proxy/legacy_rename.rb
206
207
  - lib/dash/cli/proxy/loadbalancer_claim.rb
207
208
  - lib/dash/cli/proxy/loadbalancer_reboot.rb
208
209
  - lib/dash/cli/proxy/reboot.rb