commit 44ea2b2d22d3bf1b4a982adbb796fef10a68464f
parent 70fb20459654f4d687f5227ac730718395dc3a4c
Author: triesap <tyson@radroots.org>
Date: Thu, 18 Jun 2026 13:59:05 -0700
security: prove identity policy config
- expose a debug-only identity policy probe
- map configured custody policy to secure store policy values
- keep production user-presence policy on compiled config
- include the generated app project source reference
Diffstat:
4 files changed, 50 insertions(+), 0 deletions(-)
diff --git a/Radroots.xcodeproj/project.pbxproj b/Radroots.xcodeproj/project.pbxproj
@@ -27,6 +27,7 @@
4B44B723FF06ECC363A486BA /* TradeListingDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26BAE32CD1D46033DDA1A5BB /* TradeListingDetailView.swift */; };
505A5731ACDBBB0296134340 /* TradeListingCreateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 947ADA6D32E42ED2B40A5351 /* TradeListingCreateView.swift */; };
5AECD474FB2F91855BDD79C0 /* PostFeedViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F21554DA87EEC1E5C5F38365 /* PostFeedViewModel.swift */; };
+ 5FB3E3E450EE7DFF30F3A005 /* FieldIdentityPolicyUITestProbe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E150C6C18B2A06F2F3227C6 /* FieldIdentityPolicyUITestProbe.swift */; };
657BEA5AAFF129E10177FE63 /* Nostr.swift in Sources */ = {isa = PBXBuildFile; fileRef = 63189EB90A86A9929BECD9ED /* Nostr.swift */; };
6E15D30653861F26AC45B501 /* FieldLocalState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EB0A2CFCBBFA9D204C6992B /* FieldLocalState.swift */; };
7C8DD424F3E3E0AB1B133863 /* RadrootsKitBindings.swift in Sources */ = {isa = PBXBuildFile; fileRef = DC881872F750120A184F45E6 /* RadrootsKitBindings.swift */; };
@@ -81,6 +82,7 @@
466BFA2F60BE3113EDD1BA3B /* TradeOrderRequestView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TradeOrderRequestView.swift; sourceTree = "<group>"; };
491D57E540BAB04F24619737 /* FieldFileAccessUITestProbe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldFileAccessUITestProbe.swift; sourceTree = "<group>"; };
4BC4B7D0BB4C6D8E4B0AA4AD /* radroots.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = radroots.xcconfig; sourceTree = "<group>"; };
+ 4E150C6C18B2A06F2F3227C6 /* FieldIdentityPolicyUITestProbe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldIdentityPolicyUITestProbe.swift; sourceTree = "<group>"; };
54EE5A34FE2086899F5B7568 /* radroots.git.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = radroots.git.xcconfig; sourceTree = "<group>"; };
59AC0543EF8335D691D56BD3 /* FieldBackgroundExecutionUITestProbe.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FieldBackgroundExecutionUITestProbe.swift; sourceTree = "<group>"; };
63189EB90A86A9929BECD9ED /* Nostr.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Nostr.swift; sourceTree = "<group>"; };
@@ -209,6 +211,7 @@
EF05B944D348DAA4EF28B463 /* FieldDocumentInterchangeUITestProbe.swift */,
3E6187FA7C4786EC662718B2 /* FieldExternalActions.swift */,
491D57E540BAB04F24619737 /* FieldFileAccessUITestProbe.swift */,
+ 4E150C6C18B2A06F2F3227C6 /* FieldIdentityPolicyUITestProbe.swift */,
CA942715DB13FFD494FD35A0 /* FieldIdentityPublicMetadataStore.swift */,
9EB0A2CFCBBFA9D204C6992B /* FieldLocalState.swift */,
2F3541389124A31F5D701A45 /* FieldLocationCheckIn.swift */,
@@ -448,6 +451,7 @@
E432FD39ECC8F03764EEED81 /* FieldDocumentInterchangeUITestProbe.swift in Sources */,
82903551F5E15FBDAC388D20 /* FieldExternalActions.swift in Sources */,
7E650F6DA30931E310F842E2 /* FieldFileAccessUITestProbe.swift in Sources */,
+ 5FB3E3E450EE7DFF30F3A005 /* FieldIdentityPolicyUITestProbe.swift in Sources */,
D4CFDE54747B6D6957977025 /* FieldIdentityPublicMetadataStore.swift in Sources */,
6E15D30653861F26AC45B501 /* FieldLocalState.swift in Sources */,
1C6EA551530A46CA77BD9E1C /* FieldLocationCheckIn.swift in Sources */,
diff --git a/Radroots/App/AppEntry.swift b/Radroots/App/AppEntry.swift
@@ -44,6 +44,13 @@ public struct AppEntry<Main: View>: View {
.accessibilityIdentifier("field_ios.document_interchange.probe")
.accessibilityValue(probeValue)
}
+ if let probeValue = appState.identityPolicyProbeValue {
+ Color.clear
+ .frame(width: 1, height: 1)
+ .accessibilityElement()
+ .accessibilityIdentifier("field_ios.identity_policy.probe")
+ .accessibilityValue(probeValue)
+ }
if let probeValue = appState.telemetryProbeValue {
Color.clear
.frame(width: 1, height: 1)
diff --git a/Radroots/App/AppState.swift b/Radroots/App/AppState.swift
@@ -45,6 +45,7 @@ public final class AppState: ObservableObject {
@Published public private(set) var relaySettingsSourceLabel: String = RelaySettingsSource.buildConfig.displayName
@Published public private(set) var fileAccessProbeValue: String?
@Published public private(set) var documentInterchangeProbeValue: String?
+ @Published public private(set) var identityPolicyProbeValue: String?
@Published public private(set) var telemetryProbeValue: String?
@Published public private(set) var backgroundExecutionProbeValue: String?
@Published public private(set) var externalActionStatus: String?
@@ -116,6 +117,9 @@ public final class AppState: ObservableObject {
let service = try radroots.start(telemetry: telemetry)
let secureStore = try FieldSecureIdentityStore.configured()
let metadataStore = try FieldIdentityPublicMetadataStore.configured()
+ #if DEBUG
+ identityPolicyProbeValue = try FieldIdentityPolicyUITestProbe.value()
+ #endif
let appBundleIdentifier = try bundleIdentifier()
let resetLocalStateRequested = BuildConfig.bool(.resetLocalState) == true
let backgroundExecution = try FieldBackgroundExecution.configured(
diff --git a/Radroots/Runtime/FieldIdentityPolicyUITestProbe.swift b/Radroots/Runtime/FieldIdentityPolicyUITestProbe.swift
@@ -0,0 +1,35 @@
+#if DEBUG
+import Foundation
+import RadrootsKit
+
+enum FieldIdentityPolicyUITestProbe {
+ private static let enabledKey = "RADROOTS_FIELD_IOS_UI_TEST_IDENTITY_POLICY_PROBE"
+
+ static var isRequested: Bool {
+ FieldUITestHarness.string(enabledKey) == "true"
+ }
+
+ static func value() throws -> String? {
+ guard isRequested else {
+ return nil
+ }
+ let configuredPolicy = try FieldSecureIdentityStore.configuredAccessPolicy()
+ let storePolicy = configuredPolicy.storePolicy
+ return [
+ "configured_policy=\(configuredPolicy.rawValue)",
+ "store_policy_accessibility=\(accessibilityValue(storePolicy.accessibility))",
+ "store_policy_device_local_only=\(storePolicy.deviceLocalOnly)",
+ "store_policy_user_presence_required=\(storePolicy.userPresenceRequired)"
+ ].joined(separator: ";")
+ }
+
+ private static func accessibilityValue(_ accessibility: RadrootsSecretAccessibility) -> String {
+ switch accessibility {
+ case .whenUnlocked:
+ "when_unlocked"
+ case .afterFirstUnlock:
+ "after_first_unlock"
+ }
+ }
+}
+#endif