From a021b02310140228c14fdb5a287f008db66bb8cb Mon Sep 17 00:00:00 2001 From: Heimdall Date: Mon, 9 Nov 2026 12:03:14 +0000 Subject: [PATCH 1/2] Test first: redeem refuses a target the completion never recorded Co-Authored-By: Claude Sonnet 5.5 --- tests/link-binding.test.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/link-binding.test.ts b/tests/link-binding.test.ts index e58b320..7982229 100644 --- a/tests/link-binding.test.ts +++ b/tests/link-binding.test.ts @@ -218,6 +218,16 @@ describe("redeem binds caller, target and replay", () => { expect((await redeem(r, { completionCode, targetId: "target-a" }, appAuth)).statusCode).toBe(201); }); + it("refuses a target named against a completion that recorded none, without consuming the code", async () => { + const r = await rig("d-r2b"); + const completionCode = await linked(r, undefined); + const refused = await redeem(r, { completionCode, targetId: "target-a" }, appAuth); + expect([refused.statusCode, refused.json().error]).toEqual([403, "completion_target_mismatch"]); + expect(refused.json().accessToken).toBeUndefined(); + expect((await r.store.findAuthCompletion("repixelizer", completionCode))?.consumedAt).toBeUndefined(); + expect((await redeem(r, { completionCode }, appAuth)).statusCode).toBe(201); + }); + it("refuses a replayed completion", async () => { const r = await rig("d-r3"); const completionCode = await linked(r, "target-a"); -- 2.47.3 From 36b02ea135a0531a858a7f4a35f2cad5d3c4b666 Mon Sep 17 00:00:00 2001 From: Heimdall Date: Mon, 9 Nov 2026 12:03:14 +0000 Subject: [PATCH 2/2] Redeem refuses a target the completion did not record, symmetric with the missing one Co-Authored-By: Claude Sonnet 5.5 --- src/app.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app.ts b/src/app.ts index 2051499..59086f0 100644 --- a/src/app.ts +++ b/src/app.ts @@ -2220,7 +2220,7 @@ export async function buildApp(options: BuildAppOptions = {}): Promise nowIso) { @@ -2228,7 +2228,7 @@ export async function buildApp(options: BuildAppOptions = {}): Promise