deploy: render launchctl templates safely
This commit is contained in:
@@ -5,6 +5,7 @@ import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
|
||||
import org.springframework.core.io.FileSystemResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.List;
|
||||
@@ -138,6 +139,7 @@ class PortainerComposeResourceLimitsTest {
|
||||
String readme = Files.readString(launchctl.resolve("README.md"));
|
||||
|
||||
assertThat(readme)
|
||||
.contains("python3 deploy/local/launchctl/render.py")
|
||||
.contains("gb32960 jt808 yutong-mqtt vehicle-history vehicle-analytics")
|
||||
.contains("mkdir -p /tmp/lingniu-gb32960-live /tmp/lingniu-jt808-live /tmp/lingniu-yutong-mqtt-live /tmp/lingniu-vehicle-history-live /tmp/lingniu-vehicle-analytics-live")
|
||||
.contains("launchctl bootstrap \"gui/$(id -u)\" \"$HOME/Library/LaunchAgents/com.lingniu.yutong-mqtt.plist\"")
|
||||
@@ -147,6 +149,7 @@ class PortainerComposeResourceLimitsTest {
|
||||
.contains("launchctl list | rg 'com.lingniu.(gb32960|jt808|yutong-mqtt|vehicle-history|vehicle-analytics)'")
|
||||
.contains("Yutong MQTT ingest: `http://127.0.0.1:20500/swagger-ui/index.html`")
|
||||
.contains("Analytics metrics: `http://127.0.0.1:20300/swagger-ui/index.html`")
|
||||
.doesNotContain("sed \\")
|
||||
.doesNotContain("三个服务");
|
||||
|
||||
assertLaunchctlTemplate(launchctl, "gb32960", "gb32960-ingest-app", "20100");
|
||||
@@ -156,6 +159,62 @@ class PortainerComposeResourceLimitsTest {
|
||||
assertLaunchctlTemplate(launchctl, "vehicle-analytics", "vehicle-analytics-app", "20300");
|
||||
}
|
||||
|
||||
@Test
|
||||
void localLaunchctlRendererPreservesSpecialCharactersSafely() throws Exception {
|
||||
Path root = repositoryRoot();
|
||||
Path launchctl = root.resolve("deploy/local/launchctl");
|
||||
Path home = Files.createTempDirectory("lingniu-launchctl-home");
|
||||
|
||||
ProcessBuilder processBuilder = new ProcessBuilder(
|
||||
"python3",
|
||||
launchctl.resolve("render.py").toString());
|
||||
processBuilder.directory(root.toFile());
|
||||
processBuilder.environment().put("HOME", home.toString());
|
||||
processBuilder.environment().put("PROJECT_ROOT", "/tmp/lingniu project & live");
|
||||
processBuilder.environment().put("JAVA_BIN", "/usr/bin/java");
|
||||
processBuilder.environment().put("INGEST_ARCHIVE_PATH", "/tmp/archive&live__v1");
|
||||
processBuilder.environment().put("TDENGINE_JDBC_URL", "jdbc:TAOS-WS://host:6041/vehicle_ts");
|
||||
processBuilder.environment().put("TDENGINE_USERNAME", "root");
|
||||
processBuilder.environment().put("TDENGINE_PASSWORD", "td&engine#pwd");
|
||||
processBuilder.environment().put("VEHICLE_IDENTITY_MYSQL_JDBC_URL",
|
||||
"jdbc:mysql://host:3306/vehicle_ingest?useSSL=false&serverTimezone=Asia/Shanghai");
|
||||
processBuilder.environment().put("VEHICLE_IDENTITY_MYSQL_USERNAME", "lingniu_vehicle");
|
||||
processBuilder.environment().put("VEHICLE_IDENTITY_MYSQL_PASSWORD", "id&pwd#1");
|
||||
processBuilder.environment().put("MYSQL_JDBC_URL",
|
||||
"jdbc:mysql://host:3306/vehicle_stat?useSSL=false&serverTimezone=Asia/Shanghai");
|
||||
processBuilder.environment().put("MYSQL_USERNAME", "stat_user");
|
||||
processBuilder.environment().put("MYSQL_PASSWORD", "stat&pwd#2");
|
||||
processBuilder.environment().put("YUTONG_MQTT_ENABLED", "true");
|
||||
processBuilder.environment().put("YUTONG_MQTT_URI", "ssl://mqtt.example.com:8883");
|
||||
processBuilder.environment().put("YUTONG_MQTT_TOPIC", "#");
|
||||
processBuilder.environment().put("YUTONG_MQTT_USERNAME", "mqtt_user");
|
||||
processBuilder.environment().put("YUTONG_MQTT_PASSWORD", "mqtt&pwd#3");
|
||||
|
||||
Process process = processBuilder.start();
|
||||
String output = new String(process.getInputStream().readAllBytes(), StandardCharsets.UTF_8)
|
||||
+ new String(process.getErrorStream().readAllBytes(), StandardCharsets.UTF_8);
|
||||
|
||||
assertThat(process.waitFor()).as(output).isZero();
|
||||
|
||||
Path launchAgents = home.resolve("Library/LaunchAgents");
|
||||
String mqtt = Files.readString(launchAgents.resolve("com.lingniu.yutong-mqtt.plist"));
|
||||
String analytics = Files.readString(launchAgents.resolve("com.lingniu.vehicle-analytics.plist"));
|
||||
|
||||
assertThat(mqtt)
|
||||
.contains("<string>#</string>")
|
||||
.contains("<string>mqtt&pwd#3</string>")
|
||||
.contains("<string>/tmp/archive&live__v1</string>")
|
||||
.doesNotContain("__YUTONG_MQTT_TOPIC__")
|
||||
.doesNotContain("__YUTONG_MQTT_PASSWORD__");
|
||||
assertThat(analytics)
|
||||
.contains("<string>stat&pwd#2</string>")
|
||||
.doesNotContain("__MYSQL_PASSWORD__");
|
||||
assertThat(Files.list(launchAgents)
|
||||
.filter(path -> path.getFileName().toString().endsWith(".plist"))
|
||||
.count())
|
||||
.isEqualTo(5);
|
||||
}
|
||||
|
||||
@Test
|
||||
void tdengineVerificationRunbookChecksLivenessAndReadinessForManagedApps() throws IOException {
|
||||
String runbook = Files.readString(repositoryRoot()
|
||||
|
||||
Reference in New Issue
Block a user