Skip to content

Commit 28b1b77

Browse files
committed
Release Nick 4.0 security and distribution updates
1 parent 0f072fb commit 28b1b77

109 files changed

Lines changed: 24048 additions & 1410 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 57 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,58 +6,100 @@ on:
66
pull_request:
77
branches: [main]
88

9+
permissions:
10+
contents: read
11+
912
jobs:
1013
build-and-test:
1114
runs-on: macos-26
12-
timeout-minutes: 30
15+
timeout-minutes: 45
16+
env:
17+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
1318

1419
steps:
15-
- uses: actions/checkout@v4
20+
- name: Check out source
21+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
1622
with:
23+
fetch-depth: 0
1724
lfs: true
1825

1926
- name: Select Xcode
2027
run: |
21-
ls /Applications/ | grep Xcode
22-
sudo xcode-select -s "$(ls -d /Applications/Xcode*.app | sort -V | tail -1)"
28+
XCODE_PATH="$(find /Applications -maxdepth 1 -type d -name 'Xcode*.app' | sort -V | tail -1)"
29+
test -n "$XCODE_PATH"
30+
sudo xcode-select -s "$XCODE_PATH"
2331
xcodebuild -version
2432
2533
- name: Build Nick
2634
run: |
27-
xcodebuild build -scheme Nick \
35+
xcodebuild build \
36+
-project Nick.xcodeproj \
37+
-scheme Nick \
2838
-destination "platform=macOS" \
2939
CODE_SIGN_IDENTITY="" \
3040
CODE_SIGNING_REQUIRED=NO \
3141
CODE_SIGNING_ALLOWED=NO
3242
33-
- name: Build NickHelper
43+
- name: Build shipping components
3444
run: |
35-
xcodebuild build -scheme NickHelper \
36-
-destination "platform=macOS" \
37-
CODE_SIGN_IDENTITY="" \
38-
CODE_SIGNING_REQUIRED=NO \
39-
CODE_SIGNING_ALLOWED=NO
45+
for scheme in NickExtension NickNetFilter NickHelper NickUninstaller; do
46+
xcodebuild build \
47+
-project Nick.xcodeproj \
48+
-scheme "$scheme" \
49+
-destination "platform=macOS" \
50+
CODE_SIGN_IDENTITY="" \
51+
CODE_SIGNING_REQUIRED=NO \
52+
CODE_SIGNING_ALLOWED=NO
53+
done
4054
4155
- name: Run Tests
4256
run: |
43-
xcodebuild test -scheme Nick \
57+
rm -rf TestResults.xcresult
58+
xcodebuild test \
59+
-project Nick.xcodeproj \
60+
-scheme Nick \
4461
-destination "platform=macOS" \
62+
-enableCodeCoverage YES \
63+
-resultBundlePath TestResults.xcresult \
4564
CODE_SIGN_IDENTITY="" \
4665
CODE_SIGNING_REQUIRED=NO \
47-
CODE_SIGNING_ALLOWED=NO \
48-
-resultBundlePath TestResults.xcresult
66+
CODE_SIGNING_ALLOWED=NO
4967
5068
- name: Test Summary
5169
if: always()
5270
run: |
5371
xcrun xcresulttool get test-results summary \
5472
--path TestResults.xcresult 2>/dev/null || echo "Test results unavailable"
5573
56-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
74+
- name: Upload Xcode result bundle
75+
if: always()
76+
uses: actions/upload-artifact@v4
77+
with:
78+
name: TestResults
79+
path: TestResults.xcresult
80+
if-no-files-found: warn
81+
retention-days: 14
5782

5883
- name: Upload coverage reports to Codecov
5984
uses: codecov/codecov-action@18283e04ce6e62d37312384ff67231eb8fd56d24 # v5.4.3
6085
with:
6186
token: ${{ secrets.CODECOV_TOKEN }}
87+
fail_ci_if_error: true
88+
flags: macos
6289
xcode: true
6390
xcode_archive_path: TestResults.xcresult
91+
92+
- name: Convert coverage for SonarCloud
93+
if: env.SONAR_TOKEN != ''
94+
run: |
95+
./Scripts/xccov-to-sonarqube.sh TestResults.xcresult > sonar-coverage.xml
96+
test -s sonar-coverage.xml
97+
98+
- name: Run SonarCloud analysis
99+
if: env.SONAR_TOKEN != ''
100+
uses: SonarSource/sonarqube-scan-action@v7
101+
env:
102+
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
103+
with:
104+
args: >
105+
-Dsonar.qualitygate.wait=true

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@ build/
99
*.moved-aside
1010
*.hmap
1111
*.ipa
12+
*.pkg
13+
*.dmg
1214
*.dSYM.zip
1315
*.dSYM
16+
*.xcresult/
17+
sonar-coverage.xml
1418

1519
# Swift Package Manager
1620
.build/

ARCHITECTURE.md

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,53 @@
22

33
This document describes Nick's internal architecture, detection methodology, and security model. It's intended for contributors, security auditors, and anyone who wants to understand how Nick works before trusting it on their Mac.
44

5+
## Version 4 architecture
6+
7+
Nick 4.0 separates user interface, local monitoring, privileged Endpoint
8+
Security observation, and optional network enforcement:
9+
10+
```text
11+
Nick.app
12+
├── SecurityEngine and MonitorCoordinator
13+
├── local process, persistence, connection, capture, and system-audit monitors
14+
├── Smart Scan, Alerts, Timeline, Quarantine, Reports, and setup
15+
├── ExtensionXPCClient
16+
└── NetworkProtectionManager
17+
18+
NickExtension.systemextension
19+
├── EndpointSecurityClient
20+
├── FileScanner and vendored libyara 4.5.5
21+
├── EmailAttachmentMonitor
22+
├── RansomwareDetector and FileIntegrityMonitor
23+
├── Behavioral and privacy event handling
24+
└── authenticated XPCServer
25+
26+
NickNetFilter.systemextension
27+
├── FilterDataProvider
28+
├── deterministic NetworkProtectionPolicy
29+
├── ScamGuardian
30+
├── signed NetworkBlocklist envelope validation
31+
└── bounded privacy-safe health and block-event persistence
32+
```
33+
34+
The main app never treats an installed bundle or saved preference as proof that
35+
a protection is working. System-extension and Network Extension rows become
36+
healthy only after current runtime state is verified.
37+
538
## Design Principles
639

740
1. **Defense in depth through correlation.** Any single signal (an unsigned binary, an outbound connection, a new LaunchAgent) could be benign. Nick's value is in correlating signals across monitors to surface genuinely suspicious behavior while minimizing false positives.
841

942
2. **Minimal attack surface.** Nick uses zero third-party Swift dependencies. The privileged helper exposes the smallest possible XPC API. The app requests only the permissions it needs.
1043

11-
3. **Offline by default.** Nick makes no network connections unless the user explicitly enables rule update checks. All scanning, analysis, and AI inference runs locally on the Mac.
44+
3. **Local analysis.** Scanning, correlation, and model inference run locally.
45+
Network access is limited to explicit product functions such as Sparkle
46+
update checks and future signed rule retrieval.
1247

13-
4. **Separation of concerns.** The detection engine (`Core/`) has no UI dependency and can be tested, audited, and embedded independently. The UI (`App/`) is a thin layer over the engine. The privileged helper (`Helper/`) is isolated behind XPC.
48+
4. **Separation of concerns.** The detection engine (`Nick/Core/`) has no UI
49+
dependency. The UI (`Nick/App/`) presents engine state. Endpoint Security
50+
and network enforcement live in separate system extensions, and privileged
51+
operations are isolated behind narrow authenticated XPC protocols.
1452

1553
---
1654

CONTRIBUTING.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,15 @@ Thanks for your interest in making Mac security better. Nick is built by the com
44

55
## Ways to Contribute
66

7-
### 🐛 Bug Reports & False Positives
7+
### Bug reports and false positives
88
Found a bug or a false positive detection? Open an [issue](https://github.com/EhsanAzish80/Nick/issues/new) with:
99
- macOS version and Mac model
1010
- Nick version
1111
- Steps to reproduce
1212
- Expected vs actual behavior
1313
- For false positives: the process/file that was flagged and why you believe it's safe
1414

15-
### 🧬 YARA Rules
15+
### YARA rules
1616
Submit new detection rules for macOS-specific threats:
1717

1818
1. Place your rule in the appropriate directory under `Rules/` (stealers, backdoors, adware, ransomware, or community)
@@ -36,7 +36,7 @@ Submit new detection rules for macOS-specific threats:
3636
4. Test your rule against known-good files to minimize false positives
3737
5. Open a PR with the rule and a brief description of the threat it detects
3838

39-
### 🧠 Behavioral Scoring Model
39+
### Behavioral scoring model
4040
The CoreML threat scoring model can be improved with:
4141
- New training data (anonymized behavioral patterns from confirmed threats)
4242
- Feature engineering suggestions (new signals to correlate)
@@ -45,15 +45,16 @@ The CoreML threat scoring model can be improved with:
4545

4646
See `Models/Training/` for the training pipeline and data format.
4747

48-
### 💻 Code Contributions
48+
### Code contributions
4949
1. Fork the repository
5050
2. Create a feature branch: `git checkout -b feature/your-feature`
5151
3. Make your changes
52-
4. Run tests: `xcodebuild test -scheme NickTests`
52+
4. Run the full build and coverage command in
53+
[Documentation/DEVELOPMENT.md](Documentation/DEVELOPMENT.md)
5354
5. Commit with a clear message: `git commit -m "Add SSH tunnel detection to NetworkAnalyzer"`
5455
6. Push and open a PR
5556

56-
### 📖 Documentation
57+
### Documentation
5758
- Fix typos, clarify explanations, add examples
5859
- Document detection logic for specific threat types
5960
- Write guides for common use cases
@@ -68,16 +69,22 @@ See `Models/Training/` for the training pipeline and data format.
6869
- All public APIs must have documentation comments
6970

7071
### Architecture Rules
71-
- `Core/` must have **zero** UI dependencies — it's a pure detection engine
72-
- `App/` depends on `Core/` but never the reverse
73-
- `Helper/` has the smallest possible API surface — every XPC method must be justified
72+
- `Nick/Core/` must have no UI dependencies; it is the testable detection engine.
73+
- `Nick/App/` depends on `Nick/Core/`, never the reverse.
74+
- Privileged and extension XPC protocols must expose the smallest justified API.
75+
- The main app must authenticate extension health before reporting protection.
76+
- Network enforcement must fail open when configuration is unavailable.
7477
- No third-party Swift packages. Apple frameworks and POSIX APIs only.
75-
- `libyara` is the sole C dependency and must remain vendored
78+
- Vendored libyara updates must record the exact upstream version and pass the
79+
complete false-positive test suite.
7680

7781
### Testing
7882
- Every detection capability must have corresponding unit tests
7983
- Include both positive tests (does it catch the threat?) and negative tests (does it avoid false positives?)
8084
- Integration tests should use realistic but safe mock data — never include actual malware in the repo
85+
- A system-extension build is not deployment proof. Release claims require the
86+
clean-Mac checks in
87+
[Documentation/RELEASE_CHECKLIST.md](Documentation/RELEASE_CHECKLIST.md).
8188

8289
## Pull Request Process
8390

Documentation/DEVELOPMENT.md

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Development and CI
2+
3+
## Supported toolchain
4+
5+
- macOS 26 or later.
6+
- Xcode 26 or later.
7+
- Swift 6.
8+
- The checked-in `Nick.xcodeproj` is authoritative.
9+
10+
`project.yml` is retained as project-generation documentation but does not
11+
fully represent the filesystem-synchronized groups and release signing state.
12+
Do not regenerate the project for ordinary source-file changes.
13+
14+
## Local build
15+
16+
```sh
17+
xcodebuild build \
18+
-project Nick.xcodeproj \
19+
-scheme Nick \
20+
-destination "platform=macOS" \
21+
CODE_SIGN_IDENTITY="" \
22+
CODE_SIGNING_REQUIRED=NO \
23+
CODE_SIGNING_ALLOWED=NO
24+
```
25+
26+
This validates compilation without requiring the maintainer's restricted
27+
entitlements. It does not validate system-extension activation.
28+
29+
## Tests and coverage
30+
31+
```sh
32+
rm -rf TestResults.xcresult
33+
34+
xcodebuild test \
35+
-project Nick.xcodeproj \
36+
-scheme Nick \
37+
-destination "platform=macOS" \
38+
-enableCodeCoverage YES \
39+
-resultBundlePath TestResults.xcresult \
40+
CODE_SIGN_IDENTITY="" \
41+
CODE_SIGNING_REQUIRED=NO \
42+
CODE_SIGNING_ALLOWED=NO
43+
```
44+
45+
Inspect the summary:
46+
47+
```sh
48+
xcrun xcresulttool get test-results summary --path TestResults.xcresult
49+
```
50+
51+
Generate SonarCloud generic coverage:
52+
53+
```sh
54+
./Scripts/xccov-to-sonarqube.sh TestResults.xcresult > sonar-coverage.xml
55+
```
56+
57+
## CI quality gates
58+
59+
The GitHub workflow:
60+
61+
1. Checks out full history and Git LFS objects.
62+
2. Selects the newest installed Xcode.
63+
3. Builds Nick, NickExtension, NickNetFilter, NickHelper, and NickUninstaller
64+
through the Nick scheme.
65+
4. Runs unit and integration tests with Xcode coverage enabled.
66+
5. Uploads the result bundle as a diagnostic artifact.
67+
6. Uploads coverage to Codecov.
68+
7. Converts coverage and runs SonarCloud analysis when `SONAR_TOKEN` exists.
69+
70+
Configure these repository secrets:
71+
72+
- `CODECOV_TOKEN`
73+
- `SONAR_TOKEN`
74+
75+
In SonarCloud, disable Automatic Analysis. The repository uses CI-based
76+
analysis so test coverage is attached to the same commit and pull request.
77+
78+
## Static-analysis scope
79+
80+
`sonar-project.properties` includes application, extension, helper, shared, and
81+
packaging source. Tests are classified separately. Vendored YARA headers and
82+
static libraries, generated build products, packages, disk images, Xcode result
83+
bundles, and Xcode user state are excluded.
84+
85+
## Before requesting review
86+
87+
```sh
88+
git diff --check
89+
git status --short
90+
```
91+
92+
Then run the full test command above. Document any test that is skipped because
93+
the runner lacks a macOS service. A successful unsigned build is not a
94+
substitute for the clean-Mac system-extension matrix.
95+
96+
## Signed runtime validation
97+
98+
For a release candidate:
99+
100+
1. Restart to clear system extensions waiting for uninstall.
101+
2. Install only the current notarized package.
102+
3. Confirm the installed app and both system extensions have the intended
103+
version and build.
104+
4. Confirm fresh Endpoint Security and Network Filter health files.
105+
5. Verify a normal website is allowed and the reserved Scam Guardian test
106+
destination is blocked.
107+
6. Test an Email Guard fixture, quarantine, restore, update, and uninstall.
108+
7. Observe idle CPU, memory, and logs for at least ten minutes.

0 commit comments

Comments
 (0)