-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Merging to release-5.10: [TT-15863] fix random version picking for not versioned API (#7380) #7394
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merging to release-5.10: [TT-15863] fix random version picking for not versioned API (#7380) #7394
Conversation
<details open> <summary><a href="https://tyktech.atlassian.net/browse/TT-15863" title="TT-15863" target="_blank">TT-15863</a></summary> <br /> <table> <tr> <th>Summary</th> <td>Random version being picked when not_versioned is set to true</td> </tr> <tr> <th>Type</th> <td> <img alt="Bug" src="https://tyktech.atlassian.net/rest/api/2/universal_avatar/view/type/issuetype/avatar/10303?size=medium" /> Bug </td> </tr> <tr> <th>Status</th> <td>In Dev</td> </tr> <tr> <th>Points</th> <td>N/A</td> </tr> <tr> <th>Labels</th> <td>-</td> </tr> </table> </details> <!-- do not remove this marker as it will break jira-lint's functionality. added_by_jira_lint --> --- This PR fixes an issue where a random version was picked for a non-versioned API. Instead of picking a random version for non-versioned APIs it will now: 1. Use the only defined version 2. Use the version called "Default", "default" or "" when multiple versions are present 3. Return error when multiple default versions are found 4. Return error when no version exists (cherry picked from commit 14c6d8f)
API Changes --- prev.txt 2025-10-01 13:32:46.832019867 +0000
+++ current.txt 2025-10-01 13:32:37.438030138 +0000
@@ -9140,6 +9140,10 @@
func (s *APISpec) AddUnloadHook(hook func())
AddUnloadHook adds a function to be called when the API spec is unloaded
+func (a *APISpec) CheckForAmbiguousDefaultVersions() bool
+ CheckForAmbiguousDefaultVersions checks if there are multiple ambiguous
+ default versions in the version data.
+
func (a *APISpec) CheckSpecMatchesStatus(r *http.Request, rxPaths []URLSpec, mode URLStatus) (bool, interface{})
CheckSpecMatchesStatus checks if a URL spec has a specific status.
Deprecated: The function doesn't follow go return conventions (T, ok);
@@ -9159,6 +9163,11 @@
takes the precedence. If the global one is `true`, value of the one in api
level doesn't matter.
+func (a *APISpec) GetSingleOrDefaultVersion() (versionInfo apidef.VersionInfo, ok bool)
+ GetSingleOrDefaultVersion determines and returns a single version or the
+ default version if only one or a default exists. Returns versionInfo and a
+ boolean indicating success or failure.
+
func (a *APISpec) GetTykExtension() *oas.XTykAPIGateway
func (a *APISpec) Init(authStore, sessionStore, healthStore, orgStore storage.Handler)
@@ -11392,36 +11401,38 @@
RequestStatus is a custom type to avoid collisions
const (
- VersionNotFound RequestStatus = "Version information not found"
- VersionDoesNotExist RequestStatus = "This API version does not seem to exist"
- VersionWhiteListStatusNotFound RequestStatus = "WhiteListStatus for path not found"
- VersionExpired RequestStatus = "Api Version has expired, please check documentation or contact administrator"
- APIExpired RequestStatus = "API has expired, please check documentation or contact administrator"
- EndPointNotAllowed RequestStatus = "Requested endpoint is forbidden"
- StatusOkAndIgnore RequestStatus = "Everything OK, passing and not filtering"
- StatusOk RequestStatus = "Everything OK, passing"
- StatusCached RequestStatus = "Cached path"
- StatusTransform RequestStatus = "Transformed path"
- StatusTransformResponse RequestStatus = "Transformed response"
- StatusTransformJQ RequestStatus = "Transformed path with JQ"
- StatusTransformJQResponse RequestStatus = "Transformed response with JQ"
- StatusHeaderInjected RequestStatus = "Header injected"
- StatusMethodTransformed RequestStatus = "Method Transformed"
- StatusHeaderInjectedResponse RequestStatus = "Header injected on response"
- StatusRedirectFlowByReply RequestStatus = "Exceptional action requested, redirecting flow!"
- StatusHardTimeout RequestStatus = "Hard Timeout enforced on path"
- StatusCircuitBreaker RequestStatus = "Circuit breaker enforced"
- StatusURLRewrite RequestStatus = "URL Rewritten"
- StatusVirtualPath RequestStatus = "Virtual Endpoint"
- StatusRequestSizeControlled RequestStatus = "Request Size Limited"
- StatusRequestTracked RequestStatus = "Request Tracked"
- StatusRequestNotTracked RequestStatus = "Request Not Tracked"
- StatusValidateJSON RequestStatus = "Validate JSON"
- StatusValidateRequest RequestStatus = "Validate Request"
- StatusInternal RequestStatus = "Internal path"
- StatusGoPlugin RequestStatus = "Go plugin"
- StatusPersistGraphQL RequestStatus = "Persist GraphQL"
- StatusRateLimit RequestStatus = "Rate Limited"
+ VersionNotFound RequestStatus = "Version information not found"
+ VersionDoesNotExist RequestStatus = "This API version does not seem to exist"
+ VersionWhiteListStatusNotFound RequestStatus = "WhiteListStatus for path not found"
+ VersionExpired RequestStatus = "Api Version has expired, please check documentation or contact administrator"
+ VersionDefaultForNotVersionedNotFound RequestStatus = "No default API version for this non-versioned API found"
+ VersionAmbiguousDefault RequestStatus = "Ambiguous default API version for this non-versioned API"
+ APIExpired RequestStatus = "API has expired, please check documentation or contact administrator"
+ EndPointNotAllowed RequestStatus = "Requested endpoint is forbidden"
+ StatusOkAndIgnore RequestStatus = "Everything OK, passing and not filtering"
+ StatusOk RequestStatus = "Everything OK, passing"
+ StatusCached RequestStatus = "Cached path"
+ StatusTransform RequestStatus = "Transformed path"
+ StatusTransformResponse RequestStatus = "Transformed response"
+ StatusTransformJQ RequestStatus = "Transformed path with JQ"
+ StatusTransformJQResponse RequestStatus = "Transformed response with JQ"
+ StatusHeaderInjected RequestStatus = "Header injected"
+ StatusMethodTransformed RequestStatus = "Method Transformed"
+ StatusHeaderInjectedResponse RequestStatus = "Header injected on response"
+ StatusRedirectFlowByReply RequestStatus = "Exceptional action requested, redirecting flow!"
+ StatusHardTimeout RequestStatus = "Hard Timeout enforced on path"
+ StatusCircuitBreaker RequestStatus = "Circuit breaker enforced"
+ StatusURLRewrite RequestStatus = "URL Rewritten"
+ StatusVirtualPath RequestStatus = "Virtual Endpoint"
+ StatusRequestSizeControlled RequestStatus = "Request Size Limited"
+ StatusRequestTracked RequestStatus = "Request Tracked"
+ StatusRequestNotTracked RequestStatus = "Request Not Tracked"
+ StatusValidateJSON RequestStatus = "Validate JSON"
+ StatusValidateRequest RequestStatus = "Validate Request"
+ StatusInternal RequestStatus = "Internal path"
+ StatusGoPlugin RequestStatus = "Go plugin"
+ StatusPersistGraphQL RequestStatus = "Persist GraphQL"
+ StatusRateLimit RequestStatus = "Rate Limited"
)
Statuses of the request, all are false-y except StatusOk and
StatusOkAndIgnore |
PR Code Suggestions ✨Explore these optional code suggestions:
|
🔍 Code Analysis Results🚀 Pull Request Analysis: Fix for Random Version Picking in Non-Versioned APIsThis pull request addresses a bug where the Tyk Gateway would select a random version for an API marked as 1. Change Impact AnalysisWhat this PR AccomplishesThe primary goal of this PR is to fix incorrect behavior for non-versioned APIs that have multiple versions defined. Previously, the gateway would arbitrarily pick one of the available versions. This change ensures that a specific, default version is chosen based on a clear set of rules, or an error is returned if a default version cannot be determined. Key Technical ChangesThe core changes are located in
Affected System ComponentsThe change directly impacts the Tyk Gateway's request processing pipeline. Specifically, it modifies the initial step of resolving which API version should handle an incoming request. This is a critical component for routing and applying version-specific policies. 2. Architecture VisualizationThe following flowchart illustrates the updated decision-making process within the graph TD
A[Start: Request for Non-Versioned API] --> B{"Is 'NotVersioned' true?"};
B -->|Yes| C{Check for Ambiguous Defaults};
B -->|No| H[Proceed with Standard Version Extraction];
C -->|Ambiguous| D["Return 'VersionAmbiguousDefault' Error"];
C -->|Not Ambiguous| E[Get Single or Default Version];
E -->|Found| F["Return Version & 'StatusOk'"];
E -->|Not Found| G["Return 'VersionDefaultForNotVersionedNotFound' Error"];
subgraph "New Logic for Non-Versioned APIs"
C
D
E
F
G
end
style D fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#f9f,stroke:#333,stroke-width:2px
style F fill:#9f9,stroke:#333,stroke-width:2px
Powered by Visor from Probelabs Last updated: 2025-10-01T13:38:58.416Z | Triggered by: opened | Commit: 3381147 |
🔍 Code Analysis Results✅ Security Check PassedNo security issues found – changes LGTM. Performance Issues (1)
Quality Issues (2)
Style Issues (1)
Dependency Issues (2)
Connectivity Issues (2)
Powered by Visor from Probelabs Last updated: 2025-10-01T13:38:59.401Z | Triggered by: opened | Commit: 3381147 |
|
User description
TT-15863 fix random version picking for not versioned API (#7380)
TT-15863
This PR fixes an issue where a random version was picked for a
non-versioned API.
Instead of picking a random version for non-versioned APIs it will now:
versions are present
PR Type
Bug fix, Tests
Description
Deterministic version selection for non-versioned APIs
New request statuses for default version issues
Helper methods to resolve default/ambiguous versions
Comprehensive unit tests for new logic
Diagram Walkthrough
File Walkthrough
api_definition.go
Deterministic version resolution and new statuses
gateway/api_definition.go
api_definition_test.go
Unit tests for version resolution logic
gateway/api_definition_test.go