Files
Jyotisha/frontend/tests/skill-registry.test.ts
T
Jesse_Chen f708edf365
Independent Staging Quality Gate / validate (push) Successful in 10m5s
Independent Staging Quality Gate / publish (push) Successful in 7m4s
fix(rectification): ingest first-turn events without dropping day precision or claiming a unique minute
SQL kinds now match the TypeScript ledger so batch ingest can confirm dated events. Confirm no longer burns the opening focus, recap uses server date labels, and the Agent sees indistinguishable width instead of a fake unique minute.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-19 07:44:23 +08:00

492 lines
15 KiB
TypeScript

import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import {
mkdirSync,
mkdtempSync,
realpathSync,
rmSync,
symlinkSync,
writeFileSync,
} from "node:fs";
import { tmpdir } from "node:os";
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import { test, type TestContext } from "node:test";
import {
computeSkillPackageSha256,
createSkillPackageRegistry,
resolveActiveSkillPackage,
resolveExactSkillPackage,
resolveSkillPackageRuntimePath,
resolveSkillPackageVersion,
verifyAllActiveSkillPackages,
type SkillPackageIdentity,
} from "../src/lib/skill-package-registry.ts";
const sourceCommit = "0fd111d16b45796086a6c1d0945dbd3de6755d8a";
const projectRoot = fileURLToPath(new URL("../../", import.meta.url));
type RegistryEntry = SkillPackageIdentity | Record<string, unknown>;
function sha256(bytes: string | Buffer): string {
return createHash("sha256").update(bytes).digest("hex");
}
function fixture(t: TestContext): {
root: string;
registryPath: string;
writeSkill: (packagePath: string, contents: string) => string;
writeRegistry: (packages: RegistryEntry[]) => void;
} {
const root = mkdtempSync(join(tmpdir(), "skill-registry-test-"));
const registryPath = join(root, "skills", "skill-package-registry.json");
mkdirSync(dirname(registryPath), { recursive: true });
t.after(() => rmSync(root, { recursive: true, force: true }));
return {
root,
registryPath,
writeSkill(packagePath, contents) {
const directory = join(root, packagePath);
mkdirSync(directory, { recursive: true });
writeFileSync(join(directory, "SKILL.md"), contents);
return computeSkillPackageSha256(directory);
},
writeRegistry(packages) {
writeFileSync(
registryPath,
`${JSON.stringify({ schemaVersion: 1, packages }, null, 2)}\n`,
);
},
};
}
function identity(
overrides: Partial<SkillPackageIdentity> = {},
): SkillPackageIdentity {
return {
name: "example-skill",
version: "1.0.0",
sha256: "a".repeat(64),
sourceCommit,
packagePath: "skills/example-skill-1.0.0",
status: "active",
...overrides,
};
}
test("checked-in registry verifies all three active packages and returns absolute directories", () => {
const packages = verifyAllActiveSkillPackages({ projectRoot });
assert.deepEqual(
packages.map(({ name, version, sha256 }) => ({ name, version, sha256 })),
[
{
name: "jyotish-vedic-astrology",
version: "6.9.14",
sha256: "c44e6f500c671d18dd47d9714610b766fbeabe00ca5e495e5225bc2c97f5f105",
},
{
name: "jyotish-birth-time-rectification",
version: "10.0.1",
sha256: "1fcdbeef6a2ad96f564f01aa9b9186dfdffe0ea8600748069528fd6a02236b33",
},
{
name: "jyotish-personal-report",
version: "1.0.0",
sha256: "23149b9e1146b5a66b0762520b58eb750b67d95007144b959f0ff3d9ee2bf982",
},
],
);
for (const resolvedPackage of packages) {
assert.equal(isAbsolute(resolvedPackage.resolvedPath), true);
assert.equal(
resolvedPackage.resolvedPath,
resolve(projectRoot, resolvedPackage.packagePath),
);
}
assert.equal(packages[0]?.sourceCommit, null);
assert.equal(packages[1]?.sourceCommit, null);
assert.equal(packages[2]?.sourceCommit, null);
const active = resolveActiveSkillPackage("jyotish-vedic-astrology", {
projectRoot,
});
assert.equal(active.version, "6.9.14");
const runtimePath = resolveSkillPackageRuntimePath(active);
assert.equal(basename(runtimePath), active.name);
assert.equal(realpathSync(runtimePath), active.resolvedPath);
assert.notEqual(runtimePath, active.resolvedPath);
assert.deepEqual(
resolveExactSkillPackage(active.name, active.version, active.sha256, {
projectRoot,
}),
active,
);
const deprecatedRectification = resolveExactSkillPackage(
"jyotish-birth-time-rectification",
"10.0.0",
"b66f243d266e12527b6934cc0c5925df654a9e7bcbaabea3bf244b2e1dfaf2e7",
{ projectRoot },
);
assert.equal(deprecatedRectification.status, "deprecated");
assert.equal(
deprecatedRectification.sha256,
"b66f243d266e12527b6934cc0c5925df654a9e7bcbaabea3bf244b2e1dfaf2e7",
);
});
test("exact resolution of an old deprecated package is independent of active switches", (t) => {
const f = fixture(t);
const oldHash = f.writeSkill("skills/example-1.0.0", "old immutable bytes\n");
const currentHash = f.writeSkill(
"skills/example-2.0.0",
"current immutable bytes\n",
);
const nextHash = f.writeSkill("skills/example-3.0.0", "next immutable bytes\n");
const oldIdentity = identity({
version: "1.0.0",
sha256: oldHash,
packagePath: "skills/example-1.0.0",
status: "deprecated",
});
const currentIdentity = identity({
version: "2.0.0",
sha256: currentHash,
packagePath: "skills/example-2.0.0",
});
const nextIdentity = identity({
version: "3.0.0",
sha256: nextHash,
packagePath: "skills/example-3.0.0",
status: "deprecated",
});
f.writeRegistry([oldIdentity, currentIdentity, nextIdentity]);
const registry = createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
});
assert.equal(registry.resolveActive("example-skill").version, "2.0.0");
assert.deepEqual(registry.resolveExact("example-skill", "1.0.0", oldHash), {
...oldIdentity,
resolvedPath: realpathSync(join(f.root, "skills/example-1.0.0")),
});
f.writeRegistry([
oldIdentity,
{ ...currentIdentity, status: "deprecated" },
{ ...nextIdentity, status: "active" },
]);
assert.equal(registry.resolveActive("example-skill").version, "3.0.0");
assert.equal(
registry.resolveExact("example-skill", "1.0.0", oldHash).sha256,
oldHash,
);
});
test("version resolution requires one non-blocked identity and verifies its bytes", (t) => {
const f = fixture(t);
const oldHash = f.writeSkill("skills/example-old", "old version\n");
const oldIdentity = identity({
sha256: oldHash,
packagePath: "skills/example-old",
status: "deprecated",
});
f.writeRegistry([oldIdentity]);
const registry = createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
});
assert.throws(() => registry.resolveActive("example-skill"), /No active/);
assert.deepEqual(
resolveSkillPackageVersion("example-skill", "1.0.0", {
projectRoot: f.root,
registryPath: f.registryPath,
}),
{
...oldIdentity,
resolvedPath: realpathSync(join(f.root, "skills/example-old")),
},
);
const alternateHash = f.writeSkill(
"skills/example-old-repacked",
"different bytes\n",
);
f.writeRegistry([
oldIdentity,
identity({
sha256: alternateHash,
packagePath: "skills/example-old-repacked",
status: "deprecated",
}),
]);
assert.throws(
() =>
resolveSkillPackageVersion("example-skill", "1.0.0", {
projectRoot: f.root,
registryPath: f.registryPath,
}),
/Expected one registry identity/,
);
f.writeRegistry([{ ...oldIdentity, status: "blocked" }]);
assert.throws(
() =>
resolveSkillPackageVersion("example-skill", "1.0.0", {
projectRoot: f.root,
registryPath: f.registryPath,
}),
/blocked/,
);
});
test("missing lookup identities fail closed", (t) => {
const f = fixture(t);
f.writeRegistry([]);
const options = { projectRoot: f.root, registryPath: f.registryPath };
const registry = createSkillPackageRegistry(options);
assert.throws(() => registry.resolveActive("example-skill"), /No active/);
assert.throws(
() => registry.resolveExact("example-skill", "1.0.0", "a".repeat(64)),
/No exact skill package/,
);
assert.throws(
() => resolveSkillPackageVersion("example-skill", "1.0.0", options),
/found 0/,
);
});
test("missing identity fields fail closed", (t) => {
const f = fixture(t);
f.writeSkill("skills/example-skill-1.0.0", "bytes\n");
const missingHash: Record<string, unknown> = { ...identity() };
delete missingHash.sha256;
f.writeRegistry([missingHash]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/missing sha256/,
);
});
test("hash mismatch fails closed after reading the complete package tree", (t) => {
const f = fixture(t);
const packagePath = "skills/example-skill-1.0.0";
const expectedHash = f.writeSkill(packagePath, "expected bytes\n");
mkdirSync(join(f.root, packagePath, "references"), { recursive: true });
writeFileSync(
join(f.root, packagePath, "references", "runtime-policy.md"),
"tampered reference bytes\n",
);
f.writeRegistry([identity({ sha256: expectedHash })]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/SHA-256 mismatch/,
);
});
test("package hash covers paths, executable bits, references, scripts, and assets", (t) => {
const f = fixture(t);
const packageDirectory = join(f.root, "skills", "example-skill-1.0.0");
mkdirSync(join(packageDirectory, "references"), { recursive: true });
mkdirSync(join(packageDirectory, "scripts"), { recursive: true });
mkdirSync(join(packageDirectory, "assets"), { recursive: true });
writeFileSync(join(packageDirectory, "SKILL.md"), "skill bytes\n");
writeFileSync(join(packageDirectory, "references", "guide.md"), "guide v1\n");
writeFileSync(join(packageDirectory, "scripts", "run.py"), "print('v1')\n");
writeFileSync(join(packageDirectory, "assets", "template.txt"), "asset v1\n");
const initial = computeSkillPackageSha256(packageDirectory);
writeFileSync(join(packageDirectory, "references", "guide.md"), "guide v2\n");
const changedReference = computeSkillPackageSha256(packageDirectory);
assert.notEqual(changedReference, initial);
writeFileSync(join(packageDirectory, "references", "guide.md"), "guide v1\n");
writeFileSync(join(packageDirectory, "assets", "template.txt"), "asset v2\n");
assert.notEqual(computeSkillPackageSha256(packageDirectory), initial);
});
test("path traversal and symlink escape fail closed", (t) => {
const f = fixture(t);
f.writeRegistry([
identity({
packagePath: "skills/../outside",
sha256: sha256("outside\n"),
}),
]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/unsafe packagePath/,
);
const outside = mkdtempSync(join(tmpdir(), "skill-registry-outside-"));
t.after(() => rmSync(outside, { recursive: true, force: true }));
writeFileSync(join(outside, "SKILL.md"), "outside\n");
const packageDirectory = join(f.root, "skills", "symlinked-skill");
mkdirSync(packageDirectory, { recursive: true });
symlinkSync(join(outside, "SKILL.md"), join(packageDirectory, "SKILL.md"));
f.writeRegistry([
identity({
packagePath: "skills/symlinked-skill",
sha256: sha256("outside\n"),
}),
]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/resolves outside the project root/,
);
});
test("symbolic links are rejected even when their target stays inside the project root", (t) => {
const f = fixture(t);
const packageDirectory = join(f.root, "skills", "symlinked-skill");
const sharedDirectory = join(f.root, "shared");
mkdirSync(packageDirectory, { recursive: true });
mkdirSync(sharedDirectory, { recursive: true });
writeFileSync(join(packageDirectory, "SKILL.md"), "skill bytes\n");
writeFileSync(join(sharedDirectory, "guide.md"), "shared bytes\n");
symlinkSync(sharedDirectory, join(packageDirectory, "references"));
f.writeRegistry([
identity({
packagePath: "skills/symlinked-skill",
sha256: "a".repeat(64),
}),
]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/must not be a symbolic link/,
);
});
test("blocked packages are rejected by active, exact, and version resolution", (t) => {
const f = fixture(t);
const hash = f.writeSkill("skills/example-skill-1.0.0", "blocked bytes\n");
f.writeRegistry([identity({ sha256: hash, status: "blocked" })]);
const registry = createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
});
assert.throws(() => registry.resolveActive("example-skill"), /No active/);
assert.throws(
() => registry.resolveExact("example-skill", "1.0.0", hash),
/blocked/,
);
assert.throws(
() => registry.resolveVersion("example-skill", "1.0.0"),
/blocked/,
);
});
test("duplicate active packages fail the entire registry closed", (t) => {
const f = fixture(t);
const firstHash = f.writeSkill("skills/example-1.0.0", "first\n");
const secondHash = f.writeSkill("skills/example-2.0.0", "second\n");
f.writeRegistry([
identity({
sha256: firstHash,
packagePath: "skills/example-1.0.0",
}),
identity({
version: "2.0.0",
sha256: secondHash,
packagePath: "skills/example-2.0.0",
}),
]);
const registry = createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
});
assert.throws(() => registry.resolveActive("example-skill"), /duplicate active/);
assert.throws(() => registry.verifyAllActive(), /duplicate active/);
});
test("nullable source commits are accepted while malformed non-null commits fail closed", (t) => {
const f = fixture(t);
const hash = f.writeSkill("skills/example-skill-1.0.0", "bytes\n");
f.writeRegistry([identity({ sha256: hash, sourceCommit: null })]);
const resolved = createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill");
assert.equal(resolved.sourceCommit, null);
f.writeRegistry([identity({ sha256: hash, sourceCommit: "not-a-commit" })]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/invalid sourceCommit/,
);
});
test("invalid hash, commit, and non-directory package paths fail closed", (t) => {
const f = fixture(t);
f.writeRegistry([identity({ sha256: "A".repeat(64) })]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/invalid sha256/,
);
f.writeRegistry([identity({ sourceCommit: "not-a-commit" })]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/invalid sourceCommit/,
);
const filePath = join(f.root, "skills", "not-a-directory");
writeFileSync(filePath, "file\n");
f.writeRegistry([
identity({
packagePath: "skills/not-a-directory",
sha256: sha256("file\n"),
}),
]);
assert.throws(
() =>
createSkillPackageRegistry({
projectRoot: f.root,
registryPath: f.registryPath,
}).resolveActive("example-skill"),
/must be a directory/,
);
});