Skip to content

Commit eb59bf4

Browse files
committed
feat: Add Security Operations Agent with category filtering
1 parent aa3cfed commit eb59bf4

File tree

4 files changed

+157
-17
lines changed

4 files changed

+157
-17
lines changed

agents/frameworks/langchain/src/ibmi_agents/agents/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@
77
Available agents:
88
- Performance Agent: System performance monitoring and analysis
99
- SysAdmin Discovery Agent: High-level system discovery and summarization
10-
- SysAdmin Browse Agent: Detailed system browsing and exploration
10+
- SysAdmin Browse Agent: Detailed system browsing and exploration
1111
- SysAdmin Search Agent: System search and lookup capabilities
12+
- Security Operations Agent: Security vulnerability assessment and remediation
1213
"""
1314

1415
from .ibmi_agents import (
@@ -17,6 +18,7 @@
1718
create_sysadmin_discovery_agent,
1819
create_sysadmin_browse_agent,
1920
create_sysadmin_search_agent,
21+
create_security_ops_agent,
2022
chat_with_agent,
2123
list_available_agents,
2224
set_verbose_logging,
@@ -30,6 +32,7 @@
3032
"create_sysadmin_discovery_agent",
3133
"create_sysadmin_browse_agent",
3234
"create_sysadmin_search_agent",
35+
"create_security_ops_agent",
3336
"chat_with_agent",
3437
"list_available_agents",
3538
"set_verbose_logging",

agents/frameworks/langchain/src/ibmi_agents/agents/ibmi_agents.py

Lines changed: 91 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
import os
1919
import json
2020
import getpass
21-
from typing import Dict, Any, List
21+
from typing import Dict, Any, List, Optional
2222
from contextlib import _AsyncGeneratorContextManager, asynccontextmanager
2323
from langchain_ollama import ChatOllama
2424
from langchain_openai import ChatOpenAI
@@ -370,6 +370,92 @@ async def agent_session():
370370

371371
return agent_session()
372372

373+
async def create_security_ops_agent(
374+
model_id: str = "gpt-oss:20b",
375+
mcp_url: str = DEFAULT_MCP_URL,
376+
transport: str = DEFAULT_TRANSPORT,
377+
category: Optional[str] = None,
378+
**kwargs
379+
):
380+
"""
381+
Create IBM i Security Operations Agent.
382+
383+
Args:
384+
model_id: Model identifier (default: "gpt-oss:20b")
385+
mcp_url: MCP server URL
386+
transport: Transport type
387+
category: Optional category filter for security tools. Options:
388+
- "vulnerability-assessment": Tools for identifying security vulnerabilities
389+
- "audit": Tools for auditing security configurations
390+
- "remediation": Tools for generating and executing security fixes
391+
- "user-management": Tools for managing user capabilities and permissions
392+
- None: Load all security tools (default)
393+
**kwargs: Additional agent configuration options
394+
395+
Returns an async context manager that yields (agent, session).
396+
Usage: async with (await create_security_ops_agent()) as (agent, session): ...
397+
"""
398+
client = get_mcp_client(mcp_url, transport)
399+
400+
@asynccontextmanager
401+
async def agent_session():
402+
async with client.session("ibmi_tools") as session:
403+
# Load security tools with optional category filtering
404+
if category:
405+
# Use annotation filtering to load tools by domain and category
406+
tools = await load_filtered_mcp_tools(
407+
session,
408+
annotation_filters={
409+
"domain": "security",
410+
"category": category
411+
},
412+
debug=True
413+
)
414+
print(f"✅ Loaded {len(tools)} security operations tools (category: {category}) for Security Ops Agent")
415+
else:
416+
# Load all security tools by domain
417+
tools = await load_filtered_mcp_tools(
418+
session,
419+
annotation_filters={"domain": "security"},
420+
debug=True
421+
)
422+
print(f"✅ Loaded {len(tools)} security operations tools for Security Ops Agent")
423+
424+
system_message = """You are a specialized IBM i security operations assistant.
425+
You help administrators identify security vulnerabilities, audit system configurations, and remediate security issues.
426+
Your role is to:
427+
- Identify security vulnerabilities and misconfigurations
428+
- Assess user privileges and special authorities
429+
- Audit file and object permissions for *PUBLIC access
430+
- Detect potential attack vectors (triggers, impersonation, privilege escalation)
431+
- Generate remediation commands for security lockdown
432+
- Explain security risks in business terms
433+
- Provide actionable recommendations for hardening system security
434+
435+
IMPORTANT SECURITY NOTES:
436+
- Always explain the security implications of findings
437+
- Distinguish between read-only assessment tools and destructive remediation tools
438+
- For remediation tools (like execute_impersonation_lockdown), warn users about system changes
439+
- Recommend testing remediation commands in development before production
440+
- Prioritize findings by severity (critical vulnerabilities first)
441+
442+
Focus on helping administrators understand their security posture and take appropriate action to protect their IBM i systems."""
443+
444+
llm = get_model(model_id)
445+
446+
agent = create_agent(
447+
model=llm,
448+
tools=tools,
449+
system_prompt=system_message,
450+
checkpointer=get_shared_checkpointer(),
451+
store=get_shared_store(),
452+
name="IBM i Security Operations",
453+
**kwargs
454+
)
455+
yield agent, session
456+
457+
return agent_session()
458+
373459
# -----------------------------------------------------------------------------
374460
# Agent Registry and Factory Pattern
375461
# -----------------------------------------------------------------------------
@@ -379,6 +465,7 @@ async def agent_session():
379465
"discovery": create_sysadmin_discovery_agent,
380466
"browse": create_sysadmin_browse_agent,
381467
"search": create_sysadmin_search_agent,
468+
"security": create_security_ops_agent,
382469
}
383470

384471
async def create_ibmi_agent(agent_type: str, **kwargs) -> _AsyncGeneratorContextManager[tuple[Any, Any], None]:
@@ -404,7 +491,8 @@ def list_available_agents() -> Dict[str, str]:
404491
"performance": "System performance monitoring and analysis",
405492
"discovery": "High-level system discovery and summarization",
406493
"browse": "Detailed system browsing and exploration",
407-
"search": "System search and lookup capabilities"
494+
"search": "System search and lookup capabilities",
495+
"security": "Security vulnerability assessment and remediation"
408496
}
409497

410498
def set_verbose_logging(enabled: bool):
@@ -609,7 +697,7 @@ async def test_agents():
609697
"gpt-oss:20b", # Default Ollama model
610698
"ollama:llama3.1", # Explicit Ollama model
611699
"openai:gpt-4o", # OpenAI model
612-
"anthropic:claude-3.7-sonnet" # Anthropic model
700+
"aanthropic:claude-3-7-sonnet-20250219" # Anthropic model
613701
]
614702

615703
print("Available model options:")

agents/frameworks/langchain/src/ibmi_agents/agents/test_agents.py

Lines changed: 61 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import asyncio
1313
import sys
1414
import os
15+
from typing import Optional
1516

1617
# Disable LangSmith tracing for tests
1718
os.environ["LANGCHAIN_TRACING_V2"] = "false"
@@ -30,19 +31,30 @@
3031
"performance": "What is my system status? Give me CPU and memory metrics.",
3132
"discovery": "Give me an overview of available system services.",
3233
"browse": "Show me services in the QSYS2 schema.",
33-
"search": "Search for services related to system status."
34+
"search": "Search for services related to system status.",
35+
"security": "Check for user profiles vulnerable to impersonation attacks."
3436
}
3537

36-
async def test_single_agent(agent_type: str, model_id: str = "gpt-oss:20b"):
38+
async def test_single_agent(agent_type: str, model_id: str = "gpt-oss:20b", category: Optional[str] = None):
3739
"""Test a single agent with a sample query."""
3840
print(f"\n{'='*80}")
3941
print(f"Testing {agent_type.upper()} Agent")
42+
if category:
43+
print(f"Category Filter: {category}")
4044
print(f"{'='*80}\n")
4145

4246
try:
4347
# Create agent context
4448
print(f"🔧 Creating {agent_type} agent with model {model_id}...")
45-
ctx = await create_ibmi_agent(agent_type, model_id=model_id)
49+
if category:
50+
print(f" Filtering by category: {category}")
51+
52+
# Pass category parameter if provided (only for security agent)
53+
kwargs = {"model_id": model_id}
54+
if category and agent_type == "security":
55+
kwargs["category"] = category
56+
57+
ctx = await create_ibmi_agent(agent_type, **kwargs)
4658

4759
async with ctx as (agent, session):
4860
print(f"✅ Agent created: {agent.name}\n")
@@ -111,16 +123,27 @@ async def test_all_agents(model_id: str = "gpt-oss:20b"):
111123

112124
return all(results.values())
113125

114-
async def interactive_mode(agent_type: str, model_id: str = "gpt-oss:20b"):
126+
async def interactive_mode(agent_type: str, model_id: str = "gpt-oss:20b", category: Optional[str] = None):
115127
"""Interactive chat mode with a specific agent."""
116128
print(f"\n{'='*80}")
117129
print(f"Interactive Mode - {agent_type.upper()} Agent")
130+
if category:
131+
print(f"Category Filter: {category}")
118132
print(f"{'='*80}\n")
119133

120134
try:
121135
# Create agent context
122-
print(f"🔧 Initializing {agent_type} agent with {model_id}...\n")
123-
ctx = await create_ibmi_agent(agent_type, model_id=model_id)
136+
print(f"🔧 Initializing {agent_type} agent with {model_id}...")
137+
if category:
138+
print(f" Filtering by category: {category}")
139+
print()
140+
141+
# Pass category parameter if provided (only for security agent)
142+
kwargs = {"model_id": model_id}
143+
if category and agent_type == "security":
144+
kwargs["category"] = category
145+
146+
ctx = await create_ibmi_agent(agent_type, **kwargs)
124147

125148
async with ctx as (agent, session):
126149
print(f"✅ {agent.name} ready!\n")
@@ -171,19 +194,32 @@ async def interactive_mode(agent_type: str, model_id: str = "gpt-oss:20b"):
171194
import traceback
172195
traceback.print_exc()
173196

174-
async def quick_test(model_id: str = "gpt-oss:20b"):
197+
async def quick_test(model_id: str = "gpt-oss:20b", category: Optional[str] = None, agent_filter: Optional[str] = None):
175198
"""Quick test - just verify all agents can be created."""
176199
print("\n" + "="*80)
177200
print("Quick Agent Creation Test")
178201
print("="*80)
179-
print(f"Model: {model_id}\n")
202+
print(f"Model: {model_id}")
203+
if category:
204+
print(f"Category Filter: {category}")
205+
print()
180206

181207
results = {}
182208

183-
for agent_type in AVAILABLE_AGENTS.keys():
209+
# Filter to specific agent if requested
210+
agents_to_test = [agent_filter] if agent_filter else list(AVAILABLE_AGENTS.keys())
211+
212+
for agent_type in agents_to_test:
184213
try:
185214
print(f"Creating {agent_type} agent...", end=" ")
186-
ctx = await create_ibmi_agent(agent_type, model_id=model_id)
215+
216+
# Pass category parameter if provided (only for security agent)
217+
kwargs = {"model_id": model_id}
218+
if category and agent_type == "security":
219+
kwargs["category"] = category
220+
print(f"(category: {category})...", end=" ")
221+
222+
ctx = await create_ibmi_agent(agent_type, **kwargs)
187223
async with ctx as (agent, session):
188224
print(f"✅ {agent.name}")
189225
results[agent_type] = True
@@ -235,6 +271,12 @@ def main():
235271
help="Test specific agent type"
236272
)
237273

274+
parser.add_argument(
275+
"--category",
276+
choices=["vulnerability-assessment", "audit", "remediation", "user-management"],
277+
help="Filter security agent tools by category (only applies to security agent)"
278+
)
279+
238280
parser.add_argument(
239281
"--interactive",
240282
action="store_true",
@@ -278,15 +320,21 @@ def main():
278320
if args.interactive and not args.agent:
279321
parser.error("--interactive requires --agent to be specified")
280322

323+
if args.category and not args.agent:
324+
parser.error("--category requires --agent to be specified")
325+
326+
if args.category and args.agent != "security":
327+
parser.error("--category can only be used with --agent security")
328+
281329
# Run appropriate test mode
282330
try:
283331
if args.quick:
284-
success = asyncio.run(quick_test(args.model))
332+
success = asyncio.run(quick_test(args.model, args.category, args.agent))
285333
elif args.interactive:
286-
asyncio.run(interactive_mode(args.agent, args.model))
334+
asyncio.run(interactive_mode(args.agent, args.model, args.category))
287335
success = True
288336
elif args.agent:
289-
success = asyncio.run(test_single_agent(args.agent, args.model))
337+
success = asyncio.run(test_single_agent(args.agent, args.model, args.category))
290338
else:
291339
success = asyncio.run(test_all_agents(args.model))
292340

tools/security/security-ops.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# Security Vulnerability Assessment and Remediation Tools
22
# Purpose: Comprehensive security analysis tools for identifying vulnerabilities,
3+
# Based on SQL script by Scott Forstie
34
# assessing user privileges, file permissions, and potential attack vectors on IBM i systems
45

56
sources:

0 commit comments

Comments
 (0)