Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -51,22 +51,6 @@
* @author jdcasey Created on Feb 3, 2005
*/
public abstract class AbstractStringBasedModelInterpolator implements ModelInterpolator {

/**
* User property for opting back into the previous behavior of interpolating
* repository-resolved models (built at {@link ModelBuildingRequest#VALIDATION_LEVEL_MINIMAL})
* against the full set of session properties (system, environment and CLI).
* When set to {@code "false"} (default), such models are interpolated only against
* their own {@code <properties>}, preventing property leaking from the requesting
* build into transitive POMs. When set to {@code "true"}, full interpolation is
* applied as in previous Maven versions.
* <p>
* In Maven 4.x this constant is promoted to
* {@code org.apache.maven.api.Constants.MAVEN_MODEL_DEPENDENCY_INTERPOLATION_FULL}
* with {@code @Config} so it appears in the auto-generated configuration documentation.
*/
public static final String FULL_EXTERNAL_INTERPOLATION_PROPERTY = "maven.model.dependencyInterpolation.full";

private static final List<String> PROJECT_PREFIXES = Arrays.asList("pom.", "project.");

private static final Collection<String> TRANSLATED_PATH_EXPRESSIONS;
Expand Down Expand Up @@ -196,34 +180,21 @@ public Object getValue(String expression) {

valueSources.add(modelValueSource1);

// Models built at VALIDATION_LEVEL_MINIMAL are the models Maven builds while resolving
// dependency, parent and BOM-import POMs from a repository, not the operator's own
// project. Such models interpolate only against their own properties and a small set
// of environment-independent expressions; everything else in the user/system property
// space stays uninterpolated. Operator project builds use a higher validation level and
// keep the full set of value sources, unchanged from previous behavior.
boolean restricted = restrictExternalModelInterpolation(config);

ValueSource userPropertiesValueSource = new MapBasedValueSource(config.getUserProperties());
valueSources.add(restricted ? restrictToSafeExpressions(userPropertiesValueSource) : userPropertiesValueSource);
valueSources.add(new MapBasedValueSource(config.getUserProperties()));

// Overwrite existing values in model properties. Otherwise it's not possible
// to define them via command line e.g.: mvn -Drevision=6.5.7 ...
versionProcessor.overwriteModelProperties(modelProperties, config);
valueSources.add(new MapBasedValueSource(modelProperties));

ValueSource systemPropertiesValueSource = new MapBasedValueSource(config.getSystemProperties());
valueSources.add(
restricted ? restrictToSafeExpressions(systemPropertiesValueSource) : systemPropertiesValueSource);

if (!restricted) {
valueSources.add(new AbstractValueSource(false) {
@Override
public Object getValue(String expression) {
return config.getSystemProperties().getProperty("env." + expression);
}
});
}
valueSources.add(new MapBasedValueSource(config.getSystemProperties()));

valueSources.add(new AbstractValueSource(false) {
@Override
public Object getValue(String expression) {
return config.getSystemProperties().getProperty("env." + expression);
}
});

valueSources.add(modelValueSource2);

Expand All @@ -233,38 +204,6 @@ public Object getValue(String expression) {
return valueSources;
}

private static boolean restrictExternalModelInterpolation(ModelBuildingRequest config) {
return config.getValidationLevel() < ModelBuildingRequest.VALIDATION_LEVEL_MAVEN_2_0
&& !Boolean.parseBoolean(config.getSystemProperties().getProperty(FULL_EXTERNAL_INTERPOLATION_PROPERTY))
&& !Boolean.parseBoolean(config.getUserProperties().getProperty(FULL_EXTERNAL_INTERPOLATION_PROPERTY));
}

private static ValueSource restrictToSafeExpressions(ValueSource source) {
return new AbstractValueSource(false) {
@Override
public Object getValue(String expression) {
return isSafeExternalExpression(expression) ? source.getValue(expression) : null;
}
};
}

/**
* Expressions that models built at {@link ModelBuildingRequest#VALIDATION_LEVEL_MINIMAL}
* may still resolve from the session properties: JVM- and Maven-defined properties, plus
* the CI-friendly version properties (MNG-5895). All other expressions are left literal.
*/
private static boolean isSafeExternalExpression(String expression) {
return expression.startsWith("java.")
|| expression.startsWith("os.")
|| expression.startsWith("maven.")
|| "file.separator".equals(expression)
|| "path.separator".equals(expression)
|| "line.separator".equals(expression)
|| "revision".equals(expression)
|| "changelist".equals(expression)
|| "sha1".equals(expression);
}

protected List<? extends InterpolationPostProcessor> createPostProcessors(
final Model model, final File projectDir, final ModelBuildingRequest config) {
List<InterpolationPostProcessor> processors = new ArrayList<>(2);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -358,91 +358,6 @@ public void testEnvars() throws Exception {
assertEquals("/path/to/home", out.getProperties().getProperty("outputDirectory"));
}

@Test
public void testMinimalValidationInterpolationUsesRestrictedPropertySet() throws Exception {
Properties context = new Properties();
context.put("env.SOME_VAR", "some-value");
context.put("some.property", "other-value");
context.put("java.version", "21");

Model model = new Model();

Properties modelProperties = new Properties();
modelProperties.setProperty("envDir", "${env.SOME_VAR}");
modelProperties.setProperty("propDir", "${some.property}");
modelProperties.setProperty("jdk", "${java.version}");

model.setProperties(modelProperties);

ModelInterpolator interpolator = createInterpolator();

final SimpleProblemCollector collector = new SimpleProblemCollector();
ModelBuildingRequest config = createModelBuildingRequest(context);
config.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
Model out = interpolator.interpolateModel(model, new File("."), config, collector);
assertProblemFree(collector);

// At minimal validation level (the level used for models built while resolving
// dependency, parent and BOM-import POMs) env and arbitrary system/user properties
// stay literal...
assertEquals("${env.SOME_VAR}", out.getProperties().getProperty("envDir"));
assertEquals("${some.property}", out.getProperties().getProperty("propDir"));
// ...while JVM-defined and other well-known expressions keep resolving.
assertEquals("21", out.getProperties().getProperty("jdk"));
}

@Test
public void testFullInterpolationOptOutRestoresPreviousBehaviorAtMinimalValidationLevel() throws Exception {
Properties context = new Properties();
context.put("env.SOME_VAR", "some-value");
context.put(AbstractStringBasedModelInterpolator.FULL_EXTERNAL_INTERPOLATION_PROPERTY, "true");

Model model = new Model();

Properties modelProperties = new Properties();
modelProperties.setProperty("envDir", "${env.SOME_VAR}");

model.setProperties(modelProperties);

ModelInterpolator interpolator = createInterpolator();

final SimpleProblemCollector collector = new SimpleProblemCollector();
ModelBuildingRequest config = createModelBuildingRequest(context);
config.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
Model out = interpolator.interpolateModel(model, new File("."), config, collector);
assertProblemFree(collector);

assertEquals("some-value", out.getProperties().getProperty("envDir"));
}

@Test
public void testEnvarsStillInterpolatedAtStrictValidationLevel() throws Exception {
Properties context = new Properties();
context.put("env.SOME_VAR", "some-value");
context.put("some.property", "other-value");

Model model = new Model();

Properties modelProperties = new Properties();
modelProperties.setProperty("envDir", "${env.SOME_VAR}");
modelProperties.setProperty("propDir", "${some.property}");

model.setProperties(modelProperties);

ModelInterpolator interpolator = createInterpolator();

final SimpleProblemCollector collector = new SimpleProblemCollector();
ModelBuildingRequest config = createModelBuildingRequest(context);
config.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_STRICT);
Model out = interpolator.interpolateModel(model, new File("."), config, collector);
assertProblemFree(collector);

// Operator project builds use strict validation and keep full interpolation,
// unchanged from previous behavior.
assertEquals("some-value", out.getProperties().getProperty("envDir"));
assertEquals("other-value", out.getProperties().getProperty("propDir"));
}

@Test
public void testEnvarExpressionThatEvaluatesToNullReturnsTheLiteralString() throws Exception {
Model model = new Model();
Expand Down
Loading