Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Foundation
///
/// Decided by the composition root (development for DEBUG builds, production
/// otherwise) and injected; this package never reads build flags itself.
public enum CMUXAuthEnvironment: Sendable {
public enum CMUXAuthEnvironment: Equatable, Sendable {
/// The development Stack project (DEBUG builds, local web stack).
case development
/// The production Stack project (Release/nightly builds).
Expand Down
4 changes: 4 additions & 0 deletions ios/Config/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@
<string>$(CMUX_DEV_TAG)</string>
<key>CMUXGitSHA</key>
<string>$(CMUX_GIT_SHA)</string>
<key>CMUXAuthEnvironment</key>
<string>$(CMUX_AUTH_ENVIRONMENT)</string>
<key>ApiBaseURL</key>
<string>$(CMUX_API_BASE_URL)</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
Expand Down
2 changes: 2 additions & 0 deletions ios/Config/Shared.xcconfig
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ CURRENT_PROJECT_VERSION = 1
// CMUXGitSHA / CMUXDevTag Info.plist keys that AppVersionInfo reads.
CMUX_GIT_SHA =
CMUX_DEV_TAG =
CMUX_AUTH_ENVIRONMENT = production
CMUX_API_BASE_URL =

// ==========================================
// Platform Configuration
Expand Down
67 changes: 64 additions & 3 deletions ios/cmuxPackage/Sources/cmuxFeature/MobileAuthComposition.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,13 @@ public struct MobileAuthComposition {
) {
self.reachability = reachability

let isDevelopment = Self.isDevelopmentBuild
let overrides = Self.localConfigStringOverrides(in: bundle)
let overrides = Self.configurationStringOverrides(in: bundle)
let authEnvironment = Self.resolvedAuthEnvironment(
isDevelopmentBuild: Self.isDevelopmentBuild,
overrides: overrides
)
let resolvedConfig = AuthConfig(
environment: isDevelopment ? .development : .production,
environment: authEnvironment,
overrides: overrides
)
self.config = resolvedConfig
Expand Down Expand Up @@ -135,6 +138,40 @@ public struct MobileAuthComposition {
#endif
}

/// Resolve which Stack project this mobile build should use.
///
/// iOS DEBUG builds default to production auth so a normal tagged iPhone
/// build can pair with a normal tagged Mac dev build. Local/development
/// auth remains available through `CMUXAuthEnvironment=development` in the
/// bundle Info.plist or LocalConfig.plist.
static func resolvedAuthEnvironment(
isDevelopmentBuild: Bool,
overrides: [String: String]
) -> CMUXAuthEnvironment {
if let raw = overrides["CMUXAuthEnvironment"]?.trimmingCharacters(in: .whitespacesAndNewlines),
!raw.isEmpty {
switch raw.lowercased() {
case "development", "dev", "local":
return .development
case "production", "prod":
return .production
default:
break
}
}
return .production
}

/// Parse optional string overrides from bundled `LocalConfig.plist` and
/// Info.plist build settings.
private static func configurationStringOverrides(in bundle: Bundle) -> [String: String] {
var overrides = localConfigStringOverrides(in: bundle)
for (key, value) in infoPlistStringOverrides(in: bundle) {
overrides[key] = value
}
return overrides
}

/// Parse optional string overrides from a bundled `LocalConfig.plist`.
/// Stored as `[String: String]` so the result is Sendable.
private static func localConfigStringOverrides(in bundle: Bundle) -> [String: String] {
Expand All @@ -153,4 +190,28 @@ public struct MobileAuthComposition {
}
return overrides
}

/// Parse auth override build settings baked into the app Info.plist.
///
/// Empty and unexpanded values are ignored so direct Xcode builds with the
/// shared xcconfig defaults behave predictably.
private static func infoPlistStringOverrides(in bundle: Bundle) -> [String: String] {
guard let info = bundle.infoDictionary else { return [:] }
let keys = [
"CMUXAuthEnvironment",
"ApiBaseURL",
"STACK_PROJECT_ID_DEV",
"STACK_PROJECT_ID_PROD",
"STACK_PUBLISHABLE_CLIENT_KEY_DEV",
"STACK_PUBLISHABLE_CLIENT_KEY_PROD"
]
var overrides: [String: String] = [:]
for key in keys {
guard let stringValue = info[key] as? String else { continue }
let trimmed = stringValue.trimmingCharacters(in: .whitespacesAndNewlines)
guard !trimmed.isEmpty, !trimmed.contains("$(") else { continue }
overrides[key] = trimmed
}
return overrides
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import CMUXAuthCore
import Testing
@testable import cmuxFeature

@Test func mobileAuthCompositionDefaultsDevBuildsToProductionAuth() {
#expect(MobileAuthComposition.resolvedAuthEnvironment(
isDevelopmentBuild: true,
overrides: [:]
) == .production)
}

@Test func mobileAuthCompositionAllowsLocalDevAuthOverride() {
#expect(MobileAuthComposition.resolvedAuthEnvironment(
isDevelopmentBuild: true,
overrides: ["CMUXAuthEnvironment": "local"]
) == .development)
}
16 changes: 16 additions & 0 deletions ios/scripts/reload.sh
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,20 @@ DISPLAY_NAME="cmux DEV $TAG"
BUNDLE_ID="dev.cmux.ios.$TAG_SLUG"
DERIVED_DATA="$HOME/Library/Developer/Xcode/DerivedData/cmux-ios-$TAG_SLUG"
DESTINATION="platform=iOS Simulator,name=$SIMULATOR_NAME"
CMUX_DEV_AUTH_ORIGIN_MODE="${CMUX_DEV_AUTH_ORIGIN:-auto}"
CMUX_AUTH_ENVIRONMENT="production"
case "$CMUX_DEV_AUTH_ORIGIN_MODE" in
local|development|dev)
CMUX_AUTH_ENVIRONMENT="development"
;;
auto|production|prod|"")
CMUX_AUTH_ENVIRONMENT="production"
;;
*)
echo "error: CMUX_DEV_AUTH_ORIGIN must be auto, local, or production (got '$CMUX_DEV_AUTH_ORIGIN_MODE')" >&2
exit 2
;;
esac

# Dev-build identity baked into the app's Info.plist (CMUXGitSHA / CMUXDevTag),
# surfaced in-app under Settings > About so a dogfood build is tellable. The
Expand Down Expand Up @@ -408,6 +422,7 @@ reload_simulator() {
PRODUCT_DISPLAY_NAME="$DISPLAY_NAME" \
CMUX_GIT_SHA="$GIT_SHA" \
CMUX_DEV_TAG="$TAG" \
CMUX_AUTH_ENVIRONMENT="$CMUX_AUTH_ENVIRONMENT" \
EXCLUDED_SOURCE_FILE_NAMES=Info.plist \
CODE_SIGNING_ALLOWED=NO \
SWIFT_OPTIMIZATION_LEVEL=-O \
Expand Down Expand Up @@ -509,6 +524,7 @@ reload_device() {
PRODUCT_DISPLAY_NAME="$DISPLAY_NAME"
CMUX_GIT_SHA="$GIT_SHA"
CMUX_DEV_TAG="$TAG"
CMUX_AUTH_ENVIRONMENT="$CMUX_AUTH_ENVIRONMENT"
EXCLUDED_SOURCE_FILE_NAMES=Info.plist
CODE_SIGNING_ALLOWED=YES
CODE_SIGN_STYLE=Automatic
Expand Down
Loading