Class: RubyExpandinator

Inherits:
Object show all
Defined in:
lib/ceedling/ruby_expandinator.rb

Overview

Centralized, security-gated handling of Ceedling's inline Ruby string expansion feature (#{...} embedded in project configuration values). This executes arbitrary Ruby sourced from YAML content, so it is disabled by default and can only be enabled via the --ruby-replacement command line flag (never from YAML itself).

Instance Method Summary collapse

Constructor Details

#initializeRubyExpandinator

Returns a new instance of RubyExpandinator.



17
18
19
# File 'lib/ceedling/ruby_expandinator.rb', line 17

def initialize
  @enabled = false
end

Instance Method Details

#check!(string, source:) ⇒ Object

Raises if string contains the Ruby-replacement pattern and the feature is not enabled. No-op (and no evaluation) otherwise. source is a short descriptive label for what was being processed -- Ceedling's config pipeline merges project.yml, mixins, and plugin config into one in-memory hash well before most call sites run, so there's no literal source-file/line available; the label is the best available context (e.g. "tool 'test_compiler' :executable", ":environment", ":mixins ↳ :load_paths").

Raises:



42
43
44
45
46
47
48
49
50
51
# File 'lib/ceedling/ruby_expandinator.rb', line 42

def check!(string, source:)
  return unless replacement?(string)
  return if @enabled

  raise CeedlingException.new(
    "Inline Ruby string expansion is disabled ⏩️ #{source} contains `\#{...}` Ruby code " +
    "but this feature is not enabled. Re-run with `--ruby-replacement` to allow it " +
    "(security-sensitive: only enable this for configuration you trust)."
  )
end

#enable!Object

One-directional: once enabled (via the --ruby-replacement CLI flag), nothing should be able to turn this back off mid-process.



23
24
25
# File 'lib/ceedling/ruby_expandinator.rb', line 23

def enable!
  @enabled = true
end

#enabled?Boolean

Returns:

  • (Boolean)


27
28
29
# File 'lib/ceedling/ruby_expandinator.rb', line 27

def enabled?
  @enabled
end

#expand(string, source:) ⇒ Object

Gated expansion: validates via check! (raises if disabled), then evaluates and returns the result if the pattern is present; returns string unchanged otherwise.



55
56
57
58
59
# File 'lib/ceedling/ruby_expandinator.rb', line 55

def expand(string, source:)
  return string unless replacement?(string)
  check!(string, source: source)
  Object.module_eval("\"" + string + "\"")
end

#replacement?(string) ⇒ Boolean

Pure pattern predicate -- no gating, no evaluation.

Returns:

  • (Boolean)


32
33
34
# File 'lib/ceedling/ruby_expandinator.rb', line 32

def replacement?(string)
  !!(string =~ PATTERNS::RUBY_STRING_REPLACEMENT)
end