CI/docs: placeholder-baseline --check, seeder↔kernel sync script and docs,
holepunch lockfile drift Markdown dashboard + doc links - disk.os / ctx: replication_operator_sketch schema 5 + corestore stats; protomux extensions proc versioning; HRPC allowlist_sketch schema 3 + versioned stock route table; swarm_health proc + runtime caps paths - Session: BARE_OS_HOSTNAME_SET + ctx.bareOsSetSessionHostname, hostname man, security_posture; export -p in shell - kernel.ext.d: optional provides[] version conflict detection (strict boot); resolver parity + tests; BARE_OS_INIT_DEFER_KERNEL_EXT_GRAPH documented - VFS/policy: mirror/aux read tests, GUEST_BARE_READ_ALL edge negative test; adaptive warm-cache window env documented; microbench note - POSIX: syscalls.json schema 10, posix_fadvise no-op, getconf + conformance matrix sync; posix-issue7-traceability index; handbook/profile/matrix updates - Seeder: pear.multisig hint tests; SCM_RIGHTS unit coverage extended - Regenerated kernel bundle, seeder kernel mirror, posix dashboard, coreutils build/man; booter CHANGELOG maintenance row updated Full npm test / pretest green.
This commit is contained in:
@@ -376,8 +376,10 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
return true
|
||||
}
|
||||
names.sort()
|
||||
/** @type {{ file: string, extId: string, scripts: string[], dependsOn: string[], beforeIds: string[], conflictsWith: string[], signaturePointer?: string }[]} */
|
||||
/** @type {{ file: string, extId: string, scripts: string[], dependsOn: string[], beforeIds: string[], conflictsWith: string[], signaturePointer?: string, provides: { name: string, version: string }[] }[]} */
|
||||
const collected = []
|
||||
/** @type {Map<string, string[]>} */
|
||||
const extIdFiles = new Map()
|
||||
for (const name of names) {
|
||||
if (!name.endsWith('.json')) continue
|
||||
const p = `/etc/bare-os/kernel.ext.d/${name}`
|
||||
@@ -450,6 +452,19 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
const conflictsWith = Array.isArray(pol.conflictsWith)
|
||||
? pol.conflictsWith.map((d) => String(d).trim()).filter(Boolean).slice(0, 16)
|
||||
: []
|
||||
/** @type {{ name: string, version: string }[]} */
|
||||
const provides = Array.isArray(pol.provides)
|
||||
? pol.provides
|
||||
.map((x) => {
|
||||
if (!x || typeof x !== 'object') return null
|
||||
const nm = String(x.name || '').trim()
|
||||
const ver = String(x.version ?? x.semver ?? '').trim()
|
||||
if (!nm || !ver) return null
|
||||
return { name: nm, version: ver }
|
||||
})
|
||||
.filter(Boolean)
|
||||
.slice(0, 16)
|
||||
: []
|
||||
collected.push({
|
||||
file: name,
|
||||
extId,
|
||||
@@ -457,8 +472,11 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
dependsOn,
|
||||
beforeIds,
|
||||
conflictsWith,
|
||||
provides,
|
||||
signaturePointer: sig || undefined
|
||||
})
|
||||
if (!extIdFiles.has(extId)) extIdFiles.set(extId, [])
|
||||
extIdFiles.get(extId).push(name)
|
||||
} catch (e) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
@@ -468,6 +486,59 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
)
|
||||
}
|
||||
}
|
||||
/** @type {string[]} */
|
||||
const duplicateExtIds = []
|
||||
for (const [eid, files] of extIdFiles) {
|
||||
if (files.length > 1) duplicateExtIds.push(eid)
|
||||
}
|
||||
duplicateExtIds.sort()
|
||||
if (duplicateExtIds.length) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.duplicateId',
|
||||
`[kernel.ext.d] duplicate extension id(s): ${duplicateExtIds.join(', ')} — each id must appear in at most one drop-in`
|
||||
)
|
||||
if (strictPol) {
|
||||
await appendKernelExtAuditNdjson(ctx, {
|
||||
event: 'duplicate_ext_id',
|
||||
duplicateExtIds
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
/** @type {Map<string, { extId: string, version: string }>} */
|
||||
const provideNameToOwner = new Map()
|
||||
/** @type {string[]} */
|
||||
const providesVersionConflicts = []
|
||||
for (const e of collected) {
|
||||
for (const pr of e.provides || []) {
|
||||
const prev = provideNameToOwner.get(pr.name)
|
||||
if (prev && prev.version !== pr.version) {
|
||||
providesVersionConflicts.push(
|
||||
`${pr.name}: ${prev.extId}@${prev.version} vs ${e.extId}@${pr.version}`
|
||||
)
|
||||
} else if (!prev) {
|
||||
provideNameToOwner.set(pr.name, { extId: e.extId, version: pr.version })
|
||||
}
|
||||
}
|
||||
}
|
||||
providesVersionConflicts.sort()
|
||||
if (providesVersionConflicts.length) {
|
||||
bootStructuredLog(
|
||||
ctx,
|
||||
'error',
|
||||
'kernelExt.providesConflict',
|
||||
`[kernel.ext.d] conflicting provides version(s): ${providesVersionConflicts.join('; ')}`
|
||||
)
|
||||
if (strictPol) {
|
||||
await appendKernelExtAuditNdjson(ctx, {
|
||||
event: 'provides_version_conflict',
|
||||
conflicts: providesVersionConflicts
|
||||
})
|
||||
return false
|
||||
}
|
||||
}
|
||||
const idToCollected = new Map(collected.map((e) => [e.extId, e]))
|
||||
for (const e of collected) {
|
||||
for (const bid of e.beforeIds) {
|
||||
@@ -584,7 +655,16 @@ async function runKernelExtDropins(ctx, opts = {}) {
|
||||
const extGraphOn =
|
||||
ctx.env?.BARE_OS_KERNEL_EXT_GRAPH === '1' ||
|
||||
ctx.env?.BARE_OS_KERNEL_EXT_GRAPH === 'true'
|
||||
if (extGraphOn && ctx.vfs && typeof ctx.vfs.writeFile === 'function' && ctx.b4a) {
|
||||
const extGraphDefer =
|
||||
ctx.env?.BARE_OS_INIT_DEFER_KERNEL_EXT_GRAPH === '1' ||
|
||||
ctx.env?.BARE_OS_INIT_DEFER_KERNEL_EXT_GRAPH === 'true'
|
||||
if (
|
||||
extGraphOn &&
|
||||
!extGraphDefer &&
|
||||
ctx.vfs &&
|
||||
typeof ctx.vfs.writeFile === 'function' &&
|
||||
ctx.b4a
|
||||
) {
|
||||
let bareModuleTraverse = 'unresolved'
|
||||
try {
|
||||
await import('bare-module-traverse')
|
||||
|
||||
Reference in New Issue
Block a user