agentic-dev-loop 1.0.0a19__tar.gz → 1.0.0a20__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.

Potentially problematic release.


This version of agentic-dev-loop might be problematic. Click here for more details.

Files changed (86) hide show
  1. {agentic_dev_loop-1.0.0a19/src/agentic_dev_loop.egg-info → agentic_dev_loop-1.0.0a20}/PKG-INFO +1 -1
  2. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/pyproject.toml +1 -1
  3. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/egress_proxy.py +17 -0
  4. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20/src/agentic_dev_loop.egg-info}/PKG-INFO +1 -1
  5. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_egress_proxy.py +77 -0
  6. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/LICENSE +0 -0
  7. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/README.md +0 -0
  8. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/setup.cfg +0 -0
  9. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/__init__.py +0 -0
  10. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/core/__init__.py +0 -0
  11. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/core/config.py +0 -0
  12. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/core/results.py +0 -0
  13. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/core/verdict.py +0 -0
  14. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/__init__.py +0 -0
  15. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/actions.py +0 -0
  16. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/agents.py +0 -0
  17. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/cli.py +0 -0
  18. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/deps.py +0 -0
  19. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/dryrun.py +0 -0
  20. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/egress_policy.py +0 -0
  21. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/extensions/__init__.py +0 -0
  22. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/extensions/aidlc.py +0 -0
  23. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/graph.py +0 -0
  24. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/hostboundary.py +0 -0
  25. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/isolation.py +0 -0
  26. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/llm.py +0 -0
  27. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/loaders.py +0 -0
  28. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/mounts.py +0 -0
  29. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/outputs.py +0 -0
  30. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/presets.py +0 -0
  31. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/proc.py +0 -0
  32. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/registry.py +0 -0
  33. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/seccomp/__init__.py +0 -0
  34. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/seccomp/chromium-userns.json +0 -0
  35. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/secrets.py +0 -0
  36. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/stages.py +0 -0
  37. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/step_workspace.py +0 -0
  38. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/engine/sync_back.py +0 -0
  39. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/py.typed +0 -0
  40. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/viz/__init__.py +0 -0
  41. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/viz/__main__.py +0 -0
  42. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop/viz/server.py +0 -0
  43. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop.egg-info/SOURCES.txt +0 -0
  44. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop.egg-info/dependency_links.txt +0 -0
  45. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop.egg-info/entry_points.txt +0 -0
  46. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop.egg-info/requires.txt +0 -0
  47. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/src/agentic_dev_loop.egg-info/top_level.txt +0 -0
  48. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_actions.py +0 -0
  49. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_agents.py +0 -0
  50. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_aidlc.py +0 -0
  51. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_cli.py +0 -0
  52. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_config.py +0 -0
  53. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_deps.py +0 -0
  54. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_dry_run.py +0 -0
  55. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_e2e_fixtures.py +0 -0
  56. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_graph.py +0 -0
  57. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_hostboundary.py +0 -0
  58. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_hostboundary_integration.py +0 -0
  59. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_isolation.py +0 -0
  60. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_isolation_integration.py +0 -0
  61. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_isolation_pbt.py +0 -0
  62. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_llm.py +0 -0
  63. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_loaders.py +0 -0
  64. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_module_contract.py +0 -0
  65. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_outputs.py +0 -0
  66. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_outputs_pbt.py +0 -0
  67. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_proc.py +0 -0
  68. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_publish.py +0 -0
  69. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_qa_prompt.py +0 -0
  70. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_registry.py +0 -0
  71. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_repo_ascii.py +0 -0
  72. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_results.py +0 -0
  73. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_sdk_compat.py +0 -0
  74. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_secrets.py +0 -0
  75. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_secrets_integration.py +0 -0
  76. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_secrets_pipeline.py +0 -0
  77. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_source_resolution.py +0 -0
  78. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_stages.py +0 -0
  79. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_step_workspace.py +0 -0
  80. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_sync_back.py +0 -0
  81. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_trigger_script.py +0 -0
  82. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_unit5_config.py +0 -0
  83. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_unit5_pbt.py +0 -0
  84. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_unit5_pure.py +0 -0
  85. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_verdict.py +0 -0
  86. {agentic_dev_loop-1.0.0a19 → agentic_dev_loop-1.0.0a20}/tests/test_viz.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-dev-loop
3
- Version: 1.0.0a19
3
+ Version: 1.0.0a20
4
4
  Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
5
5
  Author: Luke Wilson
6
6
  License-Expression: Apache-2.0
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agentic-dev-loop"
7
- version = "1.0.0a19"
7
+ version = "1.0.0a20"
8
8
  description = "Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -131,6 +131,13 @@ class EgressProxy:
131
131
  _write(writer, b"HTTP/1.1 403 Forbidden\r\nContent-Length: 0\r\n\r\n")
132
132
  return
133
133
  self._record(host, True)
134
+ # Drain the rest of the CONNECT request (the header block after the
135
+ # request line). Clients send the whole request in one write, so the
136
+ # headers are already buffered here; relaying them to the upstream as
137
+ # if they were the first tunnel bytes corrupts the TLS handshake (the
138
+ # upstream answers with a decode alert - the restore step's SSL
139
+ # TLSV1_ALERT_DECODE_ERROR).
140
+ await _drain_headers(reader)
134
141
  conn = await _open(host, port)
135
142
  if conn is None:
136
143
  _write(writer, b"HTTP/1.1 502 Bad Gateway\r\nContent-Length: 0\r\n\r\n")
@@ -222,6 +229,16 @@ async def _forward_headers(reader, upstream, host: str) -> None:
222
229
  await upstream.drain()
223
230
 
224
231
 
232
+ async def _drain_headers(reader) -> None:
233
+ """Consume a request's header block (the lines after the request line,
234
+ terminated by a blank line). The CONNECT path must not forward these to
235
+ the upstream tunnel - only the post-200 bytes belong there."""
236
+ while True:
237
+ line = await reader.readline()
238
+ if not line or line in (b"\r\n", b"\n"):
239
+ break
240
+
241
+
225
242
  async def _relay_both(client_reader, client_writer, upstream_reader,
226
243
  upstream_writer) -> None:
227
244
  await asyncio.gather(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentic-dev-loop
3
- Version: 1.0.0a19
3
+ Version: 1.0.0a20
4
4
  Summary: Turn an LLM into a gated, sandboxed, resumable construction loop over your codebase.
5
5
  Author: Luke Wilson
6
6
  License-Expression: Apache-2.0
@@ -5,6 +5,7 @@ unmatched hostname is denied and logged as an enforcement event (BR-6)."""
5
5
  import http.server
6
6
  import socket
7
7
  import threading
8
+ import time
8
9
 
9
10
  import pytest
10
11
 
@@ -126,3 +127,79 @@ def test_connect_port_constraint_matches_exact_port():
126
127
  p.stop()
127
128
  finally:
128
129
  server.shutdown()
130
+
131
+
132
+ class _RawTcpServer:
133
+ """A bare TCP listener that records every byte it receives."""
134
+
135
+ def __init__(self):
136
+ self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
137
+ self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
138
+ self.sock.bind(("127.0.0.1", 0))
139
+ self.sock.listen(1)
140
+ self.port = self.sock.getsockname()[1]
141
+ self.received = bytearray()
142
+ self._thread = threading.Thread(target=self._accept, daemon=True)
143
+ self._thread.start()
144
+
145
+ def _accept(self):
146
+ try:
147
+ conn, _ = self.sock.accept()
148
+ except OSError:
149
+ return
150
+ with conn:
151
+ conn.settimeout(5.0)
152
+ while True:
153
+ try:
154
+ chunk = conn.recv(65536)
155
+ except socket.timeout:
156
+ break
157
+ if not chunk:
158
+ break
159
+ self.received.extend(chunk)
160
+
161
+ def close(self):
162
+ try:
163
+ self.sock.close()
164
+ except OSError:
165
+ pass
166
+
167
+
168
+ def test_connect_headers_drained_not_tunnelled():
169
+ """The CONNECT request's header block must be consumed by the proxy, not
170
+ relayed into the tunnel. Clients send the request line, headers and the
171
+ first TLS bytes in one write; leaking the headers corrupts the handshake
172
+ (the upstream answers with a TLS decode alert)."""
173
+ upstream = _RawTcpServer()
174
+ try:
175
+ policy = EgressPolicy(targets=(TargetEntry(host="127.0.0.1"),))
176
+ p = EgressProxy(policy=policy)
177
+ p.start()
178
+ try:
179
+ tls_bytes = b"\x16\x03\x01" + b"post-200-bytes"
180
+ payload = (
181
+ f"CONNECT 127.0.0.1:{upstream.port} HTTP/1.1\r\n"
182
+ "Host: 127.0.0.1\r\n"
183
+ "User-Agent: pip\r\n"
184
+ "Proxy-Connection: keep-alive\r\n"
185
+ "\r\n"
186
+ ).encode("latin-1") + tls_bytes
187
+ with socket.create_connection(("127.0.0.1", p._port), timeout=5.0) as s:
188
+ s.sendall(payload)
189
+ s.settimeout(5.0)
190
+ buf = b""
191
+ while b"\r\n\r\n" not in buf:
192
+ chunk = s.recv(65536)
193
+ if not chunk:
194
+ break
195
+ buf += chunk
196
+ assert b"200 Connection Established" in buf
197
+ deadline = time.monotonic() + 5.0
198
+ while (time.monotonic() < deadline
199
+ and len(upstream.received) < len(tls_bytes)):
200
+ time.sleep(0.05)
201
+ assert bytes(upstream.received) == tls_bytes
202
+ finally:
203
+ p.stop()
204
+ finally:
205
+ upstream.close()