test(server): port core's UO suite onto the ctx harness
All checks were successful
PR Checks / client-build (pull_request) Successful in 17s
PR Checks / server-tests (pull_request) Successful in 8m47s

22 test files moved from core, plus the two that were split out of files core
keeps. 351 tests pass.

One change runs through every moved test, and it is the boundary rather than a
chore: core internals can no longer be stubbed by requiring them, because there
are none to require. `../utils/db` and `../model/settings` do not exist here.
What a test controls instead is the ctx core would have handed over, installed
once by test/_setup.js -- which is a better seam anyway, since it is exactly the
surface the contract promises and nothing wider.

The ctx _setup installs is deliberately unfrozen. Core freezes what it hands a
module and entry.test.js still asserts against a frozen one; but a test that
needs settings.get to return a path has to be able to say so.

Two tests changed SHAPE, and that is the boundary too. fromShardEvent used to
assert through publish() into pushDevices and a captured fetch -- which
endpoints were hit, how many requests went out. None of that is this module's
any more: publish is ctx.push.publish, and the device registry and the relay are
behind it. Reaching for them from here would be reaching past ctx. What remains
is what the module owns and is the part worth guarding: a game account resolves
to a website user, a personal target that resolves to nobody is dropped rather
than published, and a sensitive kind never reaches publish at all.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-11 12:07:15 -05:00
committed by Claude
parent 740a677f92
commit 6b99d7e220
28 changed files with 4692 additions and 24 deletions

View File

@@ -0,0 +1,227 @@
// Ported from core in Phase 3 (MODULE_SYSTEM.md §2.7.1). One change runs through
// every moved test: core internals can no longer be stubbed by requiring them,
// because there are none to require — `../utils/db` and `../model/settings` do
// not exist here. What a test controls instead is the `ctx` core would have
// handed over, installed once by `test/_setup.js`, which is the seam the
// contract actually promises.
const { test, after, afterEach, beforeEach } = require('node:test')
const assert = require('node:assert/strict')
const { EventEmitter } = require('node:events')
// The SSE fan-out is the security boundary (docs/link/v3.md §3.6). Before v3 it
// was a static kind allowlist; now each subscriber carries the audience rung it
// resolved to at subscribe time, and every frame is gated + field-projected per
// viewer. These tests pin the properties that must hold no matter how the config
// is set:
//
// - the admin channel always gets the frame verbatim;
// - a public subscriber never receives an unmapped kind;
// - acct / webId never reach a public subscriber, at any rung below admin;
// - two subscribers at different rungs get different frames from one event;
// - a viewer's rung is frozen at subscribe time, not re-read per frame;
// - if the visibility config can't be read, nothing goes out on public.
const broadcast = require('../utils/shardBroadcast')
const visibility = require('../utils/shardVisibility')
const model = require('../model/shardVisibility/shardVisibility.model')
const shardLinks = require('../model/shardLinks/shardLinks.model')
const originals = {
listAll: model.listAll,
listForUser: shardLinks.listForUser,
getConfig: visibility.getConfig,
viewerLevel: visibility.viewerLevel,
}
beforeEach(() => {
model.listAll = async () => []
shardLinks.listForUser = async () => []
visibility.invalidate()
})
afterEach(() => {
broadcast.closeAll()
model.listAll = originals.listAll
shardLinks.listForUser = originals.listForUser
visibility.getConfig = originals.getConfig
visibility.viewerLevel = originals.viewerLevel
visibility.invalidate()
})
// A fake req/res pair that records everything written to the stream.
function fakeClient() {
const req = new EventEmitter()
const writes = []
const res = {
writeHead() {},
write(chunk) {
writes.push(chunk)
},
end() {},
on() {},
}
// Frames only — drop the SSE comments/retry preamble and keepalive pings.
const frames = () =>
writes
.filter((w) => w.startsWith('data: '))
.map((w) => JSON.parse(w.slice('data: '.length).trim()))
return { req, res, frames }
}
async function subscribeAt(level, channel = 'public') {
const client = fakeClient()
visibility.viewerLevel = async () => level
await broadcast.subscribe(client.req, client.res, channel)
return client
}
const GUILD_FRAME = {
kind: 'guild.update',
id: 7,
name: 'The Nameless',
abbr: 'TN',
leader: { serial: '0x1A2B', name: 'Darrow', acct: 'whitlocktech', webId: '42', player: true },
}
test('the admin channel receives the frame verbatim, acct and webId included', async () => {
const admin = await subscribeAt('admin', 'admin')
await broadcast.broadcast(GUILD_FRAME)
const [frame] = admin.frames()
assert.deepEqual(frame, GUILD_FRAME)
})
test('a public subscriber never sees acct or webId, at any rung below admin', async () => {
for (const level of ['anonymous', 'logged_in', 'player', 'staff']) {
const client = await subscribeAt(level)
await broadcast.broadcast(GUILD_FRAME)
const [frame] = client.frames()
assert.ok(frame, `${level} should receive the guild frame`)
assert.equal(frame.leader.name, 'Darrow')
assert.equal('acct' in frame.leader, false, `${level} must not see acct`)
assert.equal('webId' in frame.leader, false, `${level} must not see webId`)
broadcast.closeAll()
}
})
test('an unmapped kind reaches the admin channel and nobody else', async () => {
const anon = await subscribeAt('anonymous')
const staff = await subscribeAt('staff')
const admin = await subscribeAt('admin', 'admin')
for (const kind of ['audit.command', 'cheat.fastwalk', 'account.login.attempt', 'vendor.sale']) {
await broadcast.broadcast({ kind, secret: true })
}
assert.deepEqual(anon.frames(), [])
assert.deepEqual(staff.frames(), [])
assert.equal(admin.frames().length, 4)
})
test('one event yields different frames for subscribers at different rungs', async () => {
model.listAll = async () => [
{
feature: 'guilds',
enabled: true,
audience: 'anonymous',
stream: true,
fieldRules: { abbr: 'staff' },
},
]
visibility.invalidate()
const anon = await subscribeAt('anonymous')
const staff = await subscribeAt('staff')
await broadcast.broadcast(GUILD_FRAME)
assert.equal('abbr' in anon.frames()[0], false)
assert.equal(staff.frames()[0].abbr, 'TN')
// Both still lose the locked fields.
assert.equal('acct' in staff.frames()[0].leader, false)
})
test('raising a feature audience cuts off the lower rungs mid-stream', async () => {
const anon = await subscribeAt('anonymous')
const player = await subscribeAt('player')
await broadcast.broadcast(GUILD_FRAME)
assert.equal(anon.frames().length, 1)
assert.equal(player.frames().length, 1)
// Config changes DO take effect live — only the viewer's rung is frozen.
model.listAll = async () => [
{ feature: 'guilds', enabled: true, audience: 'player', stream: true, fieldRules: {} },
]
visibility.invalidate()
await broadcast.broadcast(GUILD_FRAME)
assert.equal(anon.frames().length, 1, 'anonymous stops receiving')
assert.equal(player.frames().length, 2, 'player keeps receiving')
})
test("a subscriber's rung is frozen at subscribe time", async () => {
const client = await subscribeAt('anonymous')
// Even if the resolver would now say "admin", the open connection must not
// gain privilege — its level was captured when it subscribed.
visibility.viewerLevel = async () => 'admin'
await broadcast.broadcast({ kind: 'audit.command', command: 'ban' })
assert.deepEqual(client.frames(), [])
})
test('an unresolvable viewer subscribes as anonymous, not as privileged', async () => {
const client = fakeClient()
visibility.viewerLevel = async () => {
throw new Error('session lookup exploded')
}
await broadcast.subscribe(client.req, client.res, 'public')
await broadcast.broadcast({ kind: 'audit.command', command: 'ban' })
assert.deepEqual(client.frames(), [])
// ...but it still receives ordinary public traffic.
await broadcast.broadcast({ kind: 'champ.update', serial: '0x1' })
assert.equal(client.frames().length, 1)
})
test('an unreadable visibility config withholds every public frame', async () => {
const client = await subscribeAt('anonymous')
visibility.getConfig = async () => {
throw new Error('db down')
}
await broadcast.broadcast(GUILD_FRAME)
assert.deepEqual(client.frames(), [])
})
test('a disabled feature stops its kinds without touching others', async () => {
model.listAll = async () => [
{ feature: 'champs', enabled: false, audience: 'anonymous', stream: true, fieldRules: {} },
]
visibility.invalidate()
const client = await subscribeAt('anonymous')
await broadcast.broadcast({ kind: 'champ.update', serial: '0x1' })
await broadcast.broadcast({ kind: 'guild.update', id: 7 })
const kinds = client.frames().map((f) => f.kind)
assert.deepEqual(kinds, ['guild.update'])
})
test('a dead client is dropped rather than repeatedly retried', async () => {
const client = fakeClient()
visibility.viewerLevel = async () => 'anonymous'
await broadcast.subscribe(client.req, client.res, 'public')
assert.equal(broadcast.stats().publicClients, 1)
client.res.write = () => {
throw new Error('EPIPE')
}
await broadcast.broadcast({ kind: 'champ.update', serial: '0x1' })
assert.equal(broadcast.stats().publicClients, 0)
})
test('broadcast is a no-op for a malformed event', async () => {
const client = await subscribeAt('anonymous')
await broadcast.broadcast(null)
await broadcast.broadcast({})
assert.deepEqual(client.frames(), [])
})