sh, diff/patch, sort, printf, find, test, getfacl/setfacl/xattr), expanded /proc and metrics (process table, syscalls, replication, net, security posture, worker budget, swarm/replication hints), initd DAG supervision metadata and richer restart journal telemetry, synthetic process groups via IPC (assignProcessGroup/signalProcessGroup) mirrored into process_table, optional kernel.ext.d incremental hot reload (BARE_OS_KERNEL_EXT_D_HOT_RELOAD) with reload audit NDJSON, features proc for hyperblobs dedup and systemd subset documentation, vault threat model doc plus posture fields for AEAD, Pear enclave pointer, account rotation continuity, and Ed25519 consistency across boot manifest / extensions / replication. Adds or extends tests and keeps kernel/ and packages/bare-os-seeder/kernel/ in parity; guest init is bundled from kernel/lib/init/init-main.js via bundle-kernel-init.
283 lines
8.6 KiB
JavaScript
283 lines
8.6 KiB
JavaScript
/**
|
|
* Bundle every bare-module-manifest entry into IIFE scripts under bundles/ so the
|
|
* system image can populate ctx.bare without relying on the Pear host node_modules.
|
|
* Fail-fast: any esbuild error aborts the build (no stub placeholders).
|
|
*/
|
|
import {
|
|
readFile,
|
|
writeFile,
|
|
mkdir,
|
|
copyFile,
|
|
readdir,
|
|
unlink
|
|
} from 'node:fs/promises'
|
|
import { execSync } from 'node:child_process'
|
|
import { dirname, join } from 'node:path'
|
|
import { fileURLToPath, pathToFileURL } from 'node:url'
|
|
import * as esbuild from 'esbuild'
|
|
|
|
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
const repoRoot = join(__dirname, '..', '..')
|
|
const manifestPath = join(
|
|
repoRoot,
|
|
'packages/bare-os-booter/lib/bare-module-manifest.json'
|
|
)
|
|
const kernelLibBare = join(repoRoot, 'kernel/lib/bare')
|
|
const seederLibBare = join(repoRoot, 'packages/bare-os-seeder/kernel/lib/bare')
|
|
const bundlesKernel = join(kernelLibBare, 'bundles')
|
|
const bundlesSeeder = join(seederLibBare, 'bundles')
|
|
|
|
const STDLIB_GLOBAL = '__bare_os_stdlib__'
|
|
const IIFE_GLOBAL = '__bare_os_bundle_exports__'
|
|
|
|
const BUNDLE_CONCURRENCY = 6
|
|
|
|
function readGitHead(cwd) {
|
|
try {
|
|
return execSync('git rev-parse HEAD', {
|
|
cwd,
|
|
encoding: 'utf8',
|
|
stdio: ['ignore', 'pipe', 'ignore']
|
|
}).trim()
|
|
} catch {
|
|
return ''
|
|
}
|
|
}
|
|
|
|
/** Resolve bare-native `imports` subpath specifiers (#web-view / #window) for the host OS. */
|
|
function bareNativeConditionalImportsPlugin() {
|
|
const bareNativeRoot = join(repoRoot, 'node_modules/bare-native')
|
|
function webViewAbs() {
|
|
const p = process.platform
|
|
if (p === 'darwin' || p === 'ios') return join(bareNativeRoot, 'lib/web-view/apple.js')
|
|
if (p === 'win32') return join(bareNativeRoot, 'lib/web-view/win32.js')
|
|
if (p === 'android') return join(bareNativeRoot, 'lib/web-view/android.js')
|
|
return join(bareNativeRoot, 'lib/web-view/linux.js')
|
|
}
|
|
function windowAbs() {
|
|
const p = process.platform
|
|
if (p === 'darwin') return join(bareNativeRoot, 'lib/window/darwin.js')
|
|
if (p === 'ios') return join(bareNativeRoot, 'lib/window/ios.js')
|
|
if (p === 'win32') return join(bareNativeRoot, 'lib/window/win32.js')
|
|
if (p === 'android') return join(bareNativeRoot, 'lib/window/android.js')
|
|
return join(bareNativeRoot, 'lib/window/linux.js')
|
|
}
|
|
return {
|
|
name: 'bare-native-subpath-imports',
|
|
setup(build) {
|
|
build.onResolve({ filter: /^#web-view$/ }, () => ({ path: webViewAbs() }))
|
|
build.onResolve({ filter: /^#window$/ }, () => ({ path: windowAbs() }))
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @template T
|
|
* @param {T[]} items
|
|
* @param {number} concurrency
|
|
* @param {(item: T, index: number) => Promise<void>} fn
|
|
*/
|
|
async function runPool(items, concurrency, fn) {
|
|
let i = 0
|
|
async function worker() {
|
|
while (i < items.length) {
|
|
const idx = i++
|
|
await fn(items[idx], idx)
|
|
}
|
|
}
|
|
await Promise.all(Array.from({ length: concurrency }, () => worker()))
|
|
}
|
|
|
|
function stdinForEntry(ent) {
|
|
const pkg = ent.package
|
|
if (ent.sideEffectImport) {
|
|
return `import ${JSON.stringify(pkg)};\nexport default true;\n`
|
|
}
|
|
if (ent.export === '*') {
|
|
return `import * as _m from ${JSON.stringify(pkg)};\nexport default _m;\n`
|
|
}
|
|
return `import _m from ${JSON.stringify(pkg)};\nexport default _m;\n`
|
|
}
|
|
|
|
export async function buildBareLibs() {
|
|
const manifest = JSON.parse(await readFile(manifestPath, 'utf8'))
|
|
const entries = Array.isArray(manifest.entries) ? manifest.entries : []
|
|
const tierFilter = String(process.env.BARE_OS_BUNDLE_TIER || '')
|
|
.trim()
|
|
.toLowerCase()
|
|
const toBundle = entries
|
|
.filter((e) => e.ctxKey && e.package)
|
|
.filter((e) => {
|
|
if (!tierFilter || tierFilter === 'all') return true
|
|
const t = (e.tier && String(e.tier).toLowerCase()) || 'core'
|
|
return t === tierFilter
|
|
})
|
|
|
|
await mkdir(bundlesKernel, { recursive: true })
|
|
await mkdir(bundlesSeeder, { recursive: true })
|
|
|
|
/** @type {{ path: string, keys: string[] }[]} */
|
|
const bundles = []
|
|
/** @type {{ ctxKey: string, package: string, path: string, bytes: number }[]} */
|
|
const bundleDiagnostics = []
|
|
let ok = 0
|
|
|
|
await runPool(toBundle, BUNDLE_CONCURRENCY, async (ent) => {
|
|
const ctxKey = ent.ctxKey
|
|
const pkg = ent.package
|
|
const outfile = join(bundlesKernel, `${ctxKey}.js`)
|
|
const outfileSeeder = join(bundlesSeeder, `${ctxKey}.js`)
|
|
const footer = `;(function(){var g=globalThis;var s=${JSON.stringify(STDLIB_GLOBAL)};g[s]=g[s]||{};var e=typeof ${IIFE_GLOBAL}!=="undefined"?${IIFE_GLOBAL}:void 0;var v=e!=null&&typeof e==="object"&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e;g[s][${JSON.stringify(ctxKey)}]=v;})();`
|
|
|
|
try {
|
|
await esbuild.build({
|
|
stdin: {
|
|
contents: stdinForEntry(ent),
|
|
resolveDir: repoRoot,
|
|
sourcefile: `bare-lib-entry-${ctxKey}.js`,
|
|
loader: 'js'
|
|
},
|
|
bundle: true,
|
|
format: 'iife',
|
|
globalName: IIFE_GLOBAL,
|
|
platform: 'node',
|
|
nodePaths: [join(repoRoot, 'node_modules')],
|
|
plugins: [bareNativeConditionalImportsPlugin()],
|
|
outfile,
|
|
footer: { js: footer },
|
|
logLevel: 'silent'
|
|
})
|
|
} catch (err) {
|
|
const msg = err?.message || String(err)
|
|
console.error(
|
|
'[bare-os-bare-libs] bundle failed',
|
|
ctxKey,
|
|
'(' + pkg + '):',
|
|
msg
|
|
)
|
|
throw new Error(
|
|
`[bare-os-bare-libs] esbuild failed for ${ctxKey} (${pkg}): ${msg}`
|
|
)
|
|
}
|
|
|
|
ok++
|
|
bundles.push({
|
|
path: `/lib/bare/bundles/${ctxKey}.js`,
|
|
keys: [ctxKey]
|
|
})
|
|
|
|
const built = await readFile(outfile)
|
|
await writeFile(outfileSeeder, built)
|
|
bundleDiagnostics.push({
|
|
ctxKey,
|
|
package: pkg,
|
|
path: `/lib/bare/bundles/${ctxKey}.js`,
|
|
bytes: built.length
|
|
})
|
|
})
|
|
|
|
bundleDiagnostics.sort((a, b) => a.ctxKey.localeCompare(b.ctxKey))
|
|
|
|
const builtNames = new Set(bundleDiagnostics.map((d) => `${d.ctxKey}.js`))
|
|
async function pruneStaleBundles(dir) {
|
|
let names
|
|
try {
|
|
names = await readdir(dir)
|
|
} catch {
|
|
return
|
|
}
|
|
for (const name of names) {
|
|
if (!name.endsWith('.js')) continue
|
|
if (builtNames.has(name)) continue
|
|
await unlink(join(dir, name))
|
|
console.warn('[bare-os-bare-libs] removed stale bundle', name)
|
|
}
|
|
}
|
|
await pruneStaleBundles(bundlesKernel)
|
|
await pruneStaleBundles(bundlesSeeder)
|
|
|
|
const { sanitizeBareBundlesInDir } = await import(
|
|
pathToFileURL(join(repoRoot, 'scripts/sanitize-bare-bundles.mjs')).href
|
|
)
|
|
sanitizeBareBundlesInDir(bundlesKernel)
|
|
sanitizeBareBundlesInDir(bundlesSeeder)
|
|
|
|
for (const row of bundleDiagnostics) {
|
|
const rel = join(bundlesKernel, `${row.ctxKey}.js`)
|
|
try {
|
|
const buf = await readFile(rel)
|
|
row.bytes = buf.length
|
|
} catch {
|
|
/* keep prior */
|
|
}
|
|
}
|
|
|
|
const driveManifest = {
|
|
version: 1,
|
|
bundles,
|
|
bundleStats: { ok, failed: 0, attempted: toBundle.length },
|
|
bundleDiagnostics,
|
|
bundleProvenance: {
|
|
schemaVersion: 1,
|
|
generatedAt: new Date().toISOString(),
|
|
gitCommit: readGitHead(repoRoot),
|
|
nodeVersion: process.version,
|
|
bundleTier: tierFilter && tierFilter !== 'all' ? tierFilter : 'all',
|
|
normativeManifest: 'packages/bare-os-booter/lib/bare-module-manifest.json',
|
|
buildScript: 'packages/bare-os-bare-libs/build.mjs'
|
|
}
|
|
}
|
|
const json = JSON.stringify(driveManifest, null, 2) + '\n'
|
|
await writeFile(join(kernelLibBare, 'manifest.json'), json)
|
|
await writeFile(join(seederLibBare, 'manifest.json'), json)
|
|
|
|
const bundleHealthPath = join(repoRoot, 'docs/audit/bundle-health.json')
|
|
const bundleHealth = {
|
|
schemaVersion: 1,
|
|
generatedAt: new Date().toISOString(),
|
|
normativeManifest: 'packages/bare-os-booter/lib/bare-module-manifest.json',
|
|
buildTool: 'packages/bare-os-bare-libs/build.mjs',
|
|
bundles: bundleDiagnostics,
|
|
bundleStats: { ok, failed: 0, attempted: toBundle.length }
|
|
}
|
|
await writeFile(
|
|
bundleHealthPath,
|
|
JSON.stringify(bundleHealth, null, 2) + '\n'
|
|
)
|
|
|
|
await copyFile(
|
|
manifestPath,
|
|
join(kernelLibBare, 'bare-module-manifest.json')
|
|
)
|
|
await copyFile(
|
|
manifestPath,
|
|
join(seederLibBare, 'bare-module-manifest.json')
|
|
)
|
|
|
|
const readmeSrc = join(__dirname, 'README.kernel-lib-bare.md')
|
|
const readmeDstKernel = join(kernelLibBare, 'README.md')
|
|
const readmeDstSeeder = join(seederLibBare, 'README.md')
|
|
try {
|
|
await copyFile(readmeSrc, readmeDstKernel)
|
|
await copyFile(readmeSrc, readmeDstSeeder)
|
|
} catch {
|
|
/* optional */
|
|
}
|
|
|
|
console.log(
|
|
'[bare-os-bare-libs] bundles:',
|
|
ok,
|
|
'ok,',
|
|
toBundle.length,
|
|
'attempted →',
|
|
kernelLibBare
|
|
)
|
|
}
|
|
|
|
if (
|
|
process.argv[1] &&
|
|
import.meta.url === pathToFileURL(process.argv[1]).href
|
|
) {
|
|
await buildBareLibs()
|
|
}
|