2577 lines
84 KiB
JavaScript
2577 lines
84 KiB
JavaScript
import {
|
|
test,
|
|
b4a,
|
|
Hyperdrive,
|
|
Corestore,
|
|
mkdirSync,
|
|
rmSync,
|
|
readFile,
|
|
readdir,
|
|
path,
|
|
fileURLToPath,
|
|
PassThrough,
|
|
XTERM_CLEAR_SCROLLBACK_AND_VIEWPORT,
|
|
runKernelFromSource,
|
|
runBinCommand,
|
|
createGitFsFromVfs,
|
|
runGitCli,
|
|
createStreamLineReader,
|
|
sanitizeInteractiveShellLine,
|
|
createVfs,
|
|
BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE,
|
|
parseHdmsPairArgv,
|
|
hcCrypto,
|
|
idEnc,
|
|
decodeRwShareOffer,
|
|
decodeShareOffer,
|
|
HDMS_AUTOPASS_SHARE_KEY,
|
|
HDMS_AUTOPASS_SHARE_RW_KEY,
|
|
normalizeWriterSecretHex,
|
|
buildBareOsHypercorePackHrpcLifecycleProcJson,
|
|
buildBareOsPearCorestoreHrpcProcJson,
|
|
buildBareOsPearInspectLoggerTlsProcJson,
|
|
buildBareOsBareRuntimeProtoMuxProcJson,
|
|
buildBareOsBootGraphProcJson,
|
|
pathnameExpandShellWord,
|
|
createBareOsIpc,
|
|
BareOsSwarmConnectionManager,
|
|
createBareOsLifecycleStateMachine,
|
|
runTransactionalLifecycleHooks,
|
|
bareOsRegisterCorestoreSuspendResumeHooks,
|
|
bareOsInstallCorestoreSuspendResumeHooks,
|
|
bareOsFindOrphanProcessRows,
|
|
topologicalOrderKernelExtensions,
|
|
resolveKernelExtensionsFull,
|
|
createBareOsProtomuxAliasRegistry,
|
|
bareOsHttpUrlAllowed,
|
|
bareOsParseBareAclText,
|
|
bareOsAclDeniesSubject,
|
|
raceWithAbortAndTimeout,
|
|
tokenize,
|
|
expandWord,
|
|
execShellLine,
|
|
expandArgvAliases,
|
|
defaultShellAliases,
|
|
loadBarerc,
|
|
BARERC_SKELETON,
|
|
splitTokensBySemicolon,
|
|
splitTokensByAndOr,
|
|
bareOsShellAstSnapshot,
|
|
planShellRedirections,
|
|
buildShellExecutionGraph,
|
|
dispatchShellTrapSignal,
|
|
BARE_OS_EXIT_STATUS_ENV,
|
|
syncBareOsExitStatusEnv,
|
|
getBareOsPipelineLimits,
|
|
DEFAULT_PIPELINE_MAX_STAGES,
|
|
tokenizeBareShellLineDetailed,
|
|
decodeBareOsDollarQuote,
|
|
applyBareOsThemeFromEnv,
|
|
bareOsListThemeNames,
|
|
bareParseLsColors,
|
|
bareSerializeLsColors,
|
|
bareLsColorOpenSgrFromMap,
|
|
bareDefaultDircolorsDatabase,
|
|
bareParseDircolorsDatabase,
|
|
BARE_OS_CTX_API_VERSION,
|
|
buildBareOsRuntimeCaps,
|
|
bareOsBareModulesEnabled,
|
|
bareOsBareModuleManifestEmbeddedRef,
|
|
buildBareCtxObjectFromHost,
|
|
buildPearCtxObjectFromHost,
|
|
loadBareModuleManifest,
|
|
maybeMergeBareFromDrive,
|
|
maybeBareOsBuildBinManifest,
|
|
createFishReadLine,
|
|
fuzzyMatch,
|
|
stripAnsi,
|
|
parseHistoryFile,
|
|
formatHistoryFile,
|
|
dedupeConsecutiveHistory,
|
|
searchHistoryEntries,
|
|
shouldPersistShellHistoryCommand,
|
|
scrubShellHistoryEntries,
|
|
SHELL_BUILTINS,
|
|
resolveShellPromptHookSegment,
|
|
parseCompletionContext,
|
|
rankCompletionItems,
|
|
suggestGhostFromHistory,
|
|
suggestGhostFromFs,
|
|
ghostReplaceCurrentWord,
|
|
longestCommonCompletionPrefix,
|
|
completeLine,
|
|
levenshtein,
|
|
fieldMatches,
|
|
dowFieldMatches,
|
|
parseCronLine,
|
|
jobMatchesDate,
|
|
bareInitdReadinessSnapshot,
|
|
bareInitdShutdownActiveUnitsReverse,
|
|
getBareServiceRuntime,
|
|
registerBareInitdDisposer,
|
|
registerKernelShutdownHook,
|
|
runKernelShutdownHooks,
|
|
startBareInitd,
|
|
stopBareInitd,
|
|
getLastBareInitdDagSnapshotJson,
|
|
appendVarLog,
|
|
ensureBareOsVarLogTree,
|
|
KERNEL_CONSOLE_LOG,
|
|
BOOT_LOG,
|
|
bareOsKernelMetricsReset,
|
|
bareOsKernelMetricsSnapshot,
|
|
parseUnitDropInText,
|
|
bareOsHyperswarmOptsFromEnv,
|
|
bareOsBootJoinPeerHexFromEnv,
|
|
bareOsBootInitPrefetchEnabled,
|
|
bareOsBootWarmBinDownloadDiffEnabled,
|
|
bareOsProcessTableSnapshot,
|
|
buildBareOsSyscallsProcJson,
|
|
bareOsParseSendmsgScmRights,
|
|
wantPosixSocketScmRights,
|
|
parseBareOsHrpcAllowlistJson,
|
|
bareOsHrpcAllowlistDeniesRoute,
|
|
buildBareOsProtomuxExtensionsProcJson,
|
|
createBareOsDiskOsBridge,
|
|
buildBareOsReplicationLiveSketch,
|
|
evaluateBareOsPeerAdmission,
|
|
bareOsFormatPeerAdmissionAuditEvent,
|
|
bareOsPeerAdmissionAuditRateAllow,
|
|
parseDelegateAllowSet,
|
|
isDelegateKindAllowed,
|
|
bareOsAuditAppend,
|
|
bareOsAuditVerifyRows,
|
|
bareOsDrainFcntlLockWaiters,
|
|
buildBareOsReplicationOperatorSurfaceProcJson,
|
|
DEFAULT_CURL_USER_AGENT,
|
|
DEFAULT_WGET_USER_AGENT,
|
|
filenameFromContentDisposition,
|
|
encodeUstarHeader,
|
|
runTarCli,
|
|
require,
|
|
__dirname,
|
|
TAR_BLK,
|
|
concatTarParts,
|
|
headerFromInit,
|
|
testCorestoreDir,
|
|
testCtx,
|
|
personalHomeBacking,
|
|
readBuiltBin
|
|
} from './test/_helpers.js'
|
|
|
|
test('vfs lstat personal file includes mode uid user mtime', async (t) => {
|
|
const dir = testCorestoreDir('lstatposix')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('lsp'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/user',
|
|
PWD: '/home/user',
|
|
PATH: '/bin',
|
|
USER: 'alice',
|
|
UID: '4242',
|
|
GID: '4242'
|
|
})
|
|
await vfs.writeFile('f', b4a.from('x'))
|
|
const st = await vfs.lstat('/home/user/f')
|
|
t.ok(st)
|
|
t.is(st.type, 'file')
|
|
t.is(st.user, 'alice')
|
|
t.is(st.uid, 4242)
|
|
t.ok((st.mode & 0o777) <= 0o777)
|
|
t.ok((st.mode & 0o100000) === 0o100000)
|
|
t.ok(typeof st.mtimeMs === 'number')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs syscalls.json uses schema 8 when provider wired', async (t) => {
|
|
const dir = testCorestoreDir('syscallsproc')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('scp'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const sample = {
|
|
schemaVersion: 8,
|
|
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
|
ops: ['readFile'],
|
|
errnoHints: { ENOENT: 2 },
|
|
fdModel: { schema: 1, stdio: [0, 1, 2] },
|
|
signalModel: { schema: 1, names: ['INT'] },
|
|
atMs: 0
|
|
}
|
|
const vfs = createVfs(
|
|
sys,
|
|
personal,
|
|
{ HOME: '/home/g', PWD: '/', PATH: '/bin' },
|
|
null,
|
|
{
|
|
procBareOsSyscallsText() {
|
|
return `${JSON.stringify(sample)}\n`
|
|
}
|
|
}
|
|
)
|
|
const buf = await vfs.readFile('/proc/bare_os/syscalls.json')
|
|
const j = JSON.parse(b4a.toString(buf))
|
|
t.is(j.schemaVersion, 8)
|
|
t.ok(j.fdModel && j.fdModel.schema === 1)
|
|
t.ok(j.signalModel && Array.isArray(j.signalModel.names))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /dev/shm named segment write read unlink roundtrip', async (t) => {
|
|
const dir = testCorestoreDir('devshm')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('shm'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin'
|
|
})
|
|
const names0 = (await vfs.readdir('/dev')).slice().sort()
|
|
t.ok(names0.includes('shm'))
|
|
await vfs.writeFile('/dev/shm/seg1', b4a.from('abc'))
|
|
const names1 = await vfs.readdir('/dev/shm')
|
|
t.ok(names1.includes('seg1'))
|
|
t.is(b4a.toString(await vfs.readFile('/dev/shm/seg1')), 'abc')
|
|
await vfs.unlink('/dev/shm/seg1')
|
|
const names2 = await vfs.readdir('/dev/shm')
|
|
t.absent(names2.includes('seg1'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /dev/shm enforces BARE_OS_SHM_MAX_BYTES quota', async (t) => {
|
|
const dir = testCorestoreDir('devshm-quota')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('shmquota'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
BARE_OS_SHM_MAX_BYTES: '4'
|
|
})
|
|
await vfs.writeFile('/dev/shm/seg1', b4a.from('abcd'))
|
|
await t.exception(async () => {
|
|
await vfs.writeFile('/dev/shm/seg2', b4a.from('e'))
|
|
})
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /dev/shm quota accounts for overwrite replacement size', async (t) => {
|
|
const dir = testCorestoreDir('devshm-quota-overwrite')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('shmquota2'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
BARE_OS_SHM_MAX_BYTES: '4'
|
|
})
|
|
await vfs.writeFile('/dev/shm/seg1', b4a.from('abcd'))
|
|
await vfs.writeFile('/dev/shm/seg1', b4a.from('ab'))
|
|
await vfs.writeFile('/dev/shm/seg2', b4a.from('cd'))
|
|
t.is(b4a.toString(await vfs.readFile('/dev/shm/seg2')), 'cd')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('/proc/bare_os/index.json has stable schema and sorted entry names', async (t) => {
|
|
const dir = testCorestoreDir('proc-index-schema-sort')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('procindex'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin'
|
|
})
|
|
|
|
const raw = await vfs.readFile('/proc/bare_os/index.json')
|
|
const idx = JSON.parse(b4a.toString(raw))
|
|
t.is(idx.schema, 10)
|
|
t.ok(Array.isArray(idx.entries))
|
|
|
|
const names = idx.entries.map((e) => String(e?.name || ''))
|
|
const sorted = [...names].sort((a, b) => a.localeCompare(b))
|
|
t.alike(names, sorted, 'proc alias names stay lexicographically sorted')
|
|
t.is(new Set(names).size, names.length, 'proc alias names remain unique')
|
|
|
|
for (const required of [
|
|
'hyperdb_readonly_index.json',
|
|
'pear_sidecar_bundle_index.json',
|
|
'hyperdrive_sparse_index.json',
|
|
'indexer_catchup.json',
|
|
'multisig_quorum_pointer.json',
|
|
'wave11_operator_slo_v2.json'
|
|
]) {
|
|
const row = idx.entries.find((e) => e?.name === required)
|
|
t.ok(row, `index entry present: ${required}`)
|
|
t.is(row.path, `/proc/bare_os/${required}`)
|
|
}
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /bin warm read cache hit then bareOsClearWarmReadCaches resets', async (t) => {
|
|
const dir = testCorestoreDir('warmcache')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('wc'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await sys.put('/bin/warmX', b4a.from('payload'))
|
|
const warmRef = { current: null }
|
|
const env = {
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
BARE_OS_VFS_BIN_CACHE: '1'
|
|
}
|
|
const vfs = createVfs(sys, personal, env, null, {
|
|
warmReadCacheStatsRef: warmRef
|
|
})
|
|
await vfs.readFile('/bin/warmX')
|
|
const h0 = warmRef.current?.hits ?? 0
|
|
await vfs.readFile('/bin/warmX')
|
|
t.ok((warmRef.current?.hits ?? 0) > h0, 'second read should warm-hit')
|
|
vfs.bareOsClearWarmReadCaches()
|
|
t.is(warmRef.current?.hits, 0)
|
|
t.is(warmRef.current?.misses, 0)
|
|
await vfs.readFile('/bin/warmX')
|
|
t.ok((warmRef.current?.misses ?? 0) >= 1, 'after clear, read counts as miss again')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs warm cache invalidates /bin entries on replication-length prefix eviction', async (t) => {
|
|
const dir = testCorestoreDir('warmcache-repl-prefix')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('wcrp'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await sys.put('/bin/replA', b4a.from('v1'))
|
|
/** @type {{ current: any }} */
|
|
const warmRef = { current: null }
|
|
const vfs = createVfs(
|
|
sys,
|
|
personal,
|
|
{
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
BARE_OS_VFS_BIN_CACHE: '1'
|
|
},
|
|
null,
|
|
{ warmReadCacheStatsRef: warmRef }
|
|
)
|
|
|
|
await vfs.readFile('/bin/replA') // miss
|
|
const h0 = warmRef.current?.hits ?? 0
|
|
await vfs.readFile('/bin/replA') // hit
|
|
t.ok((warmRef.current?.hits ?? 0) > h0)
|
|
|
|
const evicted = vfs.bareOsEvictWarmReadPrefixes(['/bin/'])
|
|
t.ok(evicted >= 1, 'replication prefix eviction removes warm /bin row(s)')
|
|
t.ok(warmRef.current?.replicationPrefixEviction)
|
|
t.ok((warmRef.current?.replicationPrefixEviction?.pathsEvicted ?? 0) >= 1)
|
|
|
|
const missBefore = warmRef.current?.misses ?? 0
|
|
await vfs.readFile('/bin/replA') // miss again after eviction
|
|
t.ok((warmRef.current?.misses ?? 0) > missBefore)
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs warm cache replication prefix eviction is selective', async (t) => {
|
|
const dir = testCorestoreDir('warmcache-repl-selective')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('wcrs'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await sys.put('/bin/replB', b4a.from('bin-v1'))
|
|
await sys.put('/lib/bare/bundles/replBundle.js', b4a.from('bundle-v1'))
|
|
/** @type {{ current: any }} */
|
|
const warmRef = { current: null }
|
|
const vfs = createVfs(
|
|
sys,
|
|
personal,
|
|
{
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
BARE_OS_VFS_BIN_CACHE: '1',
|
|
BARE_OS_VFS_LIB_BARE_CACHE: '1'
|
|
},
|
|
null,
|
|
{ warmReadCacheStatsRef: warmRef }
|
|
)
|
|
|
|
await vfs.readFile('/bin/replB')
|
|
await vfs.readFile('/lib/bare/bundles/replBundle.js')
|
|
const hits0 = warmRef.current?.hits ?? 0
|
|
await vfs.readFile('/bin/replB')
|
|
await vfs.readFile('/lib/bare/bundles/replBundle.js')
|
|
t.ok((warmRef.current?.hits ?? 0) > hits0)
|
|
|
|
const evicted = vfs.bareOsEvictWarmReadPrefixes(['/bin/'])
|
|
t.ok(evicted >= 1)
|
|
|
|
const missesBefore = warmRef.current?.misses ?? 0
|
|
await vfs.readFile('/bin/replB') // should miss
|
|
const missesAfterBin = warmRef.current?.misses ?? 0
|
|
t.ok(missesAfterBin > missesBefore)
|
|
await vfs.readFile('/lib/bare/bundles/replBundle.js') // still warm-hit
|
|
t.ok((warmRef.current?.hits ?? 0) > hits0)
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs writeFile on system /bin evicts warm-cache row for that path', async (t) => {
|
|
const dir = testCorestoreDir('warmcachewrite')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('wcw'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await sys.put('/bin/warmW', b4a.from('v1'))
|
|
const warmRef = { current: null }
|
|
const env = {
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
BARE_OS_VFS_BIN_CACHE: '1',
|
|
BARE_OS_VFS_SYSTEM_IMAGE_WRITE: '1'
|
|
}
|
|
const vfs = createVfs(sys, personal, env, null, {
|
|
warmReadCacheStatsRef: warmRef
|
|
})
|
|
t.is(b4a.toString(await vfs.readFile('/bin/warmW')), 'v1')
|
|
const hitsAfterFirst = warmRef.current?.hits ?? 0
|
|
t.is(b4a.toString(await vfs.readFile('/bin/warmW')), 'v1')
|
|
t.ok((warmRef.current?.hits ?? 0) > hitsAfterFirst)
|
|
await vfs.writeFile('/bin/warmW', b4a.from('v2'))
|
|
t.is(b4a.toString(await vfs.readFile('/bin/warmW')), 'v2')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs bareOsEvictLibBareBundlesFromManifest evicts only listed bundle paths', async (t) => {
|
|
const dir = testCorestoreDir('manifestevict')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('me'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await sys.put('/lib/bare/bundles/b4a.js', b4a.from('b4a'))
|
|
await sys.put('/lib/bare/bundles/safetyCatch.js', b4a.from('sc'))
|
|
const warmRef = { current: null }
|
|
const env = {
|
|
HOME: '/home/g',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
BARE_OS_VFS_BIN_CACHE: '1',
|
|
BARE_OS_VFS_LIB_BARE_CACHE: '1'
|
|
}
|
|
const vfs = createVfs(sys, personal, env, null, {
|
|
warmReadCacheStatsRef: warmRef
|
|
})
|
|
await vfs.readFile('/lib/bare/bundles/b4a.js')
|
|
await vfs.readFile('/lib/bare/bundles/safetyCatch.js')
|
|
const hitsBefore = warmRef.current?.hits ?? 0
|
|
await vfs.readFile('/lib/bare/bundles/b4a.js')
|
|
t.ok((warmRef.current?.hits ?? 0) > hitsBefore)
|
|
const manifest = JSON.stringify({
|
|
version: 1,
|
|
entries: [
|
|
{ ctxKey: 'b4a', package: 'b4a', bundle: true },
|
|
{ ctxKey: 'xOther', package: 'x', bundle: false }
|
|
]
|
|
})
|
|
vfs.bareOsEvictLibBareBundlesFromManifest(b4a.from(manifest))
|
|
const missesAfterEvict = warmRef.current?.misses ?? 0
|
|
await vfs.readFile('/lib/bare/bundles/b4a.js')
|
|
t.ok(
|
|
(warmRef.current?.misses ?? 0) > missesAfterEvict,
|
|
'b4a should miss after selective evict'
|
|
)
|
|
const hitsSc = warmRef.current?.hits ?? 0
|
|
await vfs.readFile('/lib/bare/bundles/safetyCatch.js')
|
|
t.ok(
|
|
(warmRef.current?.hits ?? 0) > hitsSc,
|
|
'safetyCatch still served from warm cache'
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('blind relay / pairing / geo proc JSON operator-redacted without BARE_OS_PROC_BLIND_PEER_RELAY_HINTS', async (t) => {
|
|
const a = buildBareOsPearCorestoreHrpcProcJson('blind_relay_router', {})
|
|
t.is(a.exposed, false)
|
|
t.is(a.operatorRedacted, true)
|
|
const b = buildBareOsPearInspectLoggerTlsProcJson('blind_pairing_sketch', {})
|
|
t.is(b.exposed, false)
|
|
t.is(b.operatorRedacted, true)
|
|
const c = buildBareOsHypercorePackHrpcLifecycleProcJson('relay_geo_hint', {})
|
|
t.is(c.exposed, false)
|
|
t.is(c.operatorRedacted, true)
|
|
const { buildBareOsBlindRelaySwarmRuntime } = await import(
|
|
'./lib/proc/bare-os-proc-blind-peer-relay-gate.js'
|
|
)
|
|
const rt = {
|
|
swarm: buildBareOsBlindRelaySwarmRuntime(
|
|
{ BARE_OS_SWARM_PROTOMUX_BACKPRESSURE_COUNT: '3' },
|
|
[{ id: 'a' }, { id: 'b' }],
|
|
{
|
|
hasSystemDrive: true,
|
|
hasPersonalDrive: true,
|
|
auxiliaryDriveCount: 0
|
|
}
|
|
)
|
|
}
|
|
t.is(rt.swarm.schema, 3)
|
|
t.ok(rt.swarm.blindPeerStack)
|
|
t.is(rt.swarm.replicationSurfaces?.systemDriveOpen, true)
|
|
const on = buildBareOsPearCorestoreHrpcProcJson(
|
|
'blind_relay_router',
|
|
{
|
|
BARE_OS_PROC_BLIND_PEER_RELAY_HINTS: '1',
|
|
BARE_OS_BLIND_RELAY_ROUTER_JSON: '{"lanes":1}',
|
|
BARE_OS_SWARM_PROTOMUX_BACKPRESSURE_COUNT: '3'
|
|
},
|
|
rt
|
|
)
|
|
t.is(on.schema, 2)
|
|
t.is(on.exposed, true)
|
|
t.ok(on.router && typeof on.router === 'object')
|
|
t.is(on.swarm?.peerCount, 2)
|
|
t.is(on.swarm?.relayGeoTier, 'multi_peer')
|
|
t.is(on.swarm?.protomuxBackpressure?.schema, 1)
|
|
t.is(on.swarm?.protomuxBackpressure?.emitCountEstimate, 3)
|
|
const pair = buildBareOsPearInspectLoggerTlsProcJson(
|
|
'blind_pairing_sketch',
|
|
{ BARE_OS_PROC_BLIND_PEER_RELAY_HINTS: 'yes' },
|
|
rt
|
|
)
|
|
t.is(pair.schema, 2)
|
|
t.is(pair.swarm?.pairingSurfaceReady, true)
|
|
const geo = buildBareOsHypercorePackHrpcLifecycleProcJson(
|
|
'relay_geo_hint',
|
|
{ BARE_OS_PROC_BLIND_PEER_RELAY_HINTS: 'true' },
|
|
rt
|
|
)
|
|
t.is(geo.schema, 2)
|
|
t.ok(geo.regions == null)
|
|
t.is(geo.swarm?.relayGeoTier, 'multi_peer')
|
|
})
|
|
|
|
test('pear_runtime_channel proc JSON surfaces env hints', async (t) => {
|
|
const j = buildBareOsPearCorestoreHrpcProcJson('pear_runtime_channel', {
|
|
BARE_OS_PEAR_RUNTIME_CHANNEL: 'dev',
|
|
BARE_OS_PEAR_RUNTIME_STAGE: '2',
|
|
BARE_OS_PEAR_INSPECTOR_ATTACH_HINT: 'off',
|
|
BARE_OS_PEAR_RUNTIME_SNAPSHOT_JSON: '{"schema":1,"ok":true}'
|
|
})
|
|
t.is(j.schema, 1)
|
|
t.is(j.channel, 'dev')
|
|
t.is(j.stage, '2')
|
|
t.is(j.inspectorAttachHint, 'off')
|
|
t.ok(j.snapshot && typeof j.snapshot === 'object')
|
|
})
|
|
|
|
test('protomux_extensions proc JSON gated by BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY', async (t) => {
|
|
const off = buildBareOsProtomuxExtensionsProcJson({ env: {} })
|
|
t.is(off.exposed, false)
|
|
const on = buildBareOsProtomuxExtensionsProcJson({
|
|
env: { BARE_OS_PROC_PROTOMUX_EXTENSIONS_REGISTRY: '1' },
|
|
registrySnapshot: { aliases: {}, schema: 1 },
|
|
ctxApiVersion: BARE_OS_CTX_API_VERSION
|
|
})
|
|
t.is(on.exposed, true)
|
|
t.is(on.schemaVersion, 4)
|
|
t.is(on.muxWireMajor, 3)
|
|
t.ok(Array.isArray(on.extensionLogicalChannels))
|
|
})
|
|
|
|
test('buildBareOsReplicationLiveSketch reads hyperdrive core lengths', async (t) => {
|
|
const dir = testCorestoreDir('replive-sketch')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('rls'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
const sk0 = buildBareOsReplicationLiveSketch(
|
|
{ drive, personalDrive: personal, auxiliaryDrives: [personal] },
|
|
0
|
|
)
|
|
t.is(sk0.schema, 4)
|
|
t.is(sk0.auxiliaryDriveCount, 1)
|
|
t.is(sk0.stallHint, 'no_peers')
|
|
t.ok(sk0.corestoreSnapshotSurface)
|
|
t.ok(typeof sk0.systemCoreLength === 'number')
|
|
const sk1 = buildBareOsReplicationLiveSketch(
|
|
{ drive, personalDrive: personal },
|
|
1
|
|
)
|
|
t.is(sk1.schema, 4)
|
|
t.is(sk1.auxiliaryDriveCount, 0)
|
|
t.is(sk1.stallHint, 'ok')
|
|
const sk2 = buildBareOsReplicationLiveSketch(
|
|
{ drive: { core: {} }, personalDrive: null },
|
|
2
|
|
)
|
|
t.is(sk2.stallHint, 'length_unavailable')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('buildBareOsReplicationLiveSketch exposes monitor progress when available', async (t) => {
|
|
const sk = buildBareOsReplicationLiveSketch(
|
|
{
|
|
drive: {
|
|
core: { length: 10 },
|
|
monitor() {
|
|
return { downloadedBlocks: 12, uploadedBlocks: 4, peers: 2 }
|
|
}
|
|
},
|
|
personalDrive: { core: { length: 3 } }
|
|
},
|
|
2
|
|
)
|
|
t.is(sk.schema, 4)
|
|
t.is(sk.monitorProgress?.schema, 1)
|
|
t.is(sk.monitorProgress?.download, 12)
|
|
t.is(sk.monitorProgress?.upload, 4)
|
|
})
|
|
|
|
test('audit chain tamper detection catches modified payload row', async (t) => {
|
|
const rows = []
|
|
const push = (payload) => {
|
|
const { entryHash } = bareOsAuditAppend(payload)
|
|
rows.push({ payload, entryHash })
|
|
}
|
|
push({ type: 'boot', ok: true })
|
|
push({ type: 'vault_save', fileCount: 2 })
|
|
t.ok(bareOsAuditVerifyRows(rows).ok)
|
|
const tampered = rows.map((r) => ({ ...r, payload: { ...r.payload } }))
|
|
tampered[1].payload.fileCount = 3
|
|
const bad = bareOsAuditVerifyRows(tampered)
|
|
t.absent(bad.ok)
|
|
t.is(bad.badIndex, 1)
|
|
})
|
|
|
|
test('protomux_rpc_pool_health proc uses schema 2 and backpressure correlation fields', async (t) => {
|
|
const j = buildBareOsBareRuntimeProtoMuxProcJson('protomux_rpc_pool_health', {
|
|
BARE_OS_PROTOMUX_RPC_POOL_HEALTH_JSON: '{"ok":true}',
|
|
BARE_OS_REPLICATION_BACKPRESSURE_JSON: '{"depth":1}',
|
|
BARE_OS_LAST_PROTOMUX_BACKPRESSURE_MS: '99'
|
|
})
|
|
t.is(j.schema, 2)
|
|
t.ok(j.health)
|
|
t.ok(j.replicationBackpressure)
|
|
t.is(j.lastProtomuxBackpressureMs, 99)
|
|
})
|
|
|
|
test('protomux_rpc_pool_health echoes seed pool hint and wire correlate when env health absent', async (t) => {
|
|
const j = buildBareOsBareRuntimeProtoMuxProcJson(
|
|
'protomux_rpc_pool_health',
|
|
{},
|
|
{
|
|
seedProtomuxRpcPoolHint: { schema: 1, depth: 2 },
|
|
protomuxWireCorrelate: {
|
|
schema: 1,
|
|
peerMuxSessions: 3,
|
|
backpressureEmitCount: 5,
|
|
aliasPairCount: 1,
|
|
bareOsV1WireMessageKinds: 7
|
|
}
|
|
}
|
|
)
|
|
t.is(j.schema, 2)
|
|
t.is(j.health, null)
|
|
t.is(j.seedProtomuxRpcPoolHintEcho?.depth, 2)
|
|
t.is(j.protomuxWireCorrelate?.peerMuxSessions, 3)
|
|
t.is(j.protomuxWireCorrelate?.backpressureEmitCount, 5)
|
|
})
|
|
|
|
test('protomux_channels proc includes wireShapeSummary from runtime hints', async (t) => {
|
|
const j = buildBareOsPearCorestoreHrpcProcJson(
|
|
'protomux_channels',
|
|
{},
|
|
{
|
|
protomuxWireShape: {
|
|
schema: 1,
|
|
bareOsV1MessageKinds: ['read', 'rpc_req'],
|
|
peerMuxSessions: 2
|
|
}
|
|
}
|
|
)
|
|
t.is(j.schema, 1)
|
|
t.is(j.wireShapeSummary?.peerMuxSessions, 2)
|
|
t.ok(Array.isArray(j.wireShapeSummary?.bareOsV1MessageKinds))
|
|
})
|
|
|
|
test('pathnameExpandShellWord caps matches with BARE_OS_GLOB_MAX_MATCHES', async (t) => {
|
|
const names = ['f0', 'f1', 'f2', 'f3', 'f4']
|
|
const vfs = {
|
|
getcwd: () => '/tmp',
|
|
async readdir(d) {
|
|
if (d === '/tmp') return names.slice()
|
|
return []
|
|
},
|
|
async stat(p) {
|
|
if (p === '/tmp') return { type: 'directory' }
|
|
const base = p.replace(/^.*\//, '')
|
|
if (names.includes(base)) return { type: 'file' }
|
|
throw new Error('ENOENT')
|
|
}
|
|
}
|
|
const ctx = { vfs }
|
|
const parts = [{ q: 'u', t: '/tmp/f*' }]
|
|
const out = await pathnameExpandShellWord(ctx, parts, {
|
|
BARE_OS_GLOB_MAX_MATCHES: '2'
|
|
})
|
|
t.is(out.length, 2)
|
|
t.is(out[0], '/tmp/f0')
|
|
t.is(out[1], '/tmp/f1')
|
|
})
|
|
|
|
test('pathnameExpandShellWord supports globstar when enabled', async (t) => {
|
|
const files = new Set(['/tmp/a/f.txt', '/tmp/a/b/f.txt', '/tmp/a/b/c/f.txt'])
|
|
const dirs = new Set(['/tmp', '/tmp/a', '/tmp/a/b', '/tmp/a/b/c'])
|
|
const dirMap = new Map([
|
|
['/tmp', ['a']],
|
|
['/tmp/a', ['b', 'f.txt']],
|
|
['/tmp/a/b', ['c', 'f.txt']],
|
|
['/tmp/a/b/c', ['f.txt']]
|
|
])
|
|
const vfs = {
|
|
getcwd: () => '/tmp',
|
|
async readdir(d) {
|
|
return (dirMap.get(d) || []).slice()
|
|
},
|
|
async stat(p) {
|
|
if (dirs.has(p)) return { type: 'directory' }
|
|
if (files.has(p)) return { type: 'file' }
|
|
throw new Error('ENOENT')
|
|
}
|
|
}
|
|
const ctx = { vfs }
|
|
const parts = [{ q: 'u', t: '/tmp/**/f.txt' }]
|
|
const out = await pathnameExpandShellWord(ctx, parts, {
|
|
BARE_OS_GLOBSTAR: '1'
|
|
})
|
|
t.is(out.length, 4)
|
|
t.is(out[0], '/tmp/f.txt')
|
|
t.is(out[1], '/tmp/a/f.txt')
|
|
t.is(out[2], '/tmp/a/b/f.txt')
|
|
t.is(out[3], '/tmp/a/b/c/f.txt')
|
|
})
|
|
|
|
test('pathnameExpandShellWord keeps globstar literal by default', async (t) => {
|
|
const vfs = {
|
|
getcwd: () => '/tmp',
|
|
async readdir() {
|
|
return []
|
|
},
|
|
async stat() {
|
|
throw new Error('ENOENT')
|
|
}
|
|
}
|
|
const ctx = { vfs }
|
|
const parts = [{ q: 'u', t: '/tmp/**/f.txt' }]
|
|
const out = await pathnameExpandShellWord(ctx, parts, {})
|
|
t.is(out.length, 1)
|
|
t.is(out[0], '/tmp/**/f.txt')
|
|
})
|
|
|
|
test('pathnameExpandShellWord skips brace expansion when Cartesian product exceeds cap', async (t) => {
|
|
const vfs = {
|
|
getcwd: () => '/tmp',
|
|
async readdir() {
|
|
return []
|
|
},
|
|
async stat() {
|
|
throw new Error('ENOENT')
|
|
}
|
|
}
|
|
const ctx = { vfs }
|
|
const parts = [{ q: 'u', t: '/tmp/{a,b,c}' }]
|
|
const out = await pathnameExpandShellWord(ctx, parts, {
|
|
BARE_OS_SHELL_BRACE_EXPANSION: '1',
|
|
BARE_OS_SHELL_BRACE_EXPANSION_MAX: '2'
|
|
})
|
|
t.is(out.length, 1)
|
|
t.is(out[0], '/tmp/{a,b,c}')
|
|
})
|
|
|
|
test('pathnameExpandShellWord expands ~login using HOME or /home/login', async (t) => {
|
|
const vfs = {
|
|
getcwd: () => '/tmp',
|
|
async readdir() {
|
|
return []
|
|
},
|
|
async stat() {
|
|
throw new Error('ENOENT')
|
|
}
|
|
}
|
|
const ctx = { vfs }
|
|
let out = await pathnameExpandShellWord(ctx, [{ q: 'u', t: '~zed' }], {
|
|
USER: 'alice',
|
|
HOME: '/home/alice'
|
|
})
|
|
t.is(out[0], '/home/zed')
|
|
out = await pathnameExpandShellWord(ctx, [{ q: 'u', t: '~alice' }], {
|
|
USER: 'alice',
|
|
HOME: '/home/alice'
|
|
})
|
|
t.is(out[0], '/home/alice')
|
|
out = await pathnameExpandShellWord(ctx, [{ q: 'u', t: '~alice/sub' }], {
|
|
USER: 'alice',
|
|
HOME: '/custom/a'
|
|
})
|
|
t.is(out[0], '/custom/a/sub')
|
|
})
|
|
|
|
test('buildBareOsSyscallsProcJson exposes posixLike fd mapping', async (t) => {
|
|
const j = buildBareOsSyscallsProcJson({ ctxApiVersion: BARE_OS_CTX_API_VERSION })
|
|
t.is(j.schemaVersion, 11)
|
|
const openRow = j.opsDetail.find((r) => r.name === 'open')
|
|
t.ok(openRow && Array.isArray(openRow.susv4Refs))
|
|
t.ok(openRow.susv4Refs.includes('XSH/open'))
|
|
t.ok(j.ops.includes('clock_gettime'))
|
|
t.ok(j.posixXsh.namesCsv.includes('clock_gettime'))
|
|
t.ok(j.fdModel && j.fdModel.posixLike && j.fdModel.posixLike.pipe)
|
|
t.ok(j.fdModel.posixLike.read && j.fdModel.posixLike.write)
|
|
t.ok(j.fdModel.posixLike.fcntl)
|
|
t.ok(j.fdModel.posixLike.poll)
|
|
t.ok(j.fdModel.posixLike.socketFamily)
|
|
t.ok(j.posixXsh && j.posixXsh.schema === 3 && j.posixXsh.namesCsv.includes('open'))
|
|
t.ok(j.posixXsh.namesCsv.includes('poll'))
|
|
t.ok(j.posixXsh.namesCsv.includes('select'))
|
|
t.ok(j.posixXsh.namesCsv.includes('umask'))
|
|
t.ok(j.posixXsh.namesCsv.includes('readv'))
|
|
t.ok(j.posixXsh.namesCsv.includes('writev'))
|
|
t.ok(j.posixXsh.namesCsv.includes('socket'))
|
|
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, 6)
|
|
t.is(j.socketMsgSurface?.logicalScmRightsOnSend?.syscallResultField, 'scmRightsLocalDup')
|
|
t.is(j.socketMsgSurface?.ancillaryControl?.supported, false)
|
|
t.is(j.socketMsgSurface?.ancillaryControl?.errno, 'ENOTSUP')
|
|
t.ok(Array.isArray(j.socketMsgSurface?.ancillaryControl?.rejectKeys))
|
|
const xsh = j.opsDetail.filter((r) => r.posixAlignment)
|
|
t.ok(xsh.length >= 10)
|
|
})
|
|
|
|
test('boot graph labels stay in sync with kernel init bootTimed labels', async (t) => {
|
|
const src = await readFile(path.join(__dirname, '../../kernel/init.js'), 'utf8')
|
|
const rx = /bootTimed\(\s*ctx,\s*'([^']+)'/g
|
|
/** @type {string[]} */
|
|
const timed = []
|
|
for (const m of src.matchAll(rx)) timed.push(String(m[1]))
|
|
const kernelLabels = ['boot.policy', ...timed]
|
|
const graph = buildBareOsBootGraphProcJson()
|
|
const graphLabels = Array.isArray(graph.nodes)
|
|
? graph.nodes.map((n) => String(n && n.id))
|
|
: []
|
|
t.alike(
|
|
graphLabels,
|
|
kernelLabels,
|
|
'boot graph node ids must match kernel/init.js bootTimed labels'
|
|
)
|
|
})
|
|
|
|
test('bareOsParseSendmsgScmRights binary control rejects', async (t) => {
|
|
const r = bareOsParseSendmsgScmRights(
|
|
{ control: new Uint8Array([1]) },
|
|
true,
|
|
4
|
|
)
|
|
t.is(r.ok, false)
|
|
t.is(/** @type {{ reject: string }} */ (r).reject, 'control')
|
|
})
|
|
|
|
test('bareOsParseSendmsgScmRights scm off rejects non-empty fds', async (t) => {
|
|
const r = bareOsParseSendmsgScmRights({ cmsgs: [{ fds: [3] }] }, false, 4)
|
|
t.is(r.ok, false)
|
|
})
|
|
|
|
test('bareOsParseSendmsgScmRights scm on collects fds', async (t) => {
|
|
const r = bareOsParseSendmsgScmRights({ cmsgs: [{ fds: [3, 4] }] }, true, 4)
|
|
t.is(r.ok, true)
|
|
t.is(/** @type {{ fds: number[] }} */ (r).fds.length, 2)
|
|
})
|
|
|
|
test('wantPosixSocketScmRights env', async (t) => {
|
|
t.absent(wantPosixSocketScmRights({}))
|
|
t.ok(wantPosixSocketScmRights({ BARE_OS_POSIX_SOCKET_SCM_RIGHTS: '1' }))
|
|
})
|
|
|
|
test('maybeBareOsBuildBinManifest writes schema 2 with namesDigest', async (t) => {
|
|
/** @type {{ path: string, text: string }[]} */
|
|
const writes = []
|
|
const ctx = {
|
|
env: { BARE_OS_VFS_BIN_INDEX_BUILD: '1' },
|
|
vfs: {
|
|
writeFile: async (p, buf) => {
|
|
writes.push({
|
|
path: String(p),
|
|
text: b4a.toString(buf)
|
|
})
|
|
}
|
|
},
|
|
drive: {
|
|
async *readdir() {
|
|
yield 'b'
|
|
yield 'a'
|
|
}
|
|
},
|
|
b4a,
|
|
console: {}
|
|
}
|
|
await maybeBareOsBuildBinManifest(ctx)
|
|
t.is(writes.length, 1)
|
|
t.is(writes[0].path, '/.bare-os/index/bin-manifest.json')
|
|
const j = JSON.parse(writes[0].text)
|
|
t.is(j.schema, 2)
|
|
t.ok(typeof j.namesDigest === 'string' && j.namesDigest.length === 64)
|
|
t.is(j.names[0], 'a')
|
|
t.is(j.names[1], 'b')
|
|
})
|
|
|
|
test('parseBareOsHrpcAllowlistJson + bareOsHrpcAllowlistDeniesRoute', async (t) => {
|
|
t.is(parseBareOsHrpcAllowlistJson('').allow, null)
|
|
t.is(parseBareOsHrpcAllowlistJson(' ').allow, null)
|
|
const a1 = parseBareOsHrpcAllowlistJson('["kernel.ping"]')
|
|
t.ok(a1.allow && a1.allow.has('kernel.ping'))
|
|
t.ok(bareOsHrpcAllowlistDeniesRoute(a1.allow, 'kernel', 'capabilities'))
|
|
t.absent(bareOsHrpcAllowlistDeniesRoute(a1.allow, 'kernel', 'ping'))
|
|
const a2 = parseBareOsHrpcAllowlistJson('{"kernel.ping":true}')
|
|
t.ok(a2.allow && a2.allow.has('kernel.ping'))
|
|
const a3 = parseBareOsHrpcAllowlistJson('{"*":true}')
|
|
t.ok(a3.allow && a3.allow.has('*'))
|
|
t.absent(bareOsHrpcAllowlistDeniesRoute(a3.allow, 'vfs', 'readText'))
|
|
const a4 = parseBareOsHrpcAllowlistJson('{"kernel.*":true}')
|
|
t.absent(bareOsHrpcAllowlistDeniesRoute(a4.allow, 'kernel', 'capabilities'))
|
|
t.ok(bareOsHrpcAllowlistDeniesRoute(a4.allow, 'vfs', 'readText'))
|
|
t.ok(parseBareOsHrpcAllowlistJson('{').parseError)
|
|
t.ok(parseBareOsHrpcAllowlistJson('null').allow === null)
|
|
t.ok(!parseBareOsHrpcAllowlistJson('null').parseError)
|
|
t.ok(parseBareOsHrpcAllowlistJson('"x"').allow === null)
|
|
const dup = parseBareOsHrpcAllowlistJson('["a.b","a.b","c.d"]')
|
|
t.is(dup.allow?.size, 2)
|
|
const emptyArr = parseBareOsHrpcAllowlistJson('[]')
|
|
t.is(emptyArr.allow, null)
|
|
t.ok(!emptyArr.parseError)
|
|
const emptyObj = parseBareOsHrpcAllowlistJson('{}')
|
|
t.is(emptyObj.allow, null)
|
|
})
|
|
|
|
test('hyper_multisig_trust_pointer proc schema 2 merges vault multisig continuity JSON', async (t) => {
|
|
const j = buildBareOsBareRuntimeProtoMuxProcJson(
|
|
'hyper_multisig_trust_pointer',
|
|
{
|
|
BARE_OS_VAULT_MULTISIG_CONTINUITY_JSON: '{"epoch":1,"note":"sketch"}'
|
|
}
|
|
)
|
|
t.is(j.schema, 2)
|
|
t.is(j.vaultMultisigContinuity?.epoch, 1)
|
|
})
|
|
|
|
test('hrpc_allowlist_sketch proc lists stock bareOsHrpcRequest routes', async (t) => {
|
|
const j = buildBareOsHypercorePackHrpcLifecycleProcJson(
|
|
'hrpc_allowlist_sketch',
|
|
{}
|
|
)
|
|
t.is(j.schema, 3)
|
|
t.is(j.routeTableSchemaVersion, 3)
|
|
t.ok(Array.isArray(j.stockRoutes))
|
|
t.ok(j.stockRoutes.includes('bare_os.replication_snapshot'))
|
|
t.ok(j.stockRoutes.includes('bare_os.search_local'))
|
|
t.ok(j.stockRoutes.includes('bare_os.pkg_index_get'))
|
|
})
|
|
|
|
test('pear_doctor_state proc JSON schema 2 parity fields', async (t) => {
|
|
const j = buildBareOsPearInspectLoggerTlsProcJson(
|
|
'pear_doctor_state',
|
|
{
|
|
BARE_OS_PEAR_DOCTOR_STATE_JSON: '{"ok":true}',
|
|
BARE_OS_PEAR_RUNTIME_VERSION: '1.2.3',
|
|
BARE_OS_PEAR_INSPECT_PROBE: '1',
|
|
BARE_OS_PEAR_DOCTOR_MODULE: 'pear-doctor'
|
|
},
|
|
{}
|
|
)
|
|
t.is(j.schema, 2)
|
|
t.is(j.runtimeVersion, '1.2.3')
|
|
t.is(j.pearInspectProbe, true)
|
|
t.is(j.pearDoctorModuleHint, 'pear-doctor')
|
|
t.ok(j.state && typeof j.state === 'object')
|
|
})
|
|
|
|
test('split suffix rolls past zz into three-letter names', async (t) => {
|
|
const a = 'abcdefghijklmnopqrstuvwxyz'
|
|
function suffix(i) {
|
|
let idx = i
|
|
let len = 2
|
|
let span = 26 ** len
|
|
while (idx >= span) {
|
|
idx -= span
|
|
len++
|
|
span = 26 ** len
|
|
}
|
|
let s = ''
|
|
let n = idx
|
|
for (let p = 0; p < len; p++) {
|
|
s = a[n % 26] + s
|
|
n = Math.floor(n / 26)
|
|
}
|
|
return 'x' + s
|
|
}
|
|
t.is(suffix(0), 'xaa')
|
|
t.is(suffix(675), 'xzz')
|
|
t.is(suffix(676), 'xaaa')
|
|
t.is(suffix(677), 'xaab')
|
|
})
|
|
|
|
test('disk.os replication_snapshot and replication_operator_sketch RPCs', async (t) => {
|
|
const dir = testCorestoreDir('diskosrpc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
await drive.ready()
|
|
const bridge = createBareOsDiskOsBridge({
|
|
drive,
|
|
bareOsIpc: { list: () => [] },
|
|
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
|
systemRevision: { currentId: 'cur', pendingId: '', slot: 'a' },
|
|
bootStartedMs: Date.now() - 1000,
|
|
seedReplicationStatus: { depth: 1 },
|
|
protomuxOperatorSketch: {
|
|
schema: 2,
|
|
protomuxAppChannelRxTotal: 0,
|
|
envGateAppChannel: 'BARE_OS_PROTOMUX_APP_CHANNEL'
|
|
}
|
|
})
|
|
const snap = await bridge.execRpc('bare_os', 'replication_snapshot', [])
|
|
const sj = JSON.parse(snap)
|
|
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', [])
|
|
const oj = JSON.parse(op)
|
|
t.is(oj.schema, 8)
|
|
t.is(oj.protomuxOperatorSketch?.schema, 2)
|
|
t.ok(Object.prototype.hasOwnProperty.call(oj, 'hyperdhtAddressSketch'))
|
|
t.is(oj.corestoreSnapshotUxHint?.schema, 4)
|
|
t.is(oj.corestoreSnapshotPackageRef?.npmPackage, 'corestore-snapshot')
|
|
t.is(oj.seedReplicationStatus?.depth, 1)
|
|
t.is(oj.swarmPeerCount, null)
|
|
const badIntent = await bridge.execRpc(
|
|
'bare_os',
|
|
'replication_operator_intent',
|
|
['{}']
|
|
)
|
|
const ij = JSON.parse(badIntent)
|
|
t.is(ij.schema, 2)
|
|
t.is(ij.ok, false)
|
|
t.is(ij.code, 'EPERM')
|
|
await drive.put('/boot/init.js', b4a.from('//x'))
|
|
const pe = await bridge.execRpc('bare_os', 'path_exists', ['/boot/init.js'])
|
|
const pej = JSON.parse(pe)
|
|
t.is(pej.ok, true)
|
|
t.is(pej.exists, true)
|
|
const bi = await bridge.execRpc('bare_os', 'boot_init_exists', [])
|
|
const bij = JSON.parse(bi)
|
|
t.is(bij.ok, true)
|
|
t.is(bij.exists, true)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('disk.os searchLocal merges auxiliary drives and disk_os_hints RPC', async (t) => {
|
|
const dir = testCorestoreDir('diskossearch')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const auxStore = store.namespace('auxs')
|
|
const aux = new Hyperdrive(auxStore)
|
|
await drive.ready()
|
|
await aux.ready()
|
|
await drive.put('/sys/x_only', b4a.from('1'))
|
|
await aux.put('/mirror/y_aux', b4a.from('2'))
|
|
const bridge = createBareOsDiskOsBridge({
|
|
drive,
|
|
auxiliaryDrives: [aux],
|
|
bareOsIpc: { list: () => [] },
|
|
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
|
systemRevision: null,
|
|
bootStartedMs: Date.now(),
|
|
seedMirrorDriveHintV2: { schema: 2, note: 't' },
|
|
seedHttpDhtProxyHint: { routes: 1 }
|
|
})
|
|
const m = await bridge.searchLocal('y_aux')
|
|
t.ok(m.some((p) => p.includes('y_aux')))
|
|
const m2 = await bridge.searchLocal('x_only')
|
|
t.ok(m2.some((p) => p.includes('x_only')))
|
|
const h = await bridge.execRpc('bare_os', 'disk_os_hints', [])
|
|
const hj = JSON.parse(h)
|
|
t.is(hj.schema, 3)
|
|
t.is(hj.auxiliaryDriveCount, 1)
|
|
t.ok(hj.protocolPackageVersion)
|
|
t.ok(typeof hj.protomuxChannelSchemaVersion === 'number')
|
|
t.is(hj.mirrorDriveHintV2?.schema, 2)
|
|
t.is(hj.httpDhtProxyHint?.routes, 1)
|
|
t.ok(hj.pathSearchLocal && hj.pathSearchLocal.schema === 1)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('disk.os searchLocal uses path-manifest before drive listing', async (t) => {
|
|
const dir = testCorestoreDir('diskosmanifest')
|
|
const prevManifest = process.env.BARE_OS_DISK_OS_PATH_MANIFEST
|
|
const prevOnly = process.env.BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY
|
|
process.env.BARE_OS_DISK_OS_PATH_MANIFEST = '/etc/bare-os/path-manifest.json'
|
|
process.env.BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY = '1'
|
|
try {
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
await drive.ready()
|
|
await drive.put(
|
|
'/etc/bare-os/path-manifest.json',
|
|
b4a.from(
|
|
JSON.stringify({
|
|
schema: 1,
|
|
paths: ['/vendor/only-on-manifest.txt']
|
|
})
|
|
)
|
|
)
|
|
const bridge = createBareOsDiskOsBridge({
|
|
drive,
|
|
auxiliaryDrives: [],
|
|
bareOsIpc: { list: () => [] },
|
|
ctxApiVersion: BARE_OS_CTX_API_VERSION,
|
|
systemRevision: null,
|
|
bootStartedMs: Date.now()
|
|
})
|
|
const m = await bridge.searchLocal('only-on')
|
|
t.ok(m.some((p) => p === '/vendor/only-on-manifest.txt'))
|
|
const h = await bridge.execRpc('bare_os', 'disk_os_hints', [])
|
|
const hj = JSON.parse(h)
|
|
t.is(hj.schema, 3)
|
|
t.is(hj.pathSearchLocal.manifestOnly, true)
|
|
t.ok(hj.pathSearchLocal.manifestMatchCount >= 1)
|
|
t.is(hj.pathSearchLocal.primaryScanMatchCount, 0)
|
|
await store.close()
|
|
} finally {
|
|
if (prevManifest === undefined) delete process.env.BARE_OS_DISK_OS_PATH_MANIFEST
|
|
else process.env.BARE_OS_DISK_OS_PATH_MANIFEST = prevManifest
|
|
if (prevOnly === undefined) delete process.env.BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY
|
|
else process.env.BARE_OS_DISK_OS_SEARCH_MANIFEST_ONLY = prevOnly
|
|
}
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('ls -l long listing uses session user and regular file mode', async (t) => {
|
|
const lsPath = path.join(__dirname, '../../kernel/bin/ls')
|
|
const lsSrc = await readFile(lsPath, 'utf8')
|
|
const dir = testCorestoreDir('lslong')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pll'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/ls', b4a.from(lsSrc))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal, {
|
|
USER: 'carol',
|
|
UID: '9001',
|
|
GID: '9001'
|
|
})
|
|
ctx.console = {
|
|
log: (s) => lines.push(String(s)),
|
|
error: (...a) => lines.push(a.join(' '))
|
|
}
|
|
await ctx.vfs.writeFile('shown.txt', b4a.from(''))
|
|
await runBinCommand(ctx, ['ls', '-l', 'shown.txt'])
|
|
const longLine = lines.find((l) => l.includes('shown.txt'))
|
|
t.ok(longLine)
|
|
t.ok(longLine.includes('carol'))
|
|
t.ok(/^-rw/.test(longLine), 'expected regular file mode prefix')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('ls --color=always colors directory blue and executable green', async (t) => {
|
|
const lsPath = path.join(__dirname, '../../kernel/bin/ls')
|
|
const lsSrc = await readFile(lsPath, 'utf8')
|
|
const dir = testCorestoreDir('lscolor')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('plsc'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/ls', b4a.from(lsSrc))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.console = {
|
|
log: (s) => lines.push(String(s)),
|
|
error: (...a) => lines.push(a.join(' '))
|
|
}
|
|
await ctx.vfs.mkdir('subdir', { recursive: true })
|
|
await ctx.vfs.writeFile('xfile', b4a.from(''))
|
|
await ctx.vfs.chmod('xfile', 0o755)
|
|
await runBinCommand(ctx, ['ls', '--color=always'])
|
|
const shortLine = lines.find(
|
|
(l) => l.includes('subdir') && l.includes('xfile')
|
|
)
|
|
t.ok(shortLine)
|
|
t.ok(
|
|
/\x1b\[[0-9;]*msubdir\x1b\[0m/.test(shortLine),
|
|
'directory uses LS_COLORS di SGR'
|
|
)
|
|
t.ok(
|
|
/\x1b\[[0-9;]*mxfile\x1b\[0m/.test(shortLine),
|
|
'executable uses LS_COLORS ex SGR'
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('ls honors NO_COLOR over --color=always', async (t) => {
|
|
const lsPath = path.join(__dirname, '../../kernel/bin/ls')
|
|
const lsSrc = await readFile(lsPath, 'utf8')
|
|
const dir = testCorestoreDir('lscolornc')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('plsn'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/ls', b4a.from(lsSrc))
|
|
const lines = []
|
|
const ctx = testCtx(drive, personal, { NO_COLOR: '1' })
|
|
ctx.console = {
|
|
log: (s) => lines.push(String(s)),
|
|
error: (...a) => lines.push(a.join(' '))
|
|
}
|
|
await ctx.vfs.mkdir('onlydir', { recursive: true })
|
|
await runBinCommand(ctx, ['ls', '--color=always'])
|
|
const shortLine = lines.find((l) => l.includes('onlydir'))
|
|
t.ok(shortLine)
|
|
t.ok(!shortLine.includes('\x1b['), 'NO_COLOR strips ANSI')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('ls rejects unknown long option', async (t) => {
|
|
const lsPath = path.join(__dirname, '../../kernel/bin/ls')
|
|
const lsSrc = await readFile(lsPath, 'utf8')
|
|
const dir = testCorestoreDir('lsbadopt')
|
|
const store = new Corestore(dir)
|
|
const drive = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('plbo'))
|
|
await drive.ready()
|
|
await personal.ready()
|
|
await drive.put('/bin/ls', b4a.from(lsSrc))
|
|
const errs = []
|
|
const ctx = testCtx(drive, personal)
|
|
ctx.console = {
|
|
log: () => {},
|
|
error: (...a) => errs.push(a.join(' '))
|
|
}
|
|
await runBinCommand(ctx, ['ls', '--not-a-real-option'])
|
|
t.is(ctx.exitCode, 2)
|
|
t.ok(errs.some((e) => e.includes('unrecognized')))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs readFile missing path in home does not throw (touch pattern)', async (t) => {
|
|
const dir = testCorestoreDir('vfsreadmiss')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvrm'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/zed',
|
|
PWD: '/home/zed',
|
|
PATH: '/bin',
|
|
USER: 'zed',
|
|
UID: '7000',
|
|
GID: '7000'
|
|
})
|
|
const missing = await vfs.readFile('newfile')
|
|
t.is(missing, null)
|
|
await vfs.writeFile('newfile', b4a.from('ok'))
|
|
t.is(b4a.toString(await vfs.readFile('newfile')), 'ok')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs routes HOME to personal drive', async (t) => {
|
|
const dir = testCorestoreDir('vfs')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pv'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = { HOME: '/home/user', PWD: '/home/user', PATH: '/bin' }
|
|
const vfs = createVfs(sys, personal, env)
|
|
await vfs.writeFile('f.txt', b4a.from('hi'))
|
|
const buf = await personal.get(personalHomeBacking('/home/user', 'f.txt'))
|
|
t.ok(buf)
|
|
t.is(b4a.toString(buf), 'hi')
|
|
const sysTry = await sys.get('/home/user/f.txt')
|
|
t.is(sysTry, null)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs routes /.bare to personal drive', async (t) => {
|
|
const dir = testCorestoreDir('vfsbare')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvb'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put('/.bare/vault-marker', b4a.from('1'))
|
|
await sys.put('/.bare/system-only', b4a.from('2'))
|
|
const env = { HOME: '/home/user', PWD: '/home/user', PATH: '/bin' }
|
|
const vfs = createVfs(sys, personal, env)
|
|
const names = await vfs.readdir('/.bare')
|
|
t.ok(names.includes('vault-marker'))
|
|
t.is(names.includes('system-only'), false)
|
|
t.is(await sys.get('/.bare/vault-marker'), null)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs chdir / and stat $HOME root (Hyperdrive rejects entry("/"))', async (t) => {
|
|
const dir = testCorestoreDir('vfsroot')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pv2'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = { HOME: '/home/user', PWD: '/home/user', PATH: '/bin' }
|
|
const vfs = createVfs(sys, personal, env)
|
|
await vfs.chdir('/')
|
|
t.is(vfs.getcwd(), '/')
|
|
const st = await vfs.stat('/home/user')
|
|
t.is(st.type, 'directory')
|
|
await vfs.chdir('/home/user')
|
|
t.is(vfs.getcwd(), '/home/user')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs bareOsForkShellEnv isolates cwd and shares identity ref', async (t) => {
|
|
const dir = testCorestoreDir('vfork')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvfork'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = { HOME: '/home/user', PWD: '/home/user', PATH: '/bin' }
|
|
const vfs = createVfs(sys, personal, env)
|
|
const forkA = vfs.bareOsForkShellEnv({ SSH_CLIENT: 'a' })
|
|
const forkB = vfs.bareOsForkShellEnv({ SSH_CLIENT: 'b' })
|
|
t.is(vfs.getcwd(), '/home/user')
|
|
t.is(forkA.getcwd(), '/home/user')
|
|
t.is(forkB.getcwd(), '/home/user')
|
|
await forkA.chdir('/')
|
|
t.is(vfs.getcwd(), '/home/user')
|
|
t.is(forkB.getcwd(), '/home/user')
|
|
t.is(forkA.getcwd(), '/')
|
|
t.is(forkA.env.SSH_CLIENT, 'a')
|
|
t.is(forkB.env.SSH_CLIENT, 'b')
|
|
t.is(vfs.env.SSH_CLIENT, undefined)
|
|
vfs.bareOsIdentitySession = 'unlocked'
|
|
t.is(forkB.bareOsIdentitySession, 'unlocked')
|
|
forkB.bareOsIdentitySession = 'guest'
|
|
t.is(vfs.bareOsIdentitySession, 'guest')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs expands ~ and ~/ to $HOME (not read-only /~)', async (t) => {
|
|
const dir = testCorestoreDir('vfstilde')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pv3'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = { HOME: '/home/zuser', PWD: '/home/zuser', PATH: '/bin' }
|
|
const vfs = createVfs(sys, personal, env)
|
|
await vfs.chdir('/')
|
|
await vfs.chdir('~')
|
|
t.is(vfs.getcwd(), '/home/zuser')
|
|
await vfs.writeFile('~/tilde.txt', b4a.from('ok'))
|
|
const buf = await personal.get(
|
|
personalHomeBacking('/home/zuser', 'tilde.txt')
|
|
)
|
|
t.ok(buf)
|
|
t.is(b4a.toString(buf), 'ok')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs system read-only alias routes reads and denies writes', async (t) => {
|
|
const dir = testCorestoreDir('vfs-sys-ro-alias')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pv-sys-ro-alias'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await sys.put('/etc/os-release', b4a.from('ID=bareos\n'))
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/user',
|
|
PWD: '/home/user',
|
|
PATH: '/bin',
|
|
USER: 'user',
|
|
BARE_OS_VFS_SYSTEM_RO_ALIAS: '/system-ro'
|
|
})
|
|
const buf = await vfs.readFile('/system-ro/etc/os-release')
|
|
t.ok(buf)
|
|
t.is(b4a.toString(buf), 'ID=bareos\n')
|
|
await t.exception(async () => {
|
|
await vfs.writeFile('/system-ro/etc/os-release', b4a.from('ID=mutated\n'))
|
|
})
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs denies mutating system-drive operations outside HOME', async (t) => {
|
|
const dir = testCorestoreDir('vfs-system-write-deny')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pv-system-write-deny'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await sys.put('/etc/os-release', b4a.from('ID=bareos\n'))
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/user',
|
|
PWD: '/home/user',
|
|
PATH: '/bin',
|
|
USER: 'user',
|
|
UID: '1000',
|
|
GID: '1000'
|
|
})
|
|
|
|
for (const op of [
|
|
() => vfs.writeFile('/etc/new.conf', b4a.from('x')),
|
|
() => vfs.unlink('/etc/os-release'),
|
|
() => vfs.mkdir('/etc/newdir'),
|
|
() => vfs.symlink('/bin/sh', '/etc/sh-link'),
|
|
() => vfs.chmod('/etc/os-release', 0o644),
|
|
() => vfs.chown('/etc/os-release', { uid: 1000, gid: 1000 })
|
|
]) {
|
|
await t.exception(async () => {
|
|
await op()
|
|
})
|
|
}
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs lists virtual /home at root; /home shows only active session dir', async (t) => {
|
|
const dir = testCorestoreDir('vfshomevirt')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvh'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const envGuest = { HOME: '/home/guest', PWD: '/home/guest', PATH: '/bin' }
|
|
const vfsG = createVfs(sys, personal, envGuest)
|
|
const rootG = await vfsG.readdir('/')
|
|
t.ok(rootG.includes('home'))
|
|
t.ok(rootG.includes('bin') || rootG.includes('boot') || rootG.length >= 1)
|
|
t.alike(await vfsG.readdir('/home'), ['guest'])
|
|
const envUser = {
|
|
HOME: '/home/eeb18de988e9',
|
|
PWD: '/home/eeb18de988e9',
|
|
PATH: '/bin'
|
|
}
|
|
const vfsU = createVfs(sys, personal, envUser)
|
|
t.alike(await vfsU.readdir('/home'), ['eeb18de988e9'])
|
|
t.is(await vfsU.stat('/home/guest'), null)
|
|
await vfsU.writeFile('/home/eeb18de988e9/x', b4a.from('1'))
|
|
const buf = await personal.get(personalHomeBacking('/home/eeb18de988e9', 'x'))
|
|
t.ok(buf)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('guest vfs readFile /.bare/account is EACCES on sensitive path', async (t) => {
|
|
const dir = testCorestoreDir('vfsguestbare')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvgsb'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put('/.bare/account', b4a.from('not-a-real-account'))
|
|
const envGuest = {
|
|
HOME: '/home/guest',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
USER: 'guest'
|
|
}
|
|
const vfs = createVfs(sys, personal, envGuest)
|
|
let err = null
|
|
try {
|
|
await vfs.readFile('/.bare/account')
|
|
} catch (e) {
|
|
err = e
|
|
}
|
|
t.ok(err, 'expected throw')
|
|
t.ok(String(err.message).includes('EACCES'), err.message)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('guest vfs BARE_OS_GUEST_BARE_READ_ALL=yes does not lift sensitive /.bare deny', async (t) => {
|
|
const dir = testCorestoreDir('vfsbareyes')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvbareyes'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put('/.bare/account', b4a.from('acct'))
|
|
const env = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest',
|
|
BARE_OS_GUEST_BARE_READ_ALL: 'yes'
|
|
}
|
|
const vfs = createVfs(sys, personal, env, { getMounts: () => new Map() }, {
|
|
procBareOsSwarmText: () => '{}\n'
|
|
})
|
|
let err = null
|
|
try {
|
|
await vfs.readFile('/.bare/account')
|
|
} catch (e) {
|
|
err = e
|
|
}
|
|
t.ok(err)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('guest vfs readFile /.bare/account when BARE_OS_GUEST_BARE_READ_ALL', async (t) => {
|
|
const dir = testCorestoreDir('vfsguestbareall')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvgba'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put('/.bare/account', b4a.from('acct-body'))
|
|
const envGuest = {
|
|
HOME: '/home/guest',
|
|
PWD: '/',
|
|
PATH: '/bin',
|
|
USER: 'guest',
|
|
BARE_OS_GUEST_BARE_READ_ALL: '1'
|
|
}
|
|
const vfs = createVfs(sys, personal, envGuest)
|
|
const buf = await vfs.readFile('/.bare/account')
|
|
t.ok(buf)
|
|
t.is(b4a.toString(buf, 'utf8'), 'acct-body')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /proc /sys read-only pseudo files; write rejected', async (t) => {
|
|
const dir = testCorestoreDir('vfsproc')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvproc'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest',
|
|
BARE_OS_CTX_API_VERSION: '9.9.9-test'
|
|
}
|
|
const mntMap = new Map()
|
|
const bareOsIpc = createBareOsIpc()
|
|
const vfs = createVfs(
|
|
sys,
|
|
personal,
|
|
env,
|
|
{ getMounts: () => mntMap },
|
|
{
|
|
procSnapshot: { version: '1.2.3-test', cmdline: 'unit-test' },
|
|
bootStartedMs: Date.now() - 4000,
|
|
bootProfileText: () => 'mini\n',
|
|
sessionText: () => 'test-session-id\n',
|
|
initdRunText: () => 'demo-unit\tactive\t1\tdemo\n',
|
|
procBareOsSwarmText: () => '{}\n',
|
|
bareOsIpc
|
|
}
|
|
)
|
|
const root = await vfs.readdir('/')
|
|
t.ok(root.includes('proc'))
|
|
t.ok(root.includes('sys'))
|
|
t.ok(root.includes('tmp'))
|
|
t.ok(root.includes('run'))
|
|
t.ok(root.includes('dev'))
|
|
const procRoot = await vfs.readdir('/proc').then((a) => [...a].sort())
|
|
t.ok(procRoot.includes('bare_os'))
|
|
t.ok(procRoot.includes('cpuinfo'))
|
|
t.ok(procRoot.includes('meminfo'))
|
|
t.ok(procRoot.includes('loadavg'))
|
|
t.ok(procRoot.includes('diskstats'))
|
|
t.ok(procRoot.includes('mounts'))
|
|
t.ok(procRoot.includes('net'))
|
|
t.ok(procRoot.includes('self'))
|
|
t.ok(procRoot.includes('uptime'))
|
|
t.ok(procRoot.includes('version'))
|
|
if (false) t.alike(await vfs.readdir('/proc').then((a) => [...a].sort()).then(() => [
|
|
'bare_os',
|
|
'bare_os_activity_queue_depth.json',
|
|
'bare_os_async_hooks_lag.json',
|
|
'bare_os_autobase_writer_hint.json',
|
|
'bare_os_autopass_rotation_sketch.json',
|
|
'bare_os_autopass_session_sketch.json',
|
|
'bare_os_bare_addon_policy.json',
|
|
'bare_os_bare_boot_phase_map.json',
|
|
'bare_os_bare_crypto_policy.json',
|
|
'bare_os_bare_daemon_hooks.json',
|
|
'bare_os_bare_diagnostics_channel.json',
|
|
'bare_os_bare_inspect_policy.json',
|
|
'bare_os_bare_ipc_bridge.json',
|
|
'bare_os_bare_kit_bridge.json',
|
|
'bare_os_bare_logger_policy.json',
|
|
'bare_os_bare_module_resolution.json',
|
|
'bare_os_bare_net_interfaces.json',
|
|
'bare_os_bare_pack_cache.json',
|
|
'bare_os_bare_performance_counters.json',
|
|
'bare_os_bare_rpc_registry_sketch.json',
|
|
'bare_os_bare_signals_mask.json',
|
|
'bare_os_bare_signals_profile.json',
|
|
'bare_os_bare_storage_quota.json',
|
|
'bare_os_bare_stream_backpressure.json',
|
|
'bare_os_bare_thread_pool.json',
|
|
'bare_os_bare_timers_budget.json',
|
|
'bare_os_bare_timers_histogram.json',
|
|
'bare_os_bare_tls_session_hint.json',
|
|
'bare_os_bare_vm_sandbox_sketch.json',
|
|
'bare_os_bare_worker_pool.json',
|
|
'bare_os_bare_ws_gateway_sketch.json',
|
|
'bare_os_blind_pairing_sketch.json',
|
|
'bare_os_blind_relay_router.json',
|
|
'bare_os_boot_budget_summary.json',
|
|
'bare_os_boot_graph.json',
|
|
'bare_os_bootstrap',
|
|
'bare_os_brittle_snapshot_ci.json',
|
|
'bare_os_broadcast_encryption_hint.json',
|
|
'bare_os_build_attestation_pointer.json',
|
|
'bare_os_bundle_preload_hint.json',
|
|
'bare_os_capabilities',
|
|
'bare_os_capabilities.json',
|
|
'bare_os_cellery_sidecar_hint.json',
|
|
'bare_os_chat.json',
|
|
'bare_os_clock.json',
|
|
'bare_os_compact_encoding_profile.json',
|
|
'bare_os_corestore_gc_hint.json',
|
|
'bare_os_debug.json',
|
|
'bare_os_delegate_red.json',
|
|
'bare_os_dht_status.json',
|
|
'bare_os_dns_map_active.json',
|
|
'bare_os_drive_resolve_cache.json',
|
|
'bare_os_drive_version_graph.json',
|
|
'bare_os_extensions.json',
|
|
'bare_os_features',
|
|
'bare_os_features.json',
|
|
'bare_os_form_data_delegate_limits.json',
|
|
'bare_os_form_data_delegate_limits_v2.json',
|
|
'bare_os_giant_phase_program.json',
|
|
'bare_os_gip_transport_sketch.json',
|
|
'bare_os_git_delegate_stats.json',
|
|
'bare_os_git_lfs_budget.json',
|
|
'bare_os_git_lfs_pointer_stats.json',
|
|
'bare_os_hdms_health.json',
|
|
'bare_os_hdms_hints.json',
|
|
'bare_os_host_os.json',
|
|
'bare_os_hrpc_allowlist_sketch.json',
|
|
'bare_os_hrpc_bridge_health.json',
|
|
'bare_os_http_dht_proxy_route.json',
|
|
'bare_os_hyper_multisig_trust_pointer.json',
|
|
'bare_os_hypercore_lengths.json',
|
|
'bare_os_hypercore_repair_hint.json',
|
|
'bare_os_hypercore_replicate_budget.json',
|
|
'bare_os_hypercore_signing_status.json',
|
|
'bare_os_hyperdb_readonly_index.json',
|
|
'bare_os_hyperdrive_sparse_index.json',
|
|
'bare_os_hypermininet_topology.json',
|
|
'bare_os_indexer_catchup.json',
|
|
'bare_os_initd_dag.json',
|
|
'bare_os_initd_graph.json',
|
|
'bare_os_ipc_backpressure.json',
|
|
'bare_os_kernel_program.json',
|
|
'bare_os_libmqjs_queue_depth.json',
|
|
'bare_os_locale.json',
|
|
'bare_os_manifest_hints',
|
|
'bare_os_metrics_live.json',
|
|
'bare_os_metrics_prom.json',
|
|
'bare_os_multisig_quorum_pointer.json',
|
|
'bare_os_net_qos_class.json',
|
|
'bare_os_net_summary.json',
|
|
'bare_os_oidc_publishing_pointer.json',
|
|
'bare_os_openssh.json',
|
|
'bare_os_pear_api_allowlist_sketch.json',
|
|
'bare_os_pear_appling_manifest.json',
|
|
'bare_os_pear_build_fingerprint.json',
|
|
'bare_os_pear_doctor_state.json',
|
|
'bare_os_pear_drop_events.json',
|
|
'bare_os_pear_ipc_health.json',
|
|
'bare_os_pear_radio_state.json',
|
|
'bare_os_pear_rti_pointer.json',
|
|
'bare_os_pear_runtime_channel.json',
|
|
'bare_os_pear_runtime_matrix.json',
|
|
'bare_os_pear_sidecar_bundle_index.json',
|
|
'bare_os_pear_stage_pointer.json',
|
|
'bare_os_pear_trust.json',
|
|
'bare_os_pear_updater_state.json',
|
|
'bare_os_pear_user_dirs_map.json',
|
|
'bare_os_pear_wakeups_schedule.json',
|
|
'bare_os_pear_workshop_flags.json',
|
|
'bare_os_peer_health',
|
|
'bare_os_protomux_backpressure.json',
|
|
'bare_os_protomux_channel_alias_v2.json',
|
|
'bare_os_protomux_channels.json',
|
|
'bare_os_protomux_extensions.json',
|
|
'bare_os_protomux_rpc_pool_health.json',
|
|
'bare_os_protomux_wire.json',
|
|
'bare_os_provenance',
|
|
'bare_os_quotas',
|
|
'bare_os_react_native_bare_kit.json',
|
|
'bare_os_relay_geo_hint.json',
|
|
'bare_os_replication',
|
|
'bare_os_replication_backpressure.json',
|
|
'bare_os_replication_operator_panel.json',
|
|
'bare_os_resources',
|
|
'bare_os_rlimits.json',
|
|
'bare_os_rocksdb_pointer.json',
|
|
'bare_os_safe_sodium_buffer_policy.json',
|
|
'bare_os_sandbox_profile.json',
|
|
'bare_os_sandbox_worker_queue.json',
|
|
'bare_os_security_context.json',
|
|
'bare_os_security_posture.json',
|
|
'bare_os_seed_handshake',
|
|
'bare_os_session_stats',
|
|
'bare_os_sidecar_resource_cap.json',
|
|
'bare_os_slo_hints.json',
|
|
'bare_os_snapshot_hints',
|
|
'bare_os_snapshot_hints.json',
|
|
'bare_os_staging_slot',
|
|
'bare_os_storage_tier_hint.json',
|
|
'bare_os_structured_clone_budget_v2.json',
|
|
'bare_os_structured_clone_profile.json',
|
|
'bare_os_swarm',
|
|
'bare_os_swarm.json',
|
|
'bare_os_swarm_connection_manager_status.json',
|
|
'bare_os_swarm_datagram_replication_status.json',
|
|
'bare_os_swarm_datagrams_status.json',
|
|
'bare_os_swarm_health.json',
|
|
'bare_os_swarm_holepunch_status.json',
|
|
'bare_os_swarm_key_broker_status.json',
|
|
'bare_os_swarm_relay_status.json',
|
|
'bare_os_swarm_replication_status.json',
|
|
'bare_os_swarm_status.json',
|
|
'bare_os_sync_window.json',
|
|
'bare_os_syscalls',
|
|
'bare_os_syscalls.json',
|
|
'bare_os_udx_extended.json',
|
|
'bare_os_union',
|
|
'bare_os_updater_download_state.json',
|
|
'bare_os_version',
|
|
'bare_os_virtual_registry',
|
|
'bare_os_wave11_operator_slo_v2.json',
|
|
'bare_os_wave11_peer_qos_sketch.json',
|
|
'bare_os_worker_budget.json',
|
|
'cpuinfo',
|
|
'diskstats',
|
|
'loadavg',
|
|
'meminfo',
|
|
'mounts',
|
|
'net',
|
|
'self',
|
|
'uptime',
|
|
'version'
|
|
]))
|
|
t.alike(await vfs.readdir('/proc/self').then((a) => [...a].sort()), [
|
|
'cgroups',
|
|
'cmdline',
|
|
'environ',
|
|
'exe',
|
|
'fd',
|
|
'limits'
|
|
])
|
|
const ver = b4a.toString(await vfs.readFile('/proc/version'))
|
|
t.ok(ver.includes('Bare OS'))
|
|
t.ok(ver.includes('bare_os_ctx_api_version=1.2.3-test'))
|
|
const sysVer = b4a.toString(await vfs.readFile('/sys/fs/bare_os/version'))
|
|
t.ok(sysVer.includes('1.2.3-test'))
|
|
const cmd = b4a.toString(await vfs.readFile('/proc/self/cmdline'))
|
|
t.ok(cmd.includes('unit-test'))
|
|
const mem = b4a.toString(await vfs.readFile('/proc/meminfo'))
|
|
t.ok(mem.includes('MemTotal:'))
|
|
const up = b4a.toString(await vfs.readFile('/proc/uptime'))
|
|
t.ok(/^\d+\.\d+\s+\d+\.\d+/.test(up.trim()))
|
|
const cpu = b4a.toString(await vfs.readFile('/proc/cpuinfo'))
|
|
t.ok(cpu.includes('Bare OS pseudo CPU'))
|
|
const la = b4a.toString(await vfs.readFile('/proc/loadavg'))
|
|
t.ok(/^\d+\.\d+\s+\d+\.\d+\s+\d+\.\d+\s+/.test(la))
|
|
const exe = b4a.toString(await vfs.readFile('/proc/self/exe'))
|
|
t.ok(exe.includes('pseudo inode'))
|
|
const cg = b4a.toString(await vfs.readFile('/proc/self/cgroups'))
|
|
t.ok(cg.includes('bare-os'))
|
|
t.alike(await vfs.readdir('/proc/net').then((a) => [...a].sort()), [
|
|
'dev',
|
|
'tcp',
|
|
'udp'
|
|
])
|
|
const tcp = b4a.toString(await vfs.readFile('/proc/net/tcp'))
|
|
t.ok(tcp.includes('local_address'))
|
|
const udp = b4a.toString(await vfs.readFile('/proc/net/udp'))
|
|
t.ok(udp.includes('sl'))
|
|
let mountsTxt = b4a.toString(await vfs.readFile('/proc/mounts'))
|
|
t.ok(mountsTxt.includes('bare-os-root'))
|
|
t.ok(mountsTxt.includes(' / hyperdrive '))
|
|
mntMap.set('vol', { drive: sys, writable: true })
|
|
mountsTxt = b4a.toString(await vfs.readFile('/proc/mounts'))
|
|
t.ok(mountsTxt.includes('/mnt/vol'))
|
|
t.ok(mountsTxt.includes('bare-os-vol'))
|
|
t.alike(await vfs.readdir('/dev').then((a) => [...a].sort()), [
|
|
'null',
|
|
'shm',
|
|
'urandom',
|
|
'zero'
|
|
])
|
|
const ur = await vfs.readFile('/dev/urandom')
|
|
t.ok(ur && ur.byteLength === 4096)
|
|
await vfs.writeFile('/dev/null', b4a.from('gone'))
|
|
t.is((await vfs.readFile('/dev/null'))?.byteLength ?? 0, 0)
|
|
const z = await vfs.readFile('/dev/zero')
|
|
t.ok(z && z.byteLength === 65536)
|
|
t.alike(await vfs.readdir('/run/bare-os').then((a) => [...a].sort()), [
|
|
'boot.json',
|
|
'boot_profile',
|
|
'ipc',
|
|
'ready',
|
|
'session',
|
|
'unit-journal',
|
|
'units',
|
|
'virtual'
|
|
])
|
|
t.alike(await vfs.readdir('/run/bare-os/ipc'), [])
|
|
bareOsIpc.create('q1')
|
|
t.alike(await vfs.readdir('/run/bare-os/ipc'), ['q1'])
|
|
const readP = vfs.readFile('/run/bare-os/ipc/q1')
|
|
const t0 = Date.now()
|
|
await vfs.writeFile('/run/bare-os/ipc/q1', b4a.from('ping'))
|
|
t.is(b4a.toString(await readP), 'ping')
|
|
t.ok(Date.now() - t0 < 60000, 'kernel ipc ping-pong completes')
|
|
await vfs.unlink('/run/bare-os/ipc/q1')
|
|
t.alike(await vfs.readdir('/run/bare-os/ipc'), [])
|
|
t.is(b4a.toString(await vfs.readFile('/run/bare-os/boot_profile')), 'mini\n')
|
|
t.is(
|
|
b4a.toString(await vfs.readFile('/run/bare-os/session')),
|
|
'test-session-id\n'
|
|
)
|
|
const units = b4a.toString(await vfs.readFile('/run/bare-os/units'))
|
|
t.ok(units.includes('demo-unit'))
|
|
let writeErr = null
|
|
try {
|
|
await vfs.writeFile('/proc/version', b4a.from('x'))
|
|
} catch (e) {
|
|
writeErr = e
|
|
}
|
|
t.ok(writeErr)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs readFile /mirror/aux0 reads auxiliary hyperdrive (mirror-drive style mount)', async (t) => {
|
|
const dir = testCorestoreDir('vfsauxread')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvauxr'))
|
|
const aux = new Hyperdrive(store.namespace('auxread'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await aux.ready()
|
|
await aux.put('/hello.txt', b4a.from('mirror-body'))
|
|
const env = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest'
|
|
}
|
|
const vfs = createVfs(sys, personal, env, { getMounts: () => new Map() }, {
|
|
procBareOsSwarmText: () => '{}\n',
|
|
getAuxiliaryDrives: () => [aux]
|
|
})
|
|
t.is(b4a.toString(await vfs.readFile('/mirror/aux0/hello.txt')), 'mirror-body')
|
|
let werr = null
|
|
try {
|
|
await vfs.writeFile('/mirror/aux0/x', b4a.from('nope'))
|
|
} catch (e) {
|
|
werr = e
|
|
}
|
|
t.ok(werr, 'aux mirror mount is read-only')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /proc/mounts lists mirror aux drives', async (t) => {
|
|
const dir = testCorestoreDir('vfsauxmount')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvauxm'))
|
|
const aux = new Hyperdrive(store.namespace('auxmirror'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await aux.ready()
|
|
const env = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest'
|
|
}
|
|
const vfs = createVfs(sys, personal, env, { getMounts: () => new Map() }, {
|
|
procBareOsSwarmText: () => '{}\n',
|
|
getAuxiliaryDrives: () => [aux],
|
|
getAuxiliaryMountLines: () => [
|
|
'bare-os-aux0 /mirror/aux0 hyperdrive ro 0 0'
|
|
]
|
|
})
|
|
const mountsTxt = b4a.toString(await vfs.readFile('/proc/mounts'))
|
|
t.ok(mountsTxt.includes('bare-os-aux0'))
|
|
t.ok(mountsTxt.includes('/mirror/aux0'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs BARE_OS_HIDE_PROC_HYPERCORE_PACK_HRPC_LIFECYCLE=0 hides wave11 proc nodes', async (t) => {
|
|
const dir = testCorestoreDir('vfsprocw11')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvprocw11'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest',
|
|
BARE_OS_HIDE_PROC_HYPERCORE_PACK_HRPC_LIFECYCLE: '0'
|
|
}
|
|
const mntMap = new Map()
|
|
const vfs = createVfs(sys, personal, env, { getMounts: () => mntMap }, {
|
|
procBareOsSwarmText: () => '{}\n'
|
|
})
|
|
const flatW11 = Object.keys(BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE).map((k) =>
|
|
k.endsWith('.json') ? k : `${k}.json`
|
|
)
|
|
const bareOsW11 = Object.keys(BARE_OS_PROC_FILE_TO_ID_HYPERCORE_PACK_HRPC_LIFECYCLE).map((k) => {
|
|
const base = k.startsWith('bare_os_') ? k.slice('bare_os_'.length) : k
|
|
return base.endsWith('.json') ? base : `${base}.json`
|
|
})
|
|
const procRoot = await vfs.readdir('/proc').then((a) => [...a])
|
|
for (const n of flatW11) {
|
|
t.ok(!procRoot.includes(n), `flat ${n} should be hidden`)
|
|
}
|
|
const bo = await vfs.readdir('/proc/bare_os').then((a) => [...a])
|
|
for (const n of bareOsW11) {
|
|
t.ok(!bo.includes(n), `bare_os/${n} should be hidden`)
|
|
}
|
|
t.is(
|
|
await vfs.readFile('/proc/bare_os_hypercore_replicate_budget.json'),
|
|
null
|
|
)
|
|
const idxRaw = b4a.toString(await vfs.readFile('/proc/bare_os/index.json'))
|
|
const idx = JSON.parse(idxRaw)
|
|
t.ok(Array.isArray(idx.entries))
|
|
const names = new Set(idx.entries.map((e) => e.name))
|
|
t.ok(!names.has('hypercore_replicate_budget.json'))
|
|
t.ok(!names.has('wave11_peer_qos_sketch.json'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /proc/self/environ omits secret-like env keys', async (t) => {
|
|
const dir = testCorestoreDir('vfsprocenv')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvpe'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest',
|
|
MY_PASSWORD: 'hunter2',
|
|
MY_API_TOKEN: 'secret-token',
|
|
AWS_SECRET_ACCESS_KEY: 'aws-secret',
|
|
SESSION_TOKEN: 'session-secret',
|
|
BARE_OS_SAFE: 'visible'
|
|
}
|
|
const vfs = createVfs(sys, personal, env)
|
|
const raw = b4a.toString(await vfs.readFile('/proc/self/environ'))
|
|
t.ok(raw.includes('HOME='))
|
|
t.ok(raw.includes('BARE_OS_SAFE='))
|
|
t.ok(!raw.includes('MY_PASSWORD'))
|
|
t.ok(!raw.includes('hunter2'))
|
|
t.ok(!raw.includes('MY_API_TOKEN'))
|
|
t.ok(!raw.includes('secret-token'))
|
|
t.ok(!raw.includes('AWS_SECRET_ACCESS_KEY'))
|
|
t.ok(!raw.includes('SESSION_TOKEN'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /proc/bare_os/metrics.prom emits OpenMetrics-style payload', async (t) => {
|
|
const dir = testCorestoreDir('vfs-prom-openmetrics')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('vprom'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(
|
|
sys,
|
|
personal,
|
|
{
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest'
|
|
},
|
|
null,
|
|
{
|
|
procBareOsMetricsPromText: () =>
|
|
'# HELP bare_os_kernel_counters Bare OS kernel counters\n' +
|
|
'# TYPE bare_os_kernel_counters counter\n' +
|
|
'bare_os_kernel_counters{name="boot_ok"} 1\n'
|
|
}
|
|
)
|
|
const raw = b4a.toString(await vfs.readFile('/proc/bare_os/metrics.prom'))
|
|
t.ok(raw.includes('# HELP bare_os_kernel_counters'))
|
|
t.ok(raw.includes('# TYPE bare_os_kernel_counters counter'))
|
|
t.ok(raw.includes('bare_os_kernel_counters{name="boot_ok"} 1'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs exposes /proc/bare_os/initd_readiness.json', async (t) => {
|
|
const dir = testCorestoreDir('vfsinitdreadiness')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvinitdreadiness'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin'
|
|
})
|
|
const raw = b4a.toString(await vfs.readFile('/proc/bare_os/initd_readiness.json'))
|
|
const parsed = JSON.parse(raw)
|
|
t.is(parsed.schema, 2)
|
|
t.alike(parsed.units, [])
|
|
const idxRaw = b4a.toString(await vfs.readFile('/proc/bare_os/index.json'))
|
|
const idx = JSON.parse(idxRaw)
|
|
t.ok(
|
|
Array.isArray(idx.entries) &&
|
|
idx.entries.some((e) => e && e.name === 'initd_readiness.json')
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /tmp maps to personal drive per HOME basename', async (t) => {
|
|
const dir = testCorestoreDir('vfstmp')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvtmp'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfsGuest = createVfs(sys, personal, {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin'
|
|
})
|
|
await vfsGuest.writeFile('/tmp/session.dat', b4a.from('g'))
|
|
t.is(b4a.toString(await personal.get('/.bare-os/tmp/guest/session.dat')), 'g')
|
|
const vfsUser = createVfs(sys, personal, {
|
|
HOME: '/home/hexuserdead',
|
|
PWD: '/home/hexuserdead',
|
|
PATH: '/bin'
|
|
})
|
|
t.is(await vfsUser.readFile('/tmp/session.dat'), null)
|
|
await vfsUser.writeFile('/tmp/session.dat', b4a.from('u'))
|
|
t.is(
|
|
b4a.toString(await personal.get('/.bare-os/tmp/hexuserdead/session.dat')),
|
|
'u'
|
|
)
|
|
t.is(b4a.toString(await personal.get('/.bare-os/tmp/guest/session.dat')), 'g')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs isolates home and /var/log per HOME basename on personal drive', async (t) => {
|
|
const dir = testCorestoreDir('vfsisol')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvis'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfsGuest = createVfs(sys, personal, {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin'
|
|
})
|
|
await vfsGuest.writeFile('shared-name.txt', b4a.from('guest-data'))
|
|
await vfsGuest.writeFile('/var/log/bare-os/g.log', b4a.from('glog'))
|
|
const vfsUser = createVfs(sys, personal, {
|
|
HOME: '/home/alice12hex',
|
|
PWD: '/home/alice12hex',
|
|
PATH: '/bin'
|
|
})
|
|
t.is(await vfsUser.readFile('/home/alice12hex/shared-name.txt'), null)
|
|
await vfsUser.writeFile('shared-name.txt', b4a.from('user-data'))
|
|
t.is(
|
|
b4a.toString(
|
|
await personal.get(personalHomeBacking('/home/guest', 'shared-name.txt'))
|
|
),
|
|
'guest-data'
|
|
)
|
|
t.is(
|
|
b4a.toString(
|
|
await personal.get(
|
|
personalHomeBacking('/home/alice12hex', 'shared-name.txt')
|
|
)
|
|
),
|
|
'user-data'
|
|
)
|
|
t.is(
|
|
b4a.toString(await personal.get('/.bare-os/var/log/guest/bare-os/g.log')),
|
|
'glog'
|
|
)
|
|
await vfsUser.writeFile('/var/log/bare-os/u.log', b4a.from('ulog'))
|
|
t.is(
|
|
b4a.toString(
|
|
await personal.get('/.bare-os/var/log/alice12hex/bare-os/u.log')
|
|
),
|
|
'ulog'
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('guest VFS denies sensitive /.bare paths; unlocked allows', async (t) => {
|
|
const dir = testCorestoreDir('vfsbarepol')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvpol'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put('/.bare/account', b4a.from('acctblob'))
|
|
await personal.put('/.bare/vault/x', b4a.from('v'))
|
|
const envG = { HOME: '/home/guest', PWD: '/home/guest', PATH: '/bin' }
|
|
const vfsG = createVfs(sys, personal, envG)
|
|
vfsG.bareOsIdentitySession = 'guest'
|
|
t.is(await vfsG.exists('/.bare/account'), false)
|
|
await t.exception(async () => {
|
|
await vfsG.readFile('/.bare/account')
|
|
})
|
|
const envU = {
|
|
HOME: '/home/abc123deadbe',
|
|
PWD: '/home/abc123deadbe',
|
|
PATH: '/bin',
|
|
UID: '999',
|
|
USER: 'abc123deadbe'
|
|
}
|
|
const vfsU = createVfs(sys, personal, envU)
|
|
vfsU.bareOsIdentitySession = 'unlocked'
|
|
t.is(b4a.toString(await vfsU.readFile('/.bare/account')), 'acctblob')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('guest VFS denies /.bare readdir/readFile/writeFile/unlink on sensitive paths', async (t) => {
|
|
const dir = testCorestoreDir('vfsbareguestops')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvbareguestops'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put('/.bare/account', b4a.from('acctblob'))
|
|
|
|
const vfsGuest = createVfs(sys, personal, {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest'
|
|
})
|
|
vfsGuest.bareOsIdentitySession = 'guest'
|
|
|
|
await t.exception(async () => {
|
|
await vfsGuest.readdir('/.bare/account')
|
|
})
|
|
await t.exception(async () => {
|
|
await vfsGuest.readFile('/.bare/account')
|
|
})
|
|
await t.exception(async () => {
|
|
await vfsGuest.writeFile('/.bare/account', b4a.from('mutate'))
|
|
})
|
|
await t.exception(async () => {
|
|
await vfsGuest.unlink('/.bare/account')
|
|
})
|
|
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('BARE_OS_PERSONAL_ACCT_PREFIX scopes /.bare/account to acct subtree on personal drive', async (t) => {
|
|
const dir = testCorestoreDir('vfsbareacctscoped')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvbareacct'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
await personal.put(
|
|
'/.bare-os/acct/u999/.bare/account',
|
|
b4a.from('scoped-acct')
|
|
)
|
|
const envU = {
|
|
HOME: '/home/alice',
|
|
PWD: '/home/alice',
|
|
PATH: '/bin',
|
|
UID: '999',
|
|
USER: 'alice',
|
|
BARE_OS_PERSONAL_ACCT_PREFIX: '1'
|
|
}
|
|
const vfsU = createVfs(sys, personal, envU)
|
|
vfsU.bareOsIdentitySession = 'unlocked'
|
|
t.is(b4a.toString(await vfsU.readFile('/.bare/account')), 'scoped-acct')
|
|
const envG = {
|
|
...envU,
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
UID: '65534'
|
|
}
|
|
const vfsG = createVfs(sys, personal, envG)
|
|
vfsG.bareOsIdentitySession = 'guest'
|
|
t.is(await vfsG.exists('/.bare/account'), false)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('BARE_OS_PERSONAL_ACCT_PREFIX nests guest tmp on personal drive', async (t) => {
|
|
const dir = testCorestoreDir('vfsacct')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvacct'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
BARE_OS_PERSONAL_ACCT_PREFIX: '1'
|
|
}
|
|
const vfs = createVfs(sys, personal, env)
|
|
await vfs.writeFile('/tmp/acct.txt', b4a.from('ok'))
|
|
t.is(
|
|
b4a.toString(await personal.get('/.bare-os/acct/_guest/tmp/guest/acct.txt')),
|
|
'ok'
|
|
)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('BARE_OS_PERSONAL_ACCT_PREFIX: /.bare/holesail/guest shares personal drive root across guest and unlocked', async (t) => {
|
|
const dir = testCorestoreDir('vfsholesailstable')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvhsstable'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const envG = {
|
|
HOME: '/home/guest',
|
|
PWD: '/home/guest',
|
|
PATH: '/bin',
|
|
USER: 'guest',
|
|
UID: '65534',
|
|
GID: '65534',
|
|
BARE_OS_PERSONAL_ACCT_PREFIX: '1'
|
|
}
|
|
const vfsG = createVfs(sys, personal, envG)
|
|
vfsG.bareOsIdentitySession = 'guest'
|
|
const payload = JSON.stringify({
|
|
version: 1,
|
|
connections: { t: { server: true } }
|
|
})
|
|
await vfsG.writeFile('/.bare/holesail/guest/state.json', b4a.from(payload))
|
|
t.alike(JSON.parse(b4a.toString(await personal.get('/.bare/holesail/guest/state.json'))), {
|
|
version: 1,
|
|
connections: { t: { server: true } }
|
|
})
|
|
const envU = {
|
|
HOME: '/home/alicehs',
|
|
PWD: '/home/alicehs',
|
|
PATH: '/bin',
|
|
USER: 'alicehs',
|
|
UID: '1001',
|
|
GID: '1001',
|
|
BARE_OS_PERSONAL_ACCT_PREFIX: '1'
|
|
}
|
|
const vfsU = createVfs(sys, personal, envU)
|
|
vfsU.bareOsIdentitySession = 'unlocked'
|
|
t.alike(JSON.parse(b4a.toString(await vfsU.readFile('/.bare/holesail/guest/state.json'))), {
|
|
version: 1,
|
|
connections: { t: { server: true } }
|
|
})
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs /mnt lists HDMS mounts and allows writable put', async (t) => {
|
|
const dir = testCorestoreDir('vfsmnt')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvm'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = { HOME: '/home/u', PWD: '/home/u', PATH: '/bin', UID: '1000', GID: '1000' }
|
|
const extra = new Hyperdrive(store.namespace('exm', { writable: true }))
|
|
await extra.ready()
|
|
const mntRef = {
|
|
getMounts: () => new Map([['vault', { drive: extra, writable: true }]])
|
|
}
|
|
const vfs = createVfs(sys, personal, env, mntRef)
|
|
const root = await vfs.readdir('/')
|
|
t.ok(root.includes('mnt'))
|
|
t.alike(await vfs.readdir('/mnt'), ['vault'])
|
|
const rootSt = await vfs.lstat('/mnt/vault')
|
|
t.ok(rootSt && rootSt.type === 'directory')
|
|
t.is(rootSt.uid, 1000)
|
|
t.ok((rootSt.mode & 0o200) !== 0, 'writable mount root must allow owner write')
|
|
await vfs.writeFile('/mnt/vault/x.txt', b4a.from('ok'))
|
|
const buf = await extra.get('/x.txt')
|
|
t.ok(buf)
|
|
t.is(b4a.toString(buf), 'ok')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('hdms-share-offer decodeShareOffer parses string and bytes', async (t) => {
|
|
t.is(HDMS_AUTOPASS_SHARE_KEY, 'bare-os-hdms/pending-share')
|
|
t.is(HDMS_AUTOPASS_SHARE_RW_KEY, 'bare-os-hdms/pending-share-rw')
|
|
t.is(decodeShareOffer(null), null)
|
|
t.is(decodeShareOffer({}), null)
|
|
t.is(decodeShareOffer({ value: 'not-json' }), null)
|
|
t.is(decodeShareOffer({ value: '{}' }), null)
|
|
const json = JSON.stringify({ label: 'vol', key: 'abc123' })
|
|
t.alike(decodeShareOffer({ value: json }), { label: 'vol', key: 'abc123' })
|
|
t.alike(decodeShareOffer({ value: b4a.from(json, 'utf8') }), {
|
|
label: 'vol',
|
|
key: 'abc123'
|
|
})
|
|
})
|
|
|
|
test('hdms-share-offer decodeRwShareOffer and normalizeWriterSecretHex', async (t) => {
|
|
const hex = 'a'.repeat(128)
|
|
t.is(normalizeWriterSecretHex(' ' + hex.toUpperCase() + ' '), hex)
|
|
t.exception(() => normalizeWriterSecretHex('ff'), /128 hex/)
|
|
t.is(decodeRwShareOffer(null), null)
|
|
const kp = hcCrypto.keyPair()
|
|
const driveKey = idEnc.encode(kp.publicKey)
|
|
const signerKey = idEnc.encode(kp.publicKey)
|
|
const json = JSON.stringify({
|
|
label: 'v',
|
|
key: driveKey,
|
|
signerKey,
|
|
writerSecretHex: hex
|
|
})
|
|
t.alike(decodeRwShareOffer({ value: json }), {
|
|
label: 'v',
|
|
key: driveKey,
|
|
signerKey,
|
|
writerSecretHex: hex
|
|
})
|
|
t.is(decodeRwShareOffer({ value: '{"label":"x","key":"y","writerSecretHex":"' + hex + '"}' }), null)
|
|
})
|
|
|
|
test('autopass hyperdb legacy value header (type byte omitted)', async (t) => {
|
|
const db = require('autopass/spec/db')
|
|
const records = db.collections[0]
|
|
const keyBuf = records.encodeKey({ key: 'bare-os-hdms/pending-share' })
|
|
const valueBuf = records.encodeValue(1, 1, {
|
|
key: 'bare-os-hdms/pending-share',
|
|
value: '{"label":"x","key":"y"}',
|
|
file: null
|
|
})
|
|
t.ok(records.reconstruct(1, keyBuf, valueBuf))
|
|
const legacyHeader = Buffer.from(valueBuf)
|
|
legacyHeader[0] = 1
|
|
t.ok(records.reconstruct(1, keyBuf, legacyHeader))
|
|
})
|
|
|
|
test('parseHdmsPairArgv flags and invite token', async (t) => {
|
|
t.alike(parseHdmsPairArgv(['--no-persist', 'invitez32']), {
|
|
ok: true,
|
|
persist: false,
|
|
inviteTok: 'invitez32'
|
|
})
|
|
t.alike(parseHdmsPairArgv(['tok2', '--no-persist']), {
|
|
ok: true,
|
|
persist: false,
|
|
inviteTok: 'tok2'
|
|
})
|
|
t.alike(parseHdmsPairArgv(['tok3']), {
|
|
ok: true,
|
|
persist: true,
|
|
inviteTok: 'tok3'
|
|
})
|
|
t.alike(parseHdmsPairArgv(['--persist', 'tok4']), {
|
|
ok: true,
|
|
persist: true,
|
|
inviteTok: 'tok4'
|
|
})
|
|
t.is(parseHdmsPairArgv(['--persist', '--no-persist', 'x']).ok, false)
|
|
t.is(parseHdmsPairArgv([]).ok, false)
|
|
})
|
|
|
|
test('vfs /var in root readdir; /var/log empty lstat; writes map to personal', async (t) => {
|
|
const dir = testCorestoreDir('vfsvar')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvvar'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const env = { HOME: '/home/u', PWD: '/home/u', PATH: '/bin' }
|
|
const vfs = createVfs(sys, personal, env)
|
|
const root = await vfs.readdir('/')
|
|
t.ok(root.includes('var'))
|
|
t.alike(await vfs.readdir('/var'), ['log'])
|
|
const stLog = await vfs.lstat('/var/log')
|
|
t.ok(stLog)
|
|
t.is(stLog.type, 'directory')
|
|
await vfs.mkdir('/var/log/bare-os', { recursive: true })
|
|
await vfs.writeFile('/var/log/bare-os/test-vfs.log', b4a.from('hello'))
|
|
const buf = await personal.get('/.bare-os/var/log/u/bare-os/test-vfs.log')
|
|
t.ok(buf)
|
|
t.is(b4a.toString(buf), 'hello')
|
|
const sysTry = await sys.get('/.bare-os/var/log/u/bare-os/test-vfs.log')
|
|
t.is(sysTry, null)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('vfs chdir /var/log from home', async (t) => {
|
|
const dir = testCorestoreDir('vfsvarcd')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvcv'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const vfs = createVfs(sys, personal, {
|
|
HOME: '/home/u',
|
|
PWD: '/home/u',
|
|
PATH: '/bin'
|
|
})
|
|
await vfs.chdir('/var/log')
|
|
t.is(vfs.getcwd(), '/var/log')
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('appendVarLog increments skip metric when vfs.readFile missing', async (t) => {
|
|
bareOsKernelMetricsReset()
|
|
await appendVarLog(
|
|
{ b4a, env: {}, vfs: { async writeFile() {} } },
|
|
KERNEL_CONSOLE_LOG,
|
|
'x',
|
|
'line'
|
|
)
|
|
const snap = bareOsKernelMetricsSnapshot()
|
|
t.is(snap['varlog.append.skip_no_vfs_readfile'], 1)
|
|
bareOsKernelMetricsReset()
|
|
})
|
|
|
|
test('HOME segment switch needs ensureBareOsVarLogTree before kernel-console read', async (t) => {
|
|
const dir = testCorestoreDir('varloghomeseg')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvhs'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const ctx = testCtx(sys, personal)
|
|
await ensureBareOsVarLogTree(ctx)
|
|
ctx.vfs.env.HOME = '/home/other'
|
|
ctx.vfs.env.PWD = '/home/other'
|
|
let threw = false
|
|
try {
|
|
await ctx.vfs.readFile('/var/log/bare-os/kernel-console.log')
|
|
} catch {
|
|
threw = true
|
|
}
|
|
t.ok(threw, 'traverse fails before bare-os dir exists for new HOME segment')
|
|
await ensureBareOsVarLogTree(ctx)
|
|
const buf = await ctx.vfs.readFile('/var/log/bare-os/kernel-console.log')
|
|
t.is(buf, null)
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|
|
|
|
test('ensureBareOsVarLogTree + appendVarLog populate personal backing', async (t) => {
|
|
const dir = testCorestoreDir('varlogpop')
|
|
const store = new Corestore(dir)
|
|
const sys = new Hyperdrive(store)
|
|
const personal = new Hyperdrive(store.namespace('pvlog'))
|
|
await sys.ready()
|
|
await personal.ready()
|
|
const ctx = testCtx(sys, personal)
|
|
await ensureBareOsVarLogTree(ctx)
|
|
await appendVarLog(ctx, KERNEL_CONSOLE_LOG, 't', 'hello-var-log')
|
|
const backing = await personal.get(
|
|
'/.bare-os/var/log/user/bare-os/kernel-console.log'
|
|
)
|
|
t.ok(backing)
|
|
t.ok(b4a.toString(backing).includes('hello-var-log'))
|
|
const readme = await personal.get('/.bare-os/var/log/user/bare-os/README')
|
|
t.ok(readme && b4a.toString(readme).includes('kernel-console'))
|
|
await store.close()
|
|
rmSync(dir, { recursive: true, force: true })
|
|
})
|