Skip to content

Commit 6420089

Browse files
authored
Merge pull request #208 from githubnext/copilot/remove-duplicate-code-validation
2 parents a88eb7e + 1f92357 commit 6420089

5 files changed

Lines changed: 450 additions & 106 deletions

File tree

internal/config/env_validation.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ import (
88
"regexp"
99
"strconv"
1010
"strings"
11+
12+
"github.com/githubnext/gh-aw-mcpg/internal/config/rules"
1113
)
1214

1315
// RequiredEnvVars lists the environment variables that must be set for the gateway to operate
@@ -272,8 +274,8 @@ func GetGatewayPortFromEnv() (int, error) {
272274
return 0, fmt.Errorf("invalid MCP_GATEWAY_PORT value: %s", portStr)
273275
}
274276

275-
if port < 1 || port > 65535 {
276-
return 0, fmt.Errorf("MCP_GATEWAY_PORT must be between 1 and 65535, got %d", port)
277+
if validationErr := rules.PortRange(port, "MCP_GATEWAY_PORT"); validationErr != nil {
278+
return 0, fmt.Errorf("%s", validationErr.Message)
277279
}
278280

279281
return port, nil

internal/config/rules/rules.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package rules
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
)
7+
8+
// ValidationError represents a configuration validation error with context
9+
type ValidationError struct {
10+
Field string
11+
Message string
12+
JSONPath string
13+
Suggestion string
14+
}
15+
16+
func (e *ValidationError) Error() string {
17+
var sb strings.Builder
18+
sb.WriteString(fmt.Sprintf("Configuration error at %s: %s", e.JSONPath, e.Message))
19+
if e.Suggestion != "" {
20+
sb.WriteString(fmt.Sprintf("\nSuggestion: %s", e.Suggestion))
21+
}
22+
return sb.String()
23+
}
24+
25+
// PortRange validates that a port is in the valid range (1-65535)
26+
// Returns nil if valid, *ValidationError if invalid
27+
func PortRange(port int, jsonPath string) *ValidationError {
28+
if port < 1 || port > 65535 {
29+
return &ValidationError{
30+
Field: "port",
31+
Message: fmt.Sprintf("port must be between 1 and 65535, got %d", port),
32+
JSONPath: jsonPath,
33+
Suggestion: "Use a valid port number (e.g., 8080)",
34+
}
35+
}
36+
return nil
37+
}
38+
39+
// TimeoutPositive validates that a timeout value is at least 1
40+
// Returns nil if valid, *ValidationError if invalid
41+
func TimeoutPositive(timeout int, fieldName, jsonPath string) *ValidationError {
42+
if timeout < 1 {
43+
return &ValidationError{
44+
Field: fieldName,
45+
Message: fmt.Sprintf("%s must be at least 1, got %d", fieldName, timeout),
46+
JSONPath: jsonPath,
47+
Suggestion: "Use a positive number of seconds (e.g., 30)",
48+
}
49+
}
50+
return nil
51+
}
52+
53+
// MountFormat validates a mount specification in the format "source:dest:mode"
54+
// Returns nil if valid, *ValidationError if invalid
55+
func MountFormat(mount, jsonPath string, index int) *ValidationError {
56+
parts := strings.Split(mount, ":")
57+
if len(parts) != 3 {
58+
return &ValidationError{
59+
Field: "mounts",
60+
Message: fmt.Sprintf("invalid mount format '%s' (expected 'source:dest:mode')", mount),
61+
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
62+
Suggestion: "Use format 'source:dest:mode' where mode is 'ro' (read-only) or 'rw' (read-write)",
63+
}
64+
}
65+
66+
source, dest, mode := parts[0], parts[1], parts[2]
67+
68+
// Validate source is not empty
69+
if source == "" {
70+
return &ValidationError{
71+
Field: "mounts",
72+
Message: fmt.Sprintf("mount source cannot be empty in '%s'", mount),
73+
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
74+
Suggestion: "Provide a valid source path",
75+
}
76+
}
77+
78+
// Validate dest is not empty
79+
if dest == "" {
80+
return &ValidationError{
81+
Field: "mounts",
82+
Message: fmt.Sprintf("mount destination cannot be empty in '%s'", mount),
83+
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
84+
Suggestion: "Provide a valid destination path",
85+
}
86+
}
87+
88+
// Validate mode
89+
if mode != "ro" && mode != "rw" {
90+
return &ValidationError{
91+
Field: "mounts",
92+
Message: fmt.Sprintf("invalid mount mode '%s' (must be 'ro' or 'rw')", mode),
93+
JSONPath: fmt.Sprintf("%s.mounts[%d]", jsonPath, index),
94+
Suggestion: "Use 'ro' for read-only or 'rw' for read-write",
95+
}
96+
}
97+
98+
return nil
99+
}

0 commit comments

Comments
 (0)