Answer stability round 1: 0 🔴, 3 🟡 (0 misread); gate test pins each source, builtin-route name, exact CSS wording
This commit is contained in:
@@ -131,19 +131,19 @@ test("findConflicts: duplicate nav id is an error, a shared permission name only
|
||||
|
||||
const noopHandler = () => {};
|
||||
|
||||
test("findConflicts: a route or nav node gating on a permission no plugin declares warns once per plugin and name", () => {
|
||||
test("findConflicts: a route or nav node gating on a permission no plugin declares warns once per plugin and name, sorted", () => {
|
||||
const gated = findConflicts([
|
||||
p({ id: "a", nav: [{ children: [{ id: "a:x", label: "X", permission: "ghost:read" }], id: "a:root", label: "A", session: true }], routes: [
|
||||
{ handler: noopHandler, method: "GET", path: "/x", permission: "ghost:read" },
|
||||
{ handler: noopHandler, method: "GET", path: "/y", permission: "other:write" },
|
||||
] }),
|
||||
p({ id: "b", permissions: [{ name: "other:write" }] }),
|
||||
p({ id: "a", nav: [{ children: [{ id: "a:x", label: "X", permission: "navonly:read" }], id: "a:root", label: "A", session: true }], routes: [
|
||||
{ handler: noopHandler, method: "GET", path: "/x", permission: "routeonly:read" },
|
||||
{ handler: noopHandler, method: "GET", path: "/y", permission: "both:read" },
|
||||
{ handler: noopHandler, method: "POST", path: "/y", permission: "both:read" },
|
||||
{ handler: noopHandler, method: "GET", path: "/z", permission: "declared:write" },
|
||||
], permissions: [] }),
|
||||
p({ id: "b", nav: [{ id: "b:y", label: "Y", permission: "both:read" }], permissions: [{ name: "declared:write" }] }),
|
||||
]);
|
||||
const messages = gated.filter((c) => c.kind === "permission").map((c) => c.message);
|
||||
assert.equal(messages.length, 1);
|
||||
assert.match(messages[0] ?? "", /"ghost:read"/);
|
||||
assert.deepEqual(gated[0]?.plugins, ["a"]);
|
||||
assert.equal(gated[0]?.level, "warn");
|
||||
assert.ok(gated.every((c) => c.kind === "permission" && c.level === "warn"));
|
||||
assert.deepEqual(gated.map((c) => c.plugins), [["a"], ["a"], ["a"], ["b"]]);
|
||||
assert.deepEqual(gated.map((c) => /"([^"]+:[a-z]+)"/.exec(c.message)?.[1]), ["both:read", "navonly:read", "routeonly:read", "both:read"]);
|
||||
});
|
||||
|
||||
test("findConflicts: a gate on a permission another plugin declares, or on none, stays quiet", () => {
|
||||
|
||||
@@ -231,8 +231,9 @@ export function findConflicts(plugins: Plugin[]): PluginConflict[] {
|
||||
return out;
|
||||
}
|
||||
|
||||
// Declaring is optional, but the admin screens offer only declared names: a gate on one nobody
|
||||
// declares answers 403 until someone writes the Keto tuple by hand.
|
||||
// Declaring is optional, but the admin screens offer only declared names: a route gated on one nobody
|
||||
// declares answers 403 (a nav node is hidden) until the Keto tuple is written by hand or
|
||||
// ADMIN_PERMISSIONS seeds it.
|
||||
function undeclaredGates(plugins: Plugin[]): PluginConflict[] {
|
||||
const declared = new Set(declaredPermissions(plugins).map((decl) => decl.name));
|
||||
const out: PluginConflict[] = [];
|
||||
@@ -241,7 +242,7 @@ function undeclaredGates(plugins: Plugin[]): PluginConflict[] {
|
||||
for (const route of plugin.routes ?? []) if (route.permission != null) gated.add(route.permission);
|
||||
collectNavPermissions(plugin.nav, (name) => gated.add(name));
|
||||
for (const name of [...gated].sort()) {
|
||||
if (!declared.has(name)) out.push({ kind: "permission", level: "warn", message: `plugin "${plugin.id}" gates on "${name}", which no installed plugin declares, so the admin screens can't grant it; add it to a plugin's \`permissions\``, plugins: [plugin.id] });
|
||||
if (!declared.has(name)) out.push({ kind: "permission", level: "warn", message: `plugin "${plugin.id}" gates on "${name}", which no installed plugin declares, so the admin screens can't grant it; declare it in that plugin's \`permissions\``, plugins: [plugin.id] });
|
||||
}
|
||||
}
|
||||
return out;
|
||||
|
||||
Reference in New Issue
Block a user