Skip to content

Commit 981fda9

Browse files
committed
graphql: Add Circular Type Reference Detection
Signed-off-by: ricekot <[email protected]>
1 parent b5e550e commit 981fda9

23 files changed

+1202
-370
lines changed

addOns/graphql/CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ All notable changes to this add-on will be documented in this file.
44
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
55

66
## Unreleased
7-
7+
### Added
8+
- GraphQL Cycle detection: Imported schemas are processed for circular type references, and an alert is created for each unique circular relationship that is found.
9+
The cycle detection exhaustiveness and the maximum number of alerts raised are configurable.
810

911
## [0.28.0] - 2025-03-26
1012
### Fixed

addOns/graphql/src/main/java/org/zaproxy/addon/graphql/ExtensionGraphQl.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -307,6 +307,7 @@ public List<Alert> getExampleAlerts() {
307307
GraphQlParser.createIntrospectionAlert().build(),
308308
GraphQlFingerprinter.createFingerprintingAlert(
309309
new DiscoveredGraphQlEngine("example", uri))
310-
.build());
310+
.build(),
311+
GraphQlCycleDetector.getExampleAlert());
311312
}
312313
}

addOns/graphql/src/main/java/org/zaproxy/addon/graphql/GraphQlApi.java

Lines changed: 43 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.zaproxy.zap.extension.api.ApiImplementor;
3030
import org.zaproxy.zap.extension.api.ApiResponse;
3131
import org.zaproxy.zap.extension.api.ApiResponseElement;
32+
import org.zaproxy.zap.extension.api.ApiView;
3233

3334
public class GraphQlApi extends ApiImplementor {
3435

@@ -39,14 +40,16 @@ public class GraphQlApi extends ApiImplementor {
3940
private static final String PARAM_URL = "url";
4041
private static final String PARAM_ENDPOINT = "endurl";
4142

43+
private static final String OPTION_ARGS_TYPE = "optionArgsType";
44+
private static final String OPTION_CYCLE_DETECTION_MODE = "optionCycleDetectionMode";
45+
private static final String OPTION_QUERY_SPLIT_TYPE = "optionQuerySplitType";
46+
private static final String OPTION_REQUEST_METHOD = "optionRequestMethod";
47+
48+
private final GraphQlParam options;
49+
50+
/** Provided only for API client generator usage. */
4251
public GraphQlApi() {
43-
this.addApiAction(
44-
new ApiAction(ACTION_IMPORT_FILE, new String[] {PARAM_ENDPOINT, PARAM_FILE}));
45-
this.addApiAction(
46-
new ApiAction(
47-
ACTION_IMPORT_URL,
48-
new String[] {PARAM_ENDPOINT},
49-
new String[] {PARAM_URL}));
52+
this(null);
5053
}
5154

5255
/**
@@ -55,8 +58,19 @@ public GraphQlApi() {
5558
* @param options the options that will be exposed through the API.
5659
*/
5760
public GraphQlApi(GraphQlParam options) {
58-
this();
61+
this.addApiAction(
62+
new ApiAction(ACTION_IMPORT_FILE, new String[] {PARAM_ENDPOINT, PARAM_FILE}));
63+
this.addApiAction(
64+
new ApiAction(
65+
ACTION_IMPORT_URL,
66+
new String[] {PARAM_ENDPOINT},
67+
new String[] {PARAM_URL}));
68+
this.addApiView(new ApiView(OPTION_ARGS_TYPE));
69+
this.addApiView(new ApiView(OPTION_CYCLE_DETECTION_MODE));
70+
this.addApiView(new ApiView(OPTION_QUERY_SPLIT_TYPE));
71+
this.addApiView(new ApiView(OPTION_REQUEST_METHOD));
5972
addApiOptions(options);
73+
this.options = options;
6074
}
6175

6276
@Override
@@ -80,6 +94,27 @@ public ApiResponse handleApiAction(String name, JSONObject params) throws ApiExc
8094
return ApiResponseElement.OK;
8195
}
8296

97+
@Override
98+
public ApiResponse handleApiOptionView(String name, JSONObject params) throws ApiException {
99+
if (this.options == null) {
100+
return null;
101+
}
102+
return switch (name) {
103+
case OPTION_ARGS_TYPE ->
104+
new ApiResponseElement(OPTION_ARGS_TYPE, options.getArgsType().name());
105+
case OPTION_CYCLE_DETECTION_MODE ->
106+
new ApiResponseElement(
107+
OPTION_CYCLE_DETECTION_MODE, options.getCycleDetectionMode().name());
108+
case OPTION_QUERY_SPLIT_TYPE ->
109+
new ApiResponseElement(
110+
OPTION_QUERY_SPLIT_TYPE, options.getQuerySplitType().name());
111+
case OPTION_REQUEST_METHOD ->
112+
new ApiResponseElement(
113+
OPTION_REQUEST_METHOD, options.getRequestMethod().name());
114+
default -> super.handleApiOptionView(name, params);
115+
};
116+
}
117+
83118
private void importFile(JSONObject params) throws ApiException {
84119
try {
85120
GraphQlParser parser =

0 commit comments

Comments
 (0)