Files
tech-log-frontend/tests/unit/contract-registry-immutability.test.ts
DongHyeonkaandClaude Opus 5 4bff9ca151 chore: sync the frontend template from 4dc033c to 8157ad4
The product was materialized from the template at `4dc033c` and has stayed
on it through 43 template commits, so it was missing all three rounds of
adapter remediation — including files it never had, such as the shared
`abortable-operation` primitive and the `exact-snapshot` decoder that
later fixes are written against. Taking only the newest round was not
possible for that reason: the delta is coherent only as a whole.

The product had not touched `src/adapters` at all since materialization,
so the 140-file delta applied with a three-way merge and no conflicts.
`package.json` was the single overlap and merged cleanly: the product owns
`name`, the template contributed `check:adapter-inventory`,
`check:remediation-ledger` and the image-resolve-signal type fixture.
All 24 product-owned files — README, index.html, CI workflow, i18n
catalog, home page, generated schemas, evidence scripts, component and
visual snapshots — are byte-identical to `main`.

`template.lock.json` now pins the synced revision and tree.

Verified in this repository, not inherited from the template: six type
projects, lint, nine gates (adapter inventory, remediation ledger,
registries, diagnostics, realtime boundaries, architecture, browser
file/storage boundaries, optional recipes, documentation), the production
build, and 2,054 of 2,073 tests. The 19 failures are all in
`tests/unit/ci-artifact-contract.test.ts` and are the same pre-existing
sandbox RLIMIT, EMFILE, umask and `/tmp` permission behaviour the template
records; four suites that failed once under parallel load pass in
isolation.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-15 12:04:58 +09:00

338 lines
11 KiB
TypeScript

import { describe, expect, it } from "vitest";
import {
composeContractContributions,
type ComposedContractContributions,
} from "../../src/contracts/external-contract-runtime.ts";
import {
installRestAuthProfileRegistry,
INSTALLED_REST_AUTH_PROFILES,
REST_AUTH_PROFILES,
} from "../../src/contracts/rest-profiles.ts";
import { TEST_CONTRACT_CONTRIBUTION } from "../helpers/external-contract-fixture.ts";
/**
* LIVE-02 / LIVE-03. `Object.freeze(new Map(...))` freezes the wrapper object,
* not the backing store: `set`, `delete` and `clear` keep working. Every
* registry the executor consults after composition must therefore be a read
* facade over a private store, and the rows it hands back must be exact
* own-data snapshots that a later mutation of the source cannot reach.
*/
const MUTATORS = ["set", "delete", "clear"] as const;
function borrowedMapMutation(
facade: unknown,
mutator: (typeof MUTATORS)[number],
): "THREW" | "MUTATED" {
try {
switch (mutator) {
case "set":
Map.prototype.set.call(facade as never, "INJECTED", {} as never);
break;
case "delete":
Map.prototype.delete.call(facade as never, "ANONYMOUS");
break;
case "clear":
Map.prototype.clear.call(facade as never);
break;
}
return "MUTATED";
} catch {
return "THREW";
}
}
describe("LIVE-02 installed REST auth profile registry", () => {
it("exposes no mutation API", () => {
const registry = INSTALLED_REST_AUTH_PROFILES as unknown as Record<
string,
unknown
>;
for (const mutator of MUTATORS) {
expect(registry[mutator]).toBeUndefined();
}
});
it("survives a cast mutation and a borrowed Map.prototype mutator", () => {
const registry = installRestAuthProfileRegistry(REST_AUTH_PROFILES);
const before = registry.size;
const identity = registry.get("ANONYMOUS");
expect(identity).toBeDefined();
for (const mutator of MUTATORS) {
expect(borrowedMapMutation(registry, mutator)).toBe("THREW");
}
expect(registry.size).toBe(before);
expect(registry.get("ANONYMOUS")).toBe(identity);
expect(registry.get("REFERENCE_EXTERNAL_BEARER")?.credentials).toBe("omit");
});
it("does not observe a post-installation mutation of the source record", () => {
const source: Record<string, (typeof REST_AUTH_PROFILES)["ANONYMOUS"]> = {
ANONYMOUS: {
authProfileId: "ANONYMOUS",
transport: "ANONYMOUS",
credentials: "omit",
allowedCredentialHeaders: [],
requiredCredentialHeaders: [],
},
};
const registry = installRestAuthProfileRegistry(source);
delete source.ANONYMOUS;
expect(registry.get("ANONYMOUS")?.transport).toBe("ANONYMOUS");
});
it("keeps read APIs the executor depends on", () => {
const registry = INSTALLED_REST_AUTH_PROFILES;
expect(registry.has("ANONYMOUS")).toBe(true);
expect(registry.has("NO_SUCH_PROFILE")).toBe(false);
expect([...registry.keys()].sort()).toEqual([
"ANONYMOUS",
"REFERENCE_EXTERNAL_BEARER",
]);
expect([...registry.entries()].length).toBe(registry.size);
expect([...registry.values()].length).toBe(registry.size);
});
});
describe("LIVE-03 composed contract registry", () => {
function compose(): ComposedContractContributions {
return composeContractContributions([TEST_CONTRACT_CONTRIBUTION] as never);
}
it("exposes no mutation API on either lookup", () => {
const composed = compose();
for (const facade of [composed.httpByOperationId, composed.eventByType]) {
const record = facade as unknown as Record<string, unknown>;
for (const mutator of MUTATORS) {
expect(record[mutator]).toBeUndefined();
}
for (const mutator of MUTATORS) {
expect(borrowedMapMutation(facade, mutator)).toBe("THREW");
}
}
expect(composed.httpByOperationId.size).toBeGreaterThan(0);
});
it("snapshots the frontend policy so a later source mutation cannot reach it", () => {
const mutablePolicy = {
...TEST_CONTRACT_CONTRIBUTION.http[0]!.frontend,
};
const contribution = {
...TEST_CONTRACT_CONTRIBUTION,
http: [
{
...TEST_CONTRACT_CONTRIBUTION.http[0]!,
frontend: mutablePolicy,
},
],
};
const composed = composeContractContributions([contribution] as never);
const operationId = [...composed.httpByOperationId.keys()][0]!;
const installedBefore =
composed.httpByOperationId.get(operationId)!.frontend.totalDeadlineMs;
mutablePolicy.totalDeadlineMs = 999_999;
expect(
composed.httpByOperationId.get(operationId)!.frontend.totalDeadlineMs,
).toBe(installedBefore);
expect(installedBefore).not.toBe(999_999);
});
it("rejects an accessor or inherited policy field", () => {
const inherited = Object.create({ diagnosticsOperation: "INHERITED" }) as
Record<string, unknown>;
for (const [key, value] of Object.entries(
TEST_CONTRACT_CONTRIBUTION.http[0]!.frontend,
)) {
if (key === "diagnosticsOperation") continue;
inherited[key] = value;
}
const accessor = { ...TEST_CONTRACT_CONTRIBUTION.http[0]!.frontend };
Object.defineProperty(accessor, "totalDeadlineMs", {
configurable: true,
enumerable: true,
get: () => 10_000,
});
for (const frontend of [inherited, accessor]) {
expect(() =>
composeContractContributions([
{
...TEST_CONTRACT_CONTRIBUTION,
http: [{ ...TEST_CONTRACT_CONTRIBUTION.http[0]!, frontend }],
},
] as never),
).toThrow();
}
});
/**
* NS-02. Composition validated the caller's object and then read it again to
* copy it. Between those two reads a stateful answer could swap a deadline or
* a retry budget, so the value that passed the ceiling check and the value the
* executor ran with were two different things.
*/
describe("validate the snapshot, never the source", () => {
/** Answers a safe value to a plain read and a hostile one to a copy. */
const statefulFrontend = () =>
new Proxy(
{ ...TEST_CONTRACT_CONTRIBUTION.http[0]!.frontend },
{
get(target, key, receiver) {
if (key === "totalDeadlineMs") return 10_000;
return Reflect.get(target, key, receiver);
},
getOwnPropertyDescriptor(target, key) {
if (key === "totalDeadlineMs") {
return {
configurable: true,
enumerable: true,
value: 999_999,
};
}
return Reflect.getOwnPropertyDescriptor(target, key);
},
},
);
const contributionWith = (row: unknown) => [
{ ...TEST_CONTRACT_CONTRIBUTION, http: [row] },
];
it("validates the deadline it will install, not the one it was shown", () => {
// The copied value exceeds the hard ceiling, so composition must stop
// rather than install a deadline no check ever saw.
expect(() =>
composeContractContributions(
contributionWith({
...TEST_CONTRACT_CONTRIBUTION.http[0]!,
frontend: statefulFrontend(),
}) as never,
),
).toThrow();
});
it("keys the registry by the operation id it copied, not the one it was shown", () => {
const base = { ...TEST_CONTRACT_CONTRIBUTION.http[0]!.contract };
const contract = new Proxy(base, {
get(target, key, receiver) {
if (key === "operationId") return base.operationId;
return Reflect.get(target, key, receiver);
},
getOwnPropertyDescriptor(target, key) {
if (key === "operationId") {
return {
configurable: true,
enumerable: true,
value: "SwappedOperation",
};
}
return Reflect.getOwnPropertyDescriptor(target, key);
},
});
const composed = composeContractContributions(
contributionWith({
...TEST_CONTRACT_CONTRIBUTION.http[0]!,
contract,
}) as never,
);
expect([...composed.httpByOperationId.keys()]).toEqual([
"SwappedOperation",
]);
expect(
composed.httpByOperationId.get("SwappedOperation")!.contract
.operationId,
).toBe("SwappedOperation");
});
const hostileRows = [
{
label: "an installed row with an extra own field",
row: () => ({
...TEST_CONTRACT_CONTRIBUTION.http[0]!,
injected: true,
}),
},
{
label: "an installed row with a symbol field",
row: () => ({
...TEST_CONTRACT_CONTRIBUTION.http[0]!,
[Symbol.for("injected")]: true,
}),
},
{
label: "an installed row with a custom prototype",
row: () =>
Object.assign(Object.create({ injected: true }), {
...TEST_CONTRACT_CONTRIBUTION.http[0]!,
}),
},
{
label: "an installed row hiding a non-enumerable own field",
row: () =>
Object.defineProperty(
{ ...TEST_CONTRACT_CONTRIBUTION.http[0]! },
"injected",
{ enumerable: false, value: true },
),
},
{
label: "an installed row behind a throwing ownKeys trap",
row: () =>
new Proxy(
{ ...TEST_CONTRACT_CONTRIBUTION.http[0]! },
{
ownKeys() {
throw new TypeError("hostile ownKeys trap");
},
},
),
},
];
for (const { label, row } of hostileRows) {
it(`refuses to compose ${label}`, () => {
expect(() =>
composeContractContributions(contributionWith(row()) as never),
).toThrow();
});
}
it("refuses a contribution whose own shape is not exact", () => {
for (const contribution of [
{ ...TEST_CONTRACT_CONTRIBUTION, injected: true },
Object.assign(Object.create({ injected: true }), {
...TEST_CONTRACT_CONTRIBUTION,
}),
{
...TEST_CONTRACT_CONTRIBUTION,
[Symbol.for("injected")]: true,
},
]) {
expect(() =>
composeContractContributions([contribution] as never),
).toThrow();
}
});
it("refuses an event contract whose own shape is not exact", () => {
const events = TEST_CONTRACT_CONTRIBUTION.events;
if (events.length === 0) return;
for (const event of [
{ ...events[0]!, injected: true },
Object.assign(Object.create({ injected: true }), { ...events[0]! }),
]) {
expect(() =>
composeContractContributions([
{ ...TEST_CONTRACT_CONTRIBUTION, events: [event] },
] as never),
).toThrow();
}
});
});
});