From 31752d408989c71ea3ab45953f0b9e12b4b596a5 Mon Sep 17 00:00:00 2001 From: damocles Date: Wed, 15 Jul 2026 18:41:26 +0200 Subject: [PATCH] fix(#2488): verify assignee change landed instead of trusting forge 200 --- hive-forge/src/verbs/assign.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/hive-forge/src/verbs/assign.rs b/hive-forge/src/verbs/assign.rs index f7a63592..00ab4593 100644 --- a/hive-forge/src/verbs/assign.rs +++ b/hive-forge/src/verbs/assign.rs @@ -60,6 +60,32 @@ pub fn run(client: &Client, args: Args) -> Result<()> { .iter() .filter_map(|u| u.login.as_deref()) .collect(); + // Verify the mutation actually landed. Forgejo silently drops an assignee + // change the caller isn't permitted to make (e.g. unassigning another + // user) and echoes back the *unchanged* list with a 200 — so trusting the + // success status reports a no-op as success. Diff the returned list + // against the intent and fail loudly instead. + let still_present = logins.iter().any(|&u| u == args.user); + if args.remove && still_present { + anyhow::bail!( + "assignee '{}' is still assigned to #{} after remove — the forge \ + rejected the change (likely insufficient permission to unassign \ + this user). current assignees: [{}]", + args.user, + args.number, + logins.join(", ") + ); + } + if !args.remove && !still_present { + anyhow::bail!( + "assignee '{}' is not assigned to #{} after add — the forge rejected \ + the change (the user may not exist or lack access to this repo). \ + current assignees: [{}]", + args.user, + args.number, + logins.join(", ") + ); + } print_json(&json!({ "number": resp.number, "assignees": logins,