How to Handle Security Boundaries with sly_data in Neuro SAN Studio: A Complete Guide
Neuro SAN Studio enforces a strict security contract around the sly_data dictionary to prevent secret leakage, requiring tools to never log its contents, explicitly pass it between upstream and downstream components, and validate required keys fail-fast.
Neuro SAN Studio uses a mutable Python dictionary called sly_data to propagate contextual information between chained CodedTool instances. Because this dictionary may contain sensitive data like ServiceNow session IDs or API keys, the framework mandates specific security boundaries that govern how data flows from upstream tools to downstream consumers via to_downstream and from_downstream patterns.
Understanding the sly_data Security Contract
The security model for sly_data in Neuro SAN Studio rests on four inviolable rules enforced throughout the codebase:
-
Never log
sly_datacontents – Every tool implementation contains explicit comments warning thatsly_datamay contain secrets. For example, incoded_tools/tools/now_agents/nowagent_api_send_message.pyat line 75, the code warns:# NOTE: sly_data may contain secrets – never log it. -
Never log environment variable values – When copying environment variables into
sly_data, tools must log only the variable name, never the value. The helper_get_env_variableinnowagent_api_send_message.py(lines 48-55) demonstrates this pattern by logging the lookup attempt while suppressing the actual secret value. -
Explicit key passing with fail-fast validation – Downstream tools must receive
sly_dataexplicitly and raiseKeyErrorimmediately if required keys are missing. Incoded_tools/tools/now_agents/nowagent_api_retrieve_message.py(lines 70-73), the tool expectssly_data["session_path"]and fails fast if absent, preventing silent failures that could mask security issues. -
Runner-supplied defaults without interpretation – The CLI runner in
run.py(lines 53-58) can supply a default empty dictionary viaDEFAULT_SLY_DATAenvironment variable, but treats this purely as a string fallback without attempting to parse or log secret content.
Data Flow Between Upstream and Downstream Tools
The sly_data dictionary serves as the conduit for to_downstream and from_downstream communication in multi-tool workflows. Upstream tools (like NowAgentSendMessage) create or enrich sly_data, while downstream tools (like NowAgentRetrieveMessage) consume these values to locate external resources.
Because Python passes dictionaries by reference, the same mutable object flows through the entire tool chain. This design allows intermediate tools to safely append non-sensitive metadata without exposing existing secret keys to logs or external services.
Implementing Security Boundaries in Practice
Propagating Session IDs from Upstream to Downstream
The following pattern demonstrates secure propagation of a session identifier between two tools without logging secrets:
# Upstream tool: NowAgentSendMessage
from coded_tools.tools.now_agents.nowagent_api_send_message import NowAgentSendMessage
send_tool = NowAgentSendMessage()
sly_data = {} # Empty dict supplied by runner
send_args = {"inquiry": "What is the ticket status?", "agent_id": "abc123"}
# Tool mutates sly_data to add session_path
send_tool.invoke(send_args, sly_data)
# Value exists but must never be logged in production
assert "session_path" in sly_data
# Downstream tool: NowAgentRetrieveMessage
from coded_tools.tools.now_agents.nowagent_api_retrieve_message import NowAgentRetrieveMessage
retrieve_tool = NowAgentRetrieveMessage()
retrieve_args = {"inquiry": "", "agent_id": "abc123"}
# Consumes the session_path added by upstream tool
response = retrieve_tool.invoke(retrieve_args, sly_data)
Both tools share the identical sly_data object reference, ensuring the session identifier propagates securely without duplication or re-derivation.
Safely Adding Non-Secret Metadata
When enriching sly_data with harmless metadata for downstream consumption, mutate the dictionary directly while avoiding secret exposure:
from datetime import datetime
def enrich_with_timestamp(sly_data: dict) -> None:
"""Add harmless timestamp metadata for downstream tools."""
sly_data["request_timestamp"] = datetime.utcnow().isoformat()
# Called between upstream and downstream tools
enrich_with_timestamp(sly_data)
Downstream tools can now access sly_data["request_timestamp"] without risk of secret exposure.
Preventing Accidental Secret Logging
To maintain security boundaries, implement logging functions that reveal only dictionary structure, never values:
import logging
def safe_log_operation(msg: str, sly_data: dict) -> None:
"""Log operation context without exposing secret values."""
# Log only key names, never values
logging.debug("%s - sly_data keys: %s", msg, list(sly_data.keys()))
# Safe usage - logs only that session_path exists, not its value
safe_log_operation("After upstream send", sly_data)
Framework Guard-Rails and Validation
Neuro SAN Studio provides several built-in mechanisms to enforce these security boundaries automatically:
-
Typed CodedTool base class – Enforces that every
invokemethod signature includessly_data: Dict[str, Any], ensuring the security context is always available and type-checked. -
Unit test validation – The test suite in
tests/coded_tools/tools/now_agents/unit_tests/test_unit_message_sending_mocked.pyexplicitly verifies thatsly_datamutation is limited to expected keys likesession_path, preventing unintended side effects. Similarly,test_unit_message_retrieval_mocked.pyvalidates that tools raise exceptions when requiredsly_datakeys are missing. -
Non-secret reference implementations – Tools like
coded_tools/tools/visual_question_answering/vqa.pydemonstrate safesly_datausage for non-sensitive data (file paths) while maintaining the "never log" comment discipline.
Summary
- Never log
sly_datavalues – Log only key names or operation context, never the dictionary contents or environment variable values copied into it. - Use explicit pass-by-reference – The same
sly_datadict flows from upstream tools (likeNowAgentSendMessage) to downstream tools (likeNowAgentRetrieveMessage), preventing secret duplication. - Fail fast on missing keys – Downstream tools must raise
KeyErrorimmediately when requiredsly_datakeys are absent, as implemented innowagent_api_retrieve_message.py. - Leverage runner defaults safely – The
NeuroSanRunnerinrun.pysupplies default empty dictionaries without interpreting content as secrets. - Validate with tests – Unit tests enforce that only expected keys are mutated and that missing session data triggers immediate failures.
Frequently Asked Questions
What happens if a downstream tool doesn't receive the required sly_data key?
The downstream tool raises a KeyError immediately. For example, NowAgentRetrieveMessage in coded_tools/tools/now_agents/nowagent_api_retrieve_message.py attempts to access sly_data["session_path"] directly, causing a hard failure if the upstream tool failed to populate the session identifier. This fail-fast behavior prevents tools from operating on stale or invalid security contexts.
Can I log sly_data for debugging purposes during development?
No. Even during development, you must never interpolate sly_data into log messages. The framework's security contract, as documented in nowagent_api_send_message.py and other tools, explicitly prohibits logging because the dictionary may contain production secrets like ServiceNow session IDs or API keys. Instead, log only the keys present using list(sly_data.keys()).
How does sly_data differ from regular tool arguments?
While tool arguments (the first parameter to invoke) are typically logged for observability, sly_data is explicitly treated as a security boundary container. According to the Neuro SAN Studio source code, sly_data bypasses standard logging pipelines and must be passed as a separate dictionary parameter to maintain isolation between operational data and sensitive session state.
Is sly_data encrypted during transmission between tools?
No, sly_data exists only as an in-memory Python dictionary passed by reference between CodedTool instances within the same process. The security boundary relies on process isolation and the "never log" contract rather than encryption, since the data never leaves the runtime memory during normal tool chaining operations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →