Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
JavaScript
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841import assert from "node:assert/strict";import { test } from "node:test";import { build } from "esbuild";import { Miniflare, convertV4MiniflareOptions } from "miniflare";import { mkdtemp, rm } from "node:fs/promises";import { tmpdir } from "node:os";import { join } from "node:path";import { setTimeout as delay } from "node:timers/promises";
const defaults = { execute: "ask", network: "never", workspaceRead: "never", workspaceWrite: "never", externalCapabilities: "never",};const allow = Object.fromEntries( Object.keys(defaults).map((key) => [key, "allow"]),);const identity = (skill) => ({ source: "installed", name: skill.name, fingerprint: skill.fingerprint, revision: skill.revision,});const external = { source: { kind: "mcp", id: "fixture-server" }, id: "a".repeat(64), fingerprint: "b".repeat(64),};const envelope = (permissions, version = "1.0.0") => ({ formatVersion: 1, files: [ { path: "SKILL.md", content: `---\nname: permission-guide\ndescription: A permission fixture\nmetadata:\n version: "${version}"\nallowed-tools: "untrusted tool claim"\n---\nUse the fixture script.`, }, { path: "scripts/run.js", content: "export default async () => 'inert fixture';", }, ...(permissions === undefined ? [] : [ { path: "permissions.json", content: typeof permissions === "string" ? permissions : JSON.stringify(permissions), }, ]), ],});
test( "Skill permissions use native durable storage and invocation authority", { timeout: 90_000 }, async (t) => { let worker; let persistence; let cleanup; const dispose = () => (cleanup ??= (async () => { let timeout; try { await Promise.race([ worker?.dispose(), new Promise((_, reject) => { timeout = setTimeout( () => reject( new Error("Native permission fixture cleanup timed out"), ), 10_000, ); }), ]); } finally { clearTimeout(timeout); } if (persistence) await rm(persistence, { recursive: true, force: true }); })()); t.after(dispose); t.signal.addEventListener( "abort", () => { void dispose(); }, { once: true }, ); const bundle = await build({ entryPoints: ["tests/fixtures/skill-permissions-worker.ts"], alias: { path: "node:path" }, target: "es2022", bundle: true, write: false, format: "esm", platform: "neutral", conditions: ["workerd", "worker", "browser"], mainFields: ["module", "main"], external: ["cloudflare:*", "node:*"], }); t.signal.throwIfAborted(); persistence = await mkdtemp(join(tmpdir(), "flarebot-skill-permissions-")); if (t.signal.aborted) { await rm(persistence, { recursive: true, force: true }); t.signal.throwIfAborted(); } const options = { ...convertV4MiniflareOptions({ modules: true, script: bundle.outputFiles[0].text, compatibilityDate: "2026-09-04", compatibilityFlags: ["nodejs_compat"], durableObjects: { MODEL: { className: "SkillPermissionsFixture", useSQLite: true }, }, r2Buckets: ["PACKAGES"], }), resourcePersistencePath: persistence, }; worker = new Miniflare(options); const raw = async (action, value, owner = "alice") => { t.signal.throwIfAborted(); const response = await worker.dispatchFetch( `https://fixture.example/${owner}`, { method: "POST", body: JSON.stringify({ action, value }), signal: t.signal, }, ); return { status: response.status, body: await response.json() }; }; const call = async (action, value, owner) => { const { body } = await raw(action, value, owner); assert.equal(body.ok, true, JSON.stringify(body)); return body.value; }; const manage = async (value, owner) => { const result = await raw("manage", value, owner); assert.equal(result.status, 200, JSON.stringify(result)); return result.body; }; const permissions = async (skill, owner) => (await manage({ action: "permissions", skill: identity(skill) }, owner)) .permissions; const set = async (skill, choices, owner) => { const previous = await permissions(skill, owner); return ( await manage( { action: "set-permissions", skill: identity(skill), revision: previous.revision, choices, }, owner, ) ).permissions; }; const install = (contents, skill, owner) => call( "install", { envelope: contents, revision: skill?.revision ?? null }, owner, ); const toggle = async (skill, enabled, owner) => (await call("toggle", { ...identity(skill), enabled }, owner)).find( (item) => item.name === skill.name, ); const describe = (skill, owner) => call( "describe", { skill: identity(skill), path: "scripts/run.js" }, owner, ); const runRequest = async (skill, owner) => { const { id, fingerprint, source } = await describe(skill, owner); return { skill: identity(skill), path: "scripts/run.js", capability: { id, fingerprint, source }, }; }; const run = async (skill, options = {}, owner) => call( "run", { request: await runRequest(skill, owner), ...options }, owner, ); const rejected = (value) => assert.equal(typeof value?.failure, "string", JSON.stringify(value)); const waitHeld = async (owner) => { const deadline = Date.now() + 5000; while (!(await call("metrics", undefined, owner)).waiting) { assert.ok( Date.now() < deadline, "native host operation did not reach gate", ); await delay(10, undefined, { signal: t.signal }); } };
await t.test( "canonical requirements are strict, inert and fingerprinted", async () => { const plain = await call("validate", envelope()); assert.deepEqual(plain.permissions, { network: false, workspace: "none", externalCapabilities: [], }); const declared = await call( "validate", envelope({ network: true, workspace: "read-write", externalCapabilities: [external], }), ); assert.deepEqual(declared.permissions, { network: true, workspace: "read-write", externalCapabilities: [external], }); assert.notEqual(plain.fingerprint, declared.fingerprint); const reordered = envelope({ network: true, workspace: "read-write", externalCapabilities: [external], }); reordered.files.reverse(); assert.equal( (await call("validate", reordered)).fingerprint, declared.fingerprint, ); for (const invalid of [ "{", "null", "[]", { network: "yes" }, { workspace: "write" }, { execute: true }, { network: true, extra: true }, { externalCapabilities: [external, external] }, { externalCapabilities: [{ ...external, approvedOnce: true }] }, { externalCapabilities: Array.from({ length: 9 }, (_, i) => ({ ...external, id: i.toString().padStart(64, "0"), })), }, ]) { const response = await raw("validate", envelope(invalid)); assert.equal(response.body.ok, false, JSON.stringify(invalid)); assert.equal(response.body.error, "invalid_permissions"); } const unicodeDeclaration = JSON.stringify({ externalCapabilities: Array.from({ length: 8 }, (_, i) => ({ ...external, source: { kind: "mcp", id: "界".repeat(200) }, id: i.toString().padStart(64, "0"), })), }) + " ".repeat(2048); assert.ok(unicodeDeclaration.length < 8192); assert.ok(Buffer.byteLength(unicodeDeclaration) > 8192); assert.equal( (await raw("validate", envelope(unicodeDeclaration))).body.error, "invalid_permissions", ); const encoded = envelope({ network: true }); encoded.files.at(-1).encoding = "base64"; encoded.files.at(-1).content = Buffer.from( encoded.files.at(-1).content, ).toString("base64"); assert.equal((await raw("validate", encoded)).body.ok, false); assert.equal( (await call("metrics")).writes, 0, "validation never installs or runs scripts", ); }, );
await t.test( "owner policy updates use CAS, persist, remain bounded, and reset with installation identity", async () => { let skill = await install(envelope()); assert.equal(skill.enabled, false); assert.deepEqual(await permissions(skill), { revision: 0, choices: defaults, audit: [], }); const before = await call("metrics"); const updated = await set(skill, allow); assert.deepEqual(updated.choices, allow); assert.deepEqual(updated.audit[0].before, defaults); assert.deepEqual(updated.audit[0].after, allow); assert.ok(Number.isFinite(Date.parse(updated.audit[0].timestamp))); assert.deepEqual( await set(skill, allow), updated, "identical save does not manufacture audit history", ); assert.deepEqual( await call("metrics"), before, "permission metadata and saves use SQLite only", ); const stale = await raw("manage", { action: "set-permissions", skill: identity(skill), revision: 0, choices: defaults, }); assert.equal(stale.status, 409); assert.equal(stale.body.error.code, "skill_permissions_changed"); const malformed = await raw("manage", { action: "set-permissions", skill: identity(skill), revision: updated.revision, choices: { ...allow, network: true }, }); assert.equal(malformed.status, 400); const old = skill; skill = await toggle(skill, true); skill = await toggle(skill, false); assert.deepEqual( await permissions(skill), updated, "enablement edits preserve permission choices", ); assert.equal( (await raw("manage", { action: "permissions", skill: identity(old) })) .status, 409, ); assert.equal( ( await raw( "manage", { action: "permissions", skill: identity(skill) }, "bob", ) ).status, 409, ); await worker.dispose(); worker = new Miniflare(options); assert.deepEqual(await permissions(skill), updated); for (let i = 0; i < 260; i++) await set(skill, { ...allow, network: i % 2 ? "allow" : "ask" }); const bounded = await permissions(skill); assert.equal(bounded.audit.length, 20); assert.equal(await call("audit-count"), 256); assert.ok( bounded.audit.every( (entry, i, list) => i === 0 || entry.revision < list[i - 1].revision, ), ); skill = await install(envelope(undefined, "1.0.1"), skill); assert.deepEqual(await permissions(skill), { revision: 0, choices: defaults, audit: [], }); await set(skill, allow); const removed = skill; await manage({ action: "remove", skill: identity(skill) }); skill = await install(envelope(undefined, "1.0.1")); assert.equal(skill.fingerprint, removed.fingerprint); assert.notEqual(skill.revision, removed.revision); assert.deepEqual(await permissions(skill), { revision: 0, choices: defaults, audit: [], }); assert.equal( ( await raw("manage", { action: "permissions", skill: identity(removed), }) ).status, 409, ); }, );
await t.test( "execution gates exact capabilities and denies undeclared operations before side effects", async () => { let skill = await install(envelope(), undefined, "runtime"); assert.equal(await describe(skill, "runtime"), null); skill = await toggle(skill, true, "runtime"); assert.equal((await describe(skill, "runtime")).approval, "ask"); rejected(await run(skill, {}, "runtime")); assert.equal((await call("metrics", undefined, "runtime")).effects, 0); assert.equal( await run(skill, { approvedOnce: true }, "runtime"), "committed", ); const request = await runRequest(skill, "runtime"); rejected( await call( "run", { request: { ...request, capability: { ...request.capability, fingerprint: "c".repeat(64), }, }, approvedOnce: true, }, "runtime", ), ); rejected( await call( "run", { request: { ...request, path: "scripts/other.js" }, approvedOnce: true, }, "runtime", ), ); await set(skill, allow, "runtime"); for (const permission of [ "network", "workspaceRead", "workspaceWrite", "externalCapabilities", ]) rejected( await run( skill, { permission, approvedOnce: true, external }, "runtime", ), ); assert.equal( (await call("metrics", undefined, "runtime")).effects, 1, "owner Allow cannot exceed package declarations", ); await set(skill, { ...allow, execute: "never" }, "runtime"); rejected(await run(skill, { approvedOnce: true }, "runtime")); await set(skill, allow, "runtime"); assert.equal( await run(skill, { captureOnly: true }, "runtime"), "captured", ); assert.equal( (await raw("saved", { permission: "execute" }, "runtime")).body.ok, false, "completed invocation releases its grant", ); rejected(await run(skill, { preabort: true }, "runtime")); const diagnostics = await call("diagnostics", undefined, "runtime"); assert.ok( diagnostics.some( (event) => event.kind === "approval" && event.status === "pending", ), ); assert.ok( diagnostics.some( (event) => event.kind === "approval" && event.status === "succeeded", ), ); assert.ok(!JSON.stringify(diagnostics).includes("fixture-private")); }, );
await t.test( "shared source policy composes with all five declared categories", async () => { let skill = await install( envelope({ network: true, workspace: "read-write", externalCapabilities: [external], }), undefined, "shared", ); skill = await toggle(skill, true, "shared"); await call( "external", { ...external, name: "External", sourceName: "Server", actionSummary: "External action", enabled: true, approval: "allow", }, "shared", ); assert.equal( (await describe(skill, "shared")).approval, "never", "new required host permissions default Never", ); rejected(await run(skill, { approvedOnce: true }, "shared")); await set(skill, { ...allow, workspaceWrite: "ask" }, "shared"); assert.equal((await describe(skill, "shared")).approval, "ask"); rejected(await run(skill, { permission: "workspaceWrite" }, "shared")); for (const permission of Object.keys(allow)) assert.equal( await run( skill, { permission, approvedOnce: true, external }, "shared", ), "committed", ); const source = (await describe(skill, "shared")).source; let policy = await call("policy", undefined, "shared"); await call( "policy", { ...policy, sourceOverrides: [{ source, policy: "never" }] }, "shared", ); rejected(await run(skill, { approvedOnce: true }, "shared")); policy = await call("policy", undefined, "shared"); await call( "policy", { ...policy, sourceOverrides: [{ source, policy: "allow" }] }, "shared", ); assert.equal( await run(skill, { permission: "network" }, "shared"), "committed", ); await set(skill, { ...allow, network: "never" }, "shared"); rejected( await run(skill, { approvedOnce: true }, "shared"), "category Never cannot be relaxed by source Allow", ); }, );
await t.test( "held host work loses authority on cancellation, permission/global edits and disable", async () => { let skill = await install( envelope({ network: true, workspace: "read-write" }), undefined, "races", ); skill = await toggle(skill, true, "races"); await set(skill, allow, "races"); for (const revoke of [ "cancel", "permissions", "global", "disable", "replacement", ]) { const pending = run( skill, { hold: true, permission: "workspaceWrite" }, "races", ); await waitHeld("races"); if (revoke === "cancel") await call("cancel", undefined, "races"); if (revoke === "permissions") await set(skill, { ...allow, network: "ask" }, "races"); if (revoke === "global") { const policy = await call("policy", undefined, "races"); await call( "policy", { ...policy, defaultPolicy: "never" }, "races", ); } if (revoke === "disable") skill = await toggle(skill, false, "races"); if (revoke === "replacement") skill = await install( envelope({ network: true, workspace: "read-write" }, "1.0.1"), skill, "races", ); await call("release", undefined, "races"); rejected(await pending); assert.equal( (await call("metrics", undefined, "races")).effects, 0, `${revoke} prevents late commit`, ); if (!skill.enabled) skill = await toggle(skill, true, "races"); await set(skill, allow, "races"); } assert.equal( await run(skill, { permission: "workspaceRead" }, "races"), "committed", ); }, );
await t.test( "canonical MCP choices, disable, reconnect and wake advance Skill authority", async () => { const { removed, observations, legacyEpoch, ...snapshots } = await call( "mcp-authority", undefined, "mcp-lifecycle", ); const values = Object.values(snapshots); assert.equal( new Set(values.map((value) => value.revision)).size, values.length, ); assert.equal( new Set(values.map((value) => value.metadata.fingerprint)).size, 1, "owner choices never enter the declared definition fingerprint", ); assert.equal(snapshots.initial.metadata.approval, "allow"); assert.equal(snapshots.denied.metadata.approval, "never"); assert.equal(snapshots.restored.metadata.approval, "allow"); assert.equal(snapshots.disabled.metadata.enabled, false); assert.equal(snapshots.reenabled.metadata.enabled, true); assert.equal(snapshots.reconnected.metadata.enabled, true); assert.equal(snapshots.awakened.metadata.enabled, false); assert.equal(removed, null); assert.equal( legacyEpoch, 0, "existing documents decode with the initial authority epoch", ); assert.equal( observations.repeated.revision, snapshots.initial.revision, "identical ready observations preserve a live grant", ); assert.equal(observations.staleAccepted, false); assert.equal( observations.stale.revision, snapshots.initial.revision, "rejected stale observations cannot advance authority", ); assert.notEqual( observations.changed.revision, snapshots.initial.revision, ); assert.notEqual( observations.returned.revision, snapshots.initial.revision, "restoring the old definitions cannot restore old authority", ); assert.equal( observations.returned.metadata.fingerprint, snapshots.initial.metadata.fingerprint, ); }, );
await t.test( "downstream authority restoration cannot revive held writes or release late reads", async () => { const owner = "external-lifetime"; let skill = await install( envelope({ externalCapabilities: [external] }), undefined, owner, ); skill = await toggle(skill, true, owner); await set(skill, allow, owner); const metadata = { ...external, name: "External lifetime fixture", sourceName: "Fixture MCP", actionSummary: "Perform external action", enabled: true, approval: "allow", }; for (const change of [{ approval: "never" }, { enabled: false }]) { await call("external", metadata, owner); const held = run( skill, { permission: "externalCapabilities", external, hold: true }, owner, ); await waitHeld(owner); await call("external", { ...metadata, ...change }, owner); await call("external", metadata, owner); await call("release", undefined, owner); rejected( await held, "restoring downstream settings must require fresh invocation authority", ); assert.equal((await call("metrics", undefined, owner)).effects, 0); } const delayedRead = run( skill, { permission: "externalCapabilities", external, hold: true, rawRead: true, }, owner, ); await waitHeld(owner); await call("external", { ...metadata, approval: "never" }, owner); await call("external", metadata, owner); await call("release", undefined, owner); rejected( await delayedRead, "wrapper must suppress a raw read without an internal check", ); assert.equal((await call("metrics", undefined, owner)).effects, 0); const failedCheck = run(skill, { hold: true }, owner); await waitHeld(owner); assert.equal( (await raw("saved", { permission: "network" }, owner)).body.ok, false, ); await call("release", undefined, owner); rejected( await failedCheck, "a caught undeclared-access failure must permanently retire the grant", ); assert.equal((await call("metrics", undefined, owner)).effects, 0); assert.equal( await run( skill, { permission: "externalCapabilities", external }, owner, ), "committed", "fresh admission after restoration may run", ); }, );
await t.test( "external capability admission keeps downstream Ask and Never independent", async () => { let skill = await install( envelope({ externalCapabilities: [external] }), undefined, "external", ); skill = await toggle(skill, true, "external"); await set(skill, allow, "external"); const metadata = { ...external, name: "Private external tool", sourceName: "Fixture MCP", actionSummary: "Perform external action", enabled: true, approval: "ask", }; await call("external", metadata, "external"); rejected( await run( skill, { permission: "externalCapabilities", external, approvedOnce: true, }, "external", ), ); await call("external", { ...metadata, approval: "never" }, "external"); rejected( await run( skill, { permission: "externalCapabilities", external, approvedOnce: true, }, "external", ), ); await call("external", { ...metadata, approval: "allow" }, "external"); rejected( await run( skill, { permission: "externalCapabilities", external: { ...external, fingerprint: "d".repeat(64) }, }, "external", ), ); assert.equal((await call("metrics", undefined, "external")).effects, 0); assert.equal( await run( skill, { permission: "externalCapabilities", external }, "external", ), "committed", ); const held = run( skill, { permission: "externalCapabilities", external, hold: true }, "external", ); await waitHeld("external"); await call("external", { ...metadata, approval: "never" }, "external"); await call("release", undefined, "external"); rejected(await held); assert.equal( (await call("metrics", undefined, "external")).effects, 1, "downstream revocation prevents a held host commit", ); await call( "external", { ...metadata, approval: "allow", enabled: false }, "external", ); rejected( await run( skill, { permission: "externalCapabilities", external }, "external", ), ); assert.equal((await call("metrics", undefined, "external")).effects, 1); }, ); },);