OverviewFilesCommitsIssuesDocsReleasesPeers

hyper-proto-peer / test / labeler-did.test.js

80 lines · javascript ref:
// A LABELER DID end to end in the daemon (member labels, hyper-social #80 step 2).
//
// `labeler: true` on a DID's config entry hosts a LabelRoom on that DID's StateBase, signed with the DID
// key on the node the repo signer election picks. A label-intent on the local socket must come out as a
// verified label in the membrane's served label core (named in the announce) — and must NOT enter the
// signed repo: an intent on a post URI has a "/" and would otherwise list as a record.
//
// Run: bare test/labeler-did.test.js
import '../lib/bare-globals.js'
import test from 'brittle'
import fs from 'bare-fs'
import b4a from 'b4a'
import createTestnet from '@hyperswarm/testnet'
import { Client } from 'hyper-svc'
import { bootMultiDevice, provisionDevice } from '../lib/device-node.js'
import { deviceKeetKeyPair } from 'atproto-room/lib/membership.js'
import { keyFromPrivate } from 'atproto-identity/lib/atproto-identity.js'
import { decodeLabel, verifyLabel } from 'atproto-identity/lib/labels.js'

const ROOT = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
const DEV = 'legal winner thank year wave sausage worth useful legal winner thank yellow'
const tmp = () => { const d = '/tmp/hpp-lab-' + Math.floor(Math.random() * 1e9); fs.mkdirSync(d, { recursive: true }); return d }
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms))
const waitFor = async (fn, timeout = 30000) => { const end = Date.now() + timeout; while (Date.now() < end) { if (await fn()) return true; await sleep(200) } return false }

async function boot (t, { labeler }) {
  const testnet = await createTestnet(3)
  const dk = await deviceKeetKeyPair(DEV)
  const b = await provisionDevice({ rootMnemonic: ROOT, devicePublicKey: dk.publicKey, handle: 'lc.local', pdsUrl: 'https://pds.local' })
  const entry = { deviceMnemonic: DEV, did: b.did, signingKey: b.signingKey, deviceProof: b.deviceProof, rootIdentityKey: b.rootIdentityKey, handle: 'lc.local', labeler }
  const n = await bootMultiDevice({ storage: tmp(), dids: [entry], swarmOpts: { bootstrap: testnet.bootstrap } })
  const node = n.byDid.get(b.did)
  const c = await Client.connectUds(node.uds)
  t.teardown(async () => { try { await c.close() } catch {} ; try { await n.close() } catch {} ; await testnet.destroy() })
  return { node, c, did: b.did, signingKey: b.signingKey }
}

test('★ labeler DID: label-intent → a verified label in the served label core, never a repo record', { timeout: 120000 }, async (t) => {
  const { node, c, did, signingKey } = await boot(t, { labeler: true })
  const POST = 'at://did:plc:wj62ebbusln6gxo5azo6ogzo/app.bsky.feed.post/3mrhxnkbhv622'
  const MEMBER = 'did:plc:wj62ebbusln6gxo5azo6ogzo'

  t.ok(node.membrane.labelKey, 'the membrane serves a label core')
  t.is(node.membrane.announcement().labelKey, node.membrane.labelKey, 'named in the announce')

  t.is((await c.call('label-intent', { uri: MEMBER, val: 'loser-club-member' })).changed, true)
  t.is((await c.call('label-intent', { uri: POST, val: 'spam' })).changed, true)

  const served = await waitFor(() => node.membrane.labelCore.length === 2)
  t.ok(served, 'both labels signed and projected by the event-driven tick (no manual call)')

  const pub = keyFromPrivate(b4a.from(signingKey, 'hex')).didKey
  for (let i = 0; i < node.membrane.labelCore.length; i++) {
    const l = decodeLabel(await node.membrane.labelCore.get(i))
    t.is(l.src, did, 'src is the labeler DID')
    t.ok(verifyLabel(l, pub), 'signed with the DID key: ' + l.val)
  }

  const recs = await node.device.repo.listRecords()
  t.ok(!recs.some((r) => r.collection.includes('label')), 'no label intent entered the repo record set')
  t.is((await c.call('label-list', {})).signed, 2)
})

// ⛔ BOOT MUST PROJECT THE LABELS, NOT ONLY THE REPO. 2026-10-14: loser-club's re-signed (ver:1) member labels sat
// in both co-owners' signed logs for hours while the gateway served the old ones — label-list reported
// projection:null on both. The boot tick runs before the membrane exists, the initial projection after it synced
// the repo + firehose only, and a quiet DID has no later event to tick on. A labeler's boot projects its labels.
test('a labeler DID projects its signed log into the label core at boot, with no further event', { timeout: 120000 }, async (t) => {
  const { c } = await boot(t, { labeler: true })
  const l = await c.call('label-list', {})
  t.ok(l.projection, 'label-list reports a projection right after boot (was null)')
  t.is(l.projection && l.projection.coreLength, l.projection && l.projection.logLength, 'the served core holds the whole signed log')
})

test('a DID without labeler: no label core, verbs say so', { timeout: 120000 }, async (t) => {
  const { node, c } = await boot(t, { labeler: false })
  t.is(node.membrane.labelKey, null)
  await t.exception(() => c.call('label-list', {}), /not a labeler/)
})