import test from 'brittle'
import {
formatWorktreeSummary,
parseReleaseBlockers,
renderShipHandoff
} from '../../scripts/update-ship-handoff.mjs'
const BLOCKER_STDERR = `Release distribution preflight failed:
- UMBREL_STORE_TOKEN must be a GitHub token without whitespace or control characters
- UMBREL_OFFICIAL_PR_TOKEN must be a GitHub token without whitespace or control characters
- UMBREL_OFFICIAL_FORK must be a GitHub owner/umbrel-apps fork slug with a normal owner name and must not be getumbrel/umbrel-apps
- STARTOS_REGISTRY_URL must be a public https URL without embedded credentials, query strings, fragments, or reserved/local hostnames
Repair path:
- Generate the targeted issue #120 repair file outside the repo: npm run release:write-secret-template -- --issue-120-repair --out /private/tmp/hiverelay-release-secrets.env
- Validate without publishing: npm run release:check-distribution-env -- --issue-120-repair --env-file /private/tmp/hiverelay-release-secrets.env
`
test('ship handoff updater parses release blocker facts from preflight stderr', (t) => {
t.alike(parseReleaseBlockers(BLOCKER_STDERR), [
'UMBREL_STORE_TOKEN must be a GitHub token without whitespace or control characters',
'UMBREL_OFFICIAL_PR_TOKEN must be a GitHub token without whitespace or control characters',
'UMBREL_OFFICIAL_FORK must be a GitHub owner/umbrel-apps fork slug with a normal owner name and must not be getumbrel/umbrel-apps',
'STARTOS_REGISTRY_URL must be a public https URL without embedded credentials, query strings, fragments, or reserved/local hostnames'
])
})
test('ship handoff updater renders git and preflight-derived facts', (t) => {
const doc = renderShipHandoff({
date: '2026-06-26',
ref: '683ef0a',
refIsCurrentCheckout: false,
branch: 'main',
shortSha: '683ef0a',
commitSubject: 'docker: pin entrypoint and storage env (#136)',
packageName: 'p2p-hiverelay-monorepo',
packageVersion: '0.20.2',
worktree: {
clean: true,
changedPaths: 0,
statusLine: 'main...origin/main'
},
prNumber: '136',
prCheckNames: ['audit', 'lint', 'unit', 'integration', 'Bare tests'],
testRun: '28249805132',
dockerRun: '28249805122',
issueNumber: '120',
preflightRun: '28244297762',
preflightUrl: 'https://github.com/bigdestiny2/P2P-Hiverelay/actions/runs/28244297762',
preflightHead: 'a8eb77df74d4e245b8577a50435a00be04786d96',
preflightBranch: 'main',
preflightCreatedAt: '2026-06-26T14:25:04Z',
preflightState: 'completed/failure',
supersededPreflightSuccess: '28238930607',
supersededPreflightSuccessHead: '1ffffe6d5ed8c6af310219409e59ef2101812ed7',
repo: 'bigdestiny2/P2P-Hiverelay',
releaseBlockers: parseReleaseBlockers(BLOCKER_STDERR),
releaseDefaults: {
full: 'both',
prerelease: 'none'
}
})
t.ok(doc.includes('Generated by `npm run docs:update-ship-handoff`'))
t.ok(doc.includes('HEAD inspected: `683ef0a`'))
t.ok(doc.includes('Commit subject: `docker: pin entrypoint and storage env (#136)`'))
t.ok(doc.includes('Post-merge main Test run: `28249805132` passed.'))
t.ok(doc.includes('Release distribution preflight run: `28244297762` (issue #120).'))
t.ok(doc.includes('Run URL: https://github.com/bigdestiny2/P2P-Hiverelay/actions/runs/28244297762'))
t.ok(doc.includes('Latest checked preflight: state `completed/failure`, head `main@a8eb77d`, created `2026-06-26T14:25:04Z`.'))
t.ok(doc.includes('Earlier passing preflight `28238930607` at `1ffffe6` is superseded by this newer failure.'))
t.ok(doc.includes('UMBREL_STORE_TOKEN must be a GitHub token without whitespace or control characters'))
t.ok(doc.includes('UMBREL_OFFICIAL_PR_TOKEN must be a GitHub token without whitespace or control characters'))
t.ok(doc.includes('UMBREL_OFFICIAL_FORK must be a GitHub owner/umbrel-apps fork slug'))
t.ok(doc.includes('Full releases with no explicit channel resolve to `both`.'))
t.ok(doc.includes('Prereleases with no explicit channel resolve to `none`.'))
t.ok(doc.includes('node --test test/unit/ecosystem-consumers.test.js'))
t.ok(doc.includes('direct-consumer default-pinning'))
t.ok(doc.includes('before any image is published'))
t.ok(doc.includes('npm run ecosystem:sync -- --check'))
t.ok(doc.includes('npm run audit:ecosystem-consumers'))
t.ok(doc.includes('known app defaults and linked'))
t.ok(doc.includes('lockfile metadata plus versioned source markers'))
t.ok(doc.includes('StartOS package proof is also release-image gated'))
t.ok(doc.includes('ghcr.io/bigdestiny2/p2p-hiverelay:0.20.2'))
t.ok(doc.includes('HIVERELAY_IMAGE_DIGEST=sha256:<digest> npm run startos:verify'))
t.ok(doc.includes('Confirm the release GHCR tag resolves to a multi-arch digest'))
t.ok(doc.includes('npm run release:write-secret-template -- \\'))
t.ok(doc.includes('--issue-120-repair \\'))
t.ok(doc.includes('npm run release:check-distribution-env -- \\'))
t.ok(doc.includes('npm run release:apply-github-secrets -- \\'))
t.ok(doc.includes('--env-file /private/tmp/hiverelay-release-secrets.env \\'))
t.absent(doc.includes('--channel both \\'))
t.ok(doc.includes('The template command writes placeholders only for the four current issue #120'))
t.ok(doc.includes('The check command validates the candidate file locally without publishing.'))
t.ok(doc.includes('writing only those four'))
t.ok(doc.includes('Masked release values are sent through `gh secret set` stdin'))
t.ok(doc.includes('The same preflight did not report malformed `FLEET_SSH_PRIVATE_KEY`'))
t.absent(doc.includes('Put corrected release values in a local candidate env file outside the repo'))
t.absent(doc.includes('malformed GitHub secret/variable values'))
t.absent(doc.includes('`NPM_TOKEN`'))
})
test('ship handoff updater reports actual generator checkout when snapshot ref differs', (t) => {
t.is(formatWorktreeSummary({
branch: 'main',
ref: '683ef0a',
refIsCurrentCheckout: false,
shortSha: '683ef0a',
worktree: {
clean: false,
changedPaths: 3,
statusLine: 'audit/lease-api-durable-config'
}
}), 'clean snapshot (`main@683ef0a`)')
})