217 Commits

Author SHA1 Message Date
Mariusz Klochowicz
05efcfe31a fix(apple): Use a single keychain label (#10986)
Previous attempt to split the Keychain item between between Debug and
Release versions caused issues - we could not save things in the
keychain in Debug.

Revert the problematic change. No changelog entry as it only affected
unreleased debug versions.
2025-11-27 00:14:58 +00:00
Mariusz Klochowicz
994de0fe2a refactor(swift): replace @unchecked Sendable (#10970)
VPNConfigurationManager now uses `@MainActor` isolation instead of
`@unchecked Sendable`. This aligns with Apple's documented behaviour
where NEVPNManager callbacks arrive on the main thread.

- Made `VPNConfigurationManager` final and `@MainActor`
- Added `@MainActor` to `LogExporter.export(to:session:)` on macOS
- Marked `legacyConfiguration()` as `nonisolated` (pure function, called
from network extension)
- Removed redundant `@MainActor` from `maybeMigrateConfiguration()`
2025-11-26 03:41:17 +00:00
Mariusz Klochowicz
4e26f9943b refactor(apple): remove unsafe code instance (#10967)
Use the Combine pattern to avoid unsafe code.
2025-11-25 05:47:06 +00:00
Mariusz Klochowicz
5db7eebbb2 refactor(apple): remove unsafe from Token (#10968)
Convert static query dictionary to a computed property, eliminating the
need for nonisolated(unsafe).

Also fixes a bug where kSecAttrLabel used a hardcoded string instead of
the label property (which differs between debug and release builds).
2025-11-25 05:05:07 +00:00
Mariusz Klochowicz
528db7d9c5 fix(apple): Prevent Swift6 crash on iPadOS (#10916)
UserDefaults change notifications should always be handled on the main
thread.

This wasn't the case when PencilKit posted UserDefaults notifications
from a background thread during its initialization on iPadOS, causing a
Swift 6 MainActor violation crash.

Ultimately, the root cause of this issue was not abiding to strict
Swift6 concurrency checks by using unsafe code: even when the
UserDefaults themselves were `nonisolated(unsafe)` and bypassed the
checks, it was not the case for Apple PencilKit framework ultimately
initialised in wrong context.

Note: There are a few ways to fix, we're settling on Combine pattern as
it's used elsewhere in the codebase (e.g. in Store).

For other solutions, see:

https://stackoverflow.com/questions/74729010/swift-concurrency-notification-callbacks-on-mainactor-objects
2025-11-20 19:21:04 +00:00
Mariusz Klochowicz
f735855344 fix(apple): Restore favorites UI updates on iOS (#10908)
Recent refactors uncovered a latent bug where we never properly
subscribed to favorites updates.

The underlying data was being saved correctly to UserDefaults, but the
view wouldn't redraw to reflect the change.

The fix forwards Favourites.objectWillChange to Store.objectWillChange,
matching the existing pattern for configuration changes and the pattern
used by MenuBar on macOS.

Relevant information:
- Favourites is a nested ObservableObject inside Store
- SwiftUI views observe Store via @EnvironmentObject
- Nested ObservableObject changes don't automatically propagate through
@Published properties

Fixes #10906
2025-11-18 15:03:57 +00:00
Jamil
91962acb83 chore(apple): ignore benign keychain errors (#10899)
* macOS 13 and below has a known bug that prevents us from saving the
token on the system keychain. To avoid Sentry noise, we ignore this
specific error and continue to log other errors that aren't an exact
match.
* Relatedly, if we try to start the tunnel and a token is not found,
it's not necessarily an error. This happens when the user signs out and
then tries to activate the VPN from system settings, for example.

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-17 16:09:09 +00:00
Mariusz Klochowicz
bdffa3a697 fix(apple): prevent utun increments from IPC calls (#10855)
On macOS, IPC calls to the network extension can wake it whilst not
connected, causing the system to create a utun device.
If startTunnel() is not subsequently called, these devices
persist and accumulate over time.

The existing dryStartStopCycle() mechanism was introduced to wake the
extension after upgrades, but other IPC operations (log management
functions) could also wake the extension without proper cleanup.

Solution
--------

Add wrapper functions in IPCClient that automatically handle wake-up
and cleanup lifecycle for IPC calls made whilst disconnected:

- Check VPN connection status
- If connected: execute IPC operation directly (utun already exists)
- If disconnected: wake extension → wait 500ms → execute IPC → cleanup

Implementation
--------------

For async IPC operations (clearLogs, getLogFolderSize):
  Created free functions in IPCClient that wrap low-level IPC calls
  with wrapIPCCallIfNeeded():
  - clearLogsWithCleanup(store:session:)
  - getLogFolderSizeWithCleanup(store:session:)

For callback-based exportLogs:
  We cannot use wrapper because exportLogs returns immediately and uses
  callbacks for streaming chunks. Wrapper would call stop() before
  export finishes, killing the extension mid-stream.

  Solution: Manual wake-up/cleanup in LogExporter where we already have
  continuation that waits for chunk.done signal:
  1. Check if extension needs waking (vpnStatus != .connected)
  2. If yes: wake extension, wait 500ms
  3. Start export with callbacks
  4. When chunk.done=true: cleanup utun device, then resume continuation
  5. On error: cleanup utun device, then resume with error
  
  
  Fixes #10580

---------

Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
2025-11-13 22:01:22 +00:00
Jamil
bd2abbaae3 feat(apple): config to hide resource list (#10824)
Adds a configuration variable `hideResourceList` accessible by
provisioning profile only to hide or show the Resource list. This is
helpful when end-users need not be concerned with the resources
available to their account.

Also updates the associated ProfileManifests, docs, and a little bit of
housekeeping around `configuration`, making it public for direct access.

<img width="292" height="228" alt="Screenshot 2025-11-09 at 9 12 47 PM"
src="https://github.com/user-attachments/assets/a4ce5586-bf92-4ebc-bc0d-51215e1efd61"
/>


Related: https://github.com/ProfileManifests/ProfileManifests/pull/839
Fixes: #10808

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-11-10 19:55:27 +00:00
Mariusz Klochowicz
b5048ad779 refactor(apple): Convert IPCClient from actor to stateless enum (#10797)
Refactors IPCClient from an actor to a stateless enum with static
methods, removing unnecessary actor isolation and instance management.

- IPCClient: Actor → enum with static methods taking session parameter
- Store: Removed IPCClient instance caching, added resource list caching
- Store: Moved resource fetching logic from IPCClient into Store
- All call sites: Updated to pass session directly to static methods

Store now directly manages resource list hashing and caching via
fetchResources() method, using SHA256 hash optimisation to avoid
redundant updates when resource lists haven't changed.
2025-11-05 21:58:20 +00:00
Mariusz Klochowicz
936b095391 chore(apple): Enable Swift 6.2 Approachable Concurrency features (#10799)
Enables SWIFT_APPROACHABLE_CONCURRENCY build setting which activates
a few key Swift 6.2 concurrency features, including:

1. NonisolatedNonsendingByDefault - Makes nonisolated async functions
run
   on the caller's executor instead of the global executor, providing
   more predictable performance and behaviour

2. InferIsolatedConformances - Protocol conformances automatically
   inherit global actor isolation, reducing annotation burden

Read more:
https://www.donnywals.com/what-is-approachable-concurrency-in-xcode-26/

Also bumps swift-tools-version from 6.0 to 6.2 in Package.swift to
enable newer Package Manager manifest APIs.

As a result of better type inference, removes 1 redundant @Sendable
annotation in Store.swift:
- vpnStatusChangeHandler: @MainActor closures are implicitly Sendable
2025-11-05 21:56:24 +00:00
Mariusz Klochowicz
bf95dc45a3 refactor(apple): Upgrade to Swift 6.2 with concurrency checks (#10682)
This PR upgrades the Swift client from Swift 5 to Swift 6.2, addressing
all
concurrency-related warnings and runtime crashes that come with Swift
6's
strict concurrency checking.

## Swift 6 Concurrency Primer

**`actor`** - A new reference type that provides thread-safe, serialised
access to mutable state. Unlike classes, actors ensure that only one
piece of
code can access their mutable properties at a time. Access to actor
methods/properties requires await and automatically hops to the actor's
isolated executor.

**`@MainActor`** - An attribute that marks code to run on the main
thread.
Essential for UI updates and anything that touches UIKit/AppKit. When a
class/function is marked @MainActor, all its methods and properties
inherit
this isolation.

**`@Sendable`** - A protocol indicating that a type can be safely passed
across concurrency domains (between actors, tasks, etc.). Value types
(structs, enums) with Sendable stored properties are automatically
Sendable.
Reference types (classes) need explicit @unchecked Sendable if they
manage
thread-safety manually.

**`nonisolated`** - Opts out of the containing type's actor isolation.
For
example, a nonisolated method in a @MainActor class can be called from
any
thread without await. Useful for static methods or thread-safe
operations.

**`@concurrent`** - Used on closure parameters in delegate methods.
Indicates
the closure may be called from any thread, preventing the closure from
inheriting the surrounding context's actor isolation. Critical for
callbacks
from system frameworks that call from background threads.

**Data Races** - Swift 6 enforces at compile-time (and optionally at
runtime)
that mutable state cannot be accessed concurrently from multiple
threads. This
eliminates entire classes of bugs that were previously only caught
through
testing or production crashes.

## Swift Language Upgrade

- **Bump Swift 5 → 6.2**: Enabled strict concurrency checking throughout
the
  codebase
- **Enable ExistentialAny (SE-0335)**: Adds compile-time safety by
making
  protocol type erasure explicit (e.g., any Protocol instead of implicit
  Protocol)
- **Runtime safety configuration**: Added environment variables to log
concurrency violations during development instead of crashing, allowing
  gradual migration

## Concurrency Fixes

### Actor Isolation

- **TelemetryState actor** (Telemetry.swift:10): Extracted mutable
telemetry
state into a dedicated actor to eliminate data races from concurrent
access
- **SessionNotification @MainActor isolation**
(SessionNotification.swift:25):
  Properly isolated the class to MainActor since it manages UI-related
  callbacks
- **IPCClient caching** (IPCClient.swift): Fixed actor re-entrance
issues and
resource hash-based optimisation by caching the client instance in Store

### Thread-Safe Callbacks

- **WebAuthSession @concurrent delegate** (WebAuthSession.swift:46): The
  authentication callback is invoked from a background thread by
ASWebAuthenticationSession. Marked the wrapper function as @concurrent
to
  prevent MainActor inference on the completion handler closure, then
  explicitly hopped back to MainActor for the session.start() call. This
  fixes EXC_BAD_INSTRUCTION crashes at _dispatch_assert_queue_fail.
- **SessionNotification @concurrent delegate**
(SessionNotification.swift:131): Similarly marked the notification
delegate
method as @concurrent and used Task { @MainActor in } to safely invoke
the
  MainActor-isolated signInHandler

### Sendable Conformances

- Added Sendable to Resource, Site, Token, Configuration, and other
model
  types that are passed between actors and tasks
- **LogWriter immutability** (Log.swift): Made jsonData immutable to
prevent
  capturing mutable variables in @Sendable closures

### Nonisolated Methods

- **Static notification display** (SessionNotification.swift:73): Marked
showSignedOutNotificationiOS() as nonisolated since it's called from the
  Network Extension (different process) and only uses thread-safe APIs

Fixes #10674
Fixes #10675
2025-11-05 04:24:49 +00:00
Mariusz Klochowicz
ac6b3922be fix(apple): don't call setConfiguration when not connected (#10747)
Skip `setConfiguration()` IPC call when not in connected state; this was
observed as the root cause of the utun interface increments which we've
seen
recently.

Note: `utun` increments can still happen during other IPC calls when not
signed in,
notably during log export when signed out of Firezone. This is not a
major issue though,
as other IPC calls happen only as a result of user interaction between
network extension sleeps.
To fully get rid of the problem, we should address #10754.

To ensure we still are able to pass on configuration before sign in, we
are now
passing configuration directly in the startTunnel() options dictionary.

Fixes #10603
2025-10-28 23:51:50 +00:00
dependabot[bot]
6105f6fc6a build(deps): bump github.com/getsentry/sentry-cocoa from 8.56.0 to 8.56.2 in /swift/apple/FirezoneKit (#10726)
Bumps
[github.com/getsentry/sentry-cocoa](https://github.com/getsentry/sentry-cocoa)
from 8.56.0 to 8.56.2.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/getsentry/sentry-cocoa/releases">github.com/getsentry/sentry-cocoa's
releases</a>.</em></p>
<blockquote>
<h2>8.56.2</h2>
<blockquote>
<p>[!Warning]
Session Replay in this version does not correctly mask views when built
with Xcode 26 and running on iOS 26 with Liquid Glass, which may lead to
PII leaks. Please upgrade to 8.57.0 or later, which automatically
<strong>disables session replay</strong> in such environments.</p>
</blockquote>
<h3>Fixes</h3>
<ul>
<li>Fix crash from null UIApplication in SwiftUI apps (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6264">#6264</a>)</li>
</ul>
<h2>8.56.1</h2>
<blockquote>
<p>[!Warning]
This version can cause runtime crashes because the
<code>UIApplication.sharedApplication</code>/<code>NSApplication.sharedApplication</code>
is not yet available during SDK initialization, due to the changes in
[PR <a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5900">#5900</a>](<a
href="https://redirect.github.com/getsentry/sentry-cocoa/pull/5900">getsentry/sentry-cocoa#5900</a>),
released in <a
href="https://github.com/getsentry/sentry-cocoa/releases/tag/8.56.0">8.56.0</a>.</p>
</blockquote>
<blockquote>
<p>[!Warning]
Session Replay in this version does not correctly mask views when built
with Xcode 26 and running on iOS 26 with Liquid Glass, which may lead to
PII leaks. Please upgrade to 8.57.0 or later, which automatically
<strong>disables session replay</strong> in such environments.</p>
</blockquote>
<h3>Fixes</h3>
<ul>
<li>Fix potential app launch hang caused by the SentrySDK (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6181">#6181</a>)
Fixed by removing the call to <code>_dyld_get_image_header</code> on the
main thread.</li>
<li>Fix dynamic selector crash in SentryReplayRecording (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6211">#6211</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="9e193ac0b7"><code>9e193ac</code></a>
release: 8.56.2</li>
<li><a
href="d1c491625f"><code>d1c4916</code></a>
test: Skip flaky user feedback UITests (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6289">#6289</a>)</li>
<li><a
href="9a32d525be"><code>9a32d52</code></a>
fix: Lazily access UIApplication.shared (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6264">#6264</a>)</li>
<li><a
href="2ec27000f0"><code>2ec2700</code></a>
chore(ci): Set iOS version for running Test Server unit tests (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6287">#6287</a>)</li>
<li><a
href="4be5cd8ec9"><code>4be5cd8</code></a>
ci: Extra test plan for test server unit tests (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6177">#6177</a>)</li>
<li><a
href="449d185f00"><code>449d185</code></a>
chore(deps): Update clang-format version (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6276">#6276</a>)</li>
<li><a
href="649265b71b"><code>649265b</code></a>
test: Skip AppHangTracking when debugger attached (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6242">#6242</a>)</li>
<li><a
href="7dabfb9176"><code>7dabfb9</code></a>
docs: Add warning to releases v8.56.0 and v8.56.1 (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6266">#6266</a>)</li>
<li><a
href="d8ceea3a0c"><code>d8ceea3</code></a>
Merge branch 'release/8.56.1'</li>
<li><a
href="a82041aad9"><code>a82041a</code></a>
release: 8.56.1</li>
<li>Additional commits viewable in <a
href="https://github.com/getsentry/sentry-cocoa/compare/8.56.0...8.56.2">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/getsentry/sentry-cocoa&package-manager=swift&previous-version=8.56.0&new-version=8.56.2)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-28 01:55:52 +00:00
dependabot[bot]
6e1fb01286 build(deps): bump github.com/getsentry/sentry-cocoa from 8.55.1 to 8.56.0 in /swift/apple/FirezoneKit (#10629)
Bumps
[github.com/getsentry/sentry-cocoa](https://github.com/getsentry/sentry-cocoa)
from 8.55.1 to 8.56.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/getsentry/sentry-cocoa/releases">github.com/getsentry/sentry-cocoa's
releases</a>.</em></p>
<blockquote>
<h2>8.56.0</h2>
<blockquote>
<p>[!Warning]
This version can cause runtime crashes because the
<code>UIApplication.sharedApplication</code>/<code>NSApplication.sharedApplication</code>
is not yet available during SDK initialization, due to the changes in
[PR <a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5900">#5900</a>](<a
href="https://redirect.github.com/getsentry/sentry-cocoa/pull/5900">getsentry/sentry-cocoa#5900</a>),
released in <a
href="https://github.com/getsentry/sentry-cocoa/releases/tag/8.56.0">8.56.0</a>.</p>
</blockquote>
<blockquote>
<p>[!Warning]
Session Replay in this version does not correctly mask views when built
with Xcode 26 and running on iOS 26 with Liquid Glass, which may lead to
PII leaks. Please upgrade to 8.57.0 or later, which automatically
<strong>disables session replay</strong> in such environments.</p>
</blockquote>
<h3>Features</h3>
<ul>
<li>Structured Logs: Flush logs on SDK flush/close (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5834">#5834</a>)</li>
<li>Add masking options for screenshots (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5401">#5401</a>)</li>
<li>Add significant time change breadcrumb (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6112">#6112</a>)</li>
<li>Add support for iOS 26, macOS 26, visionOS 26, watchOS 26, and tvOS
26 in device tests (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6063">#6063</a>)</li>
</ul>
<h3>Improvements</h3>
<ul>
<li>Lazily CharacterSet only once in SentryBaggageSerialization (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5871">#5871</a>)</li>
<li>Structured Logging: Log <code>SentrySDK.logger</code> calls to
<code>SentrySDKLog</code> (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5991">#5991</a>)</li>
<li>The build type in the app context now differentiates between
<code>enterprise</code> and <code>adhoc</code> (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6044">#6044</a>)</li>
<li>visionOS no longer needs swift's interoperability mode (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6077">#6077</a>)</li>
<li>Ensure IP address is only inferred by Relay if sendDefaultPii is
true (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5877">#5877</a>)</li>
<li>Sentry without UIKit / AppKit is available to install with SPM (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6160">#6160</a>)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Don't capture replays for events dropped in <code>beforeSend</code>
(<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5916">#5916</a>)</li>
<li>Fix linking with SentrySwiftUI on Xcode 26 for visionOS (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5823">#5823</a>)</li>
<li>Structured Logging: Logger called before
<code>SentrySDK.start</code> becomes unusable (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5984">#5984</a>)</li>
<li>Add masking for AVPlayerView (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5910">#5910</a>)</li>
<li>Fix missing view hierachy when enabling
<code>attachScreenshot</code> too (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5989">#5989</a>)</li>
<li>Fix macOS's frameworks not following the versioned framework
structure (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6049">#6049</a>)</li>
<li>Add warning to addBreadcrumb when used before SDK init (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6083">#6083</a>)</li>
<li>Add null-handling for parsed DSN in SentryHTTPTransport (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5800">#5800</a>)</li>
<li>Fix crash in Session Replay when opening the camera UI on iOS 26+ by
skipping redaction of internal views.
This may result in more of the camera screen being redacted. (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6045">#6045</a>)</li>
<li>Fix crash in SentryDependencyContainer init when using the SDK as a
static framework (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6125">#6125</a>)</li>
<li>Fixes a React Native legacy build failure by adding the missing self
references for explicit capture semantics (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6156">#6156</a>)</li>
</ul>
<h2>8.56.0-alpha.3</h2>
<h3>Features</h3>
<ul>
<li>Structured Logs: Flush logs on SDK flush/close (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5834">#5834</a>)</li>
<li>Add masking options for screenshots (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5401">#5401</a>)</li>
<li>Add significant time change breadcrumb (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6112">#6112</a>)</li>
<li>Add support for iOS 26, macOS 26, visionOS 26, watchOS 26, and tvOS
26 in device tests (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6063">#6063</a>)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Don't capture replays for events dropped in <code>beforeSend</code>
(<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5916">#5916</a>)</li>
<li>Fix linking with SentrySwiftUI on Xcode 26 for visionOS (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5823">#5823</a>)</li>
</ul>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3365d74b0a"><code>3365d74</code></a>
chore: Add changes from alpha releases to v8.56.0 changelog (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6166">#6166</a>)</li>
<li><a
href="5542c69989"><code>5542c69</code></a>
release: 8.56.0</li>
<li><a
href="c30e40105c"><code>c30e401</code></a>
feat: Make Sentry-WithoutUIKitOrAppKit available with SPM (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6160">#6160</a>)</li>
<li><a
href="5ae9ff1e4f"><code>5ae9ff1</code></a>
ref: Remove unused memory pressure typdef (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6152">#6152</a>)</li>
<li><a
href="8745cc0ff5"><code>8745cc0</code></a>
ref: Convert <code>SentryCrashWrapper</code> to Swift (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6047">#6047</a>)</li>
<li><a
href="c1f202e16b"><code>c1f202e</code></a>
Merge branch 'release/8.56.0-alpha.3'</li>
<li><a
href="fad8f23d7a"><code>fad8f23</code></a>
release: 8.56.0-alpha.3</li>
<li><a
href="5cbd333fee"><code>5cbd333</code></a>
chore(ci): React-Native: Adds missing self to make capture semantics
explicit...</li>
<li><a
href="89e74bc125"><code>89e74bc</code></a>
Merge branch 'release/8.56.0-alpha.2'</li>
<li><a
href="36b80343ab"><code>36b8034</code></a>
chore: Fix changelog (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6154">#6154</a>)</li>
<li>Additional commits viewable in <a
href="https://github.com/getsentry/sentry-cocoa/compare/8.55.1...8.56.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/getsentry/sentry-cocoa&package-manager=swift&previous-version=8.55.1&new-version=8.56.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-20 14:02:21 +00:00
Jamil
73576922ff fix(apple/macos): clean up utun on quit (#10603)
On macOS, because it uses the System Extension packaging type, the
lifecycle of the tunnel provider process is not tied directly to
connlib's session start and end, but rather managed by the system. The
process is likely running at all times, even when the GUI is not open or
signed in.

The system will start the provider process upon the first IPC call to
it, which allocates a `utun` interface. The tricky part is ensuring this
interface gets removed when the GUI app quits. Otherwise, it's likely
that upon the next launch of the GUI app, the system will allocate a
_new_ utun interface, and the old one will linger until the next system
reboot.

Here's where things get strange. The system will only remove the `utun`
interface when stopping the tunnel under the following conditions:

- The provider is currently not in a `disconnected` state (so it needs
to be in `reasserting`, `connecting`, or `connected`
- The GUI side has called `stopTunnel`, thereby invoking the provider's
`stopTunnel` override function, or
- The provider side has called `cancelTunnelWithError`, or
- The `startTunnel`'s completionHandler is called with an `Error`

The problem we had is that we make various IPC calls throughout the
lifecycle of the GUI app, for example, to gather logs, set tunnel
configuration, and the like. If the GUI app was _not_ in a connected
state when the user quit, the `utun` would linger, even though we were
issuing a final `stopTunnel` upon quit in all circumstances.

To fix the issue, we update the dry run `startTunnel` code path we added
previously in two ways:

1. We add a `dryRun` error type to the `startTunnel`'s completionHandler
2. We implement the GUI app `applicationShouldTerminate` handler in
order to trigger one final dryRun which briefly moves the provider to a
connected state so the system will clean us up when its
completionHandler is invoked.


Tested under the following conditions:

- Launch app in a signed-out state -> quit
- Launch app in a signed-out state -> sign in -> quit
- Launch app in a signed-out state -> sign in -> sign out -> quit
- Launch app in a signed-in state -> quit
- Launch app in a signed-in state -> sign out -> quit

Notably, if the GUI app is killed with `SIGKILL`, our terminate hook is
_not_ called, and the utun lingers. We'll have to accept this edge case
for now.

Along with the above, the janky `consumeStopReason` mechanism has been
removed in favor of NE's `cancelTunnelWithError` to pass the error back
to the GUI we can then use to show the signed out alert.


Fixes #10580
2025-10-17 15:12:29 +00:00
Mariusz Klochowicz
e76daaaab3 refactor: remove JSON serialization from FFI boundary (#10575)
This PR eliminates JSON-based communication across the FFI boundary,
replacing it with proper
uniffi-generated types for improved type safety, performance, and
reliability. We replace JSON string parameters with native uniffi types
for:
 - Resources (DNS, CIDR, Internet)
 - Device information
 - DNS server lists
 - Network routes (CIDR representation)
 
Also, get rid of JSON serialisation in Swift client IPC in favour of
PropertyList based serialisation.
 
 Fixes: https://github.com/firezone/firezone/issues/9548

---------

Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
2025-10-16 05:15:31 +00:00
Mariusz Klochowicz
8378819621 fix(apple): Ensure fetching resource state if already connected (#10567)
Fixes an issue where the Resources menu would not populate when
launching
the app while already connected by ensuring the initial VPN status
triggers the resource loading handler.


Fixes #9837
2025-10-14 23:55:02 +00:00
Mariusz Klochowicz
cb50800d52 refactor(apple): Migrate iOS/macOS clients to UniFFI (#10368)
Replace callback-based Adapter with event polling-based AdapterUniFfi

This change improves reliability by eliminating callback lifetime
issues.
2025-10-13 23:13:52 +00:00
dependabot[bot]
900186cd63 build(deps): bump github.com/getsentry/sentry-cocoa from 8.55.0 to 8.55.1 in /swift/apple/FirezoneKit (#10518)
Bumps
[github.com/getsentry/sentry-cocoa](https://github.com/getsentry/sentry-cocoa)
from 8.55.0 to 8.55.1.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/getsentry/sentry-cocoa/releases">github.com/getsentry/sentry-cocoa's
releases</a>.</em></p>
<blockquote>
<h2>8.55.1</h2>
<h3>Features</h3>
<h3>Fixes</h3>
<ul>
<li>Fix macOS's frameworks not following the versioned framework
structure (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6049">#6049</a>)</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="2c70925b98"><code>2c70925</code></a>
release: 8.55.1</li>
<li><a
href="4aa237de0d"><code>4aa237d</code></a>
chore: Update changelog</li>
<li><a
href="e8f2418539"><code>e8f2418</code></a>
fix(ci): Resolve symlink path before removing architectures (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/6049">#6049</a>)</li>
<li>See full diff in <a
href="https://github.com/getsentry/sentry-cocoa/compare/8.55.0...8.55.1">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/getsentry/sentry-cocoa&package-manager=swift&previous-version=8.55.0&new-version=8.55.1)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-06 17:28:43 +00:00
dependabot[bot]
f825995fc3 build(deps): bump github.com/getsentry/sentry-cocoa from 8.49.0 to 8.55.0 in /swift/apple/FirezoneKit (#10496)
Bumps
[github.com/getsentry/sentry-cocoa](https://github.com/getsentry/sentry-cocoa)
from 8.49.0 to 8.55.0.
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/getsentry/sentry-cocoa/releases">github.com/getsentry/sentry-cocoa's
releases</a>.</em></p>
<blockquote>
<h2>8.55.0</h2>
<blockquote>
<p>[!Important]
Xcode 26 no longer allows individual frameworks to contain arm64e slices
anymore if the main binary doesn't contain them.
We have decided to split the Dynamic variant and
Sentry-WithoutUIKitOrAppKit of Sentry into two variants:</p>
<ul>
<li><code>Sentry-Dynamic</code>: Without ARM64e</li>
<li><code>Sentry-Dynamic-WithARM64e</code>: <em>With</em> ARM64e
slice</li>
<li><code>Sentry-WithoutUIKitOrAppKit</code>: Without ARM64e</li>
<li><code>Sentry-WithoutUIKitOrAppKit-WithARM64e</code>: <em>With</em>
ARM64e slice</li>
</ul>
<p>If your app does not need arm64e, you don't need to make any changes.
But if your app <em>needs arm64e</em> please use
<code>Sentry-Dynamic-WithARM64e</code> or
<code>Sentry-WithoutUIKitOrAppKit-WithARM64e</code> from 8.55.0 so you
don't have issues uploading to the App Store.</p>
</blockquote>
<h3>Features</h3>
<ul>
<li>Add a new prebuilt framework with arm64e and remove it from the
regular one (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5788">#5788</a>)</li>
<li>Add <code>beforeSendLog</code> callback to
<code>SentryOptions</code> (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5678">#5678</a>)</li>
<li>Structured Logs: Flush logs on SDK flush/close (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5834">#5834</a>)</li>
<li>Add a new prebuilt framework with ARM64e for WithoutUIKitOrAppKit
(<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5897">#5897</a>)</li>
<li>Add source context and vars fields to SentryFrame (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5853">#5853</a>)</li>
</ul>
<h3>Fixes</h3>
<ul>
<li>Add support for PDFKit views in session replay (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5750">#5750</a>)</li>
<li>Fix Infinite Session Replay Processing Loop (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5765">#5765</a>)</li>
<li>Fix memory leak in SessionReplayIntegration (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5770">#5770</a>)</li>
<li>Fix reporting of energy used while profiling (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5768">#5768</a>)</li>
<li>Fixed a build error in <code>SentryFeedback.swift</code> when
building with cocoapods on Xcode 14.2 (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5917">#5917</a>)</li>
<li>Fix linking against Sentry on an app extension (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5813">#5813</a>)</li>
</ul>
<h2>8.54.1-alpha.2</h2>
<blockquote>
<p>[!Important]
Xcode 26 no longer allows individual frameworks to contain arm64e slices
anymore if the main binary doesn't contain them.
We have decided to split the Dynamic variant and
Sentry-WithoutUIKitOrAppKit of Sentry into two variants:</p>
<ul>
<li><code>Sentry-Dynamic</code>: Without ARM64e</li>
<li><code>Sentry-Dynamic-WithARM64e</code>: <em>With</em> ARM64e
slice</li>
<li><code>Sentry-WithoutUIKitOrAppKit</code>: Without ARM64e</li>
<li><code>Sentry-WithoutUIKitOrAppKit-WithARM64e</code>: <em>With</em>
ARM64e slice</li>
</ul>
<p>If your app does not need arm64e, you don't need to make any changes.
But if your app <em>needs arm64e</em> please use
<code>Sentry-Dynamic-WithARM64e</code> or
<code>Sentry-WithoutUIKitOrAppKit-WithARM64e</code> from 8.55.0 so you
don't have issues uploading to the App Store.</p>
</blockquote>
<h3>Features</h3>
<ul>
<li>Structured Logs: Flush logs on SDK flush/close (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5834">#5834</a>)</li>
<li>Add a new prebuilt framework with ARM64e for WithoutUIKitOrAppKit
(<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5897">#5897</a>)</li>
<li>Add source context and vars fields to SentryFrame (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5853">#5853</a>)</li>
</ul>
<h3>Fixes</h3>
<!-- raw HTML omitted -->
</blockquote>
<p>... (truncated)</p>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="3c2eee7773"><code>3c2eee7</code></a>
release: 8.55.0</li>
<li><a
href="3ec47ae715"><code>3ec47ae</code></a>
ci: Use iOS18.5 since 18.6 seems to be unavailable sometimes (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5944">#5944</a>)</li>
<li><a
href="1a34ddc00f"><code>1a34ddc</code></a>
ci: Bump iOS and tvOS versions to 18.6 (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5942">#5942</a>)</li>
<li><a
href="67e8e3ecf0"><code>67e8e3e</code></a>
Merge branch 'release/8.54.1-alpha.2'</li>
<li><a
href="45482a6a1b"><code>45482a6</code></a>
fix: Build error on Xcode 14.2 (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5917">#5917</a>)</li>
<li><a
href="9174496cdc"><code>9174496</code></a>
release: 8.54.1-alpha.2</li>
<li><a
href="891fd1d420"><code>891fd1d</code></a>
ref: Make SentryEventDecodable internal in V9 (<a
href="https://redirect.github.com/getsentry/sentry-cocoa/issues/5808">#5808</a>)</li>
<li><a
href="dba4ee8975"><code>dba4ee8</code></a>
Refactor SentryFeedback serialization to have 2 declarations depending
if SDK...</li>
<li><a
href="669f02ce7d"><code>669f02c</code></a>
Add changelog</li>
<li><a
href="4506bdb8b3"><code>4506bdb</code></a>
fix: Build error on Xcode 14.2</li>
<li>Additional commits viewable in <a
href="https://github.com/getsentry/sentry-cocoa/compare/8.49.0...8.55.0">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=github.com/getsentry/sentry-cocoa&package-manager=swift&previous-version=8.49.0&new-version=8.55.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop
Dependabot creating any more for this major version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop
Dependabot creating any more for this minor version (unless you reopen
the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop
Dependabot creating any more for this dependency (unless you reopen the
PR or upgrade to it yourself)


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-10-01 03:26:38 +00:00
Mariusz Klochowicz
4d2b592d65 chore: Clean up Xcode config (#10461)
- declary sentry as FirezoneKit dependency
- add config for non-Xcode LSP config 
- add some more info in README
2025-10-01 02:08:18 +00:00
Mariusz Klochowicz
b1ed2f8a5e chore: improve macos dev experience (#10363)
Quality of life improvements for macOS devs, mostly relevant when not
using Xcode as daily driver - although some convenience functions &
explicit sentry dependency should make it better there too.
2025-09-17 02:17:36 +00:00
Jamil
621028a998 fix(apple): use documents for tempfile (#10019)
On iOS, we were using the tempfile directory to stage the log export,
and then moving this into place from the share sheet presented to the
user.

For some reason, this has stopped working in iOS 18.5.0, and we need to
stage the file in the standard documents directory instead.


Fixes #10014
2025-07-26 22:05:10 +00:00
Thomas Eizinger
f211c9d46a feat(apple): use .zip for logs (#9536)
This PR replaces the use of Apple Archive with an API that allows us to
zip the log file contents. This API doesn't handle symlinks well so we
move the symlink out of the way before making the zip. The symlink is
then moved back after the process is completed. Any errors in this
process are ignored as the symlink itself is not a critical component of
Firezone.

The zip compression is marginally less efficient than the Apple Archive.
Instead of compressing ~2GB of logs to 11.8 MB we now get an archive of
12.4 MB. Considering how much easier zip files are to handle, this seems
like a fine trade-off.

<img width="774" alt="Screenshot 2025-06-16 at 00 04 52"
src="https://github.com/user-attachments/assets/8fb6bade-5308-40b9-a446-2a2c364cb621"
/>

Resolves: #7475

---------

Signed-off-by: Thomas Eizinger <thomas@eizinger.io>
Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
2025-06-23 22:25:57 +00:00
Thomas Eizinger
a2c122a3c0 refactor(apple): use guard for checking valid handle (#9614)
Follow-up to #9597
2025-06-21 21:17:01 +00:00
Jamil
5537b8cfe7 fix(apple): ensure log file exists before writing to it (#9597)
Similar to the issue for the gui clients, the log file handle needs to
be able to be rolled over after logs are cleared.

related: #6850
2025-06-20 17:03:59 +00:00
Thomas Eizinger
47befe37f4 fix(apple): disable false-positive "App hang" reports (#9568)
As recommended by the Sentry team [0], "App hang" tracking should be
disabled before calling into certain system APIs like showing alerts to
prevent false-positives.

[0]: https://github.com/getsentry/sentry-cocoa/issues/3472
2025-06-18 22:44:03 +00:00
Thomas Eizinger
01ad87b1c0 chore(apple): format swift code with formatter (#9535)
When working on the Swift codebase, I noticed that running the formatter
produced a massive diff. This PR re-formats the Swift code with `swift
format . --recursive --in-place` and adds a CI check to enforce it going
forward.

Resolves: #9534

---------

Co-authored-by: Jamil Bou Kheir <jamilbk@users.noreply.github.com>
2025-06-15 20:28:18 +00:00
Jamil
889c1a971c fix(apple): Correctly handle stopTunnel and completionHandlers (#9308)
This PR fixes two crashes related to lifetimes on Apple:

- `completionHandler` was being called from within a Task executor
context, which could be different from the one the IPC call was received
on
- The `getLogFolderSize` task could return and attempt to call
`completionHandler` after the PacketTunnelProvider deinit'd
- We were calling the completionHandler from `stopTunnel` manually.
Apple explicitly says not to do this. Instead, we must call
`cancelTunnelWithError(nil)` when we want to stop the tunnel from e.g.
the `onDisconnect`. Apple with then call our `stopTunnel` override. The
downside is that we have no control over the `NEProviderStopReason`
received in this callback, but we don't use it anyway. Instead, we write
the reason to a temporary file and read it from the GUI process when we
detect a status change to `disconnected`. When that occurs, we're able
to show a UI notification (macOS only - iOS can show this notification
from the PacketTunnelProvider itself).
2025-05-30 20:54:13 +00:00
Jamil
ec682d5871 fix(apple): Don't throw when quitting with a stopped tunnel (#9231)
If the tunnel is already down when we try to quit the application, we
were throwing a harmless error because we mistakenly required a
connected status to send the `stopTunnel` command, which is just a no-op
if we're already connected.
2025-05-26 04:19:12 +00:00
Jamil
842fe8718d chore(apple): Remove managed enforcement of full-tunnel (#9230)
After discussing with @thomaseizinger, we realized this is better
supported with Polices.
2025-05-26 03:47:17 +00:00
Jamil
e84ba4545e feat(apple): Add supportURL as managed config item (#9202)
Adds `supportURL` as a managed configuration item so that admins may
point their workforce towards their own support Resources.
2025-05-22 16:48:35 +00:00
Jamil
6fd3493ed0 refactor(apple): Consolidate configuration to host app (#9196)
On Apple platforms, `UserDefaults` provides a convenient way to store
and fetch simple plist-compatible data for your app. Unbeknownst to the
author at the time of original implementation was the fact this these
keys are already designed for managed configurations to "mask" any
user-configured equivalents.

This means we no longer need to juggle two dicts in UserDefaults, and we
can instead check which keys are forced via a simple method call.

Additionally, the implementation was simplified in the following ways:

- The host app is the "source of truth" for app configuration now. The
tunnel service receives `setConfiguration` which applies the current
configuration, and saves it in order to start up again without the GUI
connected. The obvious caveat here is that if the GUI isn't running,
configuration such as `internetResourceEnabled` applied by the
administrator won't take effect. This is considered an edge case for the
time being since no customers have asked for this. Additionally, admins
can be advised to ensure the Firezone GUI is running on the system at
all times to prevent this.
- Settings and ConfigurationManager are now able to be removed - these
became redundant after consolidating configuration to the containing
app.
2025-05-22 16:18:00 +00:00
Jamil
745b57218b chore(apple): Remove useless IPC error log (#9201)
This error case happens during normal operation, particularly when
exiting the application and can be dropped.
2025-05-22 07:19:05 +00:00
Jamil
73f334e345 feat(apple): Add start on login functionality (#9168)
Adds a new settings/configuration item `startOnLogin` which simply adds
a "Login Item" which starts Firezone after signing into the Mac.

This feature is macOS 13 and above only because otherwise we will need
to bundle a helper application to register as a service to start the
app. Given our very small footprint of macOS 12 users, and how
unsupported it is, this is ok.

When it comes time to implement MDM for this feature, note that Apple
provides a means to enforce login items via the
[`ServiceManagementLoginItems`
payload](https://developer.apple.com/documentation/devicemanagement/servicemanagementmanagedloginitems)
which is outside the scope of `com.apple.configuration.managed`. This
enforces the login item in System Settings so that the user is unable to
disable it.

We also add functionality here, but bear in mind that even if we disable
the Toggle switch in our Settings page, the user could still disable the
item in system settings unless it is being set through MDM via the
service management key above.

Another thing to note is that this setting is applied on the GUI side of
the tunnel only, because it is inherently tied to the process it is
running as. We are not able to (nor does it make sense to) enable the
login item for the tunnel service. This should be fine.

Tested to ensure enabling/disabling appropriately adds and removes the
login item (and re-adds it if I manually remove it from system
settings).


Related: #8916 
Related: #2306

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
2025-05-16 22:15:49 +00:00
Jamil
9951e82727 feat(apple): Disable the update checker for MDM and App store (#9167)
For App Store installed macOS clients, it doesn't make sense to run an
update checker, because the system is managing the updates, and will
notify the user if there's an update available for Firezone (the user
has configured the system to manage app updates).

Related: #7664 
Related: #4505
2025-05-16 09:27:57 +00:00
Jamil
e599eb2f09 fix(apple): Ensure system extension loads after upgrade (#9166)
On macOS, after upgrading the client, the new system extension fails to
respond to IPC commands until it receives a `startTunnel` call. After
that, subsequent IPC calls will succeed across relaunches of the app.

To fix this, we introduce a dummy `startTunnel` call on macOS that
attempts to bring life into the System extension whenever we receive
`nil` configuration.

We also tidy up a few other things to make this easier to follow.


Fixes #9156 
Fixes #8476

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-16 07:17:12 +00:00
Jamil
7b4aa44f30 refactor(apple): Add Settings model (#9155)
The settings fields are getting tedious to manage individually, so a
helper class `Settings` is added which abstracts all of the view-related
logic applicable to user-defined settings.

When settings are saved, they are first applied to the `store`'s
existing Configuration, and then that configuration is saved via a new
consolidated IPC call `setConfiguration`.

`actorName` has been moved to a GUI-only cached store since it does not
need to live on `Configuration` any longer.

This greatly simplifies both the view logic and the IPC interface.

Notably, this does not handle the edge case where the configuration is
updated while the Settings window is open. That is saved for a later
time.
2025-05-15 23:25:00 +00:00
Jamil
7095974204 fix(apple): Handle tunnel starting before GUI after upgrade (#9141)
If the user tries to start the tunnel from system settings without
launching the GUI after upgrading to >= 1.4.15, the new configuration
will be empty, and we'll fail to set the accountSlug, preventing the
tunnel from starting.

To fix this, we add a simple convenience function that returns the
legacy configuration, and we use this configuration to start the tunnel
in case the GUI hasn't started.

Once the GUI starts, the legacy configuration is migrated and deleted,
so this is more of an edge case. Still, given the hundreds/thousands of
Apple device installations we have, someone is bound to hit it, and it
would be better to spend a few minutes saving potentially man-hours of
troubleshooting later.
2025-05-14 22:34:36 +00:00
Jamil
6fd5d96685 fix(apple): Isolate debug and release Keychain items (#9142)
On macOS, the token is saved in the system keychain so that the `root`
user is able to manage it. `secd`, the daemon that responds to Keychain
requests, is very strict about which binaries can access Keychain items
created by other binaries.

In development, the Firezone system extension runs from an unprivileged
directory, and isn't release-signed, which means it is not able to
manage the Keychain token for the release binary, and vice-versa.

To fix this, we isolate the Keychain items from each other with
different labels for `debug` and `release`, where the latter is
unchanged.

This is only an issue on debug, so a Changelog entry is not created.

Fixes #8917 
Fixes #8642
2025-05-14 22:34:11 +00:00
Jamil
204d1eb678 feat(apple): Allow user to configure connect on start (#9134)
Exposes a configuration toggle to connect on start, allowing it to be
overridden by MDM. Currently we assume this to be true.

Will need to refactor the settings soon to a dedicated
`ObservableObject` in the ViewModel to make these validations and field
checks less verbose.

related: #4505
2025-05-14 11:45:38 -07:00
Jamil
f19702f53e feat(apple): Allow user-configurable account slug (#9119)
Now that configuration is persisted in a more reasonable fashion, we can
expose a new `General` section to the Settings, allowing the user to
configure an account slug.

This field will automatically be populated upon the first sign in, so
that subsequent sign-ins will take the user directly to the account sign
in page.


Fixes #5119 
Related #8919

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-14 04:17:29 +00:00
Jamil
36e4a653f3 feat(apple/macOS): Add config to hide admin portal link (#9125)
Adds a `hideAdminPortalMenuItem` bool to our configuration to allow
admins to hide this from users.

Related: #4505
2025-05-14 04:00:50 +00:00
Jamil
5fae382375 feat(apple/macOS): Append account slug to admin portal URL link (#9126)
Appends the account slug to the admin portal URL when opened.

Related: #4505 
Related: #9119
2025-05-14 02:18:48 +00:00
Jamil
bee6479b96 refactor(apple): Use string for URL configuration (#9124)
In the UI, we need to use Strings to bind to the text inputs.
In the configuration dictionaries, we need to use Strings to save the
URLs.

It makes no sense to convert these to URLs in between. Instead, we can
validate upon save and then use them as Strings throughout.
2025-05-13 23:48:07 +00:00
Jamil
ccd6c265bb feat(apple): Allow MDM override of internet resource enabled (#9122)
All the MDM configuration to shadow the `internetResourceEnabled` state.

Related: #4505

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
2025-05-13 23:41:42 +00:00
Jamil
ae224384be feat(apple): Disable advanced settings if overridden (#9108)
If `authURL`, `apiURL`, or `logFilter` are set in the managed
configuration, we disable each of these fields respectively from user
editing.

If all of them are overridden, we disable the `Apply` and `Reset to
Defaults` buttons.

Related #4505
2025-05-13 04:06:05 +00:00
Jamil
14892d0f27 fix(apple): Save settings before signing out (#9104)
This fixes a small bug where settings wouldn't be saved if signed in,
and also allows errors during saving to bubble up to the user.

---------

Signed-off-by: Jamil <jamilbk@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-13 02:37:09 +00:00
Jamil
7d738bc192 refactor(apple): Fix var/func scope in SettingsView (#9106)
These are incorrectly scoped. No functionality is changing.
2025-05-13 01:35:28 +00:00