mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-25 16:07:24 +00:00
feat: add metadata enforcement (#1990)
* 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>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
parent
6fbd472f27
commit
77d1810bb9
@@ -0,0 +1,141 @@
|
||||
// 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, "; ")
|
||||
}
|
||||
Reference in New Issue
Block a user