@@ -410,7 +410,9 @@ func (c *stringFormatter) Octal(arg ref.Val, locale string) (string, error) {
410410
411411// stringFormatValidator implements the cel.ASTValidator interface allowing for static validation
412412// of string.format calls.
413- type stringFormatValidator struct {}
413+ type stringFormatValidator struct {
414+ maxPrecision int
415+ }
414416
415417// Name returns the name of the validator.
416418func (stringFormatValidator ) Name () string {
@@ -427,7 +429,7 @@ func (stringFormatValidator) Configure(config cel.MutableValidatorConfig) error
427429
428430// Validate parses all literal format strings and type checks the format clause against the argument
429431// at the corresponding ordinal within the list literal argument to the function, if one is specified.
430- func (stringFormatValidator ) Validate (env * cel.Env , _ cel.ValidatorConfig , a * ast.AST , iss * cel.Issues ) {
432+ func (v stringFormatValidator ) Validate (env * cel.Env , _ cel.ValidatorConfig , a * ast.AST , iss * cel.Issues ) {
431433 root := ast .NavigateAST (a )
432434 formatCallExprs := ast .MatchDescendants (root , matchConstantFormatStringWithListLiteralArgs (a ))
433435 for _ , e := range formatCallExprs {
@@ -439,7 +441,7 @@ func (stringFormatValidator) Validate(env *cel.Env, _ cel.ValidatorConfig, a *as
439441 ast : a ,
440442 }
441443 // use a placeholder locale, since locale doesn't affect syntax
442- _ , err := parseFormatString (formatStr , formatCheck , formatCheck , "en_US" )
444+ _ , err := parseFormatString (formatStr , formatCheck , formatCheck , "en_US" , v . maxPrecision )
443445 if err != nil {
444446 iss .ReportErrorAtID (getErrorExprID (e .ID (), err ), "%v" , err )
445447 continue
@@ -778,7 +780,7 @@ type formatListArgs interface {
778780
779781// parseFormatString formats a string according to the string.format syntax, taking the clause implementations
780782// from the provided FormatCallback and the args from the given FormatList.
781- func parseFormatString (formatStr string , callback formatStringInterpolator , list formatListArgs , locale string ) (string , error ) {
783+ func parseFormatString (formatStr string , callback formatStringInterpolator , list formatListArgs , locale string , maxPrecision int ) (string , error ) {
782784 i := 0
783785 argIndex := 0
784786 var builtStr strings.Builder
@@ -802,7 +804,7 @@ func parseFormatString(formatStr string, callback formatStringInterpolator, list
802804 if int64 (argIndex ) >= list .Size () {
803805 return "" , fmt .Errorf ("index %d out of range" , argIndex )
804806 }
805- numRead , val , refErr := parseAndFormatClause (formatStr [i :], argAny , callback , list , locale )
807+ numRead , val , refErr := parseAndFormatClause (formatStr [i :], argAny , callback , list , locale , maxPrecision )
806808 if refErr != nil {
807809 return "" , refErr
808810 }
@@ -826,9 +828,9 @@ func parseFormatString(formatStr string, callback formatStringInterpolator, list
826828
827829// parseAndFormatClause parses the format clause at the start of the given string with val, and returns
828830// how many characters were consumed and the substituted string form of val, or an error if one occurred.
829- func parseAndFormatClause (formatStr string , val ref.Val , callback formatStringInterpolator , list formatListArgs , locale string ) (int , string , error ) {
831+ func parseAndFormatClause (formatStr string , val ref.Val , callback formatStringInterpolator , list formatListArgs , locale string , maxPrecision int ) (int , string , error ) {
830832 i := 1
831- read , formatter , err := parseFormattingClause (formatStr [i :], callback )
833+ read , formatter , err := parseFormattingClause (formatStr [i :], callback , maxPrecision )
832834 i += read
833835 if err != nil {
834836 return - 1 , "" , newParseFormatError ("could not parse formatting clause" , err )
@@ -841,9 +843,9 @@ func parseAndFormatClause(formatStr string, val ref.Val, callback formatStringIn
841843 return i , valStr , nil
842844}
843845
844- func parseFormattingClause (formatStr string , callback formatStringInterpolator ) (int , clauseImpl , error ) {
846+ func parseFormattingClause (formatStr string , callback formatStringInterpolator , maxPrecision int ) (int , clauseImpl , error ) {
845847 i := 0
846- read , precision , err := parsePrecision (formatStr [i :])
848+ read , precision , err := parsePrecision (formatStr [i :], maxPrecision )
847849 i += read
848850 if err != nil {
849851 return - 1 , nil , fmt .Errorf ("error while parsing precision: %w" , err )
@@ -870,7 +872,7 @@ func parseFormattingClause(formatStr string, callback formatStringInterpolator)
870872 }
871873}
872874
873- func parsePrecision (formatStr string ) (int , * int , error ) {
875+ func parsePrecision (formatStr string , maxPrecision int ) (int , * int , error ) {
874876 i := 0
875877 if formatStr [i ] != '.' {
876878 return i , nil , nil
@@ -891,6 +893,9 @@ func parsePrecision(formatStr string) (int, *int, error) {
891893 if err != nil {
892894 return - 1 , nil , fmt .Errorf ("error while converting precision to integer: %w" , err )
893895 }
896+ if maxPrecision > 0 && precision > maxPrecision {
897+ return - 1 , nil , fmt .Errorf ("precision %d exceeds maximum allowed precision %d" , precision , maxPrecision )
898+ }
894899 return i , & precision , nil
895900}
896901
0 commit comments