Skip to content

Commit cad11b9

Browse files
committed
Release Nick 4.0.1 build 408 network safety update
1 parent 8df2a57 commit cad11b9

38 files changed

Lines changed: 1180 additions & 211 deletions

CHANGELOG.md

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,33 @@ monotonically increasing macOS bundle build number.
88

99
## [Unreleased]
1010

11-
No user-facing changes have been released since 4.0.
11+
No user-facing changes have been released since 4.0.1.
12+
13+
## [4.0.1] - 2026-07-30
14+
15+
### Changed
16+
17+
- Scam Guardian is now observation-only and cannot interrupt ordinary network
18+
traffic.
19+
- Network policy configuration is versioned; missing, stale, or invalid
20+
configuration fails open.
21+
- Scam Guardian status and documentation now distinguish destination
22+
monitoring from active blocking.
23+
- Endpoint Security and Network Extension setup continues to require current
24+
runtime health before protection is shown as ready.
25+
26+
### Fixed
27+
28+
- Prevented the Network Filter from disrupting browsers, Git, developer tools,
29+
AirDrop, Handoff, and other legitimate connections.
30+
- Corrected network observations so known-rule matches remain visible for
31+
review without being converted into drop verdicts.
32+
33+
### Verification
34+
35+
- All 321 automated tests passed; 4 platform-dependent tests were skipped.
36+
- The signed package and disk image were notarized, stapled, and accepted by
37+
Gatekeeper.
1238

1339
## [4.0] - 2026-07-27
1440

@@ -71,7 +97,8 @@ See the [Nick 1.1 release](https://github.com/EhsanAzish80/Nick/releases/tag/v1.
7197

7298
- Initial public release.
7399

74-
[Unreleased]: https://github.com/EhsanAzish80/Nick/compare/v4.0.0...HEAD
100+
[Unreleased]: https://github.com/EhsanAzish80/Nick/compare/v4.0.1...HEAD
101+
[4.0.1]: https://github.com/EhsanAzish80/Nick/releases/tag/v4.0.1
75102
[4.0]: https://github.com/EhsanAzish80/Nick/releases/tag/v4.0.0
76103
[3.0]: https://github.com/EhsanAzish80/Nick/releases/tag/V3.0
77104
[1.2]: https://github.com/EhsanAzish80/Nick/releases/tag/v1.2

Documentation/RELEASE_CHECKLIST.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,11 @@
3232
- [ ] Endpoint Security activates and reports the current build.
3333
- [ ] Full Disk Access guidance covers Nick and NickExtension.
3434
- [ ] Scam Guardian activates after one approval flow.
35-
- [ ] A reserved malicious test domain is blocked.
35+
- [ ] A reserved malicious test domain is reported without interrupting its
36+
connection.
3637
- [ ] Normal Safari and third-party app networking remains available.
38+
- [ ] Git fetch/push, developer tools, AirDrop, Handoff, and clipboard
39+
continuity remain available with both extensions enabled.
3740
- [ ] Email Guard detects a safe test fixture and an actionable attachment
3841
fixture.
3942
- [ ] Quarantine re-validation, move, listing, and restore work.

Documentation/ROADMAP.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,16 @@ Delivered in source and release packaging:
1717
- YARA 4.5.5 and confidence-aware enforcement.
1818
- Native uninstaller and signed installer/disk-image pipeline.
1919
- Background performance, event-volume, and cache bounds.
20+
- Version 4.0.1 safety correction: Scam Guardian is observation-only and the
21+
Network Filter cannot drop ordinary traffic.
2022

2123
The clean-Mac checklist remains the release gate for every published build.
2224

2325
## Version 4.1: reliability and explainability
2426

27+
- Add a reviewed, explicit enforcement design only after per-app controls,
28+
time-limited allowances, recovery tests, and connectivity regression tests
29+
are complete.
2530
- Persist setup diagnostics that users can export without exposing personal
2631
content.
2732
- Group repeated alerts by app, behavior, and time window.

Documentation/SECURITY_AUDIT.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,16 @@
22

33
## Current release security status
44

5-
Nick 4.0 build 404 adds two restricted, security-sensitive surfaces beyond the
5+
Nick 4.0.1 build 408 includes two restricted, security-sensitive surfaces
6+
beyond the
67
historical audit below:
78

89
- `NickExtension`, an Endpoint Security system extension with authenticated
910
XPC, bounded event handling, confidence-aware YARA enforcement, Email Guard,
1011
file integrity, privacy monitoring, and quarantine re-validation.
11-
- `NickNetFilter`, a Network Extension content filter with deterministic
12-
allowlist-first policy, fail-open configuration, privacy-safe events, and
13-
Ed25519 validation for downloaded rule envelopes.
12+
- `NickNetFilter`, a Network Extension content filter with fail-open,
13+
observation-only policy, privacy-safe events, and Ed25519 validation for
14+
downloaded rule envelopes. Build 408 contains no traffic-drop verdict path.
1415

1516
Vendored YARA is version 4.5.5. The automated suite validates source behavior;
1617
it does not replace

Documentation/USER_GUIDE.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,15 +48,20 @@ malware exclusion.
4848
Scam Guardian evaluates connection hostnames. It does not read page contents,
4949
form data, messages, or full browsing history.
5050

51-
If normal browsing stops:
51+
Nick 4.0.1 observes suspected phishing destinations but does not block
52+
connections. A finding appears in Nick for review while the application
53+
connection remains available.
54+
55+
If normal browsing stops while the extension is enabled:
5256

5357
1. Open Nick Settings.
5458
2. Disable Network Protection using the emergency control.
5559
3. Confirm browsing returns.
5660
4. Review website and app allowlists.
5761
5. Report the affected domain and app as a false positive.
5862

59-
Nick's policy is fail-open when configuration is missing or invalid.
63+
Nick's policy is fail-open when configuration is missing, stale, or invalid.
64+
Build 408 also contains no Network Extension traffic-drop path.
6065

6166
## Email Guard
6267

Nick.xcodeproj/project.pbxproj

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
E40000000000000000000001 /* NetworkProtectionPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40000000000000000000000 /* NetworkProtectionPolicy.swift */; };
2424
E40000000000000000000002 /* NetworkProtectionPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40000000000000000000000 /* NetworkProtectionPolicy.swift */; };
2525
E40000000000000000000004 /* ScamGuardian.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40000000000000000000003 /* ScamGuardian.swift */; };
26+
E40000000000000000000006 /* RansomwareNotePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40000000000000000000005 /* RansomwareNotePolicy.swift */; };
27+
E40000000000000000000007 /* RansomwareNotePolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = E40000000000000000000005 /* RansomwareNotePolicy.swift */; };
2628
/* End PBXBuildFile section */
2729

2830
/* Begin PBXContainerItemProxy section */
@@ -113,6 +115,7 @@
113115
BB55CC11DDEEFF00AA220060 /* NetworkExtension.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NetworkExtension.framework; path = System/Library/Frameworks/NetworkExtension.framework; sourceTree = SDKROOT; };
114116
D10000000000000000000002 /* Nick Uninstaller.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Nick Uninstaller.app"; sourceTree = BUILT_PRODUCTS_DIR; };
115117
E40000000000000000000000 /* NetworkProtectionPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = NetworkProtectionPolicy.swift; path = Shared/NetworkProtectionPolicy.swift; sourceTree = SOURCE_ROOT; };
118+
E40000000000000000000005 /* RansomwareNotePolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RansomwareNotePolicy.swift; path = Shared/RansomwareNotePolicy.swift; sourceTree = SOURCE_ROOT; };
116119
E40000000000000000000003 /* ScamGuardian.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = ScamGuardian.swift; path = NickNetFilter/ScamGuardian.swift; sourceTree = SOURCE_ROOT; };
117120
/* End PBXFileReference section */
118121

@@ -266,6 +269,7 @@
266269
AA11223344556677AABB0005 /* YARAEngine.swift */,
267270
AA11223344556677AABB0006 /* YARAMatch.swift */,
268271
E40000000000000000000000 /* NetworkProtectionPolicy.swift */,
272+
E40000000000000000000005 /* RansomwareNotePolicy.swift */,
269273
E40000000000000000000003 /* ScamGuardian.swift */,
270274
);
271275
name = "Recovered References";
@@ -633,6 +637,7 @@
633637
isa = PBXSourcesBuildPhase;
634638
buildActionMask = 2147483647;
635639
files = (
640+
E40000000000000000000007 /* RansomwareNotePolicy.swift in Sources */,
636641
AA11223344556677AABB0015 /* YARAEngine.swift in Sources */,
637642
AA11223344556677AABB0016 /* YARAMatch.swift in Sources */,
638643
);
@@ -665,6 +670,7 @@
665670
buildActionMask = 2147483647;
666671
files = (
667672
E40000000000000000000001 /* NetworkProtectionPolicy.swift in Sources */,
673+
E40000000000000000000006 /* RansomwareNotePolicy.swift in Sources */,
668674
E40000000000000000000004 /* ScamGuardian.swift in Sources */,
669675
AA11223344556677AABB0011 /* ESEvent.swift in Sources */,
670676
AA11223344556677AABB0012 /* NickExtensionXPCProtocol.swift in Sources */,
@@ -743,7 +749,7 @@
743749
CLANG_WARN_UNREACHABLE_CODE = YES;
744750
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
745751
COPY_PHASE_STRIP = NO;
746-
CURRENT_PROJECT_VERSION = 405;
752+
CURRENT_PROJECT_VERSION = 408;
747753
DEBUG_INFORMATION_FORMAT = dwarf;
748754
ENABLE_STRICT_OBJC_MSGSEND = YES;
749755
ENABLE_TESTABILITY = YES;
@@ -868,7 +874,7 @@
868874
CLANG_WARN_UNREACHABLE_CODE = YES;
869875
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
870876
COPY_PHASE_STRIP = NO;
871-
CURRENT_PROJECT_VERSION = 405;
877+
CURRENT_PROJECT_VERSION = 408;
872878
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
873879
ENABLE_NS_ASSERTIONS = NO;
874880
ENABLE_STRICT_OBJC_MSGSEND = YES;
@@ -998,7 +1004,7 @@
9981004
CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
9991005
CODE_SIGN_ENTITLEMENTS = NickExtension/NickExtension.entitlements;
10001006
CODE_SIGN_STYLE = Automatic;
1001-
CURRENT_PROJECT_VERSION = 405;
1007+
CURRENT_PROJECT_VERSION = 408;
10021008
DEVELOPMENT_TEAM = UXGW5V3BY6;
10031009
ENABLE_HARDENED_RUNTIME = YES;
10041010
ENABLE_USER_SCRIPT_SANDBOXING = YES;
@@ -1055,7 +1061,7 @@
10551061
CODE_SIGN_IDENTITY = "Apple Development";
10561062
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Developer ID Application";
10571063
CODE_SIGN_STYLE = Manual;
1058-
CURRENT_PROJECT_VERSION = 405;
1064+
CURRENT_PROJECT_VERSION = 408;
10591065
DEVELOPMENT_TEAM = UXGW5V3BY6;
10601066
"DEVELOPMENT_TEAM[sdk=macosx*]" = UXGW5V3BY6;
10611067
ENABLE_HARDENED_RUNTIME = YES;
@@ -1129,7 +1135,7 @@
11291135
CODE_SIGN_ENTITLEMENTS = NickNetFilter/NickNetFilter.entitlements;
11301136
CODE_SIGN_IDENTITY = "Apple Development";
11311137
CODE_SIGN_STYLE = Automatic;
1132-
CURRENT_PROJECT_VERSION = 405;
1138+
CURRENT_PROJECT_VERSION = 408;
11331139
DEVELOPMENT_TEAM = UXGW5V3BY6;
11341140
ENABLE_APP_SANDBOX = NO;
11351141
ENABLE_HARDENED_RUNTIME = YES;
@@ -1152,7 +1158,7 @@
11521158
CODE_SIGN_ENTITLEMENTS = NickNetFilter/NickNetFilter.Release.entitlements;
11531159
CODE_SIGN_IDENTITY = "Developer ID Application";
11541160
CODE_SIGN_STYLE = Manual;
1155-
CURRENT_PROJECT_VERSION = 405;
1161+
CURRENT_PROJECT_VERSION = 408;
11561162
DEVELOPMENT_TEAM = UXGW5V3BY6;
11571163
ENABLE_APP_SANDBOX = NO;
11581164
ENABLE_HARDENED_RUNTIME = YES;
@@ -1176,7 +1182,7 @@
11761182
CODE_SIGN_IDENTITY = "Apple Development";
11771183
CODE_SIGN_STYLE = Automatic;
11781184
COMBINE_HIDPI_IMAGES = YES;
1179-
CURRENT_PROJECT_VERSION = 405;
1185+
CURRENT_PROJECT_VERSION = 408;
11801186
DEVELOPMENT_TEAM = UXGW5V3BY6;
11811187
ENABLE_APP_SANDBOX = NO;
11821188
ENABLE_HARDENED_RUNTIME = YES;
@@ -1204,7 +1210,7 @@
12041210
CODE_SIGN_IDENTITY = "Developer ID Application";
12051211
CODE_SIGN_STYLE = Manual;
12061212
COMBINE_HIDPI_IMAGES = YES;
1207-
CURRENT_PROJECT_VERSION = 405;
1213+
CURRENT_PROJECT_VERSION = 408;
12081214
DEVELOPMENT_TEAM = UXGW5V3BY6;
12091215
ENABLE_APP_SANDBOX = NO;
12101216
ENABLE_HARDENED_RUNTIME = YES;

Nick/App/AppDelegate.swift

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,17 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
4747
/// even when the main window is hidden.
4848
private var forceQuit = false
4949

50+
private var isRunningTests: Bool {
51+
let environment = ProcessInfo.processInfo.environment
52+
return environment["XCTestConfigurationFilePath"] != nil
53+
|| environment["XCTestBundlePath"] != nil
54+
|| environment["XCInjectBundleInto"] != nil
55+
|| environment["DYLD_INSERT_LIBRARIES"]?.contains("XCTest") == true
56+
|| NSClassFromString("XCTestCase") != nil
57+
|| Bundle.allBundles.contains { $0.bundlePath.hasSuffix(".xctest") }
58+
|| CommandLine.arguments.contains("-ApplePersistenceIgnoreState")
59+
}
60+
5061
/// Injected by `MainWindowView.onAppear`. Calls SwiftUI's `openSettings` environment
5162
/// action so the status-bar "Settings..." menu item opens the Settings scene through
5263
/// the official path instead of the private `showSettingsWindow:` selector.
@@ -74,17 +85,6 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
7485
// installed system extensions, and mutate persistent state while unit tests
7586
// are running. Keep the test host inert; individual tests construct only the
7687
// services they exercise.
77-
let environment = ProcessInfo.processInfo.environment
78-
let isRunningTests =
79-
environment["XCTestConfigurationFilePath"] != nil
80-
|| environment["XCTestBundlePath"] != nil
81-
|| environment["XCInjectBundleInto"] != nil
82-
|| environment["DYLD_INSERT_LIBRARIES"]?.contains("XCTest") == true
83-
|| NSClassFromString("XCTestCase") != nil
84-
|| Bundle.allBundles.contains { $0.bundlePath.hasSuffix(".xctest") }
85-
// Xcode's macOS XCTest host launches the app with this persistence
86-
// suppression argument before the XCTest bundle itself is visible.
87-
|| CommandLine.arguments.contains("-ApplePersistenceIgnoreState")
8888
if isRunningTests {
8989
return
9090
}
@@ -126,10 +126,12 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
126126
}
127127
Task { @MainActor in
128128
await networkProtection.refresh()
129-
engine.runFullScan()
130129
xpcClient.connect()
131130
let coord = MonitorCoordinator(engine: engine, correlator: ThreatCorrelator())
132131
coordinator = coord
132+
// The coordinator's first tick performs the initial full scan.
133+
// Starting another scan here duplicates process signature validation
134+
// and can saturate a CPU core during launch.
133135
coord.startRealTimePipeline()
134136
NotificationManager.shared.setup()
135137
NSApp.servicesProvider = NickServicesProvider()
@@ -358,6 +360,10 @@ final class AppDelegate: NSObject, NSApplicationDelegate {
358360
/// right-click menu (`forceQuit == true`), or (b) the main window is currently
359361
/// visible (i.e. ⌘Q is meaningful to the user).
360362
func applicationShouldTerminate(_: NSApplication) -> NSApplication.TerminateReply {
363+
// XCTest owns the lifecycle of its host process. Never apply Nick's
364+
// menu-bar "stay alive while hidden" policy to a test host, otherwise
365+
// xcodebuild waits forever after the final test has completed.
366+
if isRunningTests { return .terminateNow }
361367
if forceQuit { return .terminateNow }
362368
// canBecomeMain is unreliable during .accessory→.regular transitions; filter by
363369
// class instead. Prefer the titled "Nick" window over any other non-panel window.

0 commit comments

Comments
 (0)