Skip to content

Commit 33ca1bc

Browse files
fix: repair local approval resolution
1 parent a1934e9 commit 33ca1bc

4 files changed

Lines changed: 31 additions & 6 deletions

File tree

extensions/discord/src/monitor/exec-approvals.test.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ describe("discord exec approval monitor helpers", () => {
144144
});
145145
});
146146

147-
it("keeps already-resolved approval clicks quiet", async () => {
147+
it("shows a follow-up for already-resolved approval clicks", async () => {
148148
const interaction = createInteraction();
149149
const button = new ExecApprovalButton({
150150
getApprovers: () => ["123"],
@@ -154,7 +154,11 @@ describe("discord exec approval monitor helpers", () => {
154154
await button.run(interaction, { id: "abc", action: "allow-once" });
155155

156156
expect(interaction.acknowledge).toHaveBeenCalled();
157-
expect(interaction.followUp).not.toHaveBeenCalled();
157+
expect(interaction.followUp).toHaveBeenCalledWith({
158+
content:
159+
"That approval request is no longer pending. It may have expired or already been resolved.",
160+
ephemeral: true,
161+
});
158162
});
159163

160164
it("builds button context from config and routes resolution over gateway", async () => {

extensions/discord/src/monitor/exec-approvals.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,10 +112,13 @@ export class ExecApprovalButton extends Button {
112112
} catch {}
113113

114114
const result = await this.ctx.resolveApproval(parsed.approvalId, parsed.action);
115-
if (!result.ok && result.reason !== "not-found") {
115+
if (!result.ok) {
116116
try {
117117
await interaction.followUp({
118-
content: `Failed to submit approval decision for **${decisionLabel}**. The request may have expired or already been resolved.`,
118+
content:
119+
result.reason === "not-found"
120+
? `That approval request is no longer pending. It may have expired or already been resolved.`
121+
: `Failed to submit approval decision for **${decisionLabel}**. The request may have expired or already been resolved.`,
119122
ephemeral: true,
120123
});
121124
} catch {}

src/gateway/operator-approvals-client.test.ts

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ describe("withOperatorApprovalsGatewayClient", () => {
117117
expect(clientState.options?.deviceIdentity).toBeUndefined();
118118
});
119119

120-
it("omits approval runtime token for explicit gateway URL overrides", async () => {
120+
it("keeps approval runtime token for loopback explicit gateway URL overrides", async () => {
121121
await withOperatorApprovalsGatewayClient(
122122
{
123123
config: {} as never,
@@ -127,6 +127,21 @@ describe("withOperatorApprovalsGatewayClient", () => {
127127
async () => undefined,
128128
);
129129

130+
expect(typeof clientState.options?.approvalRuntimeToken).toBe("string");
131+
});
132+
133+
it("omits approval runtime token for remote explicit gateway URL overrides", async () => {
134+
bootstrapState.url = "wss://gateway.example/ws";
135+
136+
await withOperatorApprovalsGatewayClient(
137+
{
138+
config: {} as never,
139+
gatewayUrl: "wss://gateway.example/ws",
140+
clientDisplayName: "Matrix approval (@owner:example.org)",
141+
},
142+
async () => undefined,
143+
);
144+
130145
expect(clientState.options).not.toHaveProperty("approvalRuntimeToken");
131146
});
132147

src/gateway/operator-approvals-client.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,15 @@ export async function createOperatorApprovalsGatewayClient(
4444
gatewayUrl: params.gatewayUrl,
4545
env: process.env,
4646
});
47+
const shouldSendApprovalRuntimeToken = !params.gatewayUrl || isLoopbackGatewayUrl(bootstrap.url);
4748

4849
return new GatewayClient({
4950
url: bootstrap.url,
5051
token: bootstrap.auth.token,
5152
password: bootstrap.auth.password,
52-
...(params.gatewayUrl ? {} : { approvalRuntimeToken: getOperatorApprovalRuntimeToken() }),
53+
...(shouldSendApprovalRuntimeToken
54+
? { approvalRuntimeToken: getOperatorApprovalRuntimeToken() }
55+
: {}),
5356
preauthHandshakeTimeoutMs: bootstrap.preauthHandshakeTimeoutMs,
5457
clientName: GATEWAY_CLIENT_NAMES.GATEWAY_CLIENT,
5558
clientDisplayName: params.clientDisplayName,

0 commit comments

Comments
 (0)