mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-03-31 15:59:58 +00:00
- Add GatewayNamespacedName, AllowedGatewaySpec, GatewayRuleSpec types to pkg/api/ - Add Gateways field to NamespaceRuleEnforceBody for per-namespace gateway rules - Add HTTPRoute validation webhook to enforce allowed gateways - Add HTTPRoute default mutation webhook to inject default Gateway parentRef - Update Helm chart with validating/mutating webhook configurations for httproutes - Update CRD schemas for tenants and rulestatuses - Add GatewayForbiddenError and ReasonForbiddenGateway event reason Co-authored-by: oliverbaehler <26610571+oliverbaehler@users.noreply.github.com>
118 lines
3.0 KiB
Go
118 lines
3.0 KiB
Go
// Copyright 2020-2026 Project Capsule Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package errors
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
|
|
gatewayv1 "sigs.k8s.io/gateway-api/apis/v1"
|
|
|
|
"github.com/projectcapsule/capsule/internal/webhook/utils"
|
|
"github.com/projectcapsule/capsule/pkg/api"
|
|
)
|
|
|
|
type GatewayClassError struct {
|
|
gatewayClass string
|
|
msg error
|
|
}
|
|
|
|
func NewGatewayClassError(class string, msg error) error {
|
|
return &GatewayClassError{
|
|
gatewayClass: class,
|
|
msg: msg,
|
|
}
|
|
}
|
|
|
|
func (e GatewayClassError) Error() string {
|
|
return fmt.Sprintf("Failed to resolve Gateway Class %s: %s", e.gatewayClass, e.msg)
|
|
}
|
|
|
|
type GatewayError struct {
|
|
gateway string
|
|
msg error
|
|
}
|
|
|
|
func NewGatewayError(gateway gatewayv1.ObjectName, msg error) error {
|
|
return &GatewayError{
|
|
gateway: reflect.ValueOf(gateway).String(),
|
|
msg: msg,
|
|
}
|
|
}
|
|
|
|
func (e GatewayError) Error() string {
|
|
return fmt.Sprintf("Failed to resolve Gateway %s: %s", e.gateway, e.msg)
|
|
}
|
|
|
|
type GatewayClassForbiddenError struct {
|
|
gatewayClassName string
|
|
spec api.DefaultAllowedListSpec
|
|
}
|
|
|
|
func NewGatewayClassForbidden(class string, spec api.DefaultAllowedListSpec) error {
|
|
return &GatewayClassForbiddenError{
|
|
gatewayClassName: class,
|
|
spec: spec,
|
|
}
|
|
}
|
|
|
|
func (i GatewayClassForbiddenError) Error() string {
|
|
err := fmt.Sprintf("Gateway Class %s is forbidden for the current Tenant: ", i.gatewayClassName)
|
|
|
|
return utils.DefaultAllowedValuesErrorMessage(i.spec, err)
|
|
}
|
|
|
|
type GatewayClassUndefinedError struct {
|
|
spec api.DefaultAllowedListSpec
|
|
}
|
|
|
|
func NewGatewayClassUndefined(spec api.DefaultAllowedListSpec) error {
|
|
return &GatewayClassUndefinedError{
|
|
spec: spec,
|
|
}
|
|
}
|
|
|
|
func (i GatewayClassUndefinedError) Error() string {
|
|
return utils.DefaultAllowedValuesErrorMessage(i.spec, "No gateway Class is forbidden for the current Tenant. Specify a gateway Class which is allowed within the Tenant: ")
|
|
}
|
|
|
|
// GatewayForbiddenError is returned when an HTTPRoute references a Gateway that
|
|
// is not in the allowed list for the Tenant's namespace rules.
|
|
type GatewayForbiddenError struct {
|
|
gatewayNamespace string
|
|
gatewayName string
|
|
spec api.AllowedGatewaySpec
|
|
}
|
|
|
|
func NewGatewayForbidden(name, namespace string, spec api.AllowedGatewaySpec) error {
|
|
return &GatewayForbiddenError{
|
|
gatewayNamespace: namespace,
|
|
gatewayName: name,
|
|
spec: spec,
|
|
}
|
|
}
|
|
|
|
func (e GatewayForbiddenError) Error() string {
|
|
msg := fmt.Sprintf("Gateway %s/%s is forbidden for the current Tenant: ", e.gatewayNamespace, e.gatewayName)
|
|
|
|
parts := []string{msg}
|
|
|
|
if e.spec.Default != nil {
|
|
parts = append(parts, fmt.Sprintf("default: %s/%s", e.spec.Default.Namespace, e.spec.Default.Name))
|
|
}
|
|
|
|
if len(e.spec.Allowed) > 0 {
|
|
names := make([]string, 0, len(e.spec.Allowed))
|
|
|
|
for _, a := range e.spec.Allowed {
|
|
names = append(names, fmt.Sprintf("%s/%s", a.Namespace, a.Name))
|
|
}
|
|
|
|
parts = append(parts, fmt.Sprintf("allowed: [%s]", strings.Join(names, ", ")))
|
|
}
|
|
|
|
return strings.Join(parts, " ")
|
|
}
|