Rhodawk AI commited on
Commit Β·
4ba73c1
1
Parent(s): 58491d5
fix: BUG-009 git clone creds + BUG-010 pip fallback + BUG-011 per-repo venv
Browse files- app.py +15 -2
- language_runtime.py +16 -4
app.py
CHANGED
|
@@ -770,7 +770,16 @@ def enterprise_audit_loop(repo_override: str = None, branch: str = "main", speci
|
|
| 770 |
|
| 771 |
if not os.path.exists(REPO_DIR):
|
| 772 |
ui_log(f"Cloning {target_repo} β {REPO_DIR} ...")
|
| 773 |
-
Repo.clone_from
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 774 |
else:
|
| 775 |
ui_log(f"Repo dir exists β syncing {target_repo} to latest origin/main ...")
|
| 776 |
safe_git_pull()
|
|
@@ -1187,7 +1196,11 @@ def _research_clone(repo: str) -> str:
|
|
| 1187 |
repo_dir = f"/tmp/research_{repo.replace('/', '_')}"
|
| 1188 |
if not os.path.exists(repo_dir):
|
| 1189 |
ui_log(f"Cloning {repo} for static analysis...", "INFO")
|
| 1190 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1191 |
return repo_dir
|
| 1192 |
|
| 1193 |
|
|
|
|
| 770 |
|
| 771 |
if not os.path.exists(REPO_DIR):
|
| 772 |
ui_log(f"Cloning {target_repo} β {REPO_DIR} ...")
|
| 773 |
+
# FIX-009: Use run_subprocess_safe instead of Repo.clone_from so that
|
| 774 |
+
# GIT_CONFIG_GLOBAL (set by configure_git_credentials) is propagated to
|
| 775 |
+
# the git subprocess via os.environ.copy(). gitpython's Repo.clone_from
|
| 776 |
+
# spawns its own subprocess which inherits os.environ, but only when the
|
| 777 |
+
# env parameter is not overridden β using run_subprocess_safe is safer
|
| 778 |
+
# because it explicitly copies os.environ (including GIT_CONFIG_GLOBAL).
|
| 779 |
+
run_subprocess_safe(
|
| 780 |
+
["git", "clone", "-v", f"https://github.com/{target_repo}.git", REPO_DIR],
|
| 781 |
+
cwd="/tmp", raise_on_error=True,
|
| 782 |
+
)
|
| 783 |
else:
|
| 784 |
ui_log(f"Repo dir exists β syncing {target_repo} to latest origin/main ...")
|
| 785 |
safe_git_pull()
|
|
|
|
| 1196 |
repo_dir = f"/tmp/research_{repo.replace('/', '_')}"
|
| 1197 |
if not os.path.exists(repo_dir):
|
| 1198 |
ui_log(f"Cloning {repo} for static analysis...", "INFO")
|
| 1199 |
+
# FIX-009: Use run_subprocess_safe so GIT_CONFIG_GLOBAL credentials are inherited.
|
| 1200 |
+
run_subprocess_safe(
|
| 1201 |
+
["git", "clone", "-v", f"https://github.com/{repo}.git", repo_dir],
|
| 1202 |
+
cwd="/tmp", raise_on_error=True,
|
| 1203 |
+
)
|
| 1204 |
return repo_dir
|
| 1205 |
|
| 1206 |
|
language_runtime.py
CHANGED
|
@@ -247,7 +247,13 @@ class PythonRuntime(LanguageRuntime):
|
|
| 247 |
|
| 248 |
def setup_env(self, repo_dir: str, persistent_dir: str = "/data") -> EnvConfig:
|
| 249 |
import sys
|
| 250 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 251 |
|
| 252 |
# FIX: guarantee the parent directory exists before uv/venv tries to write into it.
|
| 253 |
# In HuggingFace Spaces /data is a mounted volume that may not be pre-created.
|
|
@@ -285,10 +291,14 @@ class PythonRuntime(LanguageRuntime):
|
|
| 285 |
raise_on_error=True,
|
| 286 |
)
|
| 287 |
|
| 288 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 289 |
|
| 290 |
def _install_deps(args: list[str]) -> bool:
|
| 291 |
-
"""Try uv pip install first; fall back to pip on failure."""
|
| 292 |
out, code = self._run(
|
| 293 |
["uv", "pip", "install", "--python", venv_dir, "--quiet"] + args,
|
| 294 |
cwd=repo_dir, timeout=600, extra_env=uv_env,
|
|
@@ -296,8 +306,10 @@ class PythonRuntime(LanguageRuntime):
|
|
| 296 |
if code != 0:
|
| 297 |
import warnings
|
| 298 |
warnings.warn(f"uv pip install failed (exit {code}) β falling back to pip. {out.strip()[:200]}")
|
|
|
|
|
|
|
| 299 |
_, pip_code = self._run(
|
| 300 |
-
[
|
| 301 |
cwd=repo_dir, timeout=600,
|
| 302 |
)
|
| 303 |
return pip_code == 0
|
|
|
|
| 247 |
|
| 248 |
def setup_env(self, repo_dir: str, persistent_dir: str = "/data") -> EnvConfig:
|
| 249 |
import sys
|
| 250 |
+
# FIX-011: Use a per-repo venv name derived from repo_dir so that switching
|
| 251 |
+
# between target repos never reuses a stale virtualenv with different deps.
|
| 252 |
+
# The old shared "target_venv" caused "[Errno 2] No such file or directory:
|
| 253 |
+
# '/data/target_venv/bin/pip'" when the venv belonged to a different repo.
|
| 254 |
+
import hashlib as _hashlib
|
| 255 |
+
_repo_hash = _hashlib.md5(repo_dir.encode()).hexdigest()[:8]
|
| 256 |
+
venv_dir = os.path.join(persistent_dir, f"target_venv_{_repo_hash}")
|
| 257 |
|
| 258 |
# FIX: guarantee the parent directory exists before uv/venv tries to write into it.
|
| 259 |
# In HuggingFace Spaces /data is a mounted volume that may not be pre-created.
|
|
|
|
| 291 |
raise_on_error=True,
|
| 292 |
)
|
| 293 |
|
| 294 |
+
# FIX-010: Resolve the venv's python interpreter to use as the pip fallback.
|
| 295 |
+
# Using `python -m pip` via the venv's python binary avoids the "No such file or
|
| 296 |
+
# directory: '/data/target_venv/bin/pip'" error seen when a fresh venv was created
|
| 297 |
+
# via `python -m venv` (which includes pip) but the bare pip script is absent.
|
| 298 |
+
venv_python = os.path.join(venv_dir, "bin", "python")
|
| 299 |
|
| 300 |
def _install_deps(args: list[str]) -> bool:
|
| 301 |
+
"""Try uv pip install first; fall back to the venv python -m pip on failure."""
|
| 302 |
out, code = self._run(
|
| 303 |
["uv", "pip", "install", "--python", venv_dir, "--quiet"] + args,
|
| 304 |
cwd=repo_dir, timeout=600, extra_env=uv_env,
|
|
|
|
| 306 |
if code != 0:
|
| 307 |
import warnings
|
| 308 |
warnings.warn(f"uv pip install failed (exit {code}) β falling back to pip. {out.strip()[:200]}")
|
| 309 |
+
# FIX-010: use venv_python -m pip instead of a bare pip_bin path β
|
| 310 |
+
# the `pip` script may be absent in freshly-created stdlib venvs.
|
| 311 |
_, pip_code = self._run(
|
| 312 |
+
[venv_python, "-m", "pip", "install", "--quiet"] + args,
|
| 313 |
cwd=repo_dir, timeout=600,
|
| 314 |
)
|
| 315 |
return pip_code == 0
|