import { expect } from "@std/expect"; import { describe, it } from "@std/testing/bdd"; import { CFC_ATOM_TYPE, type CfcAtom, cfcAtom } from "@commonfabric/api/cfc"; import type { FabricValue } from "@commonfabric/data-model"; import { linkProbeSubPath } from "@commonfabric/data-model/cell-rep"; import { Identity } from "@commonfabric/identity"; import { maxOf } from "@commonfabric/utils/math"; import { SEED_ENVELOPE_SCHEMA_HASH, seedStoredEnvelope, writeSeedEnvelopeDoc, } from "./cfc-seed-envelope.ts"; import type { JSONSchema } from "../src/builder/types.ts"; import type { AtomPattern } from "../src/cfc/atom-pattern.ts"; import type { ImplementationIdentity, LabelMapEntry, } from "../src/cfc/types.ts"; import type { CfcPolicyRecordInput } from "../src/cfc/policy.ts"; import { runtimeWritePolicyAuthorization } from "../src/cfc/types.ts"; import { INPUT_WITNESS_MAX_DEPTH, inputWitnessDepth, mintTransformedBy, retainedInputWitnesses, } from "../src/cfc/input-witness.ts"; import { readStoredCfcMetadata } from "../src/cfc/metadata.ts"; import { createSigilLinkFromParsedLink } from "../src/link-utils.ts"; import { Runtime } from "../src/runtime.ts"; import { StorageManager } from "../src/storage/cache.deno.ts"; import type { IExtendedStorageTransaction } from "../src/storage/interface.ts"; import { setCfcImplementationIdentity } from "../src/storage/extended-storage-transaction.ts"; import { linkResolutionProbe } from "../src/storage/reactivity-log.ts"; // An endorsed transformer's output is released by an exchange rule guarded on // the `TransformedBy` atom the runtime mints for it. Naming only the code that // wrote the output lets any caller of that code choose what it computes over: // an unendorsed derivation reshapes a secret into input the endorsed code // accepts, the endorsed code writes, and the rule releases the result. These // cases pin the witness-bearing form, `TransformedBy{identity, inputWitness}`, // which additionally states what wrote every confidential input the // transformation consumed, and the laundering shapes it has to refuse. const signer = await Identity.fromPassphrase("runner-cfc-input-witness"); const space = signer.did(); // The room clause names the room's own space: its members are the audience a // document living there already reaches, so the writer-fit gate admits the // room's own writes and only the ceiling below stands in the way. const ROOM = cfcAtom.space(space); const verified = ( moduleIdentity: string, symbol: string, ): ImplementationIdentity => ({ kind: "verified", moduleIdentity, symbol, bindingPath: [symbol], }); const COMMIT = verified("module:conclave", "commitStances"); const TALLY = verified("module:conclave", "tallyBallot"); const ATTACKER = verified("module:attacker", "bitOfNote"); const OTHER = verified("module:attacker", "helper"); const transformedBy = (identity: ImplementationIdentity) => ({ type: CFC_ATOM_TYPE.TransformedBy, identity: { kind: "verified", moduleIdentity: (identity as { moduleIdentity: string }).moduleIdentity, symbol: (identity as { symbol: string }).symbol, }, }); // The guard existing rules are written with: which code wrote the value. const IDENTITY_GUARD: AtomPattern = transformedBy(TALLY); // The witnessed guard: the tally wrote it, and everything confidential the // tally read was written by the commit step. const WITNESSED_GUARD: AtomPattern = { ...transformedBy(TALLY), inputWitness: transformedBy(COMMIT), }; const releaseRule = (guard: AtomPattern): CfcPolicyRecordInput[] => [{ id: "conclave-release", rules: [{ id: "release-ballot", appliesTo: ROOM, preCondition: { integrity: [guard] }, post: { dropClause: true }, }], }]; // The room-visible store: it may hold only public values, so a write into it // consumes the maxConfidentiality gate, where the rule gets its chance. const ROOM_STORE_SCHEMA = { type: "object", ifc: { confidentiality: [ROOM] }, properties: { out: { type: "string", ifc: { maxConfidentiality: [] } }, }, required: ["out"], } as const satisfies JSONSchema; const SELECTION_SCHEMA = { type: "array", items: { type: "object", properties: { votes: { type: "array", items: { type: "string" } } }, }, } as const satisfies JSONSchema; type Harness = { runtime: Runtime; storageManager: ReturnType; }; const withRuntime = async ( guard: AtomPattern, body: (harness: Harness) => Promise, ): Promise => { const storageManager = StorageManager.emulate({ as: signer }); const runtime = new Runtime({ apiUrl: new URL("https://example.com"), storageManager, cfcFlowLabels: "persist", cfcPolicyRecords: releaseRule(guard), cfcPolicyEvaluation: "enforce", }); try { await body({ runtime, storageManager }); } finally { await runtime.dispose(); await storageManager.close(); } }; /** A document seeded with exactly `entries` as its label map. */ const seedLabeled = async ( runtime: Runtime, cause: string, value: FabricValue, entries: readonly LabelMapEntry[], ): Promise => { const seed = runtime.edit(); const id = runtime.getCell(space, cause, undefined, seed) .getAsNormalizedFullLink().id; writeSeedEnvelopeDoc(seed, space); seedStoredEnvelope(seed, { space, scope: "space", id, path: [] }, { value, cfc: { version: 1, schemaHash: SEED_ENVELOPE_SCHEMA_HASH, labelMap: { version: 1, entries: [...entries] }, }, }); expect((await seed.commit().settled).ok).toBeDefined(); }; /** A room-confidential document holding one member's sealed note. */ const seedSecret = ( runtime: Runtime, cause: string, note: string, ): Promise => seedLabeled(runtime, cause, { note }, [ { path: [], label: { confidentiality: [ROOM] } }, ]); /** A public document: no label at all. */ const seedPublic = async ( runtime: Runtime, cause: string, value: FabricValue, ): Promise => { const tx = runtime.edit(); const id = runtime.getCell(space, cause, undefined, tx) .getAsNormalizedFullLink().id; tx.writeOrThrow({ space, scope: "space", id, path: ["value"] }, value); expect((await tx.commit().settled).ok).toBeDefined(); }; /** * One transformation: a transaction under `identity` that reads every input, * lets `observe` consume anything else, and writes what `compute` makes of the * inputs at `path` of the output. The write is raw so the output's own prior * value is not journaled as an input. */ const transform = async ( runtime: Runtime, identity: ImplementationIdentity | readonly ImplementationIdentity[], inputs: readonly string[], output: string, compute: (values: unknown[]) => FabricValue, path: readonly string[] = [], observe?: (tx: IExtendedStorageTransaction) => void | Promise, ): Promise => { const identities = Array.isArray(identity) ? identity : [identity]; const tx = runtime.edit(); setCfcImplementationIdentity(tx, identities[0]); const values = inputs.map((cause) => runtime.getCell(space, cause, undefined, tx).getRaw() ); await observe?.(tx); const id = runtime.getCell(space, output, undefined, tx) .getAsNormalizedFullLink().id; tx.writeOrThrow( { space, scope: "space", id, path: ["value", ...path] }, compute(values), ); // A second identity writing in the same transaction leaves the whole // transaction unattributed (`CfcTxState.writeIdentity`). for (const other of identities.slice(1)) { setCfcImplementationIdentity(tx, other); const scratch = runtime.getCell(space, `${output}-scratch`, undefined, tx) .getAsNormalizedFullLink().id; tx.writeOrThrow({ space, scope: "space", id: scratch, path: ["value"] }, 1); } tx.prepareCfc(); const result = await tx.commit().settled; expect(result.error).toBeUndefined(); }; /** * Copies `input` into the room-visible store and reports why prepare refused * the write, if it did. */ const publish = (runtime: Runtime, input: string): readonly string[] => { const tx = runtime.edit(); const value = runtime.getCell(space, input, undefined, tx).getRaw(); runtime.getCell(space, `${input}-room-store`, ROOM_STORE_SCHEMA, tx) .set({ out: String(value) }); tx.prepareCfc(); const state = tx.getCfcState(); const reasons = state.prepare.status === "invalidated" ? [...state.prepare.reasons] : []; tx.abort(); return reasons; }; const refusedByCeiling = (reasons: readonly string[]): boolean => reasons.some((reason) => reason.includes("maxConfidentiality failed")); const storedIntegrity = (runtime: Runtime, cause: string): unknown[] => { const tx = runtime.edit(); const cell = runtime.getCell(space, cause, undefined, tx); const metadata = readStoredCfcMetadata(tx, cell.getAsNormalizedFullLink()); tx.abort(); return (metadata?.labelMap.entries ?? []).flatMap((entry) => entry.label.integrity ?? [] ); }; const tally = (values: unknown[]): string => { let approve = 0; for (const value of values) { for (const vote of (value as { votes?: string[] }).votes ?? []) { if (vote === "approve") approve++; } } return `${approve}`; }; /** The honest path: the commit step seals the room's stances into one doc. */ const commitStances = (runtime: Runtime, output = "committed") => transform(runtime, COMMIT, ["alice-note", "bob-note"], output, () => ({ votes: ["approve", "reject"], })); /** * `writer` writing the room's stances as a list into the existing document * `cause`, the way the diff writes a list where a value of another kind * stood: the list empty, then each member at its slot. */ const commitListInPlace = async ( runtime: Runtime, members: readonly string[], writer: ImplementationIdentity = COMMIT, cause = "committed", ): Promise => { const tx = runtime.edit(); setCfcImplementationIdentity(tx, writer); for (const note of ["alice-note", "bob-note"]) { runtime.getCell(space, note, undefined, tx).getRaw(); } const id = runtime.getCell(space, cause, undefined, tx) .getAsNormalizedFullLink().id; tx.writeOrThrow({ space, scope: "space", id, path: ["value"] }, []); members.forEach((member, index) => tx.writeOrThrow( { space, scope: "space", id, path: ["value", String(index)] }, member, ) ); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); }; /** A list of stances, read through its schema. */ const STANCES = { type: "array", items: { type: "string" }, } as const satisfies JSONSchema; /** The laundering step: bit 0 of Alice's note as a one-vote ballot. */ const bitOfAlicesNote = (runtime: Runtime, output = "crafted") => transform(runtime, ATTACKER, ["alice-note"], output, ([alice]) => ({ votes: [ ((alice as { note: string }).note.charCodeAt(0) & 1) ? "approve" : "reject", ], })); const seedRoom = async (runtime: Runtime): Promise => { await seedSecret(runtime, "alice-note", "alice-secret"); await seedSecret(runtime, "bob-note", "bob-secret"); }; describe("TransformedBy input witnesses", () => { describe("minting", () => { it("names what wrote every confidential input beside the transformer", async () => { await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await transform(runtime, TALLY, ["committed"], "ballot", tally); const integrity = storedIntegrity(runtime, "ballot"); expect(integrity).toContainEqual({ type: CFC_ATOM_TYPE.TransformedBy, identity: TALLY, }); expect(integrity).toContainEqual({ type: CFC_ATOM_TYPE.TransformedBy, identity: TALLY, inputWitness: { type: CFC_ATOM_TYPE.TransformedBy, identity: COMMIT }, }); }); }); it("names the writer of a list whose link probe triggered the run", async () => { // A run scheduled by a change to a link probe's path reads the slot // the probe asked about, not the sub-path a link exposes its form at, // whose segments no `*` template matches. The list is read through // its schema, one shallow read per node, as compiled code reads it. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await seedPublic(runtime, "committed", "pending"); await commitListInPlace(runtime, ["approve", "reject"]); await transform( runtime, TALLY, [], "ballot", () => "1", [], (tx) => { const list = runtime.getCell(space, "committed", STANCES, tx); list.get(); tx.addCfcTriggerReads([{ space, id: list.getAsNormalizedFullLink().id, type: "application/json", path: ["value", ...linkProbeSubPath()], }]); }, ); expect(storedIntegrity(runtime, "ballot")).toContainEqual({ type: CFC_ATOM_TYPE.TransformedBy, identity: TALLY, inputWitness: { type: CFC_ATOM_TYPE.TransformedBy, identity: COMMIT }, }); }); }); it("mints no witness when a list other code wrote triggered the run", async () => { // The slot a link probe asked about is still an input when the trigger // is read there: its membership stamp names the writer that filled it. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await seedPublic(runtime, "crafted-list", "pending"); await commitListInPlace( runtime, ["approve", "reject"], ATTACKER, "crafted-list", ); await transform( runtime, TALLY, ["committed"], "ballot", tally, [], (tx) => { const id = runtime.getCell(space, "crafted-list", undefined, tx) .getAsNormalizedFullLink().id; tx.addCfcTriggerReads([{ space, id, type: "application/json", path: ["value", ...linkProbeSubPath()], }]); }, ); const integrity = storedIntegrity(runtime, "ballot"); expect(integrity).toContainEqual({ type: CFC_ATOM_TYPE.TransformedBy, identity: TALLY, }); expect( integrity.some((atom) => (atom as { inputWitness?: unknown }).inputWitness !== undefined ), ).toBe(false); }); }); it("mints no witness when a confidential input was written by other code", async () => { await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await bitOfAlicesNote(runtime); await transform( runtime, TALLY, ["committed", "crafted"], "ballot", tally, ); const integrity = storedIntegrity(runtime, "ballot"); expect(integrity).toContainEqual({ type: CFC_ATOM_TYPE.TransformedBy, identity: TALLY, }); expect( integrity.some((atom) => (atom as { inputWitness?: unknown }).inputWitness !== undefined ), ).toBe(false); }); }); }); describe("an identity-only guard", () => { // What a rule guarded on the writer alone admits. The first case is the // endorsed path; the second is the laundering this primitive exists for, // pinned so a rule author can see why the identity alone is not enough. // Both stay admitted: the witness is additive, and existing guards keep // matching the identity-only atom. it("releases the endorsed transformer's output", async () => { await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("also releases a secret laundered through the endorsed transformer", async () => { await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime); await transform(runtime, TALLY, ["crafted"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); }); describe("a witnessed guard", () => { it("releases the endorsed transformer's output over committed inputs", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("releases when the transformer also reads public inputs", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await seedPublic(runtime, "ballot-options", { options: ["a", "b"] }); await commitStances(runtime); await transform( runtime, TALLY, ["committed", "ballot-options"], "ballot", tally, ); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("refuses a secret laundered through the endorsed transformer", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime); await transform(runtime, TALLY, ["crafted"], "ballot", tally); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); it("refuses when a crafted input is mixed in with committed ones", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await bitOfAlicesNote(runtime); await transform( runtime, TALLY, ["committed", "crafted"], "ballot", tally, ); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); it("refuses when a transformer read a secret directly", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await transform( runtime, TALLY, ["committed", "alice-note"], "ballot", tally, ); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); it("refuses a crafted value written beside a committed one in the same input", async () => { // The input document holds a committed value at one path and a crafted // one at another. Integrity on the committed path says nothing about // the crafted one, so the input as read carries no witness. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await transform( runtime, COMMIT, ["alice-note", "bob-note"], "shared", () => ["approve", "reject"], ["committed"], ); await transform( runtime, ATTACKER, ["alice-note"], "shared", ([alice]) => [(alice as { note: string }).note.slice(0, 1)], ["votes"], ); await transform(runtime, TALLY, ["shared"], "ballot", tally); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); it("refuses a secret-chosen selection of committed documents", async () => { // Every document the tally reads was written by the commit step, but // which of them it reads was chosen from Alice's note: the list of // references is the attacker's write, and reading through it observes // that choice. A reference slot's label carries the link's provenance // and no `TransformedBy`, so a list of references is refused whoever // wrote it; this pins that the choice is not skipped as plumbing. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime, "committed-a"); await transform( runtime, COMMIT, ["alice-note", "bob-note"], "committed-b", () => ({ votes: ["reject"] }), ); const tx = runtime.edit(); setCfcImplementationIdentity(tx, ATTACKER); const alice = runtime.getCell(space, "alice-note", undefined, tx) .getRaw() as { note: string }; const chosen = runtime.getCell( space, alice.note.charCodeAt(0) & 1 ? "committed-a" : "committed-b", undefined, tx, ); runtime.getCell(space, "selection", SELECTION_SCHEMA, tx).set([ chosen, ] as never); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); const tallyTx = runtime.edit(); setCfcImplementationIdentity(tallyTx, TALLY); const selected = runtime.getCell( space, "selection", SELECTION_SCHEMA, tallyTx, ).get() as unknown[]; const ballotId = runtime.getCell(space, "ballot", undefined, tallyTx) .getAsNormalizedFullLink().id; tallyTx.writeOrThrow( { space, scope: "space", id: ballotId, path: ["value"] }, tally(selected), ); tallyTx.prepareCfc(); expect((await tallyTx.commit().settled).error).toBeUndefined(); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); it("refuses a secret-chosen selection of public documents", async () => { // The documents the selection names carry no label, so nothing the // tally reads in them is confidential: the choice reaches it through // the reference alone, which the attacker wrote. The committed input // read beside it must not lend the output its witness. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await seedPublic(runtime, "public-a", { votes: ["approve"] }); await seedPublic(runtime, "public-b", { votes: ["reject"] }); const tx = runtime.edit(); setCfcImplementationIdentity(tx, ATTACKER); const alice = runtime.getCell(space, "alice-note", undefined, tx) .getRaw() as { note: string }; const chosen = runtime.getCell( space, alice.note.charCodeAt(0) & 1 ? "public-a" : "public-b", undefined, tx, ); runtime.getCell(space, "public-selection", SELECTION_SCHEMA, tx).set([ chosen, ] as never); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); const tallyTx = runtime.edit(); setCfcImplementationIdentity(tallyTx, TALLY); const committed = runtime.getCell( space, "committed", undefined, tallyTx, ) .getRaw(); const selected = runtime.getCell( space, "public-selection", undefined, tallyTx, ).key(0).get(); const ballotId = runtime.getCell( space, "public-ballot", undefined, tallyTx, ).getAsNormalizedFullLink().id; tallyTx.writeOrThrow( { space, scope: "space", id: ballotId, path: ["value"] }, tally([committed, selected]), ); tallyTx.prepareCfc(); expect((await tallyTx.commit().settled).error).toBeUndefined(); expect(refusedByCeiling(publish(runtime, "public-ballot"))).toBe(true); }); }); it("refuses an input whose writer is unattributed", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await transform( runtime, [COMMIT, OTHER], ["alice-note"], "crafted", ([alice]) => ({ votes: [(alice as { note: string }).note.slice(0, 1)], }), ); await transform(runtime, TALLY, ["crafted"], "ballot", tally); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); }); describe("chains of endorsed transformers", () => { // The commit step is endorsed code too, so a caller can feed IT crafted // input. A guard pinning one level trusts whatever the commit step was // fed; a guard pinning the commit step's own witness does not. const SUBMIT = verified("module:conclave", "submitStance"); const pinsChain: AtomPattern = { ...transformedBy(TALLY), inputWitness: { ...transformedBy(COMMIT), inputWitness: transformedBy(SUBMIT), }, }; // Each member's stance is born in the room: the submit step reads the // room's roster (so its write is attributed) and writes the stance. const submitStances = async (runtime: Runtime): Promise => { await seedSecret(runtime, "roster", "members"); for (const [who, vote] of [["alice", "approve"], ["bob", "reject"]]) { await transform(runtime, SUBMIT, ["roster"], `${who}-stance`, () => ({ vote, })); } }; const commitSubmitted = (runtime: Runtime, inputs: readonly string[]) => transform(runtime, COMMIT, inputs, "committed", (values) => ({ votes: values.flatMap((value) => { const { vote, votes } = value as { vote?: string; votes?: string[] }; return vote === undefined ? votes ?? [] : [vote]; }), })); it("records the inner transformer's witness inside the outer one", async () => { await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await submitStances(runtime); await commitSubmitted(runtime, ["alice-stance", "bob-stance"]); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(storedIntegrity(runtime, "ballot")).toContainEqual({ type: CFC_ATOM_TYPE.TransformedBy, identity: TALLY, inputWitness: { type: CFC_ATOM_TYPE.TransformedBy, identity: COMMIT, inputWitness: { type: CFC_ATOM_TYPE.TransformedBy, identity: SUBMIT, }, }, }); }); }); it("a guard pinning the chain releases the endorsed chain", async () => { await withRuntime(pinsChain, async ({ runtime }) => { await submitStances(runtime); await commitSubmitted(runtime, ["alice-stance", "bob-stance"]); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("a guard pinning the chain refuses crafted input fed to the inner step", async () => { await withRuntime(pinsChain, async ({ runtime }) => { await submitStances(runtime); await seedRoom(runtime); await bitOfAlicesNote(runtime); await commitSubmitted(runtime, ["crafted"]); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); it("a guard pinning one level admits crafted input fed to the inner step", async () => { // Every value the commit step writes carries the commit step's // identity-only atom, whatever it was fed, so a one-level pin is // satisfied by it. A rule pins as deep as the code it trusts. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await submitStances(runtime); await seedRoom(runtime); await bitOfAlicesNote(runtime); await commitSubmitted(runtime, ["crafted"]); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); }); describe("a whole-value set over another writer's value", () => { // `Cell.set` stamps its destination as written whole, so the commit step // setting a document another writer filled is its writer everywhere // beneath. That holds only for a set that wrote: one that threw part way // supplied nothing, and the other writer's value must keep its own stamp. const commitOver = async ( runtime: Runtime, set: (committed: ReturnType) => void, ): Promise => { const tx = runtime.edit(); setCfcImplementationIdentity(tx, COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); set(runtime.getCell(space, "committed", undefined, tx)); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); }; it("releases what the commit step set over a crafted value", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); await commitOver(runtime, (committed) => { committed.set({ votes: ["approve", "reject"] }); }); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("refuses a crafted value the commit step read back and set again", async () => { // The commit step appends to what it finds. The crafted vote it read // is carried into its set unchanged, so the diff leaves it in place; // the destination is not stamped whole over a value the step read. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); await commitOver(runtime, (committed) => { const previous = (committed.get() as { votes?: string[] })?.votes ?? []; committed.set({ votes: [...previous, "approve", "reject"] }); }); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); it("releases a crafted value the commit step read through a copy (documented)", async () => { // Documented behaviour, not a guarantee: the destination skip catches // only a direct read of the destination. Here other code copies the // committed document into `mirror`, and the commit step reads the copy // and appends to it. The crafted vote reaches the destination through // the commit step's set, whose destination it never read, so the set is // stamped whole and a one-level guard releases it, as it trusts every // input the commit step read. A guard pinning the commit step's own // inputs is what refuses this. If this starts refusing, the documented // behaviour changed: update the spec and the pattern README with it. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); await transform( runtime, OTHER, ["committed"], "mirror", ([value]) => value as FabricValue, ); const tx = runtime.edit(); setCfcImplementationIdentity(tx, COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); const previous = (runtime.getCell(space, "mirror", undefined, tx) .get() as { votes?: string[] })?.votes ?? []; runtime.getCell(space, "committed", undefined, tx).set({ votes: [...previous, "approve", "reject"], }); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("stamps a member set whole beside a shallow read of its parent", async () => { // A shallow read of the parent observes its keys, not the member's // value, so it carries nothing into the set; only a recursive read above // the destination counts as reading it. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await transform( runtime, ATTACKER, ["alice-note"], "committed", ([alice]) => ({ ballot: { votes: [(alice as { note: string }).note.slice(0, 1)], }, }), ); const tx = runtime.edit(); setCfcImplementationIdentity(tx, COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); const committed = runtime.getCell(space, "committed", undefined, tx); const { id } = committed.getAsNormalizedFullLink(); tx.readOrThrow({ space, scope: "space", id, path: ["value"] }, { nonRecursive: true, }); committed.key("ballot" as never).set({ votes: ["approve", "reject"], } as never); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); const tallyTx = runtime.edit(); setCfcImplementationIdentity(tallyTx, TALLY); const ballot = runtime.getCell(space, "committed", undefined, tallyTx) .key("ballot" as never).getRaw(); const ballotId = runtime.getCell(space, "ballot", undefined, tallyTx) .getAsNormalizedFullLink().id; tallyTx.writeOrThrow( { space, scope: "space", id: ballotId, path: ["value"] }, tally([ballot]), ); tallyTx.prepareCfc(); expect((await tallyTx.commit().settled).error).toBeUndefined(); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("refuses a crafted value a failed set left beside a write of its own", async () => { await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); await commitOver(runtime, (committed) => { try { committed.set({ get votes(): string[] { throw new Error("the set supplies no value"); }, }); } catch { // The failed set is swallowed; the write below still commits. } committed.key("note").set("committed"); }); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); }); describe("what a whole-value stamp rests on", () => { // `Cell.set` records its destination on the transaction, and prepare // stamps it whole only when every condition below holds. These cases // record the destination directly, beside a write of the transaction's // own, so each condition can be removed alone. The crafted vote planted // first must stay refused whenever one is missing; the control is the // same record with every condition met. const committedId = (runtime: Runtime, tx: IExtendedStorageTransaction) => runtime.getCell(space, "committed", undefined, tx) .getAsNormalizedFullLink().id; const recordAndWrite = async ( runtime: Runtime, options: { root?: readonly string[]; write?: readonly string[]; authorized?: boolean; recordedBy?: ImplementationIdentity; /** A path recorded as holding a reference the runtime stored there. */ referenced?: { slot: readonly string[]; entity: string }; } = {}, ): Promise => { const tx = runtime.edit(); setCfcImplementationIdentity(tx, options.recordedBy ?? COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); const id = committedId(runtime, tx); tx.recordCfcAssertedValueRoot( { space, id, scope: "space", path: [...(options.root ?? [])] }, options.authorized === false ? undefined : runtimeWritePolicyAuthorization, ); if (options.referenced !== undefined) { tx.recordCfcAssertedValueRoot( { space, id, scope: "space", path: [...options.referenced.slot] }, runtimeWritePolicyAuthorization, { space, scope: "space", id: runtime.getCell(space, options.referenced.entity, undefined, tx) .getAsNormalizedFullLink().id, path: [], }, ); } setCfcImplementationIdentity(tx, COMMIT); tx.writeOrThrow( { space, scope: "space", id, path: ["value", ...(options.write ?? ["note"])], }, "committed", ); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); }; /** The tally over the committed votes alone. */ const tallyVotes = async (runtime: Runtime): Promise => { const tx = runtime.edit(); setCfcImplementationIdentity(tx, TALLY); const votes = runtime.getCell(space, "committed", undefined, tx) .key("votes" as never).getRaw(); const ballotId = runtime.getCell(space, "ballot", undefined, tx) .getAsNormalizedFullLink().id; tx.writeOrThrow( { space, scope: "space", id: ballotId, path: ["value"] }, tally([{ votes }]), ); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); }; const released = async ( options: Parameters[1], plant?: (runtime: Runtime) => Promise, ): Promise => { let reasons: readonly string[] = []; await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); await plant?.(runtime); await recordAndWrite(runtime, options); await tallyVotes(runtime); reasons = publish(runtime, "ballot"); }); if (reasons.length > 0) { expect(refusedByCeiling(reasons)).toBe(true); } return reasons.length === 0; }; it("stamps a recorded destination whole when every condition holds", async () => { expect(await released({})).toBe(true); }); it("drops a record without the runtime's mark", async () => { expect(await released({ authorized: false })).toBe(false); }); it("drops a record made under another identity", async () => { expect(await released({ recordedBy: OTHER })).toBe(false); }); it("drops a destination the transaction wrote nothing beneath", async () => { expect(await released({ root: ["votes"], write: ["note"] })).toBe( false, ); }); it("drops a destination holding a reference the writer did not supply", async () => { expect( await released({}, async (runtime) => { const tx = runtime.edit(); setCfcImplementationIdentity(tx, ATTACKER); runtime.getCell(space, "committed", undefined, tx).key( "ref" as never, ).set(runtime.getCell(space, "bob-note", undefined, tx) as never); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); }), ).toBe(false); }); // A reference planted beside the votes, which a slot record below may // claim as the one the runtime stored there. const plantReference = async (runtime: Runtime): Promise => { const tx = runtime.edit(); setCfcImplementationIdentity(tx, ATTACKER); runtime.getCell(space, "committed", undefined, tx).key( "ref" as never, ).set(runtime.getCell(space, "bob-note", undefined, tx) as never); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); }; it("stamps a destination holding the reference the runtime recorded at its path", async () => { expect( await released( { referenced: { slot: ["ref"], entity: "bob-note" } }, plantReference, ), ).toBe(true); }); it("drops a destination whose path holds a reference other than the one recorded there", async () => { expect( await released( { referenced: { slot: ["ref"], entity: "alice-note" } }, plantReference, ), ).toBe(false); }); it("drops a destination whose reference sits at a path with no reference recorded", async () => { expect( await released( { referenced: { slot: ["other"], entity: "bob-note" } }, plantReference, ), ).toBe(false); }); it("drops a destination whose join does not fit a ceiling declared beneath it", async () => { // `open` declares a policy the join does not fit. The destination is // left to the per-path stamps rather than measuring a misfit no write // made, so no value stamp lands at its path. const stampedAtRoot = async (openPolicy: boolean): Promise => { const schema = { type: "object", ifc: { confidentiality: ["alice-only"] }, properties: { votes: { type: "array", items: { type: "string" } }, open: openPolicy ? { type: "string", ifc: { confidentiality: ["public-room"] } } : { type: "string" }, }, } as const satisfies JSONSchema; let stamped = false; await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedLabeled(runtime, "alice-note", { note: "alice-secret" }, [ { path: [], label: { confidentiality: ["alice-only"] } }, ]); // The document is created by a transaction that read nothing // labeled, so it carries no value stamp of its own. for (const commitStep of [false, true]) { const tx = runtime.edit(); if (commitStep) { setCfcImplementationIdentity(tx, COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); } runtime.getCell(space, "committed", schema, tx).set({ votes: [commitStep ? "approve" : "reject"], open: "public", } as never); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); } const tx = runtime.edit(); const metadata = readStoredCfcMetadata( tx, runtime.getCell(space, "committed", undefined, tx) .getAsNormalizedFullLink(), ); tx.abort(); stamped = (metadata?.labelMap.entries ?? []).some((entry) => entry.path.length === 0 && entry.origin === "derived" && entry.observes === "value" ); }); return stamped; }; expect(await stampedAtRoot(false)).toBe(true); expect(await stampedAtRoot(true)).toBe(false); }); it("replaces another writer's stamp on a member the set left in place", async () => { // The attacker's own stamp on `votes/0` would outrank the destination's // and refuse the release, though the commit step's set supplied that // value too. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); await transform( runtime, ATTACKER, ["alice-note"], "committed", () => "reject", ["votes", "0"], ); const tx = runtime.edit(); setCfcImplementationIdentity(tx, COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); runtime.getCell(space, "committed", undefined, tx).set({ votes: ["reject", "approve"], }); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("is not shadowed by the existence stamp of a member the set removed", async () => { // The attacker added `extra`, which leaves an existence stamp that // outlives the key. The commit step's set removes it, and what remains // is all the commit step's. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); await transform( runtime, ATTACKER, ["alice-note"], "committed", () => "planted", ["extra"], ); const tx = runtime.edit(); setCfcImplementationIdentity(tx, COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); runtime.getCell(space, "committed", undefined, tx).set({ votes: ["approve", "reject"], }); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(publish(runtime, "ballot")).toEqual([]); }); }); it("keeps a member's stamp where its schema declares a label until a write covers it", async () => { // Each member path carries a declared entry. A member set whole is // stamped at its own path; a write to another member leaves that // stamp, and a write at the member replaces it. const schema = { type: "object", properties: { a: { type: "object", ifc: { confidentiality: [ROOM] } }, b: { type: "object", ifc: { confidentiality: [ROOM] } }, }, } as const satisfies JSONSchema; const setMember = async ( runtime: Runtime, identity: ImplementationIdentity, member: "a" | "b", value: FabricValue, ) => { const tx = runtime.edit(); setCfcImplementationIdentity(tx, identity); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); runtime.getCell(space, "members", schema, tx).key(member).set( value as never, ); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); }; const writersAtA = (runtime: Runtime): unknown[] => { const tx = runtime.edit(); const metadata = readStoredCfcMetadata( tx, runtime.getCell(space, "members", undefined, tx) .getAsNormalizedFullLink(), ); tx.abort(); return (metadata?.labelMap.entries ?? []) .filter((entry) => entry.path.length === 1 && entry.path[0] === "a" && entry.origin === "derived" && entry.observes === "value" ) .flatMap((entry) => entry.label.integrity ?? []) .filter((atom) => (atom as { inputWitness?: unknown }).inputWitness === undefined ); }; await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); // Created by a transaction that read nothing labeled, so the members // start with no value stamp. const setup = runtime.edit(); runtime.getCell(space, "members", schema, setup).set({ a: { vote: "none" }, b: { vote: "none" }, } as never); setup.prepareCfc(); expect((await setup.commit().settled).error).toBeUndefined(); await setMember(runtime, COMMIT, "a", { vote: "approve" }); await setMember(runtime, COMMIT, "b", { vote: "reject" }); expect(writersAtA(runtime)).toEqual([{ type: CFC_ATOM_TYPE.TransformedBy, identity: COMMIT, }]); await setMember(runtime, ATTACKER, "a", { vote: "reject" }); expect(writersAtA(runtime)).toEqual([{ type: CFC_ATOM_TYPE.TransformedBy, identity: ATTACKER, }]); }); }); it("refuses a crafted value beside a set that changed nothing", async () => { // The set supplies exactly what the attacker planted, so the diff writes // nothing; a write elsewhere in the document must not turn it into an // assertion of the whole. await withRuntime(WITNESSED_GUARD, async ({ runtime }) => { await seedRoom(runtime); await bitOfAlicesNote(runtime, "committed"); const tx = runtime.edit(); setCfcImplementationIdentity(tx, COMMIT); runtime.getCell(space, "alice-note", undefined, tx).getRaw(); const committed = runtime.getCell(space, "committed", undefined, tx); committed.set({ votes: ["approve"] }); committed.key("note" as never).set("committed" as never); tx.prepareCfc(); expect((await tx.commit().settled).error).toBeUndefined(); await transform(runtime, TALLY, ["committed"], "ballot", tally); expect(refusedByCeiling(publish(runtime, "ballot"))).toBe(true); }); }); }); describe("the room's committed document", () => { it("is attributed to the commit step", async () => { await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); expect(storedIntegrity(runtime, "committed")).toContainEqual({ type: CFC_ATOM_TYPE.TransformedBy, identity: COMMIT, }); }); }); }); describe("what fails closed", () => { // Each case pairs a control, where the witness is minted, with the same // transformation over an input that violates one guard, where it must not // be. The control keeps the refusal from passing for an unrelated reason. const tb = (identity: ImplementationIdentity) => ({ type: CFC_ATOM_TYPE.TransformedBy, identity, }); const COMMITTED_VALUE = (integrity: CfcAtom[]): LabelMapEntry => ({ path: [], origin: "derived", observes: "value", label: { confidentiality: [ROOM], integrity }, }); const DECLARED_ROOM: LabelMapEntry = { path: [], origin: "declared", label: { confidentiality: [ROOM] }, }; const witnessesOf = (runtime: Runtime, cause: string): unknown[] => storedIntegrity(runtime, cause).flatMap((atom) => { const witness = (atom as { inputWitness?: unknown }).inputWitness; return witness === undefined ? [] : [witness]; }); it("a witnessed child does not vouch for an unwitnessed `*` slot beside it", async () => { // The `*` slot stands for the children with no entry of their own, and // its own resolution carries no witness. The concrete sibling's entry // resolves at the sibling alone. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { const witnessed = [ DECLARED_ROOM, COMMITTED_VALUE([tb(COMMIT)]), { path: ["items", "a"], origin: "derived", observes: "value", label: { confidentiality: [ROOM], integrity: [tb(COMMIT)] }, }, ] satisfies LabelMapEntry[]; const value = { items: { a: "approve", b: "approve" } }; await seedLabeled(runtime, "slots-control", value, witnessed); await seedLabeled(runtime, "slots", value, [...witnessed, { path: ["items", "*"], origin: "derived", observes: "value", label: { confidentiality: [ROOM] }, }]); await transform(runtime, TALLY, ["slots-control"], "control", tally); await transform(runtime, TALLY, ["slots"], "ballot", tally); expect(witnessesOf(runtime, "control")).toEqual([tb(COMMIT)]); expect(witnessesOf(runtime, "ballot")).toEqual([]); }); }); it("a runtime-minted `*` template's integrity witnesses nothing", async () => { // The template shadows the witnessed value above it in replace-down, // and its own `TransformedBy` labels membership, not a written value. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { const witnessed = [DECLARED_ROOM, COMMITTED_VALUE([tb(COMMIT)])]; const value = { items: { a: "approve" } }; await seedLabeled(runtime, "template-control", value, witnessed); await seedLabeled(runtime, "template", value, [...witnessed, { path: ["items", "*"], origin: "derived", observes: "value", label: { confidentiality: [ROOM], integrity: [tb(COMMIT)] }, }]); await transform(runtime, TALLY, ["template-control"], "control", tally); await transform(runtime, TALLY, ["template"], "ballot", tally); expect(witnessesOf(runtime, "control")).toEqual([tb(COMMIT)]); expect(witnessesOf(runtime, "ballot")).toEqual([]); }); }); describe("a probe of a member slot", () => { // Compiled code probes each member slot for a reference before it // reads the member. A probe that finds a value there observes that // value, so it is resolved as a shallow read of the slot. const QUEUE_SCHEMA = { type: "object", properties: { votes: { type: "array", items: { type: "string", ifc: { confidentiality: [ROOM] } }, }, }, } as const satisfies JSONSchema; const stamped = ( key: string, writer: ImplementationIdentity, ): LabelMapEntry => ({ path: [key], origin: "derived", observes: "value", label: { confidentiality: [ROOM], integrity: [tb(writer)] }, }); it("refuses a probe of a slot another writer put a value in", async () => { // A probe asks which reference sits at a slot. At a slot holding a // value it finds that value, whose writer the slot's value stamp // records, as a shallow read of the slot would. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); const template: LabelMapEntry = { path: ["*"], origin: "structure", observes: "followRef", label: { confidentiality: [ROOM], integrity: [tb(COMMIT)] }, }; await seedLabeled(runtime, "slots-control", ["approve"], [ template, stamped("0", COMMIT), ]); await seedLabeled(runtime, "slots", ["approve"], [ template, stamped("0", ATTACKER), ]); const probe = (cause: string) => (tx: IExtendedStorageTransaction) => { const id = runtime.getCell(space, cause, undefined, tx) .getAsNormalizedFullLink().id; tx.read({ space, scope: "space", id, type: "application/json", path: ["value", "0", ...linkProbeSubPath()], }, { meta: linkResolutionProbe }); }; await transform( runtime, TALLY, ["committed"], "control", tally, [], probe("slots-control"), ); await transform( runtime, TALLY, ["committed"], "ballot", tally, [], probe("slots"), ); expect(witnessesOf(runtime, "control")).toEqual([tb(COMMIT)]); expect(witnessesOf(runtime, "ballot")).toEqual([]); }); }); it("refuses a probe of a slot holding a reference, whatever the slot's value stamp names", async () => { // A pointer is labeled by the link write that put it at the slot, // which carries no `TransformedBy`, so the probe keeps its own // entries. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); const reference = createSigilLinkFromParsedLink( runtime.getCell(space, "committed").getAsNormalizedFullLink(), ); await seedLabeled(runtime, "slots-reference", [reference], [ { path: ["*"], origin: "structure", observes: "followRef", label: { confidentiality: [ROOM], integrity: [tb(COMMIT)] }, }, stamped("0", COMMIT), ]); await transform( runtime, TALLY, ["committed"], "ballot", tally, [], (tx) => { const id = runtime.getCell(space, "slots-reference", undefined, tx) .getAsNormalizedFullLink().id; tx.read({ space, scope: "space", id, type: "application/json", path: ["value", "0", ...linkProbeSubPath()], }, { meta: linkResolutionProbe }); }, ); expect(witnessesOf(runtime, "ballot")).toEqual([]); }); }); it("refuses a probe of a slot the reader then wrote", async () => { // What the slot holds at prepare is not what the probe found, so the // probe keeps its own entries. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); const entries: LabelMapEntry[] = [ { path: ["votes", "*"], origin: "structure", observes: "followRef", label: { confidentiality: [ROOM], integrity: [tb(COMMIT)] }, }, { ...stamped("0", COMMIT), path: ["votes", "0"] }, ]; const value = { votes: ["approve"] }; await seedLabeled(runtime, "probed-control", value, entries); await seedLabeled(runtime, "probed", value, entries); const probe = (cause: string, write: boolean) => ( tx: IExtendedStorageTransaction, ) => { const id = runtime.getCell(space, cause, undefined, tx) .getAsNormalizedFullLink().id; tx.read({ space, scope: "space", id, type: "application/json", path: ["value", "votes", "0", ...linkProbeSubPath()], }, { meta: linkResolutionProbe }); if (write) { runtime.getCell(space, cause, QUEUE_SCHEMA, tx).set({ votes: ["reject"], }); } }; await transform( runtime, TALLY, ["committed"], "control", tally, [], probe("probed-control", false), ); await transform( runtime, TALLY, ["committed"], "ballot", tally, [], probe("probed", true), ); expect(witnessesOf(runtime, "control")).toEqual([tb(COMMIT)]); expect(witnessesOf(runtime, "ballot")).toEqual([]); }); }); }); it("observing confidential label metadata empties the witnesses", async () => { // Label metadata is a confidential input that carries no evidence. The // observation is recorded through the transaction's channel directly, // as `inspectStoredConfLabel` records one for a protected result. await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await transform(runtime, TALLY, ["committed"], "control", tally); await transform( runtime, TALLY, ["committed"], "ballot", tally, [], (tx) => { const { id } = runtime.getCell(space, "committed", undefined, tx) .getAsNormalizedFullLink(); tx.recordCfcLabelMetadataObservation({ target: { space, id, scope: "space", path: ["cfc", "labels", "value", "votes"], }, observes: "labelMetadata", confidentiality: [ROOM], }); }, ); expect(witnessesOf(runtime, "control")).toEqual([tb(COMMIT)]); expect(witnessesOf(runtime, "ballot")).toEqual([]); }); }); it("confidential external content without the witness empties it", async () => { // A host-observed row is a confidential input like any read; the // producer that records it is the transformer here. const PRODUCER = "input-witness-producer"; const producer: ImplementationIdentity = { kind: "builtin", builtinId: PRODUCER, }; const ROW_SCHEMA = { type: "object", properties: { title: { type: "string" } }, required: ["title"], ifc: { confidentiality: [ROOM] }, } as const satisfies JSONSchema; await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedRoom(runtime); await commitStances(runtime); await transform(runtime, producer, ["committed"], "control", tally); await transform( runtime, producer, ["committed"], "ballot", tally, [], async (tx) => { const receipt = await runtime.prepareExternalContentObservation({ targetTx: tx, space, cause: "input-witness-external-row", schema: ROW_SCHEMA, value: { title: "host row" }, producer: PRODUCER, }); runtime.recordExternalContentObservation(tx, receipt, { space, producer: PRODUCER, }); const [observation] = tx.getCfcState().externalContentObservations; expect(observation.flow.confidentiality).toContainEqual(ROOM); }, ); expect(witnessesOf(runtime, "control")).toEqual([tb(COMMIT)]); expect(witnessesOf(runtime, "ballot")).toEqual([]); }); }); it("a chain of five endorsed steps records at most three levels", async () => { // Each step nests the previous step's atoms one level deeper, so an // uncapped chain would carry four levels at the fifth step. const steps = ["submit", "commit", "tally", "audit", "archive"].map(( symbol, ) => verified("module:conclave", symbol)); await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { await seedSecret(runtime, "roster", "members"); let input = "roster"; for (const [index, step] of steps.entries()) { await transform(runtime, step, [input], `step-${index}`, () => ({ votes: ["approve"], })); input = `step-${index}`; } const depths = storedIntegrity(runtime, input).map((atom) => inputWitnessDepth(atom as CfcAtom) ); expect(maxOf(depths)).toBe(INPUT_WITNESS_MAX_DEPTH); }); }); it("stamps the same label whatever order the witnesses were read in", async () => { await withRuntime(IDENTITY_GUARD, async ({ runtime }) => { const SUBMIT = verified("module:conclave", "submitStance"); const value = { votes: ["approve"] }; await seedLabeled(runtime, "pair-ab", value, [ DECLARED_ROOM, COMMITTED_VALUE([tb(COMMIT), tb(SUBMIT)]), ]); await seedLabeled(runtime, "pair-ba", value, [ DECLARED_ROOM, COMMITTED_VALUE([tb(SUBMIT), tb(COMMIT)]), ]); await transform(runtime, TALLY, ["pair-ab", "pair-ba"], "ab", tally); await transform(runtime, TALLY, ["pair-ba", "pair-ab"], "ba", tally); expect(witnessesOf(runtime, "ab")).toHaveLength(2); expect(JSON.stringify(storedIntegrity(runtime, "ba"))).toBe( JSON.stringify(storedIntegrity(runtime, "ab")), ); }); }); }); }); describe("mintTransformedBy", () => { const A = { type: CFC_ATOM_TYPE.TransformedBy, identity: COMMIT }; const B = { type: CFC_ATOM_TYPE.TransformedBy, identity: OTHER }; it("orders witnesses canonically, not by arrival", () => { expect(JSON.stringify(mintTransformedBy(TALLY, [B, A]))).toBe( JSON.stringify(mintTransformedBy(TALLY, [A, B])), ); }); it("mints one atom per distinct witness", () => { expect(mintTransformedBy(TALLY, [A, { ...A }, B])).toHaveLength(3); }); it("retains no witness at the depth cap", () => { let atom: CfcAtom = A; for (let depth = 0; depth < INPUT_WITNESS_MAX_DEPTH; depth++) { atom = { ...B, inputWitness: atom }; } expect(inputWitnessDepth(atom)).toBe(INPUT_WITNESS_MAX_DEPTH); expect(retainedInputWitnesses([atom])).toEqual([]); }); });