Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b223bd9
test(desktop-gpui): capture Apple's glass over fixed backdrops as a r…
richiemcilroy Oct 27, 2026
79b6f2c
test(desktop-gpui): record the reference runner's accessibility and G…
richiemcilroy Oct 27, 2026
a25aafd
feat(desktop-gpui): Cap Glass renderer, model and real-app probe
richiemcilroy Oct 27, 2026
feb6bff
fix(desktop-gpui): draw glass panes painted last, capture the probe w…
richiemcilroy Oct 27, 2026
16afb47
feat(desktop-gpui): fit glass to Apple with a cubic colour transform …
richiemcilroy Oct 27, 2026
9c73afa
fix(desktop-gpui): weight the glass colour fit as intended and pin th…
richiemcilroy Oct 27, 2026
6456ede
Merge branch 'feat/gpui-window-arrange-focus' into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
ad8724d
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
aa8bf35
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
90777da
fix(desktop-gpui): glass-fit reads Retina references at their capture…
richiemcilroy Oct 27, 2026
2b38863
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
7cdd62a
ci(desktop-gpui): run the glass probe's summary with whichever Python…
richiemcilroy Oct 27, 2026
6f7ea42
ci(desktop-gpui): the glass probe captures its window's area on Windo…
richiemcilroy Oct 27, 2026
3b487ef
fix(desktop-gpui): map the reduced backdrop back by its real scale on…
richiemcilroy Oct 27, 2026
5e67047
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
d57ace9
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
7a09e75
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
88168f0
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
e40da5c
feat(desktop-gpui): match Apple's glass size adaptation, lens falloff…
richiemcilroy Oct 27, 2026
87b8924
style(desktop-gpui): format glass presets
richiemcilroy Oct 27, 2026
82f7de3
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
f3ead4d
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
5fba2d1
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
2fffb5e
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
a618794
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
6956839
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
fb539b3
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
ec83278
ci(glass-probe): skip the matrix for fork pull requests that change n…
richiemcilroy Oct 27, 2026
b8f4b0e
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
0cb9fbe
ci(glass-probe): upload the probed Windows and Linux builds for GPU m…
richiemcilroy Oct 27, 2026
105ba28
Merge feat/gpui-window-arrange-focus into feat/gpui-cap-glass
richiemcilroy Oct 27, 2026
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
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,7 @@ jobs:
cargo +1.95.0 test --manifest-path apps/desktop-gpui/Cargo.toml --locked --target ${{ matrix.settings.target }} --bin cap-gpui
fi
cargo +1.95.0 test --manifest-path apps/desktop-gpui/Cargo.toml --locked --target ${{ matrix.settings.target }} -p cap-gpui-kernels
cargo +1.95.0 test --manifest-path apps/desktop-gpui/Cargo.toml --locked --target ${{ matrix.settings.target }} -p cap-glass
cargo +1.95.0 test --manifest-path apps/desktop-gpui/Cargo.toml --locked --target ${{ matrix.settings.target }} -p cap-i18n-build

# Cap only builds gpui's crates as dependencies, so their own tests never run
Expand Down
207 changes: 207 additions & 0 deletions .github/workflows/glass-probe.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
name: Glass probe (real app)
# Draws Cap Glass in the real GPUI app on macOS (Metal), Windows (Direct3D 11
# on WARP) and Linux (wgpu on lavapipe), captures the window and scores every
# scene and preset against the CPU model in apps/desktop-gpui/glass, which is
# fitted to Apple's own glass.

on:
pull_request:
types: [opened, synchronize, reopened, ready_for_review]
paths:
- "apps/desktop-gpui/glass/**"
- "apps/desktop-gpui/patches/zed-glass.patch"
- "apps/desktop-gpui/src/ui/glass.rs"
- "apps/desktop-gpui/src/glass_probe.rs"
- "scripts/glass-probe/**"
- ".github/workflows/glass-probe.yml"

@superagent-security superagent-security Bot Oct 27, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Fork pull requests can queue the full three-OS glass probe by editing only the workflow file

A fork PR changing only this workflow file can queue the full 3-OS, 75-minute-per-job glass probe matrix.

Gate workflow-only changes on same-repo PRs, as perf-budget.yml and instant-reliability.yml already do.

AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.

<file name=".github/workflows/glass-probe.yml">
<violation number="1" location=".github/workflows/glass-probe.yml:16">
<priority>P2</priority>
<title>Fork pull requests can queue the full three-OS glass probe by editing only the workflow file</title>
<evidence>The newly added workflow runs on pull_request (opened, synchronize, reopened, ready_for_review) and lists its own file, `.github/workflows/glass-probe.yml`, in `paths` (line 16). A fork contributor can therefore change only this CI file and schedule the `probe` job matrix on three runners (`blacksmith-6vcpu-macos-15`, `windows-2022`, `blacksmith-8vcpu-ubuntu-2404`; lines 33-45) with `timeout-minutes: 75` per job (line 29). Each job runs `node scripts/setup.js`, prepares the patched GPUI dependency, builds the whole `cap-gpui` desktop app (lines 75-95), and runs the real-app probe. The cache step sets `save-cache: "false"` (line 70), so a fork cannot shorten later runs by writing a cache; `concurrency` with `cancel-in-progress: true` cancels only overlapping runs, and every subsequent `synchronize` push can queue a fresh matrix. This repository already fixed this exact workflow-only fork trigger pattern: `perf-budget.yml:54-60` only sets `own_files` for same-repository PRs, and `instant-reliability.yml:43-68` explicitly skips the macOS job for a fork PR that changes only that workflow. The glass probe omits that same-repo gate for changes to its own files.</evidence>
<recommendation>Add a lightweight scope job that computes whether the pull request changed only this workflow (and its CI harness) and, as in `perf-budget.yml` and `instant-reliability.yml`, allow that case to queue the probe only when `github.event.pull_request.head.repo.full_name == github.repository`. Keep the full matrix for changes to actual glass/product code, or reserve workflow-only validation for same-repository branches and workflow_dispatch.</recommendation>
</violation>
</file>

workflow_dispatch:

permissions:
contents: read
pull-requests: read

concurrency:
group: glass-probe-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
# A pull request from a fork that changes only this workflow or the probe's
# scripts does not queue the three-runner matrix; one that also changes the
# glass itself does, and so does any change from this repository.
scope:
name: Scope
runs-on: blacksmith-2vcpu-ubuntu-2404
timeout-minutes: 5
outputs:
run: ${{ steps.scope.outputs.run }}
steps:
- name: Scope
id: scope
env:
GH_TOKEN: ${{ github.token }}
EVENT: ${{ github.event_name }}
PR: ${{ github.event.pull_request.number }}
SAME_REPO: ${{ github.event.pull_request.head.repo.full_name == github.repository }}
run: |
set -euo pipefail
if [[ "$EVENT" != pull_request || "$SAME_REPO" == true ]]; then
echo "run=true" >> "$GITHUB_OUTPUT"; exit 0
fi
gh api "repos/$GITHUB_REPOSITORY/pulls/$PR/files" --paginate --jq '.[].filename' > "$RUNNER_TEMP/changed.txt"
glass='^apps/desktop-gpui/(glass/.*|patches/zed-glass\.patch|src/ui/glass\.rs|src/glass_probe\.rs)$'
if grep -qE "$glass" "$RUNNER_TEMP/changed.txt"; then
echo "run=true" >> "$GITHUB_OUTPUT"
else
echo "run=false" >> "$GITHUB_OUTPUT"
echo "A fork pull request that changes no glass code does not run the glass probe." | tee -a "$GITHUB_STEP_SUMMARY"
fi

probe:
name: Glass probe (${{ matrix.settings.name }})
needs: scope
if: needs.scope.outputs.run == 'true'
timeout-minutes: 75
strategy:
fail-fast: false
matrix:
settings:
- name: macOS
slug: macos
target: aarch64-apple-darwin
runner: blacksmith-6vcpu-macos-15
- name: Windows
slug: windows
target: x86_64-pc-windows-msvc
runner: windows-2022
- name: Linux X11
slug: linux-x11
target: x86_64-unknown-linux-gnu
runner: blacksmith-8vcpu-ubuntu-2404
runs-on: ${{ matrix.settings.runner }}
env:
CARGO_PROFILE_DEV_DEBUG: "0"
steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Install Linux desktop dependencies
if: ${{ runner.os == 'Linux' }}
uses: ./.github/actions/install-desktop-deps

- name: Install a window manager and software Vulkan
if: ${{ runner.os == 'Linux' }}
run: sudo apt-get install -y openbox mesa-vulkan-drivers libvulkan1

- name: Rust setup
uses: dtolnay/rust-toolchain@1.95.0
with:
targets: ${{ matrix.settings.target }}

- uses: ./.github/actions/setup-rust-cache
with:
target: ${{ matrix.settings.target }}
prefix-key: v1-rust-gpui
save-cache: "false"
workspaces: apps/desktop-gpui -> target

- name: Run setup
shell: bash
run: node scripts/setup.js
env:
RUST_TARGET_TRIPLE: ${{ matrix.settings.target }}

- name: Prepare GPUI dependency
shell: bash
run: |
node scripts/sync-desktop-versions.mjs
./scripts/prepare-gpui-dependency.sh

- name: Test the glass model
shell: bash
run: cargo +1.95.0 test --manifest-path apps/desktop-gpui/Cargo.toml --locked -p cap-glass

- name: Build the app
shell: bash
run: |
cargo +1.95.0 build --manifest-path apps/desktop-gpui/Cargo.toml --locked \
--target ${{ matrix.settings.target }} --bin cap-gpui
if [[ "$RUNNER_OS" == "macOS" ]]; then
for frameworks in "$GITHUB_WORKSPACE/apps/desktop-gpui/target/${{ matrix.settings.target }}/debug/Frameworks" \
"$GITHUB_WORKSPACE/apps/desktop-gpui/target/${{ matrix.settings.target }}/Frameworks"; do
mkdir -p "$frameworks"
ln -sfn "$GITHUB_WORKSPACE/target/Frameworks/Spacedrive.framework" "$frameworks/Spacedrive.framework"
done
fi

- name: Screen capture permission
if: ${{ runner.os == 'macOS' }}
run: |
set -euo pipefail
sudo pmset -a displaysleep 0 sleep 0 || true
caffeinate -u -t 2
app="$GITHUB_WORKSPACE/apps/desktop-gpui/target/${{ matrix.settings.target }}/debug/cap-gpui"
db="/Library/Application Support/com.apple.TCC/TCC.db"
now=$(date +%s)
for client in "$app" /bin/bash /Users/runner/bin/Runner.Worker /Users/runner/bin/Runner.Listener; do
sudo sqlite3 "$db" "INSERT OR REPLACE INTO access (service,client,client_type,auth_value,auth_reason,auth_version,indirect_object_identifier,flags,last_modified) VALUES ('kTCCServiceScreenCapture','$client',1,2,4,1,'UNUSED',0,$now);"
done
sudo killall tccd || true
sleep 2

- name: Glass probe
shell: bash
run: |
app="$GITHUB_WORKSPACE/apps/desktop-gpui/target/${{ matrix.settings.target }}/debug/cap-gpui"
out="$RUNNER_TEMP/glass-probe"
case "$RUNNER_OS" in
macOS)
scripts/glass-probe/run.sh "$app" "$out"
;;
Windows)
export PATH="$(cygpath "$GITHUB_WORKSPACE/target/debug"):$PATH"
scripts/glass-probe/run.sh "$app.exe" "$out"
;;
Linux)
export LD_LIBRARY_PATH="$GITHUB_WORKSPACE/target/native-deps/lib:$GITHUB_WORKSPACE/target/debug${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
Xvfb :99 -screen 0 1920x1080x24 -noreset &
export DISPLAY=:99
sleep 1
openbox &
sleep 1
scripts/glass-probe/run.sh "$app" "$out"
;;
esac

- name: Upload captures
if: always()
uses: actions/upload-artifact@v4
with:
name: glass-probe-${{ matrix.settings.slug }}
path: ${{ runner.temp }}/glass-probe
retention-days: 7

# The probed build itself, so the same binary can run on machines with
# real GPUs (the hosted runners draw on WARP and lavapipe).
- name: Stage the build
if: ${{ success() && runner.os != 'macOS' }}
shell: bash
run: |
out="$RUNNER_TEMP/cap-gpui-build"
mkdir -p "$out"
bin="$GITHUB_WORKSPACE/apps/desktop-gpui/target/${{ matrix.settings.target }}/debug/cap-gpui"
if [[ "$RUNNER_OS" == Windows ]]; then
cp "$bin.exe" "$out/"
cp "$GITHUB_WORKSPACE"/target/debug/*.dll "$out/" 2>/dev/null || true
else
cp "$bin" "$out/"
cp -r "$GITHUB_WORKSPACE/target/native-deps/lib" "$out/lib" 2>/dev/null || true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Linux build artifact stages libs where the loader never looks

Medium Severity

The Stage the build step copies target/native-deps/lib to $out/lib, but the Linux binary is linked with -Wl,-rpath,$ORIGIN -Wl,-rpath,$ORIGIN/../lib/cap (scripts/setup.js line 332 writes those rustflags to .cargo/config.toml because the workflow runs node scripts/setup.js with RUST_TARGET_TRIPLE), and it carries DT_NEEDED entries for ffmpeg's lib*.so.N sonames (ffmpeg-next linking against FFMPEG_DIR=target/native-deps). On a GPU machine the uploaded cap-gpui-debug-linux artifact therefore dies at process start with libavcodec.so.60: cannot open shared object file: the loader searches $ORIGIN (the artifact dir, which holds only the binary) and $ORIGIN/../lib/cap (which the step never creates — it ships lib, not lib/cap), and scripts/glass-probe/run.sh sets no LD_LIBRARY_PATH; the workflow's probe step is what exports LD_LIBRARY_PATH=target/native-deps/lib:target/debug, so CI green proves nothing about the artifact. The step also omits libonnxruntime.so* entirely — setup.js stages it into native-deps/onnxruntime/lib, not native-deps/lib, while camera-effects' ort (load-dynamic) dlopens it for segmentation. setup.js already stages exactly the runtime set (the versioned soname copies and the onnxruntime copies) into apps/desktop-gpui/target/<triple>/debug, right next to the binary where $ORIGIN looks; staging those *.so* beside the binary in $out (instead of the inert $out/lib tree) makes the artifact run with no environment. The Windows branch is fine: its DLLs land beside the exe, which the loader searches first.

Suggested change
cp -r "$GITHUB_WORKSPACE/target/native-deps/lib" "$out/lib" 2>/dev/null || true
cp "$(dirname "$bin")"/*.so* "$out/" 2>/dev/null || true

Open in Capy

fi

- name: Upload the build
if: ${{ success() && runner.os != 'macOS' }}
uses: actions/upload-artifact@v4
with:
name: cap-gpui-debug-${{ matrix.settings.slug }}
path: ${{ runner.temp }}/cap-gpui-build
if-no-files-found: ignore
retention-days: 3
10 changes: 10 additions & 0 deletions apps/desktop-gpui/Cargo.lock

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

7 changes: 6 additions & 1 deletion apps/desktop-gpui/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
# wgpu-hal, tao) that only exist for the Tauri app.
[workspace]
resolver = "2"
members = [".", "kernels", "i18n-build"]
members = [".", "kernels", "i18n-build", "glass"]

[package]
name = "cap-desktop-gpui"
Expand All @@ -27,6 +27,7 @@ path = "../../crates/recording/examples/studio-finalization-benchmark.rs"
cap-audio = { path = "../../crates/audio" }
cap-cli-install = { path = "../../crates/cli-install" }
cap-gpui-kernels = { path = "kernels" }
cap-glass = { path = "glass" }
# gpui — the wingleeio/zed fork Comet ships. The pinned rev carries f596cde
# ("destination alpha on transparent windows: Porter-Duff OVER, not additive"),
# which our transparent rounded main-window shell depends on.
Expand Down Expand Up @@ -333,6 +334,10 @@ debug = "line-tables-only"
[profile.dev.package.cap-gpui-kernels]
opt-level = 3

# The glass probe renders the CPU model of every scene it captures.
[profile.dev.package.cap-glass]
opt-level = 3

# Incremental halves a one-line rebuild for about 2 GB of cache, and line tables
# cut its codegen and link time; breakpoints and backtraces keep their lines.
[profile.dev.package.cap-desktop-gpui]
Expand Down
11 changes: 11 additions & 0 deletions apps/desktop-gpui/glass/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
[package]
name = "cap-glass"
version = "0.1.0"
edition = "2024"
license = "AGPL-3.0"
publish = false

[dependencies]
image = { version = "0.25.1", default-features = false, features = ["png"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
Loading
Loading