Skip to content

Releases: modern-python/lite-bootstrap

1.2.1

24 Jun 09:47
3bb26ad

Choose a tag to compare

lite-bootstrap 1.2.1 — lift the FastAPI 0.137 cap

1.2.1 is a patch release. No public-API or behavior changes. It removes the temporary fastapi<0.137 ceiling introduced in 1.1.1, now that the upstream prometheus-fastapi-instrumentator fix has shipped.

Dependency constraints

  • fastapi<0.137 cap removed from the fastapi extra (the single declaration every fastapi-* extra composes from). FastAPI 0.137 and 0.138 now resolve.
  • prometheus-fastapi-instrumentator floor raised on the fastapi-metrics extra: >=6.1>=8.0.1. The crash that motivated the cap required FastAPI ≥0.137 and instrumentator ≤8.0.0, so lifting the FastAPI ceiling is paired with a floor that guarantees the fixed instrumentator wherever metrics are installed.

The original cap was added in 1.1.1 because prometheus-fastapi-instrumentator read route.path unconditionally and crashed on FastAPI 0.137's internal _IncludedRouter route type. That is fixed upstream in instrumentator v8.0.1 (issue #370, closed 2026-06-22). lite-bootstrap's own offline-docs guard (the isinstance(route, Route) filter shipped in 1.1.1) remains in place.

Verified end-to-end against FastAPI 0.138.0 + prometheus-fastapi-instrumentator 8.0.2: full suite green at 100% coverage, including the offline-docs and metrics paths that previously crashed.

Backwards compatibility

Fully backward compatible with 1.2.0. No public API or behavior changed; this is purely a loosening of resolution constraints. Installs that were held at FastAPI ≤0.136 by the cap will now resolve forward to current FastAPI.

References

1.2.0

24 Jun 09:34
1b0860e

Choose a tag to compare

lite-bootstrap 1.2.0 — deeper seams: structured-log payload, unified teardown guard, OTel config tidy-up

1.2.0 is a minor release. Backward compatible with 1.1.1, with one observable behavior change (a new double-attach warning on Litestar and FastStream). It lands the shippable results of an architecture-deepening sweep: the structlog→Sentry contract gets a single owner, the teardown-on-shutdown guard is unified across all frameworks, and an OpenTelemetry config field moves to where it belongs.

Features

  • StructuredLogPayload owns the structlog→Sentry contract (PR #129). The rendered-log-line shape that the Sentry instrument used to sniff and re-parse inline now lives in one value object (lite_bootstrap.instruments.logging_factory.StructuredLogPayload), with its meta-key vocabulary exposed as the public STRUCTLOG_META_KEYS. This closes a silent-drift failure mode: previously, renaming or adding a structlog meta-key could quietly leak it into Sentry's contexts.structlog or drop the enrichment, with no test to catch it. Sentry output is unchanged for existing setups; the enrichment is now pinned by a round-trip test.

  • opentelemetry_excluded_urls now lives on OpenTelemetryConfig (PR #132). The field was OpenTelemetry's own setting but had been declared separately on each of the FastAPI, Litestar, and FastStream configs. It now lives on OpenTelemetryConfig, so it is available wherever OpenTelemetry is configured and is read with typed access internally. The automatic exclusion of the metrics path and (unless health-check spans are enabled) the health-check path from traces is unchanged and now covered by a regression test.

Behavior changes

  • The double-attach teardown guard now applies to Litestar and FastStream (PR #130). Teardown-on-shutdown wiring is unified behind a single BaseBootstrapper._attach_teardown_once seam. The safeguard that warns and skips when a second bootstrapper is constructed against the same application — previously present only on FastAPI and FastMCP — now covers Litestar and FastStream as well. If your code constructs two bootstrappers against one Litestar AppConfig or FastStream app, you will now see a UserWarning and the second teardown is skipped, where this was previously silent. This is non-breaking: the warning is informational, the second attach is skipped (not errored), and the first bootstrapper's teardown still runs on shutdown. Construct one bootstrapper per application.

Backwards compatibility

Fully backward compatible with 1.1.1. No public API was removed.

  • IGNORED_STRUCTLOG_ATTRIBUTES is retained in sentry_instrument as a silent alias of STRUCTLOG_META_KEYS, so existing imports keep working.
  • opentelemetry_excluded_urls is still set exactly as before (e.g. FastAPIConfig(opentelemetry_excluded_urls=[...])) — it is now inherited rather than locally declared. FreeConfig additionally accepts the field now (inert there, since Free has no HTTP surface).
  • The only observable difference is the new Litestar/FastStream double-attach warning described above.

Internal-only changes that do not affect the public API: FastMCP's double-attach detection moved from scanning the provider list to the shared attribute marker, and FastAPI's internal lifespan marker was renamed to the unified _lite_bootstrap_teardown_attached.

References

  • PRs: #129, #130, #132
  • Design bundles and the decisions behind the rejected/limited options: planning/changes/2026-06-23.01-structured-log-payload/, planning/changes/2026-06-24.01-unify-teardown-attach/, planning/changes/2026-06-24.02-otel-excluded-urls-home/, and planning/decisions/.

1.1.1

14 Jun 19:51
3d2bdc0

Choose a tag to compare

lite-bootstrap 1.1.1 — FastAPI 0.137 compatibility

1.1.1 is a patch release. No public-API or behavior changes. It restores compatibility with FastAPI 0.137 and pins a transitive incompatibility, nothing more.

Bug fixes

  • Offline docs no longer crash on FastAPI 0.137's _IncludedRouter (PR #122). FastAPI 0.137.0 added the internal _IncludedRouter route type (a BaseRoute subclass with no .path) to app.router.routes. enable_offline_docs filtered routes via an unchecked typing.cast(Route, route).path, which raised AttributeError: '_IncludedRouter' object has no attribute 'path' whenever a router was included (e.g. by the health-checks instrument). The filter now matches only real Route instances (isinstance(route, Route) and route.path in …), leaving _IncludedRouter and other route types untouched. Correct on both old and new FastAPI.

Dependency constraints

  • fastapi<0.137 cap on the fastapi extra (temporary). prometheus-fastapi-instrumentator (≤ 8.0.0) has the same unguarded route.path access and is not yet fixed upstream, so any lite-bootstrap install that pulls FastAPI 0.137 would break metrics. The cap lives on the base fastapi extra — the single declaration every other fastapi-* extra composes from — so the whole FastAPI surface resolves to a version tested end-to-end with no skew between extras. Lift the cap once a fixed instrumentator ships.

Backwards compatibility

Fully backward compatible with 1.1.0. No public API changed; the FastAPI fix is purely defensive. The only observable difference is the new fastapi<0.137 resolution ceiling, which holds installs at a known-good FastAPI until the upstream metrics fix lands.

References

1.1.0

05 Jun 19:00
558b1d5

Choose a tag to compare

lite-bootstrap 1.1.0 — Lifecycle hardening, config validation, CI gate

1.1.0 is a minor release. No intentional public-API breakage. The two behavior changes that could affect existing code are fixes to genuine bugs and are called out in Behavior changes below.

This release closes a 26-finding bug-audit cycle (audits + retro live under planning/specs/2026-06-05-bug-audit-v2*.md). The changes split across four shipped PRs:

  • #108 — Lifecycle & teardown correctness (10 findings)
  • #109 — Config UX & security validation (6 findings)
  • #110 — Hygiene + CI gate (4 findings)
  • #111 — Generalized TeardownError aggregation + cascade tests + README lifecycle docs (3 deferred follow-ups)

Test suite grew from 153 → 194 (+27%) at 100% line coverage throughout. pip-audit now runs on every PR and weekly via cron; a new filterwarnings config catches accidental InstrumentSkippedWarning emissions.

New features

  • Injectable prometheus_collector_registry on FastStreamConfig. Pass an existing prometheus_client.CollectorRegistry to expose counters registered elsewhere through FastStream's /metrics endpoint. Defaults to a fresh per-instance registry — fully backward compatible.
  • opentelemetry_excluded_urls field on FastStreamConfig. Was a getattr fallback before; now a discoverable, IDE-completable config field matching FastAPIConfig and LitestarConfig.
  • SentryInstrument.teardown(). Calls sentry_sdk.flush(timeout=2) then sentry_sdk.init() (no args) to reset the SDK to a no-op state. Previously the SDK stayed globally configured after bootstrapper teardown, leaking state across process-local tests.
  • FastStreamLoggingInstrument.teardown(). Restores broker.config.logger.params_storage to its pre-bootstrap value. The bootstrap mutated broker state; teardown didn't reverse it.

Bug fixes

Lifecycle & teardown (PR #108)

  • OpenTelemetry teardown now flushes spans and shuts down the tracer provider (LOG-1, LOG-2). bootstrap() stored the TracerProvider only as a local; teardown() couldn't reach it to call shutdown(). Buffered spans in BatchSpanProcessor were dropped on graceful shutdown. Teardown also restores the two OTel-namespace stdlib loggers (opentelemetry.instrumentation.instrumentor, opentelemetry.trace) to their pre-bootstrap disabled state.
  • LoggingInstrument.teardown() runs all cleanup steps even on partial failure (LOG-3). A raise from any handler.close() previously left remaining handlers attached, skipped the root-level reset, and never called close_handlers() on the memory factory. Now wrapped in try/finally with per-handler error capture; all collected errors raise together via TeardownError(errors).
  • LitestarOpenTelemetryInstrumentationMiddleware cache evicts dead refs (LOG-6). The old dict[int, ASGIApp] keyed by id() never evicted, holding wrapper OpenTelemetryMiddleware instances alive after Litestar dropped next_app. Replaced with weakref.WeakKeyDictionary; non-weakrefable apps fall through to the un-cached path.
  • Double-bootstrap on the same application is now detected and warned (LOG-7, LOG-8). Constructing two FastMcpBootstrappers around the same FastMCP (or two FastAPIBootstrappers around the same FastAPI) previously stacked teardown hooks. The second construction now emits a UserWarning, skips the re-attachment, and tells you the second bootstrapper's teardown() won't fire on ASGI shutdown.
  • Generalized TeardownError aggregation across all instruments (PR #111). OpenTelemetryInstrument, FastStreamLoggingInstrument, and SentryInstrument now run their full cleanup sequence even if an early step raises — aggregating errors into a single TeardownError or letting super().teardown() run via try/finally. Previously a misbehaving instrumentor / broker / Sentry flush silently skipped subsequent cleanup.
  • Pyroscope's precondition check survives python -O (LOG-5/SEC-4). Replaced two assert statements (in _narrow_app and PyroscopeInstrument.bootstrap) with explicit raise TypeError(...) and raise RuntimeError(...). python -O strips asserts; the invariants now hold under all optimization levels. Closes the two bandit B101 findings.

Config & security (PR #109)

  • FastAPIConfig no longer stomps user-supplied app's title/debug/version (UX-1). Previously the three assignments ran unconditionally; a user passing FastAPI(title="My API", version="3.0.0") would silently have those clobbered by lite-bootstrap defaults. Now the assignments only run in the UnsetType branch (when lite-bootstrap constructed the app). See Behavior changes below.
  • enable_offline_docs validates request.scope["root_path"] against the existing path allowlist (SEC-1). Invalid root paths (e.g., HTML-injection payloads via a malicious upstream proxy's X-Forwarded-Prefix) now fall back to empty and emit a warning instead of being reflected into Swagger/Redoc HTML script tags. Threat model: not an issue in default ASGI deployments; only matters if ProxyHeadersMiddleware trusts upstream prefix headers.
  • OpenTelemetry endpoint with insecure=True emits a warning for non-local hosts (SEC-2). New OpenTelemetryConfig.__post_init__ parses the endpoint (handles both host:port and scheme://host:port forms, including IPv6 brackets and unix://) and warns when traces would ship unencrypted to a non-localhost/127.0.0.1/::1/unix:// target.
  • CorsConfig rejects unsafe wildcard + credentials combos at construction (SEC-3). cors_allowed_credentials=True combined with cors_allowed_origins=["*"] (or a permissive regex like ".*"/".+") is the canonical CORS misconfiguration — browsers reject the response. Now raises ConfigurationError immediately instead of silently building a non-functional CORS layer. See Behavior changes below.

Hygiene & process (PR #110)

  • Missing-dependency events now log via stdlib logging in addition to warnings.warn (UX-4). Users running under python -W ignore or PYTHONWARNINGS=ignore previously saw nothing when a configured instrument's optional dep was missing. The new logger.warning line on lite_bootstrap.bootstrappers.base is unaffected by warning filters.

Behavior changes

Two changes could affect existing code in ways the previous release wouldn't have. Both fix real bugs; surfaced here so you can audit.

  1. User-supplied FastAPI instance retains its own title, debug, version. If you were relying on lite-bootstrap to overwrite these from service_name/service_debug/service_version after handing it a pre-built FastAPI(), you'll now see your original values. Migration: set these on your FastAPI() directly, or use FastAPIConfig(application_kwargs={...}) to have lite-bootstrap construct the app.

  2. CorsConfig(cors_allowed_origins=["*"], cors_allowed_credentials=True) now raises ConfigurationError. This combo was never functional — browsers reject responses with Access-Control-Allow-Credentials: true and Access-Control-Allow-Origin: *. If your code constructed this combo and worked anyway (because the credentials header was silently dropped by FastAPI's CORSMiddleware), construction now fails with a clear message. Migration: enumerate allowed origins explicitly, or set cors_allowed_credentials=False.

New constraints documented

Three lifecycle constraints surfaced by the audit are now documented in README.md and CLAUDE.md:

  • One bootstrapper per application instance. Second construction emits a warning and skips re-attachment (see LOG-7/LOG-8 above).
  • One OpenTelemetryInstrument per process. The OTel SDK enforces set_tracer_provider as set-once via _TRACER_PROVIDER_SET_ONCE.do_once(...) (verified against opentelemetry/trace/__init__.py:548-556); teardown() cannot reset the global pointer.
  • __post_init__ cascade invariant. Every config-class __post_init__ must call super().__post_init__(). BaseConfig ships a no-op as the chain terminator. FastAPIConfig uses the explicit super(FastAPIConfig, self).__post_init__() form because @dataclass(slots=True) breaks bare super().

CI changes

  • security-audit.yml workflow added. pip-audit runs on every PR and weekly via cron against the lockfile (uv export --all-extras --no-hashes). The default-branch run is purely informational; PRs that introduce CVEs will block until resolved.
  • InstrumentSkippedWarning escalated to error in tests. Any unexpected emission outside a pytest.warns(...) block now fails the test (registered via pytest_configure() in tests/conftest.py; can't live in pyproject.toml because that import order breaks pytest-cov tracing).

Backwards compatibility

Aside from the two Behavior changes called out above, every public API behaves identically. New fields default to their old behavior (prometheus_collector_registry=None → fresh registry as before; opentelemetry_excluded_urls=[] → empty set as before). New warnings/validators trigger only on configurations that were already broken or risky.

The 26-fix list with full file:line references and rationale is in:

  • planning/specs/2026-06-05-bug-audit-v2.md — the audit
  • planning/specs/2026-06-05-bug-audit-v2-sequencing.md — the 3-PR breakdown
  • planning/specs/2026-06-05-bug-audit-v2-retro.md — what the cycle taught us

References

Read more

1.0.0

02 Jun 15:08
0d1b6ec

Choose a tag to compare

What's Changed

  • fix: honor root_path in offline-docs redoc handler by @lesnik512 in #89
  • fix: shut down TracerProvider in OpenTelemetryInstrument.teardown by @lesnik512 in #90
  • fix: make teardown idempotent and exception-safe by @lesnik512 in #91
  • fix: strip skip_sentry from Sentry context; drop dead is_X_installed conjuncts by @lesnik512 in #92
  • docs: document and pin BaseConfig.from_dict / from_object semantics by @lesnik512 in #93
  • refactor: extract OpenTelemetryServiceFieldsConfig mixin by @lesnik512 in #94
  • refactor: make BaseInstrument generic; delete pure-annotation subclasses by @lesnik512 in #95
  • fix: tighten Sentry idiom and typing micro-issues by @lesnik512 in #96
  • refactor: OTel instrument touch-ups (REF-1, LOW-3, LOW-5) by @lesnik512 in #97
  • test: add standalone instrument tests and is_valid_path negative tests by @lesnik512 in #98
  • refactor: split logging module + cleanup + lifecycle test by @lesnik512 in #99
  • refactor: drop unused abc.ABC from BaseInstrument; document config holders by @lesnik512 in #100
  • refactor: drop frozen=True from instruments; sentinel for FastAPIConfig.application by @lesnik512 in #101
  • feat: configurable broker ping timeout for FastStream health check by @lesnik512 in #102
  • refactor: rename OpentelemetryConfig → OpenTelemetryConfig; FreeBootstrapperConfig → FreeConfig by @lesnik512 in #103
  • chore: pin uv_build upper bound; assert pyroscope_endpoint precondition by @lesnik512 in #104
  • feat: add FastMcpBootstrapper by @lesnik512 in #105
  • fix: make BaseBootstrapper.bootstrap() idempotent by @lesnik512 in #106
  • refactor: replace InstrumentNotReadyWarning with is_configured classmethod + summary log by @lesnik512 in #107

Full Changelog: 0.28.1...1.0.0

0.28.1

13 May 16:42
57d2c59

Choose a tag to compare

What's Changed

  • fix: prevent FastStream bootstrap NameError when optional extras are missing by @lesnik512 in #88

Full Changelog: 0.28.0...0.28.1

0.28.0

02 May 17:09
2db731f

Choose a tag to compare

What's Changed

  • fix: cache OpenTelemetryMiddleware in litestar instrumentation by @lesnik512 in #80
  • Fix/low severity cleanups by @lesnik512 in #81
  • fix: preserve teardown error detail via TeardownError exception by @lesnik512 in #82
  • perf: hoist OTel import in tracer_injection to module level by @lesnik512 in #83
  • refactor: declare opentelemetry_service_name/namespace on PyroscopeCo… by @lesnik512 in #84
  • feat: add logging_enabled flag, decouple from service_debug by @lesnik512 in #85
  • feat: unify instrument skip feedback through warning subclasses by @lesnik512 in #86

Full Changelog: 0.27.1...0.28.0

0.27.1

30 Apr 16:39
563c634

Choose a tag to compare

What's Changed

  • feat: make TimeStamper configurable in LoggingConfig by @lesnik512 in #79

Full Changelog: 0.27.0...0.27.1

0.27.0

29 Apr 07:48
65fcbd2

Choose a tag to compare

What's Changed

  • feat: integrate litestar StructlogPlugin for request.logger support by @lesnik512 in #78

Full Changelog: 0.26.1...0.27.0

0.26.1

28 Apr 12:42
53334b9

Choose a tag to compare

What's Changed

  • fix: set faststream log level on logger before injecting into broker by @lesnik512 in #77

Full Changelog: 0.26.0...0.26.1