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
68 changes: 68 additions & 0 deletions docs/swagger/docs.go
Original file line number Diff line number Diff line change
Expand Up @@ -8680,12 +8680,38 @@ const docTemplate = `{
"domain.GatewayRoute": {
"type": "object",
"properties": {
"allowed_cidrs": {
"description": "IPs allowed to access (empty = all)",
"type": "array",
"items": {
"type": "string"
}
},
"blocked_cidrs": {
"description": "IPs blocked from access",
"type": "array",
"items": {
"type": "string"
}
},
"created_at": {
"type": "string"
},
"dial_timeout": {
"description": "TCP dial timeout in milliseconds",
"type": "integer"
},
"id": {
"type": "string"
},
"idle_conn_timeout": {
"description": "Idle connection timeout in milliseconds",
"type": "integer"
},
"max_body_size": {
"description": "Max request body size in bytes",
"type": "integer"
},
"methods": {
"description": "New: HTTP methods to match (empty = all)",
"type": "array",
Expand Down Expand Up @@ -8723,6 +8749,14 @@ const docTemplate = `{
"description": "Maximum allowed requests per second per IP",
"type": "integer"
},
"require_tls": {
"description": "Force HTTPS for backend",
"type": "boolean"
},
"response_header_timeout": {
"description": "Time to receive headers in milliseconds",
"type": "integer"
},
"strip_prefix": {
"description": "If true, removes path_prefix from request before forwarding",
"type": "boolean"
Expand All @@ -8734,6 +8768,10 @@ const docTemplate = `{
"tenant_id": {
"type": "string"
},
"tls_skip_verify": {
"description": "Skip TLS verification for backend",
"type": "boolean"
},
"updated_at": {
"type": "string"
},
Expand Down Expand Up @@ -11036,6 +11074,27 @@ const docTemplate = `{
"target_url"
],
"properties": {
"allowed_cidrs": {
"type": "array",
"items": {
"type": "string"
}
},
"blocked_cidrs": {
"type": "array",
"items": {
"type": "string"
}
},
"dial_timeout": {
"type": "integer"
},
"idle_conn_timeout": {
"type": "integer"
},
"max_body_size": {
"type": "integer"
},
"methods": {
"type": "array",
"items": {
Expand All @@ -11054,11 +11113,20 @@ const docTemplate = `{
"rate_limit": {
"type": "integer"
},
"require_tls": {
"type": "boolean"
},
"response_header_timeout": {
"type": "integer"
},
"strip_prefix": {
"type": "boolean"
},
"target_url": {
"type": "string"
},
"tls_skip_verify": {
"type": "boolean"
}
}
},
Expand Down
68 changes: 68 additions & 0 deletions docs/swagger/swagger.json
Original file line number Diff line number Diff line change
Expand Up @@ -8672,12 +8672,38 @@
"domain.GatewayRoute": {
"type": "object",
"properties": {
"allowed_cidrs": {
"description": "IPs allowed to access (empty = all)",
"type": "array",
"items": {
"type": "string"
}
},
"blocked_cidrs": {
"description": "IPs blocked from access",
"type": "array",
"items": {
"type": "string"
}
},
"created_at": {
"type": "string"
},
"dial_timeout": {
"description": "TCP dial timeout in milliseconds",
"type": "integer"
},
"id": {
"type": "string"
},
"idle_conn_timeout": {
"description": "Idle connection timeout in milliseconds",
"type": "integer"
},
"max_body_size": {
"description": "Max request body size in bytes",
"type": "integer"
},
"methods": {
"description": "New: HTTP methods to match (empty = all)",
"type": "array",
Expand Down Expand Up @@ -8715,6 +8741,14 @@
"description": "Maximum allowed requests per second per IP",
"type": "integer"
},
"require_tls": {
"description": "Force HTTPS for backend",
"type": "boolean"
},
"response_header_timeout": {
"description": "Time to receive headers in milliseconds",
"type": "integer"
},
"strip_prefix": {
"description": "If true, removes path_prefix from request before forwarding",
"type": "boolean"
Expand All @@ -8726,6 +8760,10 @@
"tenant_id": {
"type": "string"
},
"tls_skip_verify": {
"description": "Skip TLS verification for backend",
"type": "boolean"
},
"updated_at": {
"type": "string"
},
Expand Down Expand Up @@ -11028,6 +11066,27 @@
"target_url"
],
"properties": {
"allowed_cidrs": {
"type": "array",
"items": {
"type": "string"
}
},
"blocked_cidrs": {
"type": "array",
"items": {
"type": "string"
}
},
"dial_timeout": {
"type": "integer"
},
"idle_conn_timeout": {
"type": "integer"
},
"max_body_size": {
"type": "integer"
},
"methods": {
"type": "array",
"items": {
Expand All @@ -11046,11 +11105,20 @@
"rate_limit": {
"type": "integer"
},
"require_tls": {
"type": "boolean"
},
"response_header_timeout": {
"type": "integer"
},
"strip_prefix": {
"type": "boolean"
},
"target_url": {
"type": "string"
},
"tls_skip_verify": {
"type": "boolean"
}
}
},
Expand Down
48 changes: 48 additions & 0 deletions docs/swagger/swagger.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,29 @@ definitions:
type: object
domain.GatewayRoute:
properties:
allowed_cidrs:
description: IPs allowed to access (empty = all)
items:
type: string
type: array
blocked_cidrs:
description: IPs blocked from access
items:
type: string
type: array
created_at:
type: string
dial_timeout:
description: TCP dial timeout in milliseconds
type: integer
id:
type: string
idle_conn_timeout:
description: Idle connection timeout in milliseconds
type: integer
max_body_size:
description: Max request body size in bytes
type: integer
methods:
description: 'New: HTTP methods to match (empty = all)'
items:
Expand Down Expand Up @@ -432,6 +451,12 @@ definitions:
rate_limit:
description: Maximum allowed requests per second per IP
type: integer
require_tls:
description: Force HTTPS for backend
type: boolean
response_header_timeout:
description: Time to receive headers in milliseconds
type: integer
strip_prefix:
description: If true, removes path_prefix from request before forwarding
type: boolean
Expand All @@ -440,6 +465,9 @@ definitions:
type: string
tenant_id:
type: string
tls_skip_verify:
description: Skip TLS verification for backend
type: boolean
updated_at:
type: string
user_id:
Expand Down Expand Up @@ -2099,6 +2127,20 @@ definitions:
type: object
httphandlers.CreateRouteRequest:
properties:
allowed_cidrs:
items:
type: string
type: array
blocked_cidrs:
items:
type: string
type: array
dial_timeout:
type: integer
idle_conn_timeout:
type: integer
max_body_size:
type: integer
methods:
items:
type: string
Expand All @@ -2111,10 +2153,16 @@ definitions:
type: integer
rate_limit:
type: integer
require_tls:
type: boolean
response_header_timeout:
type: integer
strip_prefix:
type: boolean
target_url:
type: string
tls_skip_verify:
type: boolean
required:
- name
- path_prefix
Expand Down
2 changes: 1 addition & 1 deletion internal/api/setup/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func InitHandlers(svcs *Services, cfg *platform.Config, logger *slog.Logger) *Ha
Queue: httphandlers.NewQueueHandler(svcs.Queue),
Notify: httphandlers.NewNotifyHandler(svcs.Notify),
Cron: httphandlers.NewCronHandler(svcs.Cron),
Gateway: httphandlers.NewGatewayHandler(svcs.Gateway),
Gateway: httphandlers.NewGatewayHandler(svcs.Gateway, logger),
Container: httphandlers.NewContainerHandler(svcs.Container),
Pipeline: httphandlers.NewPipelineHandler(svcs.Pipeline),
Health: httphandlers.NewHealthHandler(svcs.Health),
Expand Down
38 changes: 23 additions & 15 deletions internal/core/domain/gateway.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,29 @@ import (

// GatewayRoute defines an ingress rule for mapping external HTTP traffic to internal resources.
type GatewayRoute struct {
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
TenantID uuid.UUID `json:"tenant_id"`
Name string `json:"name"`
PathPrefix string `json:"path_prefix"` // Legacy: Request path to match (e.g., "/api/v1")
PathPattern string `json:"path_pattern"` // New: Pattern with {params}
PatternType string `json:"pattern_type"` // "prefix" or "pattern"
ParamNames []string `json:"param_names"` // Extracted parameter names
TargetURL string `json:"target_url"` // Internal destination (e.g., "http://service-a:8080")
Methods []string `json:"methods"` // New: HTTP methods to match (empty = all)
StripPrefix bool `json:"strip_prefix"` // If true, removes path_prefix from request before forwarding
RateLimit int `json:"rate_limit"` // Maximum allowed requests per second per IP
Priority int `json:"priority"` // Manual priority for tie-breaking
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
ID uuid.UUID `json:"id"`
UserID uuid.UUID `json:"user_id"`
TenantID uuid.UUID `json:"tenant_id"`
Name string `json:"name"`
PathPrefix string `json:"path_prefix"` // Legacy: Request path to match (e.g., "/api/v1")
PathPattern string `json:"path_pattern"` // New: Pattern with {params}
PatternType string `json:"pattern_type"` // "prefix" or "pattern"
ParamNames []string `json:"param_names"` // Extracted parameter names
TargetURL string `json:"target_url"` // Internal destination (e.g., "http://service-a:8080")
Methods []string `json:"methods"` // New: HTTP methods to match (empty = all)
StripPrefix bool `json:"strip_prefix"` // If true, removes path_prefix from request before forwarding
RateLimit int `json:"rate_limit"` // Maximum allowed requests per second per IP
DialTimeout int64 `json:"dial_timeout"` // TCP dial timeout in milliseconds
ResponseHeaderTimeout int64 `json:"response_header_timeout"` // Time to receive headers in milliseconds
IdleConnTimeout int64 `json:"idle_conn_timeout"` // Idle connection timeout in milliseconds
TLSSkipVerify bool `json:"tls_skip_verify"` // Skip TLS verification for backend
RequireTLS bool `json:"require_tls"` // Force HTTPS for backend
AllowedCIDRs []string `json:"allowed_cidrs"` // IPs allowed to access (empty = all)
BlockedCIDRs []string `json:"blocked_cidrs"` // IPs blocked from access
MaxBodySize int64 `json:"max_body_size"` // Max request body size in bytes
Comment on lines +24 to +31
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

New optional fields are missing omitempty in their JSON tags — coding guidelines violation.

All eight new fields are optional (zero/nil means "disabled" or "no restriction") but none carry omitempty:

Field Zero-value meaning
DialTimeout / ResponseHeaderTimeout / IdleConnTimeout use transport default
MaxBodySize no limit
AllowedCIDRs / BlockedCIDRs no CIDR restriction
TLSSkipVerify / RequireTLS safe defaults (false)

For the bool fields, note that omitempty on a plain bool will omit false, which is fine for GET/serialization semantics here since false is the safe default. If a future update path (e.g. PATCH) needs to explicitly reset a flag to false and detect that in a JSON body, the fields would need to be *bool instead.

🔧 Proposed fix
-	DialTimeout              int64     `json:"dial_timeout"`    // TCP dial timeout in milliseconds
-	ResponseHeaderTimeout     int64     `json:"response_header_timeout"` // Time to receive headers in milliseconds
-	IdleConnTimeout          int64     `json:"idle_conn_timeout"`       // Idle connection timeout in milliseconds
-	TLSSkipVerify            bool      `json:"tls_skip_verify"`  // Skip TLS verification for backend
-	RequireTLS              bool      `json:"require_tls"`      // Force HTTPS for backend
-	AllowedCIDRs             []string  `json:"allowed_cidrs"`   // IPs allowed to access (empty = all)
-	BlockedCIDRs             []string  `json:"blocked_cidrs"`   // IPs blocked from access
-	MaxBodySize              int64     `json:"max_body_size"`   // Max request body size in bytes
+	DialTimeout              int64     `json:"dial_timeout,omitempty"`             // TCP dial timeout in milliseconds
+	ResponseHeaderTimeout    int64     `json:"response_header_timeout,omitempty"`  // Time to receive headers in milliseconds
+	IdleConnTimeout          int64     `json:"idle_conn_timeout,omitempty"`        // Idle connection timeout in milliseconds
+	TLSSkipVerify            bool      `json:"tls_skip_verify,omitempty"`          // Skip TLS verification for backend
+	RequireTLS               bool      `json:"require_tls,omitempty"`              // Force HTTPS for backend
+	AllowedCIDRs             []string  `json:"allowed_cidrs,omitempty"`            // IPs allowed to access (empty = all)
+	BlockedCIDRs             []string  `json:"blocked_cidrs,omitempty"`            // IPs blocked from access
+	MaxBodySize              int64     `json:"max_body_size,omitempty"`            // Max request body size in bytes

As per coding guidelines: "Include json tags on struct fields with omitempty for optional fields."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
DialTimeout int64 `json:"dial_timeout"` // TCP dial timeout in milliseconds
ResponseHeaderTimeout int64 `json:"response_header_timeout"` // Time to receive headers in milliseconds
IdleConnTimeout int64 `json:"idle_conn_timeout"` // Idle connection timeout in milliseconds
TLSSkipVerify bool `json:"tls_skip_verify"` // Skip TLS verification for backend
RequireTLS bool `json:"require_tls"` // Force HTTPS for backend
AllowedCIDRs []string `json:"allowed_cidrs"` // IPs allowed to access (empty = all)
BlockedCIDRs []string `json:"blocked_cidrs"` // IPs blocked from access
MaxBodySize int64 `json:"max_body_size"` // Max request body size in bytes
DialTimeout int64 `json:"dial_timeout,omitempty"` // TCP dial timeout in milliseconds
ResponseHeaderTimeout int64 `json:"response_header_timeout,omitempty"` // Time to receive headers in milliseconds
IdleConnTimeout int64 `json:"idle_conn_timeout,omitempty"` // Idle connection timeout in milliseconds
TLSSkipVerify bool `json:"tls_skip_verify,omitempty"` // Skip TLS verification for backend
RequireTLS bool `json:"require_tls,omitempty"` // Force HTTPS for backend
AllowedCIDRs []string `json:"allowed_cidrs,omitempty"` // IPs allowed to access (empty = all)
BlockedCIDRs []string `json:"blocked_cidrs,omitempty"` // IPs blocked from access
MaxBodySize int64 `json:"max_body_size,omitempty"` // Max request body size in bytes
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/core/domain/gateway.go` around lines 24 - 31, The JSON tags for the
optional Gateway config fields must include omitempty; update the struct tags
for DialTimeout, ResponseHeaderTimeout, IdleConnTimeout, TLSSkipVerify,
RequireTLS, AllowedCIDRs, BlockedCIDRs, and MaxBodySize to add `omitempty` so
zero/nil values are omitted during serialization (e.g., change
`json:"dial_timeout"` to `json:"dial_timeout,omitempty"` etc.); if you
anticipate needing to distinguish an explicit false from omitted in future PATCH
semantics, consider changing TLSSkipVerify/RequireTLS to `*bool` before adding
omitempty, otherwise keep them as plain bools with omitempty.

Priority int `json:"priority"` // Manual priority for tie-breaking
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}

// RouteMatch represents a successful route pattern match.
Expand Down
Loading
Loading