mattrguerra/meridian-ops-boardmainPrivate on GitHub, published here in full

own-list-isolation.test.ts

Language TypeScript3.2 KB81 lines

apps/dashboard/test/own-list-isolation.test.ts

  1. /**
  2. * The private list cannot reach anything shared, because nothing shared can see
  3. * it.
  4. *
  5. * Every other guarantee in this feature is a runtime one: a scoping clause, an
  6. * ownership check, a per-viewer stamp. This file asserts the structural one,
  7. * which is the only kind that holds against a change nobody reviewed carefully:
  8. * the modules that build the company surfaces, the history rows and the
  9. * briefing payload do not import the list, so there is no code path along which
  10. * a line could travel to `/payload.json` (which `seesLeadership` may fetch), to
  11. * `briefings.json` (which is pushed), or to `analysis/brief.py` (the one place
  12. * a model is called).
  13. *
  14. * The same shape as onboarding-export.test.ts's guard, and for the same reason
  15. * recorded there: whoever is next asked to "surface what people are carrying"
  16. * will reach for `readOwnList` long before they reach for a comment.
  17. */
  18. import { readFile } from 'node:fs/promises'
  19. import { fileURLToPath } from 'node:url'
  20. import { describe, expect, it } from 'vitest'
  21. import { FIXTURE_SNAPSHOT } from '../src/fixtures.js'
  22. import { headline } from '../src/collect.js'
  23. import { buildViewModel } from '../src/view-model.js'
  24. import { buildBriefingPayload } from '../src/briefing-payload.js'
  25. import { viewerFor } from '../src/viewer.js'
  26. const DAY = '2026-08-12'
  27. /** The modules that produce anything a second person can read. */
  28. const SHARED = [
  29. 'collect.ts',
  30. 'view-model.ts',
  31. 'history.ts',
  32. 'briefing-payload.ts',
  33. 'variants.ts',
  34. ]
  35. describe('nothing shared can see the private list', () => {
  36. for (const file of SHARED) {
  37. it(`${file} does not import it`, async () => {
  38. const src = await readFile(fileURLToPath(new URL(`../src/${file}`, import.meta.url)), 'utf8')
  39. const imports = [...src.matchAll(/^import[\s\S]*?from '([^']+)'/gm)].map((m) => m[1]!)
  40. expect(
  41. imports.filter((i) => i.includes('own-list')),
  42. `${file} must not import the private list; it feeds a surface other people read`,
  43. ).toEqual([])
  44. })
  45. }
  46. it('surfaces.ts sees ONLY the placeholder and the grant, never the store', async () => {
  47. // It has to see something: it emits the marker. What it must not be able to
  48. // reach is anything that returns a line.
  49. const src = await readFile(fileURLToPath(new URL('../src/surfaces.ts', import.meta.url)), 'utf8')
  50. expect(src).toContain('ownListPlaceholder')
  51. expect(src).not.toContain('readOwnList')
  52. expect(src).not.toContain('ownListBlock')
  53. })
  54. it('the briefing payload contains no field belonging to the list', () => {
  55. // Asserted on the built payload as well as on the imports, because the
  56. // import check would not catch a field copied in by hand.
  57. const payload = JSON.stringify(buildBriefingPayload(FIXTURE_SNAPSHOT))
  58. for (const marker of ['own_item', 'ownList', 'own-list', 'linkKey', 'doneAt']) {
  59. expect(payload).not.toContain(marker)
  60. }
  61. })
  62. it('the view model a viewer’s page is built from has no list on it', () => {
  63. const vm = buildViewModel(
  64. FIXTURE_SNAPSHOT,
  65. headline(FIXTURE_SNAPSHOT),
  66. [],
  67. DAY,
  68. viewerFor('hello@meridiandisplay.example'),
  69. )
  70. const json = JSON.stringify(vm)
  71. expect(json).not.toContain('own_item')
  72. expect(json).not.toContain('ownList')
  73. })
  74. })