mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-19 04:26:45 +00:00
* fix(controller): decode old object for delete requests Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: modernize golang Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: modernize golang Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * chore: modernize golang Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> * fix: preserve ca-bundles injected from external providers Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat: add metadata enforcement Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * feat: add metadata enforcement Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * fix: add resourcepoolclaim validation Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * fix: add resourcepoolclaim validation Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * fix: add resourcepoolclaim validation Signed-off-by: Oliver Baehler <oliver@sudo-i.net> * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * fix: add resourcepoolclaim validation Signed-off-by: Oliver Baehler <oliver@sudo-i.net> --------- Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com> Signed-off-by: Oliver Baehler <oliver@sudo-i.net> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
142 lines
3.1 KiB
Go
142 lines
3.1 KiB
Go
// Copyright 2020-2026 Project Capsule Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package runtime
|
|
|
|
import (
|
|
"fmt"
|
|
"regexp"
|
|
"slices"
|
|
"strings"
|
|
)
|
|
|
|
// At least one of Exact or Exp must be set.
|
|
// Both may be set together.
|
|
// +kubebuilder:object:generate=true
|
|
// +kubebuilder:validation:XValidation:rule="has(self.exact) || has(self.exp)",message="at least one of exact or exp must be set"
|
|
type ExpressionMatch struct {
|
|
ExpressionRegex `json:",inline"`
|
|
|
|
// Exact matches one of the provided values exactly.
|
|
//
|
|
// +kubebuilder:validation:MinItems=1
|
|
// +kubebuilder:validation:Items:MinLength=1
|
|
// +optional
|
|
Exact []string `json:"exact,omitempty"`
|
|
}
|
|
|
|
type ExpressionRegex struct {
|
|
// Exp matches regular expression.
|
|
//
|
|
// +kubebuilder:validation:MinLength=1
|
|
// +optional
|
|
Expression string `json:"exp,omitempty"`
|
|
// Negate regular Expression
|
|
//+kubebuilder:default:=false
|
|
Negate bool `json:"negate,omitempty"`
|
|
}
|
|
|
|
type ExpressionRegexMatcher interface {
|
|
MatchRegex(expression ExpressionRegex, value string) (bool, error)
|
|
}
|
|
|
|
func (m ExpressionMatch) Matches(value string) (bool, error) {
|
|
matched, err := m.matches(value)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
return m.applyNegate(matched), nil
|
|
}
|
|
|
|
func (m ExpressionMatch) MatchesWithExpressionMatcher(
|
|
matcher ExpressionRegexMatcher,
|
|
value string,
|
|
) (bool, error) {
|
|
if len(m.Exact) == 0 && m.Expression == "" {
|
|
return false, fmt.Errorf("expression match must define at least one of exact or exp")
|
|
}
|
|
|
|
matched := containsExact(m.Exact, value)
|
|
if matched {
|
|
return m.applyNegate(true), nil
|
|
}
|
|
|
|
if m.Expression == "" {
|
|
return m.applyNegate(false), nil
|
|
}
|
|
|
|
if matcher == nil {
|
|
return m.Matches(value)
|
|
}
|
|
|
|
matched, err := matcher.MatchRegex(m.ExpressionRegex, value)
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
|
|
// Important: assume MatchRegex already applies ExpressionRegex.Negate.
|
|
// If your RegexCache.MatchRegex already handles Negate, return directly.
|
|
return matched, nil
|
|
}
|
|
|
|
func (m ExpressionMatch) Describe() string {
|
|
return DescribeExpressionMatch(m)
|
|
}
|
|
|
|
func (m ExpressionMatch) matches(value string) (bool, error) {
|
|
if len(m.Exact) == 0 && m.Expression == "" {
|
|
return false, fmt.Errorf("expression match must define at least one of exact or exp")
|
|
}
|
|
|
|
if containsExact(m.Exact, value) {
|
|
return true, nil
|
|
}
|
|
|
|
if m.Expression == "" {
|
|
return false, nil
|
|
}
|
|
|
|
re, err := regexp.Compile(m.Expression)
|
|
if err != nil {
|
|
return false, fmt.Errorf("compile regexp %q: %w", m.Expression, err)
|
|
}
|
|
|
|
return re.MatchString(value), nil
|
|
}
|
|
|
|
func containsExact(values []string, value string) bool {
|
|
return slices.Contains(values, value)
|
|
}
|
|
|
|
func (m ExpressionMatch) applyNegate(matched bool) bool {
|
|
if m.Negate {
|
|
return !matched
|
|
}
|
|
|
|
return matched
|
|
}
|
|
|
|
func DescribeExpressionMatch(match ExpressionMatch) string {
|
|
parts := make([]string, 0, 3)
|
|
|
|
prefix := ""
|
|
if match.Negate {
|
|
prefix = "not "
|
|
}
|
|
|
|
if len(match.Exact) > 0 {
|
|
parts = append(parts, fmt.Sprintf("%sexact: %s", prefix, strings.Join(match.Exact, ", ")))
|
|
}
|
|
|
|
if match.Expression != "" {
|
|
parts = append(parts, fmt.Sprintf("%sexp: %s", prefix, match.Expression))
|
|
}
|
|
|
|
if len(parts) == 0 && match.Negate {
|
|
return "not <empty>"
|
|
}
|
|
|
|
return strings.Join(parts, "; ")
|
|
}
|