👋 👋
Severity: Critical
File: confidence/confidence.py:80
I forked the repository and made a branch but wanted to respect the contribution guidelines before I opened a pull request.
description
context is declared as a class-level attribute with a mutable default dict:
class Confidence:
context: Dict[str, FieldType] = {}
because__init__never assigns self.context = {}, all instances share the same dict object at the class level. Any call to put_context on one instance mutates that shared dict, silently contaminating every other Confidence instance in the process.
impact
- context set on one Confidence instance leaks into all other instances.
- child instances created via with_context are safe (they assign a new dict), but the root instance and any sibling roots
are not.
- in a multi-tenant or multi-user scenario, this is a data isolation failure.
reproduction
from confidence.confidence import Confidence
a = Confidence("secret-a")
b = Confidence("secret-b")
a.put_context("user", "alice")
print(b.context) # {"user": "alice"} — wrong, b is contaminated
Bug confirmed. b was never touched, but it has Alice's context because both instances share the same class-level dict.
fix
-
context (critical)
add self.context: Dict[str, FieldType] = {} inside __init__, and change the async_client default to None with a guard in the body.
-
async_client (secondary) Change the default from httpx.AsyncClient() (evaluated once at class definition time, shared across all instances) to None, instantiating a fresh httpx.AsyncClient() per instance in the body of __init__. This prevents shared client state under concurrent use.
-
Regression test added tests/test_confidence.py::TestConfidence::test_context_is_isolated_per_instance — creates two root instances, mutates one, and asserts the other is unaffected.
👋 👋
Severity: Critical
File:
confidence/confidence.py:80I forked the repository and made a branch but wanted to respect the contribution guidelines before I opened a pull request.
description
context is declared as a class-level attribute with a mutable default dict:
because
__init__never assignsself.context = {}, all instances share the same dict object at the class level. Any call to put_context on one instance mutates that shared dict, silently contaminating every otherConfidenceinstance in the process.impact
are not.
reproduction
Bug confirmed. b was never touched, but it has Alice's context because both instances share the same class-level dict.
fix
context(critical)add
self.context: Dict[str, FieldType] = {}inside__init__, and change theasync_clientdefault toNonewith a guard in the body.async_client(secondary) Change the default fromhttpx.AsyncClient()(evaluated once at class definition time, shared across all instances) toNone, instantiating a freshhttpx.AsyncClient()per instance in the body of__init__. This prevents shared client state under concurrent use.Regression test added
tests/test_confidence.py::TestConfidence::test_context_is_isolated_per_instance— creates two root instances, mutates one, and asserts the other is unaffected.