fix: reject invalid keyed mutation intents

This commit is contained in:
DongHyeonka
2026-08-02 01:21:50 +09:00
parent cbcc7b5ed7
commit fa2f699125
3 changed files with 272 additions and 8 deletions
@@ -1,10 +1,12 @@
import { describe, expect, it, vi } from "vitest";
import { createHttpClient } from "../../src/adapters/http/client.ts";
import { createContractHttpExecutor } from "../../src/adapters/http/http-execution-v3.ts";
import {
entityQueryKeys,
TEST_HTTP_CONTRACT,
} from "../helpers/http-contract-fixture.ts";
import { TEST_CREATE_HTTP_CONTRACT } from "../helpers/external-contract-fixture.ts";
function successResponse(data: unknown) {
return Response.json({
@@ -48,6 +50,79 @@ function testClient(options: HttpDependencies) {
}
describe("HTTP operation execution contract", () => {
it("permits a keyless command intent but rejects an unexpected key before dispatch", async () => {
const attachCredentials = vi.fn(() => ({
kind: "READY" as const,
headers: {},
credentials: "omit" as const,
}));
const observedKeys: Array<string | null> = [];
const fetcher = vi.fn(
async (_input: RequestInfo | URL, init?: RequestInit) => {
observedKeys.push(new Headers(init?.headers).get("Idempotency-Key"));
return Response.json(
{ id: "created", name: "Created" },
{ status: 201 },
);
},
);
const executor = createContractHttpExecutor({
baseUrl: "https://api.example/",
maxRetryAttempts: 0,
attachCredentials,
fetcher,
});
const nonKeyedCommand = {
...TEST_CREATE_HTTP_CONTRACT,
contract: {
...TEST_CREATE_HTTP_CONTRACT.contract,
retrySemantics: "NEVER" as const,
commandRecovery: null,
},
};
const scope = Object.freeze({
generation: 1,
fingerprint: "scope-1",
identities: Object.freeze({}) as never,
signal: new AbortController().signal,
isCurrent: () => true,
});
const intent = Object.freeze({
intentId: "intent-1",
operationId: "TEST_CREATE_ENTITY",
canonicalInputIdentity: "opaque-input-identity",
createdAtMonotonicMs: 1,
});
await expect(
executor.execute(
nonKeyedCommand,
{ name: "created" },
{ scope, intent },
),
).resolves.toMatchObject({ kind: "SUCCESS" });
expect(observedKeys).toEqual([null]);
attachCredentials.mockClear();
fetcher.mockClear();
await expect(
executor.execute(
nonKeyedCommand,
{ name: "created" },
{ scope, intent: { ...intent, idempotencyKey: "unexpected-key" } },
),
).resolves.toMatchObject({
kind: "CONTRACT_VIOLATION",
violation: {
kind: "UNEXPECTED_IDEMPOTENCY_KEY",
operation: "REQUEST",
},
effect: "NOT_STARTED",
});
expect(attachCredentials).not.toHaveBeenCalled();
expect(fetcher).not.toHaveBeenCalled();
});
it("fails auth-required execution before fetch when the session integration is unavailable", async () => {
const fetcher = vi.fn();
const client = testClient({