From 7da34a6e9a62690dc5ea9ba3210ea914b952a4b0 Mon Sep 17 00:00:00 2001 From: mikemolinet Date: Sun, 10 May 2026 11:21:20 -0700 Subject: [PATCH] fix(cli): agents webhook-secret regenerate sends X-Confirm-Destructive header (Bug cmp03hy9o) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `cueapi agents webhook-secret regenerate ` was making the POST /v1/agents/{ref}/webhook-secret/regenerate request without the `X-Confirm-Destructive: true` header that the server requires. Result: even after the user typed `y` at the confirmation prompt, the request was rejected HTTP 400 server-side. Surfaced 2026-05-10 from Phase 2 messaging smoke testing — identical bug shape to the one already fixed on `cueapi key webhook-secret regenerate` (which did pass the header). Mirror the existing pattern: pass the header on the httpx POST right after the Y/N confirm clears. Tests: - New `test_agents_webhook_secret_regenerate_sends_destructive_header` pins the header on the wire — same shape as the existing `test_key_webhook_secret_regenerate_sends_destructive_header`. --- cueapi/cli.py | 6 +++++- tests/test_cli.py | 28 ++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/cueapi/cli.py b/cueapi/cli.py index 794f0be..c036310 100644 --- a/cueapi/cli.py +++ b/cueapi/cli.py @@ -1662,7 +1662,11 @@ def agents_webhook_secret_regenerate(ctx: click.Context, ref: str, yes: bool) -> return try: with CueAPIClient(api_key=ctx.obj.get("api_key"), profile=ctx.obj.get("profile")) as client: - resp = client.post(f"/agents/{ref}/webhook-secret/regenerate", json={}) + resp = client.post( + f"/agents/{ref}/webhook-secret/regenerate", + json={}, + headers={"X-Confirm-Destructive": "true"}, + ) if resp.status_code == 200: data = resp.json() click.echo() diff --git a/tests/test_cli.py b/tests/test_cli.py index 4e8c37c..314a299 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -682,6 +682,34 @@ def test_agents_webhook_secret_regenerate_with_yes(monkeypatch): assert "save now" in result.output.lower() or "shown once" in result.output.lower() +def test_agents_webhook_secret_regenerate_sends_destructive_header(monkeypatch): + """Pin: `cueapi agents webhook-secret regenerate` MUST send + `X-Confirm-Destructive: true` header — server requires it (Bug + cmp03hy9o, surfaced 2026-05-10 from Phase 2 messaging smoke). + Mirrors the same header pin on `cueapi key webhook-secret regenerate`. + """ + holder: dict = {} + _patch_ws_client( + monkeypatch, + holder, + responses={ + ("POST", "/agents/agt_x/webhook-secret/regenerate"): lambda: _FakeResp( + 200, {"webhook_secret": "wsec_new"} + ) + }, + ) + result = runner.invoke( + main, + ["agents", "webhook-secret", "regenerate", "agt_x", "--yes"], + ) + assert result.exit_code == 0, result.output + method, path, body, headers = holder["client"].calls[-1] + assert method == "POST" + assert path == "/agents/agt_x/webhook-secret/regenerate" + assert headers == {"X-Confirm-Destructive": "true"} + assert "wsec_new" in result.output + + # --- inbox / sent ---