Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| The docs service answers every artifacts call: docs can be made, listed, shared, moved, trashed, restored, searched, versioned and edited live in their own rooms, agents read, write and recall them only where their person and everyone in the conversation can, and folio events go out on the bus, while Docs' pages keep working as before. | 1 | import assert from "node:assert/strict"; |
| 2 | import { test } from "node:test"; | |
| 3 | ||
| 4 | import { aclChain, type FolioAclNode, type FolioGrant, type Person, type SpaceRules } from "../access.ts"; | |
| 5 | import { agentMayFind, agentReach, audienceRule, type AudienceRule } from "./agents.ts"; | |
| 6 | ||
| The docs folder is gone, and what it held lives where people read it: how a self-hosted g1t runs and how to deploy g1t to Cloudflare are pages on docs.g1t.sh under Run g1t yourself, and speed, rate limits and operating g1t.sh are sections of CONTRIBUTING.md; code that cited a file in docs/ now points to the page or section that covers it, or says what it means itself, and applied migrations and the runner images are left as they were. | 7 | // The leak rules (docs.g1t.sh/guides/agent-access/). |
| The docs service answers every artifacts call: docs can be made, listed, shared, moved, trashed, restored, searched, versioned and edited live in their own rooms, agents read, write and recall them only where their person and everyone in the conversation can, and folio events go out on the bus, while Docs' pages keep working as before. | 8 | |
| 9 | const ana: Person = { user_id: "ana", owner: false, teams: new Set(["web"]) }; | |
| 10 | const bo: Person = { user_id: "bo", owner: false, teams: new Set() }; | |
| 11 | const cy: Person = { user_id: "cy", owner: false, teams: new Set(["web"]) }; | |
| 12 | ||
| 13 | const open: SpaceRules = { kind: "workspace", team: null, default_role: "edit", members: [] }; | |
| 14 | const team: SpaceRules = { kind: "team", team: "web", default_role: "edit", members: [] }; | |
| 15 | ||
| 16 | function node(id: string, over: Partial<FolioAclNode> = {}): FolioAclNode { | |
| 17 | return { id, owner: "user:ana", parent_id: null, space_id: null, inherit: true, general_access: "none", general_role: null, ...over }; | |
| 18 | } | |
| 19 | ||
| 20 | function reach(n: FolioAclNode, grants: Record<string, FolioGrant[]>, space: SpaceRules | null, rule: AudienceRule, people: Person[] = [], visits: string[] = [], asker = ana) { | |
| 21 | return agentReach({ | |
| 22 | chain: aclChain(n.id, new Map([[n.id, n]])), | |
| 23 | grants: new Map(Object.entries(grants)), | |
| 24 | space, | |
| 25 | asker, | |
| 26 | askerVisited: visits.includes(asker.user_id), | |
| 27 | rule, | |
| 28 | people, | |
| 29 | visited: (p) => visits.includes(p.user_id), | |
| 30 | agent_mode: "edit", | |
| 31 | }); | |
| 32 | } | |
| 33 | ||
| 34 | test("audience rules: none or only the asker is the asker; more than 20 people is the workspace", () => { | |
| 35 | assert.deepEqual(audienceRule(null, "ana"), { kind: "asker" }); | |
| 36 | assert.deepEqual(audienceRule({ kind: "people", user_ids: ["ana"] }, "ana"), { kind: "asker" }); | |
| 37 | assert.deepEqual(audienceRule({ kind: "people", user_ids: ["ana", "bo", "bo"] }, "ana"), { kind: "people", user_ids: ["bo"] }); | |
| 38 | assert.deepEqual(audienceRule({ kind: "workspace" }, "ana"), { kind: "workspace" }); | |
| 39 | const crowd = Array.from({ length: 21 }, (_, i) => `u${i}`); | |
| 40 | assert.deepEqual(audienceRule({ kind: "people", user_ids: crowd }, "ana"), { kind: "workspace" }); | |
| 41 | const twenty = Array.from({ length: 19 }, (_, i) => `u${i}`); | |
| 42 | assert.equal(audienceRule({ kind: "people", user_ids: twenty }, "ana").kind, "people"); | |
| 43 | }); | |
| 44 | ||
| 45 | test("rule 1: a public channel finds only open-space and workspace-wide folios", () => { | |
| 46 | const ws: AudienceRule = { kind: "workspace" }; | |
| 47 | assert.equal(agentMayFind(reach(node("a", { space_id: "open" }), {}, open, ws)), true); | |
| 48 | assert.equal(agentMayFind(reach(node("a", { general_access: "workspace", general_role: "view" }), {}, null, ws)), true); | |
| 49 | // Private, shared, team, link: never in a public channel. | |
| 50 | assert.equal(agentMayFind(reach(node("a"), {}, null, ws)), false); | |
| 51 | assert.equal(agentMayFind(reach(node("a"), { a: [{ principal: "user:bo", role: "view" }] }, null, ws)), false); | |
| 52 | assert.equal(agentMayFind(reach(node("a", { space_id: "team" }), {}, team, ws)), false); | |
| 53 | assert.equal(agentMayFind(reach(node("a", { general_access: "link", general_role: "view" }), {}, null, ws, [], ["ana"])), false); | |
| 54 | }); | |
| 55 | ||
| 56 | test("rule 1: a conversation finds only what everyone in it can read", () => { | |
| 57 | const withBo: AudienceRule = { kind: "people", user_ids: ["bo"] }; | |
| 58 | const shared = node("a"); | |
| 59 | assert.equal(agentMayFind(reach(shared, { a: [{ principal: "user:bo", role: "view" }] }, null, withBo, [bo])), true); | |
| 60 | assert.equal(agentMayFind(reach(shared, {}, null, withBo, [bo])), false); | |
| 61 | // A team space: Cy is in the team, Bo isn't. | |
| 62 | const t = node("t", { space_id: "team" }); | |
| 63 | assert.equal(agentMayFind(reach(t, {}, team, { kind: "people", user_ids: ["cy"] }, [cy])), true); | |
| 64 | assert.equal(agentMayFind(reach(t, {}, team, withBo, [bo])), false); | |
| 65 | // A link folio: only when everyone opened it. | |
| 66 | const link = node("l", { general_access: "link", general_role: "view" }); | |
| 67 | assert.equal(agentMayFind(reach(link, {}, null, withBo, [bo], ["ana"])), false); | |
| 68 | assert.equal(agentMayFind(reach(link, {}, null, withBo, [bo], ["ana", "bo"])), true); | |
| 69 | }); | |
| 70 | ||
| 71 | test("rule 1: the asker's own Private is theirs alone", () => { | |
| 72 | assert.equal(agentMayFind(reach(node("p"), {}, null, { kind: "asker" })), true); | |
| 73 | assert.equal(agentMayFind(reach(node("p"), {}, null, { kind: "people", user_ids: ["bo"] }, [bo])), false); | |
| 74 | // Someone else's Private: not even for its asker. | |
| 75 | assert.equal(agentMayFind(reach(node("p", { owner: "user:bo" }), {}, null, { kind: "asker" })), false); | |
| 76 | }); | |
| 77 | ||
| 78 | test("rule 2: reading what the audience can't all read says so", () => { | |
| 79 | const r = reach(node("p"), {}, null, { kind: "workspace" }); | |
| 80 | assert.equal(r.asker_role, "manage"); | |
| 81 | assert.equal(r.audience_can_read, false); | |
| 82 | const fine = reach(node("o", { space_id: "open" }), {}, open, { kind: "workspace" }); | |
| 83 | assert.equal(fine.audience_can_read, true); | |
| 84 | }); | |
| 85 | ||
| 86 | test("an agent's grant never widens what it can do for its asker", () => { | |
| 87 | const n = node("f", { owner: "user:cy" }); | |
| 88 | const grants = { f: [{ principal: "agent:ag1", role: "manage" as const }, { principal: "user:bo", role: "comment" as const }] }; | |
| 89 | const r = reach(n, grants, null, { kind: "asker" }, [], [], bo); | |
| 90 | assert.equal(r.asker_role, "comment"); | |
| 91 | assert.deepEqual(r.can, { read: true, suggest: true, edit: false }); | |
| 92 | const none = reach(n, grants, null, { kind: "asker" }, [], [], ana); | |
| 93 | assert.equal(none.asker_role, null); | |
| 94 | assert.deepEqual(none.can, { read: false, suggest: false, edit: false }); | |
| 95 | assert.equal(agentMayFind(none), false); | |
| 96 | }); |