This SonarQube Plugin is designed to test Apigee apiproxies. The goals is to help API developpers in doing a static analysis and providing issues to the Sonar engine.
The rules are based on the apigeecs/bundle-linter and on this document about best-practices.
All rules are not yet implemented (see below). Apigee Shared Flows are not yet supported.
Tested with Sonarqube 5.6, 5.6.1, 5.6.6, 5.6.7 LTS, 6.7.1 LTS and 7.0.
![]() |
![]() |
To work, the plugin sonar-xml-plugin MUST be installed.
As Apigee also deals with Javascript and Python, it would be pertinent to install sonar-python-plugin and sonar-javascript-plugin, but it's not mandatory.
For SonarQube from 5.6 up to 5.6.6 :
- Check that the sonarXML Plugin is already installed (minimum release 1.4.3.1027)
- Put the file sonar-apigee-plugin-X.X.X.jar in the directory $SONARQUBE_HOME/extensions/plugins. (the jar is available in the release section)
- Restart the server
For SonarQube from 5.6.7 and later (including 6.7.*)
- Check that the sonarXML Plugin is already installed (minimum release 1.4.3.1027)
- Use the Marketplace Update Center to install the Apigee plugin :

- Restart the server
Finally :
- Activate all rules in the sonar way profile or make the "Sonar way Apigee" quality profile as default.
- Add
.wsdlas suffix to be analyzed in the XMLPlugin administration.
If you want to try the very last version :
mvn clean install
You'll get a jar file in the target directory.
Copy this jar in the directory $SONARQUBE_HOME/extensions/plugins and restart the server.
- because companies, like mine, prefer using a centralized platform like Sonar, instead of an standalone tool
- because SonarQube provides a lot of tools, measures, issue management, ... out-of-the-box
- because SonarQube is well integrated with CI platform like Jenkins. It's part of continuous delivery.
This plugin shares the classloader of sonar-xml-plugin thanks to the usage of <basePlugin>.
Adding the check classes in the package org.sonar.plugins.xml.checks is the only way to be able to use XmlSourceCode.getDocument(boolean) since this method is protected.
The rule IDs come from the apigeecs/bundle-linter. Other rules start from "500" to not interfer with the first rules. Example : PD500.
Legend :
✅ : implemented
✖️ : not yet implemented
❌ : won't be implemented. See details in Description column
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✖️ | BN001 | Bundle folder structure correctness. | Bundles have a clear structure. | |
| ✖️ | BN002 | Extraneous files. | Ensure each folder contains approrpriate resources in the bundle. | |
| ✅ | BN003 | Major | Cache Coherence | A bundle that includes cache reads should include cache writes with the same keys. |
| ✖️ | BN004 | Unused variables. | Within a bundle variables created should be used in conditions, resource callouts, or policies. | |
| ✅ | BN005 | Minor | Unattached policies. | Unattached policies are dead code and should be removed from production bundles. |
| ✖️ | BN006 | Bundle size - policies. | Large bundles are a symptom of poor design. A high number of policies is predictive of an oversized bundle. | |
| ✖️ | BN007 | Bundle size - resource callouts. | Large bundles are a symptom of poor design. A high number of resource callouts is indicative of underutilizing out of the box Apigee policies. | |
| ✖️ | BN008 | IgnoreUnresolvedVariables and FaultRules | Use of IgnoreUnresolvedVariables without the use of FaultRules may lead to unexpected errors. | |
| ✖️ | BN009 | Statistics Collector - duplicate policies | Warn on duplicate policies when no conditions are present or conditions are duplicates. | |
| ✅ | BN500 | Info | Description length | A Description tag should have more than N chars to be useful. "N" can be modified in the Quality Profile. The default value is 5. |
| ✅ | BN501 | Blocker | Description pattern | The Description of the APIProxy must be compliant with a pattern defined in the Quality Profile. For example : .*\(code=([A-Z0-9]{4})\).*. The default pattern is .* |
| ✅ | BN502 | Minor | Unattached resources. | Unattached resources are dead code and should be removed from production bundles. This rule only checks XSL, XSD and WSDL resources. Don't forget to add .wsdl as suffix to be analyzed in the XMLPlugin administration. |
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✅ | PD001 | Blocker | RouteRules to Targets | RouteRules should map to defined Targets |
| ✅ | PD002 | Blocker | Unreachable Route Rules - defaults | Only one RouteRule should be present without a condition |
| ✅ | PD003 | Blocker | Unreachable Route Rules | RouteRule without a condition should be last. |
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✅ | TD001 | Major | Mgmt Server as Target | Discourage calls to the Management Server from a Proxy via target. |
| ✅ | TD002 | Major | Use Target Servers | Encourage the use of target servers |
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✅ | FL001 | Blocker | Unconditional Flows | Only one unconditional flow will get executed. Error if more than one was detected. |
| ✅ | FL500 | Critical | Default flow | A default flow must be defined to catch all requests on undefined resources. |
| ✅ | FL501 | Blocker | Unreachable flow | Flow without a condition must be last. |
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✅ | ST001 | Minor | Empty Step | Empty steps clutter the bundle. (Should never happen, Apigee already blocks this error form occuring.) |
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✅ | PO001 | Major | JSON Threat Protection | A check for a body element should be performed before policy execution. |
| ✅ | PO002 | Major | XML Threat Protection | A check for a body element should be performed before policy execution. |
| ✅ | PO003 | Major | Extract Variables with JSONPayload | A check for a body element should be performed before policy execution. |
| ✅ | PO004 | Major | Extract Variables with XMLPayload | A check for a body element should be performed before policy execution. |
| ✅ | PO005 | Major | Extract Variables with FormParam | A check for a body element should be performed before policy execution. |
| ✖️ | PO006 | Policy Naming Conventions - default name | Policy names should not be default. | |
| ✅ | PO007 | Minor | Policy Naming Conventions - type indication | It is recommended that the policy name include an indicator of the policy type. |
| ✅ | PO008 | Minor | Policy Name Attribute Conventions | It is recommended that the policy name attribute match the display name of the policy. |
| ✅ | PO009 | Major | Service Callout Target - Mgmt Server | Targeting management server may result in higher than expected latency use with caution. |
| ✖️ | PO010 | Service Callout Target - Target Server | Encourage use of target servers. | |
| ✖️ | PO011 | Service Callout Target - Dynamic URLs | Error on dynamic URLs in target server URL tag. | |
| ✖️ | PO012 | Service Callout Target - Script Target Node | JSHint, ESLint. | |
| ❌ | PO013 | Resource Call Out - Javascript | Analyzed by sonar-javascript-plugin. | |
| ❌ | PO014 | Resource Call Out - Java | Analyzed by sonar-java-plugin. | |
| ❌ | PO015 | Resource Call Out - Python | Analyzed by sonar-python-plugin. | |
| ✖️ | PO016 | Statistics Collector - duplicate variables | Warn on duplicate variables. | |
| ✖️ | PO017 | Misconfigured - FaultRules/Fault Rule in Policy | FaultRules are configured in ProxyEndpoints and TargetEndpoints. | |
| ✅ | PO018 | Major | Regex Lookahead/Lookbehind are Expensive - Threat Protection Policy | Regular expressions that include lookahead or lookbehind perform slowly on large payloads and are typically not required. |
| ✅ | PO019 | Major | Reserved words as variables - ServiceCallout Request | Using "request" as the name of a Request may cause unexpected side effects. |
| ✅ | PO020 | Major | Reserved words as variables - ServiceCallout Response | Using "response" as the name of a Response may cause unexpected side effects. |
| ✖️ | PO021 | Statistics Collector - reserved variables | Warn on insertion of duplicate variables. | |
| ✖️ | PO022 | Nondistributed Quota | When using nondistributed quota the number of allowed calls is influenced by the number of Message Processors (MPs) deployed. This may lead to higher than expected transactions for a given quota as MPs now autoscale. | |
| ✖️ | PO023 | Quota Policy Reuse | When the same Quota policy is used more than once you must ensure that the conditions of execution are mutually exclusive or that you intend for a call to count more than once per message processed. | |
| ✖️ | PO024 | Cache Error Responses | By default the ResponseCache policy will cache non 200 responses. Either create a condition or use policy configuration options to exclude non 200 responses. | |
| ✅ | PO500 | Major | Avoid Python language | Python scripts can introduce performance bottlenecks for simple executions, as it is interpreted at runtime. |
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✅ | FR001 | Major | No Condition on FaultRule | It's not a best practice to have a FaultRule without an outer condition, which automatically makes the FaultRule true. |
| Status | Rule ID | Severity | Name | Description |
|---|---|---|---|---|
| ✖️ | CC001 | Literals in Conditionals | Warn on literals in any conditional statement. | |
| ✖️ | CC002 | Null Blank Checks | Blank checks should also check for null conditions. (to be reviewed) | |
| ✅ | CC003 | Minor | Long condition statement | Conditions should not be longer than "N" characters. "N" can be modified in the Quality Profile. The default value is 255. |
| ✖️ | CC004 | Overly complex condition | Condition complexity should be limited to fix number of variables and conjunctions. | |
| ✖️ | CC006 | Detect logical absurdities | Conditions should not have internal logic conflicts - warn when these are detected. |

