← Files Biological Sequence & Alignment ViewerARCHIVED FILE
src/chat-file-resource.test.ts
54.1 KB · Sep 30, 2026 · 23:01 UTC
import { createHash, createHmac, randomUUID } from "node:crypto";
import {
mkdtemp,
mkdir,
readFile,
readdir,
rename,
rm,
stat,
utimes,
writeFile,
} from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import { pathToFileURL } from "node:url";
import { gzipSync } from "node:zlib";
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { InMemoryTransport } from "@modelcontextprotocol/sdk/inMemory.js";
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { ListRootsRequestSchema } from "@modelcontextprotocol/sdk/types.js";
import { describe, expect, it } from "vitest";
import { createChatFileResourceStore } from "./chat-file-resource";
import { parseBinarySequenceEnvelope } from "./binary-sequence-envelope";
import {
makeSyntheticAbif,
makeSyntheticScf,
makeSyntheticSnapGene,
} from "./sequence/__fixtures__/chromatogram";
import { parseBinarySequenceDocumentResult } from "./sequence/binary-parser";
import { parseIndexedSequenceEnvelope } from "./indexed-sequence-envelope";
import { HISTORICAL_VIEWER_FILE_ERROR_CODE } from "./resource-error";
const RESOURCE_URI_PREFIX = "viewer-file://sequence-viewer/opened";
const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1_000;
describe("chat file resources", () => {
it.each([
["sample.ab1", makeSyntheticAbif()],
["sample.scf", makeSyntheticScf()],
["sample.dna", makeSyntheticSnapGene()],
["sample.ab1.gz", makeSyntheticAbif()],
] as const)(
"preserves %s bytes through opaque, source-verified resources",
async (fileName, bytes) => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-binary-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
try {
const sourcePath = path.join(workspace, fileName);
const sourceBytes = fileName.endsWith(".gz") ? gzipSync(bytes) : bytes;
await writeFile(sourcePath, sourceBytes);
const store = createStore({ stateDirectory });
const { uri } = (
await store.open(fileName, rootsRequestExtra(workspace))
).primaryFile;
expect(uri).not.toContain(workspace);
expect(uri).not.toContain(fileName);
const resource = await readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri,
});
const contents = resource.contents
.flatMap((item) => ("text" in item ? [item.text] : []))
.join("");
expect(contents).not.toContain(workspace);
const decoded = parseBinarySequenceEnvelope(contents);
expect(decoded).toEqual(bytes);
if (decoded == null) throw new Error("Expected a binary sequence resource.");
expect(
parseBinarySequenceDocumentResult({ bytes: decoded, fileName })
.status,
).toBe("success");
expect(await readFile(sourcePath)).toEqual(Buffer.from(sourceBytes));
await writeFile(sourcePath, new Uint8Array(sourceBytes.length));
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri,
}),
).rejects.toThrow(/changed|historical/iu);
} finally {
await rm(workspace, { force: true, recursive: true });
}
},
);
it("restores signed Windows viewer resources without relying on POSIX chmod", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const actualPlatform = process.platform;
const platformDescriptor = Object.getOwnPropertyDescriptor(
process,
"platform",
);
if (platformDescriptor == null) {
throw new Error("The process platform cannot be restored");
}
await mkdir(stateDirectory, { mode: 0o755, recursive: true });
const initialMode = (await stat(stateDirectory)).mode & 0o777;
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
Object.defineProperty(process, "platform", {
...platformDescriptor,
value: "win32",
});
try {
const { uri } = (
await createStore({ stateDirectory }).open(
"family.fasta",
rootsRequestExtra(workspace),
)
).primaryFile;
const resource = await readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri,
});
expect(
resource.contents.flatMap((item) =>
"text" in item ? [item.text] : [],
),
).toEqual([">family\nACGT\n"]);
expect(
(await readFile(path.join(stateDirectory, "signing-key"))).byteLength,
).toBe(32);
if (actualPlatform !== "win32") {
expect((await stat(stateDirectory)).mode & 0o777).toBe(initialMode);
}
} finally {
Object.defineProperty(process, "platform", platformDescriptor);
await rm(workspace, { force: true, recursive: true });
}
});
it("keeps resource URIs opaque and bounds private persisted state", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
try {
const store = createStore({ maxPersistedFiles: 2, stateDirectory });
const resourceUris: Array<string> = [];
for (const fileName of ["one.fasta", "two.fasta", "three.fasta"]) {
await writeFile(path.join(workspace, fileName), `>${fileName}\nACGT\n`);
resourceUris.push(
(await store.open(fileName, rootsRequestExtra(workspace))).primaryFile
.uri,
);
}
for (const resourceUri of resourceUris) {
expect(resourceUri).toMatch(
/^viewer-file:\/\/sequence-viewer\/opened\/[0-9a-f-]{36}$/,
);
expect(resourceUri).not.toContain(workspace);
expect(resourceUri).not.toContain(".fasta");
}
const persistedRecords = (await readdir(stateDirectory)).filter((name) =>
name.endsWith(".json"),
);
expect(persistedRecords).toHaveLength(2);
for (const persistedRecord of persistedRecords) {
const serializedRecord = await readFile(
path.join(stateDirectory, persistedRecord),
"utf8",
);
expect(serializedRecord).not.toContain("ACGT");
expect(JSON.parse(serializedRecord)).not.toHaveProperty("contents");
}
if (process.platform !== "win32") {
expect((await stat(stateDirectory)).mode & 0o777).toBe(0o700);
expect(
(await stat(path.join(stateDirectory, persistedRecords[0]))).mode &
0o777,
).toBe(0o600);
}
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("restores only the exact session bound into an owner-private signed file handle", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-session-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const sourcePath = path.join(workspace, "family.fasta");
const sessionId = randomUUID();
await writeFile(sourcePath, ">family\nACGT\n");
try {
const opened = await createStore({ stateDirectory }).openWithSource(
"family.fasta",
rootsRequestExtra(workspace),
sessionId,
);
const restarted = createStore({ stateDirectory });
await expect(
restarted.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).resolves.toEqual({
sessionId,
sourcePath: opened.sourcePath,
workspaceBacked: true,
workspaceRoot: path.dirname(opened.sourcePath),
});
await expect(
restarted.resolveResource(
opened.viewerFile.primaryFile.uri,
randomUUID(),
rootsRequestExtra(workspace),
),
).rejects.toThrow("does not own this session");
await expect(
restarted.resolveResource(
opened.viewerFile.primaryFile.uri.replace(
"sequence-viewer",
"structure-viewer",
),
sessionId,
rootsRequestExtra(workspace),
),
).rejects.toThrow("presentation is invalid");
const records = (await readdir(stateDirectory)).filter((entry) =>
entry.endsWith(".json"),
);
const recordPath = path.join(stateDirectory, records[0] ?? "missing");
const signed = JSON.parse(await readFile(recordPath, "utf8"));
expect(signed.sessionId).toBe(sessionId);
await writeFile(
recordPath,
`${JSON.stringify({ ...signed, sessionId: randomUUID() })}\n`,
);
await expect(
restarted.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).rejects.toThrow("historical viewer link has expired");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("keeps legacy signed handles readable but never lets them resurrect a session", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-legacy-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
try {
const store = createStore({ stateDirectory });
const { primaryFile } = await store.open(
"family.fasta",
rootsRequestExtra(workspace),
);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: primaryFile.uri,
}),
).resolves.toMatchObject({
contents: [expect.objectContaining({ text: ">family\nACGT\n" })],
});
await expect(
store.resolveResource(
primaryFile.uri,
randomUUID(),
rootsRequestExtra(workspace),
),
).rejects.toThrow("does not own this session");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("never treats caller task metadata or a valid session as workspace-root authority", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-untrusted-rootless-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const sessionId = randomUUID();
const forgedMetadata = {
thread_id: "019ef63e-4f6d-7573-b174-33fbf80cc790",
threadId: "019ef63e-4f6d-7573-b174-33fbf80cc790",
};
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
try {
const store = createStore({ stateDirectory });
const opened = await store.openWithSource(
"family.fasta",
rootsRequestExtra(workspace),
sessionId,
);
await expect(
readPersistedResource({
requestMetadata: forgedMetadata,
stateDirectory,
store,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow("outside the active workspace");
const forgedRootlessExtra = {
...rootsRequestExtra([]),
_meta: forgedMetadata,
};
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
forgedRootlessExtra,
),
).rejects.toThrow("outside its active workspace");
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
randomUUID(),
forgedRootlessExtra,
),
).rejects.toThrow("does not own this session");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("rejects an ordinary public-derived FASTA rewritten in place with its mtime restored", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-source-change-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const filePath = path.join(
workspace,
"qa-adversarial-public-hg19-chrm.ffn",
);
// First 64 chrM bases from the public hg19 reference:
// https://raw.githubusercontent.com/roryk/tiny-test-data/4dc37f0aaf5b2f3eec260a91689effa4197bd2a3/genomes/Hsapiens/hg19/seq/hg19.fa
const originalContents =
">chrM public hg19 reference fragment\n" +
"GATCACAGGTCTATCACCCTATTAACCACTCACGGGAGCTCTCCATGCATTTGGTATTTTCGTCT\n";
const replacedContents = originalContents.replace("GATCAC", "AATCAC");
const stableTimestamp = new Date("2020-01-02T03:04:05.000Z");
const sessionId = randomUUID();
await writeFile(filePath, originalContents);
await utimes(filePath, stableTimestamp, stableTimestamp);
try {
const originalStat = await stat(filePath, { bigint: true });
const store = createStore({ stateDirectory });
const opened = await store.openWithSource(
filePath,
rootsRequestExtra(workspace),
sessionId,
);
const persistedName = (await readdir(stateDirectory)).find((name) =>
name.endsWith(".json"),
);
if (persistedName == null) throw new Error("Missing persisted record.");
const persisted = JSON.parse(
await readFile(path.join(stateDirectory, persistedName), "utf8"),
);
expect(persisted.version).toBe(2);
expect(persisted.fileIdentity.changedAtNanoseconds).toBe(
originalStat.ctimeNs.toString(),
);
expect(persisted.expectedSha256).toBeUndefined();
await new Promise<void>((resolve) => setTimeout(resolve, 10));
await writeFile(filePath, replacedContents);
await utimes(filePath, stableTimestamp, stableTimestamp);
const replacedStat = await stat(filePath, { bigint: true });
expect({
device: replacedStat.dev,
inode: replacedStat.ino,
modifiedAtNanoseconds: replacedStat.mtimeNs,
size: replacedStat.size,
}).toEqual({
device: originalStat.dev,
inode: originalStat.ino,
modifiedAtNanoseconds: originalStat.mtimeNs,
size: originalStat.size,
});
expect(replacedStat.ctimeNs).not.toBe(originalStat.ctimeNs);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow(
"The original file changed since this viewer card was created",
);
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).rejects.toThrow("moved or changed");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("requires ordinary v1 historical resources to be reopened", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-unverified-v1-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const sessionId = randomUUID();
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
try {
const store = createStore({ stateDirectory });
const opened = await store.openWithSource(
"family.fasta",
rootsRequestExtra(workspace),
sessionId,
);
await convertPersistedFixtureToLegacy({
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
});
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow("historical viewer link has expired");
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).rejects.toThrow("historical viewer link has expired");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("rejects tampering with the signed v2 file change time", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-signed-ctime-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
try {
const { uri } = (
await createStore({ stateDirectory }).open(
"family.fasta",
rootsRequestExtra(workspace),
)
).primaryFile;
const token = uri.slice(`${RESOURCE_URI_PREFIX}/`.length);
const recordPath = path.join(stateDirectory, `${token}.json`);
const persisted = JSON.parse(await readFile(recordPath, "utf8"));
persisted.fileIdentity.changedAtNanoseconds = (
BigInt(persisted.fileIdentity.changedAtNanoseconds) + 1n
).toString();
await writeFile(recordPath, `${JSON.stringify(persisted)}\n`);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri,
}),
).rejects.toThrow("historical viewer link has expired");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("preserves digest-pinned v1 public handles and verifies them during session recovery", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-verified-v1-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const filePath = path.join(workspace, "family.fasta");
const originalContents = ">family\nACGT\n";
const replacedContents = ">family\nTGCA\n";
const stableTimestamp = new Date("2020-01-02T03:04:05.000Z");
const sessionId = randomUUID();
await writeFile(filePath, originalContents);
await utimes(filePath, stableTimestamp, stableTimestamp);
try {
const originalStat = await stat(filePath, { bigint: true });
const expected = {
byteLength: Buffer.byteLength(originalContents),
fileIdentity: {
device: originalStat.dev.toString(),
inode: originalStat.ino.toString(),
modifiedAtNanoseconds: originalStat.mtimeNs.toString(),
size: originalStat.size.toString(),
},
sha256: createHash("sha256").update(originalContents).digest("hex"),
};
const store = createStore({ stateDirectory });
const opened = await store.openVerifiedWithSource(
filePath,
expected,
rootsRequestExtra(workspace),
sessionId,
);
await convertPersistedFixtureToLegacy({
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
});
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
}),
).resolves.toMatchObject({
contents: [expect.objectContaining({ text: originalContents })],
});
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).resolves.toMatchObject({
sessionId,
sourcePath: opened.sourcePath,
});
await writeFile(filePath, replacedContents);
await utimes(filePath, stableTimestamp, stableTimestamp);
const replacedStat = await stat(filePath, { bigint: true });
expect(replacedStat.ino).toBe(originalStat.ino);
expect(replacedStat.mtimeNs).toBe(originalStat.mtimeNs);
expect(replacedStat.size).toBe(originalStat.size);
expect(replacedStat.ctimeNs).not.toBe(originalStat.ctimeNs);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow("original file changed");
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).rejects.toThrow("moved or changed");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("rejects source replacement and changed active roots during session recovery", async () => {
const sandbox = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-session-drift-test-"),
);
const workspace = path.join(sandbox, "workspace");
const other = path.join(sandbox, "other");
const stateDirectory = path.join(sandbox, ".viewer-state");
await mkdir(workspace);
await mkdir(other);
const sourcePath = path.join(workspace, "family.fasta");
await writeFile(sourcePath, ">family\nACGT\n");
const sessionId = randomUUID();
try {
const store = createStore({ stateDirectory });
const opened = await store.openWithSource(
"family.fasta",
rootsRequestExtra(workspace),
sessionId,
);
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(other),
),
).rejects.toThrow("outside its active workspace");
await rename(sourcePath, `${sourcePath}.old`);
await writeFile(sourcePath, ">family\nTGCA\n");
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).rejects.toThrow("moved or changed");
} finally {
await rm(sandbox, { force: true, recursive: true });
}
});
it("rejects expired session handles", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-session-expiry-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const sourcePath = path.join(workspace, "family.fasta");
await writeFile(sourcePath, ">family\nACGT\n");
const sessionId = randomUUID();
let now = Date.now();
try {
const store = createStore({ now: () => now, stateDirectory });
const opened = await store.openWithSource(
"family.fasta",
rootsRequestExtra(workspace),
sessionId,
);
now += THIRTY_DAYS_MS + 1;
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).rejects.toThrow("historical viewer link has expired");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("rejects a tampered persisted path before reading it", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const filePath = path.join(workspace, "family.fasta");
const outsideWorkspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-outside-"),
);
const outsidePath = path.join(outsideWorkspace, "attacker-selected.fasta");
await writeFile(filePath, ">family\nACGT\n");
await writeFile(outsidePath, ">outside\nSECRET\n");
try {
const store = createStore({ stateDirectory });
const { uri } = (
await store.open("family.fasta", rootsRequestExtra(workspace))
).primaryFile;
const persistedName = (await readdir(stateDirectory)).find((name) =>
name.endsWith(".json"),
);
if (persistedName == null) {
throw new Error("Expected a persisted viewer record.");
}
const persistedPath = path.join(stateDirectory, persistedName);
const persisted = JSON.parse(await readFile(persistedPath, "utf8")) as {
absolutePath: string;
};
persisted.absolutePath = outsidePath;
await writeFile(persistedPath, `${JSON.stringify(persisted)}\n`);
await expect(
readPersistedResource({ stateDirectory, uri }),
).rejects.toThrow(HISTORICAL_VIEWER_FILE_ERROR_CODE);
} finally {
await rm(workspace, { force: true, recursive: true });
await rm(outsideWorkspace, { force: true, recursive: true });
}
});
it("does not mint handles for files outside active workspace roots", async () => {
const sandbox = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const workspace = path.join(sandbox, "workspace");
const outsideDirectory = path.join(sandbox, "outside");
const outsidePath = path.join(outsideDirectory, "outside.fasta");
await Promise.all([mkdir(workspace), mkdir(outsideDirectory)]);
await writeFile(outsidePath, ">outside\nACGT\n");
try {
const store = createStore({
stateDirectory: path.join(sandbox, ".viewer-state"),
});
await expect(
store.open("../outside/outside.fasta", rootsRequestExtra(workspace)),
).rejects.toThrow("not found inside the active local workspace roots");
await expect(
store.open(outsidePath, rootsRequestExtra(workspace)),
).rejects.toThrow("not found inside the active local workspace roots");
} finally {
await rm(sandbox, { force: true, recursive: true });
}
});
it("fails closed when a relative source is ambiguous across workspace roots", async () => {
const sandbox = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const first = path.join(sandbox, "first");
const second = path.join(sandbox, "second");
await Promise.all([mkdir(first), mkdir(second)]);
await Promise.all([
writeFile(path.join(first, "family.fasta"), ">first\nAAAA\n"),
writeFile(path.join(second, "family.fasta"), ">second\nCCCC\n"),
]);
try {
const store = createStore({
stateDirectory: path.join(sandbox, ".viewer-state"),
});
await expect(
store.open("family.fasta", rootsRequestExtra([first, second])),
).rejects.toThrow("multiple active workspace roots");
} finally {
await rm(sandbox, { force: true, recursive: true });
}
});
it("revalidates active workspace roots after a restart", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const otherWorkspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-other-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
try {
const { uri } = (
await createStore({ stateDirectory }).open(
"family.fasta",
rootsRequestExtra(workspace),
)
).primaryFile;
await expect(
readPersistedResource({
activeWorkspace: otherWorkspace,
stateDirectory,
uri,
}),
).rejects.toThrow("outside the active workspace");
} finally {
await Promise.all([
rm(workspace, { force: true, recursive: true }),
rm(otherWorkspace, { force: true, recursive: true }),
]);
}
});
it("rejects a changed deepest workspace-root binding", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const nestedWorkspace = path.join(workspace, "nested");
const stateDirectory = path.join(workspace, ".viewer-state");
await mkdir(nestedWorkspace);
await writeFile(
path.join(nestedWorkspace, "family.fasta"),
">family\nACGT\n",
);
try {
const { uri } = (
await createStore({ stateDirectory }).open(
path.join(nestedWorkspace, "family.fasta"),
rootsRequestExtra([workspace, nestedWorkspace]),
)
).primaryFile;
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri,
}),
).rejects.toThrow("outside the active workspace");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("expires persisted handles after the retention window", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
try {
const { uri } = (
await createStore({
now: () => 10_000,
stateDirectory,
}).open("family.fasta", rootsRequestExtra(workspace))
).primaryFile;
await expect(
readPersistedResource({
activeWorkspace: workspace,
now: () => 10_000 + THIRTY_DAYS_MS + 1,
stateDirectory,
uri,
}),
).rejects.toThrow("historical viewer link has expired");
expect(
(await readdir(stateDirectory)).filter((name) =>
name.endsWith(".json"),
),
).toHaveLength(0);
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("retires signed historical bundled cards without reading their source", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
try {
const { uri } = (
await createStore({ stateDirectory }).open(
"family.fasta",
rootsRequestExtra(workspace),
)
).primaryFile;
const persistedName = (await readdir(stateDirectory)).find((name) =>
name.endsWith(".json"),
);
if (persistedName == null) throw new Error("Missing persisted record.");
const persistedPath = path.join(stateDirectory, persistedName);
const persisted = JSON.parse(await readFile(persistedPath, "utf8"));
persisted.bundled = true;
persisted.workspaceRoot = null;
const key = await readFile(path.join(stateDirectory, "signing-key"));
persisted.signature = signPersistedFixture(persisted, key);
await writeFile(persistedPath, `${JSON.stringify(persisted)}\n`);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri,
}),
).rejects.toThrow("Bundled example cards are retired");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("verifies an expected public-source digest before persisting and supports rollback", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const filePath = path.join(workspace, "family.fasta");
const contents = ">family\nACGT\n";
await writeFile(filePath, contents);
try {
const fileStat = await stat(filePath, { bigint: true });
const expected = {
byteLength: Buffer.byteLength(contents),
fileIdentity: {
device: fileStat.dev.toString(),
inode: fileStat.ino.toString(),
modifiedAtNanoseconds: fileStat.mtimeNs.toString(),
size: fileStat.size.toString(),
},
sha256: createHash("sha256").update(contents).digest("hex"),
};
const store = createStore({ stateDirectory });
await expect(
store.openVerifiedWithSource(
filePath,
{ ...expected, sha256: "0".repeat(64) },
rootsRequestExtra(workspace),
),
).rejects.toThrow("changed before it could be opened");
await expect(readdir(stateDirectory)).rejects.toMatchObject({
code: "ENOENT",
});
const opened = await store.openVerifiedWithSource(
filePath,
expected,
rootsRequestExtra(workspace),
);
expect(
(await readdir(stateDirectory)).filter((name) =>
name.endsWith(".json"),
),
).toHaveLength(1);
const persistedName = (await readdir(stateDirectory)).find((name) =>
name.endsWith(".json"),
);
if (persistedName == null) throw new Error("Missing persisted record.");
const persistedPath = path.join(stateDirectory, persistedName);
const persisted = JSON.parse(await readFile(persistedPath, "utf8"));
expect(persisted.expectedSha256).toBe(expected.sha256);
const resource = await readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
});
expect(resource.contents).toEqual([
expect.objectContaining({ text: contents }),
]);
persisted.expectedSha256 = "f".repeat(64);
await writeFile(persistedPath, `${JSON.stringify(persisted)}\n`);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow("historical viewer link has expired");
await opened.discard();
await opened.discard();
expect(
(await readdir(stateDirectory)).filter((name) =>
name.endsWith(".json"),
),
).toHaveLength(0);
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("rejects a verified public source rewritten at the same size with its mtime restored", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const filePath = path.join(workspace, "family.fasta");
const originalContents = ">family\nACGT\n";
const replacedContents = ">family\nTGCA\n";
const stableTimestamp = new Date("2020-01-02T03:04:05.000Z");
await writeFile(filePath, originalContents);
await utimes(filePath, stableTimestamp, stableTimestamp);
try {
const originalStat = await stat(filePath, { bigint: true });
const expected = {
byteLength: Buffer.byteLength(originalContents),
fileIdentity: {
device: originalStat.dev.toString(),
inode: originalStat.ino.toString(),
modifiedAtNanoseconds: originalStat.mtimeNs.toString(),
size: originalStat.size.toString(),
},
sha256: createHash("sha256").update(originalContents).digest("hex"),
};
const opened = await createStore({
stateDirectory,
}).openVerifiedWithSource(
filePath,
expected,
rootsRequestExtra(workspace),
);
const persistedName = (await readdir(stateDirectory)).find((name) =>
name.endsWith(".json"),
);
if (persistedName == null) throw new Error("Missing persisted record.");
const persisted = JSON.parse(
await readFile(path.join(stateDirectory, persistedName), "utf8"),
);
expect(persisted.expectedSha256).toBe(expected.sha256);
await writeFile(filePath, replacedContents);
await utimes(filePath, stableTimestamp, stableTimestamp);
const replacedStat = await stat(filePath, { bigint: true });
expect({
device: replacedStat.dev.toString(),
inode: replacedStat.ino.toString(),
modifiedAtNanoseconds: replacedStat.mtimeNs.toString(),
size: replacedStat.size.toString(),
}).toEqual(expected.fileIdentity);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow(
"The original file changed since this viewer card was created",
);
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("removes a newly signed handle when post-write pruning fails", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(path.join(workspace, "family.fasta"), ">family\nACGT\n");
const failingPersistedLimit = {
valueOf() {
throw new Error("injected prune failure");
},
} as unknown as number;
try {
const store = createChatFileResourceStore({
isSupportedFileName: (fileName) => fileName.endsWith(".fasta"),
maxPersistedFiles: failingPersistedLimit,
resourceUriPrefix: RESOURCE_URI_PREFIX,
stateDirectory,
viewerName: "sequence viewer",
});
await expect(
store.open("family.fasta", rootsRequestExtra(workspace)),
).rejects.toThrow("could not securely save this file handle");
expect(
(await readdir(stateDirectory)).filter((name) =>
name.endsWith(".json"),
),
).toHaveLength(0);
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("reports moved and changed source files explicitly", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const changedPath = path.join(workspace, "changed.fasta");
const movedPath = path.join(workspace, "moved.fasta");
await Promise.all([
writeFile(changedPath, ">changed\nACGT\n"),
writeFile(movedPath, ">moved\nACGT\n"),
]);
try {
const store = createStore({ stateDirectory });
const changedUri = (
await store.open("changed.fasta", rootsRequestExtra(workspace))
).primaryFile.uri;
const movedUri = (
await store.open("moved.fasta", rootsRequestExtra(workspace))
).primaryFile.uri;
await writeFile(changedPath, ">changed\nACGTACGT\n");
await rename(movedPath, path.join(workspace, "new-name.fasta"));
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: changedUri,
}),
).rejects.toThrow("file changed");
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: movedUri,
}),
).rejects.toThrow("moved or deleted");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("rejects oversized files before persisting or materializing their contents", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(
path.join(workspace, "large.fasta"),
`>large\n${"A".repeat(64)}\n`,
);
try {
await expect(
createStore({ maxFileBytes: 32, stateDirectory }).open(
"large.fasta",
rootsRequestExtra(workspace),
),
).rejects.toThrow("accepts at most 32 B");
await expect(readdir(stateDirectory)).rejects.toMatchObject({
code: "ENOENT",
});
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("keeps oversized workspace FASTA handles signed, opaque, and inaccessible to generic resources", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-range-only-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(
path.join(workspace, "large.fasta"),
`>large\n${"A".repeat(192)}\n`,
);
const store = createChatFileResourceStore({
isSupportedFileName: () => true,
maxFileBytes: 32,
maxIndexedFileBytes: 128,
maxRangedFileBytes: 256,
resourceUriPrefix: RESOURCE_URI_PREFIX,
stateDirectory,
viewerName: "sequence viewer",
});
try {
const opened = await store.openWithSource(
"large.fasta",
rootsRequestExtra(workspace),
);
expect(opened.rangeOnly).toBe(true);
expect(opened.workspaceBacked).toBe(true);
expect(JSON.stringify(opened.viewerFile)).not.toContain(workspace);
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
store,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow("bounded, app-only range tools");
const recordName = (await readdir(stateDirectory)).find((name) =>
name.endsWith(".json"),
);
if (recordName == null)
throw new Error("Missing signed range-only record.");
const recordPath = path.join(stateDirectory, recordName);
const record = JSON.parse(await readFile(recordPath, "utf8")) as {
rangeOnly?: true;
};
expect(record.rangeOnly).toBe(true);
delete record.rangeOnly;
await writeFile(recordPath, JSON.stringify(record));
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
store,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow("historical viewer link has expired");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("reauthorizes signed range-only sessions without reading the whole source", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-range-session-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(
path.join(workspace, "large.fasta"),
`>large\n${"A".repeat(192)}\n`,
);
const store = createChatFileResourceStore({
isSupportedFileName: () => true,
maxFileBytes: 32,
maxIndexedFileBytes: 128,
maxRangedFileBytes: 256,
resourceUriPrefix: RESOURCE_URI_PREFIX,
stateDirectory,
viewerName: "sequence viewer",
});
const sessionId = randomUUID();
try {
const opened = await store.openWithSource(
"large.fasta",
rootsRequestExtra(workspace),
sessionId,
);
await expect(
store.resolveResource(
opened.viewerFile.primaryFile.uri,
sessionId,
rootsRequestExtra(workspace),
),
).resolves.toEqual({
rangeOnly: true,
sessionId,
sourcePath: opened.sourcePath,
workspaceBacked: true,
workspaceRoot: path.dirname(opened.sourcePath),
});
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
store,
uri: opened.viewerFile.primaryFile.uri,
}),
).rejects.toThrow("bounded, app-only range tools");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("selects only workspace-backed indexable inputs above the native direct-text threshold", async () => {
const sandbox = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-native-index-test-"),
);
const workspace = path.join(sandbox, "workspace");
const outside = path.join(sandbox, "outside");
const stateDirectory = path.join(sandbox, ".viewer-state");
await Promise.all([mkdir(workspace), mkdir(outside)]);
await Promise.all([
writeFile(path.join(workspace, "exact.fasta"), Buffer.alloc(32, "A")),
writeFile(path.join(workspace, "large.fastq"), Buffer.alloc(33, "A")),
writeFile(
path.join(workspace, "too-large.fasta"),
Buffer.alloc(129, "A"),
),
writeFile(path.join(workspace, "large.gb"), Buffer.alloc(64, "A")),
writeFile(path.join(outside, "outside.fasta"), Buffer.alloc(64, "A")),
]);
const store = createChatFileResourceStore({
isSupportedFileName: () => true,
maxFileBytes: 32,
maxIndexedFileBytes: 128,
resourceUriPrefix: RESOURCE_URI_PREFIX,
stateDirectory,
viewerName: "sequence viewer",
});
try {
await expect(
store.openIndexedWorkspaceFile(
path.join(workspace, "exact.fasta"),
rootsRequestExtra(workspace),
32,
),
).resolves.toBeNull();
await expect(
store.openIndexedWorkspaceFile(
path.join(workspace, "large.gb"),
rootsRequestExtra(workspace),
32,
),
).resolves.toBeNull();
await expect(
store.openIndexedWorkspaceFile(
path.join(outside, "outside.fasta"),
rootsRequestExtra(workspace),
32,
),
).resolves.toBeNull();
await expect(
store.openIndexedWorkspaceFile(
path.join(workspace, "large.fastq"),
{ sendRequest: async () => Promise.reject(new Error("no roots")) },
32,
),
).resolves.toBeNull();
const opened = await store.openIndexedWorkspaceFile(
path.join(workspace, "large.fastq"),
rootsRequestExtra(workspace),
32,
);
expect(opened).toMatchObject({
viewerFile: {
primaryFile: {
name: "large.fastq",
uri: expect.stringMatching(
/^viewer-file:\/\/sequence-viewer\/opened\/[0-9a-f-]{36}$/,
),
},
},
workspaceBacked: true,
});
expect(JSON.stringify(opened?.viewerFile)).not.toContain(workspace);
await expect(
store.openIndexedWorkspaceFile(
path.join(workspace, "too-large.fasta"),
rootsRequestExtra(workspace),
32,
),
).rejects.toThrow("accepts at most 128 B");
} finally {
await rm(sandbox, { force: true, recursive: true });
}
});
it.each(["gz", "bgz", "bgzf", "bgzip"] as const)(
"streams %s-compressed FASTA into a bounded indexed envelope",
async (extension) => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const source = ">alpha first\nACGT\n>beta\nTTTT\n";
const fileName = `family.fasta.${extension}`;
await writeFile(path.join(workspace, fileName), gzipSync(source));
try {
const store = createStore({ stateDirectory });
const opened = await store.openIndexedWorkspaceFile(
fileName,
rootsRequestExtra(workspace),
1,
);
if (opened == null) throw new Error("Expected an indexed gzip handle.");
const { uri } = opened.viewerFile.primaryFile;
const resource = await readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri,
});
const text = resource.contents.flatMap((item) =>
"text" in item ? [item.text] : [],
)[0];
const envelope = parseIndexedSequenceEnvelope(text ?? "");
expect(envelope?.index).toMatchObject({
complete: true,
compressed: true,
indexedRecordCount: 2,
materializedRecordCount: 2,
});
expect(envelope?.document.records.map(({ id }) => id)).toEqual([
"alpha",
"beta",
]);
} finally {
await rm(workspace, { force: true, recursive: true });
}
},
);
it("streams BGZF-suffixed FASTQ and restores exact genuine qualities", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
const source = "@read-1 first\nACGT\n+\n!!!!\n";
await writeFile(path.join(workspace, "reads.fastq.bgzf"), gzipSync(source));
try {
const store = createStore({ stateDirectory });
const opened = await store.openIndexedWorkspaceFile(
"reads.fastq.bgzf",
rootsRequestExtra(workspace),
1,
);
if (opened == null) {
throw new Error("Expected an indexed compressed FASTQ handle.");
}
const resource = await readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
uri: opened.viewerFile.primaryFile.uri,
});
const text = resource.contents.flatMap((item) =>
"text" in item ? [item.text] : [],
)[0];
const envelope = parseIndexedSequenceEnvelope(text ?? "");
expect(envelope?.index).toMatchObject({
complete: true,
compressed: true,
indexedRecordCount: 1,
});
expect(envelope?.document).toMatchObject({
format: "fastq",
records: [
{
id: "read-1",
sequence: "ACGT",
quality: { ascii: "!!!!", phred: [0, 0, 0, 0] },
},
],
});
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("bounds decoded gzip bytes before scanning an indexed FASTA", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(
path.join(workspace, "expanded.fasta.gz"),
gzipSync(`>expanded\n${"A".repeat(4_096)}\n`),
);
try {
const store = createChatFileResourceStore({
isSupportedFileName: (fileName) => fileName.endsWith(".fasta.gz"),
maxFileBytes: 32,
maxIndexedFileBytes: 128,
resourceUriPrefix: RESOURCE_URI_PREFIX,
stateDirectory,
viewerName: "sequence viewer",
});
const { uri } = (
await store.open("expanded.fasta.gz", rootsRequestExtra(workspace))
).primaryFile;
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
store,
uri,
}),
).rejects.toThrow("expands beyond the bounded viewer limit of 128 B");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
it("bounds gzip expansion before materializing non-indexed text", async () => {
const workspace = await mkdtemp(
path.join(os.tmpdir(), "sequence-viewer-resource-test-"),
);
const stateDirectory = path.join(workspace, ".viewer-state");
await writeFile(
path.join(workspace, "expanded.gb.gz"),
gzipSync("A".repeat(4_096)),
);
try {
const store = createChatFileResourceStore({
isSupportedFileName: (fileName) => fileName.endsWith(".gb.gz"),
maxCompressedFileBytes: 1_024,
maxFileBytes: 32,
resourceUriPrefix: RESOURCE_URI_PREFIX,
stateDirectory,
viewerName: "sequence viewer",
});
const { uri } = (
await store.open("expanded.gb.gz", rootsRequestExtra(workspace))
).primaryFile;
await expect(
readPersistedResource({
activeWorkspace: workspace,
stateDirectory,
store,
uri,
}),
).rejects.toThrow("expands beyond the bounded viewer limit of 32 B");
} finally {
await rm(workspace, { force: true, recursive: true });
}
});
});
function createStore({
maxFileBytes,
maxPersistedFiles,
now,
stateDirectory,
}: {
maxFileBytes?: number;
maxPersistedFiles?: number;
now?: () => number;
stateDirectory: string;
}) {
return createChatFileResourceStore({
isSupportedFileName: (fileName) =>
/\.(?:fasta|fastq|ffn|ab1|abi|scf|dna)(?:\.(?:bgz|bgzf|bgzip|gz))?$/iu.test(fileName),
maxFileBytes,
maxPersistedFiles,
now,
resourceUriPrefix: RESOURCE_URI_PREFIX,
stateDirectory,
viewerName: "sequence viewer",
});
}
function rootsRequestExtra(workspace: string | Array<string>) {
const workspaces = Array.isArray(workspace) ? workspace : [workspace];
return {
sendRequest: async () => ({
roots: workspaces.map((root) => ({ uri: pathToFileURL(root).href })),
}),
};
}
async function readPersistedResource({
activeWorkspace,
now,
requestMetadata,
stateDirectory,
store,
uri,
}: {
activeWorkspace?: string;
now?: () => number;
requestMetadata?: Record<string, unknown>;
stateDirectory: string;
store?: ReturnType<typeof createChatFileResourceStore>;
uri: string;
}) {
const client = new Client(
{ name: "sequence-viewer-resource-test", version: "0.1.0" },
activeWorkspace == null ? undefined : { capabilities: { roots: {} } },
);
if (activeWorkspace != null) {
client.setRequestHandler(ListRootsRequestSchema, async () => ({
roots: [{ uri: pathToFileURL(activeWorkspace).href }],
}));
}
const server = new McpServer({
name: "sequence-viewer-resource-test",
version: "0.1.0",
});
(store ?? createStore({ now, stateDirectory })).register(server);
const [clientTransport, serverTransport] =
InMemoryTransport.createLinkedPair();
await Promise.all([
client.connect(clientTransport),
server.connect(serverTransport),
]);
try {
return await client.readResource({
...(requestMetadata == null ? {} : { _meta: requestMetadata }),
uri,
});
} finally {
await client.close();
await server.close();
}
}
function signPersistedFixture(
payload: {
absolutePath: string;
bundled?: true;
expectedSha256?: string;
fileIdentity: {
changedAtNanoseconds?: string;
device: string;
inode: string;
modifiedAtNanoseconds: string;
size: string;
};
name: string;
openedAt: number;
rangeOnly?: true;
sessionId?: string;
token: string;
version: number;
workspaceRoot: string | null;
},
key: Buffer,
): string {
return createHmac("sha256", key)
.update(
JSON.stringify({
absolutePath: payload.absolutePath,
bundled: payload.bundled,
expectedSha256: payload.expectedSha256,
fileIdentity: payload.fileIdentity,
name: payload.name,
openedAt: payload.openedAt,
...(payload.rangeOnly ? { rangeOnly: true } : {}),
...(payload.sessionId == null ? {} : { sessionId: payload.sessionId }),
token: payload.token,
version: payload.version,
workspaceRoot: payload.workspaceRoot,
}),
)
.digest("base64url");
}
async function convertPersistedFixtureToLegacy({
stateDirectory,
uri,
}: {
stateDirectory: string;
uri: string;
}): Promise<void> {
const token = uri.slice(`${RESOURCE_URI_PREFIX}/`.length);
const recordPath = path.join(stateDirectory, `${token}.json`);
const persisted = JSON.parse(await readFile(recordPath, "utf8"));
const { changedAtNanoseconds: _changedAtNanoseconds, ...legacyIdentity } =
persisted.fileIdentity;
const legacy = {
...persisted,
fileIdentity: legacyIdentity,
version: 1,
};
const key = await readFile(path.join(stateDirectory, "signing-key"));
legacy.signature = signPersistedFixture(legacy, key);
await writeFile(recordPath, `${JSON.stringify(legacy)}\n`);
}
SHA-256: 33fc07c40acf2338347e4f45a3cb6c93c6c4e18e3aa30ce09de9905cd973b6aa