Files
bare-operating-system/packages/bare-os-seeder/kernel/bin/test
T
Raven Scott 551d68ac6c - Peer admission: denylist, require-caps JSON, schema-2 results; optional
NDJSON audit + rate limit; env passthrough and handbook/appendix/docs
- /proc/bare_os/security_posture.json schema 4: vaultCryptoPrimitives,
  bareCryptoReportedVersion, expanded peerAdmission
- /proc/bare_os_features: pearIpcConservativeAdvertisement (names only)
- Syscall select returns pollClock with timeout; coreutils test -u/-g/-k
- Host env: BARE_OS_CTX_BARE_SUBPROCESS_SPAWN,
  BARE_OS_REPLICATION_PEER_PRIORITY_JSON, peer audit keys
- Placeholder scan: rename expandCmdsubstEmbedded; sendmsg wording
- Docs: vault threat model, preface Mermaid, protocol/changelog, posix
  matrix, holepunch clone audit refresh, developer-guide/kernel-program Wasm
- ctx.d.ts + gen-ctx-client-helper; booter CHANGELOG maintenance notes
2026-04-05 13:15:12 -04:00

201 lines
5.9 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* BARE_OS_BIN_API 1.0.0 — bump when staged /bin script semantics change (see developer guide). */
/** Shared helpers for drive-resident /bin scripts (prepended before each command). */
function bareStdin(ctx) {
return typeof ctx.shellStdin === 'string' ? ctx.shellStdin : ''
}
/** @param {number} mode @param {'file' | 'directory' | 'symlink'} type */
function bareFormatModeString(mode, type) {
const typeChar = type === 'directory' ? 'd' : type === 'symlink' ? 'l' : '-'
const perm = mode & 0o777
const r = (bit) => (perm & bit ? 'r' : '-')
const w = (bit) => (perm & bit ? 'w' : '-')
const x = (bit) => (perm & bit ? 'x' : '-')
return (
typeChar +
r(0o400) +
w(0o200) +
x(0o100) +
r(0o040) +
w(0o020) +
x(0o010) +
r(0o004) +
w(0o002) +
x(0o001)
)
}
/** @param {number} mtimeMs @param {number} [nowMs] */
function bareFormatLsMtime(mtimeMs, nowMs) {
const now = nowMs != null ? nowMs : Date.now()
const d = new Date(mtimeMs)
const months = [
'Jan',
'Feb',
'Mar',
'Apr',
'May',
'Jun',
'Jul',
'Aug',
'Sep',
'Oct',
'Nov',
'Dec'
]
const mon = months[d.getMonth()]
const day = String(d.getDate()).padStart(2, ' ')
const sixMo = 180 * 24 * 3600 * 1000
if (Math.abs(now - mtimeMs) > sixMo) {
const yr = String(d.getFullYear()).padStart(4, ' ')
return mon + ' ' + day + ' ' + yr
}
const hh = String(d.getHours()).padStart(2, '0')
const mm = String(d.getMinutes()).padStart(2, '0')
return mon + ' ' + day + ' ' + hh + ':' + mm
}
/** @param {number} size */
function barePosixBlocks(size) {
return Math.ceil(Number(size) / 512) || 0
}
/**
* Raw stdout for NUL/binary when **`process.stdout.write`** is missing.
* If **`ctx.bareOsBinWrite(Uint8Array|string)`** is set (tests / host), use it.
* @param {Record<string, unknown>} ctx
* @param {string | Uint8Array} chunk
* @returns {boolean}
*/
function bareOsEmitRaw(ctx, chunk) {
if (typeof ctx.bareOsBinWrite === 'function') {
const b4 = ctx.b4a
const u8 =
typeof chunk === 'string'
? b4 && typeof b4.from === 'function'
? b4.from(chunk)
: new TextEncoder().encode(chunk)
: chunk
ctx.bareOsBinWrite(u8 instanceof Uint8Array ? u8 : new Uint8Array(u8))
return true
}
const w = globalThis.process?.stdout?.write
if (typeof w === 'function') {
w.call(globalThis.process.stdout, chunk)
return true
}
return false
}
/** @param {string | number} s */
function parseBareOsTestInt(s) {
const t = String(s).trim()
if (t === '' || t === '+' || t === '-') return NaN
if (!/^[+-]?(?:0|[1-9][0-9]*)$/.test(t)) return NaN
const n = Number.parseInt(t, 10)
return Number.isSafeInteger(n) ? n : NaN
}
/** @param {Record<string, unknown>} ctx */
function testParseEuidEgid(ctx) {
const e = (ctx.vfs && ctx.vfs.env) || ctx.env || {}
const uid = Number.parseInt(String(e.UID != null ? e.UID : '1000'), 10)
const gid = Number.parseInt(String(e.GID != null ? e.GID : '1000'), 10)
return {
euid: Number.isFinite(uid) ? uid : 1000,
egid: Number.isFinite(gid) ? gid : 1000
}
}
/**
* User/group/other permission triplet (07) for the effective uid/gid.
* @param {Record<string, unknown>} st
* @param {number} euid
* @param {number} egid
*/
function testEffPermTriplet(st, euid, egid) {
const mode =
typeof st.mode === 'number'
? st.mode & 0o777
: Number.parseInt(String(st.mode || '644'), 8) & 0o777
const fuid = st.uid != null ? Number(st.uid) : 0
const fgid = st.gid != null ? Number(st.gid) : 0
if (euid === fuid) return (mode >> 6) & 7
if (egid === fgid) return (mode >> 3) & 7
return mode & 7
}
async function evalTest(ctx, args) {
if (!args.length) return false
if (args[0] === '!') {
const inner = await evalTest(ctx, args.slice(1))
return !inner
}
if (args.length === 3) {
const [a, op, b] = args
if (op === '-eq' || op === '-ne' || op === '-lt' || op === '-le' || op === '-gt' || op === '-ge') {
const la = parseBareOsTestInt(a)
const lb = parseBareOsTestInt(b)
if (!Number.isFinite(la) || !Number.isFinite(lb)) return false
switch (op) {
case '-eq':
return la === lb
case '-ne':
return la !== lb
case '-lt':
return la < lb
case '-le':
return la <= lb
case '-gt':
return la > lb
case '-ge':
return la >= lb
default:
return false
}
}
if (op === '=') return a === b
if (op === '!=') return a !== b
return false
}
if (args.length === 2) {
const op = args[0]
const p = args[1]
if (op === '-h' || op === '-L') {
const st = await ctx.vfs.lstat(p)
return st != null && st.type === 'symlink'
}
const { euid, egid } = testParseEuidEgid(ctx)
const st = await ctx.vfs.stat(p)
if (op === '-e' || op === '-a') return st != null
if (op === '-f') return st != null && st.type === 'file'
if (op === '-d') return st != null && st.type === 'directory'
if (op === '-r')
return st != null && (testEffPermTriplet(st, euid, egid) & 4) !== 0
if (op === '-w')
return st != null && (testEffPermTriplet(st, euid, egid) & 2) !== 0
if (op === '-x')
return st != null && (testEffPermTriplet(st, euid, egid) & 1) !== 0
if (st != null) {
const m =
typeof st.mode === 'number'
? st.mode
: Number.parseInt(String(st.mode || '0'), 8) || 0
if (op === '-u') return (m & 0o4000) !== 0
if (op === '-g') return (m & 0o2000) !== 0
if (op === '-k') return (m & 0o1000) !== 0
}
if (op === '-s')
return st != null && st.type === 'file' && Number(st.size) > 0
if (op === '-z') return p.length === 0
if (op === '-n') return p.length > 0
return false
}
if (args.length === 1) return args[0] !== ''
return false
}
async function run(ctx, argv) {
ctx.exitCode = (await evalTest(ctx, argv.slice(1))) ? 0 : 1
}