module

Krikri::ConditionalEvaluator

Constants

REGEX_BARE_CALL = /\A\w+\s*\(.*\)\z/
REGEX_DIGITS = /\d+/
REGEX_ENV_LOOKUP_ORIGIN = /\Alookup\s*\(\s*['"]env['"]\s*,\s*'([^']*)'\s*\)\z|\Alookup\s*\(\s*['"]env['"]\s*,\s*"([^"]*)"\s*\)\z/

The whole-expression bare lookup('env', LITERAL) whose real 2.19.11 lineage origin is the tagged "<environment variable 'LITERAL'>" - the only lookup origin shape this engine emits in strict-conditional error wording (both quote styles accept either arg spelling; the arg group is picked by which capture matched).

REGEX_GENERIC_IS_TEST = /\bis\s+(not\s+)?\w/
REGEX_MATCH_SEARCH_TEST = /^(.+?)\s+is\s+(not\s+)?(match|search)\((.+)\)\s*$/
REGEX_SAME_FILE_TEST = /^(.+?)\s+is\s+(not\s+)?(?:is_)?same_file\((.+)\)\s*$/
REGEX_SUBSET_TEST = /^(.+?)\s+is\s+(not\s+)?(issubset|issuperset|subset|superset|contains)\((.+)\)\s*$/
REGEX_VERSION_TEST = /\A(.+?)\s+is\s+(version|version_compare)\(/

Precompiled regular expressions for condition parsing. Eliminates runtime regex compilation in hot when: and test paths. version_compare is Ansible's older alias for the version test and is still accepted by ansible-core 2.19 (verified live, round173). Missing it here was benign while conditionals were lenient - the expression fell through to the generic comparison splitter, which mistook the >= INSIDE the quoted operator argument for a real comparison operator and quietly evaluated false. Once 0.9.548 made a bare undefined reference RAISE, that same misparse started hard-failing the task ("'')' is undefined") for the extremely common x is version_compare(min, '>=') version-gate idiom.

URN_PATTERN = /^urn:[a-zA-Z0-9][a-zA-Z0-9-]{0,31}:[a-zA-Z0-9()+,\-.:=@;$_!*'%\/?#]+$/i

Class methods

allow_broken_conditionals?
Source
cached_regex(pattern : String, anchored : Bool) : Regex
Source
compile_time_name_error?(condition : String, vars : Hash(String, JSON::Any)) : Bool

Compile-time-invalid filter/test name check for the strict-undefined PROBE (Krikri.strict_undefined_probe_message): true when the condition carries a name the evaluators cannot resolve. ansible-core COMPILES the whole template before evaluating any operand, so real fails such an expression with the Syntax error wording no matter which clause would have been reached first - the probe must decline (not raise an undefined-value message over it) so #evaluate_measured's own validate_filter_names/validate_test_names wording surfaces unchanged.

Source
evaluate(condition : String, vars : Hash(String, JSON::Any), strict : Bool = false, raise_undefined : Bool = false) : Bool
Source
template_delimiter_error(condition : String) : String | Nil

Ansible never pre-renders {{ }} out of a conditional: both when: and assert's that: items are compiled as raw Jinja EXPRESSIONS (Templar.evaluate_expression -> Parser(state="variable")), so a balanced {{ ... }} anywhere outside a string literal is a TemplateSyntaxError and create_template_error(is_expression=True) composes "Syntax error in expression." + " Template delimiters are not supported in expressions." + ": " + Jinja's own parse message (the message property drops the trailing period when joining the cause - live-verified byte for byte vs ansible-playbook 2.19.11: when: 1 >= {{ 1 }} and assert: that: [a.b >= {{ x }}] both fatal "Syntax error in expression. Template delimiters are not supported in expressions: expected token ':', got '}'", found via chriswayg.mailcow's and rockandska.rabbitmq's own assert preflight tasks, rounds 1500413/1500208, where this engine rendered the delimiters away and PASSED the task).

Returns the composed message, or nil when the conditional is fine:

  • whole-template conditionals ({{ x }} and nothing else) take Ansible's legacy all-template path instead - deprecation warning, then render (live-verified: when: "{{ 1 == 1 }}" warns and passes), so they are excluded here exactly the way the caller's maybe_conditional_delimiters_deprecation detects them;
  • a {{ }} inside a string literal (that: name == '{{ x }}') is a CONST template Jinja parses fine - quoted spans are skipped;
  • the parse message is Jinja's for this shape: a balanced {{ }} misparses as a nested dict literal, so the parse dies at the inner } expecting the dict's :; an unclosed {{ runs off the end of the template. {% %}/{# #} in a conditional is likewise a Jinja parse error in real, but its message is position/content-dependent and not emulated here yet.
Source
whole_condition_is_defined_test?(condition : String) : Bool

Whether the WHOLE condition is a single is defined-family test (optionally over a filter chain feeding the test). The strict- undefined probe declines this shape: real Ansible never fails a conditional on it - the test's tolerance covers the entire chain feeding it (live-verified vs 2.19.4: when: d['missing'] is defined skips, never errors; and hwwilliams.duplicati's when: duplicati_release_url_list | list | first is defined, issue #730, likewise skips with an undefined head where the probe's strict evaluation raised) - and the is-defined handlers below answer the test leniently instead.

Source

Nested types