OverviewFilesCommitsIssuesDocsReleasesPeers

P2P-Hiverelay / test / unit / public-hive-gateway-observer.test.js

97 lines · javascript ref:
import test from 'brittle'
import { spawnSync } from 'node:child_process'
import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import path from 'node:path'

const observer = path.resolve('scripts/observe-public-hive-gateway-rollout.mjs')

test('public gateway observer owns status-2 sampling until verified', async (t) => {
  const dir = await mkdtemp(path.join(tmpdir(), 'hiverelay-gateway-observer-'))
  t.teardown(() => rm(dir, { recursive: true, force: true }))
  const checker = path.join(dir, 'checker.mjs')
  const state = path.join(dir, 'window.json')
  const counter = path.join(dir, 'counter.txt')
  await writeFile(checker, `
    import { readFileSync, writeFileSync } from 'node:fs'
    let count = 0
    try { count = Number(readFileSync(process.env.OBSERVER_COUNTER, 'utf8')) } catch {}
    count++
    writeFileSync(process.env.OBSERVER_COUNTER, String(count))
    if (count === 1) {
      writeFileSync(process.env.OBSERVER_STATE, JSON.stringify({ maxProbeGapMs: 60000 }))
      process.exit(2)
    }
    process.exit(0)
  `)

  const result = runObserver(checker, state, {
    OBSERVER_COUNTER: counter,
    OBSERVER_STATE: state
  })
  t.is(result.status, 0, result.stderr)
  t.ok(result.stdout.includes('Observation incomplete after 1 checker run'))
  t.ok(result.stdout.includes('observation complete after 2 checker run'))
  t.is(await readFile(counter, 'utf8'), '2')
})

test('public gateway observer stops immediately on a red checker', async (t) => {
  const dir = await mkdtemp(path.join(tmpdir(), 'hiverelay-gateway-observer-'))
  t.teardown(() => rm(dir, { recursive: true, force: true }))
  const checker = path.join(dir, 'checker.mjs')
  const state = path.join(dir, 'window.json')
  const counter = path.join(dir, 'counter.txt')
  await writeFile(checker, `
    import { writeFileSync } from 'node:fs'
    writeFileSync(process.env.OBSERVER_COUNTER, '1')
    process.exit(1)
  `)

  const result = runObserver(checker, state, { OBSERVER_COUNTER: counter })
  t.not(result.status, 0)
  t.ok(result.stderr.includes('stopped red with exit 1'))
  t.is(await readFile(counter, 'utf8'), '1')
})

test('public gateway observer refuses incomplete or non-canary forwarding', (t) => {
  const missing = spawnSync(process.execPath, [observer, '--', '--target', 'v1.2.3'], {
    encoding: 'utf8'
  })
  t.not(missing.status, 0)
  t.ok(missing.stderr.includes('--gateway-evidence is required'))

  const args = forwarded('/tmp/window.json')
  args[args.indexOf('canary')] = 'stable'
  const stable = spawnSync(process.execPath, [observer, '--', ...args], { encoding: 'utf8' })
  t.not(stable.status, 0)
  t.ok(stable.stderr.includes('restricted to the canary'))
})

function runObserver (checker, state, extraEnv) {
  return spawnSync(process.execPath, [
    observer,
    '--checker', checker,
    '--sample-interval-ms', '1000',
    '--max-runtime-ms', '60000',
    '--',
    ...forwarded(state)
  ], {
    encoding: 'utf8',
    timeout: 10_000,
    env: { ...process.env, ...extraEnv }
  })
}

function forwarded (state) {
  return [
    '--target', 'v1.2.3',
    '--channel', 'canary',
    '--gateway-evidence', '/root/evidence.json',
    '--gateway-manifest', 'fleet/public-hive-gateway-release.json',
    '--gateway-window-state', state,
    '--evidence', '/tmp/rollout.json',
    '--known-hosts', '/tmp/known-hosts',
    '--allowed-signers', '/tmp/allowed-signers'
  ]
}