Skip to content

fix: Agent installer - 36 cross-platform bug fixes (Windows/Mac/Linux)#7

Open
SatishwaranM wants to merge 3 commits into
giggsoinc:mainfrom
SatishwaranM:fix/agent-installer-cross-platform-bugs
Open

fix: Agent installer - 36 cross-platform bug fixes (Windows/Mac/Linux)#7
SatishwaranM wants to merge 3 commits into
giggsoinc:mainfrom
SatishwaranM:fix/agent-installer-cross-platform-bugs

Conversation

@SatishwaranM
Copy link
Copy Markdown

Summary

36 cross-platform bug fixes for the PatronAI agent installer (Windows/Mac/Linux).
4 critical, 10 high, 14 medium, 8 low severity bugs resolved.

Changes

Windows (setup_agent.ps1.template)

  • BOM-free UTF-8 writes for git hooks, config.json, authorized_domains
  • Hidden .git detection with -Force flag
  • XML-based Task Scheduler registration (indefinite repeat)
  • Microsoft Store python stub detection and skip
  • Scan Python written to file (avoids $HOME expansion in here-string)
  • -UseBasicParsing on all Invoke-WebRequest calls
  • -Otp parameter for non-interactive EXE installs
  • python -m pip install --user instead of bare pip
  • Authorized domains filename match (no .txt extension)
  • Immediate heartbeat + scan on install

Mac/Linux (setup_agent.sh.template)

  • Apple CLT stub detection (avoids modal dialog hang)
  • PEP 668 bcrypt install (--user + --break-system-packages fallback)
  • Quoted heredocs for config.json (prevents shell injection)
  • Reliable MAC detection via system tools (networksetup/ip link)
  • /Volumes coverage for repos on external drives (macOS)
  • StandardOutPath added to launchd plists
  • Silent OTP input (read -rsp)
  • Single python3 call in pre-commit hook (was 3x)
  • macOS 13+ Background Items hint
  • $BUNDLE passed via env var (prevents injection)

Server

  • UNINSTALLED event type handling in normalizer + pipeline
  • status.json updated to "uninstalled" when agent removed
  • UNINSTALLED badge in Deploy Agents table + Agent Fleet view

Delivery

  • Content-Disposition: attachment on S3 uploads (forces download)
  • Template placeholder leak fix ({{INLINE_SCAN_PYTHON}} in comment)

New Files

  • Standalone uninstall scripts (Windows + Mac/Linux) with server notification
  • patronai-agent-macos-guide.md (replaces vapourware HTML guide)
  • agent/uninstall/ folder with README

Testing

  • Live installation on Windows 11 (Intel i5-8365U, 16GB RAM)
  • 2-hour resource monitoring: 23/24 heartbeats, all HTTP 200, 6.4% CPU duty cycle
  • PowerShell template parse verification passes
  • Diagnose script runs clean

- Windows: BOM-free writes, hidden .git detection, XML task scheduling,
  MS Store python stub detection, scan.py file isolation, -UseBasicParsing,
  -Otp param for EXE, authorized_domains filename match
- Mac/Linux: Apple CLT stub detection, PEP 668 bcrypt, quoted heredocs,
  reliable MAC, /Volumes coverage, launchd stdout, OTP silent input
- Server: UNINSTALLED event handling, status.json update, dashboard badges
- Delivery: Content-Disposition download fix, template placeholder leak fix
- New: standalone uninstall scripts with server notification, macOS guide
@Arunkumar-Annamalai
Copy link
Copy Markdown

@SatishwaranM

Findings

[P0] Windows EXE install still cannot run non-interactively. The new $Otp parameter is declared after executable code, so PowerShell will not bind it as a script parameter, and the NSIS wrapper does not pass -Otp anyway. A silent EXE therefore reaches Read-Host with no usable console and hangs/fails. See ghost-ai-scanner/agent/install/setup_agent.ps1.template:10, :13, :72, and ghost-ai-scanner/scripts/build_agent_artifacts.py:115.

[P1] Windows scheduled tasks are registered with literal strings instead of variables. Register-ScheduledTask -Xml \$Xmlpasses the literal text$Xml, not the XML payload, and -Confirm:`$falsehas the same escaping issue. The catch only logs, so installs complete without recurring heartbeat/scan tasks. Seeghost-ai-scanner/agent/install/setup_agent.ps1.template:380and:381`.

[P1] Uninstall notifications do not update agent status. _update_agent_status() calls self._store._put(...), but the ingestor receives a BlobIndexStore, which exposes agent, findings, etc., not _put; the exception is swallowed, leaving status.json unchanged and the dashboard unable to show uninstalled. See ghost-ai-scanner/src/ingestor/pipeline.py:152 and ghost-ai-scanner/src/blob_index_store.py:29.

[P1] Runtime scripts ignore the Python interpreter validated during install. The installers carefully choose $PY / $PyExe, but the generated scan, heartbeat, and hook scripts hardcode python3 or python. On macOS launchd’s limited PATH or Windows machines where only py was valid, recurring scans/heartbeats fail after installation. See ghost-ai-scanner/agent/install/setup_agent.sh.template:37, :233, :245, and ghost-ai-scanner/agent/install/setup_agent.ps1.template:42, :240.

[P2] Unix pre-commit hooks break for normal company names with spaces. The hook emits COMPANY=<value> and runs it through eval; COMPANY=Acme Corp becomes an attempted Corp command and exits before uploading git-diff signals. See ghost-ai-scanner/agent/install/setup_agent.sh.template:142 and :147.

[P2] Uninstalled agents are counted as “Never checked”. _resolve_status() returns bucket "uninstalled", but the metrics code sends every non-online/non-offline bucket into pending_count, so once uninstall status works, fleet KPIs regress by inflating pending/never-checked. See ghost-ai-scanner/dashboard/ui/support_tab_fleet.py:91 and :96.

…ecycle

- Detect real Python 3 on Windows (skip MS Store stub) and persist path to python_path.txt so scheduled tasks use the same interpreter

- param([string]$Otp) moved before $ErrorActionPreference (PS parser req)

- Write-Utf8NoBom helper eliminates BOM from all file writes on Windows

- Backtick-escaped $false/$Xml/$_ removed from Register-PatronAITask

- eval in hook script hardened with shlex.quote() for shell-safe config reads

- OTP input silenced with read -rsp; PYCFG heredoc single-quoted to prevent shell expansion inside Python source

- BUNDLE_JSON env-var pattern prevents JSON injection in url-refresh path

- SilentInstall normal in NSIS so OTP prompt is visible; Read-Host pause added at end of setup_agent.ps1 for clean window close

- UNINSTALLED event lifecycle: normaliser, pipeline, fleet dashboard, agent_store.write_agent_status() -- pipeline no longer calls _store._put directly; public API boundary enforced

- json/datetime imports moved to module level in pipeline.py and agent.py

- /Volumes scanning on macOS; launchd StandardOutPath added; macOS 13+ background items notice surfaced to user

Reviewed with Raven (shadow mode) -- security, coupling, and style findings addressed before merge.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@SatishwaranM
Copy link
Copy Markdown
Author

@Arunkumar-Annamalai

fix: resolve 36 cross-platform agent installer bugs + UNINSTALLED lifecycle

  • Detect real Python 3 on Windows (skip MS Store stub) and persist path
    to python_path.txt so scheduled tasks use the same interpreter
  • param([string]$Otp) moved before $ErrorActionPreference (PS parser req)
  • Write-Utf8NoBom helper eliminates BOM from all file writes on Windows
  • Backtick-escaped $false/$Xml/$_ removed from Register-PatronAITask
  • eval in hook script hardened with shlex.quote() for shell-safe config reads
  • OTP input silenced with read -rsp; PYCFG heredoc single-quoted to prevent
    shell expansion inside Python source
  • BUNDLE_JSON env-var pattern prevents JSON injection in url-refresh path
  • SilentInstall normal in NSIS so OTP prompt is visible; Read-Host pause
    added at end of setup_agent.ps1 for clean window close
  • UNINSTALLED event lifecycle: normaliser, pipeline, fleet dashboard,
    agent_store.write_agent_status() — pipeline no longer calls _store._put
    directly; public API boundary enforced
  • json/datetime imports moved to module level in pipeline.py and agent.py
  • /Volumes scanning on macOS; launchd StandardOutPath added; macOS 13+
    background items notice surfaced to user

Reviewed with Raven (shadow mode) — security, coupling, and style findings
addressed before merge.

Co-Authored-By: Claude Sonnet 4.6 noreply@anthropic.com

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