Sandbox mount redaction clears caller-owned exceptions in place
Maintainer thường phản hồi trong vòng 1 ngày
Chưa có ai nhận issue này.
Đánh giá
- Độ khó
- 4/5
- Thời gian dự kiến
- 1-2 ngày
- Mức phù hợp với người mới
- 35/100
Hướng nghiên cứu
Start in redact_mount_error_data and _discard_exception_graph in agents/sandbox/_mount_security.py, then check the same helper in agents.exceptions. Run the reproduction script from the issue to confirm that the saved exception and the one reachable only through __context__ are both emptied. Done means the caller still gets the redacted RuntimeError, the caller's exceptions keep their __dict__, __cause__ and __context__, and the threat-model question about clearing frames is settled by a maintainer decision.
Do mô hình lập chỉ mục viết ra từ nội dung của issue.
Mô tả
Summary
When a sandbox call fails and its manifest has configured mount authority, redact_mount_error_data replaces the error with a generic RuntimeError. That part works as intended. But before replacing it, _discard_exception_graph mutates the original exception, and every exception reachable from it through __cause__, __context__, args and instance attributes. It clears each one's __dict__ and __cause__/__context__ in place.
Those objects often belong to the caller: an error it saved to raise again, or an unrelated exception it handled earlier that is now in the __context__ chain. After the sandbox call they are empty, so later code that reads them fails in ways that are hard to trace.
Reproduction
Reproduced on openai-agents 0.22.3, 0.23.1 (latest release) and main at 125efa029b4b, with Python 3.13:
import asyncio
from agents.sandbox._mount_security import redact_mount_error_data
from agents.sandbox.entries.mounts import (
InContainerMountStrategy,
RcloneMountPattern,
S3Mount,
)
from agents.sandbox.manifest import Manifest
class AppError(Exception):
def __init__(self, message: str) -> None:
super().__init__(message)
self.message = message
saved = AppError("sandbox start failed")
saved.__cause__ = ValueError("root cause")
held_elsewhere = KeyError("handled earlier, still held by the caller")
held_elsewhere.note = "important"
@redact_mount_error_data
async def start(manifest: Manifest) -> None:
try:
raise held_elsewhere
except KeyError:
raise saved
async def main() -> None:
manifest = Manifest(
entries={
"data": S3Mount(
bucket="b",
access_key_id="AKIA",
secret_access_key="secret",
mount_strategy=InContainerMountStrategy(pattern=RcloneMountPattern()),
)
}
)
try:
await start(manifest)
except Exception as raised:
print("raised: ", type(raised).__name__, "-", raised)
print("saved.__dict__: ", saved.__dict__)
print("saved.__cause__:", repr(saved.__cause__))
print("saved.message: ", getattr(saved, "message", "<missing>"))
print("held_elsewhere.__dict__:", held_elsewhere.__dict__)
asyncio.run(main())
Output:
raised: RuntimeError - sandbox operation failed while using a protected mount configuration
saved.__dict__: {}
saved.__cause__: None
saved.message: <missing>
held_elsewhere.__dict__: {}
Expected: the caller gets the redacted RuntimeError, and saved and held_elsewhere are unchanged.
Actual: both are cleared. held_elsewhere was never raised out of the sandbox call; it is only reachable through __context__.
Impact
We hit this in a Temporal workflow. When sandbox acquisition failed, we saved the temporalio.exceptions.ActivityError and raised it again on later calls, so every call after a failed acquisition failed the same way. The first raise went through BaseSandboxSession.start (decorated with redact_mount_error_data), which emptied the saved object. When we raised it again later, it had no _message or cause, and reading .message raised AttributeError. That error happened in workflow code, so Temporal failed the workflow task and retried it on every replay instead of letting the workflow handle the failure.
Our workaround is to save a detached copy and raise a new copy each time. Any other caller that keeps an exception, or holds one that ends up in a __context__ chain, can hit the same problem.
The same mutation applies to every method decorated with redact_mount_error_data (start, stop, shutdown, aclose, exec, apply_manifest, and others), and to the _discard_exception_graph calls in agents.exceptions.
Suggested fix
The redaction goal can probably be met without mutating objects the SDK doesn't own:
- Raise the safe replacement with no link to the original (
raise safe_error from None, so__cause__isNoneand__suppress_context__isTrue), and drop the SDK's own references to the original. - If frames have to be cleared because locals may hold credentials, clearing the tracebacks (
traceback.clear_frames) may be enough on its own, without also clearing each exception's__dict__and links. - If clearing instance state is still needed, limit it to exceptions the SDK created, or document clearly that any exception reachable from a failed sandbox call may be wiped.
We may be missing a threat-model reason for clearing in place. If so, documenting that behaviour on BaseSandboxSession would still help.
- Ngôn ngữ chính
- Python
- Star
- 30k
- Fork
- 4.9k
- Merge trung bình
- 18 giờ 13 phút
- Pull request đã merge (30 ngày)
- 215
Chuẩn bị môi trường
- Không có Dockerfile hay tệp Docker Compose
- Có mẫu pull request
- Đọc hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Issue khác của openai/openai-agents-python
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 77/100
openai/openai-agents-python#5348 · 2 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Support the OpenAI Decisions APIĐang mở
Độ khó 5/5 Hơn một tuần Mức phù hợp với người mới 25/100
openai/openai-agents-python#5353 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 3/5 Nửa ngày Mức phù hợp với người mới 70/100
openai/openai-agents-python#5342 · 3 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
enhancement
Độ khó 3/5 1-2 ngày Mức phù hợp với người mới 65/100
openai/openai-agents-python#5336 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Finished tool call is dropped when a parallel tool's guardrail tripsCó thể đã có người làm @jbeckwith-oai đã nhận 7 ngày trước. Đang mở
Độ khó 4/5 3-5 ngày Mức phù hợp với người mới 35/100
openai/openai-agents-python#5327 · 1 bình luận ·
Maintainer thường phản hồi trong vòng 1 ngày
Tất cả issue của openai/openai-agents-python
Issue tương tự
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 82/100
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 70/100
onyx-dot-app/onyx#16016 ·
Maintainer thường phản hồi trong vòng 1 ngày
-
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 1 ngày
-
black --check exits 0 and prints All done when a multi file run is interruptedCó thể đã có người làm @jiteshgulati đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 72/100
Maintainer thường phản hồi trong vòng 2 ngày
-
Non-positive worker counts wait for results without starting workersCó thể đã có người làm @IlyaKhalafi đã nhận hôm nay. Đang mở
Độ khó 2/5 1-3 giờ Mức phù hợp với người mới 85/100
Maintainer thường phản hồi trong vòng 1 ngày