Skip to content

v0.11.0

Latest

Choose a tag to compare

@github-actions github-actions released this 20 Jul 14:44

Changed

  • Narrowed typed_merge's get_type_hints fallback to
    (TypeError, NameError, AttributeError); the loader/command broad error
    boundaries that feed the ignore_error predicate 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 or Template.render. The template/expression caches also switched from
    clear-everything-at-capacity to LRU eviction, and their env keys are
    weakref-guarded so a recycled id(env) can't return a render bound to a dead
    environment. parse_sources duplicate detection is O(1) per source (set)
    instead of O(n²) (list).

Added

  • allow_commands control. 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
    raising CommandsDisabledError instead. Use it when loading configuration you
    do not fully trust. Defaults to permissive (commands allowed).
  • sandbox control. ConfigLoader(sandbox=True) runs interpolation in
    Jinja2's SandboxedEnvironment, blocking attribute-traversal (SSTI) attacks
    from untrusted config values. Defaults off.
  • New docs/guide/security.md documenting the trust model and both controls.

Fixed

  • !include now routes through the loader driving the current parse. The
    include constructor is registered once per YAML loader class, capturing the
    first ConfigLoader; nested !include/!load previously 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's merge_options — the documented per-call override was leaking into
    every subsequent load().
  • Backend resolution is now deterministic: recursive backend discovery returns a
    definition-ordered list instead of a set, 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 calls setLevel() 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 same MemPath("stream"), so resolving sources
    up front left all of them holding the last stream's content.
  • CommandBackend decodes command output as UTF-8 (or an explicit encoding=)
    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