OverviewFilesCommitsIssuesDocsReleasesPeers

atproto-bridge / pds / test / membrane-only.test.js

132 lines · javascript ref:
// Model B PURE MEMBRANE: createPdsServer({peers}) + startControl({peers}). No local Pds,
// no key, no account. Every fronted-DID read still routes to the remote hyper-proto-peer
// (keyless); describeServer/listRepos synthesize from opts+fronted set; every custodial /
// authed endpoint 404s; a non-fronted DID 404s; the UDS status reports a membrane.
// This is the artifact that restores wj62 on :3399 without re-custodying its key.

import test from 'brittle'
import { mkdtempSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import b4a from 'b4a'
import c from 'compact-encoding'
import Hyperswarm from 'hyperswarm'
import createTestnet from '@hyperswarm/testnet'
import ProtomuxRPC from 'protomux-rpc'
import { pushAnnounce } from './serve-announce.js'
import { Client } from 'hyper-svc'
import { openCorestore } from 'atproto-store/lib/corestore.js'
import { RepoStore } from 'atproto-store/lib/repo-store.js'
import { RepoManager } from 'atproto-store/lib/repo-manager.js'
import { FirehoseSequencer } from 'atproto-store/lib/sequencer.js'
import { keyFromPrivate } from 'atproto-identity'
import { discoveryTopic } from 'atproto-identity/lib/discovery.js'
import { createPdsServer } from '../lib/server.js'
import { startControl } from '../lib/control.js'
import { DidPeerRouter } from 'atproto-did-peer'

process.env.PGH_SIDECAR_SOCK = join(tmpdir(), `no-sidecar-${process.pid}.sock`) // no registration

const DID = 'did:plc:membraneonly'
const HANDLE = 'membraneonly.7rnx.net'
const PRIV = new Uint8Array(32).fill(7)
const NOW = '2026-07-04T00:00:00.000Z'
const SERVER_DID = 'did:web:pds.7rnx.net'
const DOMAINS = ['.7rnx.net']

test('pure membrane (pds=null) fronts a peer, synthesizes describeServer/listRepos, 404s custodial endpoints', async (t) => {
  const testnet = await createTestnet(3)

  // a discoverable self-custody peer: signed repo + firehose + get-coords / create-session
  const peerDir = mkdtempSync(join(tmpdir(), 'monly-peer-'))
  const peerStore = openCorestore(peerDir)
  const repo = await new RepoStore(peerStore, { name: `atproto-repo:${DID}` }).ready()
  let micros = 1_700_000_000_000_000n
  const mgr = await new RepoManager(repo, { did: DID, privateKey: PRIV, clock: () => (micros += 1_000_000n) }).init()
  const seq = await new FirehoseSequencer(peerStore.get({ name: 'firehose' })).ready()
  const w = await mgr.applyWrite({ action: 'create', collection: 'app.bsky.feed.post', rkey: '3a', record: { $type: 'app.bsky.feed.post', text: 'self-custody', createdAt: NOW } })
  await seq.sequenceCommit(w, { time: NOW })
  const peerSwarm = new Hyperswarm({ bootstrap: testnet.bootstrap })
  peerSwarm.on('connection', (conn) => {
    peerStore.replicate(conn)
    const rpc = new ProtomuxRPC(conn, { protocol: 'hyper-proto-peer/rpc/v1', valueEncoding: c.json })
    pushAnnounce(conn, { did: DID, handle: HANDLE, repo, seq })
    rpc.respond('create-session', async ({ identifier }) => ({ did: DID, handle: HANDLE, accessJwt: `access-${identifier}`, refreshJwt: 'refresh' }))
  })
  await peerSwarm.join(discoveryTopic(DID), { server: true, client: false }).flushed()

  // THE MEMBRANE: no Pds at all — the shared DidPeerRouter fronting DID + the HTTP server with pds=null.
  // Constructed EXACTLY as pds-serve.js does (owns-swarm + join + rpc) — verifies the prod repoint.
  const routerStore = openCorestore(mkdtempSync(join(tmpdir(), 'monly-router-')))
  const routerSwarm = new Hyperswarm({ bootstrap: testnet.bootstrap })
  const router = new DidPeerRouter(routerStore, {
    swarm: routerSwarm,
    join: (did) => { try { routerSwarm.join(discoveryTopic(did), { server: true, client: true }); routerSwarm.flush().catch(() => {}) } catch {} },
    fronted: [DID],
    resolveVerifyKey: async () => keyFromPrivate(PRIV).publicKey,
    rpc: true
  })
  const server = createPdsServer({ peers: router, serverDid: SERVER_DID, availableUserDomains: DOMAINS })
  await new Promise((r) => server.listen(0, '127.0.0.1', r))
  const base = `http://127.0.0.1:${server.address().port}`
  const xrpc = (m) => `${base}/xrpc/${m}`

  const udsDir = mkdtempSync(join(tmpdir(), 'monly-uds-'))
  const uds = join(udsDir, 'svc.sock')
  const control = await startControl({ uds, name: 'atproto-bridge-membrane-test', peers: router })

  t.teardown(async () => {
    await control.close(); server.close(); await router.close()
    await peerSwarm.destroy(); await routerSwarm.destroy()
    await seq.close(); await repo.close(); await peerStore.close(); await routerStore.close()
    await testnet.destroy()
    rmSync(peerDir, { recursive: true, force: true }); rmSync(udsDir, { recursive: true, force: true })
  })

  // --- fronted-DID reads route to the peer, keyless ---
  const carBuf = new Uint8Array(await (await fetch(xrpc('com.atproto.sync.getRepo') + '?did=' + DID)).arrayBuffer())
  t.ok(carBuf.length > 0, 'membrane getRepo returns the fronted peer CAR (keyless, pds=null)')

  const rec = await (await fetch(xrpc('com.atproto.repo.getRecord') + '?repo=' + DID + '&collection=app.bsky.feed.post&rkey=3a')).json()
  t.is(rec.value.text, 'self-custody', 'membrane getRecord routed to the peer (pds=null)')

  const status = await (await fetch(xrpc('com.atproto.sync.getRepoStatus') + '?did=' + DID)).json()
  t.is(status.active, true, 'membrane getRepoStatus routed to the peer (pds=null)')

  const latest = await (await fetch(xrpc('com.atproto.sync.getLatestCommit') + '?did=' + DID)).json()
  t.ok(latest.cid && latest.rev, 'membrane getLatestCommit routed to the peer (pds=null)')

  const sess = await (await fetch(xrpc('com.atproto.server.createSession'), { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ identifier: DID, password: 'x' }) })).json()
  t.is(sess.accessJwt, `access-${DID}`, 'membrane createSession routed to the peer (pds=null)')

  // --- synthesized server metadata (no Pds to answer these) ---
  const desc = await (await fetch(xrpc('com.atproto.server.describeServer'))).json()
  t.is(desc.did, SERVER_DID, 'describeServer.did synthesized from serverDid opt')
  t.alike(desc.availableUserDomains, DOMAINS, 'describeServer.availableUserDomains synthesized')

  const repos = await (await fetch(xrpc('com.atproto.sync.listRepos'))).json()
  t.ok(repos.repos.length === 1 && repos.repos[0].did === DID && repos.repos[0].active === true, 'listRepos advertises the fronted DID as active')

  const resolved = await (await fetch(xrpc('com.atproto.identity.resolveHandle') + '?handle=' + HANDLE)).json()
  t.is(resolved.did, DID, 'resolveHandle maps the fronted handle to its DID')

  // --- non-fronted DID + custodial/authed endpoints all 404 (nothing to serve locally) ---
  const missing = await fetch(xrpc('com.atproto.sync.getRepo') + '?did=did:plc:notfronted')
  t.is(missing.status, 404, 'non-fronted DID getRepo → 404')

  const gsess = await fetch(xrpc('com.atproto.server.getSession'), { headers: { authorization: 'Bearer whatever' } })
  t.is(gsess.status, 404, 'authed getSession on a keyless membrane → 404')

  const blob = await fetch(xrpc('com.atproto.sync.getBlob') + '?cid=bafyreiabc')
  t.is(blob.status, 404, 'getBlob on a keyless membrane → 404')

  const acct = await fetch(xrpc('com.atproto.server.createAccount'), { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ handle: 'x.7rnx.net' }) })
  t.is(acct.status, 404, 'createAccount on a keyless membrane → 404')

  // --- UDS control status reports a membrane ---
  const cli = await Client.connectUds(uds)
  const st = await cli.call('status')
  await cli.close()
  t.ok(st.ok && st.membrane === true && Array.isArray(st.fronted) && st.fronted[0] === DID, 'UDS status reports membrane:true + fronted=[DID]')
})