Omahub
← All plugins
R

Window Ward

by r404r

Protect selected applications from accidental window closes.

Security review

Review recommended · 2 findings

Deterministic scan — not a security guarantee

Medium
Risk level
Medium
Analyzed commit
dcbc5f8
Scanned
1 week ago
  • medium package_manager …/workflows/ci.yml:10

    System package manager operation.

    apt-get install -y jq shellcheck nodejs
  • Command runs with sudo, elevating the process beyond the plugin environment.

    sudo apt-get install -y jq shellcheck nodejs

Automated analysis only — not a security guarantee.

AI advisory review

No obvious issues detected

Language-model assessment · ~deepseek/deepseek-v4-flash-latest — advisory only

Low
AI risk level
Low
Recommendation
install
Model
~deepseek/deepseek-v4-flash-latest
Analyzed commit
dcbc5f8
Reviewed
1 week ago

The deterministic scan's medium findings are from the GitHub Actions CI workflow (sudo apt-get install), which runs in CI and is not executed on the user's machine. In the sampled plugin code I found no malicious, hidden, or destructive behavior: the explicit setup script only manages the user's Hyprland bindings and creates a ~/.local/bin/window-ward symlink, with strong safeguards such as O_NOFOLLOW directory traversal, atomic writes, backups, and refusal to overwrite existing files. The only residual risk is the intended, documented rebinding of Super+W and Super+Q and the associated behavior change, which is reversible through the provided uninstall script.

  • The plugin intentionally intercepts Super+W and Super+Q during the manual setup step; users with existing personal bindings on either key must resolve conflicts first, and uninstall does not automatically restore old bindings from the backup file.
  • The automated 'medium' findings are CI-only package-manager operations in .github/workflows/ci.yml and do not represent a runtime or install-time risk to plugin users.
How this check works

This review combines the deterministic scan (the rule-based results above) with an independent look at the plugin's code by a language model. The model reads a trimmed sample of the repository's files, the manifest, and the README, then gives a plain-language risk level and a recommendation: install (no notable danger), review (look closer first), or avoid (clearly dangerous).

It runs on the same analyzed commit as the deterministic scan and is strictly advisory — it is not a security guarantee and never blocks a plugin by itself. A human moderator still reviews plugins before they are listed.

AI advisory only — automated analysis, not a security guarantee.

Install
$ omarchy plugin add https://github.com/r404r/omarchy-window-ward --enable
Desktop #Hyprland #bar #security

Window Ward

English | 简体中文 | 日本語

Window Ward protects selected applications from an accidental Super+W or Super+Q. The first protected close command warns; pressing either shortcut again on the same window within the configured interval closes it normally.

View Window Ward on the Omarchy Plugin Marketplace.

Window Ward panel showing per-application controls

Requirements

  • Compatibility target: Omarchy 4.0.4 / Hyprland 0.56.2; the 0.4.2 candidate still requires its own official-install/runtime acceptance before release.
  • Python 3.10 or newer and hyprctl

Install

omarchy plugin add https://github.com/r404r/omarchy-window-ward.git --enable
~/.config/omarchy/plugins/io.github.r404r.window-ward/scripts/setup
hyprctl reload
hyprctl configerrors

The second command is intentionally explicit: Omarchy plugins do not have install hooks. It adds a small marked block to the user-owned Hyprland bindings and backs the file up first. It refuses to replace an existing ~/.local/bin/window-ward file or a modified managed block. The managed block deliberately claims both Super+W and Super+Q. On an older Omarchy release where Super+Q was not yet a default close shortcut, setup therefore adds it as a protected close shortcut; resolve any existing personal Super+Q binding before running setup.

After updating from 0.4.0, run the setup command again and then hyprctl reload. Setup recognizes only the exact previous W-only block, backs it up, and atomically migrates it to protect both W and Q; an edited or unknown block is still rejected.

Before downgrading from 0.4.1 or later, run the current scripts/uninstall; the 0.4.0 uninstaller does not recognize the newer two-shortcut managed block. Reinstall the older version and rerun its setup afterward.

Configure

window-ward list
window-ward add-focused "My application"
window-ward set-app-enabled application-id false  # or: true
window-ward remove application-id
window-ward timeout 3000
window-ward enable   # or: disable
window-ward doctor

Configuration is stored at ~/.config/window-ward/config.json. Matching uses window class and initialClass; Window Ward never needs browser URLs, profiles, titles, passwords or tokens. Configuration input is capped at 48 KiB and the status JSON response at 64 KiB. The panel resolves each icon automatically from the application rule ID, then its exact class and initialClass values, using the active system icon theme; a generic application icon is the final fallback. Each list row can be paused independently or removed after a second confirmation click.

Adding an already-covered application preserves its existing rule and enabled state; it does not silently replace a grouped rule with a narrower match. Unknown/failed status is not an editable snapshot: refresh successfully before changing rules.

Confirmation time and notification dismissal

window-ward timeout 3000 sets confirmWindowMs to 3000 milliseconds: the interval in which a second protected close shortcut on the same window confirms closing it. No application is closed merely because that interval expires. The CLI also requests that duration for its notification, but the notification server controls the visible lifetime.

In the Omarchy notification implementation inspected on 2026-09-05, normal toasts last at least 8 seconds (at most 30 seconds), and hovering pauses their countdown. Thus a 3-second confirmation can have a longer-lived toast; its visibility does not mean the confirmation is still armed. This host policy is not configurable through Window Ward, and lowering timeout cannot override the host minimum.

Right-click the toast to dismiss it immediately. Left-click also dismisses after the host's default-action/focus handling; Window Ward provides no action to close the application. Dismissing the toast does not clear the independent confirmation token. Window Ward reuses the host notification card, not a custom popup with its own close button. These interaction details may change with Omarchy updates.

Remove

~/.config/omarchy/plugins/io.github.r404r.window-ward/scripts/uninstall
omarchy plugin remove io.github.r404r.window-ward
hyprctl reload

Always run uninstall before omarchy plugin remove; otherwise the global binding points to a removed plugin. If the repository was removed first, remove the marked WINDOW WARD block from ~/.config/hypr/bindings.lua, then run hyprctl reload. The uninstall script preserves application rules. Also remove a dangling installer link only after verifying that it is a symlink:

[[ -L ~/.local/bin/window-ward ]] && rm ~/.local/bin/window-ward

Development

tests/test-window-ward.sh
python3 -B tests/test_backend.py
tests/test-setup.sh
python3 -B tests/test_integration.py
node tests/test-ward-model.mjs
tests/test-panel-theme.sh
tests/test-controller-smoke.sh # requires Quickshell; isolated, headless fixtures
python -B bin/window-ward --help >/dev/null
cache_dir=$(mktemp -d); trap 'rm -rf "$cache_dir"' EXIT; PYTHONPYCACHEPREFIX="$cache_dir" python -m py_compile scripts/window_ward_integration.py scripts/setup scripts/uninstall
bash -n tests/*.sh
omarchy plugin validate "$PWD"
QMLLINT=${QMLLINT:-/usr/lib/qt6/bin/qmllint}
"$QMLLINT" -I "$OMARCHY_PATH/shell" BarWidget.qml Panel.qml WardController.qml

Omarchy's qs.* modules are resolved by Quickshell at runtime, so standalone qmllint may report unresolved-import warnings even with the correct import path. Treat those warnings as best-effort; release validation also requires loading the plugin on the verified Omarchy version and checking logs.

Node.js is a development-test dependency only. The model/static tests do not prove real panel lifecycle or notification behavior. The headless controller smoke is a required local pre-release check on a Quickshell-capable machine (Ubuntu CI does not provide Quickshell); retain its output with the candidate SHA and do not substitute Node/static tests for it. Retain official-install runtime acceptance for each final candidate. Keep generated caches outside the checkout.

See CONTRIBUTING.md. Licensed under MIT.