Skip to content

Commit 4c03386

Browse files
fix(sdk): preserve security policy filename contract
Normalize explicit None security policy filenames to an empty string while keeping the public field typed and serialized as str. This preserves the disable-security-policy behavior added in #2787 without widening the SDK or REST API contracts to null. Co-authored-by: openhands <openhands@all-hands.dev>
1 parent 9c8e899 commit 4c03386

File tree

2 files changed

+27
-4
lines changed

2 files changed

+27
-4
lines changed

openhands-sdk/openhands/sdk/agent/base.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -158,14 +158,13 @@ class AgentBase(DiscriminatedUnionMixin, ABC):
158158
"- An absolute path (e.g., '/path/to/custom_prompt.j2')"
159159
),
160160
)
161-
security_policy_filename: str | None = Field(
161+
security_policy_filename: str = Field(
162162
default="security_policy.j2",
163163
description=(
164-
"Security policy template filename. Can be:\n"
164+
"Security policy template filename. Can be either:\n"
165165
"- A relative filename (e.g., 'security_policy.j2') loaded from the "
166166
"agent's prompts directory\n"
167-
"- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n"
168-
"- Empty string or None to disable security policy"
167+
"- An absolute path (e.g., '/path/to/custom_security_policy.j2')"
169168
),
170169
)
171170
system_prompt_kwargs: dict[str, object] = Field(
@@ -179,6 +178,11 @@ class AgentBase(DiscriminatedUnionMixin, ABC):
179178
def _validate_system_prompt_fields(cls, data: Any) -> Any:
180179
if not isinstance(data, dict):
181180
return data
181+
if (
182+
"security_policy_filename" in data
183+
and data["security_policy_filename"] is None
184+
):
185+
data["security_policy_filename"] = ""
182186
has_inline = data.get("system_prompt") is not None
183187
has_custom_filename = (
184188
"system_prompt_filename" in data

tests/sdk/agent/test_security_policy_integration.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ def test_security_policy_in_system_message():
6565
assert "AI assistant (OpenHands)" not in system_message
6666

6767

68+
def test_none_security_policy_filename_disables_policy_without_null_public_value():
69+
"""Test that None input disables the policy without exposing a null contract."""
70+
agent = Agent.model_validate(
71+
{
72+
"llm": LLM(
73+
usage_id="test-llm",
74+
model="test-model",
75+
api_key=SecretStr("test-key"),
76+
base_url="http://test",
77+
),
78+
"security_policy_filename": None,
79+
}
80+
)
81+
82+
assert agent.security_policy_filename == ""
83+
assert agent.model_dump()["security_policy_filename"] == ""
84+
assert "🔐 Security Policy" not in agent.static_system_message
85+
86+
6887
def test_custom_security_policy_in_system_message():
6988
"""Test that custom security policy filename is used in system message."""
7089
# Create a temporary directory for test files

0 commit comments

Comments
 (0)