Skip to content

Commit 35a821f

Browse files
authored
fix: vminitd incorrectly overwrites custom HOME environment variable (#136)
## Summary The vminitd service was using `process.env.contains("HOME")` which checks for exact string match rather than environment variables starting with "HOME=". Since environment variables are stored as `"KEY=value"` strings, the condition was always false, causing vminitd to always override custom HOME values even when explicitly provided by the client. ## Changes - Updates the logic in `vminitd/Sources/vminitd/Server+GRPC.swift` to use `contains(where: { $0.hasPrefix("HOME=") })` to properly detect existing HOME environment variables - Adds regression test `testProcessCustomHomeEnvvar()` to verify that custom HOME environment variables are preserved when provided by the client ## Testing The fix has been tested with the new integration test that: - Sets a custom HOME environment variable (`HOME=/tmp/custom/home`) - Runs a shell command that outputs the HOME variable on the container runtime - Verifies the custom HOME value is preserved and not overwritten with the default ## Environment - macOS: 26.0 (25A5279m) - Hardware: M4 Pro - Xcode: 26 beta - Swift: 6.2-dev Fixes #135
1 parent 445450d commit 35a821f

File tree

4 files changed

+39
-4
lines changed

4 files changed

+39
-4
lines changed

CONTRIBUTORS.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ John Logan (jglogan)
1616
Kathryn Baldauf (katiewasnothere)
1717
Madhu Venugopal (mavenugo)
1818
Michael Crosby (crosbymichael)
19+
Nandha Reddy (nandsha)
1920
Sidhartha Mani (wlan0)
2021
Tanweer Noor (tanweernoor)
2122
Ximena Perez Diaz (ximenanperez)

Sources/Integration/ProcessTests.swift

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ extension IntegrationSuite {
9595

9696
guard String(data: buffer.data, encoding: .utf8) == "hi\n" else {
9797
throw IntegrationError.assert(
98-
msg: "process should have returned on stdout 'hi' != '\(String(data: buffer.data, encoding: .utf8)!)")
98+
msg: "process should have returned on stdout 'hi' != '\(String(data: buffer.data, encoding: .utf8)!)'")
9999
}
100100
} catch {
101101
try? await container.stop()
@@ -257,7 +257,7 @@ extension IntegrationSuite {
257257

258258
guard String(data: buffer.data, encoding: .utf8) == "\(expected)\n" else {
259259
throw IntegrationError.assert(
260-
msg: "process should have returned on stdout '\(expected)' != '\(String(data: buffer.data, encoding: .utf8)!)")
260+
msg: "process should have returned on stdout '\(expected)' != '\(String(data: buffer.data, encoding: .utf8)!)'")
261261
}
262262
}
263263

@@ -299,6 +299,39 @@ extension IntegrationSuite {
299299
}
300300
}
301301

302+
func testProcessCustomHomeEnvvar() async throws {
303+
let id = "test-process-custom-home-envvar"
304+
305+
let bs = try await bootstrap()
306+
let container = LinuxContainer(id, rootfs: bs.rootfs, vmm: bs.vmm)
307+
308+
let customHomeEnvvar = "HOME=/tmp/custom/home"
309+
container.environment = [customHomeEnvvar]
310+
container.arguments = ["sh", "-c", "echo HOME=$HOME"]
311+
container.user = .init(uid: 0, gid: 0)
312+
313+
let buffer = BufferWriter()
314+
container.stdout = buffer
315+
316+
try await container.create()
317+
try await container.start()
318+
319+
let status = try await container.wait()
320+
try await container.stop()
321+
322+
guard status == 0 else {
323+
throw IntegrationError.assert(msg: "process status \(status) != 0")
324+
}
325+
326+
guard let output = String(data: buffer.data, encoding: .utf8) else {
327+
throw IntegrationError.assert(msg: "failed to convert stdout to UTF8")
328+
}
329+
330+
guard output.contains(customHomeEnvvar) else {
331+
throw IntegrationError.assert(msg: "process should have preserved custom HOME environment variable, expected \(customHomeEnvvar), got: \(output)")
332+
}
333+
}
334+
302335
func testHostname() async throws {
303336
let id = "test-container-hostname"
304337

@@ -327,7 +360,7 @@ extension IntegrationSuite {
327360

328361
guard String(data: buffer.data, encoding: .utf8) == "\(expected)\n" else {
329362
throw IntegrationError.assert(
330-
msg: "process should have returned on stdout '\(expected)' != '\(String(data: buffer.data, encoding: .utf8)!)")
363+
msg: "process should have returned on stdout '\(expected)' != '\(String(data: buffer.data, encoding: .utf8)!)'")
331364
}
332365
}
333366
}

Sources/Integration/Suite.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,7 @@ struct IntegrationSuite: AsyncParsableCommand {
199199
"process echo hi": testProcessEchoHi,
200200
"process user": testProcessUser,
201201
"process home envvar": testProcessHomeEnvvar,
202+
"process custom home envvar": testProcessCustomHomeEnvvar,
202203
"multiple concurrent processes": testMultipleConcurrentProcesses,
203204
"multiple concurrent processes with output stress": testMultipleConcurrentProcessesOutputStress,
204205
"container hostname": testHostname,

vminitd/Sources/vminitd/Server+GRPC.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -846,7 +846,7 @@ extension Initd {
846846
process.user.uid = parsedUser.uid
847847
process.user.gid = parsedUser.gid
848848
process.user.additionalGids = parsedUser.sgids
849-
if !process.env.contains("HOME") {
849+
if !process.env.contains(where: { $0.hasPrefix("HOME=") }) {
850850
process.env.append("HOME=\(parsedUser.home)")
851851
}
852852

0 commit comments

Comments
 (0)