chore(plan): cancel end-to-end seeder-to-booter smoke harness task

test(protocol): add deterministic MBR failover-key coverage
docs(protocol): align package-bare-os-protocol version to 0.9.1
test(booter): add MBR corruption and wrong-topic smoke fixtures
test(peer-seed): add strict pre-MBR bare_os.capabilities negotiation check
feat(seeder): validate BARE_OS_SEED_REQUIRE_MBR_LABELS
feat(seeder): validate BARE_OS_SEED_CAPABILITY_ATTESTATION_JSON schema
docs(boot-policy): add requireProtocolPackageMin 0.9.1 example
test(kernel): cover boot.policy denySeedRpcMethods behavior
test(protocol): add app/cap/chat/meshdrop channel compatibility fixture
test(swarm-disk): cover duplicate Protomux channel null-return path
test(protocol): add 11-word kernelCapabilityWords round-trip fixture
docs(schema): add mbr-layout schema and validate seeder examples
test(protocol): add topicKey() golden hash fixture
docs(trust): document block-0 trust assumptions in boot docs
feat(seeder): add discovery.flushed readiness logging
feat(booter): record peer discovery timings in boot-perf.json
feat(integration): add local testnet mode to integration lab smoke
test(booter): add Hyperswarm connection-budget env regression coverage
test(booter): add swarm plus Corestore suspend/resume integration coverage
feat(booter): mirror swarm ban events into host audit logs
feat(booter): add direct-peer boot via BARE_OS_BOOT_JOIN_PEER_HEX
feat(seeder): pass BARE_OS_SEED_MAX_PEERS to Hyperswarm
feat(seeder): log drive.version and discoveryKey at startup
test(booter): add Hyperdrive.checkout read-only boot probe coverage
feat(booter): prefetch /boot/init.js before kernel handoff
feat(booter): add optional /bin warm replication via downloadDiff
feat(seeder): add manifestPaths SHA-256 generation in stage-kernel-tree
test(peer-seed): cover helper-served block-0 after seeder exit
feat(protocol): add Protomux cork batching for initial channel sends
test(boot-graph): compare kernel/init labels with booter graph proc
docs(boot-policy): add v9-v11 schema examples
feat(release): add requireInitJsSha256 fixture generation step
test(vfs): add BARE_OS_VFS_SYSTEM_RO_ALIAS coverage
test(vfs): strengthen system-drive write-deny path coverage
feat(identity): add personal-drive namespace export/import docs and tests
test(booter): add guest-to-login warm cache invalidation regression
test(vfs): add guest deny coverage for /.bare sensitive paths
test(coreutils): add cross-drive mv failure injection coverage
test(vfs): add .bareos_empty round-trip coverage across mkdir/rmdir/cp/git-fs
test(vfs): add /dev/shm quota enforcement coverage
test(proc): add /proc/bare_os/index.json sortedness and schema checks
test(vfs): add warm read cache invalidation on replication growth
docs(ctx): document bareOsInvalidateWarmReadCaches(reason)
test(kernel): add BARE_OS_BOOT_DRY_RUN behavior coverage
docs(posix): add dashboard rows for all COREUTILS_COMMANDS
feat(curl): expand -w variables beyond http_code/url_effective/size_download
feat(wget): mark -N timestamping as explicit unsupported error
feat(curl): plumb mutual TLS cert/key intent to ctx.httpFetch metadata
feat(shuf): add deterministic seed mode via BARE_OS_SHUF_SEED
docs(sort): document -M month-sort as unsupported
feat(grep): add explicit -E and -G mode handling
test(sed): add Open Group Issue 7 golden fixtures
test(awk): add getline VFS regressions for missing/repeat/boundary cases
test(shell): add non-interactive here-doc coverage
test(shell): add trap delivery coverage for synthetic PIDs/job IDs
test(shell): add set -e compound-body behavior coverage
docs(shell): strengthen read builtin opt-in guidance
test(env): add Bare-runtime coverage for -S and --env-file
docs(man): add examples for pathcap-verify pkg-swarm-index corestorectl
test(identity): add account/vault backup-restore smoke coverage
feat(audit): add tamper detection verification for audit chain rows
test(peer-admission): cover strict empty allowlist deny behavior
test(peer-admission): add denylist precedence over allowlist coverage
test(peer-admission): add BARE_OS_PEER_REQUIRE_CAPS_JSON metadata checks
docs(identity): add trusted-key rotation example for path capabilities
feat(schema): tighten extensionSignerPinsV2-V4 hash validation
test(delegate): add allowlist negative cases for curl/wget/git/hrpc/systemctl
test(proc): extend /proc/self/environ redaction key coverage
docs(security): add peer-assisted block-0 mirroring threat-model notes
feat(bench): add boot budget trend output from real booter phases
test(baretop): align fixture coverage with /proc snapshot key set
test(metrics): validate /proc/bare_os/metrics.prom OpenMetrics shape
docs(ops): add structured seeder NDJSON examples
test(replication): add live stall-hint coverage for no_peers/length_unavailable/ok
docs(release): add corestore-snapshot workflow to checklist
docs(ops): add mirror-drive experiment utility to maintainer workflow
test(booter): add monitor progress coverage for replication live sketch
feat(seeder): validate DHT bootstrap address class JSON inputs
docs(network): add HYPERSWARM_BOOTSTRAP testnet operator guidance
chore(root): add deterministic test:integration script
docs(ci): add local CI runbook for no-.github environments
docs(release): add npm run test:bare after npm test
feat(verify): add protocol docs/package version parity checker
feat(verify): enforce feature-roadmap canonical path consistency
feat(lockfile-drift): add tier-1 strict fail option for mismatches
docs(lockfile-drift): add udx-native and blind-peering upgrade workflow notes
docs(cli-parity): add bare-fetch upstream issue tracking row
feat(bundle-health): generate per-tier bundle size regression thresholds
feat(doc-contracts): verify handbook references to current proc schema versions
feat(pretest): add validate-mermaid-syntax gate
feat(probe): add bare-runtime top-25 critical command lane
docs(protocol): update capability-word prose from bits..bits5 to current words
docs(two-drive): document /tmp /var/log and account-prefix routing
docs(security): add concise boot trust model page and links
docs(dev-guide): add P2P lab cookbook section
docs(dev-guide): add how-to for adding seed RPCs
docs(dev-guide): add how-to for adding /proc/bare_os nodes
docs(dev-guide): add /bin utility checklist for man/posix/build/parity/tests
docs(user-manual): add short What BareOS is not section
This commit is contained in:
Raven Scott
2026-04-26 22:28:21 -04:00
parent a553a4e4a7
commit d286ce19b5
124 changed files with 52097 additions and 1247 deletions
+22 -4
View File
@@ -98,6 +98,12 @@ Concatenates sorted `kernel/lib/boot/*.js` + sorted `kernel/lib/init/fragments/*
Ensures [docs/data/feature-roadmap-canonical.json](../docs/data/feature-roadmap-canonical.json) aligns with the batch B table in **`feature-roadmap.md`**. Root **`pretest`**.
## `verify-feature-roadmap-paths.mjs`
**Usage:** `node scripts/verify-feature-roadmap-paths.mjs` (also **`npm run verify:feature-roadmap-paths`**)
Ensures **`docs/reference/feature-roadmap.md`** links to the canonical machine-readable source at **`docs/data/feature-roadmap-canonical.json`**. Root **`pretest`**.
## `verify-no-new-giant-phase-identifiers.mjs`
**Usage:** `node scripts/verify-no-new-giant-phase-identifiers.mjs`
@@ -266,11 +272,23 @@ Ensures **`bare-os-ctx.d.ts`** lists documented **`ctx`** fields (including **`b
Scans **`docs/`**, **`handbook/`**, **`developer-guide/`**, **`users-manual/`**, **`packages/`**, **`kernel/`**, **`scripts/*.md`**, plus root **`README.md`** / **`DOCUMENTATION.md`**, for relative **`.md`** links and fails when the target file is missing. Root **`pretest`**.
## `verify-protocol-doc-version-parity.mjs`
**Usage:** `node scripts/verify-protocol-doc-version-parity.mjs` (also **`npm run verify:protocol-doc-version`**)
Verifies **`packages/bare-os-protocol/package.json`** version text is present in **`docs/reference/package-bare-os-protocol.md`** so package/reference docs stay in lockstep. Root **`pretest`**.
## `validate-mermaid-syntax.mjs`
**Usage:** `BARE_OS_VALIDATE_MERMAID=1 node scripts/validate-mermaid-syntax.mjs` · workflow **[`.github/workflows/docs-mermaid-smoke.yml`](../.github/workflows/docs-mermaid-smoke.yml)** (**`workflow_dispatch`** + weekly **`cron`**)
**Usage:** `node scripts/validate-mermaid-syntax.mjs`
Renders every **```mermaid** fenced block (under **`docs/`**, **`handbook/`**, **`developer-guide/`**, **`users-manual/`**, **`packages/`**, **`scripts/`**, plus root **`README.md`** / **`DOCUMENTATION.md`**) via a one-off **`@mermaid-js/mermaid-cli`** install in a temp directory. **Not** part of root **`pretest`**. Locally **skips** unless `**BARE_OS_VALIDATE_MERMAID=1`**; GitHub Actions sets **`GITHUB_ACTIONS=true`** so scheduled / manual runs validate diagrams without slowing every clone.
Checks markdown **```mermaid** blocks in **`docs/`**, **`handbook/`**, **`developer-guide/`**, and **`users-manual/`** for closed fences, non-empty bodies, and recognized Mermaid diagram starters. Root **`pretest`**.
## `gen-require-initjs-sha256.mjs`
**Usage:** `node scripts/gen-require-initjs-sha256.mjs`
Regenerates the expected `kernel/init.js` SHA-256 fixture used by release-contract checks that pin the stock boot entrypoint digest.
## `verify-man-coverage.mjs`
@@ -300,7 +318,7 @@ Ensures **`BARE_OS_CTX_API_VERSION`** and **`BARE_OS_POSIX_PROFILE_VERSION`** ap
**Usage:** `node scripts/verify-bundle-health.mjs`
Asserts **[`docs/audit/bundle-health.json`](../docs/audit/bundle-health.json)** (regenerated by **`npm run build -w bare-os-bare-libs`**) matches **`kernel/lib/bare/manifest.json`** and on-disk **`kernel/lib/bare/bundles/*.js`** byte sizes. Detects orphan bundle files. Root **`pretest`**.
Asserts **[`docs/audit/bundle-health.json`](../docs/audit/bundle-health.json)** (regenerated by **`npm run build -w bare-os-bare-libs`**) matches **`kernel/lib/bare/manifest.json`** and on-disk **`kernel/lib/bare/bundles/*.js`** byte sizes. Detects orphan bundle files and enforces generated per-tier regression ceilings from **`bundleRegressionThresholds.byCtxKey`** (core / optional_js / optional_native). Root **`pretest`**.
## `verify-bundle-markers.mjs`
@@ -318,7 +336,7 @@ Writes **[`docs/audit/holepunch-clone-sync-report.json`](../docs/audit/holepunch
**Usage:** `npm run audit:holepunch-clones` (includes this step) or `node scripts/report-holepunch-lockfile-drift.mjs`
Compares hoisted **`package-lock.json`** versions (**`node_modules/<pkg>`**) against **`lockfilePackages`** in **[`docs/audit/holepunch-drift-repos.json`](../docs/audit/holepunch-drift-repos.json)** and local clone **`package.json`** versions. Writes **[`docs/audit/holepunch-lockfile-drift.json`](../docs/audit/holepunch-lockfile-drift.json)** and **`holepunch-lockfile-drift-summary.ndjson`**, plus a maintainer-readable Markdown table **[`docs/audit/holepunch-lockfile-drift-dashboard.md`](../docs/audit/holepunch-lockfile-drift-dashboard.md)**. Informational only (not a failing CI gate).
Compares hoisted **`package-lock.json`** versions (**`node_modules/<pkg>`**) against **`lockfilePackages`** in **[`docs/audit/holepunch-drift-repos.json`](../docs/audit/holepunch-drift-repos.json)** and local clone **`package.json`** versions. Writes **[`docs/audit/holepunch-lockfile-drift.json`](../docs/audit/holepunch-lockfile-drift.json)** and **`holepunch-lockfile-drift-summary.ndjson`**, plus a maintainer-readable Markdown table **[`docs/audit/holepunch-lockfile-drift-dashboard.md`](../docs/audit/holepunch-lockfile-drift-dashboard.md)**. Default mode is informational; set **`BARE_OS_HOLEPUNCH_LOCKFILE_DRIFT_TIER1_FAIL=1`** to fail when any **`tier1Repos[]`** package has a semver mismatch against its local clone.
## `report-holepunch-runtime-compat.mjs`
+37 -6
View File
@@ -4,19 +4,44 @@
* Run manually: `node scripts/benchmark-boot-sketch.mjs`
* Trend path: `BARE_OS_BENCHMARK_TREND_NDJSON` or `${TMPDIR:-/tmp}/bare-os-benchmark-trend.ndjson`
*/
import { appendFileSync } from 'node:fs'
import { appendFileSync, readFileSync } from 'node:fs'
import process from 'node:process'
const t0 = Date.now()
const ms = Math.max(0, Date.now() - t0)
function readBootPerfRows() {
const p =
String(process.env.BARE_OS_BOOT_PERF_PATH || '').trim() ||
'/run/bare-os/boot-perf.json'
try {
const raw = String(readFileSync(p, 'utf8') || '').trim()
if (!raw) return { path: p, phases: [] }
const j = JSON.parse(raw)
const phases = Array.isArray(j?.phaseSamples)
? j.phaseSamples
.map((x) => ({
phase: String(x?.phase || ''),
ms: Number(x?.ms || 0)
}))
.filter((x) => x.phase && Number.isFinite(x.ms) && x.ms >= 0)
: []
return { path: p, phases }
} catch {
return { path: p, phases: [] }
}
}
const perf = readBootPerfRows()
const totalMs = perf.phases.reduce((a, b) => a + b.ms, 0)
const path =
String(process.env.BARE_OS_BENCHMARK_TREND_NDJSON || '').trim() ||
`${process.env.TMPDIR || '/tmp'}/bare-os-benchmark-trend.ndjson`
const line =
JSON.stringify({
schema: 1,
schema: 2,
name: 'boot-sketch',
wallMs: ms,
wallMs: totalMs,
bootPerfPath: perf.path,
phaseCount: perf.phases.length,
phaseTimings: perf.phases,
atMs: Date.now()
}) + '\n'
try {
@@ -24,5 +49,11 @@ try {
} catch {
/* ignore */
}
console.log('benchmark-boot-sketch: ok (trend → ' + path + ')')
console.log(
'benchmark-boot-sketch: ok (trend → ' +
path +
', phases=' +
perf.phases.length +
')'
)
process.exit(0)
+9
View File
@@ -53,6 +53,15 @@ function main() {
}
}
}
if (Array.isArray(matrix.commandIndex)) {
for (const row of matrix.commandIndex) {
if (!row || typeof row !== 'object') continue
const name = String(row.name || '').trim()
if (!name) continue
const tier = String(row.tier || '').trim() || 'unspecified'
push('Coreutils commandIndex', name, tier)
}
}
const body = `# POSIX compliance dashboard (generated)
+38
View File
@@ -0,0 +1,38 @@
#!/usr/bin/env node
/**
* Generate a boot.policy requireInitJsSha256 fixture from kernel/init.js.
*/
import { createHash } from 'node:crypto'
import { readFileSync, writeFileSync } from 'node:fs'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const root = path.join(path.dirname(fileURLToPath(import.meta.url)), '..')
const initPath = path.join(root, 'kernel', 'init.js')
const outPath =
process.argv[2] && String(process.argv[2]).trim()
? path.resolve(root, String(process.argv[2]).trim())
: path.join(
root,
'docs',
'data',
'boot-policy-require-initjs-sha256.fixture.json'
)
const src = readFileSync(initPath)
const sha256Hex = createHash('sha256').update(src).digest('hex')
const fixture = {
schema: 1,
source: 'kernel/init.js',
algorithm: 'sha256',
requireInitJsSha256: sha256Hex,
generatedAt: new Date().toISOString(),
note: 'Copy requireInitJsSha256 into /etc/bare-os/boot.policy.json when pinning boot init bytes.'
}
writeFileSync(outPath, JSON.stringify(fixture, null, 2) + '\n')
console.log(
`[gen-require-initjs-sha256] wrote ${path.relative(root, outPath)}`
)
console.log(`[gen-require-initjs-sha256] requireInitJsSha256=${sha256Hex}`)
+223 -11
View File
@@ -1,16 +1,228 @@
#!/usr/bin/env node
/**
* Integration lab smoke: extend with local Holepunch mirrors + synthetic peers.
* Run: `node scripts/integration-lab-smoke.mjs`
* Integration smoke: boot a real seeder + booter pair with isolated stores.
* Runs `npm run os:seeder` and `npm run os:booter` against temp Corestores.
*/
import process from 'node:process'
console.log(
JSON.stringify({
schema: 1,
ok: true,
note: 'Wire local corestore + topic fixtures here; see developer-guide.',
atMs: Date.now()
})
import { spawn } from 'node:child_process'
import { mkdtemp, rm } from 'node:fs/promises'
import os from 'node:os'
import path from 'node:path'
import process from 'node:process'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const tmpBase = await mkdtemp(path.join(os.tmpdir(), 'bare-os-integration-lab-'))
const hostData = path.join(tmpBase, 'host-data')
const seedStore = path.join(hostData, 'corestore', 'seeder')
const bootStore = path.join(hostData, 'corestore', 'booter')
const timeoutMs = clampInt(process.env.BARE_OS_INTEGRATION_TIMEOUT_MS, 120000)
const seederReadyTimeoutMs = clampInt(
process.env.BARE_OS_INTEGRATION_SEEDER_READY_TIMEOUT_MS,
60000
)
process.exit(0)
const booterReadyTimeoutMs = clampInt(
process.env.BARE_OS_INTEGRATION_BOOTER_READY_TIMEOUT_MS,
90000
)
const testnet = resolveTestnetBootstrapEnv(process.env)
/** @type {{ seeder?: import('node:child_process').ChildProcess, booter?: import('node:child_process').ChildProcess }} */
const procs = {}
const startedAt = Date.now()
const baseEnv = {
...process.env,
BARE_OS_HOST_DATA: hostData,
BARE_OS_SEED_STORE: seedStore,
BARE_OS_BOOT_STORE: bootStore,
BARE_OS_NO_SPLASH: '1',
BARE_OS_BOOT_TIMEOUT_MS: String(clampInt(process.env.BARE_OS_BOOT_TIMEOUT_MS, 45000)),
...(testnet.envBootstrap ? { HYPERSWARM_BOOTSTRAP: testnet.envBootstrap } : {})
}
try {
procs.seeder = runNpmScript('os:seeder', { env: baseEnv, name: 'seeder' })
await waitForOutput(
procs.seeder,
[/seeder active/i, /MBR block 0/i],
seederReadyTimeoutMs,
'seeder readiness'
)
procs.booter = runNpmScript('os:booter', {
env: {
...baseEnv,
BARE_OS_SKIP_REPL: '1',
BARE_OS_BOOT_TRACE: 'ndjson'
},
name: 'booter'
})
await waitForOutput(
procs.booter,
[/booter:kernel_invoke/i, /"ready":\s*true/i, /"type":"boot_ready"/i],
booterReadyTimeoutMs,
'booter readiness'
)
const booterExited = await waitForExit(procs.booter, 10000)
const ok = booterExited.code === 0 || booterExited.code === null
if (!ok) {
throw new Error(`booter exited with code ${booterExited.code ?? 'signal'}`)
}
console.log(
JSON.stringify({
schema: 2,
ok: true,
atMs: Date.now(),
elapsedMs: Date.now() - startedAt,
mode: 'seeder-booter-e2e',
testnetMode: testnet.enabled,
hyperswarmBootstrap: testnet.redactedBootstrap,
tempRoot: tmpBase
})
)
} catch (err) {
console.error(
JSON.stringify({
schema: 2,
ok: false,
atMs: Date.now(),
elapsedMs: Date.now() - startedAt,
mode: 'seeder-booter-e2e',
testnetMode: testnet.enabled,
hyperswarmBootstrap: testnet.redactedBootstrap,
error: err instanceof Error ? err.message : String(err)
})
)
process.exitCode = 1
} finally {
await teardownProc(procs.booter)
await teardownProc(procs.seeder)
if (process.env.BARE_OS_INTEGRATION_KEEP_TMP !== '1') {
await rm(tmpBase, { recursive: true, force: true })
}
}
/**
* @param {string | undefined} raw
* @param {number} fallback
*/
function clampInt(raw, fallback) {
const n = Number.parseInt(String(raw ?? ''), 10)
if (!Number.isFinite(n) || n <= 0) return fallback
return Math.min(Math.max(1000, n), 15 * 60 * 1000)
}
/**
* Local integration testnet mode:
* - Enable with BARE_OS_INTEGRATION_TESTNET=1|true|yes.
* - Uses BARE_OS_INTEGRATION_TESTNET_BOOTSTRAP when present.
* - Otherwise reuses HYPERSWARM_BOOTSTRAP when already configured.
* @param {Record<string, string | undefined>} env
*/
function resolveTestnetBootstrapEnv(env) {
const on = String(env.BARE_OS_INTEGRATION_TESTNET ?? '')
.trim()
.toLowerCase()
const enabled = on === '1' || on === 'true' || on === 'yes'
const explicit = String(env.BARE_OS_INTEGRATION_TESTNET_BOOTSTRAP ?? '').trim()
const inherited = String(env.HYPERSWARM_BOOTSTRAP ?? '').trim()
const envBootstrap = enabled ? (explicit || inherited || '') : ''
const redactedBootstrap = envBootstrap
? envBootstrap
.split(',')
.map((s) => s.trim())
.filter(Boolean)
.map((s) => (s.length > 20 ? s.slice(0, 20) + '...' : s))
.join(',')
: ''
return { enabled, envBootstrap, redactedBootstrap }
}
/**
* @param {string} script
* @param {{ env: Record<string, string | undefined>, name: string }} opts
*/
function runNpmScript(script, opts) {
const child = spawn('npm', ['run', script], {
cwd: root,
env: opts.env,
stdio: ['ignore', 'pipe', 'pipe']
})
child.stdout?.setEncoding('utf8')
child.stderr?.setEncoding('utf8')
child.stdout?.on('data', (d) => process.stdout.write(`[${opts.name}] ${d}`))
child.stderr?.on('data', (d) => process.stderr.write(`[${opts.name}] ${d}`))
return child
}
/**
* @param {import('node:child_process').ChildProcess | undefined} child
* @param {RegExp[]} patterns
* @param {number} ms
* @param {string} label
*/
function waitForOutput(child, patterns, ms, label) {
if (!child) return Promise.reject(new Error(`${label}: process missing`))
return new Promise((resolve, reject) => {
let buf = ''
const to = setTimeout(() => {
cleanup()
reject(new Error(`${label}: timeout after ${ms}ms`))
}, Math.min(ms, timeoutMs))
const onChunk = (chunk) => {
buf += String(chunk)
if (buf.length > 120000) buf = buf.slice(-80000)
if (patterns.some((re) => re.test(buf))) {
cleanup()
resolve()
}
}
const onExit = (code) => {
cleanup()
reject(new Error(`${label}: process exited before match (${code ?? 'signal'})`))
}
const cleanup = () => {
clearTimeout(to)
child.stdout?.off('data', onChunk)
child.stderr?.off('data', onChunk)
child.off('exit', onExit)
}
child.stdout?.on('data', onChunk)
child.stderr?.on('data', onChunk)
child.on('exit', onExit)
})
}
/**
* @param {import('node:child_process').ChildProcess | undefined} child
* @param {number} ms
*/
function waitForExit(child, ms) {
if (!child) return Promise.resolve({ code: 0 })
return new Promise((resolve) => {
let done = false
const finish = (code) => {
if (done) return
done = true
clearTimeout(to)
resolve({ code })
}
const to = setTimeout(() => finish(null), ms)
child.once('exit', finish)
})
}
/**
* @param {import('node:child_process').ChildProcess | undefined} child
*/
async function teardownProc(child) {
if (!child || child.killed || child.exitCode != null) return
child.kill('SIGTERM')
await waitForExit(child, 6000)
if (child.exitCode == null) child.kill('SIGKILL')
}
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env node
/**
* Maintainer utility: emit a mirror-drive experiment plan/hints JSON.
* Non-destructive: this script does not mutate Corestores.
*
* Usage:
* node scripts/mirror-drive-experiment.mjs --source-key <hex> [--mirror-key <hex>] [--aux 2]
*/
import process from 'node:process'
function arg(name, def = '') {
const i = process.argv.indexOf(name)
if (i === -1 || i + 1 >= process.argv.length) return def
return String(process.argv[i + 1] || '')
}
const sourceKey = arg('--source-key', '').trim()
const mirrorKey = arg('--mirror-key', '').trim()
const aux = Math.max(0, Number.parseInt(arg('--aux', '0'), 10) || 0)
if (!/^[a-f0-9]{64}$/i.test(sourceKey)) {
console.error(
'mirror-drive-experiment: --source-key must be a 64-hex Hyperdrive key'
)
process.exit(2)
}
const out = {
schema: 1,
tool: 'mirror-drive-experiment',
sourceKeyHex: sourceKey.toLowerCase(),
mirrorKeyHex: /^[a-f0-9]{64}$/i.test(mirrorKey) ? mirrorKey.toLowerCase() : '',
auxiliaryCountHint: aux,
envHints: {
BARE_OS_MIRROR_READ_KEY: /^[a-f0-9]{64}$/i.test(mirrorKey)
? mirrorKey.toLowerCase()
: sourceKey.toLowerCase(),
BARE_OS_MIRROR_DRIVE_COMPOSITION_HINT_JSON: JSON.stringify({
schema: 1,
mirrorDrivePattern: 'single-primary-plus-aux',
auxiliaryCountHint: aux,
sourceKeyHex: sourceKey.toLowerCase()
})
},
note: 'Local experiment hints only; apply env vars manually when launching booter/seeder.'
}
process.stdout.write(JSON.stringify(out, null, 2) + '\n')
+37 -1
View File
@@ -23,6 +23,9 @@ const root = path.resolve(__dirname, '..')
const kernelBinDir = path.join(root, 'kernel', 'bin')
const probeTimeoutMs = Number.parseInt(process.env.BARE_OS_BIN_PROBE_TIMEOUT_MS || '', 10) || 2_000
const truncLen = 160
const lane = String(process.env.BARE_OS_BIN_PROBE_LANE || 'full')
.trim()
.toLowerCase()
const FAST_SAFE_ARGS = new Map([
['echo', ['ok']],
@@ -43,6 +46,34 @@ const HELP_ONLY_ARGS = new Map([
const SKIPPED = new Map([])
const CRITICAL_TOP25 = [
'sh',
'ls',
'cat',
'cp',
'mv',
'rm',
'mkdir',
'rmdir',
'chmod',
'chown',
'touch',
'grep',
'sed',
'awk',
'find',
'sort',
'uniq',
'head',
'tail',
'cut',
'xargs',
'env',
'printf',
'test',
'echo'
]
function classifyNonZero(exitCode, combinedText) {
if (exitCode === 0) return 'OK'
if (exitCode === 126 && /delegate/i.test(combinedText)) return 'SKIPPED'
@@ -144,9 +175,13 @@ async function main() {
const coreSet = new Set(coreutils)
const missing = coreutils.filter((name) => !stagedSet.has(name))
const extra = staged.filter((name) => !coreSet.has(name))
const candidates = [...new Set([...coreutils, ...staged])].sort((a, b) =>
const allCandidates = [...new Set([...coreutils, ...staged])].sort((a, b) =>
a.localeCompare(b)
)
const candidates =
lane === 'bare-runtime'
? CRITICAL_TOP25.filter((n) => allCandidates.includes(n))
: allCandidates
const { tmp, store, drive, personal, logs, errs, ctx } = await makeProbeContext()
let failed = false
@@ -252,6 +287,7 @@ async function main() {
console.log('BINS PROBE SUMMARY')
console.log('==================')
console.log(`Lane: ${lane}`)
console.log(`COREUTILS_COMMANDS: ${coreutils.length}`)
console.log(`kernel/bin files: ${staged.length}`)
console.log(`Candidates probed: ${results.length}`)
+10
View File
@@ -22,11 +22,15 @@ function run(cmd, args, opts = {}) {
console.log('[release-checklist] npm test')
run('npm', ['test'])
console.log('[release-checklist] npm run test:bare')
run('npm', ['run', 'test:bare'])
console.log('[release-checklist] verify-kernel-seeder-parity')
run('node', ['scripts/verify-kernel-seeder-parity.mjs'])
console.log('[release-checklist] verify-init-bundle-recipe (focused init bundle gate)')
run('node', ['scripts/verify-init-bundle-recipe.mjs'])
console.log('[release-checklist] gen-require-initjs-sha256 fixture')
run('node', ['scripts/gen-require-initjs-sha256.mjs'])
console.log('[release-checklist] verify-ctx-api-feature-bits')
run('node', ['scripts/verify-ctx-api-feature-bits.mjs'])
console.log('[release-checklist] verify-compat-matrix')
@@ -60,6 +64,12 @@ if (
}
console.log('[release-checklist] verify-personal-drive-path-policy')
run('node', ['scripts/verify-personal-drive-path-policy.mjs'])
console.log(
'[release-checklist] corestore snapshot workflow reminder: exercise host snapshot lane and verify /proc snapshot hints parity (BARE_OS_CORESTORE_SNAPSHOT_JSON / BARE_OS_CORESTORE_SNAPSHOT_WORKFLOW_JSON)'
)
console.log(
'[release-checklist] optional mirror-drive experiment helper: node scripts/mirror-drive-experiment.mjs --source-key <64hex> --mirror-key <64hex> --aux <n>'
)
console.log('[release-checklist] verify-ctx-client-helper-sync')
run('node', ['scripts/verify-ctx-client-helper-sync.mjs'])
console.log(
+50 -4
View File
@@ -9,6 +9,8 @@
*
* Env:
* BARE_OS_HOLEPUNCH_CLONES_ROOT — default ~/dev/pearcli/holepunch-repos/holepunchto_repos
* BARE_OS_HOLEPUNCH_LOCKFILE_DRIFT_TIER1_FAIL=1 — fail when a tier1 lockfile package
* has semverMismatchWithClone=true (uses docs/audit/holepunch-drift-repos.json tier1Repos)
*
* Config: docs/audit/holepunch-drift-repos.json
* lockfilePackages: [{ "cloneName": "protomux", "lockKey": "protomux" }, ...]
@@ -87,6 +89,24 @@ function loadLockfilePackages() {
return DEFAULT_LOCK_PACKAGES
}
/**
* @returns {Set<string>}
*/
function loadTier1RepoSet() {
if (!fs.existsSync(driftConfigPath)) return new Set()
try {
const j = JSON.parse(fs.readFileSync(driftConfigPath, 'utf8'))
if (!Array.isArray(j.tier1Repos)) return new Set()
return new Set(
j.tier1Repos
.map((v) => String(v || '').trim())
.filter(Boolean)
)
} catch {
return new Set()
}
}
function main() {
if (!fs.existsSync(lockPath)) {
console.error('report-holepunch-lockfile-drift: missing', lockPath)
@@ -94,6 +114,14 @@ function main() {
}
const lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'))
const pkgs = loadLockfilePackages()
const tier1Repos = loadTier1RepoSet()
const strictTier1Fail =
String(process.env.BARE_OS_HOLEPUNCH_LOCKFILE_DRIFT_TIER1_FAIL || '')
.trim()
.toLowerCase() === '1' ||
String(process.env.BARE_OS_HOLEPUNCH_LOCKFILE_DRIFT_TIER1_FAIL || '')
.trim()
.toLowerCase() === 'true'
const atMs = Date.now()
const rootExists = fs.existsSync(clonesRoot)
@@ -114,6 +142,7 @@ function main() {
}
const semverMismatch =
lv && cloneVersion && lv !== cloneVersion ? true : false
const tier1 = tier1Repos.has(cloneName)
rows.push({
cloneName,
lockKey,
@@ -121,9 +150,13 @@ function main() {
clonePath: cloneDir,
cloneExists: fs.existsSync(cloneDir),
clonePackageJsonVersion: cloneVersion || null,
semverMismatchWithClone: semverMismatch
semverMismatchWithClone: semverMismatch,
tier1
})
}
const tier1MismatchRows = rows.filter(
(r) => r.tier1 && r.semverMismatchWithClone
)
const report = {
schema: 1,
@@ -134,6 +167,8 @@ function main() {
driftConfigPath: path.relative(root, driftConfigPath),
note:
'lockfileVersion is the hoisted workspace entry in package-lock.json (lockfile v3). clonePackageJsonVersion is the local clones package.json when present; mismatch is informational until you bump npm deps or refresh clones.',
strictTier1Fail,
tier1MismatchCount: tier1MismatchRows.length,
rows
}
fs.mkdirSync(path.dirname(outJson), { recursive: true })
@@ -154,14 +189,15 @@ function main() {
'',
`_Generated at \`${new Date(atMs).toISOString()}\`. Regenerate with \`node scripts/report-holepunch-lockfile-drift.mjs\` (see [scripts/README.md](../../scripts/README.md))._`,
'',
'| Clone (package) | Lockfile version | Clone `package.json` version | Semver mismatch vs clone |',
'| --- | --- | --- | --- |'
'| Clone (package) | Tier1 | Lockfile version | Clone `package.json` version | Semver mismatch vs clone |',
'| --- | --- | --- | --- | --- |'
]
for (const r of rows) {
dashLines.push(
'| ' +
[
r.cloneName,
r.tier1 ? 'yes' : 'no',
r.lockfileVersion ?? '—',
r.clonePackageJsonVersion ?? '—',
r.semverMismatchWithClone ? 'yes' : 'no'
@@ -171,7 +207,11 @@ function main() {
}
dashLines.push(
'',
'**Note:** `lockfileVersion` is the hoisted workspace entry in `package-lock.json` (lockfile v3). `clonePackageJsonVersion` is the local mirrors `package.json` when present; a mismatch is informational until you bump npm deps or refresh clones.'
'**Note:** `lockfileVersion` is the hoisted workspace entry in `package-lock.json` (lockfile v3). `clonePackageJsonVersion` is the local mirrors `package.json` when present; mismatches are informational unless `BARE_OS_HOLEPUNCH_LOCKFILE_DRIFT_TIER1_FAIL=1`.',
'',
`**Tier1 strict mode:** ${strictTier1Fail ? 'enabled' : 'disabled'} · tier1 mismatches: ${tier1MismatchRows.length}.`,
'',
'**Upgrade workflow hint:** expected churn often appears first in `udx-native` and `blind-peering`; when they drift, refresh local clones, review lockfile bumps, then regenerate this dashboard and `holepunch-runtime-compat.json` together before release gating.'
)
fs.writeFileSync(dashPath, dashLines.join('\n') + '\n')
console.log(
@@ -180,6 +220,12 @@ function main() {
'packages=',
rows.length
)
if (strictTier1Fail && tier1MismatchRows.length) {
console.error(
`report-holepunch-lockfile-drift: tier1 mismatch strict mode failed (${tier1MismatchRows.length} mismatches)`
)
process.exit(1)
}
}
main()
+67 -117
View File
@@ -1,136 +1,86 @@
#!/usr/bin/env node
/**
* Validates ```mermaid fenced blocks in Markdown by rendering with @mermaid-js/mermaid-cli.
*
* - Skips unless `BARE_OS_VALIDATE_MERMAID=1` or `GITHUB_ACTIONS=true` (keeps local `pretest` fast).
* - Installs mermaid-cli once into a temp directory (requires network when not cached).
*
* Used by `.github/workflows/docs-mermaid-smoke.yml` (workflow_dispatch + weekly schedule).
*/
import { execFileSync, spawnSync } from 'node:child_process'
import fs from 'node:fs'
import path from 'node:path'
import os from 'node:os'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const bad = []
const SHOULD_RUN =
process.env.BARE_OS_VALIDATE_MERMAID === '1' || process.env.GITHUB_ACTIONS === 'true'
if (!SHOULD_RUN) {
console.log(
'validate-mermaid-syntax: skip (set BARE_OS_VALIDATE_MERMAID=1 or run in GitHub Actions)'
)
process.exit(0)
}
const GLOBS = ['docs', 'handbook', 'developer-guide', 'users-manual', 'scripts', 'packages']
const ROOT_MD = ['README.md', 'DOCUMENTATION.md']
const SKIP_FILES = new Set(['packages/bare-os-bare-libs/README.kernel-lib-bare.md'])
function isSkippedPath(relFromRoot) {
const norm = relFromRoot.split(path.sep).join('/')
return norm === 'packages/bare-os-seeder/kernel' || norm.startsWith('packages/bare-os-seeder/kernel/')
}
function walkMd(dir) {
const abs = path.join(root, dir)
if (!fs.existsSync(abs)) return []
/**
* @param {string} dir
* @returns {string[]}
*/
function walkMarkdown(dir) {
/** @type {string[]} */
const out = []
const st = fs.statSync(abs)
if (st.isFile() && abs.endsWith('.md')) {
out.push(abs)
return out
}
if (!st.isDirectory()) return out
for (const ent of fs.readdirSync(abs, { withFileTypes: true })) {
if (ent.name === 'node_modules' || ent.name === '.git') continue
const p = path.join(abs, ent.name)
const relFromRoot = p.slice(root.length + 1)
if (isSkippedPath(relFromRoot)) continue
if (ent.isDirectory()) out.push(...walkMd(relFromRoot))
else if (ent.isFile() && ent.name.endsWith('.md')) out.push(p)
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name)
const st = fs.statSync(p)
if (st.isDirectory()) out.push(...walkMarkdown(p))
else if (name.endsWith('.md')) out.push(p)
}
return out
}
/** @param {string} file */
function extractMermaidBlocks(file) {
const text = fs.readFileSync(file, 'utf8')
const re = /```mermaid\n([\s\S]*?)```/g
/** @type {string[]} */
/**
* @param {string} text
*/
function validateMermaidBlocks(text) {
/** @type {{ body: string, startLine: number }[]} */
const blocks = []
let m
while ((m = re.exec(text))) {
const body = m[1].trimEnd()
if (body.length) blocks.push(body)
const lines = text.split(/\r?\n/)
for (let i = 0; i < lines.length; i++) {
if (String(lines[i]).trim() !== '```mermaid') continue
const startLine = i + 1
let j = i + 1
while (j < lines.length && String(lines[j]).trim() !== '```') j++
if (j >= lines.length) {
bad.push(`unclosed mermaid code fence at line ${startLine}`)
break
}
const body = lines.slice(i + 1, j).join('\n').trim()
blocks.push({ body, startLine })
i = j
}
return blocks
}
/** @type {string[]} */
const files = []
for (const d of GLOBS) files.push(...walkMd(d))
for (const name of ROOT_MD) {
const p = path.join(root, name)
if (fs.existsSync(p)) files.push(p)
}
/** @type {{ file: string, index: number, body: string }[]} */
const diagrams = []
for (const file of files) {
const rel = path.relative(root, file)
if (SKIP_FILES.has(rel.split(path.sep).join('/'))) continue
const blocks = extractMermaidBlocks(file)
blocks.forEach((body, i) => diagrams.push({ file: rel, index: i, body }))
}
if (diagrams.length === 0) {
console.log('validate-mermaid-syntax: no mermaid blocks found')
process.exit(0)
}
const work = fs.mkdtempSync(path.join(os.tmpdir(), 'bare-os-mmdc-'))
const npmInstall = spawnSync(
'npm',
['install', '--no-fund', '--no-audit', '@mermaid-js/[email protected]'],
{ cwd: work, stdio: 'inherit', encoding: 'utf8' }
)
if (npmInstall.status !== 0) {
console.error('validate-mermaid-syntax: npm install mermaid-cli failed')
process.exit(1)
}
const mmdc = path.join(work, 'node_modules', '.bin', 'mmdc')
if (!fs.existsSync(mmdc)) {
console.error('validate-mermaid-syntax: mmdc not found after install')
process.exit(1)
}
let failed = 0
for (let i = 0; i < diagrams.length; i++) {
const { file, index, body } = diagrams[i]
const base = `diagram-${i}`
const input = path.join(work, `${base}.mmd`)
const output = path.join(work, `${base}.svg`)
fs.writeFileSync(input, `${body}\n`, 'utf8')
try {
execFileSync(mmdc, ['-i', input, '-o', output, '-b', 'transparent'], {
stdio: ['ignore', 'pipe', 'pipe'],
encoding: 'utf8',
})
} catch (e) {
failed++
const stderr = e instanceof Error && 'stderr' in e ? String(e.stderr) : String(e)
console.error(`\n--- Mermaid render failed: ${file} block #${index + 1} ---\n${stderr}`)
for (const b of blocks) {
if (!b.body) {
bad.push(`empty mermaid block at line ${b.startLine}`)
continue
}
const first = b.body.split(/\r?\n/, 1)[0].trim()
if (
!/^(graph|flowchart|sequenceDiagram|classDiagram|stateDiagram|erDiagram|journey|gantt|pie|mindmap|timeline)\b/.test(
first
)
) {
bad.push(
`invalid mermaid first line at ${b.startLine}: expected diagram type, got "${first}"`
)
}
}
}
if (failed > 0) {
console.error(`\nvalidate-mermaid-syntax: ${failed} of ${diagrams.length} diagram(s) failed`)
process.exit(1)
const mdFiles = [
...walkMarkdown(path.join(root, 'docs')),
...walkMarkdown(path.join(root, 'developer-guide')),
...walkMarkdown(path.join(root, 'handbook')),
...walkMarkdown(path.join(root, 'users-manual'))
]
for (const file of mdFiles) {
const raw = fs.readFileSync(file, 'utf8')
const before = bad.length
validateMermaidBlocks(raw)
if (bad.length > before) {
for (let i = before; i < bad.length; i++) {
bad[i] = `${path.relative(root, file)}: ${bad[i]}`
}
}
}
console.log(`validate-mermaid-syntax: OK (${diagrams.length} diagram(s))`)
if (bad.length) {
console.error('validate-mermaid-syntax: failed')
for (const b of bad) console.error(' ', b)
process.exit(1)
}
console.log('validate-mermaid-syntax: OK')
@@ -37,6 +37,16 @@ function main() {
)
process.exit(1)
}
if (
key !== 'extensionSignerPinsV5' &&
props[key]?.additionalProperties?.pattern !== '^[a-f0-9]{64}$'
) {
console.error(
'verify-boot-policy-extension-signer-pins: schema pattern drift',
key
)
process.exit(1)
}
}
/** @type {string[]} */
const chunks = []
+22
View File
@@ -24,6 +24,16 @@ function main() {
console.error('verify-bundle-health: bundle-health.json missing bundles[]')
process.exit(1)
}
const thresholdRows = Array.isArray(
health?.bundleRegressionThresholds?.byCtxKey
)
? health.bundleRegressionThresholds.byCtxKey
: []
const thresholdsByCtxKey = new Map(
thresholdRows
.filter((r) => r && typeof r === 'object' && typeof r.ctxKey === 'string')
.map((r) => [r.ctxKey, r])
)
const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'))
const mPaths = new Set(
@@ -58,6 +68,12 @@ function main() {
`size mismatch ${path.basename(rel)}: disk ${st.size} vs bundle-health ${want} (re-run npm run build -w bare-os-bare-libs)`
)
}
const thr = thresholdsByCtxKey.get(row.ctxKey)
if (thr && typeof thr.maxBytes === 'number' && st.size > thr.maxBytes) {
bad.push(
`bundle threshold exceeded ${row.ctxKey}: disk ${st.size} > max ${thr.maxBytes} (tier ${thr.tier || 'n/a'})`
)
}
}
if (fs.existsSync(bundlesDir)) {
@@ -84,6 +100,12 @@ function main() {
}
}
}
if (
health.bundleRegressionThresholds &&
!Array.isArray(health.bundleRegressionThresholds.byCtxKey)
) {
bad.push('bundleRegressionThresholds.byCtxKey missing or invalid')
}
if (bad.length) {
console.error('verify-bundle-health: failed')
+32
View File
@@ -92,6 +92,38 @@ function main() {
)
}
const posixMatrixRaw = read('docs/reference/posix-compliance-matrix.json')
const posixMatrix = JSON.parse(posixMatrixRaw)
const procTableSchema = Number(posixMatrix?.synthetic_proc?.process_table_schema)
const syscallsSchemaFromMatrix = Number(
posixMatrix?.synthetic_proc?.syscalls_json_schema
)
must(
Number.isFinite(procTableSchema) && procTableSchema > 0,
'posix-compliance-matrix.json missing synthetic_proc.process_table_schema'
)
must(
Number.isFinite(syscallsSchemaFromMatrix) && syscallsSchemaFromMatrix > 0,
'posix-compliance-matrix.json missing synthetic_proc.syscalls_json_schema'
)
must(
String(syscallsSchemaFromMatrix) === syscallSchema,
`posix-compliance-matrix syscalls_json_schema ${syscallsSchemaFromMatrix} !== proc builder ${syscallSchema}`
)
const handbookPosix = read('handbook/09-posix-utilities-shell-and-vfs.md')
must(
handbookPosix.includes(
'`/proc/bare_os/syscalls.json`** (schema **' + syscallsSchemaFromMatrix + '**'
),
`handbook/09-posix-utilities-shell-and-vfs.md must mention /proc/bare_os/syscalls.json schema ${syscallsSchemaFromMatrix}`
)
must(
handbookPosix.includes(
'`/proc/bare_os/process_table.json`** (**schema ' + procTableSchema + '**'
),
`handbook/09-posix-utilities-shell-and-vfs.md must mention /proc/bare_os/process_table.json schema ${procTableSchema}`
)
console.log('verify-doc-contracts: OK')
}
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env node
import { readFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const roadmapMdPath = path.join(root, 'docs', 'reference', 'feature-roadmap.md')
const canonicalPath = path.join(root, 'docs', 'data', 'feature-roadmap-canonical.json')
const roadmapMd = await readFile(roadmapMdPath, 'utf8')
await readFile(canonicalPath, 'utf8')
const expectedLink = '../data/feature-roadmap-canonical.json'
if (!roadmapMd.includes(expectedLink)) {
throw new Error(
`feature-roadmap.md must reference canonical JSON path: ${expectedLink}`
)
}
if (roadmapMd.includes('feature-roadmap-canonical.json](./')) {
throw new Error(
'feature-roadmap.md uses an inconsistent local canonical JSON path; use ../data/feature-roadmap-canonical.json'
)
}
console.log(
'[verify-feature-roadmap-paths] ok: feature-roadmap markdown references canonical JSON path'
)
@@ -63,9 +63,9 @@ function main() {
)
process.exit(1)
}
if (!bits.includes('BARE_OS_KERNEL_FEATURE_BITS_DOC = 16')) {
if (!bits.includes('BARE_OS_KERNEL_FEATURE_BITS_DOC = 17')) {
console.error(
'kernel-feature-bits.js: expected BARE_OS_KERNEL_FEATURE_BITS_DOC = 16'
'kernel-feature-bits.js: expected BARE_OS_KERNEL_FEATURE_BITS_DOC = 17'
)
process.exit(1)
}
@@ -0,0 +1,28 @@
#!/usr/bin/env node
import { readFile } from 'node:fs/promises'
import path from 'node:path'
import { fileURLToPath } from 'node:url'
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
const pkgPath = path.join(root, 'packages', 'bare-os-protocol', 'package.json')
const docPath = path.join(root, 'docs', 'reference', 'package-bare-os-protocol.md')
const pkg = JSON.parse(await readFile(pkgPath, 'utf8'))
const version = String(pkg.version || '').trim()
if (!/^\d+\.\d+\.\d+([-.][0-9A-Za-z.-]+)?$/.test(version)) {
throw new Error(`invalid bare-os-protocol package version: "${version}"`)
}
const doc = await readFile(docPath, 'utf8')
const matches = [...doc.matchAll(/\b\d+\.\d+\.\d+(?:[-.][0-9A-Za-z.-]+)?\b/g)].map(
(m) => m[0]
)
if (!matches.includes(version)) {
throw new Error(
`protocol doc version mismatch: docs/reference/package-bare-os-protocol.md missing ${version}`
)
}
console.log(
`[verify-protocol-doc-version-parity] ok: docs mention bare-os-protocol@${version}`
)