Fix saving values with special chars in env file (#14873)

Fix how special chars in env values are saved

Also included some refactoring to fix several compile time warnings and lint errors,
including proper formatting.

Signed-off-by: Shrikant Sharat Kandula <shrikant@appsmith.com>
This commit is contained in:
Shrikant Sharat Kandula 2022-07-07 11:27:16 +05:30 committed by GitHub
parent 19a6430f24
commit 30236469a9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 124 additions and 86 deletions

View File

@ -1,7 +1,7 @@
package com.appsmith.server.services.ce;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.external.constants.AnalyticsEvents;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.server.domains.User;
import com.appsmith.server.domains.UserData;
import reactor.core.publisher.Mono;
@ -16,9 +16,9 @@ public interface AnalyticsServiceCE {
void identifyInstance(String instanceId, String role, String useCase);
void sendEvent(String event, String userId, Map<String, Object> properties);
void sendEvent(String event, String userId, Map<String, ?> properties);
void sendEvent(String event, String userId, Map<String, Object> properties, boolean hashUserId);
void sendEvent(String event, String userId, Map<String, ?> properties, boolean hashUserId);
<T extends BaseDomain> Mono<T> sendObjectEvent(AnalyticsEvents event, T object, Map<String, Object> extraProperties);

View File

@ -1,9 +1,9 @@
package com.appsmith.server.services.ce;
import com.appsmith.external.constants.AnalyticsEvents;
import com.appsmith.external.models.BaseDomain;
import com.appsmith.server.acl.AclPermission;
import com.appsmith.server.configurations.CommonConfig;
import com.appsmith.external.constants.AnalyticsEvents;
import com.appsmith.server.constants.FieldName;
import com.appsmith.server.domains.User;
import com.appsmith.server.domains.UserData;
@ -102,11 +102,13 @@ public class AnalyticsServiceCEImpl implements AnalyticsServiceCE {
analytics.flush();
}
public void sendEvent(String event, String userId, Map<String, Object> properties) {
@Override
public void sendEvent(String event, String userId, Map<String, ?> properties) {
sendEvent(event, userId, properties, true);
}
public void sendEvent(String event, String userId, Map<String, Object> properties, boolean hashUserId) {
@Override
public void sendEvent(String event, String userId, Map<String, ?> properties, boolean hashUserId) {
if (!isActive()) {
return;
}

View File

@ -100,7 +100,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
* respectively.
*/
private static final Pattern ENV_VARIABLE_PATTERN = Pattern.compile(
"^(?<name>[A-Z0-9_]+)\\s*=\\s*\"?(?<value>.*?)\"?$"
"^(?<name>[A-Z\\d_]+)\\s*=\\s*(?<quote>[\"']?)(?<value>.*?)\\k<quote>$"
);
private static final Set<String> VARIABLE_WHITELIST = Stream.of(EnvVariables.values())
@ -111,10 +111,12 @@ public class EnvManagerCEImpl implements EnvManagerCE {
* Updates values of variables in the envContent string, based on the changes map given. This function **only**
* updates values of variables that already defined in envContent. It NEVER adds new env variables to it. This is so
* a malicious request won't insert new dubious env variables.
*
* @param envContent String content of an env file.
* @param changes A map with variable name to new value.
* @param changes A map with variable name to new value.
* @return List of string lines for updated env file content.
*/
@Override
public List<String> transformEnvContent(String envContent, Map<String, String> changes) {
final Set<String> variablesNotInWhitelist = new HashSet<>(changes.keySet());
variablesNotInWhitelist.removeAll(VARIABLE_WHITELIST);
@ -126,14 +128,14 @@ public class EnvManagerCEImpl implements EnvManagerCE {
if (changes.containsKey(APPSMITH_MAIL_HOST.name())) {
changes.put(
APPSMITH_MAIL_ENABLED.name(),
Boolean.toString(!StringUtils.isEmpty(changes.get(APPSMITH_MAIL_HOST.name())))
Boolean.toString(StringUtils.hasText(changes.get(APPSMITH_MAIL_HOST.name())))
);
}
if (changes.containsKey(APPSMITH_MAIL_USERNAME.name())) {
changes.put(
APPSMITH_MAIL_SMTP_AUTH.name(),
Boolean.toString(!StringUtils.isEmpty(changes.get(APPSMITH_MAIL_USERNAME.name())))
Boolean.toString(StringUtils.hasText(changes.get(APPSMITH_MAIL_USERNAME.name())))
);
}
@ -150,9 +152,11 @@ public class EnvManagerCEImpl implements EnvManagerCE {
return line;
}
remainingChangedNames.remove(name);
return line.substring(0, matcher.start("value"))
+ changes.get(name)
+ line.substring(matcher.end("value"));
String safeValue = changes.get(name);
if (safeValue.contains(" ") || safeValue.contains("?") || safeValue.contains("*") || safeValue.contains("#")) {
safeValue = "'" + safeValue.replace("'", "'\"'\"'") + "'";
}
return String.format("%s=%s", name, safeValue);
})
.collect(Collectors.toList());
@ -164,15 +168,15 @@ public class EnvManagerCEImpl implements EnvManagerCE {
}
private Mono<Void> validateChanges(User user, Map<String, String> changes) {
if(changes.containsKey(APPSMITH_ADMIN_EMAILS.name())) {
if (changes.containsKey(APPSMITH_ADMIN_EMAILS.name())) {
String emailCsv = StringUtils.trimAllWhitespace(changes.get(APPSMITH_ADMIN_EMAILS.name()));
// validate input is in the format email,email,email and is not empty
if(!ValidationUtils.validateEmailCsv(emailCsv)) {
if (!ValidationUtils.validateEmailCsv(emailCsv)) {
return Mono.error(new AppsmithException(AppsmithError.INVALID_PARAMETER, "Admin Email"));
} else { // make sure user is not removing own email
Set<String> adminEmails = TextUtils.csvToSet(emailCsv);
if(!adminEmails.contains(user.getEmail())) { // user can not remove own email address
if (!adminEmails.contains(user.getEmail())) { // user can not remove own email address
return Mono.error(new AppsmithException(
AppsmithError.GENERIC_BAD_REQUEST, "Removing own email from Admin Email is not allowed"
));
@ -182,6 +186,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
return Mono.empty();
}
@Override
public Mono<EnvChangesResponseDTO> applyChanges(Map<String, String> changes) {
return verifyCurrentUserIsSuper()
.flatMap(user -> validateChanges(user, changes).thenReturn(user))
@ -230,9 +235,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
if (changesCopy.containsKey(APPSMITH_ADMIN_EMAILS.name())) {
commonConfig.setAdminEmails(changesCopy.remove(APPSMITH_ADMIN_EMAILS.name()));
String oldAdminEmailsCsv = originalValues.get(APPSMITH_ADMIN_EMAILS.name());
dependentTasks = dependentTasks.then(
updateAdminUserPolicies(oldAdminEmailsCsv).then()
);
dependentTasks = dependentTasks.then(updateAdminUserPolicies(oldAdminEmailsCsv));
}
if (changesCopy.containsKey(APPSMITH_MAIL_FROM.name())) {
@ -285,44 +288,42 @@ public class EnvManagerCEImpl implements EnvManagerCE {
/**
* Sends analytics events after a new authentication method is added or removed.
* @param user
*
* @param user The user who triggered the event.
* @param originalVariables Already existing env variables
* @param changes Changes in the env variables
* @return
* @param changes Changes in the env variables
*/
private Mono<Void> sendAnalyticsEvent(User user, Map<String, String> originalVariables, Map<String, String> changes) {
private void sendAnalyticsEvent(User user, Map<String, String> originalVariables, Map<String, String> changes) {
// Generate analytics event properties template(s) according to the env variable changes
List<Map> analyticsEvents = getAnalyticsEvents(originalVariables, changes, new ArrayList<>());
List<Map<String, String>> analyticsEvents = getAnalyticsEvents(originalVariables, changes, new ArrayList<>());
for (Map analyticsEvent : analyticsEvents) {
for (Map<String, String> analyticsEvent : analyticsEvents) {
analyticsService.sendEvent(AnalyticsEvents.AUTHENTICATION_METHOD_CONFIGURATION.getEventName(), user.getUsername(), analyticsEvent);
}
return Mono.empty();
}
/**
* Generates analytics event properties template(s) according to the env variable changes.
*
* @param originalVariables Already existing env variables
* @param changes Changes in the env variables
* @param extraAuthEnvs To incorporate extra authentication methods in enterprise edition
* @return
* @param changes Changes in the env variables
* @param extraAuthEnvs To incorporate extra authentication methods in enterprise edition
* @return A list of analytics event properties mappings.
*/
public List<Map> getAnalyticsEvents(Map<String, String> originalVariables, Map<String, String> changes, List<String> extraAuthEnvs){
public List<Map<String, String>> getAnalyticsEvents(Map<String, String> originalVariables, Map<String, String> changes, List<String> extraAuthEnvs) {
List<String> authEnvs = new ArrayList<>(List.of(APPSMITH_OAUTH2_GOOGLE_CLIENT_ID.name(), APPSMITH_OAUTH2_GITHUB_CLIENT_ID.name()));
// Add extra authentication methods
authEnvs.addAll(extraAuthEnvs);
// Generate analytics event(s) properties
List<Map> analyticsEvents = new ArrayList<>();
List<Map<String, String>> analyticsEvents = new ArrayList<>();
for (String authEnv : authEnvs) {
if (changes.containsKey(authEnv)) {
Map<String, String> properties = new HashMap<>(){{
put("provider", authEnv);
}};
properties = setAnalyticsEventAction(properties, changes.get(authEnv), originalVariables.get(authEnv), authEnv);
if(properties.containsKey("action")){
Map<String, String> properties = new HashMap<>();
properties.put("provider", authEnv);
setAnalyticsEventAction(properties, changes.get(authEnv), originalVariables.get(authEnv), authEnv);
if (properties.containsKey("action")) {
analyticsEvents.add(properties);
}
}
@ -333,13 +334,13 @@ public class EnvManagerCEImpl implements EnvManagerCE {
/**
* Sets the correct action to analytics event properties template(s) according to the env variable changes
* @param properties
* @param newVariable Updated env variable value
*
* @param properties Properties map into which event details will be populated. **This is mutated**.
* @param newVariable Updated env variable value
* @param originalVariable Already existing env variable value
* @param authEnv Env variable name
* @return
* @param authEnv Env variable name
*/
public Map<String, String> setAnalyticsEventAction(Map<String, String> properties, String newVariable, String originalVariable, String authEnv){
public void setAnalyticsEventAction(Map<String, String> properties, String newVariable, String originalVariable, String authEnv) {
// Authentication configuration added
if (!newVariable.isEmpty() && originalVariable.isEmpty()) {
properties.put("action", "Added");
@ -348,18 +349,16 @@ public class EnvManagerCEImpl implements EnvManagerCE {
else if (newVariable.isEmpty() && !originalVariable.isEmpty()) {
properties.put("action", "Removed");
}
return properties;
}
/**
* Adds or removes admin user policy from users.
* If an email is removed from admin emails, it'll remove the policy from that user.
* If a new email is added as admin email, it'll add the policy to that user
*
* @param oldAdminEmailsCsv comma separated email addresses that was set as admin email earlier
* @return
*/
private Flux<User> updateAdminUserPolicies(String oldAdminEmailsCsv) {
private Mono<Void> updateAdminUserPolicies(String oldAdminEmailsCsv) {
Set<String> oldAdminEmails = TextUtils.csvToSet(oldAdminEmailsCsv);
Set<String> newAdminEmails = commonConfig.getAdminEmails();
@ -380,7 +379,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
Flux<User> newUsersFlux = Flux.fromIterable(newUsers).flatMap(userService::findByEmail)
.flatMap(user -> {
Map<String, Policy> policyMap = policyUtils.generatePolicyFromPermission(
Map<String, Policy> policyMap = policyUtils.generatePolicyFromPermission(
Set.of(AclPermission.MANAGE_INSTANCE_ENV), user.getUsername()
);
policyUtils.addPoliciesToExistingObject(policyMap, user);
@ -388,9 +387,10 @@ public class EnvManagerCEImpl implements EnvManagerCE {
});
int prefetchSize = oldAdminEmails.size(); // prefetch total emails
return Flux.mergeDelayError(prefetchSize, removedUserFlux, newUsersFlux);
return Flux.mergeDelayError(prefetchSize, removedUserFlux, newUsersFlux).then();
}
@Override
public Map<String, String> parseToMap(String content) {
final Map<String, String> data = new HashMap<>();
@ -400,7 +400,18 @@ public class EnvManagerCEImpl implements EnvManagerCE {
if (matcher.matches()) {
final String name = matcher.group("name");
if (VARIABLE_WHITELIST.contains(name)) {
data.put(name, matcher.group("value"));
String actualValue = matcher.group("value");
final String quote = matcher.group("quote");
if ("'".equals(quote)) {
// Undo two common methods of escaping single quotes:
actualValue = actualValue
.replace("'\"'\"'", "'")
.replace("'\\''", "'");
} else if ("\"".equals(quote)) {
// Undo escaped double quotes:
actualValue = actualValue.replace("\\\"", "\"");
}
data.put(name, actualValue);
}
}
});
@ -408,6 +419,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
return data;
}
@Override
public Mono<Map<String, String>> getAll() {
return verifyCurrentUserIsSuper()
.flatMap(user -> {
@ -423,7 +435,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
// set the default values to response
Map<String, String> envKeyValueMap = parseToMap(originalContent);
if(!envKeyValueMap.containsKey(APPSMITH_INSTANCE_NAME.name())) {
if (!envKeyValueMap.containsKey(APPSMITH_INSTANCE_NAME.name())) {
// no APPSMITH_INSTANCE_NAME set in env file, set the default value
envKeyValueMap.put(APPSMITH_INSTANCE_NAME.name(), commonConfig.getInstanceName());
}
@ -432,6 +444,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
});
}
@Override
public Mono<User> verifyCurrentUserIsSuper() {
return sessionUserService.getCurrentUser()
.flatMap(user -> userService.findByEmail(user.getEmail()))
@ -443,6 +456,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
.switchIfEmpty(Mono.error(new AppsmithException(AppsmithError.UNAUTHORIZED_ACCESS)));
}
@Override
public Mono<Void> restart() {
return verifyCurrentUserIsSuper()
.flatMap(user -> {
@ -463,6 +477,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
});
}
@Override
public Mono<Boolean> sendTestEmail(TestEmailConfigRequestDTO requestDTO) {
return verifyCurrentUserIsSuper()
.flatMap(user -> {
@ -475,7 +490,7 @@ public class EnvManagerCEImpl implements EnvManagerCE {
props.put("mail.smtp.starttls.enable", "true");
props.put("mail.smtp.timeout", 7000); // 7 seconds
if(StringUtils.hasLength(requestDTO.getUsername())) {
if (StringUtils.hasLength(requestDTO.getUsername())) {
props.put("mail.smtp.auth", "true");
mailSender.setUsername(requestDTO.getUsername());
mailSender.setPassword(requestDTO.getPassword());
@ -493,19 +508,21 @@ public class EnvManagerCEImpl implements EnvManagerCE {
try {
mailSender.testConnection();
} catch (MessagingException e) {
throw new AppsmithException(AppsmithError.GENERIC_BAD_REQUEST, e.getMessage().trim());
return Mono.error(new AppsmithException(AppsmithError.GENERIC_BAD_REQUEST, e.getMessage().trim()));
}
try {
mailSender.send(message);
} catch (MailException mailException) {
log.error("failed to send test email", mailException);
throw new AppsmithException(AppsmithError.GENERIC_BAD_REQUEST, mailException.getMessage());
return Mono.error(new AppsmithException(AppsmithError.GENERIC_BAD_REQUEST, mailException.getMessage()));
}
return Mono.just(Boolean.TRUE);
});
}
@Override
public Mono<Void> download(ServerWebExchange exchange) {
return verifyCurrentUserIsSuper()
.flatMap(user -> {

View File

@ -11,9 +11,9 @@ import com.appsmith.server.helpers.FileUtils;
import com.appsmith.server.helpers.PolicyUtils;
import com.appsmith.server.notifications.EmailSender;
import com.appsmith.server.repositories.UserRepository;
import com.appsmith.server.services.AnalyticsService;
import com.appsmith.server.services.SessionUserService;
import com.appsmith.server.services.UserService;
import com.appsmith.server.services.AnalyticsService;
import lombok.extern.slf4j.Slf4j;
import org.junit.Before;
import org.junit.Test;
@ -81,36 +81,36 @@ public class EnvManagerTest {
@Test
public void simpleSample() {
final String content = "APPSMITH_MONGODB_URI=first value\nAPPSMITH_REDIS_URL=second value\n\nAPPSMITH_INSTANCE_NAME=third value";
final String content = "APPSMITH_MONGODB_URI='first value'\nAPPSMITH_REDIS_URL='second value'\n\nAPPSMITH_INSTANCE_NAME='third value'";
assertThat(envManager.transformEnvContent(
content,
Map.of("APPSMITH_MONGODB_URI", "new first value")
)).containsExactly(
"APPSMITH_MONGODB_URI=new first value",
"APPSMITH_REDIS_URL=second value",
"APPSMITH_MONGODB_URI='new first value'",
"APPSMITH_REDIS_URL='second value'",
"",
"APPSMITH_INSTANCE_NAME=third value"
"APPSMITH_INSTANCE_NAME='third value'"
);
assertThat(envManager.transformEnvContent(
content,
Map.of("APPSMITH_REDIS_URL", "new second value")
)).containsExactly(
"APPSMITH_MONGODB_URI=first value",
"APPSMITH_REDIS_URL=new second value",
"APPSMITH_MONGODB_URI='first value'",
"APPSMITH_REDIS_URL='new second value'",
"",
"APPSMITH_INSTANCE_NAME=third value"
"APPSMITH_INSTANCE_NAME='third value'"
);
assertThat(envManager.transformEnvContent(
content,
Map.of("APPSMITH_INSTANCE_NAME", "new third value")
)).containsExactly(
"APPSMITH_MONGODB_URI=first value",
"APPSMITH_REDIS_URL=second value",
"APPSMITH_MONGODB_URI='first value'",
"APPSMITH_REDIS_URL='second value'",
"",
"APPSMITH_INSTANCE_NAME=new third value"
"APPSMITH_INSTANCE_NAME='new third value'"
);
assertThat(envManager.transformEnvContent(
@ -120,10 +120,10 @@ public class EnvManagerTest {
"APPSMITH_INSTANCE_NAME", "new third value"
)
)).containsExactly(
"APPSMITH_MONGODB_URI=new first value",
"APPSMITH_REDIS_URL=second value",
"APPSMITH_MONGODB_URI='new first value'",
"APPSMITH_REDIS_URL='second value'",
"",
"APPSMITH_INSTANCE_NAME=new third value"
"APPSMITH_INSTANCE_NAME='new third value'"
);
}
@ -137,7 +137,7 @@ public class EnvManagerTest {
Map.of("APPSMITH_REDIS_URL", "new second value")
)).containsExactly(
"APPSMITH_MONGODB_URI=first value",
"APPSMITH_REDIS_URL=new second value",
"APPSMITH_REDIS_URL='new second value'",
"",
"APPSMITH_INSTANCE_NAME=third value"
);
@ -156,7 +156,7 @@ public class EnvManagerTest {
@Test
public void quotedValues() {
final String content = "APPSMITH_MONGODB_URI=first value\nAPPSMITH_REDIS_URL=\"quoted value\"\n\nAPPSMITH_INSTANCE_NAME=third value";
final String content = "APPSMITH_MONGODB_URI='first value'\nAPPSMITH_REDIS_URL=\"quoted value\"\n\nAPPSMITH_INSTANCE_NAME='third value'";
assertThat(envManager.transformEnvContent(
content,
@ -165,20 +165,33 @@ public class EnvManagerTest {
"APPSMITH_REDIS_URL", "new second value"
)
)).containsExactly(
"APPSMITH_MONGODB_URI=new first value",
"APPSMITH_REDIS_URL=\"new second value\"",
"APPSMITH_MONGODB_URI='new first value'",
"APPSMITH_REDIS_URL='new second value'",
"",
"APPSMITH_INSTANCE_NAME=third value"
"APPSMITH_INSTANCE_NAME='third value'"
);
assertThat(envManager.transformEnvContent(
content,
Map.of("APPSMITH_REDIS_URL", "")
)).containsExactly(
"APPSMITH_MONGODB_URI=first value",
"APPSMITH_REDIS_URL=\"\"",
"APPSMITH_MONGODB_URI='first value'",
"APPSMITH_REDIS_URL=",
"",
"APPSMITH_INSTANCE_NAME=third value"
"APPSMITH_INSTANCE_NAME='third value'"
);
assertThat(envManager.transformEnvContent(
content,
Map.of(
"APPSMITH_INSTANCE_NAME", "Sponge-bob's Instance",
"APPSMITH_REDIS_URL", "value with \" char in it"
)
)).containsExactly(
"APPSMITH_MONGODB_URI='first value'",
"APPSMITH_REDIS_URL='value with \" char in it'",
"",
"APPSMITH_INSTANCE_NAME='Sponge-bob'\"'\"'s Instance'"
);
}
@ -186,11 +199,11 @@ public class EnvManagerTest {
public void parseTest() {
assertThat(envManager.parseToMap(
"APPSMITH_MONGODB_URI=first value\nAPPSMITH_REDIS_URL=second value\n\nAPPSMITH_INSTANCE_NAME=third value"
"APPSMITH_MONGODB_URI='first value'\nAPPSMITH_REDIS_URL='second value'\n\nAPPSMITH_INSTANCE_NAME='third value'"
)).containsExactlyInAnyOrderEntriesOf(Map.of(
"APPSMITH_MONGODB_URI", "first value",
"APPSMITH_REDIS_URL", "second value",
"APPSMITH_INSTANCE_NAME", "third value"
"APPSMITH_MONGODB_URI", "'first value'",
"APPSMITH_REDIS_URL", "'second value'",
"APPSMITH_INSTANCE_NAME", "'third value'"
));
}
@ -199,7 +212,7 @@ public class EnvManagerTest {
public void parseEmptyValues() {
assertThat(envManager.parseToMap(
"APPSMITH_MONGODB_URI=first value\nAPPSMITH_REDIS_URL=\n\nAPPSMITH_INSTANCE_NAME=third value"
"APPSMITH_MONGODB_URI='first value'\nAPPSMITH_REDIS_URL=\n\nAPPSMITH_INSTANCE_NAME='third value'"
)).containsExactlyInAnyOrderEntriesOf(Map.of(
"APPSMITH_MONGODB_URI", "first value",
"APPSMITH_REDIS_URL", "",
@ -212,13 +225,19 @@ public class EnvManagerTest {
public void parseQuotedValues() {
assertThat(envManager.parseToMap(
"APPSMITH_MONGODB_URI=first value\nAPPSMITH_REDIS_URL=\"quoted value\"\n\nAPPSMITH_INSTANCE_NAME=third value"
"APPSMITH_MONGODB_URI=first\nAPPSMITH_REDIS_URL=\"quoted value\"\n\nAPPSMITH_INSTANCE_NAME='third value'"
)).containsExactlyInAnyOrderEntriesOf(Map.of(
"APPSMITH_MONGODB_URI", "first value",
"APPSMITH_MONGODB_URI", "first",
"APPSMITH_REDIS_URL", "quoted value",
"APPSMITH_INSTANCE_NAME", "third value"
));
assertThat(envManager.parseToMap(
"APPSMITH_INSTANCE_NAME=\"Sponge-bob's Instance\""
)).containsExactlyInAnyOrderEntriesOf(Map.of(
"APPSMITH_INSTANCE_NAME", "Sponge-bob's Instance"
));
}
@Test
@ -238,7 +257,7 @@ public class EnvManagerTest {
@Test
public void addNewVariable() {
final String content = "APPSMITH_MONGODB_URI=first value\nAPPSMITH_REDIS_URL=\"quoted value\"\n\nAPPSMITH_INSTANCE_NAME=third value";
final String content = "APPSMITH_MONGODB_URI='first value'\nAPPSMITH_REDIS_URL='quoted value'\n\nAPPSMITH_INSTANCE_NAME='third value'";
assertThat(envManager.transformEnvContent(
content,
@ -247,10 +266,10 @@ public class EnvManagerTest {
"APPSMITH_DISABLE_TELEMETRY", "false"
)
)).containsExactly(
"APPSMITH_MONGODB_URI=new first value",
"APPSMITH_REDIS_URL=\"quoted value\"",
"APPSMITH_MONGODB_URI='new first value'",
"APPSMITH_REDIS_URL='quoted value'",
"",
"APPSMITH_INSTANCE_NAME=third value",
"APPSMITH_INSTANCE_NAME='third value'",
"APPSMITH_DISABLE_TELEMETRY=false"
);
}