Skip to content

Commit

Permalink
feat(SpEL): implement to configure the limit of characters for SpEL e…
Browse files Browse the repository at this point in the history
…xpressions

Spring Expression Lanuage (SpEL) has a default limit of 10,000 characters. Springframework provides the feature to configure the limit. This feature allows to configure the limit of characters for SpEL expressions.

Approach:
In order to use an expression with characters more than the given default limit, require to follow either of the below approaches:
1. For Springframework >=5.3.28 and <6.1.3, by setting `maximumExpressionLength` field while instantiating the custom `SpelParserConfiguration` class.
spring-projects/spring-framework#30380
spring-projects/spring-framework#30446
2. For Springframework >=6.1.3, by setting a JVM system property or Spring property named `spring.context.expression.maxLength` to the maximum expression length needed by your application.
spring-projects/spring-framework#31952
spring-projects/spring-framework@7855986
Spinnaker supports spring boot 2.7.18, that brings springframework 5.3.31 [https://docs.spring.io/spring-boot/docs/2.7.18/reference/html/dependency-versions.html#appendix.dependency-versions.propertie9]. So first approach need to be implemented along with spinnaker enhancement to expose the `maximumExpressionLength` field.
  • Loading branch information
j-sandy committed Jul 1, 2024
1 parent 9898ae1 commit 4f61e0e
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.TemplateParserContext;
import org.springframework.expression.spel.SpelParserConfiguration;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;

Expand Down Expand Up @@ -130,8 +131,7 @@ public static SpelEvaluatorVersion Default() {
PipelineExecution.AuthenticationDetails.class,
PipelineExecution.PausedDetails.class
};

private final ExpressionParser parser = new SpelExpressionParser();
private final ExpressionParser parser;
private final ParserContext parserContext = new TemplateParserContext("${", "}");
private final ExpressionsSupport support;

Expand All @@ -148,6 +148,12 @@ public PipelineExpressionEvaluator(
pluginManager,
expressionProperties);
initExecutionAwareFunctions(expressionFunctionProviders);
parser =
new SpelExpressionParser(
expressionProperties.getMaxExpressionLength() > 0
? new SpelParserConfiguration(
null, null, false, false, 0, expressionProperties.getMaxExpressionLength())
: new SpelParserConfiguration());
}

public Map<String, Object> evaluate(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright 2024 OpsMx, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.netflix.spinnaker.orca.pipeline.expressions;

import static org.junit.jupiter.api.Assertions.assertTrue;

import com.netflix.spinnaker.kork.expressions.ExpressionEvaluationSummary;
import com.netflix.spinnaker.kork.expressions.config.ExpressionProperties;
import com.netflix.spinnaker.orca.test.YamlFileApplicationContextInitializer;
import java.util.ArrayList;
import java.util.Map;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.pf4j.PluginManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.ContextConfiguration;

@ContextConfiguration(
classes = PipelineExpressionLengthTest.class,
initializers = PipelineExpressionLengthTest.class)
@SpringBootTest
@EnableConfigurationProperties(ExpressionProperties.class)
public class PipelineExpressionLengthTest extends YamlFileApplicationContextInitializer {

@Mock private PluginManager pluginManager;
@Autowired private ExpressionProperties expressionProperties;

@Override
protected String getResourceLocation() {
return "classpath:expression-properties.yml";
}

@Test
void customExpressionLength() {
String expression = String.format("%s", repeat("T", 10975));
String rootObjectExpression = String.format("${status.toString() == \"%s\"}", expression);

Map<String, String> rootObject = Map.of("status", expression);
Map<String, Object> source = Map.of("test", rootObjectExpression);

PipelineExpressionEvaluator evaluator =
new PipelineExpressionEvaluator(new ArrayList<>(), pluginManager, expressionProperties);

Map<String, Object> result =
evaluator.evaluate(source, rootObject, new ExpressionEvaluationSummary(), true);
assertTrue(Boolean.parseBoolean(result.get("test").toString()));
}

private String repeat(String str, int count) {
String res = "";
for (int i = 0; i < count; i++) {
res += str;
}
return res;
}
}
2 changes: 2 additions & 0 deletions orca-core/src/test/resources/expression-properties.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
expression:
max-expression-length: 11000

0 comments on commit 4f61e0e

Please sign in to comment.