maestro/src/bridge/local-orgs.integration.test.ts
oss-sync 454d6f957b
Some checks failed
CI / build-and-test (push) Has been cancelled
sync: update from private repo (caeb95c)
2026-06-09 12:59:57 +00:00

76 lines
3.2 KiB
TypeScript

/**
* End-to-end: a local-org member sees 'org'-scoped resources; a non-member
* does not. Validates the whole chain — local org membership → resolveOrgIds
* → session.orgIds → the provider-agnostic buildVisibilityWhere.
*
* See docs/superpowers/plans/2026-06-09-local-orgs.md.
*/
import { afterEach, beforeEach, describe, it, expect } from 'vitest';
import { mkdtempSync, rmSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { Repository } from '../db/repository.js';
import { runMigrations } from '../db/migrate.js';
import { resolveOrgIds } from './auth.js';
function viewer(id: string, orgIds: string[]): Express.User {
return {
id, email: `${id}@x.com`, name: id, avatarUrl: null,
role: 'user', status: 'active', orgIds,
defaultVisibility: 'private', defaultVisibilityOrgId: null,
};
}
describe('local orgs — org visibility E2E', () => {
let tempDir = '';
let repo: Repository;
beforeEach(() => {
tempDir = mkdtempSync(join(tmpdir(), 'maestro-orgvis-'));
repo = new Repository(join(tempDir, 'orchestrator.db'));
runMigrations(repo.getDb());
});
afterEach(() => {
repo.close();
if (tempDir) { rmSync(tempDir, { recursive: true, force: true }); tempDir = ''; }
});
it('resolveOrgIds includes the local orgs a user belongs to', () => {
const alice = repo.createUser({ email: 'a@x.com', name: 'A', role: 'user', status: 'active' }).id;
const org = repo.createLocalOrg('Team', alice);
repo.addOrgMember(org.id, alice);
expect(resolveOrgIds(repo, alice)).toContain(org.id);
});
it('an org member sees an org-scoped task; a non-member does not', async () => {
const carol = repo.createUser({ email: 'carol@x.com', name: 'Carol', role: 'user', status: 'active' }).id;
const alice = repo.createUser({ email: 'alice@x.com', name: 'Alice', role: 'user', status: 'active' }).id;
const bob = repo.createUser({ email: 'bob@x.com', name: 'Bob', role: 'user', status: 'active' }).id;
const org = repo.createLocalOrg('Team', carol);
repo.addOrgMember(org.id, carol);
repo.addOrgMember(org.id, alice); // alice is a member, bob is not
await repo.createLocalTask({
title: 'org task', body: 'b', ownerId: carol,
visibility: 'org', visibilityScopeOrgId: org.id,
});
const aliceTasks = await repo.listLocalTasks({ viewer: viewer(alice, resolveOrgIds(repo, alice)) });
const bobTasks = await repo.listLocalTasks({ viewer: viewer(bob, resolveOrgIds(repo, bob)) });
expect(aliceTasks.some(t => t.title === 'org task')).toBe(true); // member sees it
expect(bobTasks.some(t => t.title === 'org task')).toBe(false); // non-member does not
});
it('the org name resolves on display after the COALESCE extension', async () => {
const carol = repo.createUser({ email: 'c@x.com', name: 'C', role: 'user', status: 'active' }).id;
const org = repo.createLocalOrg('Engineering', carol);
repo.addOrgMember(org.id, carol);
const t = await repo.createLocalTask({
title: 'x', body: 'b', ownerId: carol, visibility: 'org', visibilityScopeOrgId: org.id,
});
const got = await repo.getLocalTask(t.id, { viewer: viewer(carol, resolveOrgIds(repo, carol)) });
expect(got?.visibilityScopeOrgName).toBe('Engineering');
});
});