- 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
93 lines
2.9 KiB
JavaScript
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
|
|
}
|