veil-proxy 0.3.1__tar.gz → 0.3.2__tar.gz

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.
Files changed (51) hide show
  1. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/PKG-INFO +6 -4
  2. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/README.md +5 -3
  3. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/pyproject.toml +1 -1
  4. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/cli.py +2 -0
  5. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/mcpdb.py +1 -1
  6. veil_proxy-0.3.2/veil/netenv.py +62 -0
  7. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/proxy.py +2 -0
  8. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/reseed.py +2 -1
  9. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/sql.py +2 -1
  10. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/LICENSE +0 -0
  11. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/__init__.py +0 -0
  12. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/adopt.py +0 -0
  13. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/anthropic.py +0 -0
  14. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/cloud.py +0 -0
  15. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/crypto.py +0 -0
  16. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/data/README.md +0 -0
  17. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/data/pg_anonymizer_identifier.csv +0 -0
  18. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/data/words.txt.gz +0 -0
  19. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/decode.py +0 -0
  20. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/detect.py +0 -0
  21. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/display.py +0 -0
  22. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/engine.py +0 -0
  23. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/filesafe.py +0 -0
  24. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/guard.py +0 -0
  25. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/hookclient.py +0 -0
  26. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/hooks.py +0 -0
  27. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/keys.py +0 -0
  28. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/match.py +0 -0
  29. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/ner.py +0 -0
  30. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/openai.py +0 -0
  31. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/quasi.py +0 -0
  32. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/responses.py +0 -0
  33. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/rotate.py +0 -0
  34. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/secretref.py +0 -0
  35. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/shell.py +0 -0
  36. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/__init__.py +0 -0
  37. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/core.py +0 -0
  38. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/dynamo.py +0 -0
  39. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/elastic.py +0 -0
  40. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/files.py +0 -0
  41. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/git.py +0 -0
  42. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/kv.py +0 -0
  43. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/mongo.py +0 -0
  44. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/mssql.py +0 -0
  45. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/schema.py +0 -0
  46. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/sources/warehouse.py +0 -0
  47. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/state.py +0 -0
  48. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/stream.py +0 -0
  49. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/team.py +0 -0
  50. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/tokens.py +0 -0
  51. {veil_proxy-0.3.1 → veil_proxy-0.3.2}/veil/vault.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: veil-proxy
3
- Version: 0.3.1
3
+ Version: 0.3.2
4
4
  Summary: Privacy middleware for AI coding agents: the model sees consistent pseudonyms, your machine keeps the real values
5
5
  Keywords: privacy,pii,llm,proxy,pseudonymization,claude-code,coding-agent
6
6
  Requires-Python: >=3.11
@@ -47,10 +47,10 @@ Privacy middleware for AI coding agents. The model sees consistent pseudonyms
47
47
  and commands the agent runs locally get the real values back (shell- and SQL-safe).
48
48
 
49
49
  ```sh
50
- pip install "veil-proxy[postgres]" # extras: postgres, mysql, mongo, redis, bedrock, ner, mssql, all
50
+ pip install "veil-proxy[postgres]" # extras: postgres, mysql, mongo, redis, bedrock, ner, mssql, snowflake, all
51
51
  # (installs the `veil` and `veil-hook` commands; import name `veil`)
52
52
  veil init ~/code/myapp # seed from .env DB URLs, SQLite, fixtures; wire Claude Code
53
- veil service install # proxy as a LaunchAgent (macOS) / systemd user unit (Linux)
53
+ veil service install # proxy as a LaunchAgent (macOS) / systemd user unit (Linux) / Startup item (Windows)
54
54
  veil status ~/code/myapp
55
55
  ```
56
56
 
@@ -63,7 +63,7 @@ https://github.com/lemonadesaltbagel/veil):
63
63
  pattern matching (1,000 labelled records).
64
64
  - **21/21** one-command bypass transforms are contained. Restored values are escaped for every
65
65
  language layer they pass through (shell, heredocs, `python -c`, `node -e`, SQL, `bash -c`...):
66
- 35/35 injection tests, and 55,000 fuzzed nested commands executed with 0 code executions.
66
+ 35/35 injection tests, and 68,000 fuzzed nested commands executed with 0 code executions.
67
67
  - Prompt caching keeps working (74–89% cache hits); about 19 ms overhead per request at 40k seeded
68
68
  values, and 37 + 68 ms per 234 KB request at 1.2 million seeded values (1.1 GB).
69
69
 
@@ -71,6 +71,8 @@ One local proxy (default `127.0.0.1:8787`) serves every client, routed by path:
71
71
  Anthropic Messages (Claude Code, Agent SDK), Amazon Bedrock InvokeModel (binary eventstream),
72
72
  Google Vertex rawPredict, Microsoft Foundry (`/foundry`), Claude Platform on AWS (`/anthropic-aws`),
73
73
  OpenAI Chat Completions (Aider, Continue, OpenAI SDK) and OpenAI Responses (Codex CLI).
74
+ DeepSeek Harness uses the [dsh-veil](https://github.com/lemonadesaltbagel/dsh-veil) plugin. Other
75
+ agents' tools can get veil's restore rules with `veil proxy --tool-alias NAME=ROLE`.
74
76
 
75
77
  Seeds from Postgres, MySQL/MariaDB, SQLite, SQL Server (native sensitivity labels), MongoDB, Redis,
76
78
  Elasticsearch/OpenSearch and fixture files, plus personal fields declared in code (Prisma, Django,
@@ -5,10 +5,10 @@ Privacy middleware for AI coding agents. The model sees consistent pseudonyms
5
5
  and commands the agent runs locally get the real values back (shell- and SQL-safe).
6
6
 
7
7
  ```sh
8
- pip install "veil-proxy[postgres]" # extras: postgres, mysql, mongo, redis, bedrock, ner, mssql, all
8
+ pip install "veil-proxy[postgres]" # extras: postgres, mysql, mongo, redis, bedrock, ner, mssql, snowflake, all
9
9
  # (installs the `veil` and `veil-hook` commands; import name `veil`)
10
10
  veil init ~/code/myapp # seed from .env DB URLs, SQLite, fixtures; wire Claude Code
11
- veil service install # proxy as a LaunchAgent (macOS) / systemd user unit (Linux)
11
+ veil service install # proxy as a LaunchAgent (macOS) / systemd user unit (Linux) / Startup item (Windows)
12
12
  veil status ~/code/myapp
13
13
  ```
14
14
 
@@ -21,7 +21,7 @@ https://github.com/lemonadesaltbagel/veil):
21
21
  pattern matching (1,000 labelled records).
22
22
  - **21/21** one-command bypass transforms are contained. Restored values are escaped for every
23
23
  language layer they pass through (shell, heredocs, `python -c`, `node -e`, SQL, `bash -c`...):
24
- 35/35 injection tests, and 55,000 fuzzed nested commands executed with 0 code executions.
24
+ 35/35 injection tests, and 68,000 fuzzed nested commands executed with 0 code executions.
25
25
  - Prompt caching keeps working (74–89% cache hits); about 19 ms overhead per request at 40k seeded
26
26
  values, and 37 + 68 ms per 234 KB request at 1.2 million seeded values (1.1 GB).
27
27
 
@@ -29,6 +29,8 @@ One local proxy (default `127.0.0.1:8787`) serves every client, routed by path:
29
29
  Anthropic Messages (Claude Code, Agent SDK), Amazon Bedrock InvokeModel (binary eventstream),
30
30
  Google Vertex rawPredict, Microsoft Foundry (`/foundry`), Claude Platform on AWS (`/anthropic-aws`),
31
31
  OpenAI Chat Completions (Aider, Continue, OpenAI SDK) and OpenAI Responses (Codex CLI).
32
+ DeepSeek Harness uses the [dsh-veil](https://github.com/lemonadesaltbagel/dsh-veil) plugin. Other
33
+ agents' tools can get veil's restore rules with `veil proxy --tool-alias NAME=ROLE`.
32
34
 
33
35
  Seeds from Postgres, MySQL/MariaDB, SQLite, SQL Server (native sensitivity labels), MongoDB, Redis,
34
36
  Elasticsearch/OpenSearch and fixture files, plus personal fields declared in code (Prisma, Django,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "veil-proxy"
3
- version = "0.3.1"
3
+ version = "0.3.2"
4
4
  description = "Privacy middleware for AI coding agents: the model sees consistent pseudonyms, your machine keeps the real values"
5
5
  readme = "README.md"
6
6
  license = "Apache-2.0"
@@ -256,6 +256,8 @@ def _service(args) -> int:
256
256
 
257
257
  def main(argv: list[str] | None = None) -> int:
258
258
  argv = sys.argv[1:] if argv is None else argv
259
+ from .netenv import normalize_no_proxy
260
+ normalize_no_proxy() # before any httpx client: one unparseable NO_PROXY entry makes them all raise
259
261
  if argv[:1] == ["audit"]:
260
262
  try: # dev harness: only in a source checkout (prototype/veil_dev), never in the package
261
263
  import os
@@ -154,7 +154,7 @@ class SQLSource:
154
154
  self.conn = pymysql.connect(host=u.hostname or "127.0.0.1", port=u.port or 3306,
155
155
  user=unquote(u.username or "root"), password=unquote(u.password or ""),
156
156
  database=u.path.lstrip("/"), autocommit=True, charset="utf8mb4",
157
- connect_timeout=10)
157
+ connect_timeout=10, read_timeout=60, write_timeout=60)
158
158
  with self.conn.cursor() as c:
159
159
  c.execute("SET SESSION TRANSACTION READ ONLY")
160
160
  for limit in ("SET SESSION MAX_EXECUTION_TIME = 30000", # MySQL (ms)
@@ -0,0 +1,62 @@
1
+ """NO_PROXY entries that httpx can't parse.
2
+
3
+ httpx turns each NO_PROXY entry into a URL pattern when a client is created, and one entry it
4
+ can't parse makes every `httpx.Client()` raise, so veil would exit at startup. DeepSeek
5
+ Harness, for one, adds `[::1]` (an IPv6 address in brackets, which httpx doesn't recognise as an
6
+ address) for its child processes.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import ipaddress
12
+ import os
13
+ import re
14
+ import sys
15
+ from typing import MutableMapping
16
+
17
+ KEYS = ("NO_PROXY", "no_proxy")
18
+ _BRACKETED = re.compile(r"\[([0-9A-Fa-f:.%]+)\](?::\d+)?")
19
+
20
+
21
+ def _pattern(host: str) -> str:
22
+ """The URL pattern httpx builds for one NO_PROXY entry (httpx._utils.get_environment_proxies)."""
23
+ if "://" in host:
24
+ return host
25
+ for cls, fmt in ((ipaddress.IPv4Address, "all://{}"), (ipaddress.IPv6Address, "all://[{}]")):
26
+ try:
27
+ cls(host.split("/")[0])
28
+ return fmt.format(host)
29
+ except ValueError:
30
+ pass
31
+ return f"all://{host}" if host.lower() == "localhost" else f"all://*{host}"
32
+
33
+
34
+ def _parses(host: str) -> bool:
35
+ import httpx
36
+ try:
37
+ httpx.URL(_pattern(host))
38
+ return True
39
+ except Exception:
40
+ return False
41
+
42
+
43
+ def normalize_no_proxy(environ: MutableMapping[str, str] = os.environ, log=sys.stderr) -> None:
44
+ """Rewrite `[::1]` and `[::1]:port` to `::1`, and drop entries httpx would still reject."""
45
+ for key in KEYS:
46
+ value = environ.get(key)
47
+ if not value:
48
+ continue
49
+ kept, dropped = [], []
50
+ for host in (h.strip() for h in value.split(",")):
51
+ if not host:
52
+ continue
53
+ m = _BRACKETED.fullmatch(host)
54
+ host = m.group(1) if m else host
55
+ if host == "*" or _parses(host):
56
+ if host not in kept:
57
+ kept.append(host)
58
+ else:
59
+ dropped.append(host)
60
+ if dropped and log:
61
+ print(f"[veil] ignoring {key} entries that can't be parsed: {', '.join(dropped)}", file=log)
62
+ environ[key] = ",".join(kept)
@@ -414,6 +414,8 @@ def serve(veil: Veil, policy: Policy, port: int = 8787, upstream: str = "https:/
414
414
  capture: str | None = None, openai_upstream: str | None = None, bedrock_upstream: str | None = None,
415
415
  vertex_upstream: str | None = None, foundry_upstream: str | None = None,
416
416
  anthropic_aws_upstream: str | None = None):
417
+ from .netenv import normalize_no_proxy
418
+ normalize_no_proxy()
417
419
  client = httpx.Client(timeout=httpx.Timeout(600, connect=10))
418
420
  observer = capture_observer(capture) if capture else None
419
421
  server = LocalHTTPServer(("127.0.0.1", port), make_handler(veil, policy, upstream, client,
@@ -63,7 +63,8 @@ def fingerprint(source: str) -> str:
63
63
  if u.scheme in ("mysql", "mariadb"):
64
64
  import pymysql
65
65
  c = pymysql.connect(host=u.hostname or "127.0.0.1", port=u.port or 3306, user=unquote(u.username or "root"),
66
- password=unquote(u.password or ""), database=u.path.lstrip("/"), connect_timeout=5)
66
+ password=unquote(u.password or ""), database=u.path.lstrip("/"), connect_timeout=5,
67
+ read_timeout=5, write_timeout=5) # connect_timeout doesn't cover the handshake
67
68
  try:
68
69
  with c.cursor() as cur:
69
70
  try:
@@ -207,7 +207,8 @@ def seed_mysql(known: KnownValues, host: str, user: str, password: str, database
207
207
  import pymysql
208
208
 
209
209
  conn = pymysql.connect(host=host, port=port, user=user, password=password, database=database,
210
- cursorclass=pymysql.cursors.DictCursor, charset="utf8mb4", connect_timeout=10)
210
+ cursorclass=pymysql.cursors.DictCursor, charset="utf8mb4", connect_timeout=10,
211
+ read_timeout=300, write_timeout=300)
211
212
  with conn.cursor() as cur:
212
213
  cur.execute("SET SESSION TRANSACTION READ ONLY")
213
214
  cur.execute("""SELECT TABLE_NAME t, COLUMN_NAME c, DATA_TYPE d, COLUMN_KEY k, COLUMN_COMMENT m
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes