import test from 'brittle'
import { execFile, spawnSync } from 'node:child_process'
import { chmod, mkdir, mkdtemp, readFile, rm, symlink, writeFile } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import path from 'node:path'
import { promisify } from 'node:util'
import { publishFleetChannel } from '../../scripts/publish-fleet-channel.mjs'
import { createPublicT1OpsFixture } from '../fixtures/public-hive-gateway-ops.js'
const execFileAsync = promisify(execFile)
const canRunGitSigning = !spawnSync('git', ['--version']).error &&
!spawnSync('ssh-keygen', ['-V']).error
const REPO = '/controller/hiverelay'
const START = 'a'.repeat(40)
const TARGET = 'b'.repeat(40)
const TAG = 'c'.repeat(40)
const PUBLISHED = 'd'.repeat(40)
const PREVIOUS_TARGET_SHA = 'e'.repeat(40)
const PREVIOUS_TAG = '8'.repeat(40)
const BLOB = '9'.repeat(40)
const CHANNELS = `${REPO}/fleet/channels.json`
const ENDPOINT = 'git@example.invalid:hiverelay.git'
const PREDECESSOR_AUTHORITY = [
['fleet/updater.sh', '100755'],
['fleet/quarantine-public-gateway.sh', '100755'],
['scripts/verify-public-hive-gateway-quarantine.mjs', '100644'],
['scripts/lib/public-hive-gateway-quarantine-authority.mjs', '100644'],
['scripts/lib/public-hive-gateway-release-manifest.mjs', '100644'],
['scripts/lib/public-hive-gateway-policy.mjs', '100644']
]
function promotion (status, wouldChange = true) {
return {
schema: 'hiverelay-fleet-channel-promotion-v1',
status,
channel: 'canary',
previousTarget: 'v1.2.2',
target: 'v1.2.3',
tagObjectSha: TAG,
targetSha: TARGET,
channelsPath: CHANNELS,
wouldChange,
publicGatewayRequired: true,
operatorContracts: [],
canaryEvidence: null
}
}
function fixture (opts = {}) {
const trustedFiles = new Map()
const predecessorFiles = new Map()
const trustedPathsByOid = new Map()
let trustedIndex = 1
for (const [name, bytes] of Object.entries(opts.trustedFiles || {})) {
const oid = (trustedIndex++).toString(16).padStart(40, '0')
trustedFiles.set(name, { oid, bytes: Buffer.from(bytes) })
trustedPathsByOid.set(oid, trustedFiles.get(name))
}
if ((opts.operatorContracts || []).length > 0) {
for (const [name, mode] of PREDECESSOR_AUTHORITY) {
const bytes = Buffer.from(`reviewed bootstrap authority ${name}\n`)
const targetOid = (trustedIndex++).toString(16).padStart(40, '0')
const target = { oid: targetOid, bytes, mode }
trustedFiles.set(name, target)
trustedPathsByOid.set(targetOid, target)
if (opts.missingPredecessorPath === name) continue
const previousBytes = opts.predecessorDriftPath === name
? Buffer.from(`drifted predecessor ${name}\n`)
: bytes
const previousOid = opts.predecessorDriftPath === name
? (trustedIndex++).toString(16).padStart(40, '0')
: targetOid
const previous = {
oid: previousOid,
bytes: previousBytes,
mode: opts.predecessorModePath === name ? '120000' : mode
}
predecessorFiles.set(name, previous)
trustedPathsByOid.set(previousOid, previous)
}
}
const state = {
head: START,
remote: START,
changed: [],
staged: [],
commitCreated: false,
pushed: false,
remoteReads: 0,
tagReads: 0,
gitCalls: [],
promoterCalls: [],
expectedCurrentReads: 0,
trustedReads: {}
}
const git = async (args) => {
state.gitCalls.push(args)
const command = args.join(' ')
if (command === 'rev-parse --show-toplevel') return output(REPO)
if (command === 'symbolic-ref --quiet --short HEAD') return output('main')
if (command === 'status --porcelain=v1 -z --untracked-files=all') {
const names = [...state.changed, ...state.staged]
return output(names.map(name => ` M ${name}\0`).join(''))
}
if (command === 'ls-files -v -z') {
return output(opts.hiddenIndexFlag
? `${opts.hiddenIndexFlag} scripts/promote-fleet-channel.mjs\0`
: 'H fleet/allowed-signers\0H fleet/channels.json\0H scripts/promote-fleet-channel.mjs\0')
}
if (command === 'rev-parse --verify HEAD') return output(state.head)
if (command === 'rev-parse --verify HEAD^') return output(START)
if (command === 'rev-parse --verify refs/tags/v1.2.2^{commit}') {
state.expectedCurrentReads++
return output(opts.driftExpectedCurrentAt === state.expectedCurrentReads
? 'f'.repeat(40)
: PREVIOUS_TARGET_SHA)
}
if (command === 'rev-parse --verify refs/tags/v1.2.2^{tag}') return output(PREVIOUS_TAG)
if (command === 'cat-file -t refs/tags/v1.2.2') return output('tag')
if (command.includes('verify-tag --raw v1.2.2')) {
return opts.badPredecessorSignature ? output('signature status unknown') : { stdout: '', stderr: 'GOODSIG trusted predecessor' }
}
if (command === 'config --null --list') {
return output(opts.urlRewrite ? 'url.https://intermediate.invalid/.insteadof\nhttps://trusted.invalid/\0' : '')
}
if (command === 'remote get-url --all origin') return output(opts.fetchUrls || ENDPOINT)
if (command === 'remote get-url --push --all origin') return output(opts.pushUrls || ENDPOINT)
if (command === `ls-remote --exit-code -- ${ENDPOINT} refs/heads/main`) {
state.remoteReads++
if (opts.raceAtRemoteRead === state.remoteReads) state.remote = 'e'.repeat(40)
return output(`${state.remote}\trefs/heads/main`)
}
if (command === `ls-remote --exit-code -- ${ENDPOINT} refs/tags/v1.2.3 refs/tags/v1.2.3^{}`) {
state.tagReads++
const tag = opts.badRemoteTag ? 'f'.repeat(40) : TAG
return output(`${tag}\trefs/tags/v1.2.3\n${TARGET}\trefs/tags/v1.2.3^{}`)
}
if (command === `ls-remote --exit-code -- ${ENDPOINT} refs/tags/v1.2.2 refs/tags/v1.2.2^{}`) {
const tag = opts.badRemotePredecessor ? '7'.repeat(40) : PREVIOUS_TAG
return output(`${tag}\trefs/tags/v1.2.2\n${PREVIOUS_TARGET_SHA}\trefs/tags/v1.2.2^{}`)
}
if (command === 'diff --name-only -z') return output(nul(state.changed))
if (command === 'diff --cached --name-only -z') return output(nul(state.staged))
if (command === 'ls-files --others --exclude-standard -z') return output('')
if (command === 'diff --check -- fleet/channels.json') return output('')
if (command === 'add -- fleet/channels.json') {
state.staged = [...state.changed]
state.changed = []
return output('')
}
if (command === 'ls-files --stage -z -- fleet/channels.json') {
return output(`${opts.indexMode || '100644'} ${opts.indexBlob || BLOB} 0\tfleet/channels.json\0`)
}
if (command.startsWith('-c core.hooksPath=/dev/null -c gpg.format=ssh commit -S -m fleet: promote canary to v1.2.3')) {
if (opts.commitFails) throw new Error('commit failed')
state.staged = []
state.head = PUBLISHED
state.commitCreated = true
return output('committed')
}
if (command === 'diff-tree --no-commit-id --name-only -r -z HEAD') {
return output(opts.commitFiles ? nul(opts.commitFiles) : 'fleet/channels.json\0')
}
if (command === 'ls-tree -z HEAD -- fleet/channels.json') {
return output(`${opts.commitMode || '100644'} blob ${opts.commitBlob || BLOB}\tfleet/channels.json\0`)
}
if (args[0] === 'ls-tree' && args[1] === '-z' && [TARGET, PREVIOUS_TARGET_SHA].includes(args[2]) && args[3] === '--') {
const name = args[4]
const file = (args[2] === TARGET ? trustedFiles : predecessorFiles).get(name)
return output(file ? `${file.mode || '100644'} blob ${file.oid}\t${name}\0` : '')
}
if (args[0] === 'cat-file' && args[1] === 'blob' && trustedPathsByOid.has(args[2])) {
const file = trustedPathsByOid.get(args[2])
const name = [...trustedFiles, ...predecessorFiles].find(([, value]) => value === file)?.[0] || args[2]
state.trustedReads[name] = (state.trustedReads[name] || 0) + 1
if (opts.onTrustedRead) await opts.onTrustedRead(name, state.trustedReads[name])
return { stdout: file.bytes, stderr: '' }
}
if (command.includes('verify-commit --raw')) {
if (opts.badSignature) return output('signature status unknown')
return { stdout: '', stderr: 'GOODSIG trusted publisher' }
}
if (command === `-c core.hooksPath=/dev/null push --atomic --porcelain --no-follow-tags --force-with-lease=refs/heads/main:${START} --force-with-lease=refs/tags/v1.2.3:${TAG} -- ${ENDPOINT} ${TAG}:refs/tags/v1.2.3 ${PUBLISHED}:refs/heads/main`) {
state.remote = state.head
state.pushed = true
return output('ok')
}
throw new Error(`unexpected git command: ${command}`)
}
const promote = async (args) => {
state.promoterCalls.push(args)
const dryRun = args.includes('--dry-run')
if (!dryRun) {
state.changed = opts.changedFiles || ['fleet/channels.json']
}
const result = promotion(dryRun ? 'dry-run' : (opts.wouldChange === false ? 'unchanged' : 'updated'),
opts.wouldChange !== false)
if (!dryRun && opts.appliedPreviousTarget) result.previousTarget = opts.appliedPreviousTarget
result.operatorContracts = structuredClone(opts.operatorContracts || [])
return result
}
const deriveChannels = async () => ({ blobOid: BLOB })
const pinAllowedSigners = async source => ({ path: source, cleanup: async () => {} })
return { state, git, promote, deriveChannels, pinAllowedSigners }
}
test('fleet channel publisher - default is a remote-bound validation-only dry run', async (t) => {
const harness = fixture()
const result = await publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3'
}, harness)
t.is(result.status, 'dry-run')
t.ok(result.publicGatewayRequired)
t.ok(result.wouldChange)
t.is(harness.state.promoterCalls.length, 1)
t.ok(harness.state.promoterCalls[0].includes('--dry-run'))
t.absent(harness.state.commitCreated)
t.absent(harness.state.pushed)
})
test('fleet channel publisher - public-t1 publication requires fresh signed-contract ops evidence', async (t) => {
const root = await mkdtemp(path.join(tmpdir(), 'hiverelay-publisher-ops-'))
t.teardown(() => rm(root, { recursive: true, force: true }))
const evidenceDirectory = path.join(root, 'ops')
await mkdir(evidenceDirectory)
const ops = createPublicT1OpsFixture({ releaseSha: TARGET })
const evidencePath = path.join(evidenceDirectory, `${ops.contract.relay}.json`)
await writeFile(evidencePath, ops.evidenceBytes)
const trustedFiles = {
'fleet/public-hive-gateway-release.json': ops.manifestBytes,
[ops.contractPath]: ops.contractBytes
}
const missing = fixture({ operatorContracts: [ops.binding], trustedFiles })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3'
}, missing), /--gateway-ops-evidence-dir is required/)
const harness = fixture({ operatorContracts: [ops.binding], trustedFiles })
const result = await publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
gatewayOpsEvidenceDir: evidenceDirectory
}, harness)
t.is(result.status, 'dry-run')
t.is(result.operatorContracts.length, 1)
t.is(result.operatorContracts[0].relay, ops.contract.relay)
t.is(result.operatorContracts[0].operatorContractSha256, ops.operatorContractSha256)
t.is(result.operatorContracts[0].suffix, ops.contract.suffix)
t.is(result.predecessorAuthority.target, 'v1.2.2')
t.is(result.predecessorAuthority.commitSha, PREVIOUS_TARGET_SHA)
t.is(result.predecessorAuthority.files.length, PREDECESSOR_AUTHORITY.length)
const linkedDirectory = path.join(root, 'linked-ops')
await symlink(evidenceDirectory, linkedDirectory)
const linkedHarness = fixture({ operatorContracts: [ops.binding], trustedFiles })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
gatewayOpsEvidenceDir: linkedDirectory
}, linkedHarness), /existing non-symlink directory/)
const stale = structuredClone(ops.evidence)
stale.checkedAt = new Date(Date.now() - 16 * 60 * 1000).toISOString()
await writeFile(evidencePath, JSON.stringify(stale) + '\n')
const staleHarness = fixture({ operatorContracts: [ops.binding], trustedFiles })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
gatewayOpsEvidenceDir: evidenceDirectory
}, staleHarness), /15 minutes/)
await writeFile(evidencePath, ops.evidenceBytes)
const driftHarness = fixture({
operatorContracts: [ops.binding],
trustedFiles,
onTrustedRead: async (name, count) => {
if (name === ops.contractPath && count === 2) {
await writeFile(evidencePath, JSON.stringify(ops.evidence, null, 2) + '\n')
}
}
})
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
gatewayOpsEvidenceDir: evidenceDirectory,
publish: true
}, driftHarness), /readiness evidence changed after publication validation/)
t.absent(driftHarness.state.commitCreated, 'ops evidence drift stops before control-plane mutation')
const legacy = fixture()
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
gatewayOpsEvidenceDir: evidenceDirectory
}, legacy), /valid only for a public-t1-gateway release/)
})
test('fleet channel publisher - enabled gateway requires blob-identical predecessor authority', async (t) => {
const root = await mkdtemp(path.join(tmpdir(), 'hiverelay-publisher-predecessor-'))
t.teardown(() => rm(root, { recursive: true, force: true }))
const evidenceDirectory = path.join(root, 'ops')
await mkdir(evidenceDirectory)
const ops = createPublicT1OpsFixture({ releaseSha: TARGET })
await writeFile(path.join(evidenceDirectory, `${ops.contract.relay}.json`), ops.evidenceBytes)
const trustedFiles = {
'fleet/public-hive-gateway-release.json': ops.manifestBytes,
[ops.contractPath]: ops.contractBytes
}
const input = {
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
gatewayOpsEvidenceDir: evidenceDirectory
}
for (const [options, expected] of [
[{ predecessorDriftPath: PREDECESSOR_AUTHORITY[0][0] }, /blob-identical fleet\/updater\.sh/],
[{ predecessorDriftPath: 'fleet/quarantine-public-gateway.sh' }, /blob-identical fleet\/quarantine-public-gateway\.sh/],
[{ missingPredecessorPath: PREDECESSOR_AUTHORITY[2][0] }, /must be one tracked 100644 regular blob/],
[{ predecessorModePath: PREDECESSOR_AUTHORITY[3][0] }, /must be one tracked 100644 regular blob/],
[{ badPredecessorSignature: true }, /did not report a trusted signature/],
[{ badRemotePredecessor: true }, /does not match its trusted local tag/]
]) {
const harness = fixture({ operatorContracts: [ops.binding], trustedFiles, ...options })
await t.exception(async () => publishFleetChannel(input, harness), expected)
t.absent(harness.state.commitCreated)
t.absent(harness.state.pushed)
}
})
test('fleet channel publisher - publishes one trusted signed non-force control commit', async (t) => {
const harness = fixture()
const result = await publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness)
t.is(result.status, 'published')
t.is(result.startingHead, START)
t.is(result.publishedHead, PUBLISHED)
t.is(result.remoteHead, PUBLISHED)
t.is(harness.state.promoterCalls.length, 2)
t.ok(harness.state.promoterCalls[0].includes('--dry-run'))
t.absent(harness.state.promoterCalls[1].includes('--dry-run'))
t.ok(harness.state.commitCreated)
t.ok(harness.state.pushed)
t.is(harness.state.tagReads, 4, 'remote release tag is pinned before mutation, atomically during push, and after publication')
const push = harness.state.gitCalls.find(args => args.includes('push'))
t.alike(push, [
'-c', 'core.hooksPath=/dev/null',
'push', '--atomic', '--porcelain', '--no-follow-tags',
`--force-with-lease=refs/heads/main:${START}`,
`--force-with-lease=refs/tags/v1.2.3:${TAG}`,
'--', ENDPOINT,
`${TAG}:refs/tags/v1.2.3`,
`${PUBLISHED}:refs/heads/main`
])
t.absent(push.includes('--force'), 'publisher has no unguarded force update')
})
test('fleet channel publisher - forward recovery CAS binds the starting tag and commit through mutation', async (t) => {
const valid = fixture()
const result = await publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
expectedCurrentTarget: 'v1.2.2',
expectedCurrentTargetSha: PREVIOUS_TARGET_SHA
}, valid)
t.is(result.status, 'dry-run')
t.is(valid.state.expectedCurrentReads, 1)
const wrongTag = fixture()
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
expectedCurrentTarget: 'v1.2.1',
expectedCurrentTargetSha: PREVIOUS_TARGET_SHA,
publish: true
}, wrongTag), /does not match the recovery expected-current target/)
t.absent(wrongTag.state.commitCreated)
const wrongSha = fixture()
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
expectedCurrentTarget: 'v1.2.2',
expectedCurrentTargetSha: '1'.repeat(40),
publish: true
}, wrongSha), /target SHA does not match the recovery receipt/)
t.absent(wrongSha.state.commitCreated)
const tagRace = fixture({ driftExpectedCurrentAt: 2 })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
expectedCurrentTarget: 'v1.2.2',
expectedCurrentTargetSha: PREVIOUS_TARGET_SHA,
publish: true
}, tagRace), /target SHA does not match the recovery receipt/)
t.is(tagRace.state.promoterCalls.length, 1, 'expected-current tag race stops before the applying promoter')
t.absent(tagRace.state.commitCreated)
const appliedDrift = fixture({ appliedPreviousTarget: 'v1.2.1' })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
expectedCurrentTarget: 'v1.2.2',
expectedCurrentTargetSha: PREVIOUS_TARGET_SHA,
publish: true
}, appliedDrift), /promotion result changed between validation and application/)
t.absent(appliedDrift.state.commitCreated)
t.absent(appliedDrift.state.pushed)
})
test('fleet channel publisher - remote tag substitution fails before mutation', async (t) => {
const harness = fixture({ badRemoteTag: true })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness), /does not match the locally verified signed tag/)
t.is(harness.state.promoterCalls.length, 1)
t.absent(harness.state.commitCreated)
t.absent(harness.state.pushed)
})
test('fleet channel publisher - URL rewrites and split push destinations fail before promotion', async (t) => {
for (const options of [
{ urlRewrite: true },
{ pushUrls: `${ENDPOINT}\ngit@backup.invalid:hiverelay.git` },
{ fetchUrls: ENDPOINT, pushUrls: 'git@other.invalid:hiverelay.git' }
]) {
const harness = fixture(options)
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness), /URL rewrite configuration is forbidden|exactly one identical fetch and push endpoint/)
t.is(harness.state.promoterCalls.length, 0)
t.absent(harness.state.pushed)
}
})
test('fleet channel publisher - concealed tracked changes fail before promotion', async (t) => {
for (const hiddenIndexFlag of ['h', 'S']) {
const harness = fixture({ hiddenIndexFlag })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness), /forbids assume-unchanged, skip-worktree/)
t.is(harness.state.promoterCalls.length, 0)
t.absent(harness.state.pushed)
}
})
test('fleet channel publisher - remote races stop before local mutation', async (t) => {
const harness = fixture({ raceAtRemoteRead: 2 })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness), /changed after validation/)
t.is(harness.state.promoterCalls.length, 1)
t.absent(harness.state.commitCreated)
t.absent(harness.state.pushed)
})
test('fleet channel publisher - promoter side effects outside channels fail closed', async (t) => {
const harness = fixture({ changedFiles: ['fleet/channels.json', 'fleet/relays.json'] })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness), /outside fleet\/channels\.json/)
t.absent(harness.state.commitCreated)
t.absent(harness.state.pushed)
})
test('fleet channel publisher - staged and committed channel bytes and mode are exact', async (t) => {
for (const options of [
{ indexBlob: '8'.repeat(40) },
{ indexMode: '120000' },
{ commitBlob: '7'.repeat(40) },
{ commitMode: '100755' }
]) {
const harness = fixture(options)
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness), /channel mode or bytes changed|unvalidated channel mode or blob/)
t.absent(harness.state.pushed)
}
})
test('fleet channel publisher - untrusted commit signature never reaches push', async (t) => {
const harness = fixture({ badSignature: true })
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'canary',
target: 'v1.2.3',
publish: true
}, harness), /did not report a trusted signature/)
t.ok(harness.state.commitCreated, 'signed local commit is retained for inspection')
t.absent(harness.state.pushed)
})
test('fleet channel publisher - stable remains an explicit evidence-bound operation', async (t) => {
const harness = fixture()
await t.exception(async () => publishFleetChannel({
repo: REPO,
channel: 'stable',
target: 'v1.2.3',
publish: true
}, harness), /--canary-evidence is required/)
t.is(harness.state.gitCalls.length, 0)
t.is(harness.state.promoterCalls.length, 0)
})
test('fleet channel publisher - real Git integration signs and publishes only channels.json', {
skip: !canRunGitSigning,
timeout: 30_000
}, async (t) => {
const root = await mkdtemp(path.join(tmpdir(), 'hiverelay-publisher-'))
const repo = path.join(root, 'repo')
const remote = path.join(root, 'remote.git')
const key = path.join(root, 'publisher-key')
const hooks = path.join(root, 'hostile-hooks')
const hookMarker = path.join(hooks, 'ran')
try {
await gitAt(root, ['init', '--bare', remote])
await gitAt(root, ['init', '-b', 'main', repo])
await gitAt(repo, ['config', 'user.name', 'Fleet Publisher'])
await gitAt(repo, ['config', 'user.email', 'publisher@example.test'])
await gitAt(repo, ['config', 'gpg.format', 'ssh'])
await execFileAsync('ssh-keygen', ['-q', '-t', 'ed25519', '-N', '', '-f', key])
await gitAt(repo, ['config', 'user.signingkey', key])
await mkdir(path.join(repo, 'fleet'), { recursive: true })
await mkdir(path.join(repo, 'scripts', 'lib'), { recursive: true })
await writeFile(path.join(repo, 'fleet', 'channels.json'), JSON.stringify({
stable: 'v1.2.2',
canary: 'v1.2.2'
}, null, 2) + '\n')
await writeFile(path.join(repo, 'package.json'), '{"version":"1.2.3"}\n')
const trustedPromoter = await readFile('scripts/promote-fleet-channel.mjs')
const trustedManifestLibrary = await readFile('scripts/lib/public-hive-gateway-release-manifest.mjs')
const trustedPolicyLibrary = await readFile('scripts/lib/public-hive-gateway-policy.mjs')
await writeFile(path.join(repo, 'scripts', 'promote-fleet-channel.mjs'), trustedPromoter)
await writeFile(path.join(repo, 'scripts', 'lib', 'public-hive-gateway-release-manifest.mjs'),
trustedManifestLibrary)
await writeFile(path.join(repo, 'scripts', 'lib', 'public-hive-gateway-policy.mjs'),
trustedPolicyLibrary)
const publicKey = (await readFile(`${key}.pub`, 'utf8')).trim().split(/\s+/).slice(0, 2).join(' ')
await writeFile(path.join(repo, 'fleet', 'allowed-signers'), `publisher@example.test ${publicKey}\n`)
await gitAt(repo, ['add', 'fleet/channels.json', 'fleet/allowed-signers', 'package.json', 'scripts'])
await gitAt(repo, ['commit', '-m', 'initial control state'])
await gitAt(repo, ['-c', 'gpg.format=ssh', 'tag', '-s', '-m', 'v1.2.3 release', 'v1.2.3'])
await gitAt(repo, ['remote', 'add', 'origin', remote])
await gitAt(repo, ['push', '-u', 'origin', 'main'])
await gitAt(repo, ['push', 'origin', 'refs/tags/v1.2.3'])
const targetSha = (await gitAt(repo, ['rev-parse', 'v1.2.3^{}'])).stdout.trim()
const maliciousChannels = path.join(root, 'replacement-channels.json')
const replacementIndex = path.join(root, 'replacement.index')
await writeFile(maliciousChannels, JSON.stringify({
stable: 'v0.0.0',
canary: 'v1.2.2'
}, null, 2) + '\n')
const maliciousBlob = (await gitAt(repo, ['hash-object', '-w', '--', maliciousChannels])).stdout.trim()
const replacementEnv = { GIT_INDEX_FILE: replacementIndex }
await gitAt(repo, ['read-tree', targetSha], { env: replacementEnv })
await gitAt(repo, [
'update-index', '--add', '--cacheinfo', `100644,${maliciousBlob},fleet/channels.json`
], { env: replacementEnv })
const replacementTree = (await gitAt(repo, ['write-tree'], { env: replacementEnv })).stdout.trim()
const replacementCommit = (await gitAt(repo, [
'commit-tree', replacementTree, '-m', 'hostile replacement commit'
])).stdout.trim()
await gitAt(repo, ['replace', targetSha, replacementCommit])
t.is(JSON.parse((await gitAt(repo, ['show', 'HEAD:fleet/channels.json'])).stdout).stable, 'v0.0.0',
'hostile replace ref is active in the fixture')
await mkdir(path.join(repo, '.git', 'info'), { recursive: true })
await writeFile(path.join(repo, '.git', 'info', 'grafts'), `${targetSha} ${replacementCommit}\n`)
t.is((await gitAt(repo, ['--no-replace-objects', 'rev-parse', 'HEAD^'])).stdout.trim(), replacementCommit,
'legacy graft is active in the fixture')
const cleanFilterSource = path.join(root, 'trusted-promoter.mjs')
await writeFile(cleanFilterSource, trustedPromoter)
await writeFile(path.join(repo, '.git', 'info', 'attributes'),
'scripts/promote-fleet-channel.mjs filter=publisher-test\n')
await gitAt(repo, ['config', 'filter.publisher-test.clean', `/bin/cat ${cleanFilterSource}`])
await gitAt(repo, ['config', 'filter.publisher-test.required', 'true'])
await writeFile(path.join(repo, 'scripts', 'promote-fleet-channel.mjs'),
'throw new Error("hostile worktree promoter executed")\n')
await gitAt(repo, ['add', '--', 'scripts/promote-fleet-channel.mjs'])
const concealedStatus = (await gitAt(repo, ['--no-replace-objects', 'status', '--porcelain'], {
env: { GIT_GRAFT_FILE: '/dev/null/hiverelay-disabled' }
})).stdout
t.is(concealedStatus, '', 'hostile clean filter conceals the raw promoter change')
await gitAt(repo, ['-c', 'gpg.format=ssh', 'tag', '-s', '-m', 'unrelated release', 'v9.9.9'])
await gitAt(repo, ['config', 'push.followTags', 'true'])
await mkdir(hooks)
for (const name of ['post-index-change', 'post-commit', 'pre-push']) {
const hook = path.join(hooks, name)
await writeFile(hook, `#!/bin/sh\nprintf ${name} >> "$(dirname "$0")/ran"\n`)
await chmod(hook, 0o755)
}
await gitAt(repo, ['config', 'core.hooksPath', hooks])
const poisonedGitEnv = {
GIT_CONFIG_COUNT: '1',
GIT_CONFIG_KEY_0: 'url.git@evil.invalid:.insteadOf',
GIT_CONFIG_VALUE_0: ENDPOINT,
GIT_DIR: remote,
GIT_INDEX_FILE: replacementIndex,
GIT_WORK_TREE: repo
}
const savedGitEnv = Object.fromEntries(Object.keys(poisonedGitEnv).map(name => [name, process.env[name]]))
Object.assign(process.env, poisonedGitEnv)
let result
try {
result = await publishFleetChannel({
repo,
channel: 'canary',
target: 'v1.2.3',
publish: true
})
} finally {
for (const [name, value] of Object.entries(savedGitEnv)) {
if (value === undefined) delete process.env[name]
else process.env[name] = value
}
}
t.is(result.status, 'published')
t.is(result.publishedHead, result.remoteHead)
t.is(await readFile(hookMarker, 'utf8').catch(() => null), null,
'local index/commit/push hooks never execute')
const changed = (await gitAt(repo, [
'--no-replace-objects', 'diff-tree', '--no-commit-id', '--name-only', '-r', result.publishedHead
], { env: { GIT_GRAFT_FILE: '/dev/null/hiverelay-disabled' } })).stdout.trim()
t.is(changed, 'fleet/channels.json')
const remoteChannels = (await gitAt(root, [
'--git-dir', remote, 'show', 'main:fleet/channels.json'
])).stdout
t.is(JSON.parse(remoteChannels).canary, 'v1.2.3')
t.is(JSON.parse(remoteChannels).stable, 'v1.2.2', 'replace ref cannot alter the other channel')
t.is((await gitAt(repo, ['--no-replace-objects', 'status', '--porcelain'], {
env: { GIT_GRAFT_FILE: '/dev/null/hiverelay-disabled' }
})).stdout, '')
const remoteFiles = (await gitAt(root, [
'--git-dir', remote, 'ls-tree', '-r', '--name-only', 'main'
])).stdout.trim().split('\n')
t.alike(remoteFiles, [
'fleet/allowed-signers',
'fleet/channels.json',
'package.json',
'scripts/lib/public-hive-gateway-policy.mjs',
'scripts/lib/public-hive-gateway-release-manifest.mjs',
'scripts/promote-fleet-channel.mjs'
])
const remotePromoter = (await gitAt(root, [
'--git-dir', remote, 'show', 'main:scripts/promote-fleet-channel.mjs'
])).stdout
t.absent(remotePromoter.includes('hostile worktree promoter executed'),
'only trusted HEAD promoter code reaches the remote')
t.is((await gitAt(repo, ['ls-remote', 'origin', 'refs/tags/v9.9.9'])).stdout, '',
'push.followTags cannot publish unrelated tags')
} finally {
await rm(root, { recursive: true, force: true })
}
})
function output (stdout) {
return { stdout: `${stdout}${stdout && !stdout.endsWith('\0') ? '\n' : ''}`, stderr: '' }
}
function nul (values) {
return values.length ? `${values.join('\0')}\0` : ''
}
async function gitAt (cwd, args, options = {}) {
return execFileAsync('git', args, {
cwd,
encoding: 'utf8',
env: { ...process.env, ...(options.env || {}) },
maxBuffer: 2 * 1024 * 1024,
timeout: 15_000
})
}