Local hardening merged - #2
Open
zumayaaustin-creator wants to merge 71 commits into
Open
Conversation
list_brain() tried to read_text() every entry in brain/, including the journal/ directory, raising IsADirectoryError.
…k-mxlkw8 Fix 500 error on dashboard load (/api/brain)
…d-with-windows-prerequisites docs: add Windows prerequisites to README
…figuration-in-server.py Configure CORS origins from dashboard settings
…atform-launcher-strategy Add cross-platform PowerShell launchers and unify Python launcher usage
read_text() defaults to the platform locale encoding (cp1252 on Windows), which fails on non-ASCII bytes in index.html. Specify utf-8 explicitly.
…up-5ubuao Fix UnicodeDecodeError serving dashboard on Windows
start.ps1/start.sh now fall back to the next free port instead of crashing when the configured port is already taken (e.g. by another local app), and auto-open the dashboard in the browser once it's up. install.ps1 also creates a desktop shortcut (Launch-Dashboard.bat) so the dashboard can be started without typing any commands.
- install.ps1: wrap desktop shortcut creation in try/catch so a COM failure doesn't abort the whole installer (ErrorActionPreference=Stop) - start.ps1: coerce dashboard.port to int on the Python side so a float value in settings.json doesn't crash the [int] cast - start.sh: fail loudly with a clear error if no free port is found in 20 attempts, instead of silently launching on an unverified port
Adds a real shell terminal to the dashboard sidebar: POST /api/terminal/run executes a command via subprocess in a server-tracked working directory (with cd support), and GET /api/terminal/session returns the current cwd. The frontend renders a scrollback panel with command history (up/down arrows) styled to match the existing chat UI. Local-only power feature: it executes arbitrary shell commands, same trust model as the existing agent CLIs the dashboard already shells out to.
Assigning a task to opencode, hermes, or gemini now actually runs it:
creating or PATCHing a task with one of those assignees moves it to
in_progress and hands the title+body to execute_agent() in a
background thread. On completion the agent's response is appended as
a task comment and the task is marked done (success) or blocked
(timeout/error), matching the existing block/complete state machine.
Adds POST /api/kanban/tasks/{id}/dispatch for manual dispatch/retry,
and makes the previously-stubbed POST /api/kanban/dispatch actually
scan todo/ready tasks with an agent assignee and dispatch each one.
Dashboard: the assignee field is now a select of the three agents,
the task detail modal shows an activity log of past agent runs and a
Dispatch button, and polls every 3s while a task is in_progress. Also
fixed a pre-existing bug where the detail modal read a nonexistent
kanbanData.tasks field (the board API only returns columns), so
clicking a card silently did nothing before this fix.
CodeQL flagged path-traversal risk (uncontrolled data used in path expression) across the kanban endpoints: task_id/parent_id/child_id path parameters were spliced directly into KANBAN_DIR paths with no validation. Task ids are always server-generated 8-char hex strings, so add kanban_task_path() which validates against that shape and raises 400 otherwise, and route every kanban file path through it.
The regex allow-list alone wasn't enough for CodeQL's path-injection sanitizer recognition. Resolve the candidate path and verify it's still a direct child of the resolved kanban directory before returning it, which is the pattern CodeQL's py/path-injection query recognizes as clearing taint.
…up-5ubuao Auto-detect free port and add one-click Windows launcher
subprocess.run(..., shell=True) uses cmd.exe on Windows by default, which doesn't understand PowerShell syntax like $env:VAR or $env:USERPROFILE - commands using it failed with 'cannot find the file specified' since cmd took it as a literal filename. Invoke powershell.exe explicitly on Windows instead; POSIX behavior is unchanged.
The previous Terminal ran one command at a time via subprocess.run and returned its output - it couldn't run interactive programs (colors, live input, TUIs like gemini's chat/auth flow), which is what a terminal actually needs to do. Backend: new /ws/terminal WebSocket endpoint spawns a real shell attached to a pseudo-terminal (stdlib pty on POSIX, pywinpty/ConPTY on Windows) and streams raw I/O bidirectionally, with resize support. Replaces the old POST /api/terminal/run and GET /api/terminal/session endpoints entirely. Frontend: terminal.js now loads xterm.js + the fit addon from CDN and renders a real terminal emulator wired to the WebSocket, instead of a scrollback div with a single input line. Verified on this Linux sandbox via raw WebSocket tests: shell spawns correctly, commands execute and echo real output, resize propagates to the PTY (confirmed via ), and closing the connection cleanly kills the shell process with no orphans (interactive bash ignores SIGTERM by default, so cleanup uses SIGKILL). Could not visually verify the xterm.js browser rendering in this sandbox since its egress policy blocks the CDN (cdn.jsdelivr.net) outright - same CDN this app already uses for chart.js, so expected to work on a normal machine; please confirm on Windows.
These were placeholder seed data shipped with the repo (a demo 'Fix login bug' task and a 'Test kanban task' with a canned 'Waiting for API review' block reason) - not real tasks. Clearing them so the board starts empty.
The Kanban detail modal's Delete button called api.deleteKanbanTask(), which didn't exist on the client, and there was no backend route for it either - clicking Delete just threw 'api.deleteKanbanTask is not a function'. Add both the client method and the backend endpoint.
The dashboard runs as a native Windows process, but Hermes' official installer is Bash-only and typically only gets set up inside WSL - a plain PATH lookup for 'hermes' on Windows will never find it there. Add hermes_cli_args(), which checks the native PATH first (so Mac/ Linux/WSL-native setups are unaffected) and falls back to routing through 'wsl -e bash -lc' (a login shell, so PATH additions like uv's ~/.local/bin are sourced) only when hermes isn't found natively but wsl.exe is available. Wire both the chat/dispatch invocation and the agent-health check through it, replacing the plain shutil.which check that always reported Hermes offline in this setup.
Two real gaps: the Skills Hub had no way to create a new skill (with
a SKILL.md) at all - the only 'Install' flow was the Plugin registry,
which just records a name in a JSON file, not an actual skill folder.
And the Context Files panel was read-only, just listing filenames
with no way to view, edit, add, or delete their contents.
Adds POST /api/skills (create, with SKILL.md content), PUT
/api/skills/{name} (edit SKILL.md), and GET/PUT/DELETE
/api/skills/{name}/context/{filename} for context files - all
validated through the same regex-allowlist + resolved-path
containment pattern already used for kanban tasks. Dashboard gets a
'+ New Skill' button, an editable SKILL.md view, and per-file
edit/delete plus 'Add File' in the Context Files panel.
hermes_cli_args() previously trusted any 'hermes' found on native PATH without checking what it actually was. Windows machines can have an unrelated tool also named 'hermes' (softwarepub/HERMES, an academic software-publication tool with harvest/process/curate/deposit subcommands - confirmed to be what was actually on this machine's PATH), which would silently get used instead of the real NousResearch agent installed in WSL, producing the misleading 'Hermes needs setup' message. Now check that a native 'hermes' actually exposes the agent's 'chat' subcommand before using it directly, falling back to the WSL bridge otherwise.
Validate the restore filename stays within backups/ and refuse tar members (and symlinks) that escape the extraction root (CVE-2007-4559 class), using tarfile's data filter. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…g failures Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…ndings Addresses findings from Devin and Codex reviews on the merged PR #10: - CRITICAL: /ws/terminal accepted connections from any origin - Starlette's CORSMiddleware does not protect WebSocket handshakes, so any webpage could open a socket to the dashboard's terminal and get an interactive shell on the user's machine. Now validates the Origin header against the same allowed-origins list used for CORS before accepting. - PtySession.close() sent SIGKILL to the shell's PID but never reaped it via os.waitpid(), leaking a zombie process per closed terminal session. - hermes_available() ran a real subprocess (possibly bridged through WSL) on every /api/status poll, which the dashboard hits every 15s. Added a 60s TTL cache. - create_skill() now also creates learnings.md and the context/ directory, matching the standard skill template (_template/) instead of only writing SKILL.md. - The '+ New Skill' button stayed visible in the Skills Hub detail view since only its sibling filter input was hidden; both now live under a shared #skillActions container that's hidden/shown together. Verified: malicious/missing-origin WebSocket connections are rejected at the handshake (HTTP 403) before any shell spawns; a valid dashboard origin still connects and works; closing a session leaves no zombie/orphaned process; the hermes availability cache avoids repeat subprocess spawns.
Resolve install.ps1 conflict by adopting main's complete installer (Resolve-Python, agent checks, desktop shortcut, browser auto-open) and folding in this branch's winget install hints and optional agent-CLI reminders. Clean up README duplicate Python/Node prerequisite rows and duplicate Windows Quick Start left over from the earlier merge. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…r_path Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…_dir_path Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…nt (CodeQL) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…up-shared-utils * Refactor duplicated patterns into shared utilities Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Harden user-controlled paths with containment check (CodeQL) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Limit shared JSON helpers to fixed-path callers to avoid path-injection alerts Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: zumayaaustin <zumayaaustin@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…-backup-restore-path-traversal * Fix path traversal in /api/backup/restore Validate the restore filename stays within backups/ and refuse tar members (and symlinks) that escape the extraction root (CVE-2007-4559 class), using tarfile's data filter. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Resolve backup filename from directory listing (satisfy CodeQL path-injection) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: zumayaaustin <zumayaaustin@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…r-handling improvements Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…uggestion Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…or-handling * Improve error handling: propagate corrupt-JSON errors, stop swallowing failures Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Validate skill name to prevent path traversal (CodeQL) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Tighten skill name allowlist to exclude '.' (path traversal) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Resolve skill name via directory match to break path-injection taint (CodeQL) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Make aggregate listings tolerate a corrupt file (best_effort), keep single GETs strict Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Move kanban_task_path inside try block in daemon thread * Resolve existing skills via iterdir match to break path-injection taint (CodeQL) Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Recompute path in kanban dispatch error handler to avoid unbound local Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Fix unbound variable in _run_kanban_agent error handler * Restore kanban dispatch success branch mangled by misapplied review suggestion Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: zumayaaustin <zumayaaustin@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…-unit-tests * Add unit test suite for server.py and scheduler.py Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> * Avoid URL substring pattern in CORS test to satisfy CodeQL Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: zumayaaustin <zumayaaustin@gmail.com> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…idance-and-cli-checks Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…tup-5ubuao Fix critical WebSocket origin bypass and other review findings
…and config updates
- Add devops audit report and learnings for CloudMart GCP infrastructure - Add new kanban cards (devops-audit P0 Doing, two additional cards) - Add new goals (entries 9, 10) to goals.json - Fix typo in active-projects.md and add active card link - Add start.bat launcher script
# Conflicts: # data/kanban/0f822987.json # data/kanban/8893ad14.json
…kup-and-restore-scripts Add native Windows backup and restore scripts
… modernization - server.py: dynamic agent execution engine (cli/http/mcp), live agent registry (/api/agents register/unregister), integrations API, agent stats & skill scoring, kanban task delete, plugin uninstall, agent-time tracking + /test page - dashboard: modernized agent-health, plugins marketplace, smart-router, styles; added agent-time monitor page + terminal page - scheduler.py rewrite; start.sh / start-agentic-os.sh improvements - skills: added firebase-*, notion-knowledge-capture, xcode-project-setup, audit/test plugins; updated learnings across skills - brain/ docs + data registry files (agent-registry, integrations, router-keywords) - .gitignore: exclude runtime artifacts (pid, graphify-out, logs) Verified live on :8081 - all new endpoints return 200 and register/unregister persists to data/agent-registry.json.
…launch guard - check_agent() custom check_type: replace subprocess shell=True with shlex.split + shell=False (prevents agent-registry config from injecting arbitrary shell). Verified malicious '; touch' no longer executes. - Add startup port guard in main: probe API port before uvicorn.run; exit 1 with clear message if already bound (stops the double-instance collision that caused phantom 'register does not persist' bugs). - start_terminal_server (8082): pre-bind probe + try/except so a taken port logs a warning instead of crashing the whole process.
…lone 8082 terminal - check_agent got mangled during conflict resolution (main's builtin logic stitched to branch's agent-referencing return -> NameError). Replaced with the correct dynamic, registry-based implementation (binary/oauth_file/http/ custom) including the shlex injection-safe custom check. - Removed the redundant standalone WebSocket terminal server on port 8082; the in-app /ws/terminal PtySession is canonical. - Verified live: status/agents/integrations/agent-time all 200; double-launch guard and shell-injection fix both hold.
Author
added 6 commits
July 25, 2026 14:34
New /api/agent-insights endpoint aggregates real data (chat-history, cost-history, agent-time, agent-registry, router-keywords) to show: - which agent you chat with most (user turns) - which agent spends the most time on tasks (derived agent-time) - which agent is best suited for what (registry desc + router keywords + roles) - which models you use most per agent (cost-history) Dashboard page (agent-insights.js) with stat cards, two Chart.js bar charts, suite cards, models-per-agent table, and full per-agent breakdown. Verified live in browser against real data.
…+ skills + chat)
- brain-core/brain_index.py: SQLite+FTS5 index over brain/** markdown,
skills/*/learnings.md, and data/chat-history.json. Idempotent upsert
keyed by (source, path, agent, #msg) so re-ingest never duplicates.
- brain-cli.py: ingest / stats / search CLI.
- server.py: /api/brain-index/{ingest,upsert,search,stats} so agents can
WRITE to the brain (upsert) and you/agents can QUERY it (search).
- .gitignore: exclude the regenerated *.db.
Verified live: ingest 66 docs (16 brain, 32 chat, 18 skill-learnings),
cross-source FTS search, and agent upsert is immediately searchable.
…un auto-upsert 1) Brain Search page (dashboard/pages/brain-search.js): mirrors Agent Insights; queries /api/brain-index/search with source filter + live index stats; nav entry + PAGE_TITLES added. 2) Scheduled auto-ingest: scheduler gains endpoint-style jobs (run_endpoint_via_api) so non-skill maintenance tasks can be cron'd; new job brain-index-ingest-job.json re-indexes every 30 min. 3) Agents auto-upsert learnings: run_skill wrap-up now calls record_brain_learning() so each skill run is immediately searchable in the unified index (best-effort, never breaks the run). Fixed a regression where AGENT_STATS_FILE def was dropped during the brain-learning helper insertion (would have broken all skill runs). Verified live: brain search returns ranked results; run_skill wrap-up upserts a searchable doc; scheduler imports + job validates.
- start.ps1 fallback 8080 -> 8081 (reads data/settings.json which is now 8081) - server.py argparse --port default 8080 -> 8081 (bare server.py lands on 8081) - (desktop Agentic OS.url already points at 127.0.0.1:8081; settings.json change kept local since it's git-ignored with api_keys) Single consistent port story across WSL start.sh, Windows start.ps1, bare server.py, and the desktop shortcut.
…nverge, log + index runs - skills/multi-angle-orchestration/SKILL.md: SOP for single-source fan-out (delegate_task leaf workers, NO external AIs) of >=5 angles + converge. - brain-core: ingest orchestration-runs/*.json as source 'orchestration' so past runs are searchable in Brain Search. - server.py: POST /api/orchestrate (optional headless fan-out of the 3 built-in agents) + GET /api/orchestrate/runs; persist runs to data/orchestration-runs/<id>.json and upsert to brain. - dashboard/pages/orchestration.js: launch runs + review past runs. - skills/multi-agent-run/SKILL.md + api helpers + nav entry.
Resolves the 404 on a direct hit to /dashboard/ (verified by reliability sweep: endpoint + dashboard verifiers). / and all assets already worked; this makes the bare directory path serve index.html too.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.