package adminstate import ( "context" "encoding/hex" "encoding/json" "errors" "net/netip" "regexp" "strings" "time" "unicode" "unicode/utf8" ) const ( MaxIdentifierBytes = 128 MaxActorIDBytes = 256 MaxReasonBytes = 512 MaxSourceBytes = 512 MaxDefinitions = 10_000 MaxPageSize = 1_000 SHA256HexBytes = 64 ) var ( ErrInvalidCommand = errors.New("invalid admin state command") ErrNotFound = errors.New("admin state resource not found") ErrConflict = errors.New("admin state conflict") ErrUnavailable = errors.New("admin state unavailable") ) var identifierPattern = regexp.MustCompile(`^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$`) type Mutator interface { SetUpstreamEnabled(context.Context, SetUpstreamCommand) (MutationResult, error) SwitchRouting(context.Context, SwitchRoutingCommand) (MutationResult, error) CommitConfig(context.Context, CommitConfigCommand) (MutationResult, error) } type SnapshotReader interface { Snapshot(context.Context) (Snapshot, error) } type AuditReader interface { ReadAudit(context.Context, AuditQuery) ([]AuditRecord, error) } type Outbox interface { Claim(context.Context, ClaimCommand) ([]Event, error) Acknowledge(context.Context, AcknowledgeCommand) error } type Store interface { Mutator SnapshotReader AuditReader Outbox } type Actor struct { ID string SourceIP string } type SetUpstreamCommand struct { RequestID string Actor Actor OccurredAt time.Time Name string Enabled bool } type SwitchRoutingCommand struct { RequestID string Actor Actor OccurredAt time.Time Name string ExpectedCurrent string Target string Reason string } type CommitConfigCommand struct { RequestID string Actor Actor OccurredAt time.Time ConfigVersion string Checksum string Source string Upstreams []UpstreamDefinition Routings []RoutingDefinition } type UpstreamDefinition struct { Name string Enabled bool } type RoutingDefinition struct { Name string Enabled bool Upstreams []string CurrentUpstream string } type MutationResult struct { RequestID string Changed bool Revision uint64 Message string } type ConfigRevision struct { Revision uint64 ConfigVersion string Checksum string Source string CreatedAt time.Time } type UpstreamState struct { Name string Enabled bool Revision uint64 UpdatedAt time.Time } type RoutingState struct { Name string Enabled bool Upstreams []string CurrentUpstream string Revision uint64 UpdatedAt time.Time } type Snapshot struct { Revision uint64 Config *ConfigRevision Upstreams []UpstreamState Routings []RoutingState } type Action string const ( ActionSetUpstream Action = "set_upstream_enabled" ActionSwitchRoute Action = "switch_routing" ActionCommitConfig Action = "commit_config" ) type AuditRecord struct { ID uint64 RequestID string Actor Actor Action Action ResourceType string ResourceName string Changed bool Revision uint64 Reason string OccurredAt time.Time } type AuditQuery struct { AfterID uint64 Limit int } type Event struct { ID uint64 Revision uint64 Type string AggregateType string AggregateID string Payload json.RawMessage OccurredAt time.Time ClaimedBy string ClaimUntil *time.Time PublishedAt *time.Time } type ClaimCommand struct { ConsumerID string Now time.Time Limit int Lease time.Duration } type AcknowledgeCommand struct { ConsumerID string Now time.Time EventIDs []uint64 } func validateSetUpstreamCommand(command SetUpstreamCommand) error { if err := validateMutationBase(command.RequestID, command.Actor, command.OccurredAt); err != nil || !validIdentifier(command.Name) { return ErrInvalidCommand } return nil } func validateSwitchRoutingCommand(command SwitchRoutingCommand) error { if err := validateMutationBase(command.RequestID, command.Actor, command.OccurredAt); err != nil || !validIdentifier(command.Name) || !validIdentifier(command.ExpectedCurrent) || !validIdentifier(command.Target) || !validOptionalText(command.Reason, MaxReasonBytes) { return ErrInvalidCommand } return nil } func validateCommitConfigCommand(command CommitConfigCommand) error { if err := validateMutationBase(command.RequestID, command.Actor, command.OccurredAt); err != nil || !validRequiredText(command.ConfigVersion, MaxIdentifierBytes) || !validSHA256(command.Checksum) || !validRequiredText(command.Source, MaxSourceBytes) || len(command.Upstreams) > MaxDefinitions || len(command.Routings) > MaxDefinitions { return ErrInvalidCommand } upstreamNames := make(map[string]struct{}, len(command.Upstreams)) for _, upstream := range command.Upstreams { if !validIdentifier(upstream.Name) { return ErrInvalidCommand } if _, duplicate := upstreamNames[upstream.Name]; duplicate { return ErrInvalidCommand } upstreamNames[upstream.Name] = struct{}{} } routingNames := make(map[string]struct{}, len(command.Routings)) for _, routing := range command.Routings { if !validIdentifier(routing.Name) || len(routing.Upstreams) == 0 || len(routing.Upstreams) > MaxDefinitions || !validIdentifier(routing.CurrentUpstream) { return ErrInvalidCommand } if _, duplicate := routingNames[routing.Name]; duplicate { return ErrInvalidCommand } routingNames[routing.Name] = struct{}{} candidates := make(map[string]struct{}, len(routing.Upstreams)) for _, upstream := range routing.Upstreams { if !validIdentifier(upstream) { return ErrInvalidCommand } if _, exists := upstreamNames[upstream]; !exists { return ErrInvalidCommand } if _, duplicate := candidates[upstream]; duplicate { return ErrInvalidCommand } candidates[upstream] = struct{}{} } if _, exists := candidates[routing.CurrentUpstream]; !exists { return ErrInvalidCommand } } return nil } func validateClaimCommand(command ClaimCommand) error { if !validIdentifier(command.ConsumerID) || command.Now.IsZero() || command.Limit <= 0 || command.Limit > MaxPageSize || command.Lease <= 0 { return ErrInvalidCommand } return nil } func validateAcknowledgeCommand(command AcknowledgeCommand) error { if !validIdentifier(command.ConsumerID) || command.Now.IsZero() || len(command.EventIDs) == 0 || len(command.EventIDs) > MaxPageSize { return ErrInvalidCommand } seen := make(map[uint64]struct{}, len(command.EventIDs)) for _, eventID := range command.EventIDs { if eventID == 0 { return ErrInvalidCommand } if _, duplicate := seen[eventID]; duplicate { return ErrInvalidCommand } seen[eventID] = struct{}{} } return nil } func validateAuditQuery(query AuditQuery) error { if query.Limit <= 0 || query.Limit > MaxPageSize { return ErrInvalidCommand } return nil } func validateMutationBase(requestID string, actor Actor, occurredAt time.Time) error { if !validRequiredText(requestID, MaxIdentifierBytes) || !validRequiredText(actor.ID, MaxActorIDBytes) || occurredAt.IsZero() { return ErrInvalidCommand } if actor.SourceIP != "" { address, err := netip.ParseAddr(actor.SourceIP) if err != nil || !address.IsValid() { return ErrInvalidCommand } } return nil } func validIdentifier(value string) bool { return len(value) <= MaxIdentifierBytes && identifierPattern.MatchString(value) } func validSHA256(value string) bool { if len(value) != SHA256HexBytes { return false } decoded, err := hex.DecodeString(value) return err == nil && len(decoded) == SHA256HexBytes/2 } func validRequiredText(value string, maximum int) bool { return value != "" && validOptionalText(value, maximum) } func validOptionalText(value string, maximum int) bool { if len(value) > maximum || !utf8.ValidString(value) || strings.TrimSpace(value) != value { return false } for _, character := range value { if unicode.IsControl(character) { return false } } return true } func cloneCommitConfigCommand(command CommitConfigCommand) CommitConfigCommand { cloned := command cloned.Upstreams = append([]UpstreamDefinition(nil), command.Upstreams...) cloned.Routings = make([]RoutingDefinition, len(command.Routings)) for index, routing := range command.Routings { cloned.Routings[index] = routing cloned.Routings[index].Upstreams = append([]string(nil), routing.Upstreams...) } return cloned } func cloneSnapshot(snapshot Snapshot) Snapshot { cloned := snapshot if snapshot.Config != nil { config := *snapshot.Config cloned.Config = &config } cloned.Upstreams = append([]UpstreamState(nil), snapshot.Upstreams...) cloned.Routings = make([]RoutingState, len(snapshot.Routings)) for index, routing := range snapshot.Routings { cloned.Routings[index] = routing cloned.Routings[index].Upstreams = append([]string(nil), routing.Upstreams...) } return cloned } func cloneEvent(event Event) Event { cloned := event cloned.Payload = append(json.RawMessage(nil), event.Payload...) if event.ClaimUntil != nil { value := *event.ClaimUntil cloned.ClaimUntil = &value } if event.PublishedAt != nil { value := *event.PublishedAt cloned.PublishedAt = &value } return cloned } func cloneEvents(events []Event) []Event { cloned := make([]Event, len(events)) for index, event := range events { cloned[index] = cloneEvent(event) } return cloned } func cloneAuditRecords(records []AuditRecord) []AuditRecord { return append([]AuditRecord(nil), records...) }