From 37eba131744ac5be20c6e0f4f072606c06695110 Mon Sep 17 00:00:00 2001 From: Andy Bold Date: Sun, 8 Feb 2026 19:57:32 +0000 Subject: [PATCH] docs: version 1.1.0 release documentation and signing infrastructure Update all documentation and version to reflect v1.1.0 release with comprehensive code signing infrastructure and new features. Version Updates: - Bump app version from 1.0 to 1.1.0 in Xcode project - Add version badge to README New Documentation: - CHANGELOG.md: Complete version history with Keep a Changelog format - SIGNED_RELEASE_GUIDE.md: Complete guide for signed releases with notarization - docs/CODE_SIGNING_GUIDE.md: Technical reference for code signing and verification Infrastructure Updates: - Makefile: Add signed build targets (release-signed, dmg-signed, notarize) - scripts/check-signing.sh: Automated code signing verification tool - Enhanced help documentation with all environment variables README Updates: - Document container creation wizard (7-step guided process) - Document batch operations for multiple containers - Document enhanced statistics dashboard with live charts - Update release build section with signed/notarized workflows - Add comprehensive build target documentation - Update component list with all new files (wizard, animations, etc.) - Update contributing section with completed features - Update roadmap to reflect v1.1.0 (February 2026) - Add new documentation links for signing guides Features Documented in v1.1.0: - Container creation wizard with custom image support - Batch operations with multi-select - Enhanced statistics with CPU, memory, network, disk I/O charts - Code signing and notarization workflow - Animation preferences with accessibility support - Build automation improvements Code Signing Infrastructure: - Developer ID Application signing support - Hardened runtime flags - DMG signing with timestamps - Apple notarization workflow - Automated verification scripts Build System: - make dmg: Unsigned development builds - make dmg-signed: Signed distribution builds with Developer ID - make notarize: Submit for Apple notarization - make check-signing: Verify signing and notarization status - make upload-release: Create GitHub draft release Co-Authored-By: Claude Sonnet 4.5 --- CHANGELOG.md | 111 +++++++ Makefile | 104 ++++++- README.md | 97 +++++-- SIGNED_RELEASE_GUIDE.md | 246 ++++++++++++++++ container-manager.xcodeproj/project.pbxproj | 12 +- docs/CODE_SIGNING_GUIDE.md | 306 ++++++++++++++++++++ scripts/check-signing.sh | 152 ++++++++++ 7 files changed, 990 insertions(+), 38 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 SIGNED_RELEASE_GUIDE.md create mode 100644 docs/CODE_SIGNING_GUIDE.md create mode 100755 scripts/check-signing.sh diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..191a87b --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,111 @@ +# Changelog + +All notable changes to Container Manager will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [1.1.0] - 2026-02-08 + +### Added +- **Container Creation Wizard**: 7-step guided process for creating new containers + - Image selection with search and custom image support + - Basic configuration (name, command) + - Port mapping configuration + - Volume mount setup + - Environment variable management + - Network configuration + - Configuration review and confirmation +- **Batch Operations**: Multi-select containers for bulk operations + - Select multiple containers with checkboxes + - Bulk start, stop, restart, or remove + - Batch actions toolbar with operation buttons +- **Enhanced Statistics Dashboard**: Real-time monitoring with live charts + - CPU usage tracking with delta calculations + - Memory usage visualization + - Network I/O monitoring (sent/received) + - Disk I/O tracking (read/write) + - Time range selection (1 minute to 1 hour) + - Historical data collection (up to 6 hours) +- **Code Signing and Release Infrastructure** + - Developer ID Application signing + - Hardened runtime support + - DMG signing with timestamps + - Notarization workflow with Apple + - Automated verification scripts + - Complete signing documentation +- **Animation Preferences**: Accessibility-aware animation controls + - Master animation toggle + - Reduce motion support (app and system) + - Configurable loading indicators + - Compact mode for reduced spacing + - Automatic macOS accessibility integration + +### Changed +- Improved stats collection efficiency with background processing +- Enhanced container list with better multi-select UX +- Updated build system with signed and unsigned build targets +- Simplified CI/CD to build validation only + +### Fixed +- Stats collection no longer blocks UI thread +- Container creation properly handles custom image names +- Removed unsupported options for Apple's container tool +- Better error messages for container operations +- UI tests no longer require code signing in CI + +### Documentation +- Added `SIGNED_RELEASE_GUIDE.md` - Complete signing and notarization guide +- Added `docs/CODE_SIGNING_GUIDE.md` - Technical reference for code signing +- Updated `README.md` with new features and version 1.1.0 +- Enhanced Makefile with comprehensive help and new targets +- Created `CHANGELOG.md` for version history tracking + +## [1.0.0] - 2026-01-XX + +### Added +- Initial release with full desktop application +- Menu bar mode for lightweight monitoring +- Desktop app mode for comprehensive management +- Real-time container monitoring +- Container operations (start, stop, restart, remove) +- Service control (start/stop container service) +- Multi-section sidebar navigation + - Containers view with list/grid modes + - Images management + - Volumes management + - Networks management + - Statistics dashboard + - Settings interface +- Inspector panel for detailed container information +- Auto-refresh with smart update detection +- Keyboard shortcuts for common operations +- Settings and preferences +- Support for Apple's container tool + +### Technical Features +- Built with Swift and SwiftUI +- Native macOS 14.0+ support +- Dual-mode operation (menu bar + desktop) +- Efficient polling with change detection +- Thread-safe stats collection +- Flexible command parsing +- Multi-command fallback for compatibility + +--- + +## Release Notes Format + +Each release includes: +- **Added**: New features +- **Changed**: Changes to existing functionality +- **Deprecated**: Soon-to-be removed features +- **Removed**: Removed features +- **Fixed**: Bug fixes +- **Security**: Security improvements +- **Documentation**: Documentation updates + +--- + +[1.1.0]: https://github.com/yourusername/container-manager/compare/v1.0.0...v1.1.0 +[1.0.0]: https://github.com/yourusername/container-manager/releases/tag/v1.0.0 diff --git a/Makefile b/Makefile index 45d27ac..f236905 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: help build clean test dmg release install upload-release release-workflow +.PHONY: help build clean test dmg release release-signed dmg-signed install upload-release release-workflow check-signing notarize # Default target help: @@ -8,19 +8,25 @@ help: @echo "" @echo "Targets:" @echo " build Build the app (debug)" - @echo " release Build the app (release)" + @echo " release Build the app (release, unsigned)" + @echo " release-signed Build the app (release, signed with Developer ID)" @echo " test Run tests" - @echo " dmg Create DMG package" + @echo " dmg Create DMG package (unsigned)" + @echo " dmg-signed Create signed DMG package" @echo " clean Clean build artifacts" @echo " install Install to /Applications" @echo " run Build and run the app" @echo " tag Create a git tag" @echo " upload-release Upload DMG to GitHub (requires VERSION=v1.0.0)" @echo " release-workflow Complete release: build + package + upload" + @echo " check-signing Check code signing status of DMG" + @echo " notarize Submit DMG for notarization (requires APPLE_ID and TEAM_ID)" @echo "" @echo "Environment Variables:" @echo " VERSION Version tag for release (e.g., v1.0.0)" - @echo " SIGNING_IDENTITY Code signing identity (optional)" + @echo " SIGNING_IDENTITY Code signing identity (default: Developer ID Application: Andrew Bold)" + @echo " APPLE_ID Apple ID email for notarization" + @echo " TEAM_ID Team ID for notarization (default: 6Y922224CW)" @echo "" # Build in debug mode @@ -31,9 +37,9 @@ build: -configuration Debug \ -derivedDataPath ./build -# Build in release mode +# Build in release mode (unsigned) release: - @echo "πŸ”¨ Building Container Manager (Release)..." + @echo "πŸ”¨ Building Container Manager (Release - Unsigned)..." xcodebuild clean build \ -scheme container-manager \ -configuration Release \ @@ -42,6 +48,21 @@ release: CODE_SIGNING_REQUIRED=NO \ CODE_SIGNING_ALLOWED=NO +# Build in release mode (signed with Developer ID) +release-signed: + @echo "πŸ”¨ Building Container Manager (Release - Signed)..." + @SIGNING_ID="$${SIGNING_IDENTITY:-Developer ID Application: Andrew Bold (6Y922224CW)}"; \ + echo "πŸ“ Using signing identity: $$SIGNING_ID"; \ + xcodebuild clean build \ + -scheme container-manager \ + -configuration Release \ + -derivedDataPath ./build \ + CODE_SIGN_IDENTITY="$$SIGNING_ID" \ + CODE_SIGN_STYLE=Manual \ + DEVELOPMENT_TEAM=6Y922224CW \ + OTHER_CODE_SIGN_FLAGS="--timestamp --options runtime" + @echo "βœ… Signed build complete" + # Run tests test: @echo "πŸ§ͺ Running tests..." @@ -49,9 +70,9 @@ test: -scheme container-manager \ -destination 'platform=macOS' -# Create DMG +# Create DMG (unsigned) dmg: release - @echo "πŸ“¦ Creating DMG..." + @echo "πŸ“¦ Creating DMG (unsigned)..." @chmod +x scripts/create-dmg.sh @./scripts/create-dmg.sh @echo "πŸ”— Creating container-manager.dmg symlink for upload..." @@ -59,6 +80,38 @@ dmg: release @ln -s $$(ls -t container-manager-*.dmg | head -n1) container-manager.dmg @echo "βœ… DMG ready: container-manager.dmg -> $$(readlink container-manager.dmg)" +# Create signed DMG (for distribution) +dmg-signed: release-signed + @echo "πŸ“¦ Creating signed DMG..." + @APP_PATH=$$(find ./build -name "container-manager.app" -type d | head -n 1); \ + if [ -z "$$APP_PATH" ]; then \ + echo "❌ Signed app not found. Run 'make release-signed' first"; \ + exit 1; \ + fi; \ + VERSION="signed-$$(date +%Y%m%d-%H%M)"; \ + DMG_NAME="container-manager-$$VERSION.dmg"; \ + echo "πŸ“¦ Packaging signed app into DMG..."; \ + rm -rf dmg_contents/; \ + mkdir -p dmg_contents/; \ + cp -R "$$APP_PATH" dmg_contents/; \ + hdiutil create -volname "Container Manager" -srcfolder dmg_contents -ov -format UDZO "$$DMG_NAME"; \ + rm -rf dmg_contents/; \ + echo "πŸ” Signing DMG..."; \ + SIGNING_ID="$${SIGNING_IDENTITY:-Developer ID Application: Andrew Bold (6Y922224CW)}"; \ + codesign --sign "$$SIGNING_ID" \ + --timestamp \ + --options runtime \ + "$$DMG_NAME"; \ + echo "πŸ”— Creating container-manager.dmg symlink..."; \ + rm -f container-manager.dmg; \ + ln -s "$$DMG_NAME" container-manager.dmg; \ + echo "βœ… Signed DMG ready: container-manager.dmg -> $$DMG_NAME" + @echo "" + @echo "Next steps:" + @echo " 1. Verify signing: make check-signing" + @echo " 2. Notarize: make notarize APPLE_ID=your-email@example.com" + @echo " 3. Upload: make upload-release VERSION=v1.0.0" + # Clean build artifacts clean: @echo "🧹 Cleaning build artifacts..." @@ -142,3 +195,38 @@ release-workflow: echo ""; \ echo "βœ… Release workflow complete!"; \ echo "πŸ”— Go to GitHub to review and publish the draft release" + +# Check code signing status +check-signing: + @if [ ! -f "container-manager.dmg" ]; then \ + echo "❌ DMG not found. Run 'make dmg' first"; \ + exit 1; \ + fi + @chmod +x scripts/check-signing.sh + @./scripts/check-signing.sh container-manager.dmg + +# Notarize DMG with Apple +notarize: + @if [ -z "$(APPLE_ID)" ]; then \ + echo "❌ APPLE_ID not set. Usage: make notarize APPLE_ID=your-email@example.com"; \ + exit 1; \ + fi + @if [ ! -f "container-manager.dmg" ]; then \ + echo "❌ DMG not found. Run 'make dmg-signed' first"; \ + exit 1; \ + fi + @echo "🍎 Submitting DMG for notarization..." + @echo " This will use the notarytool keychain profile if configured" + @echo " Or prompt for app-specific password if not configured" + @echo "" + @TEAM=$${TEAM_ID:-6Y922224CW}; \ + xcrun notarytool submit container-manager.dmg \ + --apple-id "$(APPLE_ID)" \ + --team-id "$$TEAM" \ + --wait + @echo "" + @echo "🎫 Stapling notarization ticket to DMG..." + @xcrun stapler staple container-manager.dmg + @echo "" + @echo "βœ… Notarization complete!" + @echo " Run 'make check-signing' to verify" diff --git a/README.md b/README.md index 91228af..a8c473f 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,7 @@ A native macOS application for monitoring and managing containers. Built with Sw ![macOS](https://img.shields.io/badge/macOS-14.0+-blue) ![Swift](https://img.shields.io/badge/Swift-5.9+-orange) ![SwiftUI](https://img.shields.io/badge/SwiftUI-native-green) +![Version](https://img.shields.io/badge/version-1.1.0-brightgreen) ## πŸ“Έ Screenshots @@ -59,7 +60,10 @@ Press `⌘M` to switch between modes! - **Menu Bar App** - Lives in your menu bar, hidden from Dock and App Switcher - **Container Monitoring** - Real-time monitoring of all containers (running and stopped) - **Container Management** - Start, stop, restart, and remove containers +- **Container Creation** - Wizard-guided container creation with step-by-step configuration +- **Batch Operations** - Multi-select containers for bulk start, stop, restart, or remove - **Service Control** - Start and stop the container service +- **Real-time Statistics** - CPU, memory, network, and disk I/O monitoring with live charts - **Auto-refresh** - Updates every 10 seconds automatically - **Smart Updates** - Only refreshes when actual changes occur @@ -83,6 +87,15 @@ Press `⌘M` to switch between modes! - **Stop** - Stop running containers - **Restart** - Restart containers - **Remove** - Delete containers (with confirmation) +- **Batch Actions** - Select multiple containers for bulk operations +- **Create Container** - 7-step wizard for new container creation + - Image selection with search and custom image support + - Basic configuration (name, command) + - Port mapping configuration + - Volume mount setup + - Environment variable management + - Network configuration + - Configuration review and confirmation ### ⌨️ Keyboard Shortcuts - **⌘M** - Open Manager Window (Desktop App) @@ -125,19 +138,29 @@ After building: ### Creating a Release Build -We use a local build system for releases (no CI/CD required): +We use a local build system with proper code signing for releases: ```bash -# One-command release workflow -make release-workflow -# Enter version: v1.0.0 +# For development/testing (unsigned) +make dmg -# Or step by step -make clean dmg -make upload-release VERSION=v1.0.0 +# For public distribution (signed + notarized) +make dmg-signed +make notarize APPLE_ID=your-email@example.com +make upload-release VERSION=v1.1.0 ``` -This creates a DMG package and uploads it to GitHub as a draft release. See [`RELEASE_QUICK_START.md`](RELEASE_QUICK_START.md) for details. +**Documentation:** +- [`SIGNED_RELEASE_GUIDE.md`](SIGNED_RELEASE_GUIDE.md) - Complete guide for signed releases +- [`RELEASE_QUICK_START.md`](RELEASE_QUICK_START.md) - Quick reference for releases +- [`docs/CODE_SIGNING_GUIDE.md`](docs/CODE_SIGNING_GUIDE.md) - Technical code signing reference + +**Available Build Targets:** +- `make dmg` - Unsigned DMG for development +- `make dmg-signed` - Signed DMG with Developer ID +- `make notarize` - Submit for Apple notarization +- `make check-signing` - Verify code signing status +- `make upload-release` - Upload to GitHub as draft release ## 🎨 User Interface @@ -205,11 +228,15 @@ Both modes share a single `ContainerSystemMonitor` instance for synchronized sta - **ContainerListView.swift** - Enhanced list/grid views with inspector - **ContainerInspectorView.swift** - Detailed container information panel - **ContainerActions.swift** - Reusable action menus and context menus +- **ContainerCreationView.swift** - 7-step container creation wizard +- **ContainerCreationSteps.swift** - Individual wizard step implementations +- **ContainerCreationConfig.swift** - Configuration data model - **ImageListView.swift** - Image management interface - **VolumeListView.swift** - Volume management - **NetworkListView.swift** - Network management -- **StatsView.swift** - Real-time statistics dashboard +- **StatsView.swift** - Real-time statistics dashboard with live charts - **SettingsView.swift** - Application preferences +- **AnimationPreferences.swift** - Accessibility-aware animation controls #### `ContainerSystemMonitor.swift` - Container system monitoring @@ -461,15 +488,30 @@ container-manager/ β”œβ”€β”€ ContainerListView.swift # Enhanced container list β”œβ”€β”€ ContainerInspectorView.swift # Inspector panel β”œβ”€β”€ ContainerActions.swift # Reusable actions +β”œβ”€β”€ ContainerCreationView.swift # Container creation wizard +β”œβ”€β”€ ContainerCreationSteps.swift # Wizard step implementations +β”œβ”€β”€ ContainerCreationConfig.swift # Configuration model β”œβ”€β”€ ImageListView.swift # Image management β”œβ”€β”€ VolumeListView.swift # Volume management β”œβ”€β”€ NetworkListView.swift # Network management β”œβ”€β”€ StatsView.swift # Statistics dashboard β”œβ”€β”€ SettingsView.swift # Preferences +β”œβ”€β”€ AnimationPreferences.swift # Accessibility animations +β”œβ”€β”€ LoadingIndicator.swift # Loading states β”œβ”€β”€ Assets.xcassets/ # Images and icons +β”œβ”€β”€ Makefile # Build automation +β”œβ”€β”€ scripts/ +β”‚ β”œβ”€β”€ create-dmg.sh # DMG creation script +β”‚ └── check-signing.sh # Code signing verification +β”œβ”€β”€ docs/ +β”‚ β”œβ”€β”€ CODE_SIGNING_GUIDE.md # Code signing reference +β”‚ └── development/ # Development docs +β”œβ”€β”€ SIGNED_RELEASE_GUIDE.md # Release workflow guide +β”œβ”€β”€ CHANGELOG.md # Version history └── Tests/ β”œβ”€β”€ ContainerSystemMonitorTests.swift - └── ContainerSystemMonitorValidation.swift + β”œβ”€β”€ NetworkManagementTests.swift + └── VolumeManagementTests.swift ``` ### Testing @@ -513,15 +555,18 @@ Contributions are welcome! Areas for improvement: - [x] Full desktop application interface - [x] Enhanced container list with grid/list views - [x] Inspector panel for detailed information -- [x] Statistics dashboard +- [x] Statistics dashboard with live charts - [x] Settings and preferences +- [x] Container creation wizard (7-step guided process) +- [x] Batch operations for containers +- [x] Code signing and notarization workflow - [ ] Container log viewer with live streaming - [ ] Terminal/exec integration - [ ] Image pull/push with progress - [ ] Docker/Podman compatibility layer ### Medium Priority -- [ ] Container creation wizard +- [ ] Container templates for quick creation - [ ] Volume browser with file navigation - [ ] Network configuration UI - [ ] Compose file support @@ -561,32 +606,36 @@ Contributions are welcome! Areas for improvement: ## πŸ—ΊοΈ Roadmap -### Version 2.0 (Current) +### Version 1.1.0 (Current - February 2026) - [x] Full desktop application - [x] Enhanced container list with grid view - [x] Inspector panel -- [x] Statistics dashboard +- [x] Statistics dashboard with live charts - [x] Settings interface - [x] Dual-mode operation (menu bar + desktop) +- [x] Container creation wizard (7-step guided process) +- [x] Batch operations for multiple containers +- [x] Code signing and notarization workflow +- [x] Animation preferences with accessibility support -### Version 2.1 -- [ ] Container logs viewer with live streaming +### Version 1.2.0 +- [ ] Container log viewer with live streaming - [ ] Terminal/exec integration -- [ ] Image pull/push interface -- [ ] Container creation wizard +- [ ] Image pull/push interface with progress +- [ ] Container templates for quick creation -### Version 2.2 -- [ ] Volume browser +### Version 1.3.0 +- [ ] Volume browser with file navigation - [ ] Network configuration UI - [ ] Docker/Podman auto-detection -- [ ] Historical statistics +- [ ] Historical statistics and analytics -### Version 3.0 +### Version 2.0.0 - [ ] Compose file support - [ ] Multi-host/remote management -- [ ] Advanced filtering +- [ ] Advanced filtering and search - [ ] Custom actions/scripts -- [ ] Cloud integration +- [ ] Cloud registry integration --- diff --git a/SIGNED_RELEASE_GUIDE.md b/SIGNED_RELEASE_GUIDE.md new file mode 100644 index 0000000..af32e44 --- /dev/null +++ b/SIGNED_RELEASE_GUIDE.md @@ -0,0 +1,246 @@ +# Signed Release Guide + +This guide covers creating properly signed and notarized releases for public distribution. + +## Quick Start + +### For Development/Testing (Unsigned) +```bash +make dmg +``` +Creates an unsigned DMG suitable for personal use and testing. + +### For Public Distribution (Signed + Notarized) +```bash +# 1. Build and sign +make dmg-signed + +# 2. Verify signing +make check-signing + +# 3. Submit for notarization (first time only - setup credentials) +xcrun notarytool store-credentials "notarytool-profile" \ + --apple-id "your-email@example.com" \ + --team-id "6Y922224CW" \ + --password "app-specific-password" + +# 4. Notarize the DMG +make notarize APPLE_ID=your-email@example.com + +# 5. Verify notarization +make check-signing + +# 6. Upload to GitHub +make upload-release VERSION=v1.0.0 +``` + +## Prerequisites + +### Required +- βœ… Apple Developer Account ($99/year) +- βœ… Developer ID Application certificate installed +- βœ… GitHub CLI (`gh`) installed + +### For Notarization +- Apple ID email +- App-specific password (generate at appleid.apple.com) +- Team ID: `6Y922224CW` + +## Detailed Steps + +### 1. Build and Sign + +```bash +make clean +make dmg-signed +``` + +This will: +- Build the app with Developer ID signing +- Package it into a DMG +- Sign the DMG with Developer ID +- Apply hardened runtime flags +- Add secure timestamps + +**Output:** `container-manager-signed-YYYYMMDD-HHMM.dmg` + +### 2. Verify Signing + +```bash +make check-signing +``` + +You should see: +- βœ… DMG is signed (Developer ID Application) +- βœ… App is properly signed +- βœ… Signature is valid +- ❌ App is not notarized (until step 4) + +### 3. Set Up Notarization Credentials (First Time Only) + +Generate an app-specific password: +1. Go to https://appleid.apple.com +2. Sign in β†’ Security β†’ App-Specific Passwords +3. Generate password for "notarytool" +4. Copy the password (it won't be shown again) + +Store credentials in keychain: +```bash +xcrun notarytool store-credentials "notarytool-profile" \ + --apple-id "your-email@example.com" \ + --team-id "6Y922224CW" \ + --password "app-specific-password" +``` + +### 4. Notarize + +```bash +make notarize APPLE_ID=your-email@example.com +``` + +This will: +- Submit DMG to Apple for malware scanning +- Wait for approval (usually 1-5 minutes) +- Staple the notarization ticket to the DMG + +**Note:** The first notarization may take longer (~10-15 minutes). + +### 5. Verify Notarization + +```bash +make check-signing +``` + +Now you should see: +- βœ… DMG is signed +- βœ… App is properly signed +- βœ… Signature is valid +- βœ… App is notarized + +### 6. Upload to GitHub + +```bash +# Create a git tag first +git tag -a v1.0.0 -m "Release v1.0.0" +git push origin v1.0.0 + +# Upload as draft release +make upload-release VERSION=v1.0.0 +``` + +This creates a draft release on GitHub. You can then: +1. Edit the release notes +2. Publish the release + +## Certificate Information + +**Your Developer ID:** +``` +Developer ID Application: Andrew Bold (6Y922224CW) +Bundle ID: andybold.container-manager +``` + +**Verification:** +```bash +# List all signing identities +security find-identity -v -p codesigning + +# Should show: +# 1) "Apple Development: Andrew Bold (N78FK8S7QL)" +# 2) "Developer ID Application: Andrew Bold (6Y922224CW)" +``` + +## Troubleshooting + +### Signing Fails +```bash +# Check certificate is installed +security find-identity -v -p codesigning + +# Should show Developer ID Application certificate +``` + +### Notarization Fails +```bash +# Check submission status +xcrun notarytool history --keychain-profile "notarytool-profile" + +# View specific submission +xcrun notarytool log --keychain-profile "notarytool-profile" +``` + +### DMG Not Trusted on Other Macs +- Ensure app is signed with Developer ID (not Apple Development) +- Ensure DMG is notarized and ticket is stapled +- Run `make check-signing` to verify all steps + +### "Developer Cannot Be Verified" Error +- DMG needs to be notarized +- Run `make notarize APPLE_ID=your-email@example.com` +- Verify with `spctl -a -vv container-manager.app` + +## Gatekeeper Behavior + +### Properly Signed + Notarized +- First launch: "Open" button appears in dialog +- Users can open directly without warnings + +### Signed but Not Notarized +- First launch: Gatekeeper blocks with "cannot verify developer" +- Users must: Right-click β†’ Open β†’ Open + +### Unsigned (Development Builds) +- First launch: Gatekeeper blocks completely +- Users must: System Settings β†’ Privacy & Security β†’ Open Anyway + +## Make Targets Reference + +| Command | Description | +|---------|-------------| +| `make dmg` | Create unsigned DMG (development) | +| `make dmg-signed` | Create signed DMG (distribution) | +| `make check-signing` | Verify signing status | +| `make notarize` | Submit for notarization | +| `make upload-release` | Upload to GitHub | +| `make clean` | Clean build artifacts | + +## Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `SIGNING_IDENTITY` | `Developer ID Application: Andrew Bold (6Y922224CW)` | Code signing identity | +| `APPLE_ID` | (required) | Apple ID email for notarization | +| `TEAM_ID` | `6Y922224CW` | Team ID for notarization | +| `VERSION` | (required) | Version tag for release | + +## Distribution Checklist + +Before uploading a release: + +- [ ] Clean build: `make clean` +- [ ] Create signed DMG: `make dmg-signed` +- [ ] Verify signing: `make check-signing` shows βœ… +- [ ] Notarize: `make notarize APPLE_ID=your-email@example.com` +- [ ] Verify notarization: `make check-signing` shows notarized +- [ ] Test on clean Mac (no Xcode/dev tools) +- [ ] Create git tag: `git tag -a v1.0.0 -m "Release v1.0.0"` +- [ ] Push tag: `git push origin v1.0.0` +- [ ] Upload release: `make upload-release VERSION=v1.0.0` +- [ ] Edit release notes on GitHub +- [ ] Publish release + +## Additional Resources + +- [Apple Developer Documentation - Notarizing macOS Software](https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution) +- [Code Signing Guide](docs/CODE_SIGNING_GUIDE.md) - Detailed technical reference +- [Release Process](docs/RELEASE_PROCESS.md) - Full workflow documentation + +## Support + +For signing and notarization issues: +- Apple Developer Forums: https://developer.apple.com/forums/ +- Apple Developer Support: https://developer.apple.com/contact/ + +For build system issues: +- Check: `docs/CODE_SIGNING_GUIDE.md` +- Run: `make check-signing` for diagnostics diff --git a/container-manager.xcodeproj/project.pbxproj b/container-manager.xcodeproj/project.pbxproj index 7b06ad6..fdbf915 100644 --- a/container-manager.xcodeproj/project.pbxproj +++ b/container-manager.xcodeproj/project.pbxproj @@ -637,7 +637,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 26.0; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "andybold.container-manager"; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; @@ -671,7 +671,7 @@ "@executable_path/../Frameworks", ); MACOSX_DEPLOYMENT_TARGET = 26.0; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "andybold.container-manager"; PRODUCT_NAME = "$(TARGET_NAME)"; REGISTER_APP_GROUPS = YES; @@ -693,7 +693,7 @@ DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; MACOSX_DEPLOYMENT_TARGET = 26.2; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "andybold.container-managerTests"; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; @@ -714,7 +714,7 @@ DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; MACOSX_DEPLOYMENT_TARGET = 26.2; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "andybold.container-managerTests"; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; @@ -733,7 +733,7 @@ CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "andybold.container-managerUITests"; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; @@ -752,7 +752,7 @@ CURRENT_PROJECT_VERSION = 1; DEAD_CODE_STRIPPING = YES; GENERATE_INFOPLIST_FILE = YES; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 1.1.0; PRODUCT_BUNDLE_IDENTIFIER = "andybold.container-managerUITests"; PRODUCT_NAME = "$(TARGET_NAME)"; STRING_CATALOG_GENERATE_SYMBOLS = NO; diff --git a/docs/CODE_SIGNING_GUIDE.md b/docs/CODE_SIGNING_GUIDE.md new file mode 100644 index 0000000..ff08d79 --- /dev/null +++ b/docs/CODE_SIGNING_GUIDE.md @@ -0,0 +1,306 @@ +# Code Signing Verification Guide + +This guide explains how to verify code signing on your DMG and app bundles. + +## Current Status + +**Default builds are UNSIGNED (adhoc signing only).** + +This is intentional and works fine for: +- Development and testing +- Personal use +- Distribution to trusted users who can right-click β†’ Open + +For wider distribution, you'll want proper code signing and notarization. + +## Quick Verification Commands + +### Check DMG Signature +```bash +codesign -dvv container-manager.dmg +``` + +**Unsigned DMG output:** +``` +container-manager.dmg: code object is not signed at all +``` + +**Signed DMG output:** +``` +Executable=container-manager.dmg +Identifier=com.yourcompany.container-manager-dmg +Format=disk image +CodeDirectory v=20400 size=... +Signature size=... +Authority=Developer ID Application: Your Name (TEAMID) +Authority=Developer ID Certification Authority +Authority=Apple Root CA +Timestamp=Feb 8, 2026 at 5:00:00 PM +Info.plist=not bound +TeamIdentifier=YOURTEAMID +Sealed Resources=none +Internal requirements count=1 size=... +``` + +### Check App Bundle Signature +```bash +# Mount the DMG first +hdiutil attach container-manager.dmg -readonly -mountpoint /tmp/check + +# Check the app +codesign -dvvv /Volumes/*/container-manager.app + +# Unmount +hdiutil detach /tmp/check +``` + +**Adhoc (unsigned) output:** +``` +Signature=adhoc +TeamIdentifier=not set +``` + +**Properly signed output:** +``` +Signature size=... +Authority=Developer ID Application: Your Name (TEAMID) +Authority=Developer ID Certification Authority +Authority=Apple Root CA +TeamIdentifier=YOURTEAMID +``` + +### Verify Signature (Deep Check) +```bash +codesign --verify --deep --strict --verbose=2 /path/to/container-manager.app +``` + +**Success (valid signature):** +``` +/path/to/container-manager.app: valid on disk +/path/to/container-manager.app: satisfies its Designated Requirement +``` + +**Failure:** +``` +/path/to/container-manager.app: code object is not signed at all +# or +/path/to/container-manager.app: invalid signature (code or signature have been modified) +``` + +### Check Notarization Status +```bash +spctl -a -vv /path/to/container-manager.app +``` + +**Notarized:** +``` +/path/to/container-manager.app: accepted +source=Notarized Developer ID +origin=Developer ID Application: Your Name (TEAMID) +``` + +**Not notarized:** +``` +/path/to/container-manager.app: rejected +source=no usable signature +``` + +## Understanding Signing States + +### 1. Adhoc Signed (Current Default) +- **What**: App is "self-signed" by the linker during build +- **Security**: Basic integrity checking only +- **Distribution**: Works for development, personal use +- **Gatekeeper**: Will show warning on first launch +- **Override**: Users can right-click β†’ Open to bypass + +### 2. Developer ID Signed +- **What**: Signed with Apple Developer certificate +- **Security**: Verified by Apple's identity system +- **Distribution**: Can distribute outside App Store +- **Gatekeeper**: Will verify signature but may warn if not notarized +- **Requires**: Apple Developer account ($99/year) + +### 3. Developer ID Signed + Notarized +- **What**: Signed AND scanned by Apple for malware +- **Security**: Highest level for non-App Store apps +- **Distribution**: Professional distribution +- **Gatekeeper**: No warnings, launches immediately +- **Requires**: Developer ID + notarization workflow + +### 4. App Store Signed +- **What**: Signed for App Store distribution +- **Security**: Sandboxed and reviewed by Apple +- **Distribution**: Only through Mac App Store +- **Gatekeeper**: No warnings +- **Requires**: App Store entitlements, review process + +## How to Sign Your Builds + +### Prerequisites +1. Apple Developer account ($99/year) +2. Developer ID Application certificate +3. Developer ID Installer certificate (for DMGs) + +### Install Certificate +1. Log in to https://developer.apple.com +2. Go to Certificates, Identifiers & Profiles +3. Create "Developer ID Application" certificate +4. Download and install in Keychain Access + +### Find Your Signing Identity +```bash +security find-identity -v -p codesigning +``` + +Output shows available identities: +``` +1) ABC123DEF456... "Developer ID Application: Your Name (TEAMID)" +2) XYZ789GHI012... "Apple Development: your.email@example.com (TEAMID)" +``` + +Use the "Developer ID Application" identity for distribution. + +### Sign the App +```bash +# Set your identity +export SIGNING_IDENTITY="Developer ID Application: Your Name (TEAMID)" + +# Build with signing +make dmg SIGNING_IDENTITY="$SIGNING_IDENTITY" +``` + +Or manually: +```bash +# Build unsigned first +make release + +# Find the app +APP_PATH=$(find ./build -name "container-manager.app" -type d | head -n 1) + +# Sign it +codesign --force --deep --sign "$SIGNING_IDENTITY" \ + --options runtime \ + --timestamp \ + "$APP_PATH" + +# Verify +codesign --verify --deep --strict --verbose=2 "$APP_PATH" +``` + +### Sign the DMG +```bash +# After creating DMG +codesign --force --sign "$SIGNING_IDENTITY" \ + --timestamp \ + container-manager.dmg + +# Verify +codesign -dvv container-manager.dmg +``` + +## Notarization + +After signing, submit for notarization: + +### 1. Create App-Specific Password +1. Go to https://appleid.apple.com +2. Sign in +3. Security β†’ App-Specific Passwords +4. Generate new password for "notarytool" + +### 2. Submit for Notarization +```bash +xcrun notarytool submit container-manager.dmg \ + --apple-id "your-email@example.com" \ + --team-id "YOUR_TEAM_ID" \ + --password "app-specific-password" \ + --wait +``` + +### 3. Staple Ticket +```bash +# Staple to DMG +xcrun stapler staple container-manager.dmg + +# Verify stapling +xcrun stapler validate container-manager.dmg +``` + +## Distribution Checklist + +### For Development/Testing (Current) +- [x] Build with `make dmg` +- [x] Verify app launches +- [x] Test core functionality +- [ ] No signing needed + +### For Trusted Users +- [x] Build with `make dmg` +- [ ] Sign app with Developer ID +- [ ] Create DMG +- [ ] Sign DMG +- [ ] Distribute with instructions to right-click β†’ Open on first launch + +### For Public Distribution +- [x] Build with `make dmg` +- [ ] Sign app with Developer ID +- [ ] Enable hardened runtime +- [ ] Create DMG +- [ ] Sign DMG +- [ ] Notarize with Apple +- [ ] Staple notarization ticket +- [ ] Verify with spctl +- [ ] Upload to GitHub Releases + +## Troubleshooting + +### "Developer cannot be verified" +**Cause**: App is not signed or not notarized +**Solution**: User right-clicks app β†’ Open (one time) +**Better solution**: Sign and notarize your app + +### "Code signature is invalid" +**Cause**: App was modified after signing +**Solution**: Clean build and re-sign + +### "Notarization failed" +**Cause**: App doesn't meet notarization requirements +**Solution**: Check notarization log: +```bash +xcrun notarytool log \ + --apple-id "your-email@example.com" \ + --team-id "YOUR_TEAM_ID" \ + --password "app-specific-password" +``` + +### "timestamp authority not found" +**Cause**: No internet during signing +**Solution**: Ensure internet connection and retry + +## Current Build Status + +Your current builds are: +- βœ… **Adhoc signed** (linker-signed during build) +- ❌ Not Developer ID signed +- ❌ Not notarized +- ⚠️ Will show Gatekeeper warning on first launch + +This is fine for: +- Development +- Testing +- Personal use +- Distribution to technical users + +For wider distribution, follow the signing and notarization steps above. + +## References + +- [Apple Code Signing Guide](https://developer.apple.com/library/archive/documentation/Security/Conceptual/CodeSigningGuide/) +- [Notarization Documentation](https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution) +- [codesign man page](x-man-page://codesign) +- [spctl man page](x-man-page://spctl) + +--- + +**Last Updated**: 2026-02-08 diff --git a/scripts/check-signing.sh b/scripts/check-signing.sh new file mode 100755 index 0000000..6ed8132 --- /dev/null +++ b/scripts/check-signing.sh @@ -0,0 +1,152 @@ +#!/bin/bash + +# Script to check code signing status of DMG and app bundle +# Usage: ./scripts/check-signing.sh [path-to-dmg] + +# Don't exit on error - we want to check everything +set +e + +# Colors +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Find DMG +if [ -n "$1" ]; then + DMG_PATH="$1" +else + # Find most recent DMG + DMG_PATH=$(ls -t container-manager*.dmg 2>/dev/null | head -n1) +fi + +if [ -z "$DMG_PATH" ]; then + echo -e "${RED}❌ No DMG found${NC}" + echo "Usage: $0 [path-to-dmg]" + exit 1 +fi + +echo -e "${BLUE}πŸ” Checking code signing status${NC}" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Check DMG signature +echo -e "${YELLOW}πŸ“¦ DMG Signature:${NC}" +echo "File: $DMG_PATH" +echo "" + +DMG_SIGNED=false +if codesign -dvv "$DMG_PATH" 2>&1 | grep -q "Authority="; then + DMG_SIGNED=true + echo -e "${GREEN}βœ… DMG is signed${NC}" + codesign -dvv "$DMG_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier|Timestamp)" +else + echo -e "${RED}❌ DMG is not signed${NC}" + codesign -dvv "$DMG_PATH" 2>&1 +fi + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Mount DMG +echo -e "${YELLOW}πŸ“± Mounting DMG...${NC}" +MOUNT_POINT="/tmp/signing-check-$$" +hdiutil attach "$DMG_PATH" -readonly -mountpoint "$MOUNT_POINT" -nobrowse > /dev/null 2>&1 + +# Find app in DMG +APP_PATH=$(find "$MOUNT_POINT" -name "*.app" -maxdepth 1 | head -n1) + +if [ -z "$APP_PATH" ]; then + echo -e "${RED}❌ No app found in DMG${NC}" + hdiutil detach "$MOUNT_POINT" > /dev/null 2>&1 + exit 1 +fi + +echo "App: $(basename "$APP_PATH")" +echo "" + +# Check app signature +echo -e "${YELLOW}πŸ” App Bundle Signature:${NC}" +echo "" + +APP_SIGNED=false +APP_ADHOC=false + +if codesign -dvv "$APP_PATH" 2>&1 | grep -q "Authority="; then + APP_SIGNED=true + echo -e "${GREEN}βœ… App is properly signed${NC}" + codesign -dvvv "$APP_PATH" 2>&1 | grep -E "(Authority|TeamIdentifier|Timestamp|Identifier)" | head -10 +elif codesign -dvv "$APP_PATH" 2>&1 | grep -q "Signature=adhoc"; then + APP_ADHOC=true + echo -e "${YELLOW}⚠️ App is adhoc signed (development only)${NC}" + codesign -dvv "$APP_PATH" 2>&1 | grep -E "(Signature|TeamIdentifier|Identifier)" +else + echo -e "${RED}❌ App is not signed${NC}" +fi + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Verify signature +echo -e "${YELLOW}βœ“ Verification:${NC}" +echo "" + +if codesign --verify --deep --strict --verbose=2 "$APP_PATH" 2>&1 | grep -q "valid on disk"; then + echo -e "${GREEN}βœ… Signature is valid${NC}" +else + echo -e "${RED}❌ Signature verification failed${NC}" + codesign --verify --deep --strict --verbose=2 "$APP_PATH" 2>&1 +fi + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Check notarization +echo -e "${YELLOW}🍎 Notarization Status:${NC}" +echo "" + +if spctl -a -vv "$APP_PATH" 2>&1 | grep -q "accepted"; then + echo -e "${GREEN}βœ… App is notarized${NC}" + spctl -a -vv "$APP_PATH" 2>&1 +else + echo -e "${RED}❌ App is not notarized${NC}" + spctl -a -vv "$APP_PATH" 2>&1 || true +fi + +# Unmount +hdiutil detach "$MOUNT_POINT" > /dev/null 2>&1 + +echo "" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +echo "" + +# Summary +echo -e "${BLUE}πŸ“Š Summary:${NC}" +echo "" + +if [ "$DMG_SIGNED" = true ] && [ "$APP_SIGNED" = true ]; then + echo -e "${GREEN}βœ… Fully signed - ready for distribution${NC}" + echo " Both DMG and app are properly signed" +elif [ "$APP_ADHOC" = true ]; then + echo -e "${YELLOW}⚠️ Development build - adhoc signed${NC}" + echo " Good for: Development, testing, personal use" + echo " Not suitable for: Public distribution" + echo "" + echo " Users will see Gatekeeper warning on first launch" + echo " They can bypass with: Right-click β†’ Open" + echo "" + echo " To sign for distribution:" + echo " 1. Get Apple Developer account" + echo " 2. Create Developer ID certificate" + echo " 3. See: docs/CODE_SIGNING_GUIDE.md" +else + echo -e "${RED}❌ Not signed${NC}" + echo " This build is not properly signed" + echo " See: docs/CODE_SIGNING_GUIDE.md" +fi + +echo ""