MAS-WP-0009 T01: independent JS implementation (impl/js), differential test, SCP-9
impl/js (Node, zero deps, written from the specs): parser, v0.2 statute-aware rules, signing, outside master. Passes addresses.json, statute-aware.json and auth.json unchanged; its master passes the 11 slave-setup mode flows against the Python email side (ExternalMaster). Differential testing vs mas_core found two unstated stand-in rules, now SCP-9 in the v0.2 draft with fixtures si-011..013, dt-109; ABNF comments no longer say v0.1. Runner: external masters, step errors fail the flow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Assistant: claude-code Assistant-Model: opus Assistant-Process: 5787@bnt-lap001 Assistant-Session: 5db26b82-138b-40cc-9856-4d5eb0f752fd
This commit is contained in:
parent
ecb1ba47f6
commit
a841ceec73
23 changed files with 938 additions and 49 deletions
31
impl/js/test/address.test.mjs
Normal file
31
impl/js/test/address.test.mjs
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
// mas-v0.2-spec/conformance/addresses.json, consumed unchanged (CONFORMANCE.md section 2).
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { parseLocalPart, MasSyntaxError } from "../src/parser.mjs";
|
||||
|
||||
const BUNDLE = new URL("../../../mas-v0.2-spec/", import.meta.url);
|
||||
const fixtures = JSON.parse(readFileSync(new URL("conformance/addresses.json", BUNDLE)));
|
||||
|
||||
for (const f of fixtures) {
|
||||
test(`${f.id} ${JSON.stringify(f.local_part)} (${f.profile})`, () => {
|
||||
let got;
|
||||
try {
|
||||
got = parseLocalPart(f.local_part, f.profile);
|
||||
} catch (e) {
|
||||
assert.ok(e instanceof MasSyntaxError, e);
|
||||
assert.equal(f.valid, false, `rejected (${e.code}) but fixture is valid`);
|
||||
return;
|
||||
}
|
||||
assert.equal(f.valid, true, `accepted but fixture is invalid (${f.error})`);
|
||||
const { required_profile, generator_allowed, ...parsed } = got;
|
||||
assert.deepEqual(parsed, f.parsed);
|
||||
if ("generator_allowed" in f) assert.equal(generator_allowed, f.generator_allowed);
|
||||
});
|
||||
}
|
||||
|
||||
test("a P2 parser also passes every P1 fixture (CONFORMANCE.md 2)", () => {
|
||||
for (const f of fixtures.filter((x) => x.profile === "p1" && x.valid)) {
|
||||
assert.deepEqual((({ required_profile, generator_allowed, ...p }) => p)(parseLocalPart(f.local_part, "p2")), f.parsed);
|
||||
}
|
||||
});
|
||||
27
impl/js/test/signing.test.mjs
Normal file
27
impl/js/test/signing.test.mjs
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
// mas-modes-v0.1-spec/conformance/auth.json, consumed unchanged (CONTRACT.md section 7).
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { signature, verify, AuthError } from "../src/signing.mjs";
|
||||
|
||||
const fx = JSON.parse(readFileSync(new URL("../../../mas-modes-v0.1-spec/conformance/auth.json", import.meta.url)));
|
||||
|
||||
for (const v of fx.vectors) {
|
||||
test(`${v.id} signature`, () => {
|
||||
assert.equal(signature(Buffer.from(v.key_hex, "hex"), v.timestamp, Buffer.from(v.body, "utf8")), v.signature);
|
||||
});
|
||||
}
|
||||
|
||||
for (const c of fx.verify) {
|
||||
test(`${c.id} ${c.why}`, () => {
|
||||
const keys = Object.fromEntries(Object.entries(c.keys).map(([p, k]) => [p, Buffer.from(k, "hex")]));
|
||||
let got;
|
||||
try {
|
||||
got = verify(c.headers, Buffer.from(c.body, "utf8"), keys, c.now);
|
||||
} catch (e) {
|
||||
assert.ok(e instanceof AuthError);
|
||||
got = "error:" + e.code;
|
||||
}
|
||||
assert.equal(got, "peer" in c ? c.peer : "error:" + c.error);
|
||||
});
|
||||
}
|
||||
30
impl/js/test/statute-aware.test.mjs
Normal file
30
impl/js/test/statute-aware.test.mjs
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
// mas-v0.2-spec/conformance/statute-aware.json, consumed unchanged (CONFORMANCE.md section 5).
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readFileSync } from "node:fs";
|
||||
import { Statute, interpret, equivalent, forDestination, CannotExpress } from "../src/statute.mjs";
|
||||
|
||||
const BUNDLE = new URL("../../../mas-v0.2-spec/", import.meta.url);
|
||||
const fx = JSON.parse(readFileSync(new URL("conformance/statute-aware.json", BUNDLE)));
|
||||
const statutes = Object.fromEntries(Object.entries(fx.statutes).map(([k, d]) => [k, new Statute(d)]));
|
||||
|
||||
for (const c of fx.interpretation) {
|
||||
test(`${c.id} interpret ${c.local_part}`, () => {
|
||||
const r = interpret(c.local_part, statutes[c.statute]);
|
||||
assert.deepEqual([r.canonical, r.stand_ins], [c.canonical, c.stand_ins]);
|
||||
});
|
||||
}
|
||||
|
||||
for (const c of fx.equivalence) {
|
||||
test(`${c.id} ${c.a} ~ ${c.b}`, () => {
|
||||
assert.equal(equivalent(c.a, c.b, statutes[c.statute]), c.equivalent);
|
||||
});
|
||||
}
|
||||
|
||||
for (const c of fx.destination) {
|
||||
test(`${c.id} ${c.local_part} for [${c.needs}]`, () => {
|
||||
const run = () => forDestination(c.local_part, statutes[c.statute], c.needs, { allowLossy: c.allow_lossy ?? false });
|
||||
if (c.expect === null) assert.throws(run, CannotExpress, c.reason);
|
||||
else assert.equal(run(), c.expect);
|
||||
});
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue