From f90be60e3140096ccf1c5b2b8d1c8c5f004239d9 Mon Sep 17 00:00:00 2001 From: Cyprian Kowalczyk Date: Thu, 9 Apr 2026 21:10:11 -0400 Subject: [PATCH] fix: use current branch upstream for update checks instead of default branch (#201) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: optional HTTPS/TLS support via cert and key env vars Add optional HTTPS support controlled by two env vars: HERMES_WEBUI_TLS_CERT=/path/to/cert.pem HERMES_WEBUI_TLS_KEY=/path/to/key.pem - Wraps server socket with ssl.SSLContext (min TLSv1.2) - Dynamic scheme detection for startup messages (http:// vs https://) - Graceful fallback to HTTP if cert loading fails — server never crashes due to bad TLS config, just prints a warning and continues - Auth cookie Secure flag already set when HTTPS is detected via getpeercert - 6 end-to-end tests: config flags, HTTPS handshake, HTTP still works, fallback on bad paths Addresses #191 (HTTPS support issue). * fix: use current branch upstream for update checks, not repo default branch The update checker in api/updates.py always compared HEAD against origin/master (or origin/main), which produced false 'N updates available' alerts when the user is on a feature branch and master has moved forward with unrelated commits. Now uses git rev-parse --abbrev-ref @{upstream} to get the current branch's tracking branch for both the behind-count check and the apply-update pull command. Falls back to the default branch if no upstream is set (brand-new local branch with no tracking config). Fixes #200. --- api/updates.py | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/api/updates.py b/api/updates.py index f59da6e..2bda66c 100644 --- a/api/updates.py +++ b/api/updates.py @@ -64,22 +64,32 @@ def _check_repo(path, name): if not fetch_ok: return {'name': name, 'behind': 0, 'error': 'fetch failed'} - branch = _detect_default_branch(path) + # Use the current branch's upstream tracking branch, not the repo default. + # This avoids false "N updates behind" alerts when the user is on a feature + # branch and master/main has moved forward with unrelated commits. + # If no upstream is set (brand-new local branch), fall back to the default branch. + upstream, ok = _run_git(['rev-parse', '--abbrev-ref', '@{upstream}'], path) + if ok and upstream: + # upstream is like "origin/feat/foo" — use it directly in rev-list + compare_ref = upstream + else: + branch = _detect_default_branch(path) + compare_ref = f'origin/{branch}' # Count commits behind - out, ok = _run_git(['rev-list', '--count', f'HEAD..origin/{branch}'], path) + out, ok = _run_git(['rev-list', '--count', f'HEAD..{compare_ref}'], path) behind = int(out) if ok and out.isdigit() else 0 # Get short SHAs for display current, _ = _run_git(['rev-parse', '--short', 'HEAD'], path) - latest, _ = _run_git(['rev-parse', '--short', f'origin/{branch}'], path) + latest, _ = _run_git(['rev-parse', '--short', compare_ref], path) return { 'name': name, 'behind': behind, 'current_sha': current, 'latest_sha': latest, - 'branch': branch, + 'branch': compare_ref, } @@ -129,7 +139,14 @@ def _apply_update_inner(target): if path is None or not (path / '.git').exists(): return {'ok': False, 'message': 'Not a git repository'} - branch = _detect_default_branch(path) + # Use the current branch's upstream for pull, matching the behaviour + # of _check_repo. Falls back to default branch if no upstream is set. + upstream, ok = _run_git(['rev-parse', '--abbrev-ref', '@{upstream}'], path) + if ok and upstream: + compare_ref = upstream + else: + branch = _detect_default_branch(path) + compare_ref = f'origin/{branch}' # Check for dirty working tree status_out, _ = _run_git(['status', '--porcelain'], path) @@ -141,7 +158,7 @@ def _apply_update_inner(target): stashed = True # Pull with ff-only (no merge commits) - pull_out, pull_ok = _run_git(['pull', '--ff-only', 'origin', branch], path, timeout=30) + pull_out, pull_ok = _run_git(['pull', '--ff-only', compare_ref], path, timeout=30) if not pull_ok: if stashed: _run_git(['stash', 'pop'], path)