Files
Void-Homelab/tests/ai/agent/tools/read_scope.test.js
2026-06-04 20:07:22 +10:00

36 lines
1.7 KiB
JavaScript

import { describe, it, expect, beforeAll } from 'vitest';
import { pool } from '../../../../lib/db/pool.js';
import { resetDb } from '../../../helpers/db.js';
import { migrateUp } from '../../../../lib/db/migrate.js';
import { readTool } from '../../../../lib/ai/agent/tools/read.js';
let spaceA, spaceB, pageInA, convoId;
beforeAll(async () => {
await resetDb(); await migrateUp();
({ rows: [{ id: spaceA }] } = await pool.query(`INSERT INTO spaces(slug,name) VALUES('a','A') RETURNING id`));
({ rows: [{ id: spaceB }] } = await pool.query(`INSERT INTO spaces(slug,name) VALUES('b','B') RETURNING id`));
({ rows: [{ id: pageInA }] } = await pool.query(
`INSERT INTO pages(space_id,slug,title,body_md) VALUES($1,'p','P','body') RETURNING id`, [spaceA]));
({ rows: [{ id: convoId }] } = await pool.query(
`INSERT INTO conversations(title) VALUES('c') RETURNING id`));
});
describe('read tool space scoping', () => {
it('reads an in-space page', async () => {
const out = await readTool.handler({ kind: 'page', id: pageInA }, { space_id: spaceA });
expect(out.title).toBe('P');
});
it('blocks a cross-space page (scoped caller)', async () => {
const out = await readTool.handler({ kind: 'page', id: pageInA }, { space_id: spaceB });
expect(out.error).toMatch(/not found/i);
});
it('blocks unprovable kinds (conversation) for spaceScoped callers', async () => {
const out = await readTool.handler({ kind: 'conversation', id: convoId }, { space_id: spaceA, spaceScoped: true });
expect(out.error).toMatch(/not found/i);
});
it('owner (no space bound) reads anything', async () => {
const out = await readTool.handler({ kind: 'page', id: pageInA }, {});
expect(out.title).toBe('P');
});
});