Merge pull request #248 from manaflow-ai/feat-socket-override-boundary
Ignore ambient CMUX_SOCKET_PATH in stable/nightly builds
This commit is contained in:
commit
b600d1c738
3 changed files with 158 additions and 7 deletions
|
|
@ -38,6 +38,7 @@ enum SocketControlMode: String, CaseIterable, Identifiable {
|
|||
struct SocketControlSettings {
|
||||
static let appStorageKey = "socketControlMode"
|
||||
static let legacyEnabledKey = "socketControlEnabled"
|
||||
static let allowSocketPathOverrideKey = "CMUX_ALLOW_SOCKET_OVERRIDE"
|
||||
|
||||
/// Map old persisted rawValues to the new enum.
|
||||
static func migrateMode(_ raw: String) -> SocketControlMode {
|
||||
|
|
@ -55,15 +56,83 @@ struct SocketControlSettings {
|
|||
return .cmuxOnly
|
||||
}
|
||||
|
||||
static func socketPath() -> String {
|
||||
if let override = ProcessInfo.processInfo.environment["CMUX_SOCKET_PATH"], !override.isEmpty {
|
||||
private static var isDebugBuild: Bool {
|
||||
#if DEBUG
|
||||
true
|
||||
#else
|
||||
false
|
||||
#endif
|
||||
}
|
||||
|
||||
static func socketPath(
|
||||
environment: [String: String] = ProcessInfo.processInfo.environment,
|
||||
bundleIdentifier: String? = Bundle.main.bundleIdentifier,
|
||||
isDebugBuild: Bool = SocketControlSettings.isDebugBuild
|
||||
) -> String {
|
||||
let fallback = defaultSocketPath(bundleIdentifier: bundleIdentifier, isDebugBuild: isDebugBuild)
|
||||
|
||||
guard let override = environment["CMUX_SOCKET_PATH"], !override.isEmpty else {
|
||||
return fallback
|
||||
}
|
||||
|
||||
if shouldHonorSocketPathOverride(
|
||||
environment: environment,
|
||||
bundleIdentifier: bundleIdentifier,
|
||||
isDebugBuild: isDebugBuild
|
||||
) {
|
||||
return override
|
||||
}
|
||||
#if DEBUG
|
||||
return "/tmp/cmux-debug.sock"
|
||||
#else
|
||||
|
||||
return fallback
|
||||
}
|
||||
|
||||
static func defaultSocketPath(bundleIdentifier: String?, isDebugBuild: Bool) -> String {
|
||||
if bundleIdentifier == "com.cmuxterm.app.nightly" {
|
||||
return "/tmp/cmux-nightly.sock"
|
||||
}
|
||||
if isDebugLikeBundleIdentifier(bundleIdentifier) || isDebugBuild {
|
||||
return "/tmp/cmux-debug.sock"
|
||||
}
|
||||
if isStagingBundleIdentifier(bundleIdentifier) {
|
||||
return "/tmp/cmux-staging.sock"
|
||||
}
|
||||
return "/tmp/cmux.sock"
|
||||
#endif
|
||||
}
|
||||
|
||||
static func shouldHonorSocketPathOverride(
|
||||
environment: [String: String],
|
||||
bundleIdentifier: String?,
|
||||
isDebugBuild: Bool
|
||||
) -> Bool {
|
||||
if isTruthy(environment[allowSocketPathOverrideKey]) {
|
||||
return true
|
||||
}
|
||||
if isDebugLikeBundleIdentifier(bundleIdentifier) || isStagingBundleIdentifier(bundleIdentifier) {
|
||||
return true
|
||||
}
|
||||
return isDebugBuild
|
||||
}
|
||||
|
||||
static func isDebugLikeBundleIdentifier(_ bundleIdentifier: String?) -> Bool {
|
||||
guard let bundleIdentifier else { return false }
|
||||
return bundleIdentifier == "com.cmuxterm.app.debug"
|
||||
|| bundleIdentifier.hasPrefix("com.cmuxterm.app.debug.")
|
||||
}
|
||||
|
||||
static func isStagingBundleIdentifier(_ bundleIdentifier: String?) -> Bool {
|
||||
guard let bundleIdentifier else { return false }
|
||||
return bundleIdentifier == "com.cmuxterm.app.staging"
|
||||
|| bundleIdentifier.hasPrefix("com.cmuxterm.app.staging.")
|
||||
}
|
||||
|
||||
static func isTruthy(_ raw: String?) -> Bool {
|
||||
guard let raw else { return false }
|
||||
switch raw.trimmingCharacters(in: .whitespacesAndNewlines).lowercased() {
|
||||
case "1", "true", "yes", "on":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
static func envOverrideEnabled() -> Bool? {
|
||||
|
|
|
|||
|
|
@ -2540,7 +2540,7 @@ struct SettingsView: View {
|
|||
SettingsCardDivider()
|
||||
|
||||
SettingsCardNote("Controls access to the local Unix socket for programmatic control. In \"cmux processes only\" mode, only processes spawned inside cmux terminals can connect.")
|
||||
SettingsCardNote("Overrides: CMUX_SOCKET_ENABLE, CMUX_SOCKET_MODE, and CMUX_SOCKET_PATH.")
|
||||
SettingsCardNote("Overrides: CMUX_SOCKET_ENABLE, CMUX_SOCKET_MODE, and CMUX_SOCKET_PATH (set CMUX_ALLOW_SOCKET_OVERRIDE=1 for stable/nightly builds).")
|
||||
}
|
||||
|
||||
SettingsCard {
|
||||
|
|
|
|||
|
|
@ -316,3 +316,85 @@ final class TabManagerNotificationOrderingSourceTests: XCTestCase {
|
|||
return URL(fileURLWithPath: FileManager.default.currentDirectoryPath)
|
||||
}
|
||||
}
|
||||
|
||||
final class SocketControlSettingsTests: XCTestCase {
|
||||
func testStableReleaseIgnoresAmbientSocketOverrideByDefault() {
|
||||
let path = SocketControlSettings.socketPath(
|
||||
environment: [
|
||||
"CMUX_SOCKET_PATH": "/tmp/cmux-debug-issue-153-tmux-compat.sock",
|
||||
],
|
||||
bundleIdentifier: "com.cmuxterm.app",
|
||||
isDebugBuild: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(path, "/tmp/cmux.sock")
|
||||
}
|
||||
|
||||
func testNightlyReleaseUsesDedicatedDefaultAndIgnoresAmbientSocketOverride() {
|
||||
let path = SocketControlSettings.socketPath(
|
||||
environment: [
|
||||
"CMUX_SOCKET_PATH": "/tmp/cmux-debug-issue-153-tmux-compat.sock",
|
||||
],
|
||||
bundleIdentifier: "com.cmuxterm.app.nightly",
|
||||
isDebugBuild: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(path, "/tmp/cmux-nightly.sock")
|
||||
}
|
||||
|
||||
func testDebugBundleHonorsSocketOverrideWithoutOptInFlag() {
|
||||
let path = SocketControlSettings.socketPath(
|
||||
environment: [
|
||||
"CMUX_SOCKET_PATH": "/tmp/cmux-debug-my-tag.sock",
|
||||
],
|
||||
bundleIdentifier: "com.cmuxterm.app.debug.my-tag",
|
||||
isDebugBuild: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(path, "/tmp/cmux-debug-my-tag.sock")
|
||||
}
|
||||
|
||||
func testStagingBundleHonorsSocketOverrideWithoutOptInFlag() {
|
||||
let path = SocketControlSettings.socketPath(
|
||||
environment: [
|
||||
"CMUX_SOCKET_PATH": "/tmp/cmux-staging-my-tag.sock",
|
||||
],
|
||||
bundleIdentifier: "com.cmuxterm.app.staging.my-tag",
|
||||
isDebugBuild: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(path, "/tmp/cmux-staging-my-tag.sock")
|
||||
}
|
||||
|
||||
func testStableReleaseCanOptInToSocketOverride() {
|
||||
let path = SocketControlSettings.socketPath(
|
||||
environment: [
|
||||
"CMUX_SOCKET_PATH": "/tmp/cmux-debug-forced.sock",
|
||||
"CMUX_ALLOW_SOCKET_OVERRIDE": "1",
|
||||
],
|
||||
bundleIdentifier: "com.cmuxterm.app",
|
||||
isDebugBuild: false
|
||||
)
|
||||
|
||||
XCTAssertEqual(path, "/tmp/cmux-debug-forced.sock")
|
||||
}
|
||||
|
||||
func testDefaultSocketPathByChannel() {
|
||||
XCTAssertEqual(
|
||||
SocketControlSettings.defaultSocketPath(bundleIdentifier: "com.cmuxterm.app", isDebugBuild: false),
|
||||
"/tmp/cmux.sock"
|
||||
)
|
||||
XCTAssertEqual(
|
||||
SocketControlSettings.defaultSocketPath(bundleIdentifier: "com.cmuxterm.app.nightly", isDebugBuild: false),
|
||||
"/tmp/cmux-nightly.sock"
|
||||
)
|
||||
XCTAssertEqual(
|
||||
SocketControlSettings.defaultSocketPath(bundleIdentifier: "com.cmuxterm.app.debug.tag", isDebugBuild: false),
|
||||
"/tmp/cmux-debug.sock"
|
||||
)
|
||||
XCTAssertEqual(
|
||||
SocketControlSettings.defaultSocketPath(bundleIdentifier: "com.cmuxterm.app.staging.tag", isDebugBuild: false),
|
||||
"/tmp/cmux-staging.sock"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue