Files
2026-07-20 00:03:02 +00:00

305 lines
11 KiB
JavaScript

"use strict";
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const test = require("node:test");
const versions = require("../../lib/aas-v1/versions");
const { canonicalJson, sha256 } = require("../../lib/aas-v1/canonical-json");
const { buildPlanEnvelope, validateManifest, validatePlanEnvelope } = require("../../lib/aas-v1/stack");
const { sanitizeValidationDetails, validateInstance } = require("../../lib/aas-v1/schema-validator");
const DIGEST_A = `sha256-${"a".repeat(64)}`;
const DIGEST_B = `sha256-${"b".repeat(64)}`;
const DIGEST_C = `sha256-${"c".repeat(64)}`;
const DIGEST_D = `sha256-${"d".repeat(64)}`;
const DIGEST_E = `sha256-${"e".repeat(64)}`;
const DIGEST_F = `sha256-${"f".repeat(64)}`;
function manifest(overrides = {}) {
return {
schemaVersion: 2,
name: "react-vite-production",
catalog: {
package: "agentic-awesome-skills",
version: "15.0.0",
integrity: DIGEST_A,
},
targets: [
{ host: "codex", scope: "project" },
{ host: "claude", scope: "user" },
],
profile: {
goals: ["build", "test", "deploy"],
projectType: "web application",
languages: ["typescript"],
frameworks: ["react", "vite"],
constraints: ["production-ready"],
},
skills: [
{ id: "react-best-practices" },
{ id: "testing/playwright-skill" },
],
...overrides,
};
}
function planInput(overrides = {}) {
const value = manifest();
const installedEntries = [
{ skillId: "react-best-practices", treeDigest: DIGEST_E, catalogIntegrity: DIGEST_A },
];
const nextEntries = [
{ skillId: "react-best-practices", treeDigest: DIGEST_B, catalogIntegrity: DIGEST_A },
{ skillId: "testing/playwright-skill", treeDigest: DIGEST_F, catalogIntegrity: DIGEST_A },
];
return {
manifest: value,
handshake: { ...versions },
catalog: { ...value.catalog },
runtime: {
package: "agentic-awesome-skills",
version: "15.0.0",
integrity: "sha512-VTOb3O9PSYKCDO99i3h0vOn7vHQlGtO/+jSErR80g6OGaDJoBzg3q2GE9Nu890en1/Z54hBEYiVQj/1Rl95xEg==",
closureDigest: DIGEST_B,
},
target: {
host: "codex",
scope: "project",
adapterVersion: "1.0.0",
identityDigest: DIGEST_C,
},
installedState: {
digest: sha256(canonicalJson({ schemaVersion: 1, entries: installedEntries })),
entries: installedEntries,
},
operations: [
{
kind: "install",
skillId: "testing/playwright-skill",
sourceTreeDigest: DIGEST_F,
expectedTreeDigest: null,
resultTreeDigest: DIGEST_F,
backupRequired: false,
},
{
kind: "replaceManaged",
skillId: "react-best-practices",
sourceTreeDigest: DIGEST_B,
expectedTreeDigest: DIGEST_E,
resultTreeDigest: DIGEST_B,
backupRequired: true,
},
],
overrides: [{
kind: "managedDrift",
skillId: "react-best-practices",
reasonCodes: ["AAS_PLAN_MANAGED_DRIFT_APPROVED", "AAS_PLAN_BACKUP_REQUIRED"],
}],
stateCommit: {
previousDigest: sha256(canonicalJson({ schemaVersion: 1, entries: installedEntries })),
nextDigest: sha256(canonicalJson({ schemaVersion: 1, entries: nextEntries })),
position: "final",
},
...overrides,
};
}
test("validateManifest returns a canonical digest with the agent-provided profile", () => {
const value = manifest();
const result = validateManifest(value);
assert.equal(result.ok, true);
assert.equal(result.status, "valid");
assert.equal(result.manifestDigest, sha256(canonicalJson(value)));
assert.deepEqual(
{
protocolVersion: result.protocolVersion,
coreVersion: result.coreVersion,
catalogSchemaVersion: result.catalogSchemaVersion,
},
versions,
);
const withLegacyPolicy = { ...value, policy: { requireKnownSource: true } };
const invalid = validateManifest(withLegacyPolicy);
assert.equal(invalid.ok, false);
assert(invalid.details.issues.some((entry) => (
entry.field === "input"
&& entry.keyword === "additionalProperties"
&& entry.limit === false
&& entry.code === "AAS_STACK_FIELD_UNKNOWN"
)));
});
test("validateManifest reports bounded path-safe profile diagnostics without echoing input", () => {
const sensitiveKey = "/Users/example/private/TOKEN_CANARY";
const cases = [
{
value: manifest({ profile: { ...manifest().profile, goals: ["x".repeat(129)] } }),
expected: { field: "profile.goals[]", keyword: "maxLength", limit: 128 },
},
{
value: manifest({ profile: { ...manifest().profile, languages: Array.from({ length: 33 }, (_, index) => `lang-${index}`) } }),
expected: { field: "profile.languages", keyword: "maxItems", limit: 32 },
},
{
value: manifest({ profile: { ...manifest().profile, [sensitiveKey]: "SECRET_VALUE_CANARY" } }),
expected: { field: "profile", keyword: "additionalProperties", limit: false },
},
{
value: manifest({ profile: "SECRET_PROFILE_CANARY" }),
expected: { field: "profile", keyword: "type", limit: "object" },
},
];
for (const { value, expected } of cases) {
const result = validateManifest(value);
assert.equal(result.ok, false);
assert(result.details.issues.some((entry) => (
entry.field === expected.field
&& entry.keyword === expected.keyword
&& entry.limit === expected.limit
)), `missing diagnostic ${JSON.stringify(expected)}`);
const serialized = JSON.stringify(result);
assert.doesNotMatch(serialized, /Users|TOKEN_CANARY|SECRET_VALUE_CANARY|SECRET_PROFILE_CANARY|schemaPath|instancePath/);
assert(result.details.issues.length <= 32);
}
});
test("schema diagnostics redact dynamic map keys even when they look path-safe", () => {
const details = sanitizeValidationDetails({
issues: [{
instancePath: "/metadata/TOKEN_SECRET_CANARY",
keyword: "type",
params: { type: "string" },
}],
});
assert.deepEqual(details, {
issues: [{ field: "metadata.[unknown]", keyword: "type", limit: "string" }],
});
assert.doesNotMatch(JSON.stringify(details), /TOKEN_SECRET_CANARY/);
});
test("validateManifest rejects duplicates, unsafe ids, legacy policy, and unsupported targets", () => {
const value = manifest({
targets: [
{ host: "codex", scope: "project" },
{ host: "codex", scope: "project" },
{ host: "gemini", scope: "project" },
],
profile: {
goals: ["build"],
languages: ["typescript", "typescript"],
frameworks: [],
constraints: [],
},
policy: { requireKnownSource: true },
skills: [{ id: "../escape" }, { id: "same" }, { id: "same" }],
});
const result = validateManifest(value);
assert.equal(result.ok, false);
const codes = new Set(result.details.issues.map((entry) => entry.code));
for (const code of [
"AAS_STACK_TARGET_DUPLICATE",
"AAS_STACK_TARGET_HOST_UNSUPPORTED",
"AAS_STACK_FIELD_UNKNOWN",
"AAS_STACK_VALUE_DUPLICATE",
"AAS_STACK_STRING_FORMAT_INVALID",
"AAS_STACK_SKILL_DUPLICATE",
]) assert(codes.has(code), `missing issue code ${code}`);
});
test("buildPlanEnvelope is byte-deterministic, single-target, path-free, and digest-bound", () => {
const firstInput = planInput();
const secondInput = planInput({
operations: [...firstInput.operations].reverse(),
overrides: [{
...firstInput.overrides[0],
reasonCodes: [...firstInput.overrides[0].reasonCodes].reverse(),
}],
});
const first = buildPlanEnvelope(firstInput);
const second = buildPlanEnvelope(secondInput);
assert.equal(canonicalJson(first), canonicalJson(second));
assert.equal(first.kind, "aas.stack-plan");
assert.equal(first.digest, sha256(canonicalJson(first.payload)));
assert.deepEqual(first.payload.target, firstInput.target);
assert.equal(Object.hasOwn(first.payload.target, "path"), false);
assert.deepEqual(first.payload.desiredSkills, ["react-best-practices", "testing/playwright-skill"]);
assert.deepEqual(first.payload.operations.map((entry) => entry.kind), ["replaceManaged", "install"]);
assert.equal(first.payload.stateCommit.position, "final");
const tampered = structuredClone(first);
tampered.payload.operations[0].resultTreeDigest = DIGEST_C;
assert.notEqual(tampered.digest, sha256(canonicalJson(tampered.payload)));
});
test("buildPlanEnvelope fails closed on handshake, catalog, target, drift, and physical path input", () => {
assert.throws(
() => buildPlanEnvelope(planInput({ handshake: { ...versions, catalogSchemaVersion: "9.0.0" } })),
(error) => error.code === "AAS_PLAN_VERSION_INCOMPATIBLE" && error.category === "incompatibleVersion",
);
assert.throws(
() => buildPlanEnvelope(planInput({ catalog: { ...manifest().catalog, integrity: DIGEST_B } })),
(error) => error.code === "AAS_PLAN_CATALOG_MISMATCH",
);
assert.throws(
() => buildPlanEnvelope(planInput({ target: { host: "claude", scope: "project", adapterVersion: "1.0.0", identityDigest: DIGEST_C } })),
(error) => error.code === "AAS_PLAN_TARGET_NOT_IN_MANIFEST",
);
assert.throws(
() => buildPlanEnvelope(planInput({ stateCommit: { previousDigest: DIGEST_A, nextDigest: DIGEST_F, position: "final" } })),
(error) => error.code === "AAS_PLAN_STATE_COMMIT_MISMATCH",
);
assert.throws(
() => buildPlanEnvelope(planInput({ target: { ...planInput().target, path: "/tmp/escape" } })),
(error) => error.code === "AAS_PLAN_FIELD_UNKNOWN" && error.details.keys.includes("path"),
);
});
test("validatePlanEnvelope rejects a re-digested incompatible or internally inconsistent plan", () => {
const plan = buildPlanEnvelope(planInput());
assert.equal(validatePlanEnvelope(plan), plan);
const incompatible = structuredClone(plan);
incompatible.payload.versions.catalogSchemaVersion = "9.0.0";
incompatible.digest = sha256(canonicalJson(incompatible.payload));
assert.throws(() => validatePlanEnvelope(incompatible), { code: "AAS_PLAN_VERSION_INCOMPATIBLE" });
const inconsistent = structuredClone(plan);
inconsistent.payload.stateCommit.nextDigest = DIGEST_C;
inconsistent.digest = sha256(canonicalJson(inconsistent.payload));
assert.throws(() => validatePlanEnvelope(inconsistent), { code: "AAS_PLAN_NEXT_STATE_MISMATCH" });
});
test("all public v1 stack schemas are valid JSON Schema documents with unique ids", () => {
const schemaDirectory = path.resolve(__dirname, "..", "..", "..", "schemas", "aas-v1");
const expected = [
"catalog-manifest.schema.json",
"catalog-metadata.schema.json",
"doctor-result.schema.json",
"journal.schema.json",
"managed-state.schema.json",
"plan.schema.json",
"recovery-plan.schema.json",
"result-envelope.schema.json",
"selection-input.schema.json",
"stack-manifest.schema.json",
];
const ids = new Set();
for (const name of expected) {
const schema = JSON.parse(fs.readFileSync(path.join(schemaDirectory, name), "utf8"));
assert.equal(schema.$schema, "https://json-schema.org/draft/2020-12/schema");
assert.match(schema.$id, /^urn:agentic-awesome-skills:schema:/);
assert.equal(ids.has(schema.$id), false, `duplicate schema id ${schema.$id}`);
ids.add(schema.$id);
}
});
test("the generated offline catalog manifest validates against its public schema", () => {
const manifestPath = path.resolve(__dirname, "..", "..", "..", "data", "aas-v1", "catalog-manifest.v1.json");
const instance = JSON.parse(fs.readFileSync(manifestPath, "utf8"));
assert.equal(validateInstance("catalog-manifest.schema.json", instance), instance);
});