Skip to content

[BUG]: ConfigLoader.load_config Jinja pass blanks non-env {{...}} placeholders in plugin config #81

Description

@owen-pengtao

Summary

ConfigLoader.load_config(config, use_jinja=True) renders the entire plugin
config.yaml as a Jinja2 template using the default (empty) Undefined
(cpex/framework/loader/config.py, the use_jinja branch):

jinja_env = SandboxedEnvironment(loader=jinja2.BaseLoader(), autoescape=True)
rendered_template = jinja_env.from_string(template).render(env=os.environ)

The intent is to support {{ env.X }} interpolation. But because every config
value is run through this one pass with an empty Undefined, any {{...}} that
is not an env reference is silently blanked to ""
— including placeholders a
plugin legitimately stores in its config to render itself later, at runtime.

Impact (real downstream bug)

The WebhookNotification plugin stores a default_template like:

{ "event": "{{event}}", "timestamp": "{{timestamp}}", "user": "{{user}}",
  "violation": {{violation}}, "metadata": {{metadata}} }

Those {{event}}/{{timestamp}}/… are meant for the plugin's own template
rendering at delivery time. After ConfigLoader.load_config, the stored template
has already been blanked to { "event": "", "timestamp": "", "violation": , ... },
so the plugin posts an all-empty (and invalid-JSON) webhook body. The
unconditionally-set timestamp being empty is the smoking gun that the blanking
happens at config load, not in the plugin.

Minimal repro

import os, jinja2
from jinja2.sandbox import SandboxedEnvironment
env = SandboxedEnvironment(loader=jinja2.BaseLoader(), autoescape=True)
print(env.from_string('{"event": "{{event}}"}').render(env=os.environ))
# -> '{"event": ""}'   (the {{event}} placeholder is destroyed)

Reproduced with cpex==0.1.0; the same code is present on the default branch
(cpex/framework/loader/config.py, lines ~73-74).

Suggested fix

Don't silently destroy non-env placeholders. Options:

  1. Render with an undefined that preserves the original text for unknown names,
    e.g. undefined=jinja2.DebugUndefined (note: it emits {{ name }} with
    canonical spacing, so plugins doing exact-string substitution may need to
    tolerate that), or a custom Undefined that returns the original {{name}}
    verbatim.
  2. Restrict interpolation to the env namespace only (e.g. a narrowly-scoped pass
    that resolves {{ env.* }} and leaves all other {{...}} untouched).
  3. At minimum, document that plugin config values must not contain literal {{...}}
    unless they are env references, and make non-env placeholders an error rather
    than silent blanking.

Current workaround

Wrap the affected config value in a Jinja raw/endraw guard in config.yaml so
the load-time pass leaves the placeholders verbatim. (Caveat: the guard tokens must
not appear in nearby YAML comments — the whole file is rendered before YAML parse,
so a guard token in a comment opens/closes the block at the wrong place.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    0.1.xbugSomething isn't working

    Type

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions