Network/auth/delegate hardening

hdms
Added ls alias to list.
Made delegate failures explicit and nonzero in packages/bare-os-coreutils/src/hdms.js.
Added nonzero error exit in packages/bare-os-booter/lib/hdms-manager.js.
git-pear
Implemented clone subcommand routing to git clone in packages/bare-os-coreutils/src/git-pear.js.
trustctl
Added ls alias to status/policy output in packages/bare-os-coreutils/src/trustctl.js.
oidc-publish
Added explicit unknown-subcommand handling and publish subcommand compatibility in packages/bare-os-coreutils/src/oidc-publish.js.
ssh-keygen
Wrapped delegate invocation with explicit error propagation in packages/bare-os-coreutils/src/ssh-keygen.js.
Added success output on generated keypair in packages/bare-os-booter/lib/ssh-keygen-cli.js.
sshd
Added -t config test mode and explicit exit semantics in packages/bare-os-booter/lib/bare-openssh.js.
Ensured wrapper sets exit code consistently in packages/bare-os-openssh/src/sshd.js.
telnet
Changed connector preference to use net.createConnection first when available, then syscall bridge fallback, in packages/bare-os-coreutils/src/telnet.js.
crontab -e flow

Implemented edit flow with VISUAL/EDITOR fallback, unlocked-state checks, temp file handling, install, and cleanup in packages/bare-os-coreutils/src/crontab.js.
Shell/runtime hardcore semantics

Added numeric brace range expansion {1..5} in packages/bare-os-booter/lib/shell-glob.js.
Enabled brace expansion by default unless explicitly disabled.
Added normalization for inline brace-expression tokens in packages/bare-os-booter/lib/shell.js.
Added arithmetic command-form handling for (( ... )) in packages/bare-os-booter/lib/shell.js.
Extended shell signal trap dispatch support for USR1/USR2 (in addition to INT/TERM) in packages/bare-os-booter/index.js.
Hardened kill command delivery validation in packages/bare-os-coreutils/src/kill.js.
Regression tests

Added new: packages/bare-os-coreutils/test/hardcore-bugs.test.mjs.
Extended shell tests in packages/bare-os-booter/test.js for:
default cmdsub behavior,
brace range expansion,
arithmetic command form.
Existing regression files still pass after updates.
This commit is contained in:
Raven Scott
2026-04-27 08:54:50 -04:00
parent d5535cdb65
commit 27292f2ba6
39 changed files with 670 additions and 100 deletions
+51
View File
@@ -137,6 +137,57 @@ async function run(ctx, argv) {
return
}
if (rest[0] === '-e') {
if (ctx.identity?.state !== 'unlocked') {
ctx.console.error('crontab: log in to edit crontab')
ctx.exitCode = 1
return
}
if (typeof ctx.runBinCommand !== 'function') {
ctx.console.error('crontab: -e requires runBinCommand support in this runtime')
ctx.exitCode = 1
return
}
const editorRaw = String(vfs.env?.VISUAL || vfs.env?.EDITOR || '').trim()
const editor = editorRaw || 'edit'
const editorParts = editor.split(/\s+/).filter(Boolean)
if (!editorParts.length) {
ctx.console.error('crontab: no editor configured')
ctx.exitCode = 1
return
}
const tmpPath = `${h}/.crontab.edit.${Date.now()}`
try {
const prev = await vfs.readFile(tabPath)
await vfs.writeFile(tmpPath, prev || ctx.b4a.from(''))
} catch (e) {
ctx.console.error('crontab: failed preparing editor buffer: ' + (e?.message || e))
ctx.exitCode = 1
return
}
try {
await ctx.runBinCommand([...editorParts, tmpPath])
const edited = await vfs.readFile(tmpPath)
if (edited == null) {
ctx.console.error('crontab: edit aborted (temporary file missing)')
ctx.exitCode = 1
return
}
await vfs.writeFile(tabPath, edited)
ctx.console.log('crontab: installed')
} catch (e) {
ctx.console.error('crontab: edit failed: ' + (e?.message || e))
ctx.exitCode = 1
} finally {
try {
await vfs.unlink(tmpPath)
} catch {
/* ignore temp cleanup errors */
}
}
return
}
if (rest[0].startsWith('-')) {
ctx.console.error('crontab: unknown option ' + rest[0])
ctx.exitCode = 1
+18
View File
@@ -106,6 +106,24 @@ async function run(ctx, argv) {
ctx.exitCode = 0
return
}
if (sub === 'clone') {
const url = String(argv[2] || '').trim()
const dir = argv[3]
if (!url) {
ctx.console.error('git-pear clone: missing repository URL')
ctx.exitCode = 1
return
}
if (typeof ctx.runBinCommand !== 'function') {
ctx.console.error('git-pear clone: runBinCommand unavailable')
ctx.exitCode = 1
return
}
const args = ['git', 'clone', url]
if (dir) args.push(String(dir))
await ctx.runBinCommand(args)
return
}
ctx.console.error('git-pear: unknown subcommand; use git-pear help')
ctx.exitCode = 1
}
+8 -1
View File
@@ -88,9 +88,16 @@ function bareOsEmitRaw(ctx, chunk) {
}
async function run(ctx, argv) {
if (argv[1] === 'ls') argv = [argv[0], 'list', ...argv.slice(2)]
if (typeof ctx.runHdms === 'function') {
await ctx.runHdms(argv)
try {
await ctx.runHdms(argv)
} catch (e) {
ctx.console.error('hdms: ' + ((e && e.message) || String(e)))
ctx.exitCode = 1
}
return
}
ctx.console.error('hdms: unavailable')
ctx.exitCode = 1
}
+10 -1
View File
@@ -170,7 +170,16 @@ async function run(ctx, argv) {
for (const t of targets) {
try {
const resolved = bareOsKillResolveTarget(t, ctx)
send.call(ctx, resolved, signal)
const r = send.call(ctx, resolved, signal)
if (
r &&
typeof r === 'object' &&
r.delivered === false &&
r.exists !== true &&
r.ignored !== true
) {
throw new Error('signal not delivered')
}
} catch (e) {
failed++
ctx.console.error('kill: ' + t + ': ' + (e?.message || String(e)))
+10 -3
View File
@@ -93,6 +93,7 @@ function bareOsEmitRaw(ctx, chunk) {
*/
async function run(ctx, argv) {
const args = argv.slice(1)
const sub = String(args[0] || '').trim()
if (args.includes('help') || args.includes('-h') || args.includes('--help')) {
ctx.console.log(`oidc-publish — optional OIDC token helper
@@ -108,10 +109,16 @@ async function run(ctx, argv) {
ctx.exitCode = 0
return
}
if (sub && sub !== 'publish') {
ctx.console.error('oidc-publish: unknown subcommand ' + sub + ' (use `oidc-publish publish` or no subcommand)')
ctx.exitCode = 1
return
}
const env = ctx.vfs?.env || {}
const issuer = String(env.OIDC_ISSUER || argv[2] || '').replace(/\/+$/, '')
const cid = String(env.OIDC_CLIENT_ID || argv[3] || '')
const csec = String(env.OIDC_CLIENT_SECRET || argv[4] || '')
const base = sub === 'publish' ? 2 : 1
const issuer = String(env.OIDC_ISSUER || argv[base + 1] || '').replace(/\/+$/, '')
const cid = String(env.OIDC_CLIENT_ID || argv[base + 2] || '')
const csec = String(env.OIDC_CLIENT_SECRET || argv[base + 3] || '')
if (!issuer || !cid || !csec) {
ctx.console.error(
'oidc-publish: set OIDC_ISSUER, OIDC_CLIENT_ID, OIDC_CLIENT_SECRET'
+6 -1
View File
@@ -106,7 +106,12 @@ async function run(ctx, argv) {
return
}
if (typeof ctx.bareOsRunSshKeygenCli === 'function') {
await ctx.bareOsRunSshKeygenCli(argv)
try {
await ctx.bareOsRunSshKeygenCli(argv)
} catch (e) {
ctx.console.error('ssh-keygen: ' + ((e && e.message) || String(e)))
ctx.exitCode = 1
}
return
}
ctx.console.error(
+24 -21
View File
@@ -435,6 +435,29 @@ function bareTelnetResolveConnector(ctx) {
return ctx.bareOsTelnetConnect(host, port, opts || {})
}
}
var req = null
try {
if (typeof globalThis.require === 'function') req = globalThis.require
} catch {
req = null
}
if (!req && typeof Bare !== 'undefined' && Bare && typeof Bare.require === 'function') req = Bare.require
if (req) {
try {
var net = req('net')
if (net && typeof net.createConnection === 'function') {
return function (host, port, opts) {
return net.createConnection({
host: host,
port: port,
family: opts && opts.family ? opts.family : undefined
})
}
}
} catch {
/* fall through to syscall bridge */
}
}
if (typeof ctx.bareOsSyscall === 'function') {
return function (host, port, opts) {
const handlers = new Map()
@@ -548,27 +571,7 @@ function bareTelnetResolveConnector(ctx) {
}
}
}
var req = null
try {
if (typeof globalThis.require === 'function') req = globalThis.require
} catch {
req = null
}
if (!req && typeof Bare !== 'undefined' && Bare && typeof Bare.require === 'function') req = Bare.require
if (!req) return null
try {
var net = req('net')
if (!net || typeof net.createConnection !== 'function') return null
return function (host, port, opts) {
return net.createConnection({
host: host,
port: port,
family: opts && opts.family ? opts.family : undefined
})
}
} catch {
return null
}
return null
}
function bareTelnetSleep(ms) {
+6 -2
View File
@@ -474,7 +474,11 @@ async function run(ctx, argv) {
}
const sub = String(args[0] || '').trim()
const policy = await bareOsTrustReadPolicy(ctx)
if (sub === 'status' || (sub === 'policy' && String(args[1] || '') === 'show')) {
if (
sub === 'status' ||
sub === 'ls' ||
(sub === 'policy' && String(args[1] || '') === 'show')
) {
bareP2pPrint(ctx, policy, opt)
return
}
@@ -523,7 +527,7 @@ async function run(ctx, argv) {
bareP2pPrint(ctx, { ok: true, signerPins: policy.signerPins }, opt)
return
}
const sug = bareP2pSuggestSubcommand(sub, ['status', 'inspect', 'pin', 'policy'])
const sug = bareP2pSuggestSubcommand(sub, ['status', 'ls', 'inspect', 'pin', 'policy'])
bareP2pError(
ctx,
argv0,