feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -36,6 +36,15 @@ type CostEstimator struct {
func (l *CostEstimator) CallCost(function, overloadId string, args []ref.Val, result ref.Val) *uint64 {
switch function {
case "check":
// An authorization check has a fixed cost
// This cost is set to allow for only two authorization checks per expression
cost := uint64(350000)
return &cost
case "serviceAccount", "path", "group", "resource", "subresource", "namespace", "name", "allowed", "reason", "error", "errored":
// All authorization builder and accessor functions have a nominal cost
cost := uint64(1)
return &cost
case "isSorted", "sum", "max", "min", "indexOf", "lastIndexOf":
var cost uint64
if len(args) > 0 {
@@ -78,6 +87,13 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch
// WARNING: Any changes to this code impact API compatibility! The estimated cost is used to determine which CEL rules may be written to a
// CRD and any change (cost increases and cost decreases) are breaking.
switch function {
case "check":
// An authorization check has a fixed cost
// This cost is set to allow for only two authorization checks per expression
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 350000, Max: 350000}}
case "serviceAccount", "path", "group", "resource", "subresource", "namespace", "name", "allowed", "reason", "error", "errored":
// All authorization builder and accessor functions have a nominal cost
return &checker.CallEstimate{CostEstimate: checker.CostEstimate{Min: 1, Max: 1}}
case "isSorted", "sum", "max", "min", "indexOf", "lastIndexOf":
if target != nil {
// Charge 1 cost for comparing each element in the list
@@ -85,8 +101,8 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch
// If the list contains strings or bytes, add the cost of traversing all the strings/bytes as a way
// of estimating the additional comparison cost.
if elNode := l.listElementNode(*target); elNode != nil {
t := elNode.Type().GetPrimitive()
if t == exprpb.Type_STRING || t == exprpb.Type_BYTES {
k := elNode.Type().Kind()
if k == types.StringKind || k == types.BytesKind {
sz := l.sizeEstimate(elNode)
elCost = elCost.Add(sz.MultiplyByCostFactor(common.StringTraversalCostFactor))
}
@@ -94,7 +110,6 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch
} else { // the target is a string, which is supported by indexOf and lastIndexOf
return &checker.CallEstimate{CostEstimate: l.sizeEstimate(*target).MultiplyByCostFactor(common.StringTraversalCostFactor)}
}
}
case "url":
if len(args) == 1 {
@@ -111,13 +126,51 @@ func (l *CostEstimator) EstimateCallCost(function, overloadId string, target *ch
sz := l.sizeEstimate(*target)
toReplaceSz := l.sizeEstimate(args[0])
replaceWithSz := l.sizeEstimate(args[1])
// smallest possible result: smallest input size composed of the largest possible substrings being replaced by smallest possible replacement
minSz := uint64(math.Ceil(float64(sz.Min)/float64(toReplaceSz.Max))) * replaceWithSz.Min
// largest possible result: largest input size composed of the smallest possible substrings being replaced by largest possible replacement
maxSz := uint64(math.Ceil(float64(sz.Max)/float64(toReplaceSz.Min))) * replaceWithSz.Max
var replaceCount, retainedSz checker.SizeEstimate
// find the longest replacement:
if toReplaceSz.Min == 0 {
// if the string being replaced is empty, replace surrounds all characters in the input string with the replacement.
if sz.Max < math.MaxUint64 {
replaceCount.Max = sz.Max + 1
} else {
replaceCount.Max = sz.Max
}
// Include the length of the longest possible original string length.
retainedSz.Max = sz.Max
} else if replaceWithSz.Max <= toReplaceSz.Min {
// If the replacement does not make the result longer, use the original string length.
replaceCount.Max = 0
retainedSz.Max = sz.Max
} else {
// Replace the smallest possible substrings with the largest possible replacement
// as many times as possible.
replaceCount.Max = uint64(math.Ceil(float64(sz.Max) / float64(toReplaceSz.Min)))
}
// find the shortest replacement:
if toReplaceSz.Max == 0 {
// if the string being replaced is empty, replace surrounds all characters in the input string with the replacement.
if sz.Min < math.MaxUint64 {
replaceCount.Min = sz.Min + 1
} else {
replaceCount.Min = sz.Min
}
// Include the length of the shortest possible original string length.
retainedSz.Min = sz.Min
} else if toReplaceSz.Max <= replaceWithSz.Min {
// If the replacement does not make the result shorter, use the original string length.
replaceCount.Min = 0
retainedSz.Min = sz.Min
} else {
// Replace the largest possible substrings being with the smallest possible replacement
// as many times as possible.
replaceCount.Min = uint64(math.Ceil(float64(sz.Min) / float64(toReplaceSz.Max)))
}
size := replaceCount.Multiply(replaceWithSz).Add(retainedSz)
// cost is the traversal plus the construction of the result
return &checker.CallEstimate{CostEstimate: sz.MultiplyByCostFactor(2 * common.StringTraversalCostFactor), ResultSize: &checker.SizeEstimate{Min: minSz, Max: maxSz}}
return &checker.CallEstimate{CostEstimate: sz.MultiplyByCostFactor(2 * common.StringTraversalCostFactor), ResultSize: &size}
}
case "split":
if target != nil {
@@ -194,7 +247,8 @@ func (l *CostEstimator) sizeEstimate(t checker.AstNode) checker.SizeEstimate {
}
func (l *CostEstimator) listElementNode(list checker.AstNode) checker.AstNode {
if lt := list.Type().GetListType(); lt != nil {
if params := list.Type().Parameters(); len(params) > 0 {
lt := params[0]
nodePath := list.Path()
if nodePath != nil {
// Provide path if we have it so that a OpenAPIv3 maxLength validation can be looked up, if it exists
@@ -202,10 +256,10 @@ func (l *CostEstimator) listElementNode(list checker.AstNode) checker.AstNode {
path := make([]string, len(nodePath)+1)
copy(path, nodePath)
path[len(nodePath)] = "@items"
return &itemsNode{path: path, t: lt.GetElemType(), expr: nil}
return &itemsNode{path: path, t: lt, expr: nil}
} else {
// Provide just the type if no path is available so that worst case size can be looked up based on type.
return &itemsNode{t: lt.GetElemType(), expr: nil}
return &itemsNode{t: lt, expr: nil}
}
}
return nil
@@ -220,7 +274,7 @@ func (l *CostEstimator) EstimateSize(element checker.AstNode) *checker.SizeEstim
type itemsNode struct {
path []string
t *exprpb.Type
t *types.Type
expr *exprpb.Expr
}
@@ -228,7 +282,7 @@ func (i *itemsNode) Path() []string {
return i.path
}
func (i *itemsNode) Type() *exprpb.Type {
func (i *itemsNode) Type() *types.Type {
return i.t
}