// ── The boundary, asserted ──────────────────────────────────────────────── // // `catalogue.js` is the only thing standing between a frame carrying an IP // address and a public page, so it gets a suite of its own rather than being // covered incidentally by a route test. // // The most valuable test here is the last one: it holds the classification // against the specification in `docs/rust-link/PROTOCOL.md` §8.4. Without it the // two drift the first time somebody adds a kind to the protocol, and the drift // is silent in the direction that matters — a new kind is simply never served, // until the day somebody "fixes" that by adding it to the wrong list. const test = require('node:test') const assert = require('node:assert') const catalogue = require('../catalogue') test('an unknown kind is not public — the default is deny', () => { assert.equal(catalogue.isPublic('player.death'), true) assert.equal(catalogue.isPublic('something.new'), false) assert.equal(catalogue.isPublic(''), false) assert.equal(catalogue.isPublic(undefined), false) // The shape of the mistake this prevents: a kind a LATER protocol adds, which // this build ingests happily and would publish on the day it first arrived if // the filter were a deny list. assert.equal(catalogue.isKnown('player.location'), false) assert.equal(catalogue.isPublic('player.location'), false) }) test('nothing carrying an IP address or a report is public', () => { for (const kind of [ 'player.login.attempt', 'player.approved', 'player.banned', 'player.unbanned', 'player.reported', 'entity.destroyed', ]) { assert.equal(catalogue.isPublic(kind), false, `${kind} must not be public`) assert.ok(catalogue.STAFF_KINDS.includes(kind), `${kind} must be classified, not merely absent`) } }) test('a viewer with no kinds asked for gets the allowlist, never everything', () => { const asPublic = catalogue.kindsFor({}) const asAdmin = catalogue.kindsFor({ admin: true }) assert.deepEqual(asPublic, [...catalogue.PUBLIC_KINDS]) assert.equal(asAdmin.length, catalogue.ALL_KINDS.length) // The property that makes the route safe by construction: there is no argument // a caller can omit that turns the filter off. assert.ok(asPublic.length > 0) assert.ok(!asPublic.includes('player.banned')) }) test('a kind a viewer may not see is dropped, not refused', () => { const asked = catalogue.kindsFor({ requested: ['player.death', 'player.banned'] }) assert.deepEqual(asked, ['player.death']) // Asking for only forbidden kinds answers with nothing to select, which the // model turns into an empty list — the events are, as far as this viewer is // concerned, not there. assert.deepEqual(catalogue.kindsFor({ requested: ['player.banned'] }), []) // And an admin gets what they asked for. assert.deepEqual(catalogue.kindsFor({ admin: true, requested: ['player.banned'] }), [ 'player.banned', ]) }) test('every kind is classified exactly once', () => { const seen = new Set() for (const kind of catalogue.ALL_KINDS) { assert.ok(!seen.has(kind), `${kind} appears in both lists`) seen.add(kind) } assert.equal(seen.size, catalogue.PUBLIC_KINDS.length + catalogue.STAFF_KINDS.length) }) test('the classification covers exactly the kinds protocol 2 defines', () => { // The spec lives in another repository, so the list is restated here rather // than parsed — and restating it is the point: adding a kind to the protocol // without deciding who may see it has to fail somewhere, and this is where. // // Sourced from docs/rust-link/PROTOCOL.md §8.4. const PROTOCOL_2 = [ 'player.connected', 'player.disconnected', 'player.respawned', 'player.death', 'player.chat', 'player.tally', 'entity.destroyed', 'player.reported', 'player.banned', 'player.unbanned', 'player.login.attempt', 'player.approved', 'server.wipe', 'server.initialized', 'server.shutdown', ] assert.deepEqual([...catalogue.ALL_KINDS].sort(), [...PROTOCOL_2].sort()) })