proxy-aiops 0.3.0__tar.gz → 0.3.1__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 (99) hide show
  1. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/PKG-INFO +1 -1
  2. proxy_aiops-0.3.1/RELEASE_NOTES.md +26 -0
  3. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/docs/VERIFICATION.md +8 -4
  4. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/connection.py +23 -0
  5. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/platform.py +18 -13
  6. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/pyproject.toml +1 -1
  7. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/server.json +2 -2
  8. proxy_aiops-0.3.1/tests/test_dpapi_version.py +56 -0
  9. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_platform.py +4 -2
  10. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/uv.lock +1 -1
  11. proxy_aiops-0.3.0/RELEASE_NOTES.md +0 -27
  12. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/.github/workflows/mcp-publish.yml +0 -0
  13. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/.github/workflows/publish.yml +0 -0
  14. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/.gitignore +0 -0
  15. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/CHANGELOG.md +0 -0
  16. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/LICENSE +0 -0
  17. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/README.md +0 -0
  18. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/SECURITY.md +0 -0
  19. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/__init__.py +0 -0
  20. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/_shared.py +0 -0
  21. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/server.py +0 -0
  22. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/__init__.py +0 -0
  23. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/analysis.py +0 -0
  24. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/certs.py +0 -0
  25. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/configread.py +0 -0
  26. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/routes.py +0 -0
  27. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/services.py +0 -0
  28. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/status.py +0 -0
  29. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/traffic.py +0 -0
  30. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/undo.py +0 -0
  31. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/mcp_server/tools/writes.py +0 -0
  32. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/__init__.py +0 -0
  33. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/__init__.py +0 -0
  34. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/_common.py +0 -0
  35. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/_root.py +0 -0
  36. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/analyze.py +0 -0
  37. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/certs.py +0 -0
  38. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/configcmd.py +0 -0
  39. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/doctor.py +0 -0
  40. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/init.py +0 -0
  41. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/overview.py +0 -0
  42. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/routes.py +0 -0
  43. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/secret.py +0 -0
  44. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/server.py +0 -0
  45. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/services.py +0 -0
  46. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/cli/undo.py +0 -0
  47. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/config.py +0 -0
  48. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/doctor.py +0 -0
  49. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/__init__.py +0 -0
  50. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/audit.py +0 -0
  51. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/budget.py +0 -0
  52. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/decorators.py +0 -0
  53. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/paths.py +0 -0
  54. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/patterns.py +0 -0
  55. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/policy.py +0 -0
  56. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/readonly.py +0 -0
  57. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/sanitize.py +0 -0
  58. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/governance/undo.py +0 -0
  59. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/__init__.py +0 -0
  60. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/_util.py +0 -0
  61. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/analysis.py +0 -0
  62. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/certs.py +0 -0
  63. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/configread.py +0 -0
  64. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/overview.py +0 -0
  65. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/routes.py +0 -0
  66. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/services.py +0 -0
  67. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/status.py +0 -0
  68. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/traffic.py +0 -0
  69. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/ops/writes.py +0 -0
  70. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/proxy_aiops/secretstore.py +0 -0
  71. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/skills/proxy-aiops/SKILL.md +0 -0
  72. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/skills/proxy-aiops/references/agent-guardrails.md +0 -0
  73. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/skills/proxy-aiops/references/capabilities.md +0 -0
  74. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/skills/proxy-aiops/references/cli-reference.md +0 -0
  75. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/skills/proxy-aiops/references/setup-guide.md +0 -0
  76. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/smithery.yaml +0 -0
  77. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/conftest.py +0 -0
  78. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_analysis.py +0 -0
  79. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_cli_reads.py +0 -0
  80. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_cli_secret.py +0 -0
  81. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_cli_writes.py +0 -0
  82. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_connection.py +0 -0
  83. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_doctor.py +0 -0
  84. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_gov_audit.py +0 -0
  85. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_gov_decorators.py +0 -0
  86. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_gov_patterns.py +0 -0
  87. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_gov_policy.py +0 -0
  88. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_governance_persistence.py +0 -0
  89. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_init.py +0 -0
  90. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_int_fidelity.py +0 -0
  91. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_mcp_read_tools.py +0 -0
  92. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_ops_extra.py +0 -0
  93. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_optional_fields.py +0 -0
  94. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_readonly.py +0 -0
  95. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_reads.py +0 -0
  96. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_secretstore.py +0 -0
  97. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_smoke.py +0 -0
  98. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_undo_executor.py +0 -0
  99. {proxy_aiops-0.3.0 → proxy_aiops-0.3.1}/tests/test_writes.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: proxy-aiops
3
- Version: 0.3.0
3
+ Version: 0.3.1
4
4
  Summary: Governed AI-ops for Traefik + Caddy + HAProxy reverse proxies / load balancers: routes, services, upstream health, TLS cert expiry sweep, 5xx error-rate RCA, route conflict analysis, and governed writes (caddy config, haproxy server state/weight) with a built-in governance harness (audit, budget, undo, risk tiers)
5
5
  Author-email: wei <zhouwei008@gmail.com>
6
6
  License-Expression: MIT
@@ -0,0 +1,26 @@
1
+ # Release notes — proxy-aiops 0.3.1
2
+
3
+ Previous release: 0.3.0.
4
+
5
+ ## Fixed: the HAProxy branch could not talk to any current HAProxy
6
+
7
+ Every HAProxy path was hardcoded to Data Plane API **v2**. HAProxy 3.x ships
8
+ Data Plane API v3, which serves **only** `/v3` — every `/v2` path returns 404.
9
+ So the whole HAProxy platform branch was unusable against a current HAProxy,
10
+ failing at the very first probe.
11
+
12
+ The path registry now holds v3 paths, and the connection probes `/v3/info` once
13
+ per connection and rewrites the prefix to `/v2` when it sees an older server.
14
+ Both generations work; the probe is cached, so a v3 server costs one extra
15
+ request per connection and a v2 server two.
16
+
17
+ ## Live-verified: HAProxy
18
+
19
+ Verified against **HAProxy 3.0.25 with Data Plane API v3.0.21**: `doctor`, plus
20
+ reads cross-checked against the Data Plane API itself — the configured backend
21
+ and its two servers were reported accurately, including `serversUp: 0` for
22
+ servers pointed at closed ports.
23
+
24
+ With Traefik 3.2.5 and Caddy 2 verified in 0.3.0, **all three platforms are now
25
+ live-verified**. See [docs/VERIFICATION.md](docs/VERIFICATION.md) — guarded
26
+ config writes and TLS/certificate expiry against real certificates remain open.
@@ -3,7 +3,9 @@
3
3
  This document records what has and has not been validated against real reverse
4
4
  proxies, so the maturity claim is auditable rather than a vibe.
5
5
 
6
- ## Already live-verified ✅ — Traefik 3.2.5 and Caddy 2 (2026-07-20)
6
+ ## Already live-verified ✅ — all three platforms (2026-07-20)
7
+
8
+ Traefik 3.2.5, Caddy 2, and HAProxy 3.0.25 (Data Plane API v3.0.21).
7
9
 
8
10
  - `doctor` against both live endpoints (unauthenticated admin APIs, as the tool
9
11
  documents for traefik/caddy).
@@ -22,9 +24,11 @@ that never round-trips through float64.
22
24
 
23
25
  ## Not yet live-verified ⚠️
24
26
 
25
- - **HAProxy** the whole platform branch. It talks to the Data Plane API, which
26
- needs a `program api` section in `haproxy.cfg` plus a dataplaneapi binary; that
27
- setup was not built for this round. This is now the largest gap in this repo.
27
+ - **HAProxy is now verified** and that run found the branch was **entirely
28
+ broken**: every path was hardcoded to Data Plane API v2, but HAProxy 3.x serves
29
+ only `/v3`, so the first probe 404'd. The connection now detects the API
30
+ generation and supports both. Still untested there: runtime server state changes
31
+ and the stats-derived traffic analyses under real load.
28
32
  - **TLS / certificate expiry** (`certs`) against real certificates — both verified
29
33
  instances served plaintext on a lab port.
30
34
  - **Guarded config writes** (`config set/delete`) and their undo paths.
@@ -84,6 +84,8 @@ class ProxyConnection:
84
84
  auth=self._build_auth(target),
85
85
  headers={"Accept": "application/json"},
86
86
  )
87
+ # HAProxy Data Plane API generation, resolved lazily by _haproxy_path.
88
+ self._dpapi_prefix: str | None = None
87
89
 
88
90
  @staticmethod
89
91
  def _build_auth(target: TargetConfig) -> Any | None:
@@ -104,8 +106,29 @@ class ProxyConnection:
104
106
  def platform(self) -> Any:
105
107
  return self._target.platform_obj
106
108
 
109
+ def _haproxy_path(self, path: str) -> str:
110
+ """Rewrite a ``/v3/`` Data Plane API path to ``/v2/`` on an older server.
111
+
112
+ HAProxy 3.x ships Data Plane API v3, which serves **only** ``/v3`` — every
113
+ ``/v2`` path 404s. Older installs are the mirror image. The registry holds
114
+ the current (v3) paths and this probes ``/v3/info`` once per connection,
115
+ falling back to ``/v2`` so both generations work. Probed lazily and cached:
116
+ a v3 server costs one extra request per connection, a v2 server two.
117
+ """
118
+ if not path.startswith("/v3/"):
119
+ return path
120
+ if self._dpapi_prefix is None:
121
+ try:
122
+ resp = self._client.request("GET", "/v3/info")
123
+ self._dpapi_prefix = "/v3/" if resp.status_code < 400 else "/v2/"
124
+ except httpx.HTTPError:
125
+ self._dpapi_prefix = "/v3/" # unreachable: let the real call report it
126
+ return self._dpapi_prefix + path[4:]
127
+
107
128
  def _request(self, method: str, path: str, **kwargs: Any) -> Any:
108
129
  label = self._target.platform_obj.label
130
+ if self._target.platform == "haproxy":
131
+ path = self._haproxy_path(path)
109
132
  try:
110
133
  resp = self._client.request(method, path, **kwargs)
111
134
  except httpx.HTTPError as exc:
@@ -18,7 +18,7 @@ v0.1 registers three platforms:
18
18
  read via ``GET /config/``, targeted config writes via ``PATCH/POST/DELETE
19
19
  /config/<path>`` and full replace via ``POST /load``. This platform carries
20
20
  the write surface (prior-config capture → replayable undo).
21
- * **haproxy** — HAProxy Data Plane API v2 (``/v2/services/haproxy/...``,
21
+ * **haproxy** — HAProxy Data Plane API v3, with v2 fallback (``/v3/services/haproxy/...``,
22
22
  HTTP Basic auth): frontends/backends/servers/stats reads plus runtime
23
23
  server writes (admin state ready/drain/maint, weight).
24
24
 
@@ -288,19 +288,24 @@ _CADDY_UNSUPPORTED = {
288
288
  ),
289
289
  }
290
290
 
291
- # ─── HAProxy (Data Plane API v2, HTTP Basic auth) ────────────────────────────
291
+ # ─── HAProxy (Data Plane API, HTTP Basic auth) ──────────────────────────────
292
+ # Paths are written for Data Plane API **v3** (HAProxy 3.x). A v2 server is
293
+ # still supported: the connection probes once and rewrites the /v3/ prefix to
294
+ # /v2/ when it sees an older API. Verified live against dataplaneapi v3.0.21,
295
+ # which serves ONLY /v3 — every /v2 path 404s, so hardcoding v2 (as this did)
296
+ # made the whole HAProxy branch unusable on any current HAProxy.
292
297
  _HAPROXY_PATHS = {
293
- "probe": "/v2/info",
294
- "version": "/v2/info",
295
- "frontends": "/v2/services/haproxy/configuration/frontends",
296
- "frontend_detail": "/v2/services/haproxy/configuration/frontends/{name}",
297
- "binds": "/v2/services/haproxy/configuration/binds?frontend={frontend}",
298
- "backends": "/v2/services/haproxy/configuration/backends",
299
- "backend_detail": "/v2/services/haproxy/configuration/backends/{name}",
300
- "servers": "/v2/services/haproxy/configuration/servers?backend={backend}",
301
- "runtime_servers": "/v2/services/haproxy/runtime/servers?backend={backend}",
302
- "runtime_server": "/v2/services/haproxy/runtime/servers/{name}?backend={backend}",
303
- "stats": "/v2/services/haproxy/stats/native",
298
+ "probe": "/v3/info",
299
+ "version": "/v3/info",
300
+ "frontends": "/v3/services/haproxy/configuration/frontends",
301
+ "frontend_detail": "/v3/services/haproxy/configuration/frontends/{name}",
302
+ "binds": "/v3/services/haproxy/configuration/binds?frontend={frontend}",
303
+ "backends": "/v3/services/haproxy/configuration/backends",
304
+ "backend_detail": "/v3/services/haproxy/configuration/backends/{name}",
305
+ "servers": "/v3/services/haproxy/configuration/servers?backend={backend}",
306
+ "runtime_servers": "/v3/services/haproxy/runtime/servers?backend={backend}",
307
+ "runtime_server": "/v3/services/haproxy/runtime/servers/{name}?backend={backend}",
308
+ "stats": "/v3/services/haproxy/stats/native",
304
309
  }
305
310
  _HAPROXY_UNSUPPORTED = {
306
311
  "metrics": (
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "proxy-aiops"
7
- version = "0.3.0"
7
+ version = "0.3.1"
8
8
  description = "Governed AI-ops for Traefik + Caddy + HAProxy reverse proxies / load balancers: routes, services, upstream health, TLS cert expiry sweep, 5xx error-rate RCA, route conflict analysis, and governed writes (caddy config, haproxy server state/weight) with a built-in governance harness (audit, budget, undo, risk tiers)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -7,12 +7,12 @@
7
7
  "url": "https://github.com/AIops-tools/Proxy-AIops",
8
8
  "source": "github"
9
9
  },
10
- "version": "0.3.0",
10
+ "version": "0.3.1",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "pypi",
14
14
  "identifier": "proxy-aiops",
15
- "version": "0.3.0",
15
+ "version": "0.3.1",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  }
@@ -0,0 +1,56 @@
1
+ """HAProxy Data Plane API generation must be detected, not assumed.
2
+
3
+ Regression from live verification against HAProxy 3.0 / dataplaneapi v3.0.21,
4
+ which serves ONLY /v3 — every /v2 path 404s. The registry previously hardcoded
5
+ /v2, so the entire HAProxy branch was unusable against any current HAProxy.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from unittest.mock import MagicMock
11
+
12
+ import pytest
13
+
14
+ from proxy_aiops.connection import ProxyConnection
15
+
16
+
17
+ def _conn(probe_status: int) -> ProxyConnection:
18
+ c = ProxyConnection.__new__(ProxyConnection)
19
+ client = MagicMock(name="client")
20
+ client.request.return_value = MagicMock(status_code=probe_status)
21
+ c._client = client
22
+ c._dpapi_prefix = None
23
+ return c
24
+
25
+
26
+ @pytest.mark.unit
27
+ def test_v3_server_keeps_v3_paths():
28
+ c = _conn(200)
29
+ assert c._haproxy_path("/v3/info") == "/v3/info"
30
+ assert c._haproxy_path("/v3/services/haproxy/configuration/backends") == (
31
+ "/v3/services/haproxy/configuration/backends"
32
+ )
33
+
34
+
35
+ @pytest.mark.unit
36
+ def test_v2_server_gets_paths_rewritten():
37
+ c = _conn(404) # /v3/info missing => an older Data Plane API
38
+ assert c._haproxy_path("/v3/info") == "/v2/info"
39
+ assert c._haproxy_path("/v3/services/haproxy/configuration/backends") == (
40
+ "/v2/services/haproxy/configuration/backends"
41
+ )
42
+
43
+
44
+ @pytest.mark.unit
45
+ def test_probe_is_cached_not_repeated_per_request():
46
+ c = _conn(200)
47
+ for _ in range(5):
48
+ c._haproxy_path("/v3/info")
49
+ assert c._client.request.call_count == 1
50
+
51
+
52
+ @pytest.mark.unit
53
+ def test_non_versioned_paths_are_untouched():
54
+ c = _conn(200)
55
+ assert c._haproxy_path("/metrics") == "/metrics"
56
+ assert c._client.request.call_count == 0, "must not probe for unrelated paths"
@@ -44,9 +44,11 @@ def test_path_templates_differ_per_platform():
44
44
  ha = get_platform(HAPROXY)
45
45
  assert tr.path("routers") == "/api/http/routers"
46
46
  assert tr.path("router_detail", name="web@file").endswith("/web%40file")
47
- assert ha.path("backends") == "/v2/services/haproxy/configuration/backends"
47
+ # The registry holds Data Plane API **v3** paths (HAProxy 3.x serves only
48
+ # /v3); the connection rewrites them to /v2 for an older server.
49
+ assert ha.path("backends") == "/v3/services/haproxy/configuration/backends"
48
50
  assert ha.path("runtime_server", name="web1", backend="app") == (
49
- "/v2/services/haproxy/runtime/servers/web1?backend=app"
51
+ "/v3/services/haproxy/runtime/servers/web1?backend=app"
50
52
  )
51
53
  assert get_platform(CADDY).path("config_load") == "/load"
52
54
 
@@ -484,7 +484,7 @@ wheels = [
484
484
 
485
485
  [[package]]
486
486
  name = "proxy-aiops"
487
- version = "0.3.0"
487
+ version = "0.3.1"
488
488
  source = { editable = "." }
489
489
  dependencies = [
490
490
  { name = "cryptography" },
@@ -1,27 +0,0 @@
1
- # Release notes — proxy-aiops 0.3.0
2
-
3
- Previous release: 0.2.0.
4
-
5
- ## Fixed: route priority lost precision and collapsed distinct values
6
-
7
- Traefik route priority is an int64. Routing it through the float helper rendered it
8
- in scientific notation (`9.223372036854776e+18`) *and* lost precision, because a
9
- float64 cannot represent values near 2**63 exactly.
10
-
11
- The practical consequence, seen on a live Traefik: two routers with **different**
12
- priorities (…806 and …805) displayed as the **same** number. Route priority decides
13
- matching order, so this actively misleads anyone debugging which route wins.
14
-
15
- Integer quantities — route priority, server weight, request totals, session counts —
16
- now use an exact `as_int` that returns an existing `int` untouched instead of
17
- round-tripping it through float64. Genuinely fractional values are unchanged.
18
-
19
- If you parse these fields, the JSON changes from `9.223372036854776e+18` to
20
- `9223372036854775806`, and counters from `12.0` to `12`.
21
-
22
- ## Live-verified
23
-
24
- Against **Traefik 3.2.5** and **Caddy 2**: reads cross-checked against each proxy's
25
- own API, plus the three analyses. See [docs/VERIFICATION.md](docs/VERIFICATION.md) —
26
- **HAProxy remains unverified** (its Data Plane API setup was not built for this
27
- round) and is now the largest gap here.
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes