feat: Extract Wild Central as standalone Go service
Extract the Central networking functionality from wild-cloud/api into a standalone service. Wild Central manages DNS (dnsmasq), gateway (HAProxy), firewall (nftables), VPN (WireGuard), TLS (certbot), security (CrowdSec), and DDNS — all the network appliance concerns. All Cloud-specific code (instances, clusters, nodes, apps, backups, operations, kubectl/talosctl tooling) has been removed. The API struct and route registration contain only Central endpoints. Tests updated to match the new API signature. Builds and all tests pass. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
80
internal/api/v1/validation.go
Normal file
80
internal/api/v1/validation.go
Normal file
@@ -0,0 +1,80 @@
|
||||
package v1
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
maxInstanceNameLength = 63 // Kubernetes DNS label limit (RFC 1123)
|
||||
maxNodeIdentifierLength = 253 // RFC 1035 hostname limit
|
||||
)
|
||||
|
||||
// validNamePattern matches valid resource names.
|
||||
// Names must:
|
||||
// - Start and end with a lowercase letter or number
|
||||
// - Contain only lowercase letters, numbers, and hyphens
|
||||
// - Be between 1 and 63 characters
|
||||
// This follows Kubernetes naming conventions for consistency.
|
||||
var validNamePattern = regexp.MustCompile(`^[a-z0-9]([a-z0-9-]*[a-z0-9])?$`)
|
||||
|
||||
// ValidateName validates a resource name (instance, app, node, etc.).
|
||||
// Returns an error if the name is invalid.
|
||||
func ValidateName(name string) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("name is required")
|
||||
}
|
||||
if len(name) > maxInstanceNameLength {
|
||||
return fmt.Errorf("name must be %d characters or less", maxInstanceNameLength)
|
||||
}
|
||||
if !validNamePattern.MatchString(name) {
|
||||
return fmt.Errorf("name must contain only lowercase letters, numbers, and hyphens, and must start and end with a letter or number")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateInstanceName validates an instance name with a user-friendly error message.
|
||||
func ValidateInstanceName(name string) error {
|
||||
if err := ValidateName(name); err != nil {
|
||||
return fmt.Errorf("invalid instance name: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateAppName validates an app name with a user-friendly error message.
|
||||
func ValidateAppName(name string) error {
|
||||
if err := ValidateName(name); err != nil {
|
||||
return fmt.Errorf("invalid app name: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateServiceName validates a service name with a user-friendly error message.
|
||||
func ValidateServiceName(name string) error {
|
||||
if err := ValidateName(name); err != nil {
|
||||
return fmt.Errorf("invalid service name: %w", err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidateNodeIdentifier validates a node identifier (hostname or IP).
|
||||
// Node identifiers have slightly relaxed rules since they can be IPs.
|
||||
func ValidateNodeIdentifier(identifier string) error {
|
||||
if identifier == "" {
|
||||
return fmt.Errorf("node identifier is required")
|
||||
}
|
||||
if len(identifier) > maxNodeIdentifierLength {
|
||||
return fmt.Errorf("node identifier must be %d characters or less", maxNodeIdentifierLength)
|
||||
}
|
||||
// Basic check for path traversal
|
||||
if containsPathTraversal(identifier) {
|
||||
return fmt.Errorf("invalid node identifier: contains invalid characters")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// containsPathTraversal checks if a string contains path traversal patterns.
|
||||
func containsPathTraversal(s string) bool {
|
||||
return strings.ContainsAny(s, "/\\") || strings.Contains(s, "..") || strings.ContainsRune(s, '\x00')
|
||||
}
|
||||
Reference in New Issue
Block a user