-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat(v3): Add WindowMouseEnter/WindowMouseLeave events for tray popup windows #4889
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v3-alpha
Are you sure you want to change the base?
Conversation
I've implemented mouse enter/leave events for Wails v3 windows across all three platforms. Here's what was done: ### 1. New Events Added (`v3/pkg/events/events.go`) - `WindowMouseEnter` (ID 1259) - fired when mouse enters a window - `WindowMouseLeave` (ID 1260) - fired when mouse leaves a window ### 2. Platform Implementations **Windows** (`webview_window_windows.go`): - Uses `WM_MOUSEMOVE` with `TrackMouseEvent` API to start tracking - Uses `WM_MOUSELEAVE` to detect when mouse exits - Works even when window is not focused **macOS** (`webview_window_darwin.m`): - Created `MouseTrackingView` class with `NSTrackingArea` - Uses `NSTrackingActiveAlways` flag to track mouse even when unfocused - Implements `mouseEntered:` and `mouseExited:` handlers - View is transparent to clicks (passes through to underlying content) **Linux** (`linux_cgo.go`): - Added `GDK_ENTER_NOTIFY_MASK` and `GDK_LEAVE_NOTIFY_MASK` event masks - Connected `enter-notify-event` and `leave-notify-event` GTK signals - Filters out `GDK_NOTIFY_INFERIOR` events to avoid spurious triggers ### 3. New Window Option (`webview_window_options.go`) - `FocusOnMouseEnter bool` - When true, automatically focuses the window when mouse enters ### 4. Example (`v3/examples/mouse-hover/`) - Demonstrates both mouse events and the `FocusOnMouseEnter` option - Shows events in the UI and logs them to console - Includes a README explaining the use cases ### 5. Documentation - Updated `UNRELEASED_CHANGELOG.md` with the new features ### Answers to Your Questions 1. **Would this method work?** Yes, using mouse enter events to focus a window is a viable approach, especially for tray popup windows. 2. **Do windows get mouse enter events when not focused?** Yes, on all platforms: - Windows: Uses `TrackMouseEvent` which works regardless of focus - macOS: Uses `NSTrackingActiveAlways` flag - Linux: GTK's enter/leave events work on unfocused windows 3. **Implementation difficulty:** - **Windows**: Easiest - existing `TrackMouseEvent` API - **macOS**: Moderate - required creating tracking view with `NSTrackingArea` - **Linux**: Straightforward - just adding GTK event masks and signal handlers
…seEnter", ...)` which uses the event string directly. The `wails.Events.Types.Common.WindowMouseEnter` is also valid (it just returns the string `"common:WindowMouseEnter"`), but using the string directly is simpler and more commonly seen in the examples.
## Summary 1. **Removed the `mouse-hover` binary** from the branch (it was accidentally committed) 2. **Fixed event generation** - Events are now properly added via `events.txt`: - Added `common:WindowMouseEnter` and `common:WindowMouseLeave` to `v3/pkg/events/events.txt` - Ran the generator to regenerate all event files 3. **Added standard Wails generated code headers** to the generator templates in `v3/tasks/events/generate.go`: - `events.go` now includes the Wails logo and English/Welsh comments - `events_darwin.h`, `events_linux.h`, `events_ios.h` all include the headers - `event_types.ts` already had the headers 4. **Updated AGENTS.md** with comprehensive documentation about the event system: - Which files are generated (and should not be edited manually) - How to add new events properly - The generator commands to run - Event naming conventions - Example of adding new common events - The standard header format 5. **Rebuilt the JavaScript runtime** with the new events The changes are now ready for review. The key files modified: - `AGENTS.md` - Added event system documentation - `v3/pkg/events/events.txt` - Added new events - `v3/tasks/events/generate.go` - Added Wails headers to templates - Generated files: `events.go`, `events_darwin.h`, `events_linux.h`, `events_ios.h`, `event_types.ts`
…rn used elsewhere in the Wails codebase. Both are technically correct for MRC, but `autorelease` is the pattern used throughout the rest of the code for objects that get passed to another owner (like a superview).
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
| name: Detect v2 Changes | ||
| runs-on: ubuntu-latest | ||
| needs: check-permissions | ||
| if: needs.check-permissions.outputs.authorized == 'true' | ||
| outputs: | ||
| has_changes: ${{ steps.changes.outputs.has_changes }} | ||
| commits_since_last: ${{ steps.changes.outputs.commits_since_last }} | ||
| last_release_tag: ${{ steps.changes.outputs.last_release_tag }} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Check for v2 changes since last release | ||
| id: changes | ||
| run: | | ||
| echo "🔍 Checking for v2 changes since last release..." | ||
|
|
||
| # Find the last v2 release tag | ||
| LAST_TAG=$(git tag -l "v2.*" --sort=-version:refname | head -n 1) | ||
| if [ -z "$LAST_TAG" ]; then | ||
| echo "No previous v2 tags found, assuming first release" | ||
| LAST_TAG=$(git rev-list --max-parents=0 HEAD) | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| echo "commits_since_last=999" >> $GITHUB_OUTPUT | ||
| echo "last_release_tag=none" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "Last v2 release tag: $LAST_TAG" | ||
| echo "last_release_tag=$LAST_TAG" >> $GITHUB_OUTPUT | ||
|
|
||
| # Count commits since last release affecting v2 or root files | ||
| COMMITS_COUNT=$(git rev-list --count ${LAST_TAG}..HEAD -- v2/ website/ README.md CHANGELOG.md || echo "0") | ||
| echo "Commits since last v2 release: $COMMITS_COUNT" | ||
| echo "commits_since_last=$COMMITS_COUNT" >> $GITHUB_OUTPUT | ||
|
|
||
| if [ "$COMMITS_COUNT" -gt 0 ] || [ "${{ github.event.inputs.force_release }}" == "true" ]; then | ||
| echo "✅ Changes detected or forced release" | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "ℹ️ No changes detected since last release" | ||
| echo "has_changes=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| fi | ||
|
|
||
| detect-v3-changes: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the fix is to explicitly set a permissions block so that the GITHUB_TOKEN has only the minimal rights required. For read-only analysis jobs like detect-v2-changes and detect-v3-changes, contents: read is sufficient. Other jobs that create releases or tags may need contents: write and possibly packages: write or similar, but we should only grant those to the specific jobs that perform write operations, not globally.
The best fix here without changing functionality is to add a workflow‑level permissions block near the top of .github/workflows/automated-releases.yml, setting contents: read as the default for all jobs. The existing check-permissions job already declares permissions: {}, so it will remain with no token permissions, which is safe. Jobs that need elevated rights (e.g., release-v2, release-v3-alpha, or similar later in the file) can override the default in their own permissions section; since their code is not shown, we won’t touch them. This change satisfies CodeQL’s requirement for explicit permissions, limits the default GITHUB_TOKEN to read-only, and does not affect the existing behavior of the detection jobs, which only read git history and do not push changes.
Concretely:
- Edit
.github/workflows/automated-releases.yml. - Insert a
permissions:block after thename:(or after theon:block, either is valid) that setscontents: read. - Leave all existing job definitions unchanged, including
check-permissions: permissions: {}.
-
Copy modified lines R3-R5
| @@ -1,5 +1,8 @@ | ||
| name: Automated Nightly Releases | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: |
| name: Detect v3-alpha Changes | ||
| runs-on: ubuntu-latest | ||
| needs: check-permissions | ||
| if: needs.check-permissions.outputs.authorized == 'true' | ||
| outputs: | ||
| has_changes: ${{ steps.changes.outputs.has_changes }} | ||
| commits_since_last: ${{ steps.changes.outputs.commits_since_last }} | ||
| last_release_tag: ${{ steps.changes.outputs.last_release_tag }} | ||
| steps: | ||
| - name: Checkout v3-alpha branch | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: v3-alpha | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Check for v3-alpha changes since last release | ||
| id: changes | ||
| run: | | ||
| echo "🔍 Checking for v3-alpha changes since last release..." | ||
|
|
||
| # Find the last v3 alpha release tag | ||
| LAST_TAG=$(git tag -l "v3.*-alpha.*" --sort=-version:refname | head -n 1) | ||
| if [ -z "$LAST_TAG" ]; then | ||
| echo "No previous v3-alpha tags found, assuming first release" | ||
| LAST_TAG=$(git rev-list --max-parents=0 HEAD) | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| echo "commits_since_last=999" >> $GITHUB_OUTPUT | ||
| echo "last_release_tag=none" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "Last v3-alpha release tag: $LAST_TAG" | ||
| echo "last_release_tag=$LAST_TAG" >> $GITHUB_OUTPUT | ||
|
|
||
| # Count commits since last release affecting v3 or docs | ||
| COMMITS_COUNT=$(git rev-list --count ${LAST_TAG}..HEAD -- v3/ docs/ || echo "0") | ||
| echo "Commits since last v3-alpha release: $COMMITS_COUNT" | ||
| echo "commits_since_last=$COMMITS_COUNT" >> $GITHUB_OUTPUT | ||
|
|
||
| if [ "$COMMITS_COUNT" -gt 0 ] || [ "${{ github.event.inputs.force_release }}" == "true" ]; then | ||
| echo "✅ Changes detected or forced release" | ||
| echo "has_changes=true" >> $GITHUB_OUTPUT | ||
| else | ||
| echo "ℹ️ No changes detected since last release" | ||
| echo "has_changes=false" >> $GITHUB_OUTPUT | ||
| fi | ||
| fi | ||
|
|
||
| release-v2: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the problem is fixed by explicitly declaring a permissions block to limit the GITHUB_TOKEN to the minimal scopes required. This can be done at the workflow level (applies to all jobs) and overridden per job where more permissions are needed. For jobs that only read the repository (like detect-v2-changes and detect-v3-changes), contents: read is sufficient. For jobs that create or update releases/tags, you typically need contents: write (and potentially pull-requests: write or others if they modify PRs).
The best way to fix this specific workflow without changing functionality is:
- Add a workflow-level
permissions:block setting a secure default, e.g.contents: read. - Keep
check-permissions’s existingpermissions: {}(equivalent to no permissions) since it only runs shell code and usesgithub.actorfrom the event context. - For release jobs that actually perform writes (e.g.,
release-v2andrelease-v3), add per-jobpermissions:blocks that grantcontents: write. This ensures detect-only jobs likedetect-v3-changes(the one flagged by CodeQL) inherit onlycontents: read, satisfying the analyzer’s recommendation while preserving existing behavior.
Concretely:
- In
.github/workflows/automated-releases.yml, above theenv:block (afteron:), insert a workflow-levelpermissions:block withcontents: read. - In the same file, add
permissions:blocks torelease-v2andrelease-v3jobs (once you reach their job definitions) grantingcontents: write. The snippet forrelease-v3is elided, but you can still add the block at its job root. No new imports or external dependencies are required.
-
Copy modified lines R20-R22 -
Copy modified lines R150-R151 -
Copy modified lines R238-R239
| @@ -17,6 +17,9 @@ | ||
| # Run at 2 AM UTC every day - DISABLED for safety until ready | ||
| # - cron: '0 2 * * *' | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| env: | ||
| GO_VERSION: '1.24' | ||
|
|
||
| @@ -144,6 +147,8 @@ | ||
| if: | | ||
| needs.check-permissions.outputs.authorized == 'true' && | ||
| needs.detect-v2-changes.outputs.has_changes == 'true' | ||
| permissions: | ||
| contents: write | ||
| outputs: | ||
| version: ${{ steps.release.outputs.version }} | ||
| release_notes: ${{ steps.release.outputs.release_notes }} | ||
| @@ -230,6 +235,8 @@ | ||
| cat release_notes_v2.md | ||
|
|
||
| release-v3: | ||
| permissions: | ||
| contents: write | ||
| name: Create v3-alpha Release | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v3-changes] |
| name: Create v2 Release | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v2-changes] | ||
| if: | | ||
| needs.check-permissions.outputs.authorized == 'true' && | ||
| needs.detect-v2-changes.outputs.has_changes == 'true' | ||
| outputs: | ||
| version: ${{ steps.release.outputs.version }} | ||
| release_notes: ${{ steps.release.outputs.release_notes }} | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v4 | ||
| with: | ||
| go-version: ${{ env.GO_VERSION }} | ||
|
|
||
| - name: Run v2 release script and extract notes | ||
| id: release | ||
| run: | | ||
| echo "🚀 Running v2 release script..." | ||
| cd v2/tools/release | ||
|
|
||
| # Run release script and capture output | ||
| RELEASE_OUTPUT=$(go run release.go 2>&1) | ||
| echo "$RELEASE_OUTPUT" | ||
|
|
||
| # Extract version from output or version file | ||
| NEW_VERSION=$(cat ../../cmd/wails/internal/version.txt) | ||
| echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| # Extract release notes from delimited output | ||
| RELEASE_NOTES=$(echo "$RELEASE_OUTPUT" | sed -n '/=== RELEASE NOTES FOR/,/=== END RELEASE NOTES ===/p' | sed '1d;$d') | ||
|
|
||
| # Save release notes to file for multiline output | ||
| echo "$RELEASE_NOTES" > ../../../release_notes_v2.md | ||
|
|
||
| # Set output (escape for GitHub Actions) | ||
| { | ||
| echo "release_notes<<EOF" | ||
| echo "$RELEASE_NOTES" | ||
| echo "EOF" | ||
| } >> $GITHUB_OUTPUT | ||
|
|
||
| echo "✅ v2 release script completed - version: $NEW_VERSION" | ||
|
|
||
| - name: Create v2 git tag and release | ||
| if: github.event.inputs.dry_run != 'true' | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| VERSION="${{ steps.release.outputs.version }}" | ||
| echo "📝 Creating v2 release: $VERSION" | ||
|
|
||
| # Configure git | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| # Commit the changelog changes | ||
| git add website/src/pages/changelog.mdx v2/cmd/wails/internal/version.txt | ||
| git commit -m "chore: release $VERSION | ||
|
|
||
| Automated release created by GitHub Actions | ||
|
|
||
| 🤖 Generated with [Claude Code](https://claude.ai/code) | ||
|
|
||
| Co-Authored-By: Claude <noreply@anthropic.com>" | ||
|
|
||
| # Create and push tag | ||
| git tag -a "$VERSION" -m "Release $VERSION" | ||
| git push origin master | ||
| git push origin "$VERSION" | ||
|
|
||
| # Create GitHub release with notes | ||
| gh release create "$VERSION" \ | ||
| --title "Release $VERSION" \ | ||
| --notes-file release_notes_v2.md \ | ||
| --target master | ||
|
|
||
| - name: Log dry-run results for v2 | ||
| if: github.event.inputs.dry_run == 'true' | ||
| run: | | ||
| echo "🧪 DRY RUN - Would have created v2 release:" | ||
| echo "Version: ${{ steps.release.outputs.version }}" | ||
| echo "Release Notes:" | ||
| cat release_notes_v2.md | ||
|
|
||
| release-v3: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the fix is to add explicit permissions: blocks to the workflow so that each job’s GITHUB_TOKEN has the minimum scopes it needs. Jobs that only check out code and run read-only checks can typically use contents: read. Jobs that push commits/tags or create releases must request contents: write. This makes the workflow’s security posture explicit and satisfies the CodeQL rule.
For this workflow, the minimal, non-breaking adjustment is:
- Add a workflow-level
permissions: contents: readto give all jobs read-only access by default. - Override that default for the
release-v2andrelease-v3jobs, which actually perform write operations usingGITHUB_TOKEN, by addingpermissions: contents: writeto those jobs. - Jobs like
check-permissions,detect-v2-changes, anddetect-v3-changesonly need to read repository contents and metadata, so they can safely use the inheritedcontents: read.
Concretely:
- At the top of
.github/workflows/automated-releases.yml, right aftername: Automated Nightly Releases, insert apermissions:block withcontents: read. - Within the
release-v2:job definition (line 140 onward), add apermissions:block (e.g. betweenname:andruns-on:) settingcontents: write. - Do the same for the
release-v3:job definition.
No additional imports or external packages are needed; this is purely a YAML configuration change.
-
Copy modified lines R2-R3 -
Copy modified lines R144-R145 -
Copy modified lines R238-R239
| @@ -1,4 +1,6 @@ | ||
| name: Automated Nightly Releases | ||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| @@ -139,6 +141,8 @@ | ||
|
|
||
| release-v2: | ||
| name: Create v2 Release | ||
| permissions: | ||
| contents: write | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v2-changes] | ||
| if: | | ||
| @@ -231,6 +235,8 @@ | ||
|
|
||
| release-v3: | ||
| name: Create v3-alpha Release | ||
| permissions: | ||
| contents: write | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v3-changes] | ||
| if: | |
| name: Create v3-alpha Release | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v3-changes] | ||
| if: | | ||
| needs.check-permissions.outputs.authorized == 'true' && | ||
| needs.detect-v3-changes.outputs.has_changes == 'true' | ||
| outputs: | ||
| version: ${{ steps.release.outputs.version }} | ||
| release_notes: ${{ steps.release.outputs.release_notes }} | ||
| steps: | ||
| - name: Checkout v3-alpha branch | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: v3-alpha | ||
| fetch-depth: 0 | ||
| token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v4 | ||
| with: | ||
| go-version: ${{ env.GO_VERSION }} | ||
|
|
||
| - name: Run v3 release script and extract notes | ||
| id: release | ||
| run: | | ||
| echo "🚀 Running v3-alpha release script..." | ||
| cd v3/tasks/release | ||
|
|
||
| # Run release script and capture output | ||
| RELEASE_OUTPUT=$(go run release.go 2>&1) | ||
| echo "$RELEASE_OUTPUT" | ||
|
|
||
| # Extract version from output or version file | ||
| NEW_VERSION=$(cat ../../internal/version/version.txt) | ||
| echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| # Extract release notes from delimited output | ||
| RELEASE_NOTES=$(echo "$RELEASE_OUTPUT" | sed -n '/=== RELEASE NOTES FOR/,/=== END RELEASE NOTES ===/p' | sed '1d;$d') | ||
|
|
||
| # Save release notes to file for multiline output | ||
| echo "$RELEASE_NOTES" > ../../../release_notes_v3.md | ||
|
|
||
| # Set output (escape for GitHub Actions) | ||
| { | ||
| echo "release_notes<<EOF" | ||
| echo "$RELEASE_NOTES" | ||
| echo "EOF" | ||
| } >> $GITHUB_OUTPUT | ||
|
|
||
| echo "✅ v3-alpha release script completed - version: $NEW_VERSION" | ||
|
|
||
| - name: Create v3-alpha git tag and release | ||
| if: github.event.inputs.dry_run != 'true' | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| run: | | ||
| VERSION="${{ steps.release.outputs.version }}" | ||
| echo "📝 Creating v3-alpha release: $VERSION" | ||
|
|
||
| # Configure git | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| # Commit the changelog changes | ||
| git add docs/src/content/docs/changelog.mdx v3/internal/version/version.txt | ||
| git commit -m "chore: release $VERSION | ||
|
|
||
| Automated v3-alpha release created by GitHub Actions | ||
|
|
||
| 🤖 Generated with [Claude Code](https://claude.ai/code) | ||
|
|
||
| Co-Authored-By: Claude <noreply@anthropic.com>" | ||
|
|
||
| # Create and push tag | ||
| git tag -a "$VERSION" -m "Release $VERSION" | ||
| git push origin v3-alpha | ||
| git push origin "$VERSION" | ||
|
|
||
| # Create GitHub release with notes | ||
| gh release create "$VERSION" \ | ||
| --title "Release $VERSION" \ | ||
| --notes-file release_notes_v3.md \ | ||
| --target v3-alpha \ | ||
| --prerelease | ||
|
|
||
| - name: Log dry-run results for v3-alpha | ||
| if: github.event.inputs.dry_run == 'true' | ||
| run: | | ||
| echo "🧪 DRY RUN - Would have created v3-alpha release:" | ||
| echo "Version: ${{ steps.release.outputs.version }}" | ||
| echo "Release Notes:" | ||
| cat release_notes_v3.md | ||
|
|
||
| summary: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
To fix this, add explicit permissions blocks that grant only the scopes each job actually needs, instead of relying on implicit repository defaults. Since some jobs (like check-permissions) do not need the GITHUB_TOKEN at all, they can keep permissions: {}. Jobs that only read code (e.g., change-detection jobs, not fully shown) can be given contents: read. The release-v2 and release-v3 jobs, which commit, tag, push, and create releases, need contents: write and packages: write (for gh release create and any potential artifacts), plus pull-requests: write only if they actually modify PRs (not shown here, so we will not add it).
Concretely, in .github/workflows/automated-releases.yml, add a top-level permissions: block after name: that sets a safe default such as contents: read. Then, for the release-v2, release-v3, and summary jobs, add job-level permissions blocks tailored to their needs. release-v2 and release-v3 should get contents: write (they push commits/tags) and contents: read is implied by write; summary only writes to $GITHUB_STEP_SUMMARY, which does not require repo write scope, so it can inherit the default contents: read and does not need its own override. The CodeQL warning is specifically on release-v3, so we will explicitly add permissions to that job (and, for consistency, to release-v2 as well, since it performs similar operations). No new libraries or external dependencies are needed; this is purely a workflow YAML change.
-
Copy modified lines R3-R5 -
Copy modified lines R147-R148 -
Copy modified lines R241-R242
| @@ -1,5 +1,8 @@ | ||
| name: Automated Nightly Releases | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
| inputs: | ||
| @@ -141,6 +144,8 @@ | ||
| name: Create v2 Release | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v2-changes] | ||
| permissions: | ||
| contents: write | ||
| if: | | ||
| needs.check-permissions.outputs.authorized == 'true' && | ||
| needs.detect-v2-changes.outputs.has_changes == 'true' | ||
| @@ -233,6 +238,8 @@ | ||
| name: Create v3-alpha Release | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v3-changes] | ||
| permissions: | ||
| contents: write | ||
| if: | | ||
| needs.check-permissions.outputs.authorized == 'true' && | ||
| needs.detect-v3-changes.outputs.has_changes == 'true' |
| name: Release Summary | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v2-changes, detect-v3-changes, release-v2, release-v3] | ||
| if: always() && needs.check-permissions.outputs.authorized == 'true' | ||
| steps: | ||
| - name: Create release summary | ||
| run: | | ||
| echo "# 🚀 Automated Release Summary" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "**Repository**: ${{ github.repository }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "**Triggered by**: ${{ github.actor }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "**Dry Run Mode**: ${{ github.event.inputs.dry_run || 'false' }}" >> $GITHUB_STEP_SUMMARY | ||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
|
|
||
| # v2 Summary | ||
| echo "## v2 Release" >> $GITHUB_STEP_SUMMARY | ||
| if [ "${{ needs.detect-v2-changes.outputs.has_changes }}" == "true" ]; then | ||
| if [ "${{ needs.release-v2.result }}" == "success" ]; then | ||
| echo "✅ **v2 Release**: Created successfully" >> $GITHUB_STEP_SUMMARY | ||
| echo " - Version: ${{ needs.release-v2.outputs.version }}" >> $GITHUB_STEP_SUMMARY | ||
| echo " - Commits since last: ${{ needs.detect-v2-changes.outputs.commits_since_last }}" >> $GITHUB_STEP_SUMMARY | ||
| else | ||
| echo "❌ **v2 Release**: Failed" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
| else | ||
| echo "⏭️ **v2 Release**: Skipped (no changes)" >> $GITHUB_STEP_SUMMARY | ||
| echo " - Commits since last: ${{ needs.detect-v2-changes.outputs.commits_since_last }}" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| # v3 Summary | ||
| echo "## v3-alpha Release" >> $GITHUB_STEP_SUMMARY | ||
| if [ "${{ needs.detect-v3-changes.outputs.has_changes }}" == "true" ]; then | ||
| if [ "${{ needs.release-v3.result }}" == "success" ]; then | ||
| echo "✅ **v3-alpha Release**: Created successfully" >> $GITHUB_STEP_SUMMARY | ||
| echo " - Version: ${{ needs.release-v3.outputs.version }}" >> $GITHUB_STEP_SUMMARY | ||
| echo " - Commits since last: ${{ needs.detect-v3-changes.outputs.commits_since_last }}" >> $GITHUB_STEP_SUMMARY | ||
| else | ||
| echo "❌ **v3-alpha Release**: Failed" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
| else | ||
| echo "⏭️ **v3-alpha Release**: Skipped (no changes)" >> $GITHUB_STEP_SUMMARY | ||
| echo " - Commits since last: ${{ needs.detect-v3-changes.outputs.commits_since_last }}" >> $GITHUB_STEP_SUMMARY | ||
| fi | ||
|
|
||
| echo "" >> $GITHUB_STEP_SUMMARY | ||
| echo "---" >> $GITHUB_STEP_SUMMARY | ||
| echo "🤖 **Automated Release System** | Generated with [Claude Code](https://claude.ai/code)" >> $GITHUB_STEP_SUMMARY No newline at end of file |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, to fix this class of issue, add an explicit permissions block either at the workflow root (to affect all jobs) or on the specific job that doesn’t need broad access. The block should grant the minimum required privileges for what that job actually does. When a job only writes to the step summary or uses generic shell commands without authenticated GitHub operations, it can safely run with permissions: {} (no API permissions granted to GITHUB_TOKEN).
For this workflow, the minimal, non-disruptive change is to add a job-level permissions block to the summary job (starting at line 327). The summary job only writes to $GITHUB_STEP_SUMMARY and reads needs.* and github.* context variables, which do not require any GitHub API scopes. Therefore we can set permissions: {} for this job, mirroring the existing check-permissions job. Concretely, in .github/workflows/automated-releases.yml, under summary: (line 327), insert a permissions: {} line (properly indented) between name: Release Summary and runs-on: ubuntu-latest. No imports or additional steps are required.
-
Copy modified line R328
| @@ -325,6 +325,7 @@ | ||
|
|
||
| summary: | ||
| name: Release Summary | ||
| permissions: {} | ||
| runs-on: ubuntu-latest | ||
| needs: [check-permissions, detect-v2-changes, detect-v3-changes, release-v2, release-v3] | ||
| if: always() && needs.check-permissions.outputs.authorized == 'true' |
| name: Cleanup build artifacts | ||
| if: always() | ||
| needs: [test_js, test_go, test_templates] | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: geekyeggo/delete-artifact@v5 | ||
| with: | ||
| name: | | ||
| runtime-build-artifacts | ||
| runtime-package | ||
| failOnError: false | ||
|
|
||
| test_templates: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the problem is fixed by explicitly specifying a permissions: block either at the workflow root (applies to all jobs without their own permissions) or per job, assigning only the minimal privileges needed. For CI workflows that primarily run tests and manage artifacts, typical minimal permissions are contents: read and actions: write (for artifact operations). If no job needs to write to repository contents, issues, or PRs, those should be left at default (implicit none) or explicitly set to read/none.
For this specific workflow, the simplest and least disruptive fix is to define a workflow‑level permissions: block directly under the name: (before on:), granting contents: read so jobs can check out code, and actions: write so the cleanup job (and any others) can manage artifacts via the GitHub Actions API. No job appears to require write access to repository contents, issues, or pull requests, so we do not grant any extra scopes. This preserves existing functionality (checkout, artifact deletion) while constraining the GITHUB_TOKEN. Concretely, you would edit .github/workflows/build-and-test-v3.yml to insert:
permissions:
contents: read
actions: writeafter the first line (name: Build + Test v3) and before the on: block. No additional imports or methods are required because this is purely a YAML configuration change.
-
Copy modified lines R3-R6
| @@ -1,5 +1,9 @@ | ||
| name: Build + Test v3 | ||
|
|
||
| permissions: | ||
| contents: read | ||
| actions: write | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened, ready_for_review] |
| runtime-package | ||
| failOnError: false | ||
|
|
||
| test_templates: | ||
| name: Test Templates | ||
| needs: [test_js, test_go] | ||
| runs-on: ${{ matrix.os }} | ||
| if: github.base_ref == 'v3-alpha' | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: [ubuntu-latest, windows-latest, macos-latest] | ||
| template: | ||
| - svelte | ||
| - svelte-ts | ||
| - vue | ||
| - vue-ts | ||
| - react | ||
| - react-ts |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the fix is to add a permissions: block that explicitly scopes the GITHUB_TOKEN to the minimal set of permissions required. This is best done at the workflow root so that it applies to all jobs, unless specific jobs need different permissions. For this workflow, none of the shown jobs push commits, create releases, or manage issues/PRs; they primarily check approval state, build, test, and manipulate artifacts. Those activities only require read access to repository contents and (if needed) the default token access to artifacts, which is governed by actions and contents permissions. A safe and minimal configuration is to set contents: read at the workflow root. If any job later needs stronger permissions, it can override at the job level.
The single best fix without changing functionality is therefore: add a root���level permissions: block after the name: (or after on: if you prefer) with contents: read. This keeps all current behavior while ensuring the GITHUB_TOKEN is not accidentally granted write access. Concretely, in .github/workflows/build-and-test-v3.yml, insert:
permissions:
contents: readaligned at the root indentation, just after line 2 (the blank line after the workflow name). No additional imports or methods are needed, as this is a pure YAML configuration change.
-
Copy modified lines R3-R5
| @@ -1,5 +1,8 @@ | ||
| name: Build + Test v3 | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| pull_request: | ||
| types: [opened, synchronize, reopened, ready_for_review] |
| name: Test Templates | ||
| needs: [test_js, test_go] | ||
| runs-on: ${{ matrix.os }} | ||
| if: github.base_ref == 'v3-alpha' | ||
| strategy: | ||
| fail-fast: false | ||
| matrix: | ||
| os: [ubuntu-latest, windows-latest, macos-latest] | ||
| template: | ||
| - svelte | ||
| - svelte-ts | ||
| - vue | ||
| - vue-ts | ||
| - react | ||
| - react-ts | ||
| - preact | ||
| - preact-ts | ||
| - lit | ||
| - lit-ts | ||
| - vanilla | ||
| - vanilla-ts | ||
| go-version: [1.24] | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@v4 | ||
|
|
||
| - name: Install linux dependencies | ||
| uses: awalsh128/cache-apt-pkgs-action@latest | ||
| if: matrix.os == 'ubuntu-latest' | ||
| with: | ||
| packages: libgtk-3-dev libwebkit2gtk-4.1-dev build-essential pkg-config | ||
| version: 1.0 | ||
|
|
||
| - name: Setup Go | ||
| uses: actions/setup-go@v5 | ||
| with: | ||
| go-version: ${{ matrix.go-version }} | ||
| cache: true | ||
| cache-dependency-path: "v3/go.sum" | ||
|
|
||
| - name: Install Task | ||
| uses: arduino/setup-task@v2 | ||
| with: | ||
| version: 3.x | ||
| repo-token: ${{ secrets.GITHUB_TOKEN }} | ||
|
|
||
| - name: Build Wails3 CLI | ||
| working-directory: v3 | ||
| run: | | ||
| task install | ||
| wails3 doctor | ||
|
|
||
| - name: Download runtime package | ||
| uses: actions/download-artifact@v4 | ||
| with: | ||
| name: runtime-package | ||
| path: wails-runtime-temp | ||
|
|
||
| - name: Generate template '${{ matrix.template }}' | ||
| shell: bash | ||
| run: | | ||
| # Get absolute path - use pwd -W on Windows for native paths, pwd elsewhere | ||
| if [[ "$RUNNER_OS" == "Windows" ]]; then | ||
| RUNTIME_TGZ="$(cd wails-runtime-temp && pwd -W)/$(ls wails-runtime-temp/*.tgz | xargs basename)" | ||
| else | ||
| RUNTIME_TGZ="$(cd wails-runtime-temp && pwd)/$(ls wails-runtime-temp/*.tgz | xargs basename)" | ||
| fi | ||
| mkdir -p ./test-${{ matrix.template }} | ||
| cd ./test-${{ matrix.template }} | ||
| wails3 init -n ${{ matrix.template }} -t ${{ matrix.template }} | ||
| cd ${{ matrix.template }}/frontend | ||
| # Replace @wailsio/runtime version with local tarball | ||
| npm pkg set dependencies.@wailsio/runtime="file://$RUNTIME_TGZ" | ||
| cd .. | ||
| wails3 build | ||
|
|
||
| build_results: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, this should be fixed by explicitly declaring a permissions block either at the workflow root (applies to all jobs) or per job, with the least privileges required. Since test_templates only needs to read the repository contents and artifacts and does not appear to need write access to anything, giving it contents: read is sufficient. To avoid affecting other jobs which are not shown and might legitimately need broader permissions, we will add a job-level permissions block for test_templates only.
Concretely, in .github/workflows/build-and-test-v3.yml, under the test_templates: job definition (around line 187), insert a permissions: section between needs: [test_js, test_go] and runs-on: ${{ matrix.os }}. The block will specify contents: read. No imports or additional definitions are needed, as this is purely YAML configuration for GitHub Actions.
-
Copy modified lines R189-R190
| @@ -186,6 +186,8 @@ | ||
| test_templates: | ||
| name: Test Templates | ||
| needs: [test_js, test_go] | ||
| permissions: | ||
| contents: read | ||
| runs-on: ${{ matrix.os }} | ||
| if: github.base_ref == 'v3-alpha' | ||
| strategy: |
| name: Detect committed changes | ||
| if: github.event_name != 'workflow_dispatch' | ||
| outputs: | ||
| changed: ${{ steps.package-json-changes.outputs.any_modified == 'true' || steps.source-changes.outputs.any_modified == 'true' }} | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| ref: ${{ github.sha }} | ||
| persist-credentials: 'true' | ||
|
|
||
| - name: Detect committed package.json changes | ||
| id: package-json-changes | ||
| uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1 | ||
| with: | ||
| files: | | ||
| v3/internal/runtime/desktop/@wailsio/runtime/package.json | ||
| v3/internal/runtime/desktop/@wailsio/runtime/package-lock.json | ||
|
|
||
| - name: Detect committed source changes | ||
| if: >- | ||
| steps.package-json-changes.outputs.any_modified != 'true' | ||
| id: source-changes | ||
| uses: step-security/changed-files@3dbe17c78367e7d60f00d78ae6781a35be47b4a1 # v45.0.1 | ||
| with: | ||
| files: | | ||
| v3/internal/runtime/Taskfile.yaml | ||
| v3/internal/runtime/desktop/@wailsio/compiled/main.js | ||
| v3/internal/runtime/desktop/@wailsio/runtime/tsconfig.json | ||
| v3/internal/runtime/desktop/@wailsio/runtime/src/** | ||
| v3/pkg/events/events.txt | ||
| v3/tasks/events/** | ||
|
|
||
| rebuild_and_publish: |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
To fix the problem, explicitly declare restricted permissions for the detect job so that the GITHUB_TOKEN cannot perform unnecessary write operations. The job only needs to read repository contents to check out code and inspect changed files, so contents: read is sufficient.
The best targeted fix, without changing existing functionality, is:
- Add a
permissions:section under thedetectjob, parallel toname,if,outputs, andruns-on. - Set
contents: readas a minimal scope, matching CodeQL’s suggested baseline.
Concretely, in .github/workflows/publish-npm.yml, between the outputs: block (line 14–15) and runs-on: ubuntu-latest (line 16), insert:
permissions:
contents: readNo additional imports or methods are needed because this is a workflow configuration change only.
-
Copy modified lines R16-R17
| @@ -13,6 +13,8 @@ | ||
| if: github.event_name != 'workflow_dispatch' | ||
| outputs: | ||
| changed: ${{ steps.package-json-changes.outputs.any_modified == 'true' || steps.source-changes.outputs.any_modified == 'true' }} | ||
| permissions: | ||
| contents: read | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout code |
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Test | ||
| run: echo "Hello World" No newline at end of file |
Check warning
Code scanning / CodeQL
Workflow does not contain permissions Medium test
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
To fix the problem, explicitly restrict the GITHUB_TOKEN permissions for this workflow or job. Since the job only prints a message and does not use the token at all, the safest and simplest approach is to disable the token entirely by setting permissions: { contents: none } or, more strictly, permissions: {} / permissions: none at the appropriate level, depending on desired clarity and compatibility.
The best way to fix this workflow without changing existing functionality is to add a permissions block at the workflow root (top level, alongside name and on). This will apply to all jobs in the workflow, including test. Because the job does not use GitHub APIs, we can safely set permissions: contents: read (a common minimal baseline) or fully disable access. To align with common recommendations while remaining conservative, we will set contents: read. Concretely, in .github/workflows/test-simple.yml, between the name: Test Simple and on: lines, insert:
permissions:
contents: readNo additional methods, imports, or definitions are required; only this YAML edit is needed.
-
Copy modified lines R3-R5
| @@ -1,5 +1,8 @@ | ||
| name: Test Simple | ||
|
|
||
| permissions: | ||
| contents: read | ||
|
|
||
| on: | ||
| workflow_dispatch: | ||
|
|
| url := r.URL.Path | ||
| path := dir + "/assets" + url | ||
|
|
||
| if _, err := os.Stat(path); err == nil { |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the fix is to ensure that any path derived from r.URL.Path is constrained to stay within the intended assets directory. That means: join the user path with the base directory via filepath.Join, normalize to an absolute path, and then verify that it still resides under the assets root before using it with os.Stat or http.ServeFile. If the check fails, we should not serve a file from disk and should instead fall back to the default asset handler.
Concretely, in v3/examples/screen/main.go inside the middleware, we should:
- Compute the base assets directory once:
assetsDir := filepath.Join(dir, "assets"). - Use
filepath.Join(assetsDir, url)to combine the base and the requested path rather than string concatenation. - Resolve the result to an absolute path:
absPath, err := filepath.Abs(path). - Resolve the base directory to an absolute path once as well and check that
absPathis within that directory, using a prefix check that accounts for path separators (e.g., by ensuringstrings.HasPrefix(absPath, assetsDirAbs+string(os.PathSeparator)) || absPath == assetsDirAbs). - Only if the normalization succeeds and the path is within the assets directory do we call
os.Statandhttp.ServeFile; otherwise, we should skip serving from disk and callnext.ServeHTTP.
To implement this, we need to (a) adjust the existing dir, url, and path assignments, (b) introduce assetsDir and its absolute form, and (c) import the strings package to perform the prefix check. No other behavior of the application needs to change: valid asset paths will still be served from disk during development, and invalid or traversal attempts will be passed through to the bundled asset handler (or result in a normal 404 from that handler).
-
Copy modified line R11 -
Copy modified lines R48-R55 -
Copy modified lines R57-R63 -
Copy modified lines R65-R72 -
Copy modified line R74
| @@ -8,6 +8,7 @@ | ||
| "os" | ||
| "path/filepath" | ||
| "runtime" | ||
| "strings" | ||
|
|
||
| "github.com/wailsapp/wails/v3/pkg/application" | ||
| ) | ||
| @@ -44,12 +45,33 @@ | ||
|
|
||
| _, filename, _, _ := runtime.Caller(0) | ||
| dir := filepath.Dir(filename) | ||
| assetsDir := filepath.Join(dir, "assets") | ||
| assetsDirAbs, err := filepath.Abs(assetsDir) | ||
| if err != nil { | ||
| // If we cannot determine the assets directory, fall back to default handler | ||
| next.ServeHTTP(w, r) | ||
| return | ||
| } | ||
|
|
||
| url := r.URL.Path | ||
| path := dir + "/assets" + url | ||
| path := filepath.Join(assetsDirAbs, url) | ||
| absPath, err := filepath.Abs(path) | ||
| if err != nil { | ||
| // On error resolving path, fall back to default handler | ||
| next.ServeHTTP(w, r) | ||
| return | ||
| } | ||
|
|
||
| if _, err := os.Stat(path); err == nil { | ||
| // Ensure the resolved path is within the assets directory | ||
| if !strings.HasPrefix(absPath, assetsDirAbs+string(os.PathSeparator)) && absPath != assetsDirAbs { | ||
| // Attempted access outside assets directory; fall back to default handler | ||
| next.ServeHTTP(w, r) | ||
| return | ||
| } | ||
|
|
||
| if _, err := os.Stat(absPath); err == nil { | ||
| // Serve file from disk to make testing easy | ||
| http.ServeFile(w, r, path) | ||
| http.ServeFile(w, r, absPath) | ||
| } else { | ||
| // Passthrough to the default asset handler if file not found on disk | ||
| next.ServeHTTP(w, r) |
|
|
||
| if _, err := os.Stat(path); err == nil { | ||
| // Serve file from disk to make testing easy | ||
| http.ServeFile(w, r, path) |
Check failure
Code scanning / CodeQL
Uncontrolled data used in path expression High
user-provided value
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 11 days ago
In general, the fix is to ensure that any path derived from user input is constrained to a safe directory. For this use-case, requests should only be able to access files inside the local assets directory. We should therefore (1) build paths using filepath.Join rather than raw string concatenation, (2) normalize the resulting path to an absolute path, and (3) verify that it still resides under the intended assets directory before using it with os.Stat or http.ServeFile. If the check fails, we should fall back to the existing bundled asset handler (next.ServeHTTP).
The best way to fix this without changing observable functionality is: compute an absolute, cleaned base path for assets once per request (assetsDir := filepath.Join(dir, "assets"), then assetsDirAbs := filepath.Clean(assetsDir)), then for each incoming URL path compute requestedPath := filepath.Join(assetsDirAbs, url) and requestedPathAbs := filepath.Clean(requestedPath). Reject or ignore the path if requestedPathAbs is not within assetsDirAbs (for example, using strings.HasPrefix on a path that is ensured to end with the separator), and in that case just call next.ServeHTTP(w, r). Only if the path is within the assets directory and exists on disk do we serve it directly. This will require importing strings and replacing the current dir + "/assets" + url logic in v3/examples/screen/main.go around lines 45–52.
Concretely:
- Add an import for
"strings"to the existing import list. - In the middleware, after obtaining
dir, computeassetsDir := filepath.Join(dir, "assets")andassetsDirAbs := filepath.Clean(assetsDir). - Replace
path := dir + "/assets" + urlwithrequestedPath := filepath.Join(assetsDirAbs, url)andrequestedPathAbs := filepath.Clean(requestedPath). - Before calling
os.Statorhttp.ServeFile, check thatrequestedPathAbsis underassetsDirAbsusing a prefix check that accounts for path separators; if the check fails, callnext.ServeHTTP(w, r)instead of serving from disk.
-
Copy modified line R11 -
Copy modified lines R48-R49 -
Copy modified lines R51-R64 -
Copy modified line R66
| @@ -8,6 +8,7 @@ | ||
| "os" | ||
| "path/filepath" | ||
| "runtime" | ||
| "strings" | ||
|
|
||
| "github.com/wailsapp/wails/v3/pkg/application" | ||
| ) | ||
| @@ -44,12 +45,25 @@ | ||
|
|
||
| _, filename, _, _ := runtime.Caller(0) | ||
| dir := filepath.Dir(filename) | ||
| url := r.URL.Path | ||
| path := dir + "/assets" + url | ||
| assetsDir := filepath.Clean(filepath.Join(dir, "assets")) | ||
| urlPath := r.URL.Path | ||
|
|
||
| if _, err := os.Stat(path); err == nil { | ||
| // Construct path under assets directory and ensure it does not escape | ||
| requestedPath := filepath.Clean(filepath.Join(assetsDir, urlPath)) | ||
| assetsDirWithSep := assetsDir | ||
| if !strings.HasSuffix(assetsDirWithSep, string(os.PathSeparator)) { | ||
| assetsDirWithSep += string(os.PathSeparator) | ||
| } | ||
|
|
||
| if !strings.HasPrefix(requestedPath, assetsDirWithSep) { | ||
| // If the requested path is outside the assets directory, fall back to bundled assets | ||
| next.ServeHTTP(w, r) | ||
| return | ||
| } | ||
|
|
||
| if _, err := os.Stat(requestedPath); err == nil { | ||
| // Serve file from disk to make testing easy | ||
| http.ServeFile(w, r, path) | ||
| http.ServeFile(w, r, requestedPath) | ||
| } else { | ||
| // Passthrough to the default asset handler if file not found on disk | ||
| next.ServeHTTP(w, r) |
| return | ||
| } | ||
|
|
||
| cmd := exec.Command(parts[0], parts[1:]...) |
Check failure
Code scanning / CodeQL
Command built from user-controlled sources Critical
user-provided value
|
Deploying wails with
|
| Latest commit: |
423377f
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://9c2866c0.wails.pages.dev |
| Branch Preview URL: | https://vk-2cfc-investigate-mous.wails.pages.dev |
| "node": "^10 || ^12 || >=14" | ||
| } | ||
| }, | ||
| "node_modules/rollup": { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
High severity vulnerability may affect your project—review required:
Line 569 lists a dependency (rollup) with a known High severity vulnerability.
ℹ️ Why this matters
Affected versions of rollup are vulnerable to Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting').
To resolve this comment:
Check if you use Rollup to bundle JavaScript with import.meta.url and the output format is set to cjs, umd, or iife formats, while allowing users to inject scriptless HTML elements with unsanitized name attributes.
- If you're affected, upgrade this dependency to at least version 3.29.5 at v3/examples/dev/frontend/package-lock.json.
- If you're not affected, comment
/fp we don't use this [condition]
💬 Ignore this finding
To ignore this, reply with:
/fp <comment>for false positive/ar <comment>for acceptable risk/other <comment>for all other reasons
You can view more details on this finding in the Semgrep AppSec Platform here.
|
Isn’t this behavior dependent on the WM/compositor? For example, on KWin (KDE), pointer enter/leave events are typically delivered, but focus-on-hover may be restricted, whereas compositors like Hyprland are more permissive. |




Summary
Implements mouse enter/leave events for windows on all three platforms (Windows, macOS, Linux), enabling tray popup windows to auto-focus when the mouse enters them.
WindowMouseEnterandWindowMouseLeavecommon eventsFocusOnMouseEnterwindow option for automatic focus on mouse hovermouse-hoverexample demonstrating the featurePlatform Implementation Details
WM_MOUSEMOVEwithTrackMouseEventAPI andWM_MOUSELEAVENSTrackingAreawithNSTrackingActiveAlwaysflag via aMouseTrackingViewoverlayenter-notify-eventandleave-notify-eventsignalsCloses #4887
Test plan
mouse-hoverexample on Windowsmouse-hoverexample on macOSmouse-hoverexample on LinuxFocusOnMouseEnteroption works correctly🤖 Generated with Claude Code