Krikri::TemplateActionPlugin
Inherits Krikri::ActionPlugin < Reference < Object
Constants
{% for (key, value) in dict.items() %} - the idiomatic real-
Jinja2 way to iterate a dict's key/value pairs (mysql_hardening's
own hardening.cnf.j2 writes it exactly this way). Only the parens
around the loop variables need stripping - the vendored crinja
fork's .items() is a real method on Hash values (see
lib/crinja/src/runtime/python_hash_methods.cr), so .items()
itself is left alone and evaluated for real rather than textually
stripped. Was NOT always true: an earlier FOR_ITEMS_METHOD regex
used to strip .items() out entirely and rely on Crinja's bare
{% for k, v in dict %} already yielding (key, value) pairs - a
real deviation from Python/Jinja2 (where a bare dict for-loop
iterates keys only) that happened to produce the right pairs, but
silently broke .items() | sort (jtyr.nsswitch's own nsswitch.
conf.j2: {% for key, val in nsswitch_config.items() | sort %})
by sorting the raw dict instead of its item tuples. Removed once
.items() support landed in the fork - verified live against
both jtyr.nsswitch (.items() | sort) and jtyr.motd (.items()
alone, item.motd.j2), byte-for-byte identical to Ansible.
Method-call .join( form that Jinja2 permits but Crinja's
parser rejects: {{ "SEP".join(LIST) }} is the standard sep.join(list)
idiom (dev-sec os_hardening's securetty template uses it). Rewritten
into the equivalent LIST | join("SEP") filter, which Crinja supports.
$1 = the sep string literal, $2 = the list expression being joined.
[^"\\] excludes \n too (not just cosmetic): a template
with an ODD number of " characters total has no valid second
quote to close a literal at all, so the unbounded (?:[^"\\]|\\.)*
tries every possible split of the REST OF THE FILE between its two
alternatives looking for one - mrlesmithjr.netdata's own 5934-line
netdata.conf.j2 has exactly one stray " in the whole file, and
this pattern alone was the one that actually overflowed PCRE2's
JIT match-time stack.
Real quoted string literals here are always single-line.
Method-call .split(...) - real Python's own str.split() method
(not a Jinja2 filter - Jinja2 exposes native object methods
directly), rejected by Crinja's parser the same way .items()
was. dev-sec apache_hardening's own httpd.conf.j2 uses it to pick
the minor version out of an already-parsed apache_version
string: {% if apache_version.split('.')[1] == '4' %}. Rewritten
to VAR | split(ARGS) (see jinja_filters.cr's own :split filter).
$1 = the dotted/bracketed variable expression being split
(apache_version, _apache_version.stdout, ...), $2 = the raw
argument text (possibly empty, for Python's own no-arg whitespace-
split form), $3 = an optional trailing literal numeric index
(apache_version.split('.')[1] - split()'s result is almost
always indexed immediately). Crinja can parse (EXPR).1 (dot-
numeric indexing on a parenthesized expression) but NOT (EXPR)[1]
(bracket indexing on one) - confirmed by direct testing, not
assumed - so a captured trailing [N] is rewritten to .N rather
than carried through as-is; #rewrite_crinja_compat's own gsub
call is responsible for making that substitution (see below).
Group 1 alternates .ident/[...] suffixes in any order - real
bug found benchmarking githubixx.ansible_role_wireguard's own
wg.conf.j2: the old pattern only allowed dot-segments before any
bracket-index suffix (foo.bar[0]), so hostvars[host]. wireguard_address.split('/')[0] (a bracket, THEN more dots) never
matched starting from "hostvars" at all - the regex engine instead
found a match starting mid-expression, from "wireguard_address"
alone, silently leaving the "hostvars[host]." prefix untouched and
producing the syntactically invalid "hostvars[host].(wireguard_
address | split('/', 0))" (a stray .( Crinja's own parser
rejects outright: "Expected IDENTIFIER, got LEFT_PAREN").
A {% if EXPR %}/{% elif EXPR %} statement tag - $1/$4 are the
optional whitespace-control markers, either the trim - or the
keep + (both preserved as-is on rewrite - the + must survive
so the vendored Crinja fork's native + handling still sees it;
the + forms used to be pre-stripped out of the whole template,
see #render_template's comment for why that's gone), $2 the
keyword, $3 the condition - each is wrapped with | pytruthy
below (see the comment inside the gsub block) so a falsy-but-
non-empty condition behaves like real Jinja2. Deliberately does
NOT match {% for %} - for x in list
is valid Crinja syntax on its own and must never be touched.
Instance methods
Execute action on controller Returns: modified params to send to remote plugin, or nil if action failed