This is an automated email from the ASF dual-hosted git repository.

pvillard31 pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new f5e20e3687f NIFI-16285 Allow existing illegal Parameter names to load 
(#11616)
f5e20e3687f is described below

commit f5e20e3687f3eee9fecb3a6b59a5b542390616ef
Author: skeossei <[email protected]>
AuthorDate: Thu Sep 3 10:58:57 2026 -0700

    NIFI-16285 Allow existing illegal Parameter names to load (#11616)
    
    Do not validate Parameter names during flow inherit so a persisted
    flow.json.gz with a legacy illegal name can start and be deleted via REST.
    
    Log a warning when inherit encounters an illegal Parameter name and add
    coverage for loading that name into a new or existing Parameter Context.
---
 .../nifi/parameter/ParameterNameValidator.java     |  6 +-
 .../nifi/parameter/ParameterNameValidatorTest.java |  3 +
 .../serialization/VersionedFlowSynchronizer.java   |  6 +-
 .../VersionedFlowSynchronizerTest.java             | 80 +++++++++++++++++++---
 4 files changed, 83 insertions(+), 12 deletions(-)

diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/parameter/ParameterNameValidator.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/parameter/ParameterNameValidator.java
index 21bc03b268a..f193f8512e9 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/parameter/ParameterNameValidator.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/main/java/org/apache/nifi/parameter/ParameterNameValidator.java
@@ -24,8 +24,12 @@ public final class ParameterNameValidator {
     private ParameterNameValidator() {
     }
 
+    public static boolean isValid(final String parameterName) {
+        return parameterName != null && 
VALID_PARAMETER_NAME_PATTERN.matcher(parameterName).matches();
+    }
+
     public static void validate(final String parameterName) {
-        if (parameterName == null || 
!VALID_PARAMETER_NAME_PATTERN.matcher(parameterName).matches()) {
+        if (!isValid(parameterName)) {
             throw new IllegalArgumentException("Request contains an illegal 
Parameter Name (" + parameterName
                     + "). Parameter names may only include letters, numbers, 
spaces, and the special characters .-_");
         }
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/parameter/ParameterNameValidatorTest.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/parameter/ParameterNameValidatorTest.java
index 5e867c6d854..3d26c914bed 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/parameter/ParameterNameValidatorTest.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core-api/src/test/java/org/apache/nifi/parameter/ParameterNameValidatorTest.java
@@ -19,12 +19,14 @@ package org.apache.nifi.parameter;
 import org.junit.jupiter.api.Test;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
+import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 class ParameterNameValidatorTest {
     @Test
     void testValidParameterName() {
+        assertTrue(ParameterNameValidator.isValid("Parameter Name-1.0"));
         assertDoesNotThrow(() -> ParameterNameValidator.validate("Parameter 
Name-1.0"));
     }
 
@@ -32,6 +34,7 @@ class ParameterNameValidatorTest {
     void testInvalidParameterName() {
         final String parameterName = "PARAMETER_{{ ENVIRONMENT }}";
 
+        assertFalse(ParameterNameValidator.isValid(parameterName));
         final IllegalArgumentException exception = 
assertThrows(IllegalArgumentException.class,
                 () -> ParameterNameValidator.validate(parameterName));
 
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
index 3fb116e4d47..bfee5269475 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/main/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizer.java
@@ -954,14 +954,16 @@ public class VersionedFlowSynchronizer implements 
FlowSynchronizer {
 
         final Map<String, Parameter> parameters = new HashMap<>();
         for (final VersionedParameter versioned : 
versionedParameterContext.getParameters()) {
-            ParameterNameValidator.validate(versioned.getName());
+            final String name = versioned.getName();
+            if (!ParameterNameValidator.isValid(name)) {
+                logger.warn("An invalid Parameter name was found and will be 
loaded so it can be removed");
+            }
             final boolean provided = providerBacked || versioned.isProvided();
             final String parameterValue;
             final String rawValue = versioned.getValue();
             if (rawValue == null) {
                 parameterValue = null;
             } else if (provided) {
-                final String name = versioned.getName();
                 final Parameter providedParameter = 
providedParameters.get(name);
                 if (providedParameter == null) {
                     logger.warn("Parameter Context [{}] Provided Parameter 
[{}] not found", versionedParameterContext.getIdentifier(), name);
diff --git 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
index d541e7bfabe..221f730de0f 100644
--- 
a/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
+++ 
b/nifi-framework-bundle/nifi-framework/nifi-framework-core/src/test/java/org/apache/nifi/controller/serialization/VersionedFlowSynchronizerTest.java
@@ -48,6 +48,7 @@ import org.apache.nifi.groups.BundleUpdateStrategy;
 import org.apache.nifi.groups.ProcessGroup;
 import org.apache.nifi.nar.ExtensionManager;
 import org.apache.nifi.parameter.Parameter;
+import org.apache.nifi.parameter.ParameterContext;
 import org.apache.nifi.parameter.ParameterDescriptor;
 import org.apache.nifi.parameter.ParameterGroup;
 import org.apache.nifi.parameter.ParameterProvider;
@@ -82,7 +83,6 @@ import java.util.concurrent.CompletableFuture;
 
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertInstanceOf;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -370,34 +370,96 @@ class VersionedFlowSynchronizerTest {
     }
 
     @Test
-    void testSyncRejectsInvalidParameterName() {
+    void testSyncLoadsInvalidParameterName() {
         setRootGroup();
         setFlowController();
 
         final String invalidParameterName = "PARAMETER_{{ ENVIRONMENT }}";
+        final String parameterValue = "parameter-value";
+        final String contextId = "parameter-context-id";
+        final String contextName = "parameter-context";
 
         final StandardParameterContextManager contextManager = new 
StandardParameterContextManager();
+        stubParameterContextResolution(contextManager);
+        when(flowManager.createParameterContext(any(), any(), any(), any(), 
any(), any())).thenAnswer(invocation -> {
+            final StandardParameterContext created = new 
StandardParameterContext.Builder()
+                    .id(invocation.getArgument(0))
+                    .name(invocation.getArgument(1))
+                    .parameterReferenceManager(ParameterReferenceManager.EMPTY)
+                    .build();
+            created.setParameters(invocation.getArgument(3));
+            contextManager.addParameterContext(created);
+            return created;
+        });
+
+        stubInvalidVersionedParameterContext(invalidParameterName, 
parameterValue, contextId, contextName);
+
+        assertDoesNotThrow(() ->
+                versionedFlowSynchronizer.sync(flowController, dataFlow, 
flowService, BundleUpdateStrategy.USE_SPECIFIED_OR_GHOST));
+
+        final ParameterContext loadedContext = 
contextManager.getParameterContext(contextId);
+        assertLoadedInvalidParameter(loadedContext, invalidParameterName, 
parameterValue);
+    }
+
+    @Test
+    void testSyncReconcilesExistingInvalidParameterName() {
+        setRootGroup();
+        setFlowController();
+
+        final String invalidParameterName = "PARAMETER_{{ ENVIRONMENT }}";
+        final String parameterValue = "parameter-value";
+        final String contextId = "parameter-context-id";
+        final String contextName = "parameter-context";
+
+        final StandardParameterContext existingContext = new 
StandardParameterContext.Builder()
+                .id(contextId)
+                .name(contextName)
+                .parameterReferenceManager(ParameterReferenceManager.EMPTY)
+                .build();
+        
existingContext.setParameters(Collections.singletonMap(invalidParameterName,
+                new Parameter.Builder()
+                        .name(invalidParameterName)
+                        .value("previous-value")
+                        .sensitive(true)
+                        .build()));
+
+        final StandardParameterContextManager contextManager = new 
StandardParameterContextManager();
+        contextManager.addParameterContext(existingContext);
+        stubParameterContextResolution(contextManager);
+        stubInvalidVersionedParameterContext(invalidParameterName, 
parameterValue, contextId, contextName);
+
+        assertDoesNotThrow(() ->
+                versionedFlowSynchronizer.sync(flowController, dataFlow, 
flowService, BundleUpdateStrategy.USE_SPECIFIED_OR_GHOST));
+
+        assertLoadedInvalidParameter(existingContext, invalidParameterName, 
parameterValue);
+    }
+
+    private void stubParameterContextResolution(final 
StandardParameterContextManager contextManager) {
         
when(flowManager.getParameterContextManager()).thenReturn(contextManager);
         doAnswer(invocation -> {
             invocation.getArgument(0, Runnable.class).run();
             return null;
         }).when(flowManager).withParameterContextResolution(any());
+    }
 
+    private void stubInvalidVersionedParameterContext(final String 
invalidParameterName, final String parameterValue,
+            final String contextId, final String contextName) {
         final VersionedParameter versionedParameter = new VersionedParameter();
         versionedParameter.setName(invalidParameterName);
         versionedParameter.setSensitive(true);
-        versionedParameter.setValue("parameter-value");
+        versionedParameter.setValue(parameterValue);
 
         final VersionedParameterContext versionedParameterContext = new 
VersionedParameterContext();
-        
versionedParameterContext.setInstanceIdentifier("parameter-context-id");
-        versionedParameterContext.setName("parameter-context");
+        versionedParameterContext.setInstanceIdentifier(contextId);
+        versionedParameterContext.setName(contextName);
         
versionedParameterContext.setParameters(Collections.singleton(versionedParameter));
         
when(versionedDataflow.getParameterContexts()).thenReturn(List.of(versionedParameterContext));
+    }
 
-        final FlowSynchronizationException exception = 
assertThrows(FlowSynchronizationException.class, () ->
-                versionedFlowSynchronizer.sync(flowController, dataFlow, 
flowService, BundleUpdateStrategy.USE_SPECIFIED_OR_GHOST));
-        final IllegalArgumentException cause = 
assertInstanceOf(IllegalArgumentException.class, exception.getCause());
-        assertTrue(cause.getMessage().contains(invalidParameterName));
+    private void assertLoadedInvalidParameter(final ParameterContext context, 
final String invalidParameterName, final String parameterValue) {
+        final Optional<Parameter> loaded = 
context.getParameter(invalidParameterName);
+        assertTrue(loaded.isPresent(), "Illegal Parameter already present in 
the flow must be loaded so it can be removed");
+        assertEquals(parameterValue, loaded.get().getValue());
     }
 
     private void setRootGroup() {

Reply via email to