@westbayberry/dg 1.0.62 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,116 @@
1
+ """Dependency Guardian pip-install interceptor.
2
+
3
+ Loaded via dg_pip_hook.pth in user site-packages. Patches
4
+ pip._internal.commands.install.InstallCommand.run to route through
5
+ dg __wrap pip-hook before the real install runs.
6
+
7
+ DEFENSIVE CONTRACT (do not violate):
8
+ - Must never break Python startup. Any exception is swallowed; the
9
+ user's Python interpreter must always come up.
10
+ - Must patch only InstallCommand.run; nothing else in pip is touched.
11
+ - Must be re-entrant safe via DG_PIP_HOOK_ACTIVE env var.
12
+ - Must live ONLY in user-site (never system-site).
13
+ - Removed cleanly by `dg uninstall`.
14
+ - At .pth-load time pip is NOT yet on sys.path on some systems, so
15
+ we register a meta-path finder that patches when pip is first
16
+ imported (and also try an immediate patch as a fast path).
17
+ """
18
+
19
+
20
+ def _build_dg_wrapped_run(orig_run):
21
+ def dg_wrapped_run(self, options, args):
22
+ import os, sys, subprocess
23
+ try:
24
+ has_target = bool(args) or bool(getattr(options, "requirements", None))
25
+ if not has_target:
26
+ return orig_run(self, options, args)
27
+ except Exception:
28
+ return orig_run(self, options, args)
29
+
30
+ if os.environ.get("DG_PIP_HOOK_ACTIVE"):
31
+ return orig_run(self, options, args)
32
+
33
+ os.environ["DG_PIP_HOOK_ACTIVE"] = "1"
34
+ try:
35
+ cmd = ["dg", "__wrap", "pip-hook", "--"] + list(sys.argv[1:])
36
+ try:
37
+ proc = subprocess.run(cmd)
38
+ except FileNotFoundError:
39
+ return orig_run(self, options, args)
40
+ if proc.returncode != 0:
41
+ return proc.returncode
42
+ finally:
43
+ os.environ.pop("DG_PIP_HOOK_ACTIVE", None)
44
+
45
+ return orig_run(self, options, args)
46
+ return dg_wrapped_run
47
+
48
+
49
+ def _patch_install_command_module(mod):
50
+ try:
51
+ if not hasattr(mod, "InstallCommand"):
52
+ return
53
+ run = mod.InstallCommand.run
54
+ if getattr(run, "_dg_wrapped", False):
55
+ return
56
+ wrapped = _build_dg_wrapped_run(run)
57
+ wrapped._dg_wrapped = True
58
+ mod.InstallCommand.run = wrapped
59
+ except Exception:
60
+ pass
61
+
62
+
63
+ def _install_hook():
64
+ import sys
65
+ try:
66
+ if "pip._internal.commands.install" in sys.modules:
67
+ _patch_install_command_module(sys.modules["pip._internal.commands.install"])
68
+ return
69
+ except Exception:
70
+ pass
71
+
72
+ try:
73
+ from importlib.machinery import PathFinder
74
+ except Exception:
75
+ return
76
+
77
+ if getattr(PathFinder, "_dg_patched", False):
78
+ return
79
+
80
+ orig_find_spec = PathFinder.find_spec
81
+
82
+ def dg_find_spec(fullname, path=None, target=None):
83
+ try:
84
+ spec = orig_find_spec(fullname, path, target)
85
+ except Exception:
86
+ return None
87
+ if spec is None:
88
+ return spec
89
+ if fullname != "pip._internal.commands.install":
90
+ return spec
91
+ try:
92
+ loader = spec.loader
93
+ if loader is None:
94
+ return spec
95
+ orig_exec = loader.exec_module
96
+
97
+ def wrapped_exec(module):
98
+ orig_exec(module)
99
+ _patch_install_command_module(module)
100
+
101
+ loader.exec_module = wrapped_exec
102
+ except Exception:
103
+ pass
104
+ return spec
105
+
106
+ try:
107
+ PathFinder.find_spec = staticmethod(dg_find_spec)
108
+ PathFinder._dg_patched = True
109
+ except Exception:
110
+ pass
111
+
112
+
113
+ try:
114
+ _install_hook()
115
+ except Exception:
116
+ pass
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@westbayberry/dg",
3
- "version": "1.0.62",
3
+ "version": "1.1.0",
4
4
  "description": "Supply chain security scanner for npm and Python dependencies — 35 behavioral detectors catch zero-day attacks CVE databases miss. 99.66% catch rate on 155K packages.",
5
5
  "bin": {
6
6
  "dependency-guardian": "dist/index.mjs",
@@ -42,6 +42,7 @@
42
42
  "test": "vitest run",
43
43
  "pretest": "node build.mjs",
44
44
  "lint": "eslint src",
45
+ "postinstall": "node dist/postinstall.mjs || true",
45
46
  "prepublishOnly": "npm run lint && npm test && npm run build"
46
47
  },
47
48
  "engines": {