Repository navigation
v0.88.0
Fixed
-
ISO Introspection UnknownLocaleError Leak (ROBUST-ISO-UNKNOWN-LOCALE-001):
- Previous:
_get_babel_currency_name()and_get_babel_currency_symbol()only caught(ValueError, LookupError, KeyError, AttributeError) - Issue: Babel's
UnknownLocaleErrorinherits fromException, notLookupError; very long or garbage locale strings caused the exception to leak to callers, violating the API contract that onlyBabelImportErrorshould propagate - Discovery: Atheris fuzzer with input
locale="x" * 100triggeredUnknownLocaleErroringet_currency() - Fix: Added defensive
except Exceptionclause (matching_get_babel_territories()pattern) that checks for locale-related errors and returns graceful fallback - Location:
introspection/iso.py_get_babel_currency_name(),_get_babel_currency_symbol() - Impact: API contract honored; garbage locale inputs return
Noneor fallback instead of raising Babel-specific exceptions
- Previous:
-
ISO Introspection Cache Integration (MAINT-CACHE-MISSING-001):
- Previous:
clear_all_caches()did not clear ISO introspection caches (territories, currencies) - Issue: Memory from ISO lookups could not be reclaimed via the central cache clearing function
- Fix:
clear_all_caches()now imports and callsclear_iso_cache()from introspection module - Location:
__init__.pyclear_all_caches()function - Impact: Complete cache clearing for long-running applications using ISO introspection
- Previous:
-
ISO Introspection Bounded Caches (SEC-DOS-UNBOUNDED-ISO-001):
- Previous: ISO lookup functions used unbounded
@functools.cache(equivalent tolru_cache(maxsize=None)) - Security issue: Attacker could exhaust memory by cycling through unique locale strings, as each unique input was permanently cached
- Fix: Replaced
@cachewith@lru_cache(maxsize=MAX_LOCALE_CACHE_SIZE)on all cached functions - Refactored to normalize inputs before caching:
- Public functions normalize inputs (code uppercasing, locale normalization)
- Internal
_implfunctions receive pre-normalized inputs and are cached
- Functions affected:
get_territory,get_currency,list_territories,list_currencies,get_territory_currency - Location:
introspection/iso.py - Impact: Memory exhaustion attack vector eliminated; cache bounded to 128 entries per function
- Previous: ISO lookup functions used unbounded
-
ISO Introspection Locale Normalization (API-ISO-LOCALE-NORM-001):
- Previous: Locale parameters used directly as cache keys without normalization
- Issue: Variant formats ('en-US', 'en_US', 'en_us') created separate cache entries, wasting memory and reducing cache hit rates
- Fix: All locale parameters normalized via
normalize_locale()before caching - Code case also normalized: 'us', 'US', 'Us' now hit same cache entry
- Location:
introspection/iso.pyall public lookup functions - Impact: Cache efficiency improved; consistent behavior with other locale-aware modules
-
ISO Introspection Exception Narrowing (ROBUST-ISO-EXCEPTIONS-001):
- Previous: Internal Babel wrappers used broad
except Exception:catching all errors - Issue: Logic bugs (NameError, TypeError) and system errors (MemoryError) were silently converted to "data not found" results, masking bugs in financial-grade contexts
- Fix: Narrowed exception handling to
(ValueError, LookupError, KeyError, AttributeError) - Babel's
UnknownLocaleError(inherits from Exception, not LookupError) handled specially in_get_babel_territories() - Logic bugs and system errors now propagate for proper debugging
- Location:
introspection/iso.py_get_babel_currency_name(),_get_babel_currency_symbol(),_get_babel_territory_currencies(),_get_babel_territories() - Impact: Fail-fast behavior for logic bugs; improved debuggability in financial applications
- Previous: Internal Babel wrappers used broad
-
FiscalDelta month_end_policy Validation (SEC-INPUT-VALIDATION-002):
- Previous:
FiscalDeltadid not validatemonth_end_policyfield at construction - Issue: Passing invalid policy values (strings, None) caused
UnboundLocalErrordeep in arithmetic operations instead of clear validation error at construction - Fix: Added
isinstance(self.month_end_policy, MonthEndPolicy)check in__post_init__() - Added defensive default case in
_add_months()match statement for defense-in-depth - Location:
parsing/fiscal.pyFiscalDelta.__post_init__(),_add_months() - Impact: Invalid inputs fail fast at construction with clear
TypeError; arithmetic operations protected by defense-in-depth
- Previous:
-
Date Parsing Bounded Caches (SEC-DOS-UNBOUNDED-DATES-001):
- Previous: Date pattern cache functions used unbounded
@functools.cache - Security issue: Attacker could exhaust memory by calling
parse_date()orparse_datetime()with millions of unique fake locale strings, each creating a permanent cache entry - Fix: Replaced
@cachewith@lru_cache(maxsize=MAX_LOCALE_CACHE_SIZE)on_get_date_patterns()and_get_datetime_patterns() - Location:
parsing/dates.pylines 291, 396 - Impact: Memory exhaustion attack vector eliminated; cache bounded to 128 entries per function; LRU eviction for high-volume applications
- Previous: Date pattern cache functions used unbounded
Changed
- RWLock Decorators Modernized to PEP 695 (MODERN-PEP695-RWLOCK-001):
- Previous:
with_read_lockandwith_write_lockdecorators used legacyTypeVar("T")pattern - Modernization: Converted to PEP 695 generic function syntax
def with_read_lock[T](...) - Removed module-level
T = TypeVar("T")declaration - Location:
runtime/rwlock.pylines 265, 297 - Impact: Cleaner syntax aligned with Python 3.13+ standards; no API change
- Previous: