Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 40 additions & 66 deletions release-artifacts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,32 @@

| File | Size | What |
| --- | --- | --- |
| `DeepCode-0.1.0-arm64-unsigned.dmg` | 4.7 MB | macOS Apple Silicon installer (Tauri-based). **Currently unsigned** — see Apple Signing below. |
| **`DeepCode-0.1.0-arm64.dmg`** | **4.7 MB** | macOS Apple Silicon installer (Tauri-based) · **Signed + Apple-notarized** ✓ |
| `deepcode-cli-0.1.0-bundle.tgz` | 4.4 MB | Self-contained CLI bundle (includes node_modules) |
| `install-cli.sh` | — | One-line installer for the CLI |
| `install-cli.sh` | 1.3 KB | One-line installer for the CLI |
| `SIGNING_LOG.md` | — | Record of how the DMG was signed + notarized |

---

## Install the Mac client (signed + notarized)

```bash
open release-artifacts/DeepCode-0.1.0-arm64.dmg
```

- Drag **DeepCode.app** → **Applications** folder
- Eject the DMG, open Applications → DeepCode
- **No Gatekeeper warning** — the .app is signed by Bihao Wang (Team `9LH9NBX7P4`) and notarized by Apple

To verify yourself:

```bash
codesign --verify --deep --strict /Applications/DeepCode.app
spctl --assess --type exec --verbose /Applications/DeepCode.app
# Expected: accepted, source=Notarized Developer ID
xcrun stapler validate /Applications/DeepCode.app
# Expected: The validate action worked!
```

---

Expand All @@ -19,7 +42,7 @@ bash install-cli.sh
```

This extracts the bundle to `~/.local/share/deepcode/` and symlinks
`deepcode` into `~/.local/bin/` (or `/usr/local/bin/` if writeable).
`deepcode` into `~/.local/bin/` (or `/usr/local/bin/` if writable).

### Option 2 — Manual

Expand Down Expand Up @@ -48,80 +71,29 @@ Requirements: **Node.js 22+** on PATH.

---

## Install the Mac client

### What you get

A `.app` bundle (6.8 MB extracted) + `.dmg` installer (4.7 MB).
Architecture: **Apple Silicon** (`arm64`). Intel build is a separate
artifact — see "Universal build" below.

### Install

1. Double-click `DeepCode-0.1.0-arm64-unsigned.dmg`
2. Drag **DeepCode.app** into the **Applications** folder shortcut
3. Eject the DMG, open Applications → DeepCode

### Gatekeeper warning on first launch

The DMG is **currently unsigned** — Apple Developer ID signing pipeline
is in `scripts/sign-and-notarize.sh` but requires the maintainer's
Apple credentials to run.

When you first launch DeepCode.app, macOS will say "DeepCode cannot
be opened because Apple cannot check it for malicious software."

To open it:
- **Method A** (one-time): Right-click the .app → **Open** → confirm
the "Open" button in the dialog.
- **Method B**: System Settings → Privacy & Security → scroll down →
"DeepCode was blocked..." → **Open Anyway**.
- **Method C** (terminal): `xattr -d com.apple.quarantine /Applications/DeepCode.app`

After the first successful launch, macOS remembers your decision —
subsequent launches work normally.

---

## Apple Signing (for the maintainer)

To produce a signed + notarized DMG (no Gatekeeper warning):

1. Enroll in Apple Developer Program ($99/yr): https://developer.apple.com/programs/
2. Generate "Developer ID Application" cert + import into login keychain
3. Get `TEAM_ID` from https://developer.apple.com/account → Membership
4. Generate app-specific password at https://appleid.apple.com → "App-Specific Passwords"
5. Store credentials in keychain (one-time):
```bash
xcrun notarytool store-credentials "DEEPCODE_NOTARY" \
--apple-id "<you>@example.com" \
--team-id "<TEAM_ID>" \
--password "<app-specific-password>"
```
6. Run the sign + notarize script:
```bash
bash scripts/sign-and-notarize.sh
```
## Architecture

End-to-end takes ~10-15 min (Apple's notarization servers usually return
in 2-5 minutes during off-peak hours).

The script writes the signed DMG back to:
`apps/desktop/src-tauri/target/aarch64-apple-darwin/release/bundle/dmg/DeepCode_0.1.0_aarch64.dmg`
- **Mac client**: Tauri 2 (Rust main process + native WebKit webview)
- Bundle: 4.7 MB DMG · 6.8 MB .app · ~80 MB RSS idle
- vs Electron alternative: would have been ~150 MB / ~250 MB RSS
- **CLI**: Node.js 22+ via `@deepcode/core` ESM modules
- **Agent loop**: `@deepcode/core` — same code drives CLI + desktop +
VS Code extension + LSP bridge

---

## Universal build (Intel + Apple Silicon)

The shipped DMG is `aarch64` (Apple Silicon) only. For a universal binary:

```bash
. "$HOME/.cargo/env"
rustup target add x86_64-apple-darwin aarch64-apple-darwin
pnpm --filter @deepcode/desktop tauri build --target universal-apple-darwin
# Then rerun scripts/sign-and-notarize.sh with DEEPCODE_TARGET=universal-apple-darwin
```

Output: `apps/desktop/src-tauri/target/universal-apple-darwin/release/bundle/dmg/`

Universal builds are ~2× the size of single-arch.
Universal builds are ~2× the size.

---

Expand All @@ -130,8 +102,10 @@ Universal builds are ~2× the size of single-arch.
- **DeepCode CLI**: 0.1.0
- **DeepCode Mac**: 0.1.0
- **Built**: 2026-05-28
- **Tauri runtime**: 2.x (native WebKit)
- **Tauri runtime**: 2.11.2 (native WebKit)
- **Node engine (CLI)**: ≥22
- **Signing**: Developer ID Application: Bihao Wang (`9LH9NBX7P4`)
- **Apple notarization**: ticket stapled to both `.app` and `.dmg`

---

Expand Down
69 changes: 69 additions & 0 deletions release-artifacts/SIGNING_LOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# DeepCode v0.1.0 — Signing & Notarization Log

This file records the signing flow that produced the signed/notarized
artifacts in this directory.

## Credentials

| Field | Value |
| --- | --- |
| Apple ID | `wangharp@gmail.com` |
| Team ID | `9LH9NBX7P4` |
| Team | Bihao Wang |
| Signing identity | `Developer ID Application: Bihao Wang (9LH9NBX7P4)` |
| Signing cert SHA-1 | `7DC903001F863681EDBB2B4B18755D15D2F19D3B` |
| Notarytool keychain profile | `DEEPCODE_NOTARY` |

The app-specific password was stored in macOS keychain via:

```
xcrun notarytool store-credentials "DEEPCODE_NOTARY" \
--apple-id "wangharp@gmail.com" \
--team-id "9LH9NBX7P4" \
--password "<redacted>"
```

The raw app-specific password is **not stored** in this repo — only the
keychain profile reference (`DEEPCODE_NOTARY`) is.

## Flow

`scripts/sign-and-notarize.sh` does, in order:

1. `pnpm --filter @deepcode/desktop tauri build --target aarch64-apple-darwin`
2. Auto-detect Developer ID Application identity in keychain
3. `codesign --force --deep --options runtime --entitlements
apps/desktop/src-tauri/Entitlements.plist --sign <id> --timestamp <.app>`
4. `codesign --verify --deep --strict <.app>` (sanity)
5. `ditto -c -k --keepParent <.app> /tmp/.../DeepCode.zip`
6. `xcrun notarytool submit <zip> --keychain-profile DEEPCODE_NOTARY --wait`
7. `xcrun stapler staple <.app>`
8. `codesign --force --sign <id> --timestamp <.dmg>`
9. `xcrun notarytool submit <dmg> --keychain-profile DEEPCODE_NOTARY --wait`
10. `xcrun stapler staple <.dmg>`
11. `spctl --assess --type open --context context:primary-signature <.dmg>` (sanity)

## Verifying the artifact

After installation, verify the .app's signature + notarization status:

```bash
codesign --verify --deep --strict --verbose=2 /Applications/DeepCode.app
spctl --assess --type exec --verbose /Applications/DeepCode.app
# Expected: "accepted, source=Notarized Developer ID"

xcrun stapler validate /Applications/DeepCode.app
# Expected: "The validate action worked!"
```

## Re-signing

To re-sign a fresh build (e.g. after a code change):

```bash
. "$HOME/.cargo/env"
bash scripts/sign-and-notarize.sh
```

Total wall-clock: ~3 min Rust build + ~30 s codesign + ~2-5 min Apple
notarytool wait (peak hours can spike to 30 min).
20 changes: 19 additions & 1 deletion scripts/sign-and-notarize.sh
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,26 @@ xcrun notarytool submit "$ZIP_PATH" --keychain-profile "$PROFILE" --wait
echo "==> Stapling notarization ticket to $APP_PATH ..."
xcrun stapler staple "$APP_PATH"

# ----- 7. Notarize + staple the .dmg (if present) -----
# ----- 7. Rebuild the .dmg with the NOW-signed-and-stapled .app -----
# IMPORTANT: Tauri's bundle_dmg.sh ran in step 1 and baked the UNSIGNED .app
# into the DMG. Just signing the DMG container doesn't fix that — Apple
# notarization unpacks the DMG and re-verifies the .app inside. So we
# rebuild the DMG from scratch with the now-signed .app.
if [ -n "$DMG_PATH" ] && [ -f "$DMG_PATH" ]; then
echo "==> Rebuilding DMG with signed+stapled .app ..."
STAGING="$(mktemp -d)/staging"
mkdir -p "$STAGING"
cp -R "$APP_PATH" "$STAGING/DeepCode.app"
ln -s /Applications "$STAGING/Applications"
rm -f "$DMG_PATH"
hdiutil create \
-volname "DeepCode" \
-srcfolder "$STAGING" \
-ov \
-format UDZO \
-fs HFS+ \
"$DMG_PATH" >/dev/null

echo "==> Signing $DMG_PATH ..."
codesign --force --sign "$SIGNING_ID" --timestamp "$DMG_PATH"

Expand Down
Loading