Changed
- Narrowed
typed_merge'sget_type_hintsfallback to
(TypeError, NameError, AttributeError); the loader/command broad error
boundaries that feed theignore_errorpredicate now log the swallowed error
at DEBUG and are documented as deliberate. - Faster interpolation. A string with no Jinja delimiter (
{{/{%/{#) —
the common case for config values — now returns unchanged without a cache
lookup orTemplate.render. The template/expression caches also switched from
clear-everything-at-capacity to LRU eviction, and their env keys are
weakref-guarded so a recycledid(env)can't return a render bound to a dead
environment.parse_sourcesduplicate detection is O(1) per source (set)
instead of O(n²) (list).
Added
allow_commandscontrol.ConfigLoader(allow_commands=False)(or per
load()call) refuses to execute a command source —cmd://,exec://,
sh://,*+fmt://, script-extension files, and any reached via!include—
raisingCommandsDisabledErrorinstead. Use it when loading configuration you
do not fully trust. Defaults to permissive (commands allowed).sandboxcontrol.ConfigLoader(sandbox=True)runs interpolation in
Jinja2'sSandboxedEnvironment, blocking attribute-traversal (SSTI) attacks
from untrusted config values. Defaults off.- New
docs/guide/security.mddocumenting the trust model and both controls.
Fixed
!includenow routes through the loader driving the current parse. The
include constructor is registered once per YAML loader class, capturing the
firstConfigLoader; nested!include/!loadpreviously inherited that first
loader's settings (base_dir, merge, and — critically —allow_commands),
leaking state across loaders. Includes now use the loader actually performing
the load.ConfigLoader.load(merge_options=...)no longer permanently overwrites the
instance'smerge_options— the documented per-call override was leaking into
every subsequentload().- Backend resolution is now deterministic: recursive backend discovery returns a
definition-ordered list instead of aset, so when two backends' patterns both
match a path, the first-registered one reliably wins (previously hash-order
dependent). - Constructing a
ConfigLoader(including the import-time default instance) no
longer callssetLevel()on the module logger — library code no longer mutates
global logging state. - Stream and unnamed in-memory sources each get a unique virtual path; previously
every stream materialized to the sameMemPath("stream"), so resolving sources
up front left all of them holding the last stream's content. CommandBackenddecodes command output as UTF-8 (or an explicitencoding=)
instead of the locale codec, which mangled UTF-8 output on Windows; temp-file
fallback sources are cleaned up at exit and their suffixes sanitized.
Full Changelog: v0.10.0...v0.11.0