# Rsync Manager — Direct Distribution Release Rsync Manager is designed for direct macOS distribution rather than the Mac App Store because it intentionally launches `rsync`/`ssh` and accesses user-selected arbitrary paths. ## Release security baseline - Developer ID Application signing. - Hardened Runtime enabled. - App Sandbox intentionally disabled for this product architecture. - No Hardened Runtime exception entitlements. - SSH host-key verification is never disabled. - SSH uses BatchMode, connection timeout and keepalive limits. - Password storage/authentication is not supported; use a private key or the macOS SSH agent. - Advanced rsync arguments that can replace the SSH transport, run remote commands, load passwords, read/write arbitrary option/list/log/batch files or bypass controlled delete handling are rejected. - Scheduled/file-watch `--delete` requires explicit per-job authorisation. - Run logs are sanitised and capped before storage and expire according to Settings. - `PrivacyInfo.xcprivacy` declares no tracking/no collected data and the UserDefaults required-reason API. ## Mandatory preflight Before every release archive, run on the release Mac: ```bash ./Scripts/release-preflight.sh ``` This performs the static security policy checks, validates the privacy manifest, and performs a clean unsigned **Release** build with the installed macOS SDK so compiler/typecheck warnings or SDK incompatibilities are caught before signing. ## Archive In Xcode select **Any Mac (Apple Silicon, Intel)**, choose **Product > Archive**, then distribute using **Developer ID**. Alternatively: ```bash xcodebuild -project RsyncManager.xcodeproj -scheme RsyncManager -configuration Release -archivePath build/RsyncManager.xcarchive archive ``` Choose your Developer ID Application certificate/team in Xcode signing settings before archiving. ## Verify signature ```bash codesign --verify --deep --strict --verbose=2 /path/to/RsyncManager.app codesign -d --entitlements :- /path/to/RsyncManager.app ``` The Release build should show Hardened Runtime and should not contain `com.apple.security.get-task-allow`. ## Notarise Store notarisation credentials in a Keychain profile once: ```bash xcrun notarytool store-credentials "RsyncManagerNotary" ``` Submit a signed ZIP/DMG/PKG: ```bash ditto -c -k --keepParent /path/to/RsyncManager.app RsyncManager.zip xcrun notarytool submit RsyncManager.zip --keychain-profile "RsyncManagerNotary" --wait ``` Staple and validate: ```bash xcrun stapler staple /path/to/RsyncManager.app xcrun stapler validate /path/to/RsyncManager.app spctl --assess --type execute --verbose=4 /path/to/RsyncManager.app ``` ## Pre-release functional security tests 1. Local source nested inside destination is rejected. 2. Local destination nested inside source is rejected. 3. SSH host beginning with `-` is rejected. 4. SSH username containing spaces/control characters is rejected. 5. A `.pub` key cannot be selected as the effective private key. 6. Advanced arguments `-e`, `--rsh`, `--rsync-path`, `--password-file`, `--files-from`, `--log-file`, `--write-batch`, `--remove-source-files`, `--delete*` and `-M` are rejected, and malformed quoting is rejected. 7. Remote destination shell metacharacters are rejected before rsync is launched. 8. Scheduled/watch job using `--delete` cannot run until **Allow unattended delete** is explicitly enabled. 9. SSH to a previously unknown host does not silently bypass host-key checking. 10. Scheduled SSH job with unavailable authentication fails rather than prompting indefinitely. 11. History expiry removes old completed runs according to Settings. 12. A failed persistent SwiftData store opens Recovery Mode instead of immediately crashing. 13. `Scripts/security-check.sh` passes before every signed build.