Skip to content

Commit cfc6c9f

Browse files
feat: Add configurable security policy filename to AgentBase
- Add security_policy_filename field to AgentBase with default 'security_policy.j2' - Update system_prompt.j2 template to use configurable security policy filename - Update system_message property to pass security_policy_filename to template - Add comprehensive tests for configurable security policy functionality - Maintain backward compatibility with existing security policy behavior - Add custom_security_policy.j2 template for testing purposes Co-authored-by: openhands <openhands@all-hands.dev>
1 parent e86d0a7 commit cfc6c9f

File tree

4 files changed

+89
-1
lines changed

4 files changed

+89
-1
lines changed

openhands/sdk/agent/base.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,12 @@ class AgentBase(DiscriminatedUnionMixin, ABC):
109109
description="Optional kwargs to pass to the system prompt Jinja2 template.",
110110
examples=[{"cli_mode": True}],
111111
)
112+
security_policy_filename: str = Field(
113+
default="security_policy.j2",
114+
description=(
115+
"Filename of the security policy template to include in system prompt."
116+
),
117+
)
112118
security_analyzer: analyzer.SecurityAnalyzerBase | None = Field(
113119
default=None,
114120
description="Optional security analyzer to evaluate action risks.",
@@ -156,6 +162,9 @@ def system_message(self) -> str:
156162
if hasattr(self, "cli_mode"):
157163
template_kwargs["cli_mode"] = getattr(self, "cli_mode")
158164

165+
# Add security_policy_filename to template kwargs
166+
template_kwargs["security_policy_filename"] = self.security_policy_filename
167+
159168
system_message = render_template(
160169
prompt_dir=self.prompt_dir,
161170
template_name=self.system_prompt_filename,
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# 🔒 Custom Security Policy
2+
3+
## Custom Security Rules
4+
5+
- This is a custom security policy template
6+
- Used for testing configurable security policy functionality
7+
- Contains different content than the default policy
8+
9+
## Custom Guidelines
10+
11+
- Follow custom security guidelines
12+
- Test that custom templates are properly loaded

openhands/sdk/agent/prompts/system_prompt.j2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ Your primary role is to assist users by executing commands, modifying code, and
6262
</PROBLEM_SOLVING_WORKFLOW>
6363

6464
<SECURITY>
65-
{% include 'security_policy.j2' %}
65+
{% include security_policy_filename %}
6666
</SECURITY>
6767

6868
<SECURITY_RISK_ASSESSMENT>

tests/sdk/agent/test_security_policy_integration.py

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,70 @@ def test_security_policy_template_rendering():
6969
# Verify it's properly formatted (no extra whitespace at start/end)
7070
assert not security_policy.startswith(" ")
7171
assert not security_policy.endswith(" ")
72+
73+
74+
def test_configurable_security_policy_filename():
75+
"""Test that security policy filename can be configured."""
76+
# Create agent with custom security policy filename
77+
agent = Agent(
78+
llm=LLM(
79+
model="test-model", api_key=SecretStr("test-key"), base_url="http://test"
80+
),
81+
security_policy_filename="custom_security_policy.j2",
82+
)
83+
84+
# Get the system message
85+
system_message = agent.system_message
86+
87+
# Verify that the custom security policy content is included
88+
assert "🔒 Custom Security Policy" in system_message
89+
assert "Custom Security Rules" in system_message
90+
assert "This is a custom security policy template" in system_message
91+
assert "Custom Guidelines" in system_message
92+
93+
# Verify that the default security policy content is NOT included
94+
assert "🔐 Security Policy" not in system_message
95+
assert "OK to do without Explicit User Consent" not in system_message
96+
97+
98+
def test_default_security_policy_filename():
99+
"""Test that default security policy filename works correctly."""
100+
# Create agent with default security policy filename
101+
agent = Agent(
102+
llm=LLM(
103+
model="test-model", api_key=SecretStr("test-key"), base_url="http://test"
104+
)
105+
)
106+
107+
# Verify the default filename is set correctly
108+
assert agent.security_policy_filename == "security_policy.j2"
109+
110+
# Get the system message
111+
system_message = agent.system_message
112+
113+
# Verify that the default security policy content is included
114+
assert "🔐 Security Policy" in system_message
115+
assert "OK to do without Explicit User Consent" in system_message
116+
117+
118+
def test_security_policy_filename_field_access():
119+
"""Test that security_policy_filename field can be accessed and modified."""
120+
# Create agent with custom security policy filename
121+
agent = Agent(
122+
llm=LLM(
123+
model="test-model", api_key=SecretStr("test-key"), base_url="http://test"
124+
),
125+
security_policy_filename="custom_security_policy.j2",
126+
)
127+
128+
# Verify the field is accessible
129+
assert agent.security_policy_filename == "custom_security_policy.j2"
130+
131+
# Test model_copy with different security policy filename
132+
agent_copy = agent.model_copy(
133+
update={"security_policy_filename": "security_policy.j2"}
134+
)
135+
assert agent_copy.security_policy_filename == "security_policy.j2"
136+
assert (
137+
agent.security_policy_filename == "custom_security_policy.j2"
138+
) # Original unchanged

0 commit comments

Comments
 (0)