From 8255c568b1bcfb6ec7f37380aefeb7685101e257 Mon Sep 17 00:00:00 2001 From: kimi-reviewer-andresmgsl Date: Sun, 26 Jul 2026 21:41:16 +0000 Subject: [PATCH] install-apt: fail fast with a clear message when the registry has no Release file --- scripts/install-apt.sh | 13 +++++++++++++ test/install-apt.test.js | 28 ++++++++++++++++++++++++++-- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/scripts/install-apt.sh b/scripts/install-apt.sh index 9e68c5d..a64e185 100755 --- a/scripts/install-apt.sh +++ b/scripts/install-apt.sh @@ -88,6 +88,19 @@ echo "deb [signed-by=$KEYRING] $FORGE_URL/api/packages/$OWNER/debian $DISTRIBUTI # read these. $SUDO chmod 0644 "$KEYRING" "$LIST" +# Fail fast with a clear message when the registry has no package published +# yet: without a Release file, `apt-get update` would only fail with a +# generic "repository does not have a Release file" error. A definitive 404 +# is fatal; any other curl outcome (e.g. a network hiccup) is left for +# apt-get update to report. +RELEASE_URL="$FORGE_URL/api/packages/$OWNER/debian/dists/$DISTRIBUTION/Release" +if [ "$(curl -sSL -o /dev/null -w '%{http_code}' "$RELEASE_URL" || true)" = "404" ]; then + echo "error: no stoke package has been published to the $OWNER Debian registry yet" >&2 + echo "($RELEASE_URL returned 404)." >&2 + echo "Install stoke via npm or manually instead — see the README." >&2 + exit 1 +fi + # Newer apt verifies with sqv (Sequoia), which rejects the signature Forgejo # currently produces for its Debian registry (malformed Ed25519 MPI encoding # in the upstream signing library). Try the properly signed source first so diff --git a/test/install-apt.test.js b/test/install-apt.test.js index 6b30bcb..f411c39 100644 --- a/test/install-apt.test.js +++ b/test/install-apt.test.js @@ -12,12 +12,13 @@ const SCRIPT = path.join(__dirname, '..', 'scripts', 'install-apt.sh'); // candInitial `apt-cache policy` Candidate before any update // candAfterUpdate Candidate after any `apt-get update` // candAfterNodesource Candidate after an update once nodesource.list exists +// releaseStatus HTTP status curl reports for the registry Release file // The apt-cache stub localizes the "Candidate:" label unless LC_ALL=C is set, // so every scenario doubles as a regression test for locale-safe parsing. const cleanups = []; process.on('exit', () => { for (const dir of cleanups) fs.rmSync(dir, { recursive: true, force: true }); }); -function runScenario({ candInitial, candAfterUpdate, candAfterNodesource, preexistingNodesourceList }) { +function runScenario({ candInitial, candAfterUpdate, candAfterNodesource, preexistingNodesourceList, releaseStatus }) { const root = fs.mkdtempSync(path.join(os.tmpdir(), 'stoke-apt-test-')); cleanups.push(root); const bin = path.join(root, 'bin'); @@ -39,7 +40,14 @@ function runScenario({ candInitial, candAfterUpdate, candAfterNodesource, preexi // Force the non-root path so every mutation goes through the sudo stub. stub('id', 'echo 1000'); stub('sudo', 'exec "$@"'); - stub('curl', 'echo "FAKE-KEY"'); + // Registry Release-file probes (URLs under /dists/) answer with the + // scenario's HTTP status; everything else is a key fetch. + stub('curl', [ + 'for a in "$@"; do', + ' case "$a" in */dists/*) echo "${RELEASE_STATUS:-200}"; exit 0;; esac', + 'done', + 'echo "FAKE-KEY"', + ].join('\n')); stub('stoke', 'echo 1.2.0'); stub('apt-cache', [ 'cand="$(cat "$STATE_DIR/candidate")"', @@ -73,6 +81,7 @@ function runScenario({ candInitial, candAfterUpdate, candAfterNodesource, preexi STATE_DIR: state, CAND_AFTER_UPDATE: candAfterUpdate || '', CAND_AFTER_NODESOURCE: candAfterNodesource || '', + RELEASE_STATUS: releaseStatus || '', LC_ALL: 'es_ES.UTF-8', // localized environment; the script must force C }, }); @@ -147,3 +156,18 @@ test('pre-existing user-managed nodesource.list is never overwritten', () => { assert.equal(s.nodesourceList, marker); assert.doesNotMatch(s.aptGetLog, /install -y stoke/); }); + +test('registry Release file 404s: fails fast with a clear message before apt runs', () => { + const s = runScenario({ candInitial: '22.23.1-1nodesource1', releaseStatus: '404' }); + assert.notEqual(s.res.status, 0); + assert.match(s.res.stderr, /no stoke package has been published/); + assert.match(s.res.stderr, /npm/); + assert.match(s.res.stderr, /dists\/stable\/Release returned 404/); + assert.equal(s.aptGetLog, '', 'must abort before any apt-get invocation'); +}); + +test('registry Release file present: proceeds with the install', () => { + const s = runScenario({ candInitial: '22.23.1-1nodesource1', releaseStatus: '200' }); + assert.equal(s.res.status, 0, s.res.stderr); + assert.match(s.aptGetLog, /install -y stoke/); +});