fix(dashboard): guard git review credential diffs - #58036
Conversation
|
suggesting changes The new guard still lets the git review diff surfaces disclose credential contents when a protected file is renamed to a safe-looking destination. Security evidence: authenticated dashboard Git/review API calls can read working-tree and commit-context diffs from a user-selected repository; protected credential file contents must not be exposed through review diff surfaces even when Git reports a rename with a non-protected destination; current main discloses direct Signed: GPT-5.5-xhigh in Codex |
|
Priority corrected: P1 → P3 (triage calibration). Assessed against the repo The dashboard is loopback-by-default and its caller is the operator/agent already Keeping |
|
Updated the branch to handle rename/copy origins. The git review diff guard now keeps the UI/display path as the rename destination, but tracks all porcelain-v2 paths for safety decisions. Diff, file-diff, and commit-context now reject the safe-looking destination when it originated from a protected path. Validation: |
|
suggesting changes The rename-origin guard still only consults the working-tree status for the requested display path, so it covers an uncommitted rename row but misses the same credential path once the rename is committed on a branch and the worktree is clean. On a run-owned patch replay against current GitHub The submitted branch is stale relative to current GitHub Signed: GPT-5.5-xhigh in Codex |
teknium1
left a comment
There was a problem hiding this comment.
Thanks for extending the guard to uncommitted rename origins. The direct-path and dirty-worktree cases are covered, and the approach reuses the existing agent.file_safety.get_read_block_error() policy.
Problems
hermes_cli/web_git.py:358checks rename origins only through currentgit status. After committing.env → safe.txt, the worktree is clean, so the helper falls back tosafe.txt;review_diff(..., scope="branch")then runs the historical range diff. Current main executes that branch diff athermes_cli/web_git.py:311-313.- The added rename test performs
git mvbut does not commit it or exercisescope=branch, so it cannot catch that bypass.
Suggested changes
- For historical scopes, inspect rename/copy metadata from the exact diff range and reject when either source or destination is protected; keep working-tree status only for working-tree scopes.
- Add a committed, clean-worktree rename regression test for
/api/git/review/diff?scope=branch&file=safe.txt.
Automated hermes-sweeper review.
| def review_diff(cwd: str, file_path: str, scope: str, base_ref: str | None, staged: bool) -> str: | ||
| if not _is_dir(cwd): | ||
| return "" | ||
| if _entry_has_read_protected_path(cwd, _status_paths_for_display_path(cwd, file_path)): |
There was a problem hiding this comment.
This lookup only sees working-tree status. After .env is renamed to safe.txt and committed, status is clean and the helper falls back to safe.txt, so scope="branch" still emits the historical rename diff. Derive both rename endpoints from the requested diff range for historical scopes.
GottZ
left a comment
There was a problem hiding this comment.
This was generated by AI during triage.
Summary
Two PRs address the dashboard Git/review credential-path hardening gap through complementary surfaces: #58036 suppresses protected content from diff, status-count, and commit-context reads, while #58040 blocks protected-path staging, reverting, and committing. Both diffs cover direct paths and Git-detected rename origins but retain documented bypasses outside their current regression coverage.
Related pull requests
- #58036
related— (+145/-12) — keep open, changes requested: The diff applies the existing read-protection policy to untracked counts, review/file diffs, commit context, and porcelain-v2 rename origins, addressing direct-path and dirty-worktree disclosure. Consistent with the keep_open review on #58036, it does not inspect rename metadata from the historical branch diff range, so a committed.env→safe.txtrename with a clean worktree can still disclose the protected content. - #58040
related— (+167/-14) — keep open, changes requested: The diff rejects targeted protected-path mutations, replaces bulk stage/revert/auto-stage operations with filtered path lists, checks Git-reported rename origins, and maps denials to HTTP 403. Consistent with the keep_open review on #58040, a plain filesystem move appears as a protected tag-1 deletion plus an unrelated untracked safe-looking destination, allowing that destination to remain eligible for bulk stage, revert, or commit.
Suggested consolidation
Do not merge either PR yet: keep #58036 open until historical diff-range rename/copy origins are checked and covered by a committed clean-worktree branch-diff regression test, and keep #58040 open until deletion-plus-untracked filesystem moves fail closed across bulk stage, revert, and auto-stage commit with matching tests. The PRs are complementary rather than duplicates—#58036 covers read/disclosure paths and #58040 covers mutation paths—so neither should be closed in favor of the other.
Cross-PR triage: Reviewed 2 pull requests and 0 issues in this complex. Each diff was read against this issue; Assessment working set: 19 kB of PR diffs, 3 kB of issue/PR text, 12 kB of discussion (10 comments), 0 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.
Summary
The dashboard Git/review API could disclose credential files through git diff surfaces even though the dashboard file browser and file preview routes now block those same paths.
Affected routes include:
GET /api/git/review/diffGET /api/git/file-diffGET /api/git/review/commit-contextGET /api/git/status/GET /api/git/review/listline-count reads for untracked filesFor untracked files,
web_git.pysynthesizes an all-add diff using: