diff --git a/.changelog/5399.fixed b/.changelog/5399.fixed new file mode 100644 index 00000000000..21a38f5b099 --- /dev/null +++ b/.changelog/5399.fixed @@ -0,0 +1 @@ +`opentelemetry-api`: Prevent in-place mutation of `Context` via inherited `dict` methods diff --git a/opentelemetry-api/src/opentelemetry/context/context.py b/opentelemetry-api/src/opentelemetry/context/context.py index c8d87a422dd..984bf424d84 100644 --- a/opentelemetry-api/src/opentelemetry/context/context.py +++ b/opentelemetry-api/src/opentelemetry/context/context.py @@ -11,6 +11,27 @@ class Context(dict[str, object]): def __setitem__(self, key: str, value: object) -> None: raise ValueError + def __delitem__(self, key: str) -> None: + raise ValueError + + def setdefault(self, key: str, default: object = None) -> object: + raise ValueError + + def pop(self, key: str, *args: object) -> object: + raise ValueError + + def popitem(self) -> tuple[str, object]: + raise ValueError + + def clear(self) -> None: + raise ValueError + + def update(self, *args: object, **kwargs: object) -> None: + raise ValueError + + def __ior__(self, other: object) -> Context: + raise ValueError + class _RuntimeContext(ABC): """The RuntimeContext interface provides a wrapper for the different diff --git a/opentelemetry-api/tests/context/test_context.py b/opentelemetry-api/tests/context/test_context.py index ce5327d8680..10b32de363d 100644 --- a/opentelemetry-api/tests/context/test_context.py +++ b/opentelemetry-api/tests/context/test_context.py @@ -54,9 +54,23 @@ def test_set_value(self): self.assertEqual(None, context.get_value("a")) def test_context_is_immutable(self): + ctx = context.get_current() with self.assertRaises(ValueError): - # ensure a context - context.get_current()["test"] = "cant-change-immutable" + ctx["test"] = "cant-change-immutable" + with self.assertRaises(ValueError): + del ctx["test"] + with self.assertRaises(ValueError): + ctx.pop("test") + with self.assertRaises(ValueError): + ctx.popitem() + with self.assertRaises(ValueError): + ctx.clear() + with self.assertRaises(ValueError): + ctx.update({"test": "cant-change-immutable"}) + with self.assertRaises(ValueError): + ctx.setdefault("test", "cant-change-immutable") + with self.assertRaises(ValueError): + ctx |= {"test": "cant-change-immutable"} def test_set_current(self): context.attach(context.set_value("a", "yyy"))