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
4 changes: 3 additions & 1 deletion addOns/graphql/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ All notable changes to this add-on will be documented in this file.
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).

## Unreleased

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

## [0.28.0] - 2025-03-26
### Fixed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ public List<Alert> getExampleAlerts() {
GraphQlParser.createIntrospectionAlert().build(),
GraphQlFingerprinter.createFingerprintingAlert(
new DiscoveredGraphQlEngine("example", uri))
.build());
.build(),
GraphQlCycleDetector.getExampleAlert());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.zaproxy.zap.extension.api.ApiImplementor;
import org.zaproxy.zap.extension.api.ApiResponse;
import org.zaproxy.zap.extension.api.ApiResponseElement;
import org.zaproxy.zap.extension.api.ApiView;

public class GraphQlApi extends ApiImplementor {

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

private static final String OPTION_ARGS_TYPE = "optionArgsType";
private static final String OPTION_CYCLE_DETECTION_MODE = "optionCycleDetectionMode";
private static final String OPTION_QUERY_SPLIT_TYPE = "optionQuerySplitType";
private static final String OPTION_REQUEST_METHOD = "optionRequestMethod";

private final GraphQlParam options;

/** Provided only for API client generator usage. */
public GraphQlApi() {
this.addApiAction(
new ApiAction(ACTION_IMPORT_FILE, new String[] {PARAM_ENDPOINT, PARAM_FILE}));
this.addApiAction(
new ApiAction(
ACTION_IMPORT_URL,
new String[] {PARAM_ENDPOINT},
new String[] {PARAM_URL}));
this(null);
}

/**
Expand All @@ -55,8 +58,19 @@ public GraphQlApi() {
* @param options the options that will be exposed through the API.
*/
public GraphQlApi(GraphQlParam options) {
this();
this.addApiAction(
new ApiAction(ACTION_IMPORT_FILE, new String[] {PARAM_ENDPOINT, PARAM_FILE}));
this.addApiAction(
new ApiAction(
ACTION_IMPORT_URL,
new String[] {PARAM_ENDPOINT},
new String[] {PARAM_URL}));
this.addApiView(new ApiView(OPTION_ARGS_TYPE));
this.addApiView(new ApiView(OPTION_CYCLE_DETECTION_MODE));
this.addApiView(new ApiView(OPTION_QUERY_SPLIT_TYPE));
this.addApiView(new ApiView(OPTION_REQUEST_METHOD));
addApiOptions(options);
this.options = options;
}

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

@Override
public ApiResponse handleApiOptionView(String name, JSONObject params) throws ApiException {
if (this.options == null) {
return null;
}
return switch (name) {
case OPTION_ARGS_TYPE ->
new ApiResponseElement(OPTION_ARGS_TYPE, options.getArgsType().name());
case OPTION_CYCLE_DETECTION_MODE ->
new ApiResponseElement(
OPTION_CYCLE_DETECTION_MODE, options.getCycleDetectionMode().name());
case OPTION_QUERY_SPLIT_TYPE ->
new ApiResponseElement(
OPTION_QUERY_SPLIT_TYPE, options.getQuerySplitType().name());
case OPTION_REQUEST_METHOD ->
new ApiResponseElement(
OPTION_REQUEST_METHOD, options.getRequestMethod().name());
default -> super.handleApiOptionView(name, params);
};
}

private void importFile(JSONObject params) throws ApiException {
try {
GraphQlParser parser =
Expand Down
Loading