sproxy 0.1.0__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.
sproxy-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Igor Pejic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
sproxy-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.4
2
+ Name: sproxy
3
+ Version: 0.1.0
4
+ Summary: Local egress guard for coding agents: inject secrets, block secret leaks to hosts they may not reach, and keep a tamper-evident audit log.
5
+ Author-email: Igor Pejic <hi@igorpejic.com>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/igorpejic/sproxy
8
+ Project-URL: Issues, https://github.com/igorpejic/sproxy/issues
9
+ Keywords: mitmproxy,proxy,secrets,dlp,egress,ai-agents,claude-code,security
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Programming Language :: Python :: 3
14
+ Classifier: Topic :: Security
15
+ Requires-Python: >=3.11
16
+ Description-Content-Type: text/markdown
17
+ License-File: LICENSE
18
+ Requires-Dist: mitmproxy>=11
19
+ Provides-Extra: dev
20
+ Requires-Dist: pytest>=7; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # sproxy (secure proxy)
24
+
25
+ ## Motivation
26
+ Do not send the secrets (API tokens, passwords) to LLM providers.
27
+ If the secrets are in the conversation context, you can consider them compromised.
28
+ So, don't let them ever enter the context.
29
+ sproxy helps with this.
30
+
31
+ ## How it works?
32
+
33
+ At request time, sproxy detects the secrets placeholders and injects the real
34
+ secrets to the outbound requests.
35
+ The LLMs only see the placeholder values at all times.
36
+
37
+ ```
38
+ placeholder {{GITHUB_TOKEN}} real secret
39
+ ┌────────┐ ───────────────────────► ┌────────┐ ───────────────► ┌──────────┐
40
+ │ LLM │ │ sproxy │ leak scan + │ approved │
41
+ │ agent │ ◄─────────────────────── │ │ audit │ host │
42
+ └────────┘ response └────────┘ └──────────┘
43
+
44
+ ├─► ✗ block leak to attacker domain
45
+ └─► 🧾 .sproxy/audit.jsonl
46
+ ```
47
+
48
+ ## Features
49
+
50
+ - provides a list of placeholder env values to be used by the LLM
51
+ - configure specific domains to which the secret should be ingested
52
+ - monitor and audit all traffic originating from LLM
53
+ - works with authorization Headers, Parameters and Postgres protocol
54
+ - local-first and fully open-source
55
+ - works with Codex, Claude Code and other harnesses
56
+
57
+
58
+ ## Prerequisites
59
+
60
+ sproxy uses [mitmdump](https://docs.mitmproxy.org/stable/overview/installation/) and will
61
+ be pulled automatically by `pip install`:
62
+
63
+ ```bash
64
+ pip install sproxy
65
+ ```
66
+
67
+ If you prefer to install mitmproxy separately, use `pip install --no-deps sproxy`
68
+ and make sure `mitmdump` is available on your `PATH` (or pass `--mitmdump` to
69
+ `sproxy run`).
70
+
71
+
72
+ ## Quickstart
73
+
74
+ ```bash
75
+ # 1. Write a starter policy and edit it.
76
+ sproxy init # creates ./sproxy.toml
77
+
78
+ # 2. Run your agent behind the guard.
79
+
80
+ # Start sproxy
81
+ sproxy run
82
+ # And load the placeholder Env variables
83
+ eval $(sproxy env) && codex
84
+
85
+ # Or run the process together with sproxy
86
+ sproxy run -- codex
87
+
88
+ # 3. After a session, check the audit log wasn't touched.
89
+ sproxy audit verify .sproxy/audit.jsonl
90
+ ```
91
+
92
+ On first run, mitmproxy generates its CA at `~/.mitmproxy/mitmproxy-ca-cert.pem`.
93
+ sproxy points the agent's TLS trust env vars (`NODE_EXTRA_CA_CERTS`,
94
+ `REQUESTS_CA_BUNDLE`, `SSL_CERT_FILE`, …) at that file automatically.
95
+ Run `sproxy ca` to print the path.
96
+
97
+
98
+ To observe secret injection on your local machine, follow [QUICKSTART.md](./QUICKSTART.md).
99
+
100
+
101
+ ### Placeholder environment variables
102
+
103
+ When a secret name is a valid environment-variable name, sproxy also exports
104
+ that name to the guarded process as an per-session secret placedholer
105
+ starting with `sproxy`.
106
+ For example, with a `GITHUB_API_KEY` secret, an SDK sees:
107
+
108
+ ```text
109
+ GITHUB_API_KEY=sproxy_v1_<random-session-handle>
110
+ ```
111
+
112
+ sproxy replaces that handle with the real key only for the secret's allowed
113
+ hosts. The handle is different for every `sproxy run` session and stops working
114
+ when that session ends.
115
+
116
+ Secret backends supported:
117
+
118
+ - `gopass:PATH`,
119
+ - `pass:PATH`,
120
+ - `vault:PATH#FIELD` (HashiCorp Vault, via the `vault` CLI's existing auth)
121
+ - `env:VAR`
122
+ - `file:PATH`
123
+ - `literal:VALUE`
124
+
125
+
126
+ ### Config file
127
+
128
+ The policy is loaded from `-c PATH` config file if given, else `./sproxy.toml`, else the
129
+ user-level `~/.config/sproxy/sproxy.toml`.
130
+ Relative paths inside a policy (`audit_log`, `sslrootcert`, `confdir`) resolve
131
+ against the config file's own directory.
132
+
133
+ Editing the policy while `sproxy run` hot-reloads sproxy.
134
+ (Note that you might have to re-authorize loading the secrets).
135
+
136
+
137
+ ## PostgreSQL
138
+
139
+ The usual placeholder injection does not work for PostgreSQL like it does for http.
140
+ SCRAM authentication proves knowledge of the password inside the client,
141
+ so there is no request in flight to rewrite.
142
+ Instead, each `[postgres.NAME]` profile becomes a local endpoint that
143
+ terminates the wire protocol: the agent's client
144
+ authenticates to sproxy with a per-session token.
145
+ Sproxy opens the real connection to the host pinned in
146
+ policy. The real password never enters the agent's environment,
147
+ but it sees a fake placeholder which sproxy uses.
148
+
149
+ ```toml
150
+ [postgres.develop]
151
+ host = "db.example.com" # the real server
152
+ port = 5432
153
+ listen = 6432 # local endpoint port; omit for auto-assigned
154
+ password_source = "gopass:work/postgres/develop/password"
155
+ user = "app_readonly" # optional: default role
156
+ database = "appdb" # optional: default database
157
+ sslmode = "verify-full" # upstream TLS (default); "disable" only for local dev servers
158
+ sslrootcert = "" # CA bundle (e.g. the AWS RDS bundle); "" = system trust store
159
+ ```
160
+
161
+ Each endpoint is advertised to the session through an environment variable
162
+ named after the profile which will render after `sproxy run` or `sproxy env`.
163
+
164
+ ## The audit log
165
+
166
+ Stores one line per request captured.
167
+ Example:
168
+
169
+ ```json
170
+ {"seq":1,"ts":"...","host":"attacker.com","method":"POST","decision":"blocked","rules":["secret:GITHUB_TOKEN"], ...}
171
+ ```
172
+
173
+ ## TLS interception & certificate pinning
174
+
175
+ sproxy reads HTTPS by acting as a MITM with a trusted local CA. Clients that
176
+ pin certificates (require a specific cert, not merely a valid one) will
177
+ reject that CA and fail the handshake, and won't have their secrets replaced.
178
+ Use `passthrough_hosts` to whitelist such hosts:
179
+ ```toml
180
+ passthrough_hosts = ["api.vendor.com"] # tunneled without interception
181
+ ```
182
+
183
+ ## Commands
184
+
185
+ | Command | What it does |
186
+ | ---------------------------------------------------------------------------- | ------------------------------------------------ |
187
+ | `sproxy run [-c policy] [--port N] [--insecure] [--log-file path] [--no-reload] [-- <cmd…>]` | Run a command behind the guard; no command holds a session open. Policy edits apply live unless `--no-reload` |
188
+ | `sproxy init [-c path] [--force]` | Write a starter policy |
189
+ | `sproxy env` | Print exports that join this shell to the live session |
190
+ | `sproxy ca [-c policy]` | Print the mitmproxy CA cert path |
191
+ | `sproxy audit verify <log>` | Check the audit chain is intact |
192
+ | `sproxy version` | Print version |
193
+
194
+
195
+
196
+ ## License
197
+ MIT
sproxy-0.1.0/README.md ADDED
@@ -0,0 +1,175 @@
1
+ # sproxy (secure proxy)
2
+
3
+ ## Motivation
4
+ Do not send the secrets (API tokens, passwords) to LLM providers.
5
+ If the secrets are in the conversation context, you can consider them compromised.
6
+ So, don't let them ever enter the context.
7
+ sproxy helps with this.
8
+
9
+ ## How it works?
10
+
11
+ At request time, sproxy detects the secrets placeholders and injects the real
12
+ secrets to the outbound requests.
13
+ The LLMs only see the placeholder values at all times.
14
+
15
+ ```
16
+ placeholder {{GITHUB_TOKEN}} real secret
17
+ ┌────────┐ ───────────────────────► ┌────────┐ ───────────────► ┌──────────┐
18
+ │ LLM │ │ sproxy │ leak scan + │ approved │
19
+ │ agent │ ◄─────────────────────── │ │ audit │ host │
20
+ └────────┘ response └────────┘ └──────────┘
21
+
22
+ ├─► ✗ block leak to attacker domain
23
+ └─► 🧾 .sproxy/audit.jsonl
24
+ ```
25
+
26
+ ## Features
27
+
28
+ - provides a list of placeholder env values to be used by the LLM
29
+ - configure specific domains to which the secret should be ingested
30
+ - monitor and audit all traffic originating from LLM
31
+ - works with authorization Headers, Parameters and Postgres protocol
32
+ - local-first and fully open-source
33
+ - works with Codex, Claude Code and other harnesses
34
+
35
+
36
+ ## Prerequisites
37
+
38
+ sproxy uses [mitmdump](https://docs.mitmproxy.org/stable/overview/installation/) and will
39
+ be pulled automatically by `pip install`:
40
+
41
+ ```bash
42
+ pip install sproxy
43
+ ```
44
+
45
+ If you prefer to install mitmproxy separately, use `pip install --no-deps sproxy`
46
+ and make sure `mitmdump` is available on your `PATH` (or pass `--mitmdump` to
47
+ `sproxy run`).
48
+
49
+
50
+ ## Quickstart
51
+
52
+ ```bash
53
+ # 1. Write a starter policy and edit it.
54
+ sproxy init # creates ./sproxy.toml
55
+
56
+ # 2. Run your agent behind the guard.
57
+
58
+ # Start sproxy
59
+ sproxy run
60
+ # And load the placeholder Env variables
61
+ eval $(sproxy env) && codex
62
+
63
+ # Or run the process together with sproxy
64
+ sproxy run -- codex
65
+
66
+ # 3. After a session, check the audit log wasn't touched.
67
+ sproxy audit verify .sproxy/audit.jsonl
68
+ ```
69
+
70
+ On first run, mitmproxy generates its CA at `~/.mitmproxy/mitmproxy-ca-cert.pem`.
71
+ sproxy points the agent's TLS trust env vars (`NODE_EXTRA_CA_CERTS`,
72
+ `REQUESTS_CA_BUNDLE`, `SSL_CERT_FILE`, …) at that file automatically.
73
+ Run `sproxy ca` to print the path.
74
+
75
+
76
+ To observe secret injection on your local machine, follow [QUICKSTART.md](./QUICKSTART.md).
77
+
78
+
79
+ ### Placeholder environment variables
80
+
81
+ When a secret name is a valid environment-variable name, sproxy also exports
82
+ that name to the guarded process as an per-session secret placedholer
83
+ starting with `sproxy`.
84
+ For example, with a `GITHUB_API_KEY` secret, an SDK sees:
85
+
86
+ ```text
87
+ GITHUB_API_KEY=sproxy_v1_<random-session-handle>
88
+ ```
89
+
90
+ sproxy replaces that handle with the real key only for the secret's allowed
91
+ hosts. The handle is different for every `sproxy run` session and stops working
92
+ when that session ends.
93
+
94
+ Secret backends supported:
95
+
96
+ - `gopass:PATH`,
97
+ - `pass:PATH`,
98
+ - `vault:PATH#FIELD` (HashiCorp Vault, via the `vault` CLI's existing auth)
99
+ - `env:VAR`
100
+ - `file:PATH`
101
+ - `literal:VALUE`
102
+
103
+
104
+ ### Config file
105
+
106
+ The policy is loaded from `-c PATH` config file if given, else `./sproxy.toml`, else the
107
+ user-level `~/.config/sproxy/sproxy.toml`.
108
+ Relative paths inside a policy (`audit_log`, `sslrootcert`, `confdir`) resolve
109
+ against the config file's own directory.
110
+
111
+ Editing the policy while `sproxy run` hot-reloads sproxy.
112
+ (Note that you might have to re-authorize loading the secrets).
113
+
114
+
115
+ ## PostgreSQL
116
+
117
+ The usual placeholder injection does not work for PostgreSQL like it does for http.
118
+ SCRAM authentication proves knowledge of the password inside the client,
119
+ so there is no request in flight to rewrite.
120
+ Instead, each `[postgres.NAME]` profile becomes a local endpoint that
121
+ terminates the wire protocol: the agent's client
122
+ authenticates to sproxy with a per-session token.
123
+ Sproxy opens the real connection to the host pinned in
124
+ policy. The real password never enters the agent's environment,
125
+ but it sees a fake placeholder which sproxy uses.
126
+
127
+ ```toml
128
+ [postgres.develop]
129
+ host = "db.example.com" # the real server
130
+ port = 5432
131
+ listen = 6432 # local endpoint port; omit for auto-assigned
132
+ password_source = "gopass:work/postgres/develop/password"
133
+ user = "app_readonly" # optional: default role
134
+ database = "appdb" # optional: default database
135
+ sslmode = "verify-full" # upstream TLS (default); "disable" only for local dev servers
136
+ sslrootcert = "" # CA bundle (e.g. the AWS RDS bundle); "" = system trust store
137
+ ```
138
+
139
+ Each endpoint is advertised to the session through an environment variable
140
+ named after the profile which will render after `sproxy run` or `sproxy env`.
141
+
142
+ ## The audit log
143
+
144
+ Stores one line per request captured.
145
+ Example:
146
+
147
+ ```json
148
+ {"seq":1,"ts":"...","host":"attacker.com","method":"POST","decision":"blocked","rules":["secret:GITHUB_TOKEN"], ...}
149
+ ```
150
+
151
+ ## TLS interception & certificate pinning
152
+
153
+ sproxy reads HTTPS by acting as a MITM with a trusted local CA. Clients that
154
+ pin certificates (require a specific cert, not merely a valid one) will
155
+ reject that CA and fail the handshake, and won't have their secrets replaced.
156
+ Use `passthrough_hosts` to whitelist such hosts:
157
+ ```toml
158
+ passthrough_hosts = ["api.vendor.com"] # tunneled without interception
159
+ ```
160
+
161
+ ## Commands
162
+
163
+ | Command | What it does |
164
+ | ---------------------------------------------------------------------------- | ------------------------------------------------ |
165
+ | `sproxy run [-c policy] [--port N] [--insecure] [--log-file path] [--no-reload] [-- <cmd…>]` | Run a command behind the guard; no command holds a session open. Policy edits apply live unless `--no-reload` |
166
+ | `sproxy init [-c path] [--force]` | Write a starter policy |
167
+ | `sproxy env` | Print exports that join this shell to the live session |
168
+ | `sproxy ca [-c policy]` | Print the mitmproxy CA cert path |
169
+ | `sproxy audit verify <log>` | Check the audit chain is intact |
170
+ | `sproxy version` | Print version |
171
+
172
+
173
+
174
+ ## License
175
+ MIT
@@ -0,0 +1,40 @@
1
+ [build-system]
2
+ requires = ["setuptools>=77"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "sproxy"
7
+ version = "0.1.0"
8
+ description = "Local egress guard for coding agents: inject secrets, block secret leaks to hosts they may not reach, and keep a tamper-evident audit log."
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = "MIT"
12
+ license-files = ["LICENSE"]
13
+ authors = [{ name = "Igor Pejic", email = "hi@igorpejic.com" }]
14
+ keywords = ["mitmproxy", "proxy", "secrets", "dlp", "egress", "ai-agents", "claude-code", "security"]
15
+ classifiers = [
16
+ "Development Status :: 3 - Alpha",
17
+ "Environment :: Console",
18
+ "Intended Audience :: Developers",
19
+ "Programming Language :: Python :: 3",
20
+ "Topic :: Security",
21
+ ]
22
+ # The CLI drives the `mitmdump` binary as a subprocess, so mitmproxy is a
23
+ # runtime dependency of the standard installation.
24
+ dependencies = ["mitmproxy>=11"]
25
+
26
+ [project.optional-dependencies]
27
+ dev = ["pytest>=7"]
28
+
29
+ [project.scripts]
30
+ sproxy = "sproxy.cli:main"
31
+
32
+ [project.urls]
33
+ Homepage = "https://github.com/igorpejic/sproxy"
34
+ Issues = "https://github.com/igorpejic/sproxy/issues"
35
+
36
+ [tool.setuptools]
37
+ packages = ["sproxy"]
38
+
39
+ [tool.pytest.ini_options]
40
+ testpaths = ["tests"]
sproxy-0.1.0/setup.cfg ADDED
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,8 @@
1
+ """sproxy - local egress guard for coding agents.
2
+
3
+ Keep this module import-light: it is imported both by the CLI (user's Python)
4
+ and by the mitmproxy addon (mitmdump's bundled interpreter). Only the standard
5
+ library may be imported at package import time.
6
+ """
7
+
8
+ __version__ = "0.1.0"
@@ -0,0 +1,4 @@
1
+ from sproxy.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ raise SystemExit(main())