diff --git a/validate/deps.sh b/validate/deps.sh index 43bde26..91bd8db 100755 --- a/validate/deps.sh +++ b/validate/deps.sh @@ -32,7 +32,14 @@ if [ -n "$has_python" ]; then if [ -n "$has_uvlock" ]; then printf " source: %s (uv project)\n" "$has_uvlock" pyproject_dir=$(dirname "$has_uvlock") - audit_cmd="uv run --directory $pyproject_dir pip-audit" + # Audit the lockfile directly: export uv.lock as a flat + # requirements list and feed it into pip-audit. Avoids + # `uv run pip-audit` (which audits pip-audit's own bundled venv, + # not the project's) AND avoids PIPAPI_PYTHON_LOCATION (which needs + # pip installed in the project venv — uv venvs don't ship pip). + # --disable-pip + --no-deps tells pip-audit not to invoke pip as + # an installer; the exported list is already resolved. + audit_cmd="( cd $pyproject_dir && uv export --no-hashes --format requirements-txt ) | pip-audit -r /dev/stdin --disable-pip --no-deps" elif [ -n "$has_reqtxt" ]; then printf " source: %s (requirements file)\n" "$has_reqtxt" audit_cmd="pip-audit -r $has_reqtxt" @@ -41,7 +48,10 @@ if [ -n "$has_python" ]; then audit_cmd="pip-audit" fi - if $audit_cmd 2>/dev/null; then + # Run via eval so audit_cmd can carry shell metacharacters (e.g. the + # pipeline used by the uv branch). The other branches' audit_cmd + # strings are simple commands that eval handles transparently. + if eval "$audit_cmd" 2>/dev/null; then printf "${GREEN}✓${NC} No known vulnerabilities in Python dependencies\n" else printf "${RED}✗${NC} Vulnerable Python dependencies found\n"