experiments in a post-browser web
10
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(tiles): allowlist bypass for cmd/noun infrastructure topics

Two bugs surfacing as silent drops:

1. `noun:register-batch` (and the dynamic `noun:result:<noun>:<ts>`
topics the cmd panel subscribes to for each invocation) were
gated by the per-tile `pubsub.topics` allowlist. Feature manifests
don't list them — why would they, they're infrastructure — so
every noun registration and every browse-command result was
silently rejected. Symptoms: `open entities` / `list entities` /
`new feed` etc. never showed up in the cmd panel; when they did
(via stale cache), the spinner hung forever because the browse
handler's result publish was also blocked.

2. `cmd:register` / `cmd:register-batch` / `cmd:unregister` were in
the same boat but partially worked thanks to a separate
`tile:command:register` IPC that bypasses the allowlist via
main's `publish()` directly. The full-metadata publish path
(via `tile:pubsub:publish`) was still blocked.

Fix: in `tile-ipc.ts`'s `tile:pubsub:publish` handler, topics owned
by the cmd/noun registry infrastructure — `cmd:register`,
`cmd:register-batch`, `cmd:unregister`, anything starting with
`noun:` — are exempt from the per-tile allowlist when the tile holds
the `commands` capability. The scope check still applies; only the
topic allowlist is bypassed.

Also fix packaging: `chrome-extensions/**/*` must live on a real
filesystem for Electron's `session.loadExtension()` to find them.
They were getting packed into `app.asar` where `loadExtension` can't
read. Added to `asarUnpack` in `electron-builder.yml`.

+27 -4
+24 -4
backend/electron/tile-ipc.ts
··· 476 476 topic: string; 477 477 data: unknown; 478 478 }) => { 479 - if (args.topic === 'cmd:register' || args.topic === 'cmd:register-batch') { 480 - console.error(`[DIAG pub] topic=${args.topic} source=${args.source} name=${(args.data as { name?: string })?.name ?? '(batch)'}`); 481 - } 482 479 const grant = getGrantForToken(args.token); 483 480 if (!grant) { 484 481 DEBUG && console.log('[tile-ipc] pubsub:publish rejected: invalid token'); ··· 495 492 496 493 // Topic enforcement: if topics allowlist is set, check it. 497 494 // Trusted-builtin core renderers bypass the topic allowlist. 498 - if (!grant.trustedBuiltin && grant.capabilities.pubsub?.topics) { 495 + // 496 + // Infrastructure topics owned by the cmd / noun registry are exempt 497 + // from per-tile allowlists when the tile has the `commands` 498 + // capability — they're the pubsub half of api.commands.register, 499 + // api.commands.registerNoun, and the noun-execute → result 500 + // round-trip (`noun:browse:*`, `noun:query:*`, `noun:open:*`, 501 + // `noun:create:*`, and the dynamic `noun:result:<noun>:<ts>` topics 502 + // the cmd panel subscribes to for each invocation). Gating these on 503 + // manifest topics would require every feature to hand-copy an 504 + // opaque infrastructure-topic list and enumerate the dynamic result 505 + // topic pattern. `tile:command:register/unregister` IPC already 506 + // bypasses the check this way; the registerNoun + noun-invocation 507 + // publish paths go through here so we must exempt them too. 508 + const INFRA_EXACT_TOPICS = new Set([ 509 + 'cmd:register', 510 + 'cmd:register-batch', 511 + 'cmd:unregister', 512 + ]); 513 + const isInfraTopic = hasCapability(grant, 'commands') && ( 514 + INFRA_EXACT_TOPICS.has(args.topic) || 515 + args.topic.startsWith('noun:') 516 + ); 517 + 518 + if (!grant.trustedBuiltin && !isInfraTopic && grant.capabilities.pubsub?.topics) { 499 519 const allowed = grant.capabilities.pubsub.topics.some(pattern => { 500 520 if (pattern === args.topic) return true; 501 521 // Simple glob: pattern:* matches pattern:anything
+3
electron-builder.yml
··· 73 73 asar: true 74 74 asarUnpack: 75 75 - "assets/tray/**/*" 76 + # Chrome extensions must live on a real filesystem — Electron's 77 + # session.loadExtension() can't read from inside app.asar. 78 + - "chrome-extensions/**/*" 76 79 77 80 # macOS specific 78 81 mac: