Releases: AIops-tools/Proxy-AIops
Release list
v0.7.0
Fixed
- Undoing a deleted array element could never work.
delete_config_pathis a high-risk write that records an undo, but its inverse re-created the subtree with POST — and onceroutes/1is deleted the array is shorter, so Caddy answers "array index out of bounds". Array paths (routes/N,handle/N,upstreams/N) are the norm in a Caddy config, so the token for a destructive write was routinely un-replayable. The inverse now inserts with PUT, which is Caddy's insert-at-index. Verified live against Caddy 2, including deleting the last element and restoring it into an empty array. set_config_value(insert=True)no longer pre-reads the index. There is nothing at that index by definition, and Caddy answers a GET of an out-of-range index with 400, not 404, so the pre-read re-raised and the insert never reached the wire — which is what made the undo above look like a rejected write rather than a missing capability.undo applyreplays against the target the original write ran on. It dispatched the inverse against whatever target the caller named — in practice the config's first entry — while the write's own target sat unused in the undo record. On a multi-target config the inverse therefore ran against the wrong host; it only looks harmless because the resource usually is not there, but two hosts holding the same name and the inverse succeeds on the wrong one, silently. An explicitly named target still wins. Line-wide: all 24 copies had the identical defect. Caught live in container-host-aiops, where a stop recorded against a Podman target replayed against a Portainer one.
v0.6.0
Changed (BREAKING)
- Requires MCP SDK 2.0 (
mcp[cli]>=2.0,<3.0).mcp.server.fastmcpno longer exists in 2.0; the server is now built withMCPServerand reports its package version in the stdio handshake.
Fixed
undo applyworks from the CLI. Every write tool is imported lazily inside its own CLI command, so a CLI-driven undo ran in a process where the inverse tool was never registered and failed with "inverse tool is not registered" — for every write tool. Only the MCP entry point, which imports the whole server, worked. Found while live-verifying against a real cluster.- An undetermined outcome is audited
unknown, notok. The harness only classified a result as undetermined when the payload also carried anerrorkey, so a write that looked successful but had not been confirmed was recorded as a success.
v0.5.0
Release notes — proxy-aiops 0.5.0
Previous release: 0.4.0.
BREAKING — the authorization layer is removed
This tool no longer decides whether a write is permitted. Read-only mode
(<PREFIX>_READ_ONLY), the graduated-approval / approver gate, and the
rules.yaml deny engine are all gone. Whether an operation runs is the
agent's judgement, or the permission of the account you connect it with — point
it at a read-only credential and the write fails at the server, the place that
actually owns the permission.
What the tool guarantees instead is that nothing is silent: every operation,
over MCP and the CLI alike, lands a row in the audit log — there is no
unaudited entry point. Destructive writes still capture their before-state and
record an undo token where a clean inverse exists.
- If you set
<PREFIX>_READ_ONLY=1, it now has no effect and the MCP server
logs a warning at startup. Restrict writes via the connecting account instead. <PREFIX>_AUDIT_APPROVED_BY/<PREFIX>_AUDIT_RATIONALEstill work, but are now
optional audit annotations — recorded on the row when set, never required.- The declared
risk_levelis carried into the audit row as a descriptive tier
(a label, not a gate).
The governance harness is now: audit (MCP+CLI, unbypassable) · runaway/budget
safety guard · undo recording · output sanitize. policy.py is a small
risk-tier classifier; governance/readonly.py is deleted.
v0.4.0
Release notes — proxy-aiops 0.4.0
Previous release: 0.3.1.
In this tool
- Caddy config writes refuse the
adminsubtree. The Caddy admin API is this tool's own transport, andadminis an ordinary top-level key in the config tree — soset_config_value("admin/disabled", true)tore down the listener mid-request and left the undo with nowhere to go.load_configlikewise refuses a config that disables admin or moves its listener. The tool's own troubleshooting guide already listed this as a terminal state; it just did not stop itself causing it.
Every tool in the line: previews and undetermined outcomes
This release fixes three harness defects that were silently degrading the audit
trail and the undo store.
A write that loses its response is no longer recorded as a failure. The
harness assumed a sanitized error meant nothing had happened. That assumption is
false in exactly the case that matters most: when a write severs its own
connection, the request has already landed, the response cannot come back, and
the operation was recorded as status=error with no undo token created at
all. Transport-level failures are now audited as status=unknown, the result
says plainly that the operation may have taken effect and should be verified
before retrying, and a write that stashed its before-state has its inverse
recorded anyway — flagged effectVerified: false, which undo_list and
undo_apply both surface. Existing undo.db files are migrated in place; their
rows read as verified, which is accurate, since the old code only ever recorded
on the confirmed path.
A dry-run no longer writes an undo token. Previews were recording inverses
built from a before-state they never had: the undo callback's permissive default
filled the gap with a guess, producing a real, applicable token for an operation
that never happened.
A dry-run no longer demands a named approver. Requiring an approval in order
to ask whether something needs approval inverts what a preview is for. The tier
is still computed and still audited, so the preview can tell you an approver
will be needed; it just no longer refuses to answer. The write itself is gated
exactly as before.
The invariant, now stated: a dry_run may read; it must never write. Guards
run on the preview path, which means a preview can and does report that an
operation would be refused.
Also line-wide
- Truncated text now ends in an ellipsis instead of being cut silently. This
line already treats a silent cut as a defect for lists; it was doing exactly
that to strings. - Error messages are capped at 800 characters, not 300. These messages end
with what to do instead, so the cap was removing the most useful sentence of
every long refusal.
v0.3.1
Release notes — proxy-aiops 0.3.1
Previous release: 0.3.0.
Fixed: the HAProxy branch could not talk to any current HAProxy
Every HAProxy path was hardcoded to Data Plane API v2. HAProxy 3.x ships
Data Plane API v3, which serves only /v3 — every /v2 path returns 404.
So the whole HAProxy platform branch was unusable against a current HAProxy,
failing at the very first probe.
The path registry now holds v3 paths, and the connection probes /v3/info once
per connection and rewrites the prefix to /v2 when it sees an older server.
Both generations work; the probe is cached, so a v3 server costs one extra
request per connection and a v2 server two.
Live-verified: HAProxy
Verified against HAProxy 3.0.25 with Data Plane API v3.0.21: doctor, plus
reads cross-checked against the Data Plane API itself — the configured backend
and its two servers were reported accurately, including serversUp: 0 for
servers pointed at closed ports.
With Traefik 3.2.5 and Caddy 2 verified in 0.3.0, all three platforms are now
live-verified. See docs/VERIFICATION.md — guarded
config writes and TLS/certificate expiry against real certificates remain open.
v0.3.0
Release notes — proxy-aiops 0.3.0
Previous release: 0.2.0.
Fixed: route priority lost precision and collapsed distinct values
Traefik route priority is an int64. Routing it through the float helper rendered it
in scientific notation (9.223372036854776e+18) and lost precision, because a
float64 cannot represent values near 2**63 exactly.
The practical consequence, seen on a live Traefik: two routers with different
priorities (…806 and …805) displayed as the same number. Route priority decides
matching order, so this actively misleads anyone debugging which route wins.
Integer quantities — route priority, server weight, request totals, session counts —
now use an exact as_int that returns an existing int untouched instead of
round-tripping it through float64. Genuinely fractional values are unchanged.
If you parse these fields, the JSON changes from 9.223372036854776e+18 to
9223372036854775806, and counters from 12.0 to 12.
Live-verified
Against Traefik 3.2.5 and Caddy 2: reads cross-checked against each proxy's
own API, plus the three analyses. See docs/VERIFICATION.md —
HAProxy remains unverified (its Data Plane API setup was not built for this
round) and is now the largest gap here.
v0.2.0
Release notes — proxy-aiops 0.2.0
Previous release: 0.1.0.
Headline: read-only mode
export PROXY_READ_ONLY=1With this set the 6 write tools are never registered — an MCP
client lists 22 tools instead of 28. The writes are not hidden
behind a flag and not merely refused on call: they are absent from the session,
so a model cannot invoke one and cannot be argued into one. For a reviewer this
is checkable rather than promised — connect, list the tools, and the writes are
not there.
Enforcement is two layers deep: the @governed_tool harness refuses every
non-read operation (covering the CLI and in-process callers too), and the MCP
server removes write tools from list_tools(). Changing entry point does not
get around it.
BREAKING — return shapes changed
This release changes payloads that callers may be parsing. Both changes exist
to stop a result from misrepresenting itself:
- Absent fields are now
null, not"". A missing value and an empty value
were previously indistinguishable, which invited consumers to invent the
difference. Keys are still always present — only the value may be null. - Anything with a
limitnow returns an envelope —
{"<items>": [...], "returned": N, "limit": L, "truncated": bool}. Truncation is
measured (one extra row is fetched), never inferred from the page happening to
be full. Where a genuine pre-cap total is knowable it is reported astotal;
where it isn't,totalis deliberately omitted rather than echoingreturned.
Also in this release
docs/VERIFICATION.md— what the mock suite actually guarantees, a live
verification checklist, and the criteria for claiming this tool verified.skills/proxy-aiops/references/agent-guardrails.md— for driving this tool with a
smaller / local model: which guardrails are now enforced for you, and a
ready-made system prompt for the rest.- Expanded operator playbooks in the skill documentation.
- The advertised tool count now matches what an MCP client actually lists
(it includesundo_list/undo_apply), and a release gate keeps it honest. - The
(preview)label has been dropped. It never meant unreleased; verification
status now lives indocs/VERIFICATION.mdwhere it can be specific.