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
18 changes: 16 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ env:
CARGO_TERM_COLOR: always
RUST_BACKTRACE: full
MACOS_RELEASE_ASSET: rsnap-aarch64-apple-darwin.zip
MACOS_APPCAST_ASSET: appcast.xml

on:
push:
Expand Down Expand Up @@ -58,13 +59,17 @@ jobs:
APPLE_NOTARY_KEY_ID: ${{ secrets.APPLE_NOTARY_KEY_ID }}
APPLE_NOTARY_ISSUER: ${{ secrets.APPLE_NOTARY_ISSUER }}
APPLE_NOTARY_KEY_P8: ${{ secrets.APPLE_NOTARY_KEY_P8 }}
SPARKLE_PUBLIC_ED_KEY: ${{ secrets.SPARKLE_PUBLIC_ED_KEY }}
SPARKLE_PRIVATE_ED_KEY: ${{ secrets.SPARKLE_PRIVATE_ED_KEY }}
run: |
set -euo pipefail

for required_secret in \
APPLE_CERTIFICATE_P12_BASE64 \
APPLE_CERTIFICATE_PASSWORD \
APPLE_SIGNING_IDENTITY; do
APPLE_SIGNING_IDENTITY \
SPARKLE_PUBLIC_ED_KEY \
SPARKLE_PRIVATE_ED_KEY; do
if [[ -z "${!required_secret:-}" ]]; then
echo "Missing required secret: ${required_secret}" >&2
exit 1
Expand Down Expand Up @@ -113,6 +118,7 @@ jobs:
RSNAP_NATIVE_HOST_RUST_PROFILE=final-release \
RSNAP_NATIVE_HOST_SWIFT_CONFIGURATION=release \
RSNAP_NATIVE_HOST_SIGN_IDENTITY="${APPLE_SIGNING_IDENTITY}" \
RSNAP_SPARKLE_PUBLIC_ED_KEY="${SPARKLE_PUBLIC_ED_KEY}" \
./scripts/build_and_run.sh stage

APP_PATH="target/rsnap-native-host/Rsnap.app"
Expand Down Expand Up @@ -154,11 +160,19 @@ jobs:
"${APP_PATH}" \
"${MACOS_RELEASE_ASSET}"

scripts/release/sparkle-appcast.sh \
--archive "${MACOS_RELEASE_ASSET}" \
--appcast "${MACOS_APPCAST_ASSET}" \
--version "${VERSION}" \
--tag "${GITHUB_REF_NAME}"

- name: Upload artifact
uses: actions/upload-artifact@v7
with:
name: rsnap-aarch64-apple-darwin
path: ${{ env.MACOS_RELEASE_ASSET }}
path: |
${{ env.MACOS_RELEASE_ASSET }}
${{ env.MACOS_APPCAST_ASSET }}
if-no-files-found: error
retention-days: 1

Expand Down
8 changes: 4 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 4 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ homepage = "https://hack.ink/rsnap"
license = "GPL-3.0"
readme = "README.md"
repository = "https://github.com/hack-ink/rsnap"
version = "0.1.2"
version = "0.1.3"

[workspace.dependencies]
arboard = { version = "3.6" }
Expand Down Expand Up @@ -52,9 +52,9 @@ wgpu = { version = "29.0" }
winit = { version = "0.30", features = ["rwh_06"] }
xcap = { version = "0.9" }

rsnap-capture-core = { version = "0.1.2", path = "packages/rsnap-capture-core" }
rsnap-host-ffi = { version = "0.1.2", path = "packages/rsnap-host-ffi" }
rsnap-overlay = { version = "0.1.2", path = "packages/rsnap-overlay" }
rsnap-capture-core = { version = "0.1.3", path = "packages/rsnap-capture-core" }
rsnap-host-ffi = { version = "0.1.3", path = "packages/rsnap-host-ffi" }
rsnap-overlay = { version = "0.1.3", path = "packages/rsnap-overlay" }

[profile.final-release]
inherits = "release"
Expand Down
8 changes: 8 additions & 0 deletions Makefile.toml
Original file line number Diff line number Diff line change
Expand Up @@ -261,9 +261,17 @@ codesign -dv --verbose=4 "$APP_PATH" 2>&1 | grep -q '^TeamIdentifier='
test -x "$APP_PATH/Contents/MacOS/RsnapNativeHost"
test -f "$APP_PATH/Contents/Info.plist"
test -f "$APP_PATH/Contents/Resources/AppIcon.icns"
test -d "$APP_PATH/Contents/Frameworks/Sparkle.framework"
otool -L "$APP_PATH/Contents/MacOS/RsnapNativeHost" | grep -q '@rpath/Sparkle.framework'
otool -l "$APP_PATH/Contents/MacOS/RsnapNativeHost" | grep -q '@executable_path/../Frameworks'
plutil -extract CFBundleName raw "$APP_PATH/Contents/Info.plist" | grep -qx 'Rsnap'
plutil -extract CFBundleDisplayName raw "$APP_PATH/Contents/Info.plist" | grep -qx 'Rsnap'
plutil -extract CFBundleIdentifier raw "$APP_PATH/Contents/Info.plist" | grep -qx 'ink.hack.rsnap'
plutil -extract SUFeedURL raw "$APP_PATH/Contents/Info.plist" \
| grep -qx 'https://github.com/hack-ink/rsnap/releases/latest/download/appcast.xml'
plutil -extract SUEnableAutomaticChecks raw "$APP_PATH/Contents/Info.plist" | grep -qx 'true'
plutil -extract SUAutomaticallyUpdate raw "$APP_PATH/Contents/Info.plist" | grep -qx 'true'
plutil -extract SUScheduledCheckInterval raw "$APP_PATH/Contents/Info.plist" | grep -qx '86400'
if plutil -extract LSUIElement raw "$APP_PATH/Contents/Info.plist" >/dev/null 2>&1; then
echo "LSUIElement must stay unset so Settings is a normal foreground window" >&2
exit 1
Expand Down
11 changes: 8 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ Prototype / in active development.
- Menubar and Dock are not included in live window-outline targeting.
- Windows support is planned (minimum Windows 10), but not implemented yet.
- The scroll-capture engine, deterministic replay, and benchmark surfaces remain in the repository,
but the v0.1.2 native-host release does not expose scroll capture in the toolbar.
but the v0.1.3 native-host release does not expose scroll capture in the toolbar.

## Usage

Expand All @@ -85,6 +85,10 @@ Download the latest macOS zip:

Unzip it and move `Rsnap.app` to `/Applications`.

Release builds include Sparkle-based updates. Use `Settings...` -> `About` -> `Check` for the
standard macOS update flow; the About Auto Update mode defaults to `Install` for signed release builds
with the Sparkle appcast configured.

#### Build from Source

```sh
Expand Down Expand Up @@ -119,7 +123,7 @@ Rsnap currently relies on **Screen Recording** permission to capture other apps/
- ScreenCaptureKit live sampling on macOS requires macOS 12.3+ and Screen Recording permission.
- Normal region/window/monitor capture does not require Accessibility or Input Monitoring.
- The retained scroll-capture path uses Screen Recording-backed screenshots plus forwarded wheel
input, but the v0.1.2 native-host release does not expose scroll capture in the toolbar.
input, but the v0.1.3 native-host release does not expose scroll capture in the toolbar.
- macOS may describe Screen Recording as `Screen & System Audio Recording` or as direct screen/audio access when Rsnap bypasses the system picker.
- Settings -> Permissions shows Screen Recording as the only required permission.
- Normal native capture depends on Screen Recording; if access is missing, Rsnap opens the Screen Recording page in System Settings and shows a floating drag-to-grant guide.
Expand Down Expand Up @@ -152,7 +156,7 @@ Rsnap currently relies on **Screen Recording** permission to capture other apps/

### Current scroll-capture status

Scroll capture is temporarily hidden in the v0.1.2 native-host release. The retained Rust
Scroll capture is temporarily hidden in the v0.1.3 native-host release. The retained Rust
scroll-capture session, deterministic replay, and benchmark surfaces remain for validation and
future re-enablement, but users should not expect a `Scroll Capture` toolbar item in this release.

Expand Down Expand Up @@ -189,6 +193,7 @@ scripts/smoke/analyze-scroll-capture-trace.sh
scripts/smoke/native-hud-follow-macos.sh
scripts/smoke/self-check-macos.sh
scripts/smoke/macos.sh
scripts/smoke/sparkle-update-local.sh
scripts/perf/local.sh
scripts/perf/self-check-macos.sh
scripts/perf/macos.sh
Expand Down
2 changes: 1 addition & 1 deletion docs/reference/smoke-perf-validation-surface.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Depends on: `docs/runbook/performance-validation.md`; `docs/spec/performance.md`
Covers: The current layer map for smoke/perf entrypoints, deterministic replay/bench surfaces,
overlay runtime integration tests, and scroll-capture session semantics tests.

Release exposure note: v0.1.2 hides user-facing scroll capture in the native host. The
Release exposure note: v0.1.3 hides user-facing scroll capture in the native host. The
scroll-capture entries in this reference describe retained internal validation assets, not a
visible toolbar feature in that release.

Expand Down
4 changes: 2 additions & 2 deletions docs/runbook/performance-validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ Depends on: `docs/spec/performance.md`
Outputs: A clear command choice for the regression class you are testing, plus a repeatable local
baseline workflow for the committed Criterion benchmark targets.

Current release status: v0.1.2 hides user-facing scroll capture in the native host. The replay and
Current release status: v0.1.3 hides user-facing scroll capture in the native host. The replay and
benchmark commands in this runbook still own retained internal scroll-capture engine validation and
future re-enablement work, but they are not evidence that the v0.1.2 toolbar exposes scroll
future re-enablement work, but they are not evidence that the v0.1.3 toolbar exposes scroll
capture.

## Command selection
Expand Down
2 changes: 1 addition & 1 deletion docs/runbook/scroll-capture-benchmarks.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ Depends on: `docs/spec/performance.md`
Outputs: A repeatable local benchmark run, an optional saved Criterion baseline, and a clear
understanding of what the synthetic fixture is intended to cover.

Current release status: v0.1.2 hides user-facing scroll capture in the native host. This runbook
Current release status: v0.1.3 hides user-facing scroll capture in the native host. This runbook
still applies to the retained internal scroll-capture engine, replay, and future re-enablement
work.

Expand Down
43 changes: 36 additions & 7 deletions docs/runbook/validate-release.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,10 @@ manual first-run/user-flow validation.
- No existing local or remote tag already uses `v<version>`.
2. Confirm release credentials:
- Apple signing certificate secrets are available to the Release workflow.
- Apple notary credentials are optional for v0.1.2; when absent, the Release workflow still
- Sparkle update signing secrets are available to the Release workflow:
`SPARKLE_PUBLIC_ED_KEY` for `SUPublicEDKey` and `SPARKLE_PRIVATE_ED_KEY` for signing the
published update archive.
- Apple notary credentials are optional for v0.1.3; when absent, the Release workflow still
publishes a signed but unnotarized macOS zip.
3. Confirm local gates:
- `cargo make checks`
Expand Down Expand Up @@ -55,10 +58,24 @@ Validate these user-visible flows:
fullscreen fallback.
- Frozen toolbar tools: pointer, pen, arrow, text, mosaic, spotlight, undo, redo, auto-center,
Recognize Text, copy, and save.
- Scroll capture is hidden in the v0.1.2 native-host release: the toolbar must not show a scroll
- Scroll capture is hidden in the v0.1.3 native-host release: the toolbar must not show a scroll
capture item, and pressing `s` must not enter scroll capture.
- Light and dark appearance; Classic Glass and Liquid Glass where the OS and current build support
Liquid Glass.
- Settings -> About update rows: `Auto Update` and `Release Version` must use Title Case for row
titles. The Auto Update mode control must show `Off`, `Notify`, and `Install`; secondary text must use
sentence case, must not look like download progress, and the release-configured build must not
report that the Sparkle appcast is missing.
- Sparkle local update smoke:

```sh
scripts/smoke/sparkle-update-local.sh
```

The script builds a disposable old app, a higher-version update archive, a local signed appcast,
and a local HTTP server. The final Sparkle `Install and Relaunch` confirmation remains manual;
after confirming it, return to the script and press Enter so it can verify the old bundle's
`CFBundleVersion` changed to the update version.
- Output directory, filename prefix, sequence/timestamp naming, clipboard copy, and save failure
handling where practical.

Expand All @@ -77,9 +94,9 @@ user-entered annotation text.
2. Watch the Release workflow for the exact tag.
3. Treat a build, signing, or packaging failure as a release blocker.
4. Treat notarization failure as a release blocker only when notary credentials are configured.
5. The Release workflow publishes the signed macOS zip to the GitHub release. It notarizes and
staples the app only when notary credentials are configured. It does not publish crates.io
packages or non-macOS desktop archives for v0.1.2.
5. The Release workflow publishes the signed macOS zip and `appcast.xml` to the GitHub release.
It notarizes and staples the app only when notary credentials are configured. It does not
publish crates.io packages or non-macOS desktop archives for v0.1.3.

## Published Artifact Check

Expand All @@ -91,6 +108,10 @@ After the Release workflow succeeds:
- The app bundle is `Rsnap.app`.
- `CFBundleName` and `CFBundleDisplayName` are `Rsnap`.
- `CFBundleIdentifier` is `ink.hack.rsnap`.
- `SUFeedURL` is
`https://github.com/hack-ink/rsnap/releases/latest/download/appcast.xml`.
- `SUPublicEDKey` is present.
- `Sparkle.framework` is present in `Contents/Frameworks`.
3. Verify the signature:

```sh
Expand All @@ -107,5 +128,13 @@ For a signed but unnotarized build, Gatekeeper may still block a quarantined dow
quarantine override documented in `README.md` only for a bundle built locally or downloaded from
this repository's GitHub Releases page.

5. Launch the downloaded app and repeat a minimal capture, toolbar, OCR, copy, and save check.
6. Confirm release notes and the macOS zip were published.
5. Confirm the appcast asset was published:

```sh
curl -fsSL https://github.com/hack-ink/rsnap/releases/latest/download/appcast.xml \
| grep -q 'sparkle:edSignature'
```

6. Launch the downloaded app and repeat a minimal capture, toolbar, OCR, copy, save, and About
update check.
7. Confirm release notes, the macOS zip, and the appcast were published.
2 changes: 1 addition & 1 deletion docs/spec/capture-session.md
Original file line number Diff line number Diff line change
Expand Up @@ -162,7 +162,7 @@ product level rather than binding itself to a particular window toolkit or shell

## Scroll capture

- The v0.1.2 native-host release does not expose scroll capture. The frozen toolbar MUST NOT show a
- The v0.1.3 native-host release does not expose scroll capture. The frozen toolbar MUST NOT show a
scroll-capture item while the native-host scroll-capture gate is disabled, and plain `s` MUST NOT
enter scroll capture in that state.
- When scroll capture is re-enabled, it is available only from a dragged-region freeze on macOS.
Expand Down
22 changes: 22 additions & 0 deletions docs/spec/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ Defines:
- HUD tint: `0.4990234375`.
- HUD tint hue: `0.6074879184861536`.
- Loupe sample size: small.
- Sparkle update mode: install in release builds.

## Permission Settings

Expand Down Expand Up @@ -110,6 +111,27 @@ Defines:
`https://x.com/YvetteCipher`.
- The creator link may encourage following for ongoing Rsnap updates and may state that follows
help support future work through X creator rewards.
- Release builds must use Sparkle's standard updater UI and appcast format for macOS self-updates.
GitHub Releases remains the distribution surface, but the Sparkle appcast at
`https://github.com/hack-ink/rsnap/releases/latest/download/appcast.xml` is the update-version
authority for in-app update checks.
- The appcast must compare against the running app bundle's `CFBundleVersion`. The user-visible
version should remain `CFBundleShortVersionString`.
- The About section must expose a Check for Updates action backed by Sparkle's standard check
flow. When an installable update is available, Sparkle owns the native update window, download
progress, install authorization if needed, and final install-and-relaunch action.
- The About section must expose one Auto Update mode control rather than separate Automatic Checks
and Automatic Updates rows. The visible modes are Off, Notify, and Install.
- Off must disable Sparkle automatic checks and automatic downloads. Notify must enable Sparkle
automatic checks without automatic downloads. Install must enable automatic checks and Sparkle's
`automaticallyDownloadsUpdates` setting when automatic updates are available.
- Sparkle must use a 24-hour scheduled check interval, and each fresh app launch should request one
immediate background check after the updater starts when the selected mode is Notify or Install.
- The Auto Update secondary text must use sentence case, must not read like download or install
progress, and should display Sparkle's last successful check time while Notify or Install is
selected. When Sparkle is not configured in a development build, the secondary text may state
that the signed appcast is not configured.
- The About section must not display last checked as a separate row.
- The About section must not expose capture defaults or a Restore Defaults action.

## Default-Size Usability
Expand Down
11 changes: 10 additions & 1 deletion native/macos-host/Package.resolved

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion native/macos-host/Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ let package = Package(
.executable(name: "RsnapNativeHost", targets: ["RsnapNativeHost"]),
],
dependencies: [
.package(url: "https://github.com/sparkle-project/Sparkle", exact: "2.9.1"),
.package(url: "https://github.com/SimplyDanny/SwiftLintPlugins", exact: "0.63.2"),
],
targets: [
Expand Down Expand Up @@ -50,7 +51,10 @@ let package = Package(
),
.target(
name: "RsnapNativeHostKit",
dependencies: ["RsnapHostBridge"],
dependencies: [
"RsnapHostBridge",
.product(name: "Sparkle", package: "Sparkle"),
],
resources: [
.process("Resources"),
],
Expand Down
Loading
Loading