From 6b0c3fa7b5754ff6af8873d333bfec621fe64fd0 Mon Sep 17 00:00:00 2001 From: CyberMind-FR Date: Wed, 13 May 2026 07:43:18 +0200 Subject: [PATCH] fix(metablog-webhook): pass safe.directory to git on every call (ref #117) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Site dirs at /srv/metablogizer/sites/* are owned by root (from sub-B ingest), but the FastAPI service runs as secubox. Git 2.35+ refuses to operate with `fatal: detected dubious ownership in repository`, turning every webhook-triggered deploy into a 500. Pass `-c safe.directory=` per-invocation. Scoped to each git call — no global git config change. Existing git_pull test updated for the new arg layout ([git, -c, safe.directory=…, -C, , , ...]) and asserts the override is on every call. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../secubox-metablogizer/api/tests/test_webhook.py | 11 +++++++++-- packages/secubox-metablogizer/api/webhook.py | 7 ++++++- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/secubox-metablogizer/api/tests/test_webhook.py b/packages/secubox-metablogizer/api/tests/test_webhook.py index 83f0f4b7..06ef6c7c 100644 --- a/packages/secubox-metablogizer/api/tests/test_webhook.py +++ b/packages/secubox-metablogizer/api/tests/test_webhook.py @@ -127,9 +127,16 @@ def test_git_pull_returns_old_and_new_sha(tmp_path, monkeypatch): old, new = webhook.git_pull(site, "main") assert old == "aaa1111" assert new == "bbb2222" - # ensure the 4 expected git commands happened in order - op_names = [c[3] for c in calls] + # ensure the 4 expected git commands happened in order. The git arg + # layout is now [git, -c, safe.directory=..., -C, , , ...] + # so the op verb is at index 5. + op_names = [c[5] for c in calls] assert op_names == ["rev-parse", "fetch", "reset", "rev-parse"] + # every call must carry the safe.directory override (fixes dubious-ownership + # under the secubox service user on root-owned site dirs). + for c in calls: + assert c[1] == "-c" + assert c[2] == f"safe.directory={site}" def test_git_pull_timeout_propagates(tmp_path, monkeypatch): diff --git a/packages/secubox-metablogizer/api/webhook.py b/packages/secubox-metablogizer/api/webhook.py index 16c952bd..b003fe03 100644 --- a/packages/secubox-metablogizer/api/webhook.py +++ b/packages/secubox-metablogizer/api/webhook.py @@ -58,9 +58,14 @@ def git_pull(site_dir: Path, branch: str) -> tuple[str, str]: Raises subprocess.TimeoutExpired or CalledProcessError on git failure. """ + # Per-invocation safe.directory: site dirs are owned by root (from sub-B + # ingest) but the service runs as secubox; without this, git 2.35+ + # refuses with "fatal: detected dubious ownership". + safe_dir = f"safe.directory={site_dir}" + def _git(*args: str, timeout: int = GIT_OP_TIMEOUT) -> str: result = subprocess.run( - ["git", "-C", str(site_dir), *args], + ["git", "-c", safe_dir, "-C", str(site_dir), *args], capture_output=True, text=True, timeout=timeout, check=True, ) return result.stdout.strip()