feat(booter): complete P2P POSIX roadmap items and doc alignment
- ADRs under docs/adr/; KERNEL_CONTRACT + env appendix + handbook updates - socketMsgSurface schema 5; replication_snapshot schema 2; syscall/example + tests - MBR pacing docs/microbench; export mbrReadTimeoutMsForDisk; shell passthrough envs - verify-ctx-api-feature-bits: syscall schema vs posix-compliance-matrix - Wasm hostname import, disk.os snapshot hints, kernel-ext resolution docs - coreutils nice + matrix/dashboard; syscalls.example ctxApiVersion 1.51.1 - Seeder kernel rsync parity; assorted booter/protocol doc fixes
This commit is contained in:
@@ -5,7 +5,7 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
|
||||
## Maintenance
|
||||
|
||||
- **Host filesystem**: first-party booter and seeder sources use **`import … from '#host-fs'`** / **`#host-path`** (and seeder **`#host-fs-promises`**) so Bare resolves **`bare-fs`** / **`bare-path`** and Node resolves the built-in **`fs`** / **`path`** modules via the default **`imports`** condition. **`bare-fs`** is a direct **`dependencies`** entry of **`bare-os-booter`**. CI: **`scripts/verify-pear-no-static-node-import.mjs`** rejects bare **`fs`** / **`path`** specifiers.
|
||||
- **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **10** with **`socketMsgSurface` schema 4** (`logicalScmRightsOnSend`); includes **`posixXsh`** (**`posix_fadvise`** simulated), **`fdModel`**, **`errnoHints`**; JSON text **cached** until **`vfs.bareOsClearWarmReadCaches`**. **`/proc/bare_os/process_table.json`** schema **7**; **`/proc/bare_os/protomux.json`** wire text schema **2**; **`/dev/shm`** in-memory named segments. **`/proc/bare_os/security_posture.json`** schema **4** — **`vaultCryptoPrimitives`**, **`bareCryptoReportedVersion`**, **`peerAdmission`** (**denylist**, **`requireCaps`**, NDJSON audit env pointers). **`/proc/bare_os_features`**: **`pearIpcConservativeAdvertisement`** (channel names only; no host wiring claim). Protocol export **`BARE_OS_POSIX_PROFILE_*`**.
|
||||
- **POSIX / proc**: **`/proc/bare_os/syscalls.json`** schema **10** with **`socketMsgSurface` schema 5** (`logicalScmRightsOnSend`); includes **`posixXsh`** (**`posix_fadvise`** simulated), **`fdModel`**, **`errnoHints`**; JSON text **cached** until **`vfs.bareOsClearWarmReadCaches`**. **`/proc/bare_os/process_table.json`** schema **7**; **`/proc/bare_os/protomux.json`** wire text schema **2**; **`/dev/shm`** in-memory named segments. **`/proc/bare_os/security_posture.json`** schema **5** — adds **`blindPeeringOperatorSketch`** env gate pointers; **`vaultCryptoPrimitives`**, **`bareCryptoReportedVersion`**, **`peerAdmission`**. **`/proc/bare_os_features`**: **`protomuxAppChannel`** advertisement + **`pearIpcConservativeAdvertisement`**. Protocol export **`BARE_OS_POSIX_PROFILE_*`**.
|
||||
- **Blind-relay / pairing / geo proc** (default): **`bareOsProcBlindPeerRelayHintsMinimal`** returns **schema 1** with **`operatorRedacted: true`**. The legacy export **`bareOsProcBlindPeerRelayHintsStub`** was removed; use **`bareOsProcBlindPeerRelayHintsMinimal`** only.
|
||||
- **Vendored bundles**: post-esbuild **`scripts/sanitize-bare-bundles.mjs`** (from **`bare-os-bare-libs/build.mjs`**) strips CI-forbidden markers and replaces **`node:`** requires in **`bareDev.js`** with **`bare-*`** modules.
|
||||
- **Boot hooks (naming)**: canonical **`bareOsRegisterBootStepHook`**, **`bareOsInvokeBootStepHooks`**, **`bareOsEmitBareBootStepHint`**; legacy **`*BootPhase*`** methods remain thin wrappers (**no `bareOsCtxApiVersion` bump**). See [docs/reference/naming-alias-matrix.md](../../docs/reference/naming-alias-matrix.md).
|
||||
@@ -18,6 +18,7 @@ Authoritative **version alignment** with protocol and telemetry schema numbers l
|
||||
|
||||
| Version | Booter (workspace) | Notes |
|
||||
| ------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| 1.51.1 | 0.1.0 | **`disk.os` `bare_os.replication_snapshot`** JSON **schema 2** — merges seed snapshot hints / manifest slice / chain + **`BARE_OS_CORESTORE_SNAPSHOT_JSON`**. Shell **`BARE_OS_SHELL_NOUNSET`** / **`set -u`** / **`set -o nounset`**. Wasm **`BARE_OS_WASM_KERNEL_HOSTNAME_IMPORT`** → **`env.bare_os_hostname_peek`**. **`ctx.bareOsTrySpawnHostSubprocess`** merges default **`timeoutMs`** from **`BARE_OS_BARE_SUBPROCESS_TIMEOUT_MS`**. **`/proc/bare_os_features`**: **`protomuxAppChannel`**. **`/proc/bare_os/security_posture.json`** schema **5** (**`blindPeeringOperatorSketch`**). Swarm disk: **`BARE_OS_MBR_READ_TIMEOUT_MS`**, **`BARE_OS_MBR_READ_TIMEOUT_ADAPTIVE`**. Kernel **`kernel-ext-resolution.json`** schema **3** + **`BARE_OS_KERNEL_EXT_RESOLUTION_JSON_ALWAYS`**. Seeder multisig logs via **`seedLog`**. |
|
||||
| 1.51.0 | 0.1.0 | **`disk.os` `bare_os.replication_operator_sketch`** JSON **schema 5** — optional **`corestoreOperatorSketch`** from host **`BARE_OS_CORESTORE_STATS_JSON`**. **`/proc/bare_os/syscalls.json`** schema **10** — **`ctx.bareOsSyscall('posix_fadvise')`** simulated no-op; **`getconf`** / **`posix-compliance-matrix`** syscall op list includes **`posix_fadvise`**. **`hrpc_allowlist_sketch`** proc **schema 3** + **`routeTableSchemaVersion`** ( **`bare-os-hrpc-route-table.js`** ). **`export -p`** shell builtin. Optional **`kernel.ext.d` `provides`** version conflict detection (strict boot). Runtime caps: **`swarm_health`** proc paths. |
|
||||
| 1.50.0 | 0.1.0 | Optional **`BARE_OS_SHELL_READ_BUILTIN`** **`read`** builtin (bounded stdin / **`readLine`**). Expanded **`bareOsGetconfSysconf`** **`_SC_BARE_OS_*`** runtime caps (pipeline, glob, swarm, socket queues). **`pathconf`**: **`BARE_OS_PERSONAL_ACCT_PREFIX`** + union — **`_PC_NO_TRUNC`** stays **1** under **`/.bare-os/acct/…`**. Socket bridge **`SO_SNDBUF`/`SO_RCVBUF`** logical **`getsockopt`/`setsockopt`**. **`metrics_live.replicationLive`** schema **3** + **`corestoreSnapshotSurface`**; **`bootBudget*`** schema **2** + **`bootBudgetTelemetry`**. Wasm **`BARE_OS_WASM_KERNEL_MONOTONIC_MS`** → **`env.bare_os_monotonic_ms`**. MQ priority tie-break FIFO (**`posixMessageQueues` schema 2**). Blind-relay swarm proc **schema 3** (**`blindPeerStack`**). Hyperbee guest hint **schema 2** (**`hyperbee2ReadSurface`**). **`/run/bare-os/boot-perf.json`**: **`bootBudgetStrict`** / **`bootPolicyStrict`**. |
|
||||
| 1.49.0 | 0.1.0 | **`ctx.bareOsTrySpawnHostSubprocess`**: optional **`BARE_OS_CTX_BARE_SUBPROCESS_SPAWN`** prefers **`ctx.bare.bareSubprocess.spawn`** when merged. **`/proc/bare_os/extensions.json`** schema **9** (**`resolverModule`**, per-entry **`loadMs`**). **`bareOsPosixPoll`** zero-timeout path includes **`pollClock`**; **`bareOsSyscall('select')`** forwards **`pollClock`** when **`timeoutMs` > 0. **`disk.os` `replication_operator_sketch`** adds **`peerPrioritySketch`** from **`BARE_OS_REPLICATION_PEER_PRIORITY_JSON`**. Warm-cache explicit invalidation counts replication reasons (**`vfs.warm_read_cache_invalidate_replication`**). Cooperative shell job yield (**`suspend-job`** / **`fg`**) + **`foregroundPgid`** on **`fg`**. Peer admission **schema 2** (**`BARE_OS_PEER_DENYLIST_HEX`**, **`BARE_OS_PEER_REQUIRE_CAPS_JSON`**, optional **`BARE_OS_PEER_ADMISSION_AUDIT_NDJSON`** / **`BARE_OS_PEER_ADMISSION_AUDIT_RATE_MS`**). Host env passthrough adds **`BARE_OS_CTX_BARE_SUBPROCESS_SPAWN`**, **`BARE_OS_REPLICATION_PEER_PRIORITY_JSON`**, peer-policy keys. |
|
||||
|
||||
@@ -606,6 +606,8 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
'BARE_OS_SHELL_READ_BUILTIN',
|
||||
'BARE_OS_SHELL_READ_MAX_BYTES',
|
||||
'BARE_OS_SHELL_POSIX_MODE',
|
||||
'BARE_OS_SHELL_ERREXIT',
|
||||
'BARE_OS_SHELL_NOUNSET',
|
||||
'BARE_OS_TELEMETRY_NDJSON',
|
||||
'BARE_OS_TELEMETRY_OTEL_JSONL',
|
||||
'BARE_OS_PROC_POLL_MS',
|
||||
@@ -642,12 +644,14 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
'BARE_OS_BOOT_CAPABILITY_CONTRACT_DEBUG',
|
||||
'BARE_OS_BOOT_EXT_RESOLUTION_TRACE',
|
||||
'BARE_OS_KERNEL_EXT_GRAPH',
|
||||
'BARE_OS_KERNEL_EXT_RESOLUTION_JSON_ALWAYS',
|
||||
'BARE_OS_BOOT_RC_RESOLUTION_TRACE',
|
||||
'BARE_OS_WARM_REBOOT',
|
||||
'BARE_OS_WARM_REBOOT_EXTRA_CYCLES',
|
||||
'BARE_OS_WASM_KERNEL',
|
||||
'BARE_OS_WASM_KERNEL_SYSCALL',
|
||||
'BARE_OS_WASM_KERNEL_MONOTONIC_MS',
|
||||
'BARE_OS_WASM_KERNEL_HOSTNAME_IMPORT',
|
||||
'BARE_OS_POSIX_FD_SIM',
|
||||
'BARE_OS_POSIX_FD_SIM_MAX_BYTES',
|
||||
'BARE_OS_POSIX_SOCKET_FD_BRIDGE',
|
||||
@@ -1469,6 +1473,17 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
).trim() || undefined,
|
||||
note: 'OTA / Pear stage hints for operators; compare pear-runtime-updater docs on Holepunch.'
|
||||
},
|
||||
protomuxAppChannel: {
|
||||
schema: 1,
|
||||
protocolName: 'bare-os-app-v1',
|
||||
envGate: 'BARE_OS_PROTOMUX_APP_CHANNEL',
|
||||
hostEnabled:
|
||||
shellEnv.BARE_OS_PROTOMUX_APP_CHANNEL === '1' ||
|
||||
shellEnv.BARE_OS_PROTOMUX_APP_CHANNEL === 'true',
|
||||
operatorMetric: 'disk.os replication_operator_sketch.protomuxOperatorSketch.protomuxAppChannelRxTotal',
|
||||
note:
|
||||
'Optional second Protomux channel paired alongside bare-os-v1 for app-tier traffic; control plane stays on PROTOCOL_NAME.'
|
||||
},
|
||||
pearIpcConservativeAdvertisement: {
|
||||
schema: 2,
|
||||
note:
|
||||
@@ -1551,8 +1566,8 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
10
|
||||
)
|
||||
return `${JSON.stringify({
|
||||
schema: 4,
|
||||
note: 'Non-secret security posture snapshot; no vault or key material.',
|
||||
schema: 5,
|
||||
note: 'Non-secret security posture snapshot; no vault or key material. Schema 5 adds blindPeeringOperatorSketch env gates.',
|
||||
bootPolicyMerged: bootPol,
|
||||
bootPolicyStrict: strict,
|
||||
sandboxScript:
|
||||
@@ -1613,6 +1628,21 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
schema: 1,
|
||||
note: 'Replication RPC may carry attestation blobs; guests verify only when operator policy enables pinned validators.'
|
||||
},
|
||||
blindPeeringOperatorSketch: {
|
||||
schema: 1,
|
||||
blindPeerTopologyV3JsonEnv: 'BARE_OS_BLIND_PEER_TOPOLOGY_V3_JSON',
|
||||
blindPeerRouterJsonEnv: 'BARE_OS_BLIND_PEER_ROUTER_JSON',
|
||||
blindPeeringJsonPresent: !!(
|
||||
shellEnv.BARE_OS_BLIND_PEER_ROUTER_JSON &&
|
||||
String(shellEnv.BARE_OS_BLIND_PEER_ROUTER_JSON).trim()
|
||||
),
|
||||
blindTopologyV3JsonPresent: !!(
|
||||
shellEnv.BARE_OS_BLIND_PEER_TOPOLOGY_V3_JSON &&
|
||||
String(shellEnv.BARE_OS_BLIND_PEER_TOPOLOGY_V3_JSON).trim()
|
||||
),
|
||||
note:
|
||||
'Non-secret env gates only; JSON bodies are not echoed here. Wire blind-peering / blind-peer-router operator configs on the host, then read sketches via disk.os replication_operator_sketch.'
|
||||
},
|
||||
peerAdmission: {
|
||||
schema: 2,
|
||||
allowlistConfigured: !!(
|
||||
@@ -4328,6 +4358,20 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
...(opts && typeof opts === 'object' ? opts : {}),
|
||||
stdio: 'pipe'
|
||||
}
|
||||
const envT = Math.floor(
|
||||
Number(
|
||||
spawnOpts.timeoutMs != null
|
||||
? spawnOpts.timeoutMs
|
||||
: shellEnv.BARE_OS_BARE_SUBPROCESS_TIMEOUT_MS
|
||||
)
|
||||
)
|
||||
if (
|
||||
spawnOpts.timeoutMs == null &&
|
||||
Number.isFinite(envT) &&
|
||||
envT > 0
|
||||
) {
|
||||
spawnOpts.timeoutMs = Math.min(envT, 3_600_000)
|
||||
}
|
||||
const pushJob = (backend) => {
|
||||
if (!Array.isArray(this.bareOsHostSubprocessJobs)) {
|
||||
this.bareOsHostSubprocessJobs = []
|
||||
@@ -6732,7 +6776,7 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
flags: 0,
|
||||
controllen: 0,
|
||||
note:
|
||||
'TCP bridge: single flat buffer; recv ancillary controllen 0 (socketMsgSurface schema 4).'
|
||||
'TCP bridge: single flat buffer; recv ancillary controllen 0 (socketMsgSurface schema 5).'
|
||||
}
|
||||
}
|
||||
return base
|
||||
@@ -9111,6 +9155,19 @@ async function executeKernel(disk, store, swarm, initSource) {
|
||||
typeof disk.seedHttpDhtProxyHint === 'object'
|
||||
? disk.seedHttpDhtProxyHint
|
||||
: null,
|
||||
seedSnapshotHints:
|
||||
disk.seedSnapshotHints && typeof disk.seedSnapshotHints === 'object'
|
||||
? disk.seedSnapshotHints
|
||||
: null,
|
||||
seedSnapshotManifestSlice:
|
||||
disk.seedSnapshotManifestSlice &&
|
||||
typeof disk.seedSnapshotManifestSlice === 'object'
|
||||
? disk.seedSnapshotManifestSlice
|
||||
: null,
|
||||
seedSnapshotChain:
|
||||
disk.seedSnapshotChain && typeof disk.seedSnapshotChain === 'object'
|
||||
? disk.seedSnapshotChain
|
||||
: null,
|
||||
swarmPeerCount:
|
||||
disk.peers && typeof disk.peers.size === 'number'
|
||||
? disk.peers.size
|
||||
|
||||
@@ -2,4 +2,4 @@
|
||||
* Semantic version of the booter `ctx` contract for custom kernels.
|
||||
* Bump when adding/removing/renaming documented `ctx` fields or changing behavior.
|
||||
*/
|
||||
export const BARE_OS_CTX_API_VERSION = '1.51.0'
|
||||
export const BARE_OS_CTX_API_VERSION = '1.51.1'
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* Stable shapes for custom kernels and `/bin` utilities (best-effort; full `ctx` is assembled in `index.js`).
|
||||
* Match `BARE_OS_CTX_API_VERSION` in `bare-os-ctx-api.js` (stock **1.51.0**).
|
||||
* Match `BARE_OS_CTX_API_VERSION` in `bare-os-ctx-api.js` (stock **1.51.1**).
|
||||
*/
|
||||
|
||||
export interface BareOsAbortOpts {
|
||||
|
||||
@@ -66,6 +66,9 @@ function sleepMs(ms) {
|
||||
* seedReplicationStatus?: Record<string, unknown> | null
|
||||
* seedMirrorDriveHintV2?: Record<string, unknown> | null
|
||||
* seedHttpDhtProxyHint?: Record<string, unknown> | null
|
||||
* seedSnapshotHints?: Record<string, unknown> | null
|
||||
* seedSnapshotManifestSlice?: Record<string, unknown> | null
|
||||
* seedSnapshotChain?: Record<string, unknown> | null
|
||||
* swarmPeerCount?: number | null
|
||||
* swarmConnectionBudget?: Record<string, unknown> | null
|
||||
* protomuxOperatorSketch?: Record<string, unknown> | null
|
||||
@@ -195,17 +198,28 @@ export function createBareOsDiskOsBridge(opts) {
|
||||
const drive = opts.drive
|
||||
if (!drive) {
|
||||
return JSON.stringify({
|
||||
schema: 1,
|
||||
schema: 2,
|
||||
ok: false,
|
||||
reason: 'no_system_drive'
|
||||
})
|
||||
}
|
||||
const env = globalThis.process?.env
|
||||
const parseEnvJson = (key) => {
|
||||
const raw = String(env?.[key] ?? '').trim()
|
||||
if (!raw) return null
|
||||
try {
|
||||
const o = JSON.parse(raw)
|
||||
return o && typeof o === 'object' ? o : null
|
||||
} catch {
|
||||
return { schema: 1, error: 'invalid_json', key }
|
||||
}
|
||||
}
|
||||
try {
|
||||
const id = /** @type {{ id?: Uint8Array }} */ (drive).id
|
||||
const dk = /** @type {{ discoveryKey?: Uint8Array }} */ (drive)
|
||||
.discoveryKey
|
||||
return JSON.stringify({
|
||||
schema: 1,
|
||||
schema: 2,
|
||||
ok: true,
|
||||
writable: !!drive.writable,
|
||||
idPrefix:
|
||||
@@ -216,11 +230,30 @@ export function createBareOsDiskOsBridge(opts) {
|
||||
dk && dk.byteLength
|
||||
? b4a.toString(dk, 'hex').slice(0, 16)
|
||||
: null,
|
||||
note: 'Non-secret length-capped hex prefixes for operator correlation only.'
|
||||
seedSnapshotHints:
|
||||
opts.seedSnapshotHints &&
|
||||
typeof opts.seedSnapshotHints === 'object'
|
||||
? opts.seedSnapshotHints
|
||||
: null,
|
||||
seedSnapshotManifestSlice:
|
||||
opts.seedSnapshotManifestSlice &&
|
||||
typeof opts.seedSnapshotManifestSlice === 'object'
|
||||
? opts.seedSnapshotManifestSlice
|
||||
: null,
|
||||
seedSnapshotChain:
|
||||
opts.seedSnapshotChain &&
|
||||
typeof opts.seedSnapshotChain === 'object'
|
||||
? opts.seedSnapshotChain
|
||||
: null,
|
||||
corestoreSnapshotEnv: parseEnvJson(
|
||||
'BARE_OS_CORESTORE_SNAPSHOT_JSON'
|
||||
),
|
||||
note:
|
||||
'Schema 2: adds optional seed snapshot hints/manifest slice/chain (non-secret) plus BARE_OS_CORESTORE_SNAPSHOT_JSON merge for corestore-snapshot–style operator signals. Hex prefixes unchanged.'
|
||||
})
|
||||
} catch (e) {
|
||||
return JSON.stringify({
|
||||
schema: 1,
|
||||
schema: 2,
|
||||
ok: false,
|
||||
error: (e && /** @type {Error} */ (e).message) || String(e)
|
||||
})
|
||||
|
||||
@@ -27,6 +27,62 @@ function defaultNdjsonPath() {
|
||||
* @param {string} human Human-readable message (no secrets).
|
||||
* @param {string} [detail] Optional short detail (error.message, etc.).
|
||||
*/
|
||||
/**
|
||||
* Host-side informational line (boot trace off): stderr when mode is stderr; optional NDJSON append.
|
||||
* @param {string} code
|
||||
* @param {string} human
|
||||
* @param {string} [detail]
|
||||
*/
|
||||
export function bareOsHostBooterInfo(code, human, detail) {
|
||||
const env = globalThis.process?.env || {}
|
||||
const mode = String(env.BARE_OS_HOST_BOOTER_LOG || 'stderr')
|
||||
.trim()
|
||||
.toLowerCase()
|
||||
if (
|
||||
mode === '0' ||
|
||||
mode === 'false' ||
|
||||
mode === 'off' ||
|
||||
mode === 'no' ||
|
||||
mode === 'silent'
|
||||
) {
|
||||
return
|
||||
}
|
||||
|
||||
const d = detail != null ? String(detail).slice(0, 4000) : ''
|
||||
const line = `[bare-os-booter][${code}] ${human}${d ? `: ${d}` : ''}`
|
||||
|
||||
if (mode === 'ndjson') {
|
||||
const logPath = String(env.BARE_OS_HOST_BOOTER_LOG_PATH || '').trim() || defaultNdjsonPath()
|
||||
try {
|
||||
fs.mkdirSync(path.dirname(logPath), { recursive: true })
|
||||
fs.appendFileSync(
|
||||
logPath,
|
||||
`${JSON.stringify({
|
||||
type: 'booterHostInfo',
|
||||
code: String(code).slice(0, 128),
|
||||
message: String(human).slice(0, 2000),
|
||||
detail: d || undefined,
|
||||
ts: Date.now()
|
||||
})}\n`,
|
||||
'utf8'
|
||||
)
|
||||
} catch {
|
||||
/* fall through */
|
||||
}
|
||||
}
|
||||
|
||||
if (mode === 'ndjson' && env.BARE_OS_HOST_BOOTER_LOG_STDERR !== '1') {
|
||||
return
|
||||
}
|
||||
|
||||
const err = globalThis.process?.stderr
|
||||
if (err && typeof err.write === 'function') {
|
||||
err.write(`${line}\n`)
|
||||
} else if (typeof console.info === 'function') {
|
||||
console.info(line)
|
||||
}
|
||||
}
|
||||
|
||||
export function bareOsHostBooterWarn(code, human, detail) {
|
||||
const env = globalThis.process?.env || {}
|
||||
const mode = String(env.BARE_OS_HOST_BOOTER_LOG || 'stderr')
|
||||
|
||||
@@ -29,11 +29,11 @@ export function buildBareOsSyscallsProcJson(p) {
|
||||
opsDetail: [...BARE_OS_SYSCALL_OPS_DETAIL_FULL],
|
||||
posixXsh: {
|
||||
schema: 2,
|
||||
note: 'POSIX.1 XSH-style names: logical names in opsDetail; schema 10 adds posix_fadvise as a simulated ctx.bareOsSyscall no-op (Issue 7-style advice hint). Socket family are ctx.bareOsSyscall ops returning ENOSYS-shaped results (not kernel socket FDs) unless BARE_OS_POSIX_SOCKET_FD_BRIDGE. readv/writev are partial posix-pipe facades. getsockopt/setsockopt: ENOSYS without bridge fd; with bridge, partial SO_KEEPALIVE/TCP_NODELAY and optional SO_RCVBUF/SO_SNDBUF on logical fds when the Bare socket implementation exposes buffer sizes. nanosleep-shaped delay via ctx.bareOsSyscall("nanosleep"); clock_gettime via ctx.bareOsSyscall("clock_gettime") (REALTIME wall; MONOTONIC via bare-hrtime or performance.now sketch). SOCK_DGRAM bridge supports passive bind(2), optional connect(2) after bind, send/sendmsg/recv/recvfrom/recvmsg with bounded queue (BARE_OS_POSIX_DGRAM_RECVQ_MAX); bound-without-connect send requires port+host syscall args. sendmsg/recvmsg: non-empty ancillary control is ENOTSUP (socketMsgSurface schema 4) unless BARE_OS_POSIX_SOCKET_SCM_RIGHTS=1, then only SCM_RIGHTS-shaped `{ fds: number[] }` logical fd dup is accepted (see bare-os-socket-scm-rights.js and syscall-socket-contract.md).',
|
||||
note: 'POSIX.1 XSH-style names: logical names in opsDetail; schema 10 adds posix_fadvise as a simulated ctx.bareOsSyscall no-op (Issue 7-style advice hint). Socket family are ctx.bareOsSyscall ops returning ENOSYS-shaped results (not kernel socket FDs) unless BARE_OS_POSIX_SOCKET_FD_BRIDGE. readv/writev are partial posix-pipe facades. getsockopt/setsockopt: ENOSYS without bridge fd; with bridge, partial SO_KEEPALIVE/TCP_NODELAY and optional SO_RCVBUF/SO_SNDBUF on logical fds when the Bare socket implementation exposes buffer sizes. nanosleep-shaped delay via ctx.bareOsSyscall("nanosleep"); clock_gettime via ctx.bareOsSyscall("clock_gettime") (REALTIME wall; MONOTONIC via bare-hrtime or performance.now sketch). SOCK_DGRAM bridge supports passive bind(2), optional connect(2) after bind, send/sendmsg/recv/recvfrom/recvmsg with bounded queue (BARE_OS_POSIX_DGRAM_RECVQ_MAX); bound-without-connect send requires port+host syscall args. sendmsg/recvmsg: non-empty ancillary control is ENOTSUP (socketMsgSurface schema 5) unless BARE_OS_POSIX_SOCKET_SCM_RIGHTS=1, then only SCM_RIGHTS-shaped `{ fds: number[] }` logical fd dup is accepted on SOCK_STREAM and SOCK_DGRAM bridge fds (same prepareBridgeSendmsg path; see bare-os-socket-scm-rights.js and syscall-socket-contract.md).',
|
||||
namesCsv: bareOsPosixXshOpsCsv()
|
||||
},
|
||||
socketMsgSurface: {
|
||||
schema: 4,
|
||||
schema: 5,
|
||||
ancillaryControl: {
|
||||
supported: false,
|
||||
errno: 'ENOTSUP',
|
||||
@@ -45,7 +45,7 @@ export function buildBareOsSyscallsProcJson(p) {
|
||||
'msgHdr.cmsgs'
|
||||
],
|
||||
note:
|
||||
'Binary/kernel ancillary buffers remain ENOTSUP. When BARE_OS_POSIX_SOCKET_SCM_RIGHTS=1, only JSON-shaped `{ fds: number[] }` entries in cmsgs/msgHdr.cmsgs are accepted (see logicalScmRightsOnSend).'
|
||||
'Binary/kernel ancillary buffers remain ENOTSUP. When BARE_OS_POSIX_SOCKET_SCM_RIGHTS=1, only JSON-shaped `{ fds: number[] }` entries in cmsgs/msgHdr.cmsgs are accepted (see logicalScmRightsOnSend). Schema 5 documents SOCK_STREAM sendmsg parity with SOCK_DGRAM (logical dup on connected TCP bridge fds).'
|
||||
},
|
||||
logicalScmRightsOnSend: {
|
||||
env: 'BARE_OS_POSIX_SOCKET_SCM_RIGHTS',
|
||||
@@ -82,7 +82,11 @@ export function buildBareOsSyscallsProcJson(p) {
|
||||
fds: 'stdio 0–2 reserved; extras via ctx.bareOsRegisterLogicalFd'
|
||||
},
|
||||
read: {
|
||||
mapsTo: ['vfs.readFile', 'bareOsBinReadStdin', 'IPC fifo consumer'],
|
||||
mapsTo: [
|
||||
'vfs.readFile',
|
||||
'bareOsBinReadStdin',
|
||||
'IPC fifo consumer (/run/bare-os/ipc/*): blocking until push or AbortSignal (AbortError); backlog bounded via BARE_OS_IPC_MAX_BYTES'
|
||||
],
|
||||
partial: true
|
||||
},
|
||||
write: {
|
||||
|
||||
@@ -81,6 +81,7 @@ function writeCStrToMemory(memory, ptr, outCap, text) {
|
||||
* **`BARE_OS_WASM_KERNEL_SYSCALL=1`** (or **`opts.wasmSyscallImports: true`**) and **`ctx.bareOsPathconf`** exists.
|
||||
* Also **`env.bare_os_wall_time_ms32`**: low 32 bits of wall time (`Date.now()`, signed i32 wrap) for bounded guest timing.
|
||||
* With **`BARE_OS_WASM_KERNEL_MONOTONIC_MS=1`**, adds **`env.bare_os_monotonic_ms`**: floored monotonic milliseconds (`performance.now` when available), i32-shaped.
|
||||
* With **`BARE_OS_WASM_KERNEL_HOSTNAME_IMPORT=1`** (requires syscall imports), adds **`env.bare_os_hostname_peek`**: writes session **`HOSTNAME`** (or **`bare-os`**) NUL-terminated into Wasm memory (**bounded**).
|
||||
*
|
||||
* @param {Uint8Array} source
|
||||
* @param {Record<string, unknown>} ctx
|
||||
@@ -140,6 +141,10 @@ export async function bareOsWasmKernelInstantiate(source, ctx, opts = {}) {
|
||||
wantSyscall &&
|
||||
(shellEnv.BARE_OS_WASM_KERNEL_MONOTONIC_MS === '1' ||
|
||||
shellEnv.BARE_OS_WASM_KERNEL_MONOTONIC_MS === 'true')
|
||||
const wantHostname =
|
||||
wantSyscall &&
|
||||
(shellEnv.BARE_OS_WASM_KERNEL_HOSTNAME_IMPORT === '1' ||
|
||||
shellEnv.BARE_OS_WASM_KERNEL_HOSTNAME_IMPORT === 'true')
|
||||
const pathconfFn = ctx && typeof ctx.bareOsPathconf === 'function'
|
||||
? ctx.bareOsPathconf.bind(ctx)
|
||||
: null
|
||||
@@ -192,6 +197,21 @@ export async function bareOsWasmKernelInstantiate(source, ctx, opts = {}) {
|
||||
const m = parseInt(String(shellEnv.UMASK || '022'), 8)
|
||||
return Number.isFinite(m) ? m & 0o777 : 0o22
|
||||
}
|
||||
if (wantHostname) {
|
||||
envImports.bare_os_hostname_peek = (outPtr, outCap) => {
|
||||
const vfsEnv =
|
||||
ctx &&
|
||||
ctx.vfs &&
|
||||
ctx.vfs.env &&
|
||||
typeof ctx.vfs.env === 'object'
|
||||
? /** @type {Record<string, string>} */ (ctx.vfs.env)
|
||||
: {}
|
||||
const h = String(
|
||||
vfsEnv.HOSTNAME || shellEnv.HOSTNAME || 'bare-os'
|
||||
).slice(0, 256)
|
||||
return writeCStrToMemory(memory, Number(outPtr), Number(outCap), h)
|
||||
}
|
||||
}
|
||||
}
|
||||
const importObject = {
|
||||
env: envImports
|
||||
@@ -218,7 +238,8 @@ export async function bareOsWasmKernelInstantiate(source, ctx, opts = {}) {
|
||||
wasmSyscallImports: !!wantSyscall,
|
||||
wasmPathconfImport: !!(wantSyscall && pathconfFn),
|
||||
wasmWallClockMs32Import: !!wantSyscall,
|
||||
wasmMonotonicMsImport: !!wantMonotonicMs
|
||||
wasmMonotonicMsImport: !!wantMonotonicMs,
|
||||
wasmHostnamePeekImport: !!(wantSyscall && wantHostname)
|
||||
}
|
||||
} catch (e) {
|
||||
return { ok: false, reason: String(e && e.message ? e.message : e) }
|
||||
|
||||
@@ -67,8 +67,8 @@ function gitAuthor(ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
function printHelp(console) {
|
||||
console.log(`bare-os git (isomorphic-git) — not full GNU git.
|
||||
function printHelp(sink) {
|
||||
sink.log(`bare-os git (isomorphic-git) — not full GNU git.
|
||||
|
||||
Usage: git [--git-dir <path>] [-C <path>] <command> [args]
|
||||
|
||||
|
||||
@@ -12,6 +12,35 @@ import {
|
||||
} from './bare-os-theme-presets.js'
|
||||
import { pathnameExpandShellWord, bareOsFnmatch } from './shell-glob.js'
|
||||
|
||||
/** @see execShellLine — nounset violations surface as exit status 1 */
|
||||
export const BARE_OS_SHELL_NOUNSET_ERROR = 'BARE_OS_SHELL_NOUNSET'
|
||||
|
||||
/**
|
||||
* @param {Record<string, string> | null | undefined} env
|
||||
*/
|
||||
function shellNounsetEnvOn(env) {
|
||||
return (
|
||||
env &&
|
||||
(env.BARE_OS_SHELL_NOUNSET === '1' || env.BARE_OS_SHELL_NOUNSET === 'true')
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {Record<string, string>} env
|
||||
*/
|
||||
function shellCheckUnboundParam(name, env) {
|
||||
if (!shellNounsetEnvOn(env) || !name) return
|
||||
const n = name.trim()
|
||||
if (n === '?' || /^\d+$/.test(n)) return
|
||||
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(n)) return
|
||||
if (!Object.prototype.hasOwnProperty.call(env, n)) {
|
||||
const e = new Error(`unbound variable: ${n}`)
|
||||
e.code = BARE_OS_SHELL_NOUNSET_ERROR
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
const SHELL_BUILTINS = new Set([
|
||||
'alias',
|
||||
'unalias',
|
||||
@@ -821,7 +850,9 @@ function expandParamBracedInner(inner, env) {
|
||||
return v.startsWith(pref) ? v.slice(pref.length) : v
|
||||
}
|
||||
}
|
||||
return env[inner] ?? ''
|
||||
const keySimple = inner.trim()
|
||||
shellCheckUnboundParam(keySimple, env)
|
||||
return env[keySimple] ?? ''
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -868,7 +899,9 @@ export function expandWord(s, env) {
|
||||
) {
|
||||
out += expandParamBracedInner(inner, env)
|
||||
} else {
|
||||
out += env[inner] ?? ''
|
||||
const ik = inner.trim()
|
||||
shellCheckUnboundParam(ik, env)
|
||||
out += env[ik] ?? ''
|
||||
}
|
||||
j = end + 1
|
||||
continue
|
||||
@@ -879,7 +912,9 @@ export function expandWord(s, env) {
|
||||
continue
|
||||
}
|
||||
if (/[0-9]/.test(s[j + 1] ?? '')) {
|
||||
out += env[s[j + 1]] ?? ''
|
||||
const pn = s[j + 1]
|
||||
shellCheckUnboundParam(pn, env)
|
||||
out += env[pn] ?? ''
|
||||
j += 2
|
||||
continue
|
||||
}
|
||||
@@ -887,6 +922,7 @@ export function expandWord(s, env) {
|
||||
while (k < s.length && /[A-Za-z0-9_]/.test(s[k])) k++
|
||||
const name = s.slice(j + 1, k)
|
||||
if (name) {
|
||||
shellCheckUnboundParam(name, env)
|
||||
out += env[name] ?? ''
|
||||
j = k
|
||||
} else {
|
||||
@@ -1595,6 +1631,22 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
env.BARE_OS_SHELL_ERREXIT = '1'
|
||||
} else if (args.length === 1 && args[0] === '+e') {
|
||||
delete env.BARE_OS_SHELL_ERREXIT
|
||||
} else if (
|
||||
args.length === 2 &&
|
||||
args[0] === '-o' &&
|
||||
args[1] === 'nounset'
|
||||
) {
|
||||
env.BARE_OS_SHELL_NOUNSET = '1'
|
||||
} else if (
|
||||
args.length === 2 &&
|
||||
args[0] === '+o' &&
|
||||
args[1] === 'nounset'
|
||||
) {
|
||||
delete env.BARE_OS_SHELL_NOUNSET
|
||||
} else if (args.length === 1 && args[0] === '-u') {
|
||||
env.BARE_OS_SHELL_NOUNSET = '1'
|
||||
} else if (args.length === 1 && args[0] === '+u') {
|
||||
delete env.BARE_OS_SHELL_NOUNSET
|
||||
} else if (
|
||||
args.length === 2 &&
|
||||
args[0] === '-o' &&
|
||||
@@ -1610,7 +1662,7 @@ async function execParsedPipeline(ctx, pipeline) {
|
||||
} else {
|
||||
origErr.call(
|
||||
ctx.console,
|
||||
'set: unsupported arguments (only -f / +f / -e / +e / -o errexit / +o errexit / -o pipefail / +o pipefail)'
|
||||
'set: unsupported arguments (only -f / +f / -e / +e / -u / +u / -o errexit|nounset|pipefail / +o errexit|nounset|pipefail)'
|
||||
)
|
||||
ctx.exitCode = 1
|
||||
}
|
||||
@@ -2774,6 +2826,15 @@ export async function execShellLine(ctx, line) {
|
||||
}
|
||||
try {
|
||||
return await execShellLineInner(ctx, raw)
|
||||
} catch (e) {
|
||||
const code = e && /** @type {{ code?: string }} */ (e).code
|
||||
if (code === BARE_OS_SHELL_NOUNSET_ERROR) {
|
||||
ctx.console.error('shell: ' + ((e && e.message) || 'unbound variable'))
|
||||
ctx.exitCode = 1
|
||||
syncBareOsExitStatusEnv(ctx)
|
||||
return 'ok'
|
||||
}
|
||||
throw e
|
||||
} finally {
|
||||
if (savedEnv != null && vfs) vfs.env = savedEnv
|
||||
}
|
||||
|
||||
@@ -4,7 +4,10 @@ import {
|
||||
PROTOCOL_NAME,
|
||||
PROTOCOL_APP_CHANNEL_NAME
|
||||
} from 'bare-os-protocol/constants.js'
|
||||
import { bareOsHostBooterWarn } from './bare-os-host-booter-log.js'
|
||||
import {
|
||||
bareOsHostBooterInfo,
|
||||
bareOsHostBooterWarn
|
||||
} from './bare-os-host-booter-log.js'
|
||||
|
||||
/**
|
||||
* Host-side booter log for swarm disk (stderr JSON when BARE_OS_BOOT_TRACE=json|ndjson; else stderr or console.warn).
|
||||
@@ -39,13 +42,34 @@ function emitSwarmDiskHostLog(level, message, detail = null) {
|
||||
)
|
||||
return
|
||||
}
|
||||
const line = `[bare-os-booter][swarm-disk] ${message}`
|
||||
if (err && typeof err.write === 'function') err.write(`${line}\n`)
|
||||
else if (typeof console.info === 'function') console.info(line)
|
||||
bareOsHostBooterInfo('swarm_disk', message, detail ? JSON.stringify(detail) : '')
|
||||
}
|
||||
|
||||
/** Max wait for block 0 (MBR) bytes from swarm peers before failing boot. */
|
||||
const MBR_READ_TIMEOUT_MS = 60_000
|
||||
/** Default max wait for block 0 (MBR) before failing boot (override **`BARE_OS_MBR_READ_TIMEOUT_MS`**). */
|
||||
const MBR_READ_TIMEOUT_MS_DEFAULT = 60_000
|
||||
|
||||
/**
|
||||
* Max wait (ms) for block 0 / MBR replication before boot failure.
|
||||
* Exported for microbench / unit introspection (same rules as booter).
|
||||
* @param {SwarmDisk} disk
|
||||
*/
|
||||
export function mbrReadTimeoutMsForDisk(disk) {
|
||||
const env = globalThis.process?.env
|
||||
const raw = String(env?.BARE_OS_MBR_READ_TIMEOUT_MS ?? '').trim()
|
||||
if (raw) {
|
||||
const n = Math.floor(Number(raw))
|
||||
if (Number.isFinite(n) && n >= 3000) return Math.min(n, 600_000)
|
||||
}
|
||||
const adapt =
|
||||
env?.BARE_OS_MBR_READ_TIMEOUT_ADAPTIVE === '1' ||
|
||||
env?.BARE_OS_MBR_READ_TIMEOUT_ADAPTIVE === 'true'
|
||||
if (adapt && disk && disk.peers && typeof disk.peers.size === 'number') {
|
||||
const n = disk.peers.size
|
||||
if (n <= 1) return Math.min(120_000, MBR_READ_TIMEOUT_MS_DEFAULT + 30_000)
|
||||
if (n >= 4) return Math.max(45_000, MBR_READ_TIMEOUT_MS_DEFAULT - 15_000)
|
||||
}
|
||||
return MBR_READ_TIMEOUT_MS_DEFAULT
|
||||
}
|
||||
|
||||
export class SwarmDisk {
|
||||
constructor() {
|
||||
@@ -456,7 +480,7 @@ export class SwarmDisk {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeout = setTimeout(
|
||||
() => reject(new Error('MBR read timeout')),
|
||||
MBR_READ_TIMEOUT_MS
|
||||
mbrReadTimeoutMsForDisk(this)
|
||||
)
|
||||
this.pendingReads.set(index, (data) => {
|
||||
clearTimeout(timeout)
|
||||
|
||||
@@ -1383,7 +1383,7 @@ test('buildBareOsSyscallsProcJson exposes posixLike fd mapping', async (t) => {
|
||||
t.ok(j.posixXsh.namesCsv.includes('sendmsg'))
|
||||
t.ok(j.posixXsh.namesCsv.includes('recvmsg'))
|
||||
t.ok(j.posixXsh.namesCsv.includes('shutdown'))
|
||||
t.is(j.socketMsgSurface?.schema, 4)
|
||||
t.is(j.socketMsgSurface?.schema, 5)
|
||||
t.is(j.socketMsgSurface?.logicalScmRightsOnSend?.syscallResultField, 'scmRightsLocalDup')
|
||||
t.is(j.socketMsgSurface?.ancillaryControl?.supported, false)
|
||||
t.is(j.socketMsgSurface?.ancillaryControl?.errno, 'ENOTSUP')
|
||||
@@ -1563,7 +1563,7 @@ test('disk.os replication_snapshot and replication_operator_sketch RPCs', async
|
||||
})
|
||||
const snap = await bridge.execRpc('bare_os', 'replication_snapshot', [])
|
||||
const sj = JSON.parse(snap)
|
||||
t.is(sj.schema, 1)
|
||||
t.is(sj.schema, 2)
|
||||
t.is(sj.ok, true)
|
||||
t.ok(typeof sj.writable === 'boolean')
|
||||
const op = await bridge.execRpc('bare_os', 'replication_operator_sketch', [])
|
||||
@@ -2874,6 +2874,24 @@ test('execShellLine BARE_OS_SHELL_ERREXIT skips after failed command', async (t)
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('execShellLine BARE_OS_SHELL_NOUNSET rejects unbound variable', async (t) => {
|
||||
const dir = testCorestoreDir('nounset')
|
||||
const store = new Corestore(dir)
|
||||
const drive = new Hyperdrive(store)
|
||||
const personal = new Hyperdrive(store.namespace('pex-nu'))
|
||||
await drive.ready()
|
||||
await personal.ready()
|
||||
const ctx = testCtx(drive, personal)
|
||||
const errs = []
|
||||
ctx.console.error = (m) => errs.push(String(m))
|
||||
ctx.vfs.env.BARE_OS_SHELL_NOUNSET = '1'
|
||||
await execShellLine(ctx, 'echo $UNBOUND_XYZ')
|
||||
t.is(ctx.exitCode, 1)
|
||||
t.ok(errs.some((e) => /unbound variable/.test(e)))
|
||||
await store.close()
|
||||
rmSync(dir, { recursive: true, force: true })
|
||||
})
|
||||
|
||||
test('execShellLine BARE_OS_SHELL_PIPEFAIL uses first failing stage exit', async (t) => {
|
||||
const dir = testCorestoreDir('pipefail')
|
||||
const store = new Corestore(dir)
|
||||
@@ -6820,6 +6838,33 @@ test('bareOsWasmKernelInstantiate optional bare_os_monotonic_ms import', async (
|
||||
t.ok(r.wasmMonotonicMsImport)
|
||||
})
|
||||
|
||||
test('bareOsWasmKernelInstantiate optional bare_os_hostname_peek import flag', async (t) => {
|
||||
const { bareOsWasmKernelInstantiate } = await import('./lib/bare-os-wasm-kernel.js')
|
||||
if (typeof WebAssembly === 'undefined' || !WebAssembly.compile) {
|
||||
t.pass('skip: no WebAssembly')
|
||||
return
|
||||
}
|
||||
const wasmMinimal = new Uint8Array([
|
||||
0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00
|
||||
])
|
||||
const ctx = {
|
||||
bareOsPathconf: () => '4096',
|
||||
vfs: { env: { HOSTNAME: 'guest.test' } }
|
||||
}
|
||||
const r = await bareOsWasmKernelInstantiate(wasmMinimal, ctx, {
|
||||
wasmSyscallImports: true,
|
||||
shellEnv: {
|
||||
BARE_OS_WASM_KERNEL_SYSCALL: '1',
|
||||
BARE_OS_WASM_KERNEL_HOSTNAME_IMPORT: '1'
|
||||
}
|
||||
})
|
||||
if (!r.ok) {
|
||||
t.pass('instantiate may fail on minimal module')
|
||||
return
|
||||
}
|
||||
t.ok(r.wasmHostnamePeekImport)
|
||||
})
|
||||
|
||||
test('bareOsAppendVaultRotationCheckpoint appends vault_save row', async (t) => {
|
||||
const { bareOsAppendVaultRotationCheckpoint } = await import(
|
||||
'./lib/bare-os-vault-rotation-audit.js'
|
||||
|
||||
@@ -81,6 +81,7 @@ export const COREUTILS_COMMANDS = [
|
||||
'mount',
|
||||
'mv',
|
||||
'nano',
|
||||
'nice',
|
||||
'nl',
|
||||
'nohup',
|
||||
'nproc',
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "nice",
|
||||
"section": 1,
|
||||
"title": "invoke a utility with an altered scheduling priority (simulated)",
|
||||
"synopsis": [
|
||||
"nice [-n increment] utility [argument...]"
|
||||
],
|
||||
"description": "Bare OS implementation: records BARE_OS_SIMULATED_NICE on the session env and runs the utility via ctx.runBinCommand. The host JavaScript runtime does not change OS niceness; scripts use this for POSIX script compatibility.",
|
||||
"options": [],
|
||||
"keywords": [
|
||||
"nice",
|
||||
"bare-os",
|
||||
"coreutils"
|
||||
],
|
||||
"examples": [
|
||||
{
|
||||
"caption": "run with default increment",
|
||||
"code": "nice make"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
async function run(ctx, argv) {
|
||||
let inc = 10
|
||||
let i = 1
|
||||
if (argv[i] === '-n') {
|
||||
const n = Number.parseInt(String(argv[i + 1] ?? ''), 10)
|
||||
if (!Number.isFinite(n) || n < 0 || n > 39) {
|
||||
ctx.console.error('nice: invalid adjustment')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
inc = n
|
||||
i += 2
|
||||
} else if (argv[i] && /^-\d+$/.test(argv[i])) {
|
||||
const n = Number.parseInt(argv[i].slice(1), 10)
|
||||
if (!Number.isFinite(n) || n < 0 || n > 39) {
|
||||
ctx.console.error('nice: invalid adjustment')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
inc = n
|
||||
i++
|
||||
}
|
||||
const cmd = argv.slice(i)
|
||||
if (!cmd.length) {
|
||||
ctx.console.error('usage: nice [-n increment] utility [argument...]')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
if (typeof ctx.runBinCommand !== 'function') {
|
||||
ctx.console.error('nice: runBinCommand is not available')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
const env = ctx.vfs?.env
|
||||
if (env && typeof env === 'object') {
|
||||
env.BARE_OS_SIMULATED_NICE = String(inc)
|
||||
}
|
||||
await ctx.runBinCommand(cmd)
|
||||
}
|
||||
@@ -87,7 +87,7 @@ function bareOsEmitRaw(ctx, chunk) {
|
||||
return false
|
||||
}
|
||||
|
||||
var BARE_OS_HELP_BIN_SPACED = "arch awk baretop base32 base64 basename basenc btop bundlebee cat chgrp chmod chown cksum clear cmp comm cp crontab curl cut date dd df diff dir dircolors dirname du echo edit env exit expand expr factor false find fmt fold getconf getfacl git git-pear grep groups hdms head help hostid hostname hrpc iconv id install join journalctl jq kernel-boot-diff kernel-doctor kernel-explain kernel-fsck kernel-home-snapshot kernel-manifest-validate kernel-preflight kernel-triage kill link ln logger login logname logout ls man md5sum mkdir mkfifo mktemp mount mv nano nl nohup nproc numfmt od oidc-publish openssl openssl paste patch pathchk pear-runtime-matrix pr printenv printf procstat ps pwd readlink realpath rev rm rmdir savevault sed seq setfacl sh sha1sum sha256sum sha512sum shuf sidecar sleep sort split ssh-keygen ssh-keygen stat sum sync systemctl tac tail tar tar tee test theme time timeout touch tr true truncate tsort tty ulimit umount uname unexpand uniq unlink uptime users vdir wc wget which who whoami xargs xattr yes"
|
||||
var BARE_OS_HELP_BIN_SPACED = "arch awk baretop base32 base64 basename basenc btop bundlebee cat chgrp chmod chown cksum clear cmp comm cp crontab curl cut date dd df diff dir dircolors dirname du echo edit env exit expand expr factor false find fmt fold getconf getfacl git git-pear grep groups hdms head help hostid hostname hrpc iconv id install join journalctl jq kernel-boot-diff kernel-doctor kernel-explain kernel-fsck kernel-home-snapshot kernel-manifest-validate kernel-preflight kernel-triage kill link ln logger login logname logout ls man md5sum mkdir mkfifo mktemp mount mv nano nice nl nohup nproc numfmt od oidc-publish openssl openssl paste patch pathchk pear-runtime-matrix pr printenv printf procstat ps pwd readlink realpath rev rm rmdir savevault sed seq setfacl sh sha1sum sha256sum sha512sum shuf sidecar sleep sort split ssh-keygen ssh-keygen stat sum sync systemctl tac tail tar tar tee test theme time timeout touch tr true truncate tsort tty ulimit umount uname unexpand uniq unlink uptime users vdir wc wget which who whoami xargs xattr yes"
|
||||
async function run(ctx, argv) {
|
||||
ctx.console.log(
|
||||
'Bare OS — default user: guest | shell builtins: alias, barerc, cd, command, export, exit, login, logout, readonly, type, umask, unalias, unset, : | /bin: ' +
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
/* 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
|
||||
}
|
||||
|
||||
async function run(ctx, argv) {
|
||||
let inc = 10
|
||||
let i = 1
|
||||
if (argv[i] === '-n') {
|
||||
const n = Number.parseInt(String(argv[i + 1] ?? ''), 10)
|
||||
if (!Number.isFinite(n) || n < 0 || n > 39) {
|
||||
ctx.console.error('nice: invalid adjustment')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
inc = n
|
||||
i += 2
|
||||
} else if (argv[i] && /^-\d+$/.test(argv[i])) {
|
||||
const n = Number.parseInt(argv[i].slice(1), 10)
|
||||
if (!Number.isFinite(n) || n < 0 || n > 39) {
|
||||
ctx.console.error('nice: invalid adjustment')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
inc = n
|
||||
i++
|
||||
}
|
||||
const cmd = argv.slice(i)
|
||||
if (!cmd.length) {
|
||||
ctx.console.error('usage: nice [-n increment] utility [argument...]')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
if (typeof ctx.runBinCommand !== 'function') {
|
||||
ctx.console.error('nice: runBinCommand is not available')
|
||||
ctx.exitCode = 125
|
||||
return
|
||||
}
|
||||
const env = ctx.vfs?.env
|
||||
if (env && typeof env === 'object') {
|
||||
env.BARE_OS_SIMULATED_NICE = String(inc)
|
||||
}
|
||||
await ctx.runBinCommand(cmd)
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"schema": 2,
|
||||
"profileId": "bare-os-posix-like",
|
||||
"generatedAt": "2026-04-05T18:43:53.989Z",
|
||||
"generatedAt": "2026-04-05T19:03:41.000Z",
|
||||
"note": "Sparse POSIX Issue 7 coverage hints for /bin utilities. Omitted command names are not yet profiled here.",
|
||||
"commandIndex": [
|
||||
{
|
||||
@@ -316,6 +316,10 @@
|
||||
"name": "nano",
|
||||
"tier": "tier1_bin"
|
||||
},
|
||||
{
|
||||
"name": "nice",
|
||||
"tier": "tier1_bin"
|
||||
},
|
||||
{
|
||||
"name": "nl",
|
||||
"tier": "tier1_bin"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schemaVersion": 10,
|
||||
"ctxApiVersion": "1.51.0",
|
||||
"ctxApiVersion": "1.51.1",
|
||||
"posixProfile": {
|
||||
"id": "bare-os-posix-like",
|
||||
"version": "1.0.15"
|
||||
|
||||
@@ -1821,6 +1821,38 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
/** @param {string} ver */
|
||||
function bareOsKernelExtSemverValid(ver) {
|
||||
const s = String(ver || '').trim()
|
||||
return /^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/.test(
|
||||
s
|
||||
)
|
||||
}
|
||||
/** @type {string[]} */
|
||||
const providesInvalidSemver = []
|
||||
for (const e of collected) {
|
||||
for (const pr of e.provides || []) {
|
||||
if (!bareOsKernelExtSemverValid(pr.version)) {
|
||||
providesInvalidSemver.push(`${e.extId}:${pr.name}@${pr.version}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
providesInvalidSemver.sort()
|
||||
if (providesInvalidSemver.length) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'warn',
|
||||
'kernelExt.providesInvalidSemver',
|
||||
`[kernel.ext.d] provides[].version must look like semver (major.minor.patch): ${providesInvalidSemver.join('; ')}`
|
||||
)
|
||||
if (strictPol) {
|
||||
await appendKernelExtAuditNdjson(ctx, {
|
||||
event: 'provides_invalid_semver',
|
||||
items: providesInvalidSemver
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
/** @type {Map<string, { extId: string, version: string }>} */
|
||||
const provideNameToOwner = new Map()
|
||||
/** @type {string[]} */
|
||||
@@ -1927,20 +1959,27 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
strictPol &&
|
||||
(ctx.env?.BARE_OS_BOOT_EXT_RESOLUTION_TRACE === '1' ||
|
||||
ctx.env?.BARE_OS_BOOT_EXT_RESOLUTION_TRACE === 'true')
|
||||
const resolutionAlways =
|
||||
ctx.env?.BARE_OS_KERNEL_EXT_RESOLUTION_JSON_ALWAYS === '1' ||
|
||||
ctx.env?.BARE_OS_KERNEL_EXT_RESOLUTION_JSON_ALWAYS === 'true'
|
||||
const extResolutionFailure = strictPol && !topo.ok
|
||||
if (
|
||||
ctx.vfs &&
|
||||
typeof ctx.vfs.writeFile === 'function' &&
|
||||
ctx.b4a &&
|
||||
(extResolutionFailure || traceOn)
|
||||
(extResolutionFailure || traceOn || resolutionAlways)
|
||||
) {
|
||||
try {
|
||||
const cycleSorted = topo.ok
|
||||
? []
|
||||
: [...topo.cycleExtIds].sort((a, b) => a.localeCompare(b))
|
||||
const provideSnapshot = {}
|
||||
for (const [k, v] of provideNameToOwner) {
|
||||
provideSnapshot[k] = v
|
||||
}
|
||||
const body =
|
||||
JSON.stringify({
|
||||
schema: 2,
|
||||
schema: 3,
|
||||
atMs: Date.now(),
|
||||
sessionId: String((ctx.env && ctx.env.BARE_OS_SESSION_ID) || ''),
|
||||
bootPolicyStrict: !!strictPol,
|
||||
@@ -1954,9 +1993,16 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
ordered: ordered.map((e) => ({
|
||||
extId: e.extId,
|
||||
file: e.file,
|
||||
dependsOn: e.dependsOn
|
||||
dependsOn: e.dependsOn,
|
||||
provides: e.provides || []
|
||||
})),
|
||||
cycleExtIds: topo.ok ? [] : cycleSorted
|
||||
cycleExtIds: topo.ok ? [] : cycleSorted,
|
||||
providesInvalidSemver,
|
||||
providesVersionConflicts:
|
||||
providesVersionConflicts.length > 0
|
||||
? providesVersionConflicts
|
||||
: undefined,
|
||||
provideNameToOwner: provideSnapshot
|
||||
}) + '\n'
|
||||
await ctx.vfs.writeFile(
|
||||
'/run/bare-os/kernel-ext-resolution.json',
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
{
|
||||
"version": 1,
|
||||
"bundles": [
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/safetyCatch.js",
|
||||
"keys": [
|
||||
"safetyCatch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/b4a.js",
|
||||
"keys": [
|
||||
"b4a"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/hypercoreIdEncoding.js",
|
||||
"keys": [
|
||||
@@ -25,36 +25,36 @@
|
||||
"compactEncoding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUrl.js",
|
||||
"keys": [
|
||||
"bareUrl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/protomux.js",
|
||||
"keys": [
|
||||
"protomux"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareEvents.js",
|
||||
"keys": [
|
||||
"bareEvents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareEncoding.js",
|
||||
"keys": [
|
||||
"bareEncoding"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUrl.js",
|
||||
"keys": [
|
||||
"bareUrl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePath.js",
|
||||
"keys": [
|
||||
"barePath"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareEvents.js",
|
||||
"keys": [
|
||||
"bareEvents"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAbort.js",
|
||||
"keys": [
|
||||
@@ -68,15 +68,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
|
||||
"path": "/lib/bare/bundles/bareCrypto.js",
|
||||
"keys": [
|
||||
"bareAnsiEscapes"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAddonResolve.js",
|
||||
"keys": [
|
||||
"bareAddonResolve"
|
||||
"bareCrypto"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -86,33 +80,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareCrypto.js",
|
||||
"path": "/lib/bare/bundles/bareAddonResolve.js",
|
||||
"keys": [
|
||||
"bareCrypto"
|
||||
"bareAddonResolve"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAppKit.js",
|
||||
"path": "/lib/bare/bundles/bareAnsiEscapes.js",
|
||||
"keys": [
|
||||
"bareAppKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
"bareAsyncHooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAssert.js",
|
||||
"keys": [
|
||||
"bareAssert"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAtomics.js",
|
||||
"keys": [
|
||||
"bareAtomics"
|
||||
"bareAnsiEscapes"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -121,18 +97,48 @@
|
||||
"fetch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAppKit.js",
|
||||
"keys": [
|
||||
"bareAppKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareApk.js",
|
||||
"keys": [
|
||||
"bareApk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAsyncHooks.js",
|
||||
"keys": [
|
||||
"bareAsyncHooks"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAtomics.js",
|
||||
"keys": [
|
||||
"bareAtomics"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareAssert.js",
|
||||
"keys": [
|
||||
"bareAssert"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBmp.js",
|
||||
"keys": [
|
||||
"bareBmp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBuffer.js",
|
||||
"keys": [
|
||||
"bareBuffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleCompile.js",
|
||||
"keys": [
|
||||
@@ -145,12 +151,6 @@
|
||||
"bareBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBuffer.js",
|
||||
"keys": [
|
||||
"bareBuffer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBluetoothApple.js",
|
||||
"keys": [
|
||||
@@ -169,12 +169,6 @@
|
||||
"bareBoot"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleId.js",
|
||||
"keys": [
|
||||
"bareBundleId"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareConsole.js",
|
||||
"keys": [
|
||||
@@ -187,6 +181,12 @@
|
||||
"bareDebugLog"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareBundleId.js",
|
||||
"keys": [
|
||||
"bareBundleId"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareChannel.js",
|
||||
"keys": [
|
||||
@@ -205,36 +205,36 @@
|
||||
"bareDelta"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDns.js",
|
||||
"keys": [
|
||||
"bareDns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDiagnosticsChannel.js",
|
||||
"keys": [
|
||||
"bareDiagnosticsChannel"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDns.js",
|
||||
"keys": [
|
||||
"bareDns"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareEnv.js",
|
||||
"keys": [
|
||||
"bareEnv"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"keys": [
|
||||
"bareExif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDgram.js",
|
||||
"keys": [
|
||||
"bareDgram"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareExif.js",
|
||||
"keys": [
|
||||
"bareExif"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareCov.js",
|
||||
"keys": [
|
||||
@@ -272,15 +272,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareFileLogger.js",
|
||||
"path": "/lib/bare/bundles/bareGtk.js",
|
||||
"keys": [
|
||||
"bareFileLogger"
|
||||
"bareGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"path": "/lib/bare/bundles/bareFileLogger.js",
|
||||
"keys": [
|
||||
"bareHeif"
|
||||
"bareFileLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -290,9 +290,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareGtk.js",
|
||||
"path": "/lib/bare/bundles/bareHeif.js",
|
||||
"keys": [
|
||||
"bareGtk"
|
||||
"bareHeif"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -313,12 +313,6 @@
|
||||
"bareIco"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareImageResample.js",
|
||||
"keys": [
|
||||
"bareImageResample"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareHttp1.js",
|
||||
"keys": [
|
||||
@@ -326,9 +320,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareInspect.js",
|
||||
"path": "/lib/bare/bundles/bareImageResample.js",
|
||||
"keys": [
|
||||
"bareInspect"
|
||||
"bareImageResample"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -338,9 +332,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareIpc.js",
|
||||
"path": "/lib/bare/bundles/bareInspect.js",
|
||||
"keys": [
|
||||
"bareIpc"
|
||||
"bareInspect"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"keys": [
|
||||
"bareJpeg"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -350,9 +350,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareJpeg.js",
|
||||
"path": "/lib/bare/bundles/bareIpc.js",
|
||||
"keys": [
|
||||
"bareJpeg"
|
||||
"bareIpc"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -379,6 +379,12 @@
|
||||
"bareLink"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModuleLexer.js",
|
||||
"keys": [
|
||||
"bareModuleLexer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMake.js",
|
||||
"keys": [
|
||||
@@ -397,18 +403,6 @@
|
||||
"bareModuleResolve"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModuleLexer.js",
|
||||
"keys": [
|
||||
"bareModuleLexer"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareModuleTraverse.js",
|
||||
"keys": [
|
||||
"bareModuleTraverse"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNdk.js",
|
||||
"keys": [
|
||||
@@ -421,12 +415,6 @@
|
||||
"bareNative"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"keys": [
|
||||
"bareMedia"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeFetch.js",
|
||||
"keys": [
|
||||
@@ -434,9 +422,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNet.js",
|
||||
"path": "/lib/bare/bundles/bareModuleTraverse.js",
|
||||
"keys": [
|
||||
"bareNet"
|
||||
"bareModuleTraverse"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -452,15 +440,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePack.js",
|
||||
"path": "/lib/bare/bundles/bareNet.js",
|
||||
"keys": [
|
||||
"barePack"
|
||||
"bareNet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"path": "/lib/bare/bundles/bareMedia.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
"bareMedia"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -470,9 +458,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePng.js",
|
||||
"path": "/lib/bare/bundles/barePack.js",
|
||||
"keys": [
|
||||
"barePng"
|
||||
"barePack"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -482,9 +470,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeRuntime.js",
|
||||
"path": "/lib/bare/bundles/barePng.js",
|
||||
"keys": [
|
||||
"bareNodeRuntime"
|
||||
"barePng"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -493,30 +481,36 @@
|
||||
"barePipe"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareDev.js",
|
||||
"keys": [
|
||||
"bareDev"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareNodeRuntime.js",
|
||||
"keys": [
|
||||
"bareNodeRuntime"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePunycode.js",
|
||||
"keys": [
|
||||
"barePunycode"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
|
||||
"keys": [
|
||||
"bareQueueMicrotask"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/barePrebuild.js",
|
||||
"keys": [
|
||||
"barePrebuild"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareQuerystring.js",
|
||||
"keys": [
|
||||
"bareQuerystring"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRealm.js",
|
||||
"keys": [
|
||||
@@ -524,21 +518,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"path": "/lib/bare/bundles/bareQueueMicrotask.js",
|
||||
"keys": [
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"keys": [
|
||||
"bareRepl"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRuntime.js",
|
||||
"keys": [
|
||||
"bareRuntime"
|
||||
"bareQueueMicrotask"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -548,9 +530,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRpc.js",
|
||||
"path": "/lib/bare/bundles/bareProcess.js",
|
||||
"keys": [
|
||||
"bareRpc"
|
||||
"bareProcess"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRuntime.js",
|
||||
"keys": [
|
||||
"bareRuntime"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -560,9 +548,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSignals.js",
|
||||
"path": "/lib/bare/bundles/bareRepl.js",
|
||||
"keys": [
|
||||
"bareSignals"
|
||||
"bareRepl"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -572,9 +560,15 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareRun.js",
|
||||
"path": "/lib/bare/bundles/bareRpc.js",
|
||||
"keys": [
|
||||
"bareRun"
|
||||
"bareRpc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSignals.js",
|
||||
"keys": [
|
||||
"bareSignals"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -584,9 +578,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"path": "/lib/bare/bundles/bareRun.js",
|
||||
"keys": [
|
||||
"bareStdio"
|
||||
"bareRun"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -608,9 +602,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareStructuredClone.js",
|
||||
"path": "/lib/bare/bundles/bareStdio.js",
|
||||
"keys": [
|
||||
"bareStructuredClone"
|
||||
"bareStdio"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -619,12 +613,6 @@
|
||||
"bareSvg"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareSystemLogger.js",
|
||||
"keys": [
|
||||
"bareSystemLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTap.js",
|
||||
"keys": [
|
||||
@@ -632,15 +620,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTcp.js",
|
||||
"path": "/lib/bare/bundles/bareSystemLogger.js",
|
||||
"keys": [
|
||||
"bareTcp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"keys": [
|
||||
"bareTiff"
|
||||
"bareSystemLogger"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -650,9 +632,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareThread.js",
|
||||
"path": "/lib/bare/bundles/bareTiff.js",
|
||||
"keys": [
|
||||
"bareThread"
|
||||
"bareTiff"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -661,6 +643,12 @@
|
||||
"bareTimers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTcp.js",
|
||||
"keys": [
|
||||
"bareTcp"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTpl.js",
|
||||
"keys": [
|
||||
@@ -668,15 +656,27 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareType.js",
|
||||
"path": "/lib/bare/bundles/bareStructuredClone.js",
|
||||
"keys": [
|
||||
"bareType"
|
||||
"bareStructuredClone"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnpack.js",
|
||||
"path": "/lib/bare/bundles/bareThread.js",
|
||||
"keys": [
|
||||
"bareUnpack"
|
||||
"bareThread"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"keys": [
|
||||
"bareTty"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareType.js",
|
||||
"keys": [
|
||||
"bareType"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -691,12 +691,6 @@
|
||||
"bareUiKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareTty.js",
|
||||
"keys": [
|
||||
"bareTty"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8.js",
|
||||
"keys": [
|
||||
@@ -704,9 +698,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWalkHandles.js",
|
||||
"path": "/lib/bare/bundles/bareUnpack.js",
|
||||
"keys": [
|
||||
"bareWalkHandles"
|
||||
"bareUnpack"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -715,12 +709,30 @@
|
||||
"bareVm"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWalkHandles.js",
|
||||
"keys": [
|
||||
"bareWalkHandles"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUnionBundle.js",
|
||||
"keys": [
|
||||
"bareUnionBundle"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"keys": [
|
||||
"bareV8ToIstanbul"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUtils.js",
|
||||
"keys": [
|
||||
"bareUtils"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebp.js",
|
||||
"keys": [
|
||||
@@ -739,24 +751,12 @@
|
||||
"bareWebKit"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareV8ToIstanbul.js",
|
||||
"keys": [
|
||||
"bareV8ToIstanbul"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWebKitGtk.js",
|
||||
"keys": [
|
||||
"bareWebKitGtk"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareUtils.js",
|
||||
"keys": [
|
||||
"bareUtils"
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWinUi.js",
|
||||
"keys": [
|
||||
@@ -770,9 +770,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareZmq.js",
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"keys": [
|
||||
"bareZmq"
|
||||
"bareWorker"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -782,9 +782,9 @@
|
||||
]
|
||||
},
|
||||
{
|
||||
"path": "/lib/bare/bundles/bareWorker.js",
|
||||
"path": "/lib/bare/bundles/bareZmq.js",
|
||||
"keys": [
|
||||
"bareWorker"
|
||||
"bareZmq"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -1595,8 +1595,8 @@
|
||||
],
|
||||
"bundleProvenance": {
|
||||
"schemaVersion": 1,
|
||||
"generatedAt": "2026-04-05T18:43:55.029Z",
|
||||
"gitCommit": "8bde7451914ae7534418f5c06def978ca5cec733",
|
||||
"generatedAt": "2026-04-05T19:03:42.280Z",
|
||||
"gitCommit": "39dbf0f1be135931add4414edfc66b593559be83",
|
||||
"nodeVersion": "v22.22.0",
|
||||
"bundleTier": "all",
|
||||
"normativeManifest": "packages/bare-os-booter/lib/bare-module-manifest.json",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema": 1,
|
||||
"atMs": 1775414633988,
|
||||
"atMs": 1775415820999,
|
||||
"commands": [
|
||||
"arch",
|
||||
"awk",
|
||||
@@ -80,6 +80,7 @@
|
||||
"mount",
|
||||
"mv",
|
||||
"nano",
|
||||
"nice",
|
||||
"nl",
|
||||
"nohup",
|
||||
"nproc",
|
||||
|
||||
@@ -507,6 +507,38 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
/** @param {string} ver */
|
||||
function bareOsKernelExtSemverValid(ver) {
|
||||
const s = String(ver || '').trim()
|
||||
return /^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?(\+[0-9A-Za-z.-]+)?$/.test(
|
||||
s
|
||||
)
|
||||
}
|
||||
/** @type {string[]} */
|
||||
const providesInvalidSemver = []
|
||||
for (const e of collected) {
|
||||
for (const pr of e.provides || []) {
|
||||
if (!bareOsKernelExtSemverValid(pr.version)) {
|
||||
providesInvalidSemver.push(`${e.extId}:${pr.name}@${pr.version}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
providesInvalidSemver.sort()
|
||||
if (providesInvalidSemver.length) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'warn',
|
||||
'kernelExt.providesInvalidSemver',
|
||||
`[kernel.ext.d] provides[].version must look like semver (major.minor.patch): ${providesInvalidSemver.join('; ')}`
|
||||
)
|
||||
if (strictPol) {
|
||||
await appendKernelExtAuditNdjson(ctx, {
|
||||
event: 'provides_invalid_semver',
|
||||
items: providesInvalidSemver
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
/** @type {Map<string, { extId: string, version: string }>} */
|
||||
const provideNameToOwner = new Map()
|
||||
/** @type {string[]} */
|
||||
@@ -613,20 +645,27 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
strictPol &&
|
||||
(ctx.env?.BARE_OS_BOOT_EXT_RESOLUTION_TRACE === '1' ||
|
||||
ctx.env?.BARE_OS_BOOT_EXT_RESOLUTION_TRACE === 'true')
|
||||
const resolutionAlways =
|
||||
ctx.env?.BARE_OS_KERNEL_EXT_RESOLUTION_JSON_ALWAYS === '1' ||
|
||||
ctx.env?.BARE_OS_KERNEL_EXT_RESOLUTION_JSON_ALWAYS === 'true'
|
||||
const extResolutionFailure = strictPol && !topo.ok
|
||||
if (
|
||||
ctx.vfs &&
|
||||
typeof ctx.vfs.writeFile === 'function' &&
|
||||
ctx.b4a &&
|
||||
(extResolutionFailure || traceOn)
|
||||
(extResolutionFailure || traceOn || resolutionAlways)
|
||||
) {
|
||||
try {
|
||||
const cycleSorted = topo.ok
|
||||
? []
|
||||
: [...topo.cycleExtIds].sort((a, b) => a.localeCompare(b))
|
||||
const provideSnapshot = {}
|
||||
for (const [k, v] of provideNameToOwner) {
|
||||
provideSnapshot[k] = v
|
||||
}
|
||||
const body =
|
||||
JSON.stringify({
|
||||
schema: 2,
|
||||
schema: 3,
|
||||
atMs: Date.now(),
|
||||
sessionId: String((ctx.env && ctx.env.BARE_OS_SESSION_ID) || ''),
|
||||
bootPolicyStrict: !!strictPol,
|
||||
@@ -640,9 +679,16 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
ordered: ordered.map((e) => ({
|
||||
extId: e.extId,
|
||||
file: e.file,
|
||||
dependsOn: e.dependsOn
|
||||
dependsOn: e.dependsOn,
|
||||
provides: e.provides || []
|
||||
})),
|
||||
cycleExtIds: topo.ok ? [] : cycleSorted
|
||||
cycleExtIds: topo.ok ? [] : cycleSorted,
|
||||
providesInvalidSemver,
|
||||
providesVersionConflicts:
|
||||
providesVersionConflicts.length > 0
|
||||
? providesVersionConflicts
|
||||
: undefined,
|
||||
provideNameToOwner: provideSnapshot
|
||||
}) + '\n'
|
||||
await ctx.vfs.writeFile(
|
||||
'/run/bare-os/kernel-ext-resolution.json',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -2,6 +2,7 @@ import { readFile } from '#host-fs-promises'
|
||||
import path from '#host-path'
|
||||
import b4a from 'b4a'
|
||||
import { pearMultisigShapeOk } from 'bare-os-protocol/bare-os-pear-multisig-shape.js'
|
||||
import { seedLog } from './host-logger.mjs'
|
||||
|
||||
/**
|
||||
* @returns {Promise<((cmd: string, args: string[], opts?: object) => object) | null>}
|
||||
@@ -51,16 +52,20 @@ export async function logPearMultisigKernelHint(kernelRoot) {
|
||||
const raw = await readFile(f, 'utf8')
|
||||
const j = JSON.parse(raw)
|
||||
if (!pearMultisigShapeOk(j)) {
|
||||
console.warn(
|
||||
'[seeder] pear.multisig.json: expected { signers: string[], quorum: number } with 1 ≤ quorum ≤ signers.length'
|
||||
seedLog(
|
||||
'warn',
|
||||
'pear.multisig.json: expected { signers: string[], quorum: number } with 1 ≤ quorum ≤ signers.length',
|
||||
{ code: 'pear_multisig_shape' }
|
||||
)
|
||||
if (envOut) envOut.BARE_OS_SEEDER_MULTISIG_VERIFY_RESULT = 'skipped'
|
||||
return
|
||||
}
|
||||
const signers = j.signers
|
||||
const quorum = j.quorum
|
||||
console.log(
|
||||
`[seeder] pear.multisig.json OK (${signers.length} signers, quorum ${quorum})`
|
||||
seedLog(
|
||||
'info',
|
||||
`pear.multisig.json OK (${signers.length} signers, quorum ${quorum})`,
|
||||
{ code: 'pear_multisig_ok' }
|
||||
)
|
||||
const env = globalThis.process?.env
|
||||
if (
|
||||
@@ -69,8 +74,10 @@ export async function logPearMultisigKernelHint(kernelRoot) {
|
||||
) {
|
||||
const spawnSync = await loadSpawnSync()
|
||||
if (!spawnSync) {
|
||||
console.warn(
|
||||
'[seeder] hyper-multisig verify skipped (no subprocess: install bare-subprocess or use Node)'
|
||||
seedLog(
|
||||
'warn',
|
||||
'hyper-multisig verify skipped (no subprocess: install bare-subprocess or use Node)',
|
||||
{ code: 'hyper_multisig_no_subprocess' }
|
||||
)
|
||||
if (envOut) envOut.BARE_OS_SEEDER_MULTISIG_VERIFY_RESULT = 'skipped'
|
||||
return
|
||||
@@ -80,17 +87,22 @@ export async function logPearMultisigKernelHint(kernelRoot) {
|
||||
stdio: ['ignore', 'pipe', 'pipe']
|
||||
})
|
||||
if (r.error) {
|
||||
console.warn(
|
||||
'[seeder] hyper-multisig verify skipped (CLI not on PATH):',
|
||||
r.error.message
|
||||
seedLog(
|
||||
'warn',
|
||||
'hyper-multisig verify skipped (CLI not on PATH): ' +
|
||||
String(r.error.message || r.error),
|
||||
{ code: 'hyper_multisig_cli_missing' }
|
||||
)
|
||||
if (envOut) envOut.BARE_OS_SEEDER_MULTISIG_VERIFY_RESULT = 'skipped'
|
||||
} else if (r.status !== 0) {
|
||||
const msg = (pipeText(r, 'stderr') || pipeText(r, 'stdout')).trim().slice(0, 400)
|
||||
console.warn('[seeder] hyper-multisig verify failed:', msg || `exit ${r.status}`)
|
||||
seedLog('warn', 'hyper-multisig verify failed: ' + (msg || `exit ${r.status}`), {
|
||||
code: 'hyper_multisig_verify_failed',
|
||||
status: r.status
|
||||
})
|
||||
if (envOut) envOut.BARE_OS_SEEDER_MULTISIG_VERIFY_RESULT = 'failed'
|
||||
} else {
|
||||
console.log('[seeder] hyper-multisig verify OK')
|
||||
seedLog('info', 'hyper-multisig verify OK', { code: 'hyper_multisig_verify_ok' })
|
||||
if (envOut) envOut.BARE_OS_SEEDER_MULTISIG_VERIFY_RESULT = 'ok'
|
||||
}
|
||||
} else if (envOut) {
|
||||
@@ -98,7 +110,9 @@ export async function logPearMultisigKernelHint(kernelRoot) {
|
||||
}
|
||||
} catch (e) {
|
||||
if (/** @type {NodeJS.ErrnoException} */ (e).code === 'ENOENT') return
|
||||
console.warn('[seeder] pear.multisig.json:', e?.message || e)
|
||||
seedLog('warn', 'pear.multisig.json: ' + (e?.message || String(e)), {
|
||||
code: 'pear_multisig_read_error'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,19 +134,25 @@ export async function logPearMultisigKernelHintFromPearAppDrive(appDrive) {
|
||||
try {
|
||||
const j = JSON.parse(raw)
|
||||
if (!pearMultisigShapeOk(j)) {
|
||||
console.warn(
|
||||
'[seeder] pear.multisig.json: expected { signers: string[], quorum: number } with 1 ≤ quorum ≤ signers.length'
|
||||
seedLog(
|
||||
'warn',
|
||||
'pear.multisig.json: expected { signers: string[], quorum: number } with 1 ≤ quorum ≤ signers.length',
|
||||
{ code: 'pear_multisig_shape_bundle' }
|
||||
)
|
||||
if (envOut) envOut.BARE_OS_SEEDER_MULTISIG_VERIFY_RESULT = 'skipped'
|
||||
return
|
||||
}
|
||||
const signers = j.signers
|
||||
const quorum = j.quorum
|
||||
console.log(
|
||||
`[seeder] pear.multisig.json OK (${signers.length} signers, quorum ${quorum}) [from Pear bundle]`
|
||||
seedLog(
|
||||
'info',
|
||||
`pear.multisig.json OK (${signers.length} signers, quorum ${quorum}) [from Pear bundle]`,
|
||||
{ code: 'pear_multisig_ok_bundle' }
|
||||
)
|
||||
if (envOut) envOut.BARE_OS_SEEDER_MULTISIG_VERIFY_RESULT = 'skipped'
|
||||
} catch (e) {
|
||||
console.warn('[seeder] pear.multisig.json (bundle):', e?.message || e)
|
||||
seedLog('warn', 'pear.multisig.json (bundle): ' + (e?.message || String(e)), {
|
||||
code: 'pear_multisig_bundle_parse'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user