Commit Graph

16 Commits

Author SHA1 Message Date
Teknium
e83816a4d1 review-fix(comments): restore lost #NNNN rationale comments across non-test source (mechanical sweep, condensed, code unchanged)
For each issue anchor present in BASE 63279301bc non-test .py and absent on HEAD, the BASE comment/docstring block was re-attached at the HEAD location of the code it explained (matched by the distinctive code line / enclosing def). Sentences already covered by an existing HEAD comment were deduped; the issue number always survives. Insert-only: no code lines changed.
2026-09-03 09:44:26 -07:00
Teknium
779c70dc54 refactor(hermes_cli/web_git): document _review_result fill-in 2026-09-03 00:01:25 -07:00
Teknium
28abcf64ee refactor(hermes_cli/web_git): _git_line/_gh_json/_has_staged/_own_pr helpers, split worktree_add existing-branch phase, iterator-based porcelain walk 2026-09-02 23:52:33 -07:00
Teknium
977092fb41 refactor(hermes_cli/web_git): _review_result/_BRANCH_SANITIZERS table, collapse ship-info and worktree-add branches 2026-09-02 21:38:02 -07:00
Teknium
a05191ac1c refactor(hermes_cli/web_git): fold _parse_worktrees into worktree_list, add _status_z/_origin_head/_ref_exists/_all_add_diff helpers, compact docs 2026-09-02 21:03:04 -07:00
Teknium
7c0d8f2c6f refactor(web): second-pass compaction of local_models/profiles/web_git (helpers, dict literals, docstrings) 2026-09-02 13:35:48 -07:00
Teknium
bdf1d8b0cf refactor(web): dedupe web_git subprocess/ref-list plumbing, drop dead _MAX_BUFFER 2026-09-02 13:35:24 -07:00
Teknium
f6234d00c5 fix(security): close GitSpawn RCE class — malicious repo .git/config no longer executes on context gathering (GHSA-7x36-8jrh-v4pw)
Hermes gathers workspace context by running git against the session
directory automatically — the coding-workspace snapshot, gateway
project-tree build, /diff, @diff|@staged context refs, goal-gate
fingerprint, and -w startup worktree add — before any prompt, tool call,
approval, or trust gate. Those probes ran the system git without
stripping the repository's own config, so a repo delivered as files with
its .git directory intact (a shared zip, sync folder, or USB stick;
git clone never transfers .git/config) could set an execution-sink git
setting and get arbitrary host code execution as the user with nothing
on screen.

- core.fsmonitor / core.hooksPath / pager / editor / credential helper:
  neutralized by routing every automatic probe through
  noninteractive_git_env(), which pins those keys to inert values via
  GIT_CONFIG_* and ignores global/system config. bounded_git_probe (the
  reported sink, coding_context._git + tui_gateway.git_probe) now defaults
  to that env; worktree-add, working_diff, web_git, context_references,
  goals, and subagent_worktree route through it too.
- Attribute-scoped [diff "x"] command=/textconv= drivers: the attacker
  names the driver in .gitattributes, so GIT_CONFIG_KEY overrides can't
  enumerate them. Added harden_git_argv(), which inserts
  --no-ext-diff --no-textconv on diff-rendering subcommands (diff/show/
  log/blame) only — status et al reject the flags. Both flags required
  (verified empirically; each alone leaves the other live).

Builds on the noninteractive_git_env config-scrubbing from the
gemini-cli #28792 port. Real-git E2E regression suite arms a malicious
repo and asserts every automatic path neutralizes fsmonitor, hooks,
external-diff, and textconv; a baseline test proves the repo is armed.
2026-09-02 10:33:43 -07:00
Teknium
f8f43c9523 fix(desktop): make git worktrees work end-to-end on a remote gateway backend
Cmd/Ctrl+Shift+B worktree flows on a remote gateway route through the
backend's /api/git mirror (hermes_cli/web_git.py), but that mirror had
drifted behind the Electron-local git ops the same UI drives locally, so
the flows broke exactly and only on remote connections:

- Convert-a-branch: the picker offers remote-tracking refs, and the
  Electron op turns "origin/feature" into a local tracking branch. The
  mirror ran `git worktree add <dir> origin/feature` verbatim, which
  either fails or detaches HEAD. It now resolves the ref's remote via
  git (never assuming "origin"), fetches best-effort, and creates the
  worktree with `--track -b <short-name>`.
- branch_list omitted remote-tracking refs entirely and never set the
  `isRemote` flag the renderer's HermesGitBranch contract requires —
  the convert picker on a remote gateway couldn't reach a teammate's
  branch and mislabeled every row's action.
- Branching off an `origin/…` base silently wired the new branch to the
  remote upstream; the mirror now passes `--no-track` like the Electron
  op does.

Renderer side, replace the silent degradation with a capability gate:
when a remote backend predates the /api/git worktree routes, worktree
creation failed with an opaque "Expected JSON … got HTML" toast. The
route-missing shapes now surface a clear "update the Hermes backend"
message (isGitEndpointMissingError, mirroring the sidebar batch-endpoint
detector); real git errors still pass through untouched.

Sibling audit (documented, no code change needed): repo status / review /
file-diff / git-root / default-cwd already route through desktopGit()'s
REST bridge or /api/fs on remote; repo scan is deliberately a no-op there.
Stale comments claiming "empty/false on a remote backend" in projects.ts
and coding-status.ts updated to describe the backend-routed reality.

Fixes #81724
2026-08-16 20:53:44 -07:00
Brooklyn Nicholson
21aaa8b4f8 feat(desktop): resolve a session's pull request
A session row can say whether its work is open, merged or closed, and link
to it. The join is the session's own repo + branch, asked of GitHub in one
batched GraphQL request per repo (branch aliases, not a `gh pr list` page
that a busy repo crowds ours out of), through the remote-aware git facade so
a desktop on a remote gateway asks the backend's `gh`.

Two ways a session's branch can't answer, both covered:

- It ran on trunk. Fork PRs share our branch namespace, so asking about
  `main` badges a stranger's PR onto it — trunk is never asked about, and
  cross-repository PRs are dropped server-side either way.
- It worked in a worktree, so the branch it recorded at start isn't where
  the PR came from. Creating a PR from the review pane binds the session to
  the branch it actually used, and for sessions that predate that, the PR is
  recovered from the transcript: `gh pr create` prints a bare PR url and
  nothing else, so a tool result whose whole output is one is a claim rather
  than a mention. Scanned read-only across profiles, once per session ever.
2026-08-09 06:21:04 -05:00
Teknium
58708c7066 fix(git): never block internal git calls on credential prompts
Port from openai/codex#34540 / #34612 ("detach non-interactive
subprocesses from stdin"): internal git invocations that run with nobody
attached — MCP catalog installs, plugin install/update, profile
distribution staging, worktree base fetches, and the desktop review
pane's git/gh backend — could hang on a credential prompt when a remote
is private, misconfigured, or requires auth. git prompts on the
inherited terminal (or via Git Credential Manager on Windows), so the
operation silently waits until its timeout, or forever at sites without
one (mcp_catalog clones have no timeout at all and inherit the parent
terminal).

- Add noninteractive_git_env() to hermes_cli/_subprocess_compat.py:
  GIT_TERMINAL_PROMPT=0 + GCM_INTERACTIVE=Never on a copy of the
  environment; GIT_ASKPASS/SSH_ASKPASS deliberately preserved so
  working non-interactive auth still succeeds.
- Wire it + stdin=DEVNULL into: mcp_catalog._do_git_install (clone/
  checkout), plugins_cmd (clone + pull), profile_distribution._git_clone,
  web_git._git/_gh (gh also gets GH_PROMPT_DISABLED=1), and cli.py's
  worktree base fetch helper.
- Tests: env contract, a real-git E2E against a local 401 Basic-auth
  HTTP server proving fail-fast ("terminal prompts disabled") instead
  of a hang, and per-call-site plumbing assertions. Sabotage-verified:
  removing the env from web_git._git fails the site test.
2026-07-28 17:34:21 -07:00
Stoltemberg
c89481db5e fix: add explicit UTF-8 encoding to all subprocess text=True calls (#53428)
On Windows with Chinese locale (GBK), subprocess.run(text=True) without
explicit encoding causes UnicodeDecodeError crashes. This fix adds
encoding='utf-8', errors='replace' to all subprocess.run() and
subprocess.Popen() calls that use text=True across 76 non-test Python files.

Fixes #53428 (master tracker for Windows GBK locale crash).

Note: credential_pool.py and electron changes excluded per reviewer request —
those will be submitted as separate focused PRs.
2026-07-24 11:45:57 -07:00
ethernet
f6d1fd511c feat(desktop): auto-fetch remote base branch before worktree add
When the base is an origin/… ref, fetch just that branch so the
local tracking ref is fresh before `git worktree add -b new origin/main`.
Fetch failures (offline / no remote) are silently ignored — git uses
whatever local ref exists, or raises a clear error if it's missing.
2026-07-13 14:53:34 -04:00
ethernet
6f7ee72be5 feat(desktop): base-branch picker for new worktree dialog
The sidebar "New worktree" button branched off whatever HEAD you were
on — now a filterable Popover+Command combobox lets you pick any local
or remote-tracking branch as the base, defaulting to origin/HEAD.

Backend listBaseBranches() queries refs/heads + refs/remotes via
for-each-ref, flags origin/HEAD (falling back to the local default for
no-remote repos). Mirrored on the Python REST API side
(base_branch_list + /api/git/base-branches route).
2026-07-13 14:53:34 -04:00
Brooklyn Nicholson
e4cf3a2e9d refactor(web_git): unify porcelain-v2 parsing into one walker
Collapse the two near-duplicate status parsers (_parse_status_v2 +
_iter_status_entries) into a single _walk_entries generator feeding the rail,
review list, and commit flow; share the staged predicate; hoist `import re`.
Behavior unchanged.
2026-06-28 14:29:59 -05:00
Brooklyn Nicholson
fc86e35764 feat(desktop): make the git cockpit work over a remote gateway
After the folder picker fix, an added remote folder was still half-usable:
the desktop's git GUI (coding-rail status, worktree lanes, review pane,
branch switch, file diff) all ran Electron-local git on the USER's machine,
so against a remote-gateway repo they silently degraded to empty.

Mirror the whole surface over the dashboard REST API so it acts on the
BACKEND repo where sessions actually run:

- hermes_cli/web_git.py: git/gh logic (status, worktrees, branches, review
  list/diff/stage/unstage/revert/commit/commit-context/push/ship-info/
  create-pr, file-diff, worktree add/remove, branch switch) shelling to the
  system git, mirroring the Electron ops' shapes.
- web_server.py: /api/git/* routes (same auth gate + _fs_path hardening as
  /api/fs, executor-offloaded, mutations -> 400).
- apps/desktop desktop-git.ts: remote-aware facade exposing the same shape as
  window.hermesDesktop.git; coding-status / review / projects / model /
  desktop-fs route through desktopGit() so local stays Electron, remote hits
  /api/git/*.

Tests: tests/hermes_cli/test_web_server_git.py (real repo: status counts,
review classification, diff incl. untracked all-add, stage+commit roundtrip,
worktree/branch lifecycle, commit-context, gh-absent ship-info, auth) and
desktop-git.test.ts (local vs remote routing, envelope unwrap, POST bodies).
2026-06-28 14:26:09 -05:00