eleven / ocho Public

Clone
git clone https://amadan.net/eleven/ocho

Plain git — no account needed to clone.

Download

Download this file

1// Tests for the service_op consent chip's sanitize bounds (ui.js) — the client
2// whitelist gate every registry-op chip must pass. node test/serviceop.test.mjs
3import assert from "node:assert/strict";
4import { sanitizeActions, CHIP_TYPES } from "../web/static/ui.js";
5
6let failures = 0;
7async function test(name, fn) {
8 try {
9 await fn();
10 console.log(`PASS ${name}`);
11 } catch (e) {
12 failures++;
13 console.log(`FAIL ${name} — ${e.message.split("\n")[0]}`);
14 }
15}
16
17const valid = () => ({
18 type: "service_op",
19 service: "dnsimple",
20 op: "domain.check",
21 access: "read",
22 args: { account: "12345", domain: "blip.com" },
23 label: "Check blip.com",
24});
25
26await test("service_op is a whitelisted chip type", () => {
27 assert.ok(CHIP_TYPES.service_op);
28 assert.equal(typeof CHIP_TYPES.service_op.sanitize, "function");
29});
30
31await test("a valid chip passes with service/op/access/args copied", () => {
32 const [chip] = sanitizeActions([valid()]);
33 assert.deepEqual(chip, {
34 type: "service_op",
35 service: "dnsimple",
36 op: "domain.check",
37 access: "read",
38 args: { account: "12345", domain: "blip.com" },
39 label: "Check blip.com",
40 });
41});
42
43await test("a write op passes and keeps access=write", () => {
44 const a = { ...valid(), op: "domain.register", access: "write", args: { domain: "blip.com" } };
45 const [chip] = sanitizeActions([a]);
46 assert.equal(chip.access, "write");
47 assert.equal(chip.op, "domain.register");
48});
49
50await test("missing args defaults to an empty object", () => {
51 const a = valid();
52 delete a.args;
53 const [chip] = sanitizeActions([a]);
54 assert.deepEqual(chip.args, {});
55});
56
57await test("bad service slugs are rejected", () => {
58 for (const service of ["DNSimple", "dns imple", "dns/../imple", "", 42, "a".repeat(65)]) {
59 assert.deepEqual(sanitizeActions([{ ...valid(), service }]), [], `service=${JSON.stringify(service)}`);
60 }
61});
62
63await test("bad op ids are rejected", () => {
64 for (const op of ["Domain.Check", ".check", "domain.", "domain..check", "domain check", "", 7, "a".repeat(65)]) {
65 assert.deepEqual(sanitizeActions([{ ...valid(), op }]), [], `op=${JSON.stringify(op)}`);
66 }
67});
68
69await test("bad access is rejected", () => {
70 for (const access of ["admin", "READ", "", undefined, null]) {
71 assert.deepEqual(sanitizeActions([{ ...valid(), access }]), [], `access=${JSON.stringify(access)}`);
72 }
73});
74
75await test("non-string arg values are rejected", () => {
76 for (const args of [{ n: 5 }, { ok: true }, { deep: { a: "b" } }, { fn: null }, ["a"], "str"]) {
77 assert.deepEqual(sanitizeActions([{ ...valid(), args }]), [], `args=${JSON.stringify(args)}`);
78 }
79});
80
81await test("oversized args are rejected", () => {
82 const many = Object.fromEntries(Array.from({ length: 17 }, (_, i) => [`k${i}`, "v"]));
83 assert.deepEqual(sanitizeActions([{ ...valid(), args: many }]), [], "17 keys");
84 assert.deepEqual(sanitizeActions([{ ...valid(), args: { big: "x".repeat(5000) } }]), [], "stringified > 4096");
85});
86
87await test("label is copied, with room for a whole consent line (capped at 160)", () => {
88 // A write's confirm sentence ("Register blip.com? This buys the domain and
89 // costs real money.") is longer than a normal chip label — service_op gives
90 // it room so consent text never cuts mid-warning, but still bounds it.
91 const [chip] = sanitizeActions([{ ...valid(), label: " " + "L".repeat(200) }]);
92 assert.equal(chip.label, "L".repeat(160));
93 const [bare] = sanitizeActions([{ ...valid(), label: undefined }]);
94 assert.equal(bare.label, undefined); // shell.js falls back to "Run <op> on <service>"
95 // Other chip types keep the tight 40-char cap.
96 const [plain] = sanitizeActions([{ type: "open_profile", label: "T".repeat(80) }]);
97 assert.equal(plain.label, "T".repeat(40));
98});
99
100console.log(failures === 0 ? "\nALL PASSED" : `\n${failures} FAILED`);
101process.exit(failures === 0 ? 0 : 1);
102