Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions swarms/structs/graph_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -2554,7 +2554,15 @@ def visualize(
ImportError: If graphviz is not installed.
Exception: If visualization generation fails.
"""
output_path = f"{self.name}_visualization_{str(uuid.uuid4())}"
# Sanitize here, in the path that is actually used. graphviz treats
# the argument as a filesystem path, so a name containing "/" (or
# any other separator) renders into a directory that does not exist
# instead of producing a file.
safe_name = "".join(
c if c.isalnum() or c in "-_" else "_"
for c in (self.name or "GraphWorkflow")
)
output_path = f"{safe_name}_visualization_{str(uuid.uuid4())}"

if not GRAPHVIZ_AVAILABLE:
error_msg = "Graphviz is not installed. Install it with: pip install graphviz"
Expand Down Expand Up @@ -2746,14 +2754,6 @@ def visualize(
for node_id in layer:
layer_graph.node(node_id)

# Generate output path
if output_path is None:
safe_name = "".join(
c if c.isalnum() or c in "-_" else "_"
for c in (self.name or "GraphWorkflow")
)
output_path = f"{safe_name}_visualization"

# Render the graph
output_file = dot.render(
output_path, view=view, cleanup=True
Expand Down
29 changes: 29 additions & 0 deletions tests/structs/test_graph_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -1308,5 +1308,34 @@ def test_compile_calls_validate_and_reports_errors():
assert len(result["errors"]) > 0


def test_visualize_sanitizes_the_workflow_name_into_the_output_path():
"""A name with a path separator must not become a directory.

The sanitization used to live in an `if output_path is None:` branch
that was unreachable — `output_path` is assigned unconditionally above
it — so the live path used the raw name and graphviz tried to render
into a directory that does not exist.
"""
import inspect

source = inspect.getsource(GraphWorkflow.visualize)

# The dead branch that used to hold the sanitization is gone.
assert "if output_path is None" not in source

# And the sanitization now runs before graphviz availability is checked,
# i.e. in the path that actually builds the filename.
live_path = source.split("if not GRAPHVIZ_AVAILABLE")[0]
assert "safe_name" in live_path

workflow = GraphWorkflow(name="team/alpha")
safe = "".join(
c if c.isalnum() or c in "-_" else "_"
for c in (workflow.name or "GraphWorkflow")
)
assert "/" not in safe
assert safe == "team_alpha"


if __name__ == "__main__":
pytest.main([__file__, "-v"])
Loading