Module: Dash::Utils
Defined Under Namespace
Classes: Sensitive
Constant Summary collapse
- DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX =
/\$(?!{[^\}]*\})/- NUMERIC_DURATION =
dash-proxy takes durations as Go duration strings; deploy.yml takes plain seconds. Zero is a real value (it disables the timeout), so only nil drops out.
A value that already carries a unit is passed through untouched. Appending "s" to it would not just be redundant, it would change the meaning: "5m" would become "5ms", which Go parses happily as five milliseconds. An operator who writes a Go duration should get the duration they wrote or an error from the proxy, never a silently different one.
/\A-?\d+(\.\d+)?\z/
Instance Method Summary collapse
-
#argumentize(argument, attributes, sensitive: false) ⇒ Object
Return a list of escaped shell arguments using the same named argument against the passed attributes (hash or array).
- #docker_arch ⇒ Object
- #escape_ascii_shell_value(value) ⇒ Object
-
#escape_shell_value(value) ⇒ Object
Escape a value to make it safe for shell use.
-
#filter_specific_items(filters, items) ⇒ Object
Apply a list of host or role filters, including wildcard matches.
-
#flatten_args(args) ⇒ Object
Flattens a one-to-many structure into an array of two-element arrays each containing a key-value pair.
- #join_commands(commands) ⇒ Object
- #older_version?(version, other_version) ⇒ Boolean
-
#optionize(args, with: nil, escape: true) ⇒ Object
Returns a list of shell-dashed option arguments.
- #redacted(value) ⇒ Object
- #seconds_duration(value) ⇒ Object
-
#sensitive ⇒ Object
Marks sensitive values for redaction in logs and human-visible output.
- #stable_sort!(elements, &block) ⇒ Object
Instance Method Details
#argumentize(argument, attributes, sensitive: false) ⇒ Object
Return a list of escaped shell arguments using the same named argument against the passed attributes (hash or array).
9 10 11 12 13 14 15 16 17 18 19 20 21 |
# File 'lib/dash/utils.rb', line 9 def argumentize(argument, attributes, sensitive: false) Array(attributes).flat_map do |key, value| if value.present? attr = "#{key}=#{escape_shell_value(value)}" attr = self.sensitive(attr, redaction: "#{key}=[REDACTED]") if sensitive [ argument, attr ] elsif value == false [ argument, "#{key}=false" ] else [ argument, key ] end end end |
#docker_arch ⇒ Object
125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/dash/utils.rb', line 125 def docker_arch arch = `docker info --format '{{.Architecture}}'`.strip case arch when /aarch64/ "arm64" when /x86_64/ "amd64" else arch end end |
#escape_ascii_shell_value(value) ⇒ Object
96 97 98 99 100 |
# File 'lib/dash/utils.rb', line 96 def escape_ascii_shell_value(value) value.to_s.dump .gsub(/`/, '\\\\`') .gsub(DOLLAR_SIGN_WITHOUT_SHELL_EXPANSION_REGEX, '\$') end |
#escape_shell_value(value) ⇒ Object
Escape a value to make it safe for shell use.
90 91 92 93 94 |
# File 'lib/dash/utils.rb', line 90 def escape_shell_value(value) value.to_s.scan(/[\x00-\x7F]+|[^\x00-\x7F]+/) \ .map { |part| part.ascii_only? ? escape_ascii_shell_value(part) : part } .join end |
#filter_specific_items(filters, items) ⇒ Object
Apply a list of host or role filters, including wildcard matches
103 104 105 106 107 108 109 110 111 112 113 114 115 |
# File 'lib/dash/utils.rb', line 103 def filter_specific_items(filters, items) matches = [] Array(filters).select do |filter| matches += Array(items).select do |item| # Only allow * for a wildcard # items are roles or hosts File.fnmatch(filter, item.to_s, File::FNM_EXTGLOB) end end matches.uniq end |
#flatten_args(args) ⇒ Object
Flattens a one-to-many structure into an array of two-element arrays each containing a key-value pair
65 66 67 |
# File 'lib/dash/utils.rb', line 65 def flatten_args(args) args.flat_map { |key, value| value.try(:map) { |entry| [ key, entry ] } || [ [ key, value ] ] } end |
#join_commands(commands) ⇒ Object
121 122 123 |
# File 'lib/dash/utils.rb', line 121 def join_commands(commands) commands.map(&:strip).join(" ") end |
#older_version?(version, other_version) ⇒ Boolean
137 138 139 |
# File 'lib/dash/utils.rb', line 137 def older_version?(version, other_version) Gem::Version.new(version.delete_prefix("v")) < Gem::Version.new(other_version.delete_prefix("v")) end |
#optionize(args, with: nil, escape: true) ⇒ Object
Returns a list of shell-dashed option arguments. If the value is true, it's treated like a value-less option.
A Sensitive value stays Sensitive: the rendered option keeps the real value
for execution and a redacted form for anything kamal prints - same contract
as argumentize's sensitive: kwarg, but decided per value by the caller.
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/dash/utils.rb', line 27 def optionize(args, with: nil, escape: true) = if with flatten_args(args).collect do |(key, value)| if value == true "--#{key}" else rendered = "--#{key}#{with}#{escape ? escape_shell_value(value) : value}" value.is_a?(Dash::Utils::Sensitive) ? sensitive(rendered, redaction: "--#{key}#{with}#{value.redaction}") : rendered end end else flatten_args(args).collect do |(key, value)| rendered = value == true ? nil : escape ? escape_shell_value(value) : value rendered = sensitive(rendered, redaction: value.redaction) if value.is_a?(Dash::Utils::Sensitive) [ "--#{key}", rendered ] end end .flatten.compact end |
#redacted(value) ⇒ Object
76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/dash/utils.rb', line 76 def redacted(value) case when value.respond_to?(:redaction) value.redaction when value.respond_to?(:transform_values) value.transform_values { |value| redacted value } when value.respond_to?(:map) value.map { |element| redacted element } else value end end |
#seconds_duration(value) ⇒ Object
58 59 60 61 62 |
# File 'lib/dash/utils.rb', line 58 def seconds_duration(value) return if value.nil? value.to_s.match?(NUMERIC_DURATION) ? "#{value}s" : value.to_s end |
#sensitive ⇒ Object
Marks sensitive values for redaction in logs and human-visible output.
Pass redaction: to change the default "[REDACTED]" redaction, e.g.
`sensitive "#arg=#secret", redaction: "#arg=xxxx"
72 73 74 |
# File 'lib/dash/utils.rb', line 72 def sensitive(...) Dash::Utils::Sensitive.new(...) end |
#stable_sort!(elements, &block) ⇒ Object
117 118 119 |
# File 'lib/dash/utils.rb', line 117 def stable_sort!(elements, &block) elements.sort_by!.with_index { |element, index| [ block.call(element), index ] } end |