Backend handoff failure names the status, never the app's answer

Same class as Soul pass 4's F1: deliverBackendHandoff put the receiving
app's whole response body into its error message. The handoff carries
tokens and an app's error page can quote it, and the message reaches
whatever catches the error. It now names the status alone and discards the
body unread.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Meta Vens 2026-09-30 17:07:45 +02:00
commit b5b980578c
2 changed files with 30 additions and 4 deletions

View file

@ -1,6 +1,7 @@
import { afterEach, describe, expect, it } from "vitest";
import { type FastifyInstance } from "fastify";
import { buildApp } from "../src/app.js";
import { deliverBackendHandoff, type BackendHandoffPayload } from "../src/backend-handoff.js";
import { type HeimdallConfig, loadConfig } from "../src/config.js";
import { entitlementFacts, identityFacts } from "../src/facts.js";
import { createOAuthRuntimeRegistry, type OAuthProviderRuntime } from "../src/oauth.js";
@ -1588,3 +1589,28 @@ describe("the failed-callback audit event for a provider's HTTP refusal", () =>
expect(failed?.eventPayloadJson.providerStatus).toBeNull();
});
});
describe("a backend handoff the app refuses", () => {
it("fails by status alone, never with the app's answer body", async () => {
globalThis.fetch = async () => new Response('{"error":"rejected","echo":"CANARYhandoff"}', { status: 500 });
const failure = await deliverBackendHandoff("https://bifrost.gamecult.org/auth/heimdall/callback", {
source: "heimdall",
kind: "oauth_result",
handoffKind: "backend_callback",
attemptId: "attempt-1",
status: "error",
provider: "discord",
appSlug: "bifrost",
returnTo: "https://bifrost.gamecult.org/",
connection: null,
error: "oauth_callback_failed",
} as BackendHandoffPayload).then(
() => undefined,
(error: unknown) => error
);
expect(failure).toBeInstanceOf(Error);
expect((failure as Error).message).toBe("Backend handoff delivery failed (status 500).");
expect(JSON.stringify(failure) + String(failure)).not.toContain("CANARY");
});
});