8000 feat: security remediation, Linux (Hyprland/GNOME/KDE) port, custom OpenAI-compatible provider, agent autonomy + workflow recipes by FeV-06 · Pull Request #8 · KingSahil/Blinky · GitHub
[go: up one dir, main page]

Skip to content

feat: security remediation, Linux (Hyprland/GNOME/KDE) port, custom OpenAI-compatible provider, agent autonomy + workflow recipes - #8

Merged
KingSahil merged 6 commits into
mainfrom
feat/security-remediation-linux-port
Aug 26, 2026
Merged

KingSahil merged 6 commits into
mainfrom
feat/security-remediation-linux-port

Conversation

@FeV-06
@FeV-06 FeV-06 commented Aug 24, 2026 •
Copy link
Copy Markdown
Collaborator

Summary

Six commits of hardening + the full Linux desktop-automation port, rebased on current main. Verified: 243 pytest passes (blocked only by 10 pre-existing env/network-dependent tests), cargo check clean, live-tested on Hyprland and live field-tested on GNOME.

Highlights

🔒 Security remediation (docs/SECURITY-REMEDIATION.md)

  • WebSocket (0.0.0.0:9001) now requires a token for non-loopback clients (BLINKY_REMOTE_TOKEN, auto-generated, constant-time compare); mobile sends auth: frame
  • Strict CSP in tauri.conf.json; send_keys metachar sanitization; ollama think:false + JSON fence tolerance; git hygiene (runtime artifacts untracked)

🐧 Linux port — Hyprland-first, DE-agnostic (docs/LINUX-PORT-ROADMAP.md, phases 1–8)

  • linux/python/backend/: ABC contract + HyprlandBackend, GnomeBackend, KdeBackend — auto-selected by DE; grim/portal/ScreenCast capture cascade, ydotool/wtype uinput input (with GNOME-compatible fallbacks), AT-SPI element trees, .desktop app registry
  • Old MCP layer deleted; compat shims keep callers untouched
  • Focus-model-aware prompting (focus-follows-mouse on Hyprland vs click-to-focus on GNOME/KDE)

🔌 Custom OpenAI-compatible provider

  • ai/custom_client.py: text + vision via any OpenAI-compatible endpoint (Zen, OpenRouter, vLLM, LM Studio), thinking-model support, balanced-object JSON extraction
  • Settings UI (URL / model / key) in both the command bar and app windows; Rust .env persistence

🤖 Agent autonomy + workflow memory

  • Cost-hierarchy prompting (open_app → list_windows → mouse → click_element → type → screenshot-last)
  • press_key alias map, cheap list_windows verification of launches, compound-instruction routing
  • Workflow recipes: sanitized goal-path saving with user confirmation, intent-aware matching, "inspiration" context injection

Verification

  • pytest: 243 passed / 10 pre-existing failures (env/network deps: searxng, spotify, omniparser)
  • cargo check clean
  • Live on Hyprland: capture, pixel-exact cursor, input, app launch, agent loop
  • Live on GNOME: AT-SPI window listing, ydotool input fallback, gnome-screenshot capture

Summary by CodeRabbit

  • New Features

    • Added support for configurable OpenAI-compatible providers, including custom URL, model, and API key settings.
    • Added workflow save prompts so completed workflows can be reviewed, saved, or discarded.
    • Expanded Linux desktop automation across GNOME, KDE, and Hyprland, including app launching, screenshots, clicking, scrolling, typing, and keyboard shortcuts.
    • Added optional authentication tokens for mobile-to-PC connections.
  • Bug Fixes

    • Improved app-launch detection, coordinate handling, screenshot fallbacks, OCR reliability, and wake-word initialization.
    • Added stricter WebSocket, CORS, credential, and content-security protections.

FeV-06 added 6 commits August 24, 2026 19:40
…er + agent autonomy + workflow recipes

SECURITY (docs/SECURITY-REMEDIATION.md):
- WS token auth on 0.0.0.0:9001 (loopback trusted, BLINKY_REMOTE_TOKEN for remote)
- Mobile sends auth token; strict CSP in tauri.conf; send_keys sanitized
- ollama think:false + JSON fence tolerance; git hygiene (artifacts untracked)

LINUX PORT (docs/LINUX-PORT-ROADMAP.md, phases 1-7):
- backend/ layer: abc contract + hyprland impl (capture, input, window, apps,
  vision, portal, system profile) — DE-agnostic core, Hyprland-first
- MCP layer removed; linux_mcp.py + wayland_vision.py are compat shims
- tesseract OEM1/PSM3 tuned; .desktop registry + gio launch for apps

CUSTOM PROVIDER (OpenAI-compatible, Zen/Go verified live):
- ai/custom_client.py: text + vision (base64 image_url), thinking-model
  support (thinking disabled), balanced-object JSON extraction
- Rust .env persistence + frontend UI (both windows) for URL/model/key

AGENT AUTONOMY:
- Cost-hierarchy prompt (open_app > list_windows > mouse > click > type > screenshot)
- Focus-follows-mouse knowledge injected via runtime system profile
- press_key alias map (enter->Return etc); open_app verified via list_windows
- Compound "open X and Y" routes to agent loop; locator no longer hijacks open
- click_element OCR name resolution (phrase merging, backend click)

WORKFLOW RECIPES:
- recipes.py: sanitized goal-path extraction, pending save + user confirmation
  (frontend chip), intent-aware matching, numbered inspiration context
- Tauri confirm_recipe_save command + blinky://recipe-prompt event
…-SPI)

GNOME/KDE implementation of the ComputerUseBackend contract — same ABC, auto-
detected by DE. Correct-by-construction against standard mechanisms (untestable
on Hyprland; verified by graceful degradation + full regression).

NEW:
- backend/atspi.py — AT-SPI a11y tree bridge: get_elements (UIElement boxes),
  get_active_window/list_windows (aggregate app bounds), is_available gate.
  Shared element/window source for GNOME + KDE; degrades to []/None when the
  registry is empty (Hyprland). Requires python-atspi pkg.
- backend/gnome.py — GnomeBackend: portal capture, AT-SPI windows/elements,
  shared ydotool/wtype input, Shell.Eval focus. Gates on GNOME DBus ping.
- backend/kde.py — KdeBackend: grim→portal capture, AT-SPI windows/elements,
  KWin Scripting.loadScript focus. Gates on KWin DBus ping.

CHANGED:
- backend/__init__.py — get_backend() auto-detects DE (hyprland/gnome/kde via
  system profile + env fallback); get_backend_name() exposes it.
- backend/input.py — the only compositor-dependent pieces (cursor pos, move_to)
  dispatch per availability: xdotool (X11/XWayland) > hyprctl > ydotool REL w/
  accel compensation. focus_window tries hyprctl → xdotool → portal activate.
- backend/portal.py — added activate_window() per-DE DBus focus path.
- linux_mcp_compat.get_app_state — pulls AT-SPI element tree when available.

Verified on Hyprland: auto-detect → HyprlandBackend; AT-SPI degrades cleanly
(0 elements, no crash); input dispatch compiled + move_to pixel-exact; python
235 passed / 10 pre-existing (no regressions); cargo check clean.
…ture

The log.txt failure ("open youtube in firefox" → 0 windows, no monitor
geometry, "Screenshot captured (no image available)") had two root causes,
both now fixed:

1. STALE HYPRLAND_INSTANCE_SIGNATURE after a session/gdm restart. The daemon
   inherited the pre-restart instance; every hyprctl call silently hit a dead
   socket → 0 windows, no monitor geometry → grim capture dead → the whole
   vision/autopilot loop went blind (LLM got "Screenshot captured (no image
   available)" and hallucinated an empty desktop).
   - backend/window.py: _current_instance_sig() scans $XDG_RUNTIME_DIR/hypr/
     and resolves the LIVE instance; _run_hyprctl tries the resolved sig and
     retries the newest instance on connection failure. Never trusts inherited
     env blindly.
   - backend/input.py: _cursor_pos / move_to route hyprctl through the same
     instance resolution so cursor control survives restarts too.

2. HARD-CODED grim everywhere (regression from the MCP-removal pass).
   capture_screenshot() + both screenshot_tool fallback paths called
   GrimFullscreenCaptureStrategy directly, which REQUIRES hyprctl monitor
   geometry — no portal / X11 ImageGrab fallback. Now all three use
   CaptureStrategyFactory.get_strategy() (grim → window-crop → portal →
   ImageGrab), so a stale socket or missing grim can't blind the loop.

3. wake_word.py: openwakeword 0.4 API drift — download_models() removed
   (now guarded) and Model(wakeword_models=...) → Model(wakeword_model_paths=)
   via signature introspection. Verified: "Model loaded successfully.
   Listening for wake word..." (CUDA provider warning is benign CPU fallback).

Verified: stale-env simulation now yields windows=2, monitors=1, capture with
real image + 126 OCR items (was 0/0/None); pytest 235 passed / 10 pre-existing
(no regressions).
…al, AT-SPI windows

log2.txt (real GNOME run) showed every shared tool dead-ending on GNOME:
- wtype: "Compositor does not support the virtual keyboard protocol" (wtype
  is wlroots-only; GNOME rejects it)
- grim: "No monitor geometry" (get_monitors() is hyprctl-bound)
- portal: "Screen capture permission denied" (non-interactive Screenshot is
  flat-out denied by xdg-desktop-portal-gnome)
- list_windows: 0 (hyprctl only)
Result: the LLM got "Screenshot captured (no image available)" + empty
desktop and hallucinated, burning all 10 iterations.

Fixes (backend, shared across Hyprland/GNOME/KDE):
- input.py: type_text now wtype-first, ydotool type fallback on any wtype
  failure (uinput, works on every compositor). key() likewise: wtype first,
  then a ydotool raw-keycode dance (QWERTY linear-scan map: enter=28, ctrl=29,
  l=38, etc.). move_to gains DE-aware ordering: hyprctl first ONLY on a live
  Hyprland instance, xdotool for non-Hyprland X11/XWayland, ydotool REL last
  (prevents xdotool moving the wrong pointer on Hyprland XWayland).
- window.py: _is_hyprland() now keys on a LIVE instance socket / XDG_CURRENT_
  DESKTOP advertisement, NOT binary presence (hyprctl exists even under GNOME).
  get_active_window/list_windows route to AT-SPI on non-Hyprland DEs.
- portal.py + capture.py: portal Screenshot now interactive=True so GNOME/KDE
  show the user-consent dialog (previously always denied).
- capture_screenshot + screenshot_tool fallbacks now use the compositor-aware
  CaptureStrategyFactory (grim → window-crop → portal → X11 grab), never
  hard-coded grim.
- tools.py: _detect_desktop_session derives from the OS session, not grim
  availability (grim absent no longer mislabels GNOME as 'x11').

Tests updated for the new factory/mock surfaces; 235 passed / 10 pre-existing
(no regressions). Hyprland live-verified pixel-exact move_to + capture intact.
Still needed per-DE (deferred, sudo): python-atspi (AT-SPI tree), xdotool
(absolute cursor under GNOME/KDE XWayland) — both degrade gracefully.
…pture

We're on a real GNOME session now (the actual Phase 8 test), which exposed:

1. _is_hyprland() wrongly returned True on GNOME: it keyed on a leftover
   HYPRLAND_INSTANCE_SIGNATURE socket dir still on disk from the old session.
   Signal of record is XDG_CURRENT_DESKTOP; socket files/binary presence are
   not signals. This alone sent list_windows to 0 everywhere on GNOME.

2. AT-SPI unusable in-process: Arch python-atspi ships cpython-314 bindings,
   but the Blinky venv is 3.12 — pyatspi import fails silently. Added a
   python3.14 helper subprocess (same pattern as the portal CLI helper) that
   queries desktop/windows/elements via AT-SPI and returns JSON. Tolerates
   pyatspi 2.58's snake_case get_extents(). Verified live: 2 windows
   (gnome-shell, FDM) + 14 elements on this GNOME session.
   python-atspi + python3.14 are now required (Arch system pkgs).

3. Capture dead on GNOME: grim is wlroots-only (never works on Mutter), and
   headless XDG portal Screenshot is auto-denied by xdg-desktop-portal-gnome
   (no visible parent window → no consent dialog → immediate Permit). Added
   DE-aware factory: skip grim on GNOME/KDE, add GnomeScreenshotCaptureStrategy
   (native consent flow) + _SpectacleCaptureStrategy (KDE). gnome-screenshot
   is the remaining install the user runs.

4. Portal now needs dbus-python + pygobject in the venv for the GLib mainloop
   (added; previously ImportError masqueraded as PermissionDenied).

Verified live on GNOME: is_hyprland=False, AT-SPI windows=2 + elements via
helper, input via ydotool fallback. pytest 235 passed / 10 pre-existing
(no regressions); cargo clean.
GNOME 50 gates org.gnome.Shell.Screenshot and auto-denies headless portal
Screenshot requests, so gnome-screenshot fell back to XWayland (black frames).
Adds screen_cast_capture(): full ScreenCast session handshake (CreateSession →
SelectSources → Start) → PipeWire node id → one gst-launch frame. Uses the
calling interpreter (dbus-python + PyGObject present in the venv), not
/usr/bin/python3. Still needs live GNOME consent; gates on DE in the capture
factory alongside GnomeScreenshotCaptureStrategy.
@coderabbitai
coderabbitai Bot commented Aug 24, 2026 •
Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: fa62be04-16c0-4f8c-b6b8-515ad936b41b

📥 Commits

Reviewing files that changed from the base of the PR and between a8d04cb and 63c4cd4.

⛔ Files ignored due to path filters (2)
  • common/mobile/package-lock.json is excluded by !**/package-lock.json
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (66)
  • .gitignore
  • common/frontend/src/App.tsx
  • common/frontend/src/CommandBar.tsx
  • common/frontend/src/lib/tauri.ts
  • common/frontend/src/styles.css
  • common/mobile/App.tsx
  • common/mobile/usePCWebSocket.ts
  • common/python/ai/client.py
  • common/python/ai/custom_client.py
  • common/python/ai/ollama_client.py
  • common/python/ai/prompt.py
  • common/python/app_context/hermes.md
  • common/python/capture/__init__.py
  • common/python/computer_use/linux_mcp.py
  • common/python/computer_use/loop.py
  • common/python/computer_use/recipes.py
  • common/python/computer_use/tools.py
  • common/python/main.py
  • common/python/ocr/__init__.py
  • common/python/prompts/agent.yaml
  • common/python/python/cache/ui_maps/app-exe-app-fec1ec45df.json
  • common/python/python/cache/ui_maps/app-vs-code-6a2c825f13.json
  • common/python/python/cache/ui_maps/app-vs-code-7de8cbb24f.json
  • common/python/python/cache/ui_maps/app-vs-code-e06d602005.json
  • common/python/python/cache/ui_maps/code-exe-vs-code-13a106af5e.json
  • common/python/python/cache/ui_maps/code-exe-vs-code-9011fe172f.json
  • common/python/tests/test_agent_loop_ocr.py
  • common/python/tests/test_browser_agent.py
  • common/python/tests/test_guidance_flow.py
  • common/python/tests/test_screenshot_tool.py
  • common/python/tests/test_virtual_mouse.py
  • common/python/tools/temp_candidate_e754f7bc-2960-4021-97f2-aeef1f69234b.py
  • common/python/utils/window.py
  • common/scratch/test_ws.py
  • common/src-tauri/src/lib.rs
  • common/src-tauri/src/mcp_bridge.rs
  • common/src-tauri/src/platform/mod.rs
  • common/src-tauri/src/websocket.rs
  • common/src-tauri/tauri.conf.json
  • common/test_sarvam_ws.py
  • common/whatsapp_backend/data/users/blinky-default-session/settings.json
  • common/whatsapp_backend/server.js
  • docs/LINUX-PORT-ROADMAP.md
  • docs/SECURITY-REMEDIATION.md
  • linux/python/backend/__init__.py
  • linux/python/backend/abc.py
  • linux/python/backend/apps.py
  • linux/python/backend/atspi.py
  • linux/python/backend/capture.py
  • linux/python/backend/gnome.py
  • linux/python/backend/hyprland.py
  • linux/python/backend/input.py
  • linux/python/backend/kde.py
  • linux/python/backend/linux_mcp_compat.py
  • linux/python/backend/portal.py
  • linux/python/backend/system.py
  • linux/python/backend/vision.py
  • linux/python/backend/window.py
  • linux/python/linux_capture.py
  • linux/python/wayland_vision.py
  • linux/python/window_linux.py
  • linux/requirements.txt
  • linux/src-tauri/src/platform/linux.rs
  • linux/src-tauri/src/platform/power.rs
  • python/wake_word.py
  • windows/python/tools_win.py

📝 Walkthrough

Walkthrough

This change adds custom OpenAI-compatible providers, authenticated mobile-to-desktop WebSockets, a Linux desktop automation backend, staged workflow saving, updated computer-use routing, and related security, compatibility, documentation, and validation updates.

Changes

Blinky platform updates

Layer / File(s) Summary
Custom provider configuration and requests
common/frontend/src/App.tsx, common/frontend/src/CommandBar.tsx, common/frontend/src/lib/tauri.ts, common/python/ai/*, common/src-tauri/src/lib.rs
Adds custom provider URL, model, and API-key settings. Adds OpenAI-compatible text and vision requests with structured-output fallback and JSON extraction.
Remote token authentication
common/mobile/*, common/src-tauri/src/websocket.rs, common/src-tauri/tauri.conf.json, common/whatsapp_backend/server.js
Persists and transmits mobile remote tokens. Authenticates WebSocket clients and restricts remote commands, CORS, notifications, and server binding.
Linux backend contract and services
linux/python/backend/*, docs/LINUX-PORT-ROADMAP.md
Adds normalized backend data types, desktop detection, application discovery, AT-SPI integration, capture strategies, portal capture, window inspection, input handling, vision helpers, and GNOME, KDE, and Hyprland backends.
Linux tool migration and compatibility wiring
common/python/computer_use/*, common/python/capture/__init__.py, common/python/utils/window.py, linux/src-tauri/src/platform/*
Routes Linux capture, window, input, application, shortcut, and vision operations through the new backend. Preserves legacy MCP-shaped helpers through a compatibility module.
Computer-use routing and workflow persistence
common/python/computer_use/loop.py, common/python/computer_use/recipes.py, common/src-tauri/src/lib.rs, common/src-tauri/src/websocket.rs, common/frontend/src/CommandBar.tsx, common/frontend/src/styles.css
Stages successful workflows as pending recipes, emits recipe prompts, and lets the frontend save or discard them. Recipe matching and context generation now use sanitized workflow data.
Prompt routing and validation
common/python/prompts/agent.yaml, common/python/ai/prompt.py, common/python/main.py, common/python/ocr/*, common/python/tests/*
Updates Linux runtime guidance, app-opening classification, native-pixel instructions, verification rules, OCR configuration, and affected tests.
Security, cleanup, and platform support
.gitignore, docs/SECURITY-REMEDIATION.md, linux/requirements.txt, python/wake_word.py, windows/python/tools_win.py, common/src-tauri/src/platform/mod.rs
Adds ignore and remediation documentation, updates Linux requirements, improves OpenWakeWord compatibility, sanitizes Windows Search input, and adjusts volume exports.

Estimated code review effort: 5 (Critical) | ~120 minutes

Suggested reviewers: kingsahil

Sequence Diagram(s)

sequenceDiagram
  participant MobileApp
  participant DesktopWebSocket
  participant ComputerUseLoop
  participant LinuxBackend
  participant RecipeRegistry
  participant Frontend
  MobileApp->>DesktopWebSocket: connect with remote token
  DesktopWebSocket-->>MobileApp: authenticated session
  ComputerUseLoop->>LinuxBackend: execute computer-use action
  LinuxBackend-->>ComputerUseLoop: action result
  ComputerUseLoop->>RecipeRegistry: stage successful workflow
  ComputerUseLoop->>DesktopWebSocket: emit recipe_prompt
  DesktopWebSocket->>Frontend: forward recipe prompt
  Frontend->>RecipeRegistry: confirm or discard recipe
Loading
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/security-remediation-linux-port

Warning

Some tools did not complete. Review the errors below.

🔧 Clippy (1.97.1)

Clippy execution timed out


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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@KingSahil
KingSahil merged commit 3d8fddb into main Aug 26, 2026
5 of 6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

0