Skip to content

Commit 06dfb75

Browse files
lesnik512claude
andcommitted
fix(import-checker): probe opentelemetry.trace, not the bare namespace
`opentelemetry` is a PEP 420 native namespace package — any `opentelemetry-instrumentation-*` package creates the directory even when `opentelemetry-api` is absent. `find_spec("opentelemetry")` then returns non-None and `is_otel_installed` becomes True; the lazy `from opentelemetry import trace` in `_emit_event` subsequently raises ImportError mid-request. `find_spec("opentelemetry.trace")` would fix the false-positive but causes CPython to load the opentelemetry namespace package into sys.modules as a side-effect of resolving the submodule, breaking the transitive-import isolation guarantee enforced by test_optional_extras_isolation.py. Use `importlib.metadata.distribution("opentelemetry-api")` instead — it probes the package registry directly with no sys.modules side-effects, and raises PackageNotFoundError when the api package is absent. The check is now cheap and correct under every install permutation we can construct. The new test source-checks the probe target so a future revert to find_spec trips the regression guard, even though live distribution() calls succeed either way under --all-extras. Closes audit Low finding (import_checker.py:8) from planning/audit/2026-06-07-deep-audit.md. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 920859f commit 06dfb75

2 files changed

Lines changed: 45 additions & 1 deletion

File tree

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
"""Detect optional extras without importing them. Used by adapter modules to gate hard imports."""
22

3+
from importlib.metadata import PackageNotFoundError, distribution
34
from importlib.util import find_spec
45

56

67
is_msgspec_installed = find_spec("msgspec") is not None
78
is_pydantic_installed = find_spec("pydantic") is not None
8-
is_otel_installed = find_spec("opentelemetry") is not None
9+
# opentelemetry/ is a PEP 420 namespace package — instrumentation packages create the
10+
# directory even without opentelemetry-api. find_spec("opentelemetry") therefore returns
11+
# non-None regardless of whether the api package is present, and
12+
# find_spec("opentelemetry.trace") populates sys.modules with the namespace parent as a
13+
# CPython side-effect, breaking the isolation guarantee.
14+
# importlib.metadata.distribution probes the package registry instead: it returns the
15+
# distribution when opentelemetry-api is installed and raises PackageNotFoundError when
16+
# it is absent, with no sys.modules side effects.
17+
try:
18+
distribution("opentelemetry-api")
19+
is_otel_installed = True
20+
except PackageNotFoundError:
21+
is_otel_installed = False

tests/test_optional_extras_otel_missing.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@
1111
"""
1212

1313
import logging
14+
from importlib.metadata import distribution
1415
from unittest.mock import patch
1516

1617
import pytest
1718

19+
from httpware._internal import import_checker
1820
from httpware._internal.observability import _emit_event
1921

2022

@@ -56,3 +58,32 @@ def test_emit_event_does_not_call_opentelemetry_apis_when_flag_false() -> None:
5658
)
5759

5860
mock_get_span.assert_not_called()
61+
62+
63+
def test_is_otel_installed_uses_opentelemetry_trace_probe() -> None:
64+
"""The install probe must use the package registry, not find_spec on the namespace.
65+
66+
`opentelemetry` is a PEP 420 namespace — instrumentation packages create the
67+
directory even when `opentelemetry-api` is absent. find_spec("opentelemetry")
68+
returns non-None regardless, giving a false positive.
69+
70+
find_spec("opentelemetry.trace") would fix the false-positive but causes CPython
71+
to load the opentelemetry namespace package into sys.modules as a side-effect,
72+
breaking the transitive-import isolation guarantee.
73+
74+
importlib.metadata.distribution("opentelemetry-api") probes the package registry
75+
directly: no sys.modules side-effects, and it raises PackageNotFoundError when
76+
opentelemetry-api is absent. This test pins that contract.
77+
"""
78+
# In CI (opentelemetry-api IS installed), distribution succeeds.
79+
assert distribution("opentelemetry-api") is not None
80+
assert import_checker.is_otel_installed is True
81+
82+
# The structural assertion: the constant must be derived from the metadata probe.
83+
# This ensures a future revert to find_spec trips the regression guard.
84+
source = __import__("inspect").getsource(import_checker)
85+
assert 'distribution("opentelemetry-api")' in source, (
86+
"import_checker must probe via importlib.metadata.distribution('opentelemetry-api') "
87+
"(PEP 420 namespace hazard + sys.modules side-effect); "
88+
"see planning/audit/2026-06-07-deep-audit.md (Low finding on import_checker.py:8)."
89+
)

0 commit comments

Comments
 (0)