Kaynağa Gözat

security-guidance: probe for a non-PATH 3.10+ interpreter on HOOK_PY_INCOMPATIBLE (2.0.6 → 2.0.7) (#2854)

Instrument-first for the macOS Python-3.9 cohort.

v2.0.6 telemetry: ~13.6% of macOS sessions (~6,337 users) run on Apple's
Python 3.9 → HOOK_PY_INCOMPATIBLE → the agentic reviewer can't load (needs
3.10+ syntax). That's ~12x macOS's build-failure rate and the single
biggest macOS degradation. sg-python.sh only probes `python3.1x` on PATH,
so these users have nothing newer ON PATH — but they may still have a
3.10+ installed at a standard location that isn't on the hook's PATH
(Homebrew /opt/homebrew, python.org framework, etc.).

Before building an explicit-path interpreter search, size the RECOVERABLE
fraction: `_probe_alt_python()` checks Homebrew / python.org / distro
locations for a 3.10+ binary and emits the highest found as `sdk_alt_py`
(major*100+minor, or 0 = genuinely 3.9-only). Telemetry-only; probed ONLY
on the HOOK_PY_INCOMPATIBLE path, so healthy sessions never run it.

After a data cycle: non-zero sdk_alt_py = recoverable by an explicit-path
search in sg-python.sh; 0 = needs a user-side Python install (the one-time
notice is the only lever). That decides whether the search is worth building.

Verified locally on macOS Python 3.13:
  - py_compile clean; probe returns 314 on this Mac (homebrew 3.14 present).
  - 7 new tests (test_altpython_probe.py): highest-version selection,
    0-when-none (mocked os.access), framework/distro path parsing, only
    counts 3.10+, and emit gated on outcome==HOOK_PY_INCOMPATIBLE.
  - Full suite 575/575 + 2 skipped.

No behavior change — purely additive telemetry on the incompatible path.
Version 2.0.6 -> 2.0.7 per the per-PR-bump policy (#2114).

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mohamed Hegazy 1 ay önce
ebeveyn
işleme
222b19d2d1

+ 1 - 1
.claude-plugin/marketplace.json

@@ -3204,7 +3204,7 @@
     {
       "name": "security-guidance",
       "description": "Security review for Claude-generated code. Pattern-based warnings on edits, LLM-powered diff review on Stop, and an agentic commit reviewer that catches injection, XSS, SSRF, hardcoded secrets, and 25+ other vulnerability classes.",
-      "version": "2.0.6",
+      "version": "2.0.7",
       "author": {
         "name": "Anthropic",
         "email": "support@anthropic.com"

+ 1 - 1
plugins/security-guidance/.claude-plugin/plugin.json

@@ -1,6 +1,6 @@
 {
   "name": "security-guidance",
-  "version": "2.0.6",
+  "version": "2.0.7",
   "description": "Security review for Claude-generated code. Pattern-based warnings on edits, LLM-powered diff review on Stop, and an agentic commit reviewer that catches injection, XSS, SSRF, hardcoded secrets, and 25+ other vulnerability classes.",
   "author": {
     "name": "David Dworken",

+ 48 - 0
plugins/security-guidance/hooks/ensure_agent_sdk.py

@@ -318,6 +318,46 @@ def _probe_has_pip() -> bool:
         return False
 
 
+def _probe_alt_python() -> int:
+    """When the hook interpreter is <3.10 (HOOK_PY_INCOMPATIBLE), look for a
+    3.10+ interpreter at well-known install locations that aren't necessarily
+    on the hook's PATH — Homebrew (/opt/homebrew, /usr/local), python.org
+    framework builds, and the `py`/distro layouts. Returns the HIGHEST version
+    found encoded as major*100+minor (e.g. 312), or 0 if none.
+
+    Purpose (telemetry only, for now): size how many of the macOS Python-3.9
+    cohort actually HAVE a newer interpreter that sg-python.sh's PATH probe
+    missed — i.e. how many are RECOVERABLE by an explicit-path search vs.
+    genuinely 3.9-only. Emitted as sdk_alt_py. Existence-checks the versioned
+    binaries (cheap); a later explicit-path search would version-verify before
+    exec'ing. Probed only on the incompatible path, so healthy sessions never
+    pay for it."""
+    candidates = []
+    for minor in (14, 13, 12, 11, 10):
+        candidates += [
+            f"/opt/homebrew/bin/python3.{minor}",        # Apple-Silicon Homebrew
+            f"/usr/local/bin/python3.{minor}",           # Intel Homebrew / python.org shim
+            f"/Library/Frameworks/Python.framework/Versions/3.{minor}/bin/python3",  # python.org
+            f"/usr/bin/python3.{minor}",                 # distro-managed (Linux)
+        ]
+    best = 0
+    for path in candidates:
+        try:
+            if os.access(path, os.X_OK):
+                # path name encodes the minor; parse it back to a code
+                base = os.path.basename(path)
+                minor = None
+                if base.startswith("python3."):
+                    minor = int(base.split(".")[1])
+                elif "/Versions/3." in path:
+                    minor = int(path.split("/Versions/3.")[1].split("/")[0])
+                if minor is not None:
+                    best = max(best, 300 + minor)
+        except (OSError, ValueError, IndexError):
+            continue
+    return best
+
+
 def _pip_err_from_stderr(stderr_b):
     """Categorize a pip-install stderr into a known err_kind (the pip subset
     of SDK_BOOTSTRAP_ERR_CODES). Used by the --target fallback; mirrors the
@@ -788,6 +828,14 @@ if __name__ == "__main__":
         # per healthy session.
         if _encode_err_kind(err_kind) == 11:
             metrics["sdk_has_pip"] = _probe_has_pip()
+    # When the hook interpreter is <3.10 (HOOK_PY_INCOMPATIBLE), probe for a
+    # 3.10+ interpreter at known non-PATH locations. Non-zero sdk_alt_py =
+    # this user is RECOVERABLE by an explicit-path search in sg-python.sh; 0 =
+    # genuinely 3.9-only (needs a user install). Sizes the macOS Py-3.9 cohort
+    # (~13.6% of macOS sessions) before we build the search. Incompatible path
+    # only — healthy sessions never run it.
+    if outcome == HOOK_PY_INCOMPATIBLE:
+        metrics["sdk_alt_py"] = _probe_alt_python()
     # Interpreter version (major*100 + minor, e.g. 309 / 312), emitted on
     # every bootstrap. Disambiguates the macOS cohort (Apple 3.9 vs a 3.10+
     # with broken ensurepip) for both venv_ensurepip_fail AND