// Phase B: org records carry each grouped repo's tracker bootstrap key
// (resourceKeys) so a peer that joins the org can mount exactly those
// repos (scoped). These tests cover the schema apply + addResource API:
// store-with-key, name-only, backfill, remove, and cross-org reassignment.
import test from 'brittle'
import Corestore from 'corestore'
import { mkdtempSync } from 'fs'
import { join } from 'path'
import { tmpdir } from 'os'
import { HyperOrgs } from '../index.js'
function tmpStore () {
return new Corestore(mkdtempSync(join(tmpdir(), 'hyperorgs-rk-')))
}
async function makeOrgs (t, namespace = 'rk') {
const store = tmpStore()
const orgs = new HyperOrgs(store, { namespace })
await orgs.ready()
t.teardown(async () => {
try { await orgs.close() } catch {}
try { await store.close() } catch {}
})
return orgs
}
const KEY_A = 'a'.repeat(64)
const KEY_B = 'b'.repeat(64)
test('new org record initialises resourceKeys to {}', async (t) => {
const orgs = await makeOrgs(t, 'rk-1')
const org = await orgs.create('team', 'group')
t.alike(org.resourceKeys, {}, 'resourceKeys present and empty')
})
test('addResource with a bootstrapKey records it under resourceKeys', async (t) => {
const orgs = await makeOrgs(t, 'rk-2')
await orgs.create('team', 'group')
const org = await orgs.addResource('team', 'repo-1', { bootstrapKey: KEY_A })
t.alike(org.resources, ['repo-1'])
t.is(org.resourceKeys['repo-1'], KEY_A, 'key stored')
})
test('addResource without a key adds the name only (no key)', async (t) => {
const orgs = await makeOrgs(t, 'rk-3')
await orgs.create('team', 'group')
const org = await orgs.addResource('team', 'repo-1')
t.alike(org.resources, ['repo-1'])
t.absent(org.resourceKeys['repo-1'], 'no key for a name-only add')
})
test('re-adding with a key backfills a name-only entry', async (t) => {
const orgs = await makeOrgs(t, 'rk-4')
await orgs.create('team', 'group')
await orgs.addResource('team', 'repo-1') // name only (repo not created yet)
const org = await orgs.addResource('team', 'repo-1', { bootstrapKey: KEY_A })
t.alike(org.resources, ['repo-1'], 'no duplicate name')
t.is(org.resourceKeys['repo-1'], KEY_A, 'key backfilled')
})
test('removeResource drops both the name and the key', async (t) => {
const orgs = await makeOrgs(t, 'rk-5')
await orgs.create('team', 'group')
await orgs.addResource('team', 'repo-1', { bootstrapKey: KEY_A })
const org = await orgs.removeResource('team', 'repo-1')
t.alike(org.resources, [])
t.absent(org.resourceKeys['repo-1'], 'key removed with the name')
})
test('each org keeps its own key — no cross-org uniqueness in the per-org model', async (t) => {
// Under #37 each org is its OWN autobase, so the cross-org "remove from
// other orgs" scan in add-resource only sees the current org's view. A
// repo can therefore belong to two orgs independently, each carrying its
// own resourceKeys entry. (Cross-org uniqueness was a property of the old
// single-orgs-autobase model; it does not hold here, and that's fine for
// the grouped-repos feature — each org lists + keys its own repos.)
const orgs = await makeOrgs(t, 'rk-6')
await orgs.create('team-a', 'group')
await orgs.create('team-b', 'group')
await orgs.addResource('team-a', 'repo-1', { bootstrapKey: KEY_A })
await orgs.addResource('team-b', 'repo-1', { bootstrapKey: KEY_B })
const a = await orgs.get('team-a')
const b = await orgs.get('team-b')
t.is(a.resourceKeys['repo-1'], KEY_A, 'team-a keeps its own key')
t.is(b.resourceKeys['repo-1'], KEY_B, 'team-b keeps its own key')
})