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>
338 lines
11 KiB
TypeScript
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();
|
|
}
|
|
});
|
|
});
|
|
});
|