From e8aa1034aba483ab26ba17922a0c2348817bea57 Mon Sep 17 00:00:00 2001 From: tacogips Date: Tue, 2 Jun 2026 15:30:59 +0900 Subject: [PATCH 1/4] fix: restore main CI after git diff support 1. Primary Changes and Intent: Restored main CI compatibility after the Git diff viewer work by making Git available in Nix build, test, development, and packaged runtime contexts and by hardening Linux Tauri e2e execution under Xvfb. 2. Key Technical Concepts: - Nix nativeBuildInputs and dev shell runtime tools - Tauri packaged binary PATH wrapping for Git-backed diff commands - Crane cargo artifact reuse and Tauri build-script output invalidation - WebKitGTK/Xvfb software rendering with EGL and Mesa llvmpipe 3. Files and Code Sections: - flake.nix: Adds git to cargo artifact, package, clippy, and dev shell inputs; wraps the Linux binary PATH with git; clears stale Tauri build-script outputs before clippy when cargo artifacts are reused. - scripts/run-tauri-e2e-linux.sh: Adds EGL and Mesa software-rendering defaults for Linux e2e runs. - tests/tauri/tauri-smoke.e2e.ts: Mirrors the Linux headless rendering environment in generated Tauri launchers. 4. Problem Solving: Fixes nix-flake-check failures caused by missing git in the Nix sandbox and avoids stale Tauri OUT_DIR permission paths during clippy. Also addresses the tauri-e2e-linux EGL_BAD_PARAMETER startup failure by forcing X11 and llvmpipe software rendering. 5. Impact: Main CI can validate the Git diff feature without missing runtime tools, and Linux desktop smoke tests should start reliably in headless CI. 6. Unresolved TODOs: - [ ] None --- flake.nix | 20 ++++++++++++++++++-- scripts/run-tauri-e2e-linux.sh | 4 ++++ tests/tauri/tauri-smoke.e2e.ts | 4 ++++ 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index d4440c4..b3ac3c5 100644 --- a/flake.nix +++ b/flake.nix @@ -100,6 +100,7 @@ alsa-lib pipewire ]; + gitRuntimePath = lib.makeBinPath [ pkgs.git ]; linuxRuntimeLibraryPath = if pkgs.stdenv.isLinux then @@ -188,7 +189,7 @@ src = tauriBuildSource; cargoExtraArgs = "--manifest-path src-tauri/Cargo.toml"; buildInputs = commonBuildInputs; - nativeBuildInputs = with pkgs; [ pkg-config ]; + nativeBuildInputs = with pkgs; [ git pkg-config ]; }; chilla = craneLib.buildPackage { @@ -199,6 +200,7 @@ cargoExtraArgs = "--manifest-path src-tauri/Cargo.toml"; buildInputs = commonBuildInputs; nativeBuildInputs = with pkgs; [ + git makeWrapper pkg-config ]; @@ -217,6 +219,7 @@ postFixup = lib.optionalString pkgs.stdenv.isLinux '' wrapProgram $out/bin/chilla \ + --prefix PATH : "${gitRuntimePath}" \ --prefix LD_LIBRARY_PATH : "${linuxRuntimeLibraryPath}" \ --set GIO_EXTRA_MODULES "${linuxGioModulePath}" \ --set XDG_DATA_DIRS "${linuxXdgDataDirs}" \ @@ -250,6 +253,7 @@ openssl pkg-config taplo + git gh go-task ] @@ -269,7 +273,19 @@ inherit cargoArtifacts; cargoExtraArgs = "--manifest-path src-tauri/Cargo.toml"; buildInputs = commonBuildInputs; - nativeBuildInputs = with pkgs; [ pkg-config ]; + nativeBuildInputs = with pkgs; [ git pkg-config ]; + preBuild = '' + # Tauri caches build-script outputs with absolute OUT_DIR paths. + # When crane reuses cargoArtifacts across derivations, those paths + # point at the previous sandbox and break permission generation. + rm -rf target/release/build/tauri-* + rm -rf target/release/build/tauri-build-* + rm -rf target/release/build/tauri-plugin-* + rm -rf target/release/build/tauri-runtime-* + rm -rf target/release/build/tauri-runtime-wry-* + rm -rf target/release/build/tauri-utils-* + rm -rf target/release/build/chilla-* + ''; cargoClippyExtraArgs = "--all-targets -- -D warnings"; }; diff --git a/scripts/run-tauri-e2e-linux.sh b/scripts/run-tauri-e2e-linux.sh index 9f1a210..cdfc69b 100755 --- a/scripts/run-tauri-e2e-linux.sh +++ b/scripts/run-tauri-e2e-linux.sh @@ -22,8 +22,12 @@ fi export CARGO_TERM_QUIET=true export GDK_BACKEND="${GDK_BACKEND:-x11}" +export EGL_PLATFORM="${EGL_PLATFORM:-x11}" +export GALLIUM_DRIVER="${GALLIUM_DRIVER:-llvmpipe}" export GSK_RENDERER="${GSK_RENDERER:-cairo}" export LIBGL_ALWAYS_SOFTWARE="${LIBGL_ALWAYS_SOFTWARE:-1}" +export LIBGL_KOPPER_DISABLE="${LIBGL_KOPPER_DISABLE:-true}" +export MESA_LOADER_DRIVER_OVERRIDE="${MESA_LOADER_DRIVER_OVERRIDE:-llvmpipe}" export WEBKIT_DISABLE_COMPOSITING_MODE="${WEBKIT_DISABLE_COMPOSITING_MODE:-1}" export WEBKIT_DISABLE_DMABUF_RENDERER="${WEBKIT_DISABLE_DMABUF_RENDERER:-1}" export CHILLA_TAURI_E2E_REPO_ROOT="$repo_root" diff --git a/tests/tauri/tauri-smoke.e2e.ts b/tests/tauri/tauri-smoke.e2e.ts index 4c89565..10be06d 100644 --- a/tests/tauri/tauri-smoke.e2e.ts +++ b/tests/tauri/tauri-smoke.e2e.ts @@ -39,8 +39,12 @@ const FIXTURE_MP4_NAME = "file_example_MP4_480_1_5MG.mp4"; const SHUTDOWN_TIMEOUT_MS = 5_000; const HEADLESS_RENDER_ENV_EXPORTS = [ 'export GDK_BACKEND="${GDK_BACKEND:-x11}"', + 'export EGL_PLATFORM="${EGL_PLATFORM:-x11}"', + 'export GALLIUM_DRIVER="${GALLIUM_DRIVER:-llvmpipe}"', 'export GSK_RENDERER="${GSK_RENDERER:-cairo}"', 'export LIBGL_ALWAYS_SOFTWARE="${LIBGL_ALWAYS_SOFTWARE:-1}"', + 'export LIBGL_KOPPER_DISABLE="${LIBGL_KOPPER_DISABLE:-true}"', + 'export MESA_LOADER_DRIVER_OVERRIDE="${MESA_LOADER_DRIVER_OVERRIDE:-llvmpipe}"', 'export NO_AT_BRIDGE="${NO_AT_BRIDGE:-1}"', 'export WEBKIT_DISABLE_COMPOSITING_MODE="${WEBKIT_DISABLE_COMPOSITING_MODE:-1}"', 'export WEBKIT_DISABLE_DMABUF_RENDERER="${WEBKIT_DISABLE_DMABUF_RENDERER:-1}"', From 42d21c628d3d9da59799b0bad2b79ee776c8605a Mon Sep 17 00:00:00 2001 From: tacogips Date: Tue, 2 Jun 2026 15:43:44 +0900 Subject: [PATCH 2/4] fix: pin linux webkit stack for e2e stability 1. Primary Changes and Intent: Pins the Linux WebKitGTK and adjacent GUI/media runtime stack to nixos-24.05 while leaving the rest of the project on the existing Nix inputs, avoiding the WebKitGTK 2.48.3 EGL crash seen in GitHub Actions Tauri e2e. 2. Key Technical Concepts: - Separate Nixpkgs input for Linux GUI dependencies - WebKitGTK 4.1 ABI compatibility for Tauri v2 - GTK/GStreamer/runtime-library consistency under Nix dev shells and packages - Headless Linux WebDriver stability under Xvfb 3. Files and Code Sections: - flake.nix: Adds nixpkgs-webkit, imports it per system, and routes Linux GUI, GIO, XDG, WebKit media, and GStreamer packages through the pinned package set. - flake.lock: Records the nixos-24.05 nixpkgs input used for the pinned Linux WebKit stack. 4. Problem Solving: Addresses the persistent tauri-e2e-linux failure where WebKitGTK aborted with EGL_BAD_PARAMETER even after forcing software rendering environment variables. 5. Impact: Keeps Linux Tauri WebDriver tests on a known compatible WebKitGTK stack while preserving the main Nix build and development inputs. 6. Unresolved TODOs: - [ ] None --- flake.lock | 19 ++++++++++++++++++- flake.nix | 21 +++++++++++++-------- 2 files changed, 31 insertions(+), 9 deletions(-) diff --git a/flake.lock b/flake.lock index b07ceed..aa3cfae 100644 --- a/flake.lock +++ b/flake.lock @@ -162,6 +162,22 @@ "type": "github" } }, + "nixpkgs-webkit": { + "locked": { + "lastModified": 1735563628, + "narHash": "sha256-OnSAY7XDSx7CtDoqNh8jwVwh4xNL/2HaJxGjryLWzX8=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "b134951a4c9f3c995fd7be05f3243f8ecd65d798", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-24.05", + "repo": "nixpkgs", + "type": "github" + } + }, "nixpkgs_2": { "locked": { "lastModified": 1751290243, @@ -185,7 +201,8 @@ "fenix": "fenix", "flake-utils": "flake-utils", "nixpkgs": "nixpkgs_2", - "nixpkgs-unstable": "nixpkgs-unstable" + "nixpkgs-unstable": "nixpkgs-unstable", + "nixpkgs-webkit": "nixpkgs-webkit" } }, "rust-analyzer-src": { diff --git a/flake.nix b/flake.nix index b3ac3c5..1eaf634 100644 --- a/flake.nix +++ b/flake.nix @@ -3,6 +3,7 @@ inputs = { nixpkgs.url = "github:NixOS/nixpkgs/release-24.11"; + nixpkgs-webkit.url = "github:NixOS/nixpkgs/nixos-24.05"; nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; flake-utils.url = "github:numtide/flake-utils"; fenix = { @@ -20,6 +21,7 @@ { self, nixpkgs, + nixpkgs-webkit, nixpkgs-unstable, flake-utils, fenix, @@ -32,6 +34,7 @@ let overlays = [ fenix.overlays.default ]; pkgs = import nixpkgs { inherit system overlays; }; + pkgs-webkit = import nixpkgs-webkit { inherit system; }; pkgs-unstable = import nixpkgs-unstable { inherit system; }; lib = pkgs.lib; bun = pkgs-unstable.bun; @@ -59,7 +62,9 @@ ); }; - linuxGuiLibraries = with pkgs; [ + linuxGuiPkgs = if pkgs.stdenv.isLinux then pkgs-webkit else pkgs; + + linuxGuiLibraries = with linuxGuiPkgs; [ atk cairo gdk-pixbuf @@ -75,10 +80,10 @@ # - gstreamer itself for coreelements like typefind/fakesink # - base/good/bad/ugly/libav for container/codec support # - pipewire so autoaudiosink can resolve a compatible pipewiresink - linuxGStreamerCorePackage = pkgs.gst_all_1.gstreamer.out; + linuxGStreamerCorePackage = linuxGuiPkgs.gst_all_1.gstreamer.out; linuxGStreamerPluginPackages = - (with pkgs.gst_all_1; [ + (with linuxGuiPkgs.gst_all_1; [ gst-plugins-base gst-plugins-good gst-plugins-bad @@ -87,14 +92,14 @@ ]) ++ [ linuxGStreamerCorePackage - pkgs.pipewire + linuxGuiPkgs.pipewire ]; linuxGStreamerPluginPath = lib.makeSearchPath "lib/gstreamer-1.0" linuxGStreamerPluginPackages; linuxGStreamerPluginScanner = "${linuxGStreamerCorePackage}/libexec/gstreamer-1.0/gst-plugin-scanner"; - linuxWebkitMediaLibraries = with pkgs; [ + linuxWebkitMediaLibraries = with linuxGuiPkgs; [ ffmpeg libpulseaudio alsa-lib @@ -106,7 +111,7 @@ if pkgs.stdenv.isLinux then lib.makeLibraryPath ( linuxGuiLibraries - ++ (with pkgs.gst_all_1; [ + ++ (with linuxGuiPkgs.gst_all_1; [ linuxGStreamerCorePackage gst-plugins-base ]) @@ -114,11 +119,11 @@ ) else lib.makeLibraryPath linuxGuiLibraries; - linuxGioModulePath = lib.makeSearchPath "lib/gio/modules" (with pkgs; [ + linuxGioModulePath = lib.makeSearchPath "lib/gio/modules" (with linuxGuiPkgs; [ dconf.lib glib-networking ]); - linuxXdgDataDirs = lib.concatStringsSep ":" (with pkgs; [ + linuxXdgDataDirs = lib.concatStringsSep ":" (with linuxGuiPkgs; [ "${gsettings-desktop-schemas}/share/gsettings-schemas/${gsettings-desktop-schemas.name}" "${gtk3}/share/gsettings-schemas/${gtk3.name}" "${shared-mime-info}/share" From 51b9d3507ad2f717e267207eb1b16aec349f7172 Mon Sep 17 00:00:00 2001 From: tacogips Date: Tue, 2 Jun 2026 19:22:58 +0900 Subject: [PATCH 3/4] chore: add Apple notarization setup skill 1. Primary Changes and Intent: Added a project-scope Codex skill documenting the general Apple Developer ID, app-specific password, kinko storage, and notarization readiness workflow for chilla. 2. Key Technical Concepts: - Project-scope Codex skills under .agents/skills - Apple Developer ID Application signing - Apple app-specific passwords for notarization - kinko secret injection without credential disclosure - Nix shell notarytool wrapper guidance 3. Files and Code Sections: - .agents/skills/apple-notarization-setup/SKILL.md: New credential-safe procedural workflow for Apple signing and notarization setup. - .agents/skills/apple-notarization-setup/agents/openai.yaml: UI metadata for the new project skill. 4. Problem Solving: Captures the Apple registration and local notarization setup process as reusable project guidance without embedding any credential values. 5. Impact: Future local macOS signing/notarization work can follow a consistent, credential-safe workflow. 6. Unresolved TODOs: - [ ] None --- .../skills/apple-notarization-setup/SKILL.md | 169 ++++++++++++++++++ .../agents/openai.yaml | 4 + 2 files changed, 173 insertions(+) create mode 100644 .agents/skills/apple-notarization-setup/SKILL.md create mode 100644 .agents/skills/apple-notarization-setup/agents/openai.yaml diff --git a/.agents/skills/apple-notarization-setup/SKILL.md b/.agents/skills/apple-notarization-setup/SKILL.md new file mode 100644 index 0000000..9188cc8 --- /dev/null +++ b/.agents/skills/apple-notarization-setup/SKILL.md @@ -0,0 +1,169 @@ +--- +name: apple-notarization-setup +description: Use when setting up or verifying Apple Developer ID signing credentials, Apple app-specific passwords, kinko secret storage, or local macOS notarization readiness for chilla without recording credential values. +--- + +# Apple Notarization Setup + +Use this for chilla macOS signing/notarization setup before local deploys or release builds. Keep all credential values out of logs, skill files, commits, and final responses. + +## Credential Safety + +- Never print, paste, commit, or summarize actual Apple passwords, app-specific passwords, certificate passwords, private keys, `.p12` contents, or kinko secret values. +- It is acceptable to mention secret key names such as `APPLE_ID`, `APPLE_PASSWORD`, `APPLE_TEAM_ID`, and `APPLE_SIGNING_IDENTITY`. +- When a private login, passkey, or 2FA step is needed, use Computer Use to navigate to the prompt, then ask the user to enter it directly in the browser or system dialog. +- Use `kinko exec --env ...` for commands that need secrets. Do not use commands that echo exported secret values. + +## Required Local Inputs + +The local notarization path expects: + +- A valid Developer ID Application certificate imported into the macOS login keychain. +- `APPLE_SIGNING_IDENTITY` stored in kinko. +- `APPLE_ID` stored in kinko. +- `APPLE_TEAM_ID` stored in kinko. +- `APPLE_PASSWORD` stored in kinko as an Apple app-specific password. + +Check presence only: + +```bash +kinko exec --env APPLE_SIGNING_IDENTITY,APPLE_ID,APPLE_PASSWORD,APPLE_TEAM_ID -- bash -lc ' +for key in APPLE_SIGNING_IDENTITY APPLE_ID APPLE_PASSWORD APPLE_TEAM_ID; do + if [ -n "${!key:-}" ]; then echo "$key=present"; else echo "$key=missing"; fi +done +' +``` + +Check the local certificate: + +```bash +security find-identity -v -p codesigning +``` + +Expect a valid `Developer ID Application` identity matching `APPLE_SIGNING_IDENTITY`. + +## App-Specific Password Flow + +Use Computer Use for browser navigation when requested. + +1. Open `https://account.apple.com/account/manage`. +2. Ask the user to complete Apple Account login, passkey, and 2FA directly in Safari. +3. Open `Sign-In and Security`. +4. Open `App-Specific Passwords`. +5. Generate a password with a label such as `Chilla`. +6. Store it in kinko as `APPLE_PASSWORD`. +7. Do not include the generated password in chat, commits, or files. + +Use kinko storage: + +```bash +kinko set-key APPLE_PASSWORD --value '' +``` + +After storage, avoid showing the value again. If the browser dialog is still open, close it after confirming the password is stored. + +## Local Build And Notarization + +Prefer the existing macOS release skill and tasks for actual packaging. The common local command is: + +```bash +kinko exec --env APPLE_SIGNING_IDENTITY,APPLE_ID,APPLE_PASSWORD,APPLE_TEAM_ID -- task bundle-macos-dmg +``` + +This builds: + +- `target/release/bundle/macos/chilla.app` +- `target/release/bundle/dmg/*.dmg` after notarization and DMG packaging complete + +Cargo commands must use `CARGO_TERM_QUIET=true` when invoked directly. + +## Nix Environment Notarytool Workaround + +In this repository's Nix shell, `xcrun` may point at the Nix Apple SDK and fail with: + +```text +tool 'notarytool' not found +``` + +Do not replace the whole build environment with the system Xcode `DEVELOPER_DIR`; that can break Nix SDK linking. Instead, create a temporary `notarytool` wrapper and keep the Nix build environment intact: + +```bash +tmp_notary_dir=/tmp/chilla-notarytool-wrapper +mkdir -p "$tmp_notary_dir" +printf '%s\n' \ + '#!/usr/bin/env bash' \ + 'exec /Applications/Xcode.app/Contents/Developer/usr/bin/notarytool "$@"' \ + > "$tmp_notary_dir/notarytool" +chmod 700 "$tmp_notary_dir/notarytool" + +kinko exec --env APPLE_SIGNING_IDENTITY,APPLE_ID,APPLE_PASSWORD,APPLE_TEAM_ID -- bash -lc ' + export PATH="/tmp/chilla-notarytool-wrapper:$PATH" + task bundle-macos-dmg +' +``` + +If `/Applications/Xcode.app/Contents/Developer/usr/bin/notarytool` is unavailable, check: + +```bash +/usr/bin/mdfind 'kMDItemFSName == "notarytool"' +``` + +## Notarization Status + +When Tauri submits notarization, record only the submission ID and status. To check status: + +```bash +kinko exec --env APPLE_ID,APPLE_PASSWORD,APPLE_TEAM_ID -- bash -lc ' +/Applications/Xcode.app/Contents/Developer/usr/bin/notarytool info \ + --apple-id "$APPLE_ID" \ + --password "$APPLE_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" +' +``` + +Look for: + +```text +status: Accepted +``` + +Recent submissions: + +```bash +kinko exec --env APPLE_ID,APPLE_PASSWORD,APPLE_TEAM_ID -- bash -lc ' +/Applications/Xcode.app/Contents/Developer/usr/bin/notarytool history \ + --apple-id "$APPLE_ID" \ + --password "$APPLE_PASSWORD" \ + --team-id "$APPLE_TEAM_ID" +' +``` + +If a submission stays `In Progress`, do not claim deployment is complete. Report that Apple has not returned a decision yet. + +## Validation After Acceptance + +After notarization is accepted and artifacts exist: + +```bash +codesign --verify --deep --strict --verbose=2 target/release/bundle/macos/chilla.app +xcrun stapler validate target/release/bundle/macos/chilla.app +xcrun stapler validate target/release/bundle/dmg/*.dmg +spctl --assess --type execute --verbose=4 target/release/bundle/macos/chilla.app +spctl --assess --type open --context context:primary-signature --verbose=4 target/release/bundle/dmg/*.dmg +``` + +If `xcrun stapler` cannot find tools due to the Nix SDK, call the Xcode tool directly when appropriate: + +```bash +/Applications/Xcode.app/Contents/Developer/usr/bin/stapler validate target/release/bundle/macos/chilla.app +``` + +## Completion Criteria + +Local Apple setup is complete when: + +- kinko has all required Apple secret keys present. +- `security find-identity` reports a valid Developer ID Application identity. +- `task bundle-macos-dmg` or the wrapper-based equivalent signs the app. +- Notarization reaches `Accepted`. +- Stapler and Gatekeeper validation pass for the app and DMG. diff --git a/.agents/skills/apple-notarization-setup/agents/openai.yaml b/.agents/skills/apple-notarization-setup/agents/openai.yaml new file mode 100644 index 0000000..b662028 --- /dev/null +++ b/.agents/skills/apple-notarization-setup/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Apple Notarization Setup" + short_description: "Set up Apple signing and notarization prerequisites for chilla" + default_prompt: "Set up or verify Apple Developer ID signing, app-specific password storage, and local notarization readiness for chilla without exposing credential values." From 82e3c419bf71033d807fef49bcd0da11ff2fc27a Mon Sep 17 00:00:00 2001 From: tacogips Date: Tue, 2 Jun 2026 19:23:14 +0900 Subject: [PATCH 4/4] fix: wait for workspace path in Linux e2e 1. Primary Changes and Intent: Updated the Linux Tauri smoke test to wait until the workspace path text reflects the loaded fixture workspace before asserting startup success. 2. Key Technical Concepts: - Selenium WebDriver polling - Tauri desktop startup synchronization - Linux headless e2e timing stability 3. Files and Code Sections: - tests/tauri/tauri-smoke.e2e.ts: Reuses the existing waitUntil helper around .file-browser__path text retrieval so transient Loading... content does not fail the startup check. 4. Problem Solving: Fixes the latest tauri-e2e-linux failure where the app started successfully but the test read the path element before workspace loading completed. 5. Impact: The Linux e2e check should now wait for the same user-visible readiness state it asserts, reducing CI timing flakiness after WebKit startup is fixed. 6. Unresolved TODOs: - [ ] None --- tests/tauri/tauri-smoke.e2e.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/tauri/tauri-smoke.e2e.ts b/tests/tauri/tauri-smoke.e2e.ts index 10be06d..2292eed 100644 --- a/tests/tauri/tauri-smoke.e2e.ts +++ b/tests/tauri/tauri-smoke.e2e.ts @@ -277,9 +277,14 @@ async function verifyWorkspaceLoads( until.elementLocated(By.css(".file-browser__path")), STARTUP_TIMEOUT_MS, ); - const pathText = await pathElement.getText(); + let pathText = ""; + await waitUntil(currentDriver, async () => { + pathText = await pathElement.getText(); + + return pathText.includes(expectedWorkspaceRoot); + }); - if (!pathText.includes(expectedWorkspaceRoot)) { + if (pathText.length === 0 || !pathText.includes(expectedWorkspaceRoot)) { throw new Error( `Expected workspace path to include ${expectedWorkspaceRoot}, got ${JSON.stringify(pathText)}`, );