#!/usr/bin/env node
import assert from 'node:assert/strict'
import fs from 'node:fs'
import path from 'node:path'
import { execFileSync, spawnSync } from 'node:child_process'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const policyPath = path.join(root, 'deploy/blind/image-inventory-policy.json')
const policy = JSON.parse(fs.readFileSync(policyPath, 'utf8'))
const args = new Set(process.argv.slice(2))
const staticOnly = args.has('--static-only')
const noBuild = args.has('--no-build')
function command (program, commandArgs, options = {}) {
const result = spawnSync(program, commandArgs, {
cwd: root,
encoding: 'utf8',
stdio: options.capture ? 'pipe' : 'inherit'
})
if (result.error) throw result.error
if (result.status !== 0) {
const detail = options.capture ? `${result.stdout || ''}${result.stderr || ''}` : ''
throw new Error(`${program} ${commandArgs.join(' ')} failed (${result.status})${detail ? `\n${detail}` : ''}`)
}
return options.capture ? result.stdout : ''
}
function exactKeys (value) {
return Object.keys(value).sort()
}
function verifyStaticPackaging () {
const dockerfile = fs.readFileSync(path.join(root, 'Dockerfile.blind'), 'utf8')
const compose = fs.readFileSync(path.join(root, 'docker-compose.blind.yml'), 'utf8')
const edgeManifest = JSON.parse(fs.readFileSync(path.join(root, 'deploy/blind/edge/package.json'), 'utf8'))
const daemonManifest = JSON.parse(fs.readFileSync(path.join(root, 'deploy/blind/daemon/package.json'), 'utf8'))
const edgeLock = fs.readFileSync(path.join(root, 'deploy/blind/edge/package-lock.json'), 'utf8')
const daemonLock = fs.readFileSync(path.join(root, 'deploy/blind/daemon/package-lock.json'), 'utf8')
assert.deepEqual(exactKeys(edgeManifest.dependencies), [
'@hiverelay/blind-edge',
'@hiverelay/blind-ipc',
'@hiverelay/blind-peercred',
'@hiverelay/blind-protocol'
])
assert.deepEqual(exactKeys(daemonManifest.dependencies), [
'@hiverelay/blind-daemon',
'@hiverelay/blind-ipc',
'@hiverelay/blind-peercred',
'@hiverelay/blind-protocol'
])
assert.equal(edgeLock.includes('blind-daemon'), false)
assert.equal(edgeLock.includes('blind-peercred'), true)
assert.equal(daemonLock.includes('blind-edge'), false)
assert.match(dockerfile, /^# syntax=docker\/dockerfile:1\.7@sha256:[0-9a-f]{64}$/m)
assert.match(dockerfile, /ARG NODE_IMAGE=node:22-bookworm-slim@sha256:[0-9a-f]{64}/)
assert.match(dockerfile, /AS blind-native-toolchain/)
assert.match(dockerfile, /AS blind-edge-toolchain/)
assert.match(dockerfile, /AS blind-daemon-toolchain/)
assert.match(dockerfile, /AS blind-edge$/m)
assert.match(dockerfile, /AS blind-daemon$/m)
assert.equal(dockerfile.split('npm_config_build_from_source=true npm ci').length - 1, 2)
assert.equal(dockerfile.split('blind_peercred.node').length - 1, 2)
assert.match(dockerfile, /USER 998:997/)
assert.match(dockerfile, /USER 999:997/)
assert.equal(dockerfile.split('HIVERELAY_BLIND_UNARY_SOCKET=/run/hiverelay-blind/unary.sock').length - 1, 2)
assert.equal(dockerfile.split('HIVERELAY_BLIND_STREAM_SOCKET=/run/hiverelay-blind/stream.sock').length - 1, 2)
assert.equal(dockerfile.includes('HIVERELAY_BLIND_SOCKET='), false)
assert.match(compose, /target: blind-edge/)
assert.match(compose, /target: blind-daemon/)
assert.match(compose, /condition: service_healthy/)
assert.match(compose, /condition: service_completed_successfully/)
assert.equal(compose.includes('condition: service_started'), false)
assert.equal(compose.split('HIVERELAY_BLIND_UNARY_SOCKET: /run/hiverelay-blind/unary.sock').length - 1, 2)
assert.equal(compose.split('HIVERELAY_BLIND_STREAM_SOCKET: /run/hiverelay-blind/stream.sock').length - 1, 2)
assert.match(compose, /entrypoint: \["\/usr\/bin\/timeout", "--signal=KILL", "59s", "\/bin\/sh", "-ec"\]/)
const daemonService = compose.match(/ {2}blind-daemon:[\s\S]+?\n {2}blind-edge:/)?.[0] || ''
const edgeService = compose.match(/ {2}blind-edge:[\s\S]+?\nvolumes:/)?.[0] || ''
assert.equal(daemonService.includes('cap_add:'), false)
assert.equal(edgeService.includes('cap_add:'), false)
assert.match(daemonService, /network_mode: none/)
assert.equal(daemonService.includes('ports:'), false)
assert.equal(daemonService.includes('blind-public'), false)
assert.match(edgeService, /networks:\n {6}- blind-public/)
assert.match(edgeService, /ports:/)
assert.match(compose, /cap_add:\n {6}- CHOWN\n {6}- DAC_OVERRIDE\n {6}- FOWNER/)
assert.match(compose, /blind-runtime:\/run\/hiverelay-blind:ro/)
command('docker', ['compose', '-f', 'docker-compose.blind.yml', 'config', '--quiet'])
}
const probeSource = String.raw`
import crypto from 'node:crypto'
import fs from 'node:fs'
import path from 'node:path'
const component = process.env.BLIND_PROBE_COMPONENT
const root = '/opt/hiverelay/' + component
const runtime = fs.statSync('/run/hiverelay-blind')
const status = fs.readFileSync('/proc/self/status', 'utf8')
const capEff = status.match(/^CapEff:\s+(.+)$/m)?.[1]?.trim()
const commandPaths = process.env.PATH.split(':')
const compilerCommands = JSON.parse(process.env.BLIND_PROBE_COMPILERS)
const compilers = compilerCommands.filter(name => commandPaths.some(directory => fs.existsSync(path.join(directory, name))))
const forbiddenRoots = JSON.parse(process.env.BLIND_PROBE_FORBIDDEN_ROOTS).filter(candidate => fs.existsSync(candidate))
const packages = fs.readdirSync(path.join(root, 'node_modules/@hiverelay')).sort()
function hashTree (directory) {
const files = []
function visit (current, relative) {
for (const entry of fs.readdirSync(current, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
const next = path.join(current, entry.name)
const nextRelative = relative ? relative + '/' + entry.name : entry.name
if (entry.isDirectory()) visit(next, nextRelative)
else if (entry.isFile()) files.push([nextRelative, next])
else throw new Error('unexpected non-file package entry: ' + nextRelative)
}
}
visit(directory, '')
const hash = crypto.createHash('sha256')
for (const [relative, file] of files) {
hash.update(relative)
hash.update('\0')
hash.update(fs.readFileSync(file))
hash.update('\0')
}
return hash.digest('hex')
}
const result = {
component,
uid: process.geteuid(),
gid: process.getegid(),
capEff,
packages,
compilers,
forbiddenRoots,
sharedPackageHashes: Object.fromEntries(['blind-ipc', 'blind-protocol'].map(name => [
name,
hashTree(path.join(root, 'node_modules/@hiverelay', name))
])),
runtime: { uid: runtime.uid, gid: runtime.gid, mode: runtime.mode & 0o777 },
runtimeWritable: true,
peercredAddon: false,
peercredImport: false,
targetArchitecture: null,
data: null
}
try {
fs.accessSync('/run/hiverelay-blind', fs.constants.W_OK)
} catch {
result.runtimeWritable = false
}
const addon = path.join(root, 'node_modules/@hiverelay/blind-peercred/build/Release/blind_peercred.node')
result.peercredAddon = fs.statSync(addon).isFile()
const imported = await import(path.join(root, 'node_modules/@hiverelay/blind-peercred/index.js'))
result.peercredImport = typeof imported.socketPeerCredentials === 'function'
result.targetArchitecture = fs.readFileSync(path.join(root, 'peercred-target-architecture'), 'utf8').trim()
if (component === 'daemon') {
const data = fs.statSync('/data/blind')
result.data = { uid: data.uid, gid: data.gid, mode: data.mode & 0o777 }
}
process.stdout.write(JSON.stringify(result))
`
function imageInspect (image) {
return JSON.parse(execFileSync('docker', ['image', 'inspect', image], { cwd: root, encoding: 'utf8' }))[0]
}
function imageProbe (component, image) {
const output = execFileSync('docker', [
'run', '--rm',
'--cap-drop', 'ALL',
'--security-opt', 'no-new-privileges:true',
'--network', 'none',
'--env', `BLIND_PROBE_COMPONENT=${component}`,
'--env', `BLIND_PROBE_COMPILERS=${JSON.stringify(policy.forbiddenCompilerCommands)}`,
'--env', `BLIND_PROBE_FORBIDDEN_ROOTS=${JSON.stringify(policy.forbiddenRoots)}`,
'--entrypoint', 'node',
image,
'--input-type=module', '--eval', probeSource
], { cwd: root, encoding: 'utf8' })
return JSON.parse(output)
}
function verifyImage (component, image) {
const expected = policy.components[component]
const inspected = imageInspect(image)
const config = inspected.Config
const labels = config.Labels || {}
const probe = imageProbe(component, image)
assert.equal(config.User, expected.user)
assert.deepEqual(config.Entrypoint, expected.entrypoint)
assert.equal(labels['org.opencontainers.image.hiverelay.product-mode'], policy.productMode)
assert.equal(labels['org.opencontainers.image.hiverelay.component'], component)
assert.ok(labels[policy.bundleLabel])
assert.ok(config.Healthcheck && Array.isArray(config.Healthcheck.Test))
assert.deepEqual(probe.packages, expected.hiverelayPackages)
assert.deepEqual(probe.compilers, [])
assert.deepEqual(probe.forbiddenRoots, [])
assert.equal(probe.capEff, '0000000000000000')
assert.deepEqual(probe.runtime, { uid: 999, gid: 997, mode: 0o750 })
assert.equal(probe.uid, Number(expected.user.split(':')[0]))
assert.equal(probe.gid, 997)
assert.equal(probe.peercredAddon, true)
assert.equal(probe.peercredImport, true)
assert.equal(probe.targetArchitecture, inspected.Architecture)
const env = Object.fromEntries((config.Env || []).map(entry => {
const separator = entry.indexOf('=')
return [entry.slice(0, separator), entry.slice(separator + 1)]
}))
assert.equal(env.HIVERELAY_BLIND_UNARY_SOCKET, '/run/hiverelay-blind/unary.sock')
assert.equal(env.HIVERELAY_BLIND_STREAM_SOCKET, '/run/hiverelay-blind/stream.sock')
assert.equal(env.HIVERELAY_BLIND_DAEMON_UID, '999')
assert.equal(env.HIVERELAY_BLIND_DAEMON_GID, '997')
assert.equal(env.HIVERELAY_BLIND_SHARED_GID, '997')
assert.equal(env.HIVERELAY_BLIND_SOCKET, undefined)
for (const forbidden of policy.forbiddenHiverelayPackages) {
assert.equal(probe.packages.includes(forbidden), false)
}
if (component === 'edge') {
assert.equal(probe.packages.includes('blind-daemon'), false)
assert.equal(probe.packages.includes('blind-peercred'), true)
assert.equal(probe.runtimeWritable, false)
assert.ok(config.ExposedPorts && config.ExposedPorts['9100/tcp'])
} else {
assert.equal(probe.packages.includes('blind-edge'), false)
assert.equal(probe.runtimeWritable, true)
assert.deepEqual(probe.data, { uid: 999, gid: 997, mode: 0o700 })
assert.equal(config.ExposedPorts == null, true)
}
return {
component,
image,
id: inspected.Id,
architecture: inspected.Architecture,
packages: probe.packages,
sharedPackageHashes: probe.sharedPackageHashes
}
}
verifyStaticPackaging()
if (staticOnly) {
process.stdout.write('blind product packaging static smoke: ok\n')
process.exit(0)
}
if (!noBuild) command('docker', ['compose', '-f', 'docker-compose.blind.yml', 'build', 'blind-edge', 'blind-daemon'])
const edgeImage = process.env.HIVERELAY_BLIND_EDGE_IMAGE || policy.components.edge.image
const daemonImage = process.env.HIVERELAY_BLIND_DAEMON_IMAGE || policy.components.daemon.image
const edge = verifyImage('edge', edgeImage)
const daemon = verifyImage('daemon', daemonImage)
assert.notEqual(edge.id, daemon.id)
assert.deepEqual(edge.sharedPackageHashes, daemon.sharedPackageHashes)
const edgeBundle = imageInspect(edgeImage).Config.Labels[policy.bundleLabel]
const daemonBundle = imageInspect(daemonImage).Config.Labels[policy.bundleLabel]
assert.equal(edgeBundle, daemonBundle)
process.stdout.write(`${JSON.stringify({ schema: 'HiveRelayBlindImageSmokeV1', bundleId: edgeBundle, images: [edge, daemon] }, null, 2)}\n`)