Skip to content

Latest commit

 

History

6 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AppScope

Press Space to see what a macOS app is really doing.

license platform swift dependencies

AppScope is a macOS Quick Look preview extension: select any .app bundle in Finder, press Space, and instantly read its code signing, permission declarations, network behavior, filesystem scope, and a 7-dimension security radar chart — then trigger a deep scan for a full audit report. Tap the Bundle ID to copy it, or export a PNG audit card in one click.

Built entirely on Apple frameworks (Swift + SwiftUI + Security.framework + SQLite). Zero third-party dependencies, zero Process calls.

Features

  • Quick Look preview: Space on an .app for a second-level readout of signing type, notarization status, high-risk permissions, and a 4-dimension instant score.
  • 7-dimension security score: code signing / permissions / network / script quality / filesystem / data exfiltration / process manipulation, visualized on a radar chart — higher is riskier.
  • Deep scan: one click completes all 7 dimensions, adding script review (obfuscation / eval / download-execute) and process-manipulation detection.
  • One-tap copy: click the Bundle ID to copy it to the clipboard, with a lightweight toast.
  • One-click PNG export: renders a 2× retina audit card (score ring + radar + key metrics) to ~/Downloads.
  • CLI appscope: preview / scan / cache, with recursive directory scanning and JSON/Markdown reports.
  • Four-language i18n: Simplified Chinese / Traditional Chinese / English / Japanese, across UI, reports, and CLI.

Screenshots

AppScope preview AppScope preview

Quick start

Requirements

  • macOS 13.0+
  • Xcode (with xcodegen, used to generate the project from project.yml)

Install (build from source)

git clone <repo-url> && cd appscope

# Core libraries + CLI + tests (SwiftPM)
cd Core
swift build -c release
swift test                        # 125 tests, all green

# Host app + Quick Look extension (one-shot build + sign + install)
cd ../App
./build.sh Release                # installs to /Applications and registers the extension
# Signing identity resolution: $SIGN_IDENTITY env > App/signing.env > ad-hoc (local debugging only)

Once installed to /Applications and launched, press Space on any .app in Finder to preview it.

Usage

GUI: Space-preview in Finder → tap the Bundle ID to copy / tap "Export PNG" to save a card to ~/Downloads / tap "Deep Scan" for all 7 dimensions.

CLI:

appscope preview  "/Applications/iTerm.app"                # quick preview (4-dimension score)
appscope scan     "/Applications/iTerm.app" --output json  # deep scan (7 dimensions + script review)
appscope scan     /Applications --recursive                # recursive directory scan
appscope cache list | purge | clear                        # cache management
appscope --lang ja scan "/Applications/iTerm.app"          # i18n: zh-Hans / zh-Hant / en / ja

Engineering conventions (Quick Look lifecycle rules, extension resource budgets, logging and testing) live in AGENTS.md.

Architecture

Four targets share one pure-Swift core:

Target Kind Responsibility
AppScopeCore Swift library (no UI) Data collection + scoring engine + cache + report generation
AppScopeUI Swift library (SwiftUI) Preview UI: score ring / radar / cards / collapsible sections / export card
AppScopeCLI CLI tool appscope preview / scan / cache
AppScopeHost macOS host app (menu bar) Carries the Quick Look extension
AppScopeQL Quick Look preview extension (.appex) Renders the native SwiftUI preview

AppScopeCore layers by responsibility: collectors (Identity / Signature / Entitlement / Content / Network / Filesystem / Capability / Script / Process) → scoring engine → report rendering → SQLite cache, orchestrated by AppScopeAnalyzer (parallel collection via async let).

Data flow

Finder Space → QLPreviewingController.preparePreviewOfFile
  → AppScopeAnalyzer.quickScan (parallel: identity + signing + permissions + content)
  → network / filesystem (depend on content inventory)
  → RiskScoringEngine.evaluate (4-dimension instant score)
  → NSHostingView renders PreviewRootView (native SwiftUI)
  → deep-scan button → deepScan (7 dimensions + script review + process manipulation) → hot update

The 7-dimension scoring model

Each dimension is 0–3 (higher is riskier), total 0–21:

Dimension 0 low risk 1 medium 2 high 3 critical
Code signing Apple-signed Developer ID, not notarized Ad-hoc Unsigned
Permissions none declared read-only network + filesystem full disk / screen recording / accessibility
Network local only update check telemetry suspicious C2
Script quality no scripts few, readable many, unvalidated obfuscation / eval / download-execute
Filesystem self-contained user config user documents system paths
Data exfiltration no external traffic exfiltration pattern detected
Process manipulation none reads processes modifies other apps code injection

Risk levels: 🟢 0–4 low · 🟡 5–8 medium · 🟠 9–13 high · 🔴 14–21 critical. Quick preview scores only the first 4 dimensions (denominator 12); deep scan completes all 7 (denominator 21).

Scope boundaries (explicitly out of scope)

Capability Status Notes
Real-time behavior monitoring ❌ No No syscall hooking, no runtime network monitoring — that's EndpointSecurity / NetworkExtension territory; AppScope is static analysis only
App uninstall / cleanup ❌ No Avoids the risk of accidental deletion
Malware signatures / YARA ❌ No Static analysis + heuristic scoring suffices
Inter-app dependency analysis ❌ No No XPC call-chain tracing, no cross-process tracking
Finder icon badges ❌ v2 Deferred to avoid alarm-inducing permission prompts
Windows / Linux ports ❌ No Deeply tied to macOS Quick Look + codesign + plist

Implementation decisions (deviations from spec)

  1. Fully native rendering: the spec called for HTML/CSS + WKWebView; the implementation uses native SwiftUI views (NSHostingView), a Canvas-drawn radar, and SwiftUI animations. Dark mode, accessibility, and Reduce Motion are handled natively by the system.
  2. Zero Process calls: a Quick Look extension runs sandboxed and forbids NSTask/Process. The spec's spctl / strings were replaced with native equivalents — signing via SecCode, string extraction via a pure-Swift NativeStringScanner, quarantine via getxattr. Notarization is inferred from signing type + hardened-runtime flag.
  3. .qlgenerator.appex: the spec conflated .qlgenerator with QLPreviewingController — two different APIs. The implementation uses the modern Quick Look preview extension (com.apple.quicklook.preview, QLPreviewingController) embedded in the host app's PlugIns/.
  4. Type renames: DimensionRiskDimension, ProcessInfoProcessManipulationInfo, to avoid colliding with Foundation's NSDimension / ProcessInfo.
  5. Performance: endpoint extraction initially used NSRegularExpression over the whole file — 70 s on a 93 MB binary; switching to per-token string operations cut it to 4 s.
  6. Quick Look lifecycle (preview stability): Quick Look touches .view (firing viewDidLoad) before preparePreviewOfFile, and handler(nil) snapshots the root view immediately. Replacing self.view later breaks the ViewBridge XPC session (NSCocoaErrorDomain 4099) and fails the preview. So the view mounts once in loadView(), prepare never touches it, and UI state transitions through a @Published phase (loading / ready / error).
  7. SwiftUI layout contract: Layout.sizeThatFits must return a finite size for every proposal. The old FlowLayout returned {inf, …} under an unbounded proposal (always used for intrinsicContentSize), making AppKit throw NSInvalidArgumentException — 12/12 previews failed. Fixed by returning the content's natural width, plus disabling NSHostingView content-size constraints (sizingOptions = []) as defense in depth.
  8. Scan budgets: Electron-class apps ship 13k–24k scripts (Cursor / Kimi); scanning every file blows the quick-preview latency budget and the host kills the extension. Script scans are capped (Network / Filesystem / Process 200 each, Script 2000), with scripts=scanned/total in the logs to make truncation observable — small apps are unaffected.
  9. PNG export via AppKit bitmap snapshot: not SwiftUI ImageRenderer — its offscreen render can't capture Canvas content (the radar is Metal-drawn), returning a nil nsImage and failing the export. Uses NSHostingView.bitmapImageRepForCachingDisplay + cacheDisplay (the same path as the appscope-render tool), which captures Canvas content fully.

Localization

UI copy ships in Simplified Chinese / Traditional Chinese / English / Japanese, carried by a self-contained static table in AppScopeCore/Support/L10n.swift (no resource bundle dependency), auto-selected from the system language:

  • The Quick Look preview UI and audit reports (readable fields in Markdown/JSON) follow the system language.
  • The CLI switches explicitly via --lang <zh-Hans|zh-Hant|en|ja>, defaulting to the system language.
  • Core / CLI / UI share one copy table; L10nTests asserts key entries per language to catch omissions.

Testing

Core/Tests/AppScopeCoreTests/ holds 125 XCTest cases covering the scoring-engine rule matrix, collector pure functions, Mach-O parsing, report render round-trips, SQLite cache, native string extraction, four-language copy (L10nTests), and end-to-end analyzer runs (temporary .app fixtures + injected doubles).

cd Core && swift test

Directory layout

appscope/
├── Core/                    # SwiftPM package: AppScopeCore + AppScopeUI + AppScopeCLI + AppScopeRender + tests
├── AppIcon.png                                   # app icon source (1024×1024)
├── App/
│   ├── AppScopeHost/AppIcon.icns                 # icon generated from AppIcon.png
│   ├── build.sh                                  # one-shot build + sign + install (identity injection)
│   └── project.yml                               # single source of truth for the project (xcodegen)
├── AGENTS.md                                     # engineering conventions (Quick Look rules / budgets / logging / tests)
├── prd.md / tech-design.md / ux-spec.md / DESIGN.md / basic-capabilities-audit.md  # spec documents
└── README.md

Contributing

Issues and pull requests are welcome. Read AGENTS.md first (build commands, test conventions, Quick Look lifecycle rules). Before opening a PR, ensure swift test is green and ./build.sh Release succeeds.

License

MIT © 2026 nanzhi

About

Press Space on any macOS app to see its security — 7-dimension risk score, signing, permissions, network, filesystem.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages