fix: preserve the runtime PATH when overriding guest binaries

This commit is contained in:
qinsiyuan committed 2026-10-30 18:35:06 +08:00
1 parent f69e2d0171
commit ab43524bbc
5 files changed
+34 -3

No files matched your search

@@ -18,7 +18,6 @@ object AgentEnv {
private const val TAG = "AgentEnv"
private const val FILE = "agent-env.json"
private const val GUEST_BIN = "/opt/droiddeck-agent/bin"
private const val BASE_PATH = "/usr/local/bin:/usr/bin:/bin"
private val NAME = Regex("[A-Za-z0-9._-]{1,64}")
private val KEY = Regex("[A-Za-z_][A-Za-z0-9_]*")
private val lock = Any()
@@ -160,7 +159,7 @@ object AgentEnv {
}
private fun pathOf(lines: List<String>) =
lines.lastOrNull { it.startsWith("PATH=") }?.substringAfter('=')?.takeIf { it.isNotBlank() } ?: BASE_PATH
lines.lastOrNull { it.startsWith("PATH=") }?.substringAfter('=')?.takeIf { it.isNotBlank() } ?: LinuxRuntime.GUEST_PATH
private fun bin(context: Context): File {
val root = LinuxRuntime.rootDir(context).canonicalFile.toPath()
@@ -26,6 +26,7 @@ public final class LinuxRuntime {
public static final String EXTRA_LINUX_MODE = "linux_mode";
private static final String KGSL_DEVICE = "/dev/kgsl-3d0";
public static final String GUEST_RUNTIME_DIR = "/run/droiddeck";
public static final String GUEST_PATH = "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games";
private static final String SYSTEM_FONTS = "/system/fonts";
private static final String GUEST_SYSTEM_FONTS = "/usr/local/share/fonts/android";
public static final String DEBUG_LOG_DIR = "DroidDeck";
@@ -753,7 +753,7 @@ class SessionService : Service() {
guest.add("DROIDDECK_BWRAP_SOCKET=" + com.droiddeck.launcher.runtime.BwrapSpawner.socket(this))
guest.add("HOME=/root")
guest.add("USER=root")
guest.add("PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games")
guest.add("PATH=" + LinuxRuntime.GUEST_PATH)
guest.add("TERM=xterm-256color")
guest.add("LANG=C.UTF-8")
guest.add("BL_STEAM_LANGUAGE=" + SteamLanguage.forLocale(
@@ -181,6 +181,32 @@ class AgentSecurityTest {
assertEquals(listOf("TEST=old", "STICKY=1"), AgentEnv.beginSession(context))
}
@Test fun binaryOverridesPreserveTheRuntimeSearchPathForOneSession() {
AgentAccess.setCommandsEnabled(context, true)
File(AgentEnv.inbox(context).apply { mkdirs() }, "gamescope").writeText("test binary")
AgentEnv.override(context, "gamescope")
val path = AgentEnv.beginSession(context).single { it.startsWith("PATH=") }.substringAfter('=')
assertEquals("/opt/droiddeck-agent/bin:" + LinuxRuntime.GUEST_PATH, path)
assertTrue(path.split(':').contains("/usr/games"))
assertTrue(path.split(':').contains("/usr/sbin"))
AgentEnv.endSession(context)
assertTrue(AgentEnv.beginSession(context).none { it.startsWith("PATH=") })
}
@Test fun binaryOverridesKeepExplicitPathsAndPendingPathPrecedence() {
AgentAccess.setCommandsEnabled(context, true)
AgentEnv.set(context, listOf("PATH=/custom/persistent"), true)
AgentEnv.set(context, listOf("PATH=/custom/next:/usr/games"), false)
File(AgentEnv.inbox(context).apply { mkdirs() }, "gamescope").writeText("test binary")
AgentEnv.override(context, "gamescope")
assertEquals("PATH=/opt/droiddeck-agent/bin:/custom/next:/usr/games", AgentEnv.beginSession(context).last())
AgentEnv.endSession(context)
assertEquals(listOf("PATH=/custom/persistent"), AgentEnv.beginSession(context))
}
@Test fun fastPathLibraryIsValidatedAndSelectedForOneSession() {
AgentAccess.setCommandsEnabled(context, true)
val source = File(AgentEnv.inbox(context).apply { mkdirs() }, "libblfastpath.so")
+5
View File
@@ -39,6 +39,11 @@ Disabling the toggle clears queued and persistent agent environment settings and
overrides. Disabled settings cannot apply at the next session start. Already running commands and
effects already applied to a session are not undone; stop and restart that session to discard them.
Program overrides prepend their directory to the normal session PATH, including `/usr/games`
where Ubuntu installs `gamescopereaper`. An explicit `PATH=...` environment entry replaces that
default. Keep the runtime directories when setting a custom PATH; if an old persistent override
hides runtime tools, inspect `env list`, clear or correct that entry, and restart the session.
Authorized command execution runs inside the runtime containing Steam's saved login. CDP evaluates
JavaScript in the authenticated Steam client, and preferences can contain private values. These
capabilities remain unrestricted when enabled: the toggle is an explicit opt-in, not credential