fix: repair local approval resolution (#86771)

This commit is contained in:
Jason (Json)
2026-05-26 20:56:30 -06:00
committed by GitHub
parent f89fcdd5b3
commit 13cfb77c10
4 changed files with 31 additions and 6 deletions

View File

@@ -144,7 +144,7 @@ describe("discord exec approval monitor helpers", () => {
});
});
it("keeps already-resolved approval clicks quiet", async () => {
it("shows a follow-up for already-resolved approval clicks", async () => {
const interaction = createInteraction();
const button = new ExecApprovalButton({
getApprovers: () => ["123"],
@@ -154,7 +154,11 @@ describe("discord exec approval monitor helpers", () => {
await button.run(interaction, { id: "abc", action: "allow-once" });
expect(interaction.acknowledge).toHaveBeenCalled();
expect(interaction.followUp).not.toHaveBeenCalled();
expect(interaction.followUp).toHaveBeenCalledWith({
content:
"That approval request is no longer pending. It may have expired or already been resolved.",
ephemeral: true,
});
});
it("builds button context from config and routes resolution over gateway", async () => {

View File

@@ -112,10 +112,13 @@ export class ExecApprovalButton extends Button {
} catch {}
const result = await this.ctx.resolveApproval(parsed.approvalId, parsed.action);
if (!result.ok && result.reason !== "not-found") {
if (!result.ok) {
try {
await interaction.followUp({
content: `Failed to submit approval decision for **${decisionLabel}**. The request may have expired or already been resolved.`,
content:
result.reason === "not-found"
? `That approval request is no longer pending. It may have expired or already been resolved.`
: `Failed to submit approval decision for **${decisionLabel}**. The request may have expired or already been resolved.`,
ephemeral: true,
});
} catch {}

View File

@@ -117,7 +117,7 @@ describe("withOperatorApprovalsGatewayClient", () => {
expect(clientState.options?.deviceIdentity).toBeUndefined();
});
it("omits approval runtime token for explicit gateway URL overrides", async () => {
it("keeps approval runtime token for loopback explicit gateway URL overrides", async () => {
await withOperatorApprovalsGatewayClient(
{
config: {} as never,
@@ -127,6 +127,21 @@ describe("withOperatorApprovalsGatewayClient", () => {
async () => undefined,
);
expect(typeof clientState.options?.approvalRuntimeToken).toBe("string");
});
it("omits approval runtime token for remote explicit gateway URL overrides", async () => {
bootstrapState.url = "wss://gateway.example/ws";
await withOperatorApprovalsGatewayClient(
{
config: {} as never,
gatewayUrl: "wss://gateway.example/ws",
clientDisplayName: "Matrix approval (@owner:example.org)",
},
async () => undefined,
);
expect(clientState.options).not.toHaveProperty("approvalRuntimeToken");
});

View File

@@ -44,12 +44,15 @@ export async function createOperatorApprovalsGatewayClient(
gatewayUrl: params.gatewayUrl,
env: process.env,
});
const shouldSendApprovalRuntimeToken = !params.gatewayUrl || isLoopbackGatewayUrl(bootstrap.url);
return new GatewayClient({
url: bootstrap.url,
token: bootstrap.auth.token,
password: bootstrap.auth.password,
...(params.gatewayUrl ? {} : { approvalRuntimeToken: getOperatorApprovalRuntimeToken() }),
...(shouldSendApprovalRuntimeToken
? { approvalRuntimeToken: getOperatorApprovalRuntimeToken() }
: {}),
preauthHandshakeTimeoutMs: bootstrap.preauthHandshakeTimeoutMs,
clientName: GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
clientDisplayName: params.clientDisplayName,