Files
bare-operating-system/packages/bare-os-booter/lib/bare-os-sandbox.js
T
Raven Scott 8c3151319d feat(kernel): expand stock image, boot policy, and ecosystem integration
- Stock kernel: boot.policy v2 (maxExecLineDepth, denyEnvKeys, requireProcNodes);
  richer BARE_OS_KERNEL_SELFTEST; example policy and timer drop-in samples
- Protocol: feature bits 28–30, seed RPCs (manifest_hints, peer_health, staging_slot)
- Booter: /proc mirrors, provenance, metrics_live, pear IPC registry, initd DAG,
  suspend/resume wiring, exec budget, shell ${var} expansion, delegate limits,
  telemetry v3 / OTel JSONL, ctx API 1.11.0
- Coreutils: /bin/timeout; seeder Pear/Bare: avoid bare process.env (globalThis.process?.env)
- CI: verify-ctx-api-feature-bits; docs: handbook, developer-guide, kernel-extensions,
  capabilities index, environment appendix, READMEs
2026-04-04 01:41:27 -04:00

93 lines
2.9 KiB
JavaScript

/**
* Reduced `ctx` for `bareOsSandboxRunScript`: personal-drive writes only, no identity hooks.
*
* Stronger isolation (separate worker / bundle evaluate) is an optional future path; see
* holepunch `cross-worker` and `bare-bundle-evaluate` for Bare/Pear patterns. When
* `BARE_OS_SANDBOX_WORKER=1`, the booter defers evaluation on a fresh microtask only
* (not a separate thread); see developer-guide security chapter.
*/
import { isPersonalRoute } from './vfs-posix-meta.js'
/**
* @param {Record<string, unknown>} ctx
* @returns {boolean}
*/
function sandboxWritesOk(ctx, logicalPath) {
const vfs = ctx.vfs
if (!vfs || typeof vfs.resolveLogical !== 'function') return false
if (typeof vfs.route !== 'function') return false
const abs = vfs.resolveLogical(logicalPath)
const r = vfs.route(abs)
const pd = ctx.personalDrive
if (!pd) return false
return isPersonalRoute(pd, r)
}
/**
* @param {Record<string, unknown>} ctx
*/
export function createBareOsSandboxContext(ctx) {
const vfs = ctx.vfs
if (!vfs) throw new Error('bareOsSandboxRunScript: missing vfs')
/**
* @param {string} name
* @param {(...args: unknown[]) => unknown} fn
* @param {number} pathArgIndex
*/
const wrapWrite = (name, fn, pathArgIndex = 0) => {
if (typeof fn !== 'function') return fn
return async function (...args) {
const path = args[pathArgIndex]
if (typeof path === 'string' && !sandboxWritesOk(ctx, path)) {
throw new Error(`sandbox: ${name}: write denied outside personal namespace`)
}
return fn.apply(vfs, args)
}
}
const sandboxVfs = Object.assign(Object.create(Object.getPrototypeOf(vfs)), vfs, {
writeFile: wrapWrite('writeFile', vfs.writeFile, 0),
mkdir: wrapWrite('mkdir', vfs.mkdir, 0),
unlink: wrapWrite('unlink', vfs.unlink, 0),
rmdir: wrapWrite('rmdir', vfs.rmdir, 0),
chmod: wrapWrite('chmod', vfs.chmod, 0),
chown: wrapWrite('chown', vfs.chown, 0),
symlink: wrapWrite('symlink', vfs.symlink, 1)
})
/** @type {Record<string, unknown>} */
const o = Object.assign({}, ctx, {
vfs: sandboxVfs,
bareOsSandboxed: true,
async applyUnlock() {
throw new Error('sandbox: identity unlock disabled')
},
async applyRegister() {
throw new Error('sandbox: identity register disabled')
},
async applyLogin() {
throw new Error('sandbox: identity login disabled')
},
async applyLogout() {
throw new Error('sandbox: identity logout disabled')
},
async saveVault() {
throw new Error('sandbox: saveVault disabled')
},
registerKernelShutdownHook() {},
bareOsRegisterVirtualFile() {
throw new Error('sandbox: bareOsRegisterVirtualFile disabled')
},
bareOsInvalidateVirtualFile() {
throw new Error('sandbox: bareOsInvalidateVirtualFile disabled')
},
bareOsUpdateVirtualFileMeta() {
throw new Error('sandbox: bareOsUpdateVirtualFileMeta disabled')
}
})
return o
}