Skip to content

Commit 80f16bb

Browse files
authored
fix(graph): reject unknown graph names in /graph/search with a 400 (#1290)
1 parent eed2520 commit 80f16bb

3 files changed

Lines changed: 42 additions & 18 deletions

File tree

core/database_arango.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,9 @@
3232
CODE_DB_VERSION = 2
3333
AQL_QUERY_MAX_TTL = 3600 * 12
3434

35-
LINK_TYPE_TO_GRAPH = {
36-
"tagged": "tags",
37-
"stix": "stix",
38-
}
35+
# Edge collections that back the defined ArangoDB graphs (see create_graphs);
36+
# these are the only names neighbors() can traverse with `@@graph`.
37+
TRAVERSABLE_GRAPHS = {"links", "acls"}
3938

4039
TESTING = "unittest" in sys.modules.keys()
4140

@@ -862,6 +861,11 @@ def neighbors(
862861
- the relationships (edges),
863862
- total neighbor (vertices) count
864863
"""
864+
if graph not in TRAVERSABLE_GRAPHS:
865+
raise ValueError(
866+
f"Cannot traverse graph '{graph}': expected one of "
867+
f"{sorted(TRAVERSABLE_GRAPHS)}."
868+
)
865869
query_filter = ""
866870
args = {
867871
"extended_id": self.extended_id,

core/web/apiv2/graph.py

Lines changed: 17 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -142,20 +142,23 @@ def search(httpreq: Request, request: GraphSearchRequest) -> GraphSearchResponse
142142
raise HTTPException(
143143
status_code=404, detail=f"Source object {request.source} not found"
144144
)
145-
vertices, paths, total = yeti_object.neighbors(
146-
link_types=request.link_types,
147-
target_types=request.target_types,
148-
direction=request.direction,
149-
filter=request.filter,
150-
include_original=request.include_original,
151-
graph=request.graph,
152-
min_hops=request.min_hops or request.hops,
153-
max_hops=request.max_hops or request.hops,
154-
count=request.count,
155-
offset=request.page * request.count,
156-
sorting=request.sorting,
157-
user=httpreq.state.user,
158-
)
145+
try:
146+
vertices, paths, total = yeti_object.neighbors(
147+
link_types=request.link_types,
148+
target_types=request.target_types,
149+
direction=request.direction,
150+
filter=request.filter,
151+
include_original=request.include_original,
152+
graph=request.graph,
153+
min_hops=request.min_hops or request.hops,
154+
max_hops=request.max_hops or request.hops,
155+
count=request.count,
156+
offset=request.page * request.count,
157+
sorting=request.sorting,
158+
user=httpreq.state.user,
159+
)
160+
except ValueError as error:
161+
raise HTTPException(status_code=400, detail=str(error))
159162
return GraphSearchResponse(vertices=vertices, paths=paths, total=total)
160163

161164

tests/apiv2/graph.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,23 @@ def test_get_neighbors(self):
6868
self.assertEqual(edges[0][0]["target"], self.observable2.extended_id)
6969
self.assertEqual(edges[0][0]["type"], "resolves")
7070

71+
def test_get_neighbors_unknown_graph(self):
72+
# An unknown graph name (e.g. the retired "tagged" graph) has no edge
73+
# collection to traverse; the API must reject it cleanly, not 500.
74+
response = client.post(
75+
"/api/v2/graph/search",
76+
json={
77+
"source": self.observable1.extended_id,
78+
"hops": 1,
79+
"graph": "tagged",
80+
"direction": "any",
81+
"include_original": False,
82+
},
83+
)
84+
data = response.json()
85+
self.assertEqual(response.status_code, 400, data)
86+
self.assertIn("Cannot traverse graph 'tagged'", data["detail"])
87+
7188
def test_get_neighbors_bad_hops(self):
7289
response = client.post(
7390
"/api/v2/graph/search",

0 commit comments

Comments
 (0)