Case sync: refresh remote URL with current token before each push
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 1m28s

Cases failed to push silently after the Gitea token in Infisical was
rotated: the embedded credential in each case repo's origin URL was
the old token, the rotation never propagated, and capture_output=True
hid the auth failure as a logger.warning. Three cases (1033-25,
1130-25, 1194-25) accumulated unpushed commits over weeks before
this was noticed.

Fixes the root cause in two places: web/gitea_client.py for uploads
through the FastAPI endpoint, and mcp-server/services/git_sync.py
for case_update / document_upload through MCP tools (which previously
committed but never pushed at all).

The new commit_and_push helper:
- re-injects the current GITEA_ACCESS_TOKEN into the existing origin
  URL on every call, so pushes survive token rotation
- logs push failures at WARNING with the actual stderr (the previous
  code suppressed errors entirely)
- continues to push even when the commit was a no-op, in case earlier
  commits are still unpushed

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-28 17:14:57 +00:00
parent 6b5d6586dc
commit 5e4c03d0cd
5 changed files with 183 additions and 60 deletions

View File

@@ -34,7 +34,7 @@ from legal_mcp.tools import cases as cases_tools, search as search_tools, workfl
# Import integration clients (same directory)
_web_dir = Path(__file__).resolve().parent
sys.path.insert(0, str(_web_dir.parent))
from web.gitea_client import create_repo, setup_remote_and_push
from web.gitea_client import commit_and_push, create_repo, setup_remote_and_push
from web.paperclip_client import (
archive_project as pc_archive_project,
create_project as pc_create_project,
@@ -3005,26 +3005,11 @@ async def _process_tagged_document(task_id: str, dest: Path, case_number: str, c
_progress[task_id] = {"status": "processing", "filename": display_name, "step": "extracting"}
result = await processor.process_document(doc_id, case_id)
# Git commit + push (best-effort — don't fail upload on git errors)
try:
repo_dir = config.find_case_dir(case_number)
if repo_dir.exists():
env = {
"GIT_AUTHOR_NAME": "Ezer Mishpati", "GIT_AUTHOR_EMAIL": "legal@local",
"GIT_COMMITTER_NAME": "Ezer Mishpati", "GIT_COMMITTER_EMAIL": "legal@local",
"PATH": "/usr/bin:/bin",
}
doc_type_hebrew = DOC_TYPE_NAMES.get(doc_type, doc_type)
subprocess.run(["git", "add", "."], cwd=repo_dir, capture_output=True)
subprocess.run(
["git", "commit", "-m", f"הוספת {doc_type_hebrew}: {display_name}"],
cwd=repo_dir, capture_output=True, env=env,
)
# Try to push to Gitea (non-blocking)
subprocess.run(["git", "push"], cwd=repo_dir, capture_output=True, env={
**env,
"GIT_TERMINAL_PROMPT": "0",
})
commit_and_push(repo_dir, f"הוספת {doc_type_hebrew}: {display_name}")
except Exception:
logger.warning("Git commit/push failed for %s (non-critical)", display_name)
@@ -3360,20 +3345,13 @@ async def _process_case_document(task_id: str, source: Path, req: ClassifyReques
try:
repo_dir = config.find_case_dir(req.case_number)
if repo_dir.exists():
subprocess.run(["git", "add", "."], cwd=repo_dir, capture_output=True)
doc_type_hebrew = {
"appeal": "כתב ערר", "response": "תשובה", "decision": "החלטה",
"reference": "מסמך עזר", "exhibit": "נספח",
}.get(req.doc_type, req.doc_type)
subprocess.run(
["git", "commit", "-m", f"הוספת {doc_type_hebrew}: {title}"],
cwd=repo_dir, capture_output=True,
env={"GIT_AUTHOR_NAME": "Ezer Mishpati", "GIT_AUTHOR_EMAIL": "legal@local",
"GIT_COMMITTER_NAME": "Ezer Mishpati", "GIT_COMMITTER_EMAIL": "legal@local",
"PATH": "/usr/bin:/bin"},
)
commit_and_push(repo_dir, f"הוספת {doc_type_hebrew}: {title}")
except Exception:
logger.warning("Git commit failed for %s (non-critical)", req.filename)
logger.warning("Git commit/push failed for %s (non-critical)", req.filename)
# Remove from uploads
source.unlink(missing_ok=True)