- Bump BARE_OS_CTX_API_VERSION to 1.54.0 and POSIX profile to 1.0.19 - Process table schema 9: nice/accountingSource, logical maps/threads /proc builders, renice - disk.os: replication_operator_sketch v8, HyperDHT address sketch, pkg index surfaces - Protomux operator sketch v4, security_posture v7, corestore snapshot UX hint, pear_stage_pointer v2 - Swarm: BARE_OS_SWARM_ATTEMPT_BURST_PER_SEC; HDMS: host booter warn logging; shell wait exit codes - getconf/sysconf: additional _SC_* via bareOsGetconfSysconf; socketMsgSurface v6 (iovec/SUSv4 refs) - Identity: vault rotation audit includes pathcap trusted key count - CI/docs: holepunch drift report env, kernel STRUCTURE note, verify-bundle-throws comment, matrices and examples
195 lines
6.0 KiB
JavaScript
195 lines
6.0 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* Default pretest gate: when `docs/audit/holepunch-drift-repos.json` lists repos, ensure
|
|
* local clones under `BARE_OS_HOLEPUNCH_CLONES_ROOT` are not behind `origin/main`.
|
|
* Disable with `BARE_OS_HOLEPUNCH_DRIFT_CHECK=0` (offline / no clones).
|
|
*
|
|
* Optional maintainer gate: `BARE_OS_HOLEPUNCH_DRIFT_TIER1=1` checks **`tier1Repos[]`**
|
|
* from the same JSON (ignores **`repos[]`**), for a small Holepunch spine set.
|
|
*
|
|
* Prereq: `git fetch origin main` in each clone so origin/main is meaningful.
|
|
* Config: docs/audit/holepunch-drift-repos.json → { repos: ["name", ...] }
|
|
* Clones root: BARE_OS_HOLEPUNCH_CLONES_ROOT (same default as sync-holepunch-clones.mjs)
|
|
*/
|
|
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
import process from 'node:process'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { execSync } from 'node:child_process'
|
|
|
|
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
const configPath = path.join(root, 'docs/audit/holepunch-drift-repos.json')
|
|
|
|
const defaultClones = path.join(
|
|
process.env.HOME || '',
|
|
'dev/pearcli/holepunch-repos/holepunchto_repos'
|
|
)
|
|
const clonesRoot = String(
|
|
process.env.BARE_OS_HOLEPUNCH_CLONES_ROOT || defaultClones
|
|
).trim()
|
|
|
|
function gitOk(cmd, cwd) {
|
|
try {
|
|
execSync(cmd, {
|
|
cwd,
|
|
encoding: 'utf8',
|
|
stdio: ['ignore', 'pipe', 'ignore']
|
|
})
|
|
return true
|
|
} catch {
|
|
return false
|
|
}
|
|
}
|
|
|
|
/** @param {string} dir */
|
|
function gitCommitsBehindOriginMain(dir) {
|
|
try {
|
|
const o = execSync('git rev-list --count HEAD..origin/main', {
|
|
cwd: dir,
|
|
encoding: 'utf8',
|
|
stdio: ['ignore', 'pipe', 'ignore']
|
|
}).trim()
|
|
const n = Number.parseInt(o, 10)
|
|
return Number.isFinite(n) ? n : -1
|
|
} catch {
|
|
return -1
|
|
}
|
|
}
|
|
|
|
function main() {
|
|
const off =
|
|
process.env.BARE_OS_HOLEPUNCH_DRIFT_CHECK === '0' ||
|
|
process.env.BARE_OS_HOLEPUNCH_DRIFT_CHECK === 'false'
|
|
if (off) {
|
|
console.log(
|
|
'verify-holepunch-clone-drift: skip (BARE_OS_HOLEPUNCH_DRIFT_CHECK=0)'
|
|
)
|
|
return
|
|
}
|
|
if (!fs.existsSync(configPath)) {
|
|
console.error('verify-holepunch-clone-drift: missing', configPath)
|
|
process.exit(1)
|
|
}
|
|
let cfg
|
|
try {
|
|
cfg = JSON.parse(fs.readFileSync(configPath, 'utf8'))
|
|
} catch (e) {
|
|
console.error('verify-holepunch-clone-drift: parse config failed', e)
|
|
process.exit(1)
|
|
}
|
|
const tier1 =
|
|
process.env.BARE_OS_HOLEPUNCH_DRIFT_TIER1 === '1' ||
|
|
process.env.BARE_OS_HOLEPUNCH_DRIFT_TIER1 === 'true'
|
|
let repos = Array.isArray(cfg.repos)
|
|
? cfg.repos.map((r) => String(r).trim()).filter(Boolean)
|
|
: []
|
|
if (tier1) {
|
|
repos = Array.isArray(cfg.tier1Repos)
|
|
? cfg.tier1Repos.map((r) => String(r).trim()).filter(Boolean)
|
|
: []
|
|
if (!repos.length) {
|
|
console.log(
|
|
'verify-holepunch-clone-drift: tier1 mode but tier1Repos[] empty — nothing to check'
|
|
)
|
|
return
|
|
}
|
|
console.log(
|
|
'verify-holepunch-clone-drift: tier1 mode — checking',
|
|
repos.length,
|
|
'repo(s)'
|
|
)
|
|
} else if (!repos.length) {
|
|
console.log('verify-holepunch-clone-drift: repos[] empty — nothing to check')
|
|
return
|
|
}
|
|
let failed = false
|
|
/** @type {{ name: string, commitsBehind: number }[]} */
|
|
const behindReport = []
|
|
for (const name of repos) {
|
|
const dir = path.join(clonesRoot, name)
|
|
if (!fs.existsSync(dir)) {
|
|
console.warn(
|
|
'verify-holepunch-clone-drift: skip missing clone',
|
|
path.relative(root, dir)
|
|
)
|
|
continue
|
|
}
|
|
if (!gitOk('git rev-parse --git-dir', dir)) {
|
|
console.warn('verify-holepunch-clone-drift: skip non-git', name)
|
|
continue
|
|
}
|
|
const hasOriginMain = gitOk('git rev-parse --verify origin/main', dir)
|
|
if (!hasOriginMain) {
|
|
console.warn(
|
|
'verify-holepunch-clone-drift: no origin/main in',
|
|
name,
|
|
'(run git fetch origin main)'
|
|
)
|
|
continue
|
|
}
|
|
const upToDate = gitOk(
|
|
'git merge-base --is-ancestor origin/main HEAD',
|
|
dir
|
|
)
|
|
if (!upToDate) {
|
|
const commitsBehind = gitCommitsBehindOriginMain(dir)
|
|
behindReport.push({ name, commitsBehind })
|
|
console.error(
|
|
'verify-holepunch-clone-drift: clone is behind origin/main:',
|
|
name,
|
|
commitsBehind >= 0 ? `(~${commitsBehind} commits behind)` : ''
|
|
)
|
|
failed = true
|
|
}
|
|
}
|
|
if (failed) {
|
|
behindReport.sort((a, b) => b.commitsBehind - a.commitsBehind)
|
|
const top = behindReport.slice(0, 12)
|
|
console.error(
|
|
'verify-holepunch-clone-drift: repos most behind origin/main (actionable PR order):'
|
|
)
|
|
for (const r of top) {
|
|
console.error(
|
|
` - ${r.name}: ~${r.commitsBehind >= 0 ? r.commitsBehind : '?'} commits`
|
|
)
|
|
}
|
|
console.error(
|
|
'verify-holepunch-clone-drift: cross-check lockfile vs clones: node scripts/report-holepunch-lockfile-drift.mjs'
|
|
)
|
|
console.error(
|
|
'verify-holepunch-clone-drift: FAIL — pull or fetch listed clones, or trim docs/audit/holepunch-drift-repos.json (see handbook ch.7 / scripts/release-checklist.mjs)'
|
|
)
|
|
process.exit(1)
|
|
}
|
|
const writeReport =
|
|
process.env.BARE_OS_HOLEPUNCH_DRIFT_WRITE_REPORT === '1' ||
|
|
process.env.BARE_OS_HOLEPUNCH_DRIFT_WRITE_REPORT === 'true'
|
|
if (writeReport) {
|
|
const outMd = path.join(root, 'docs/audit/holepunch-drift-last-run.md')
|
|
const lines = [
|
|
'# Holepunch clone drift (last verify)',
|
|
'',
|
|
`Generated: ${new Date().toISOString()}`,
|
|
'',
|
|
'All listed clones were at or ahead of `origin/main` when this file was written.',
|
|
'',
|
|
`Mode: ${tier1 ? 'tier1Repos[]' : 'repos[]'}`,
|
|
'',
|
|
'Repos checked:',
|
|
...repos.map((n) => `- ${n}`),
|
|
'',
|
|
'Re-run: `BARE_OS_HOLEPUNCH_DRIFT_WRITE_REPORT=1 npm run pretest` (or run this script directly after `git fetch`).',
|
|
''
|
|
]
|
|
try {
|
|
fs.mkdirSync(path.dirname(outMd), { recursive: true })
|
|
fs.writeFileSync(outMd, lines.join('\n'), 'utf8')
|
|
} catch (e) {
|
|
console.warn('verify-holepunch-clone-drift: could not write report', e)
|
|
}
|
|
}
|
|
console.log('verify-holepunch-clone-drift: OK')
|
|
}
|
|
|
|
main()
|