platform: modularize api/gui, add docs-tests-web foundation, and refresh root config
This commit is contained in:
126
selective-vpn-api/app/transport_policy_validate.go
Normal file
126
selective-vpn-api/app/transport_policy_validate.go
Normal file
@@ -0,0 +1,126 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
)
|
||||
|
||||
func validateTransportPolicy(next []TransportPolicyIntent, current []TransportPolicyIntent, clients []TransportClient) transportValidationResult {
|
||||
clientByID := map[string]TransportClient{}
|
||||
for _, c := range clients {
|
||||
clientByID[c.ID] = c
|
||||
}
|
||||
|
||||
type ownerSet map[string]struct{}
|
||||
ownership := map[string]ownerSet{}
|
||||
seenSameOwner := map[string]int{}
|
||||
cidrs := make([]cidrIntent, 0)
|
||||
conflicts := make([]TransportConflictRecord, 0)
|
||||
block := 0
|
||||
warn := 0
|
||||
|
||||
normalized := make([]TransportPolicyIntent, 0, len(next))
|
||||
for i, raw := range next {
|
||||
norm, key, pfx, err := normalizeTransportIntent(raw)
|
||||
if err != nil {
|
||||
conflicts = append(conflicts, TransportConflictRecord{
|
||||
Key: fmt.Sprintf("intent:%d", i),
|
||||
Type: "invalid_intent",
|
||||
Severity: "block",
|
||||
Reason: err.Error(),
|
||||
SuggestedResolution: "fix selector/client fields",
|
||||
})
|
||||
block++
|
||||
continue
|
||||
}
|
||||
if _, ok := clientByID[norm.ClientID]; !ok {
|
||||
conflicts = append(conflicts, TransportConflictRecord{
|
||||
Key: key,
|
||||
Type: "unknown_client",
|
||||
Severity: "block",
|
||||
Owners: []string{norm.ClientID},
|
||||
Reason: "client not found",
|
||||
SuggestedResolution: "create client or fix client_id",
|
||||
})
|
||||
block++
|
||||
continue
|
||||
}
|
||||
|
||||
if ownership[key] == nil {
|
||||
ownership[key] = ownerSet{}
|
||||
}
|
||||
ownership[key][norm.ClientID] = struct{}{}
|
||||
seenSameOwner[key+"|"+norm.ClientID]++
|
||||
if seenSameOwner[key+"|"+norm.ClientID] > 1 {
|
||||
conflicts = append(conflicts, TransportConflictRecord{
|
||||
Key: key,
|
||||
Type: "duplicate_intent",
|
||||
Severity: "warn",
|
||||
Owners: []string{norm.ClientID},
|
||||
Reason: "duplicate selector for same client",
|
||||
SuggestedResolution: "deduplicate identical intents",
|
||||
})
|
||||
warn++
|
||||
}
|
||||
if pfx.IsValid() {
|
||||
cidrs = append(cidrs, cidrIntent{ClientID: norm.ClientID, Prefix: pfx, Key: key})
|
||||
}
|
||||
normalized = append(normalized, norm)
|
||||
}
|
||||
|
||||
for key, owners := range ownership {
|
||||
if len(owners) <= 1 {
|
||||
continue
|
||||
}
|
||||
own := make([]string, 0, len(owners))
|
||||
for id := range owners {
|
||||
own = append(own, id)
|
||||
}
|
||||
sort.Strings(own)
|
||||
conflicts = append(conflicts, TransportConflictRecord{
|
||||
Key: key,
|
||||
Type: "ownership",
|
||||
Severity: "block",
|
||||
Owners: own,
|
||||
Reason: "selector is assigned to multiple clients",
|
||||
SuggestedResolution: "keep exactly one owner for selector",
|
||||
})
|
||||
block++
|
||||
}
|
||||
|
||||
for i := 0; i < len(cidrs); i++ {
|
||||
for j := i + 1; j < len(cidrs); j++ {
|
||||
a, b := cidrs[i], cidrs[j]
|
||||
if a.ClientID == b.ClientID {
|
||||
continue
|
||||
}
|
||||
if !prefixOverlap(a.Prefix, b.Prefix) {
|
||||
continue
|
||||
}
|
||||
key := "cidr_overlap:" + a.Prefix.String() + "|" + b.Prefix.String()
|
||||
conflicts = append(conflicts, TransportConflictRecord{
|
||||
Key: key,
|
||||
Type: "cidr_overlap",
|
||||
Severity: "block",
|
||||
Owners: []string{a.ClientID, b.ClientID},
|
||||
Reason: "CIDR selectors overlap across different clients",
|
||||
SuggestedResolution: "split CIDR ranges or keep one owner",
|
||||
})
|
||||
block++
|
||||
}
|
||||
}
|
||||
|
||||
conflicts = dedupeTransportConflicts(conflicts)
|
||||
diff := computeTransportPolicyDiff(current, normalized)
|
||||
|
||||
return transportValidationResult{
|
||||
Normalized: normalized,
|
||||
Conflicts: conflicts,
|
||||
Summary: TransportPolicyValidateSummary{
|
||||
BlockCount: block,
|
||||
WarnCount: warn,
|
||||
},
|
||||
Diff: diff,
|
||||
Valid: block == 0,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user