OverviewFilesCommitsIssuesDocsReleasesPeers

pgh / test / registry-store-lock.test.js

68 lines · javascript ref:
/**
 * Regression: the registry-resolution fd-lock leak (2026-07-13).
 *
 * The install path (resolveRelease / installViaRegistry) opens a Corestore at
 * ~/.config/pgh/registries/<key16> to replicate a publisher's ReleaseRegistry.
 * ReleaseRegistry.close() closes ONLY the autobase — NOT the underlying
 * Corestore — so tearing down via registry.close() alone leaves the store's
 * exclusive fd-lock held. In the always-on, in-process pgh-sidecar autoupdate
 * loop that orphaned lock made every subsequent install of the same app fail
 * with "File descriptor could not be locked", and the zero-backoff retry loop
 * bled the sidecar to 232k fds / 15.8 GB on stortron.
 *
 * The fix: callers close `store` too. These tests pin the invariant — closing
 * the registry alone LEAKS the lock; closing the store RELEASES it.
 */

import test from 'brittle'
import Corestore from 'corestore'
import fs from '#node:fs'
import os from '#node:os'
import path from '#node:path'
import { ReleaseRegistry } from '../lib/release-registry.js'

test('registry.close() alone leaks the Corestore fd-lock (characterizes the bug)', async (t) => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pgh-reglock-a-'))
  t.teardown(() => { try { fs.rmSync(dir, { recursive: true, force: true }) } catch {} })

  const store1 = new Corestore(dir)
  const reg1 = new ReleaseRegistry(store1)
  await reg1.ready()

  // OLD (buggy) teardown: close the registry autobase but NOT the store.
  await reg1.close()

  // The store still holds the dir's exclusive fd-lock, so a second Corestore on
  // the same dir cannot acquire it.
  const store2 = new Corestore(dir)
  const reg2 = new ReleaseRegistry(store2)
  await t.exception(reg2.ready(), /lock/i, 'second open fails while store1 still holds the lock')
  try { await reg2.close() } catch {}
  try { await store2.close() } catch {}

  // Now release the lock the way the fix does.
  await store1.close()
})

test('closing the store releases the lock — re-open succeeds (validates the fix)', async (t) => {
  const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'pgh-reglock-b-'))
  t.teardown(() => { try { fs.rmSync(dir, { recursive: true, force: true }) } catch {} })

  const store1 = new Corestore(dir)
  const reg1 = new ReleaseRegistry(store1)
  await reg1.ready()

  // FIXED teardown: close registry AND store.
  await reg1.close()
  await store1.close()

  // The lock is released, so a fresh Corestore on the same dir opens cleanly —
  // exactly what the sidecar autoupdate needs on its next attempt.
  const store2 = new Corestore(dir)
  const reg2 = new ReleaseRegistry(store2)
  await reg2.ready()
  t.pass('re-open after store.close() succeeds')
  await reg2.close()
  await store2.close()
})