forked from heavy-duty/stoke
Merge pull request 'fix: clarify publish-deb auth failure' (#59) from build/57-publish-deb-auth-message into main
Reviewed-on: heavy-duty/stoke#59 Reviewed-by: glm-bot-andresmgsl <andres+5@heavyduty.builders> Reviewed-by: claude-bot-andresmgsl <andres+1@heavyduty.builders> Reviewed-by: kimi-bot-andresmgsl <andres+4@heavyduty.builders>
This commit is contained in:
commit
bbde478157
3 changed files with 68 additions and 2 deletions
1
changelog.d/57.md
Normal file
1
changelog.d/57.md
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
- Clarified Debian publish authentication failures with the CI secret source and the local remedies. (#57).
|
||||||
|
|
@ -9,7 +9,7 @@
|
||||||
# component APT component, default: main
|
# component APT component, default: main
|
||||||
#
|
#
|
||||||
# Authentication (first match wins):
|
# Authentication (first match wins):
|
||||||
# 1. STOKE_TOKEN environment variable
|
# 1. STOKE_TOKEN environment variable (set from secrets.RELEASE_TOKEN in CI)
|
||||||
# 2. The token stored by `stoke auth login`
|
# 2. The token stored by `stoke auth login`
|
||||||
#
|
#
|
||||||
# The Forgejo URL defaults to the instance in the stoke config, falling back
|
# The Forgejo URL defaults to the instance in the stoke config, falling back
|
||||||
|
|
@ -30,7 +30,15 @@ CONFIG_JSON="$(node -e "const c = require('$ROOT/src/config').loadConfig(); if (
|
||||||
TOKEN="${STOKE_TOKEN:-$(node -pe "(JSON.parse(process.argv[1] || '{}').token) || ''" "$CONFIG_JSON")}"
|
TOKEN="${STOKE_TOKEN:-$(node -pe "(JSON.parse(process.argv[1] || '{}').token) || ''" "$CONFIG_JSON")}"
|
||||||
FORGE_URL="${FORGE_URL:-$(node -pe "(JSON.parse(process.argv[1] || '{}').url) || 'https://forgejo.heavyduty.builders'" "$CONFIG_JSON")}"
|
FORGE_URL="${FORGE_URL:-$(node -pe "(JSON.parse(process.argv[1] || '{}').url) || 'https://forgejo.heavyduty.builders'" "$CONFIG_JSON")}"
|
||||||
|
|
||||||
[ -n "$TOKEN" ] || { echo "error: no token. Set STOKE_TOKEN or run: stoke auth login" >&2; exit 1; }
|
if [ -z "$TOKEN" ]; then
|
||||||
|
cat >&2 <<'EOF'
|
||||||
|
error: no token.
|
||||||
|
In CI, this step reads STOKE_TOKEN from secrets.RELEASE_TOKEN; an empty value
|
||||||
|
means the secret is unset or unreadable by this workflow, not that the tool is missing.
|
||||||
|
Locally: export STOKE_TOKEN, or run `stoke auth login`.
|
||||||
|
EOF
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
URL="$FORGE_URL/api/packages/$OWNER/debian/pool/$DISTRIBUTION/$COMPONENT/upload"
|
URL="$FORGE_URL/api/packages/$OWNER/debian/pool/$DISTRIBUTION/$COMPONENT/upload"
|
||||||
echo "Uploading $(basename "$DEB") to $URL"
|
echo "Uploading $(basename "$DEB") to $URL"
|
||||||
|
|
|
||||||
57
test/publish-deb.test.js
Normal file
57
test/publish-deb.test.js
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
const { test } = require('node:test');
|
||||||
|
const assert = require('node:assert/strict');
|
||||||
|
const { spawnSync } = require('node:child_process');
|
||||||
|
const fs = require('node:fs');
|
||||||
|
const os = require('node:os');
|
||||||
|
const path = require('node:path');
|
||||||
|
|
||||||
|
const ROOT = path.join(__dirname, '..');
|
||||||
|
const SCRIPT = path.join(ROOT, 'scripts', 'publish-deb.sh');
|
||||||
|
const TOKEN = 'deb-token-that-must-not-appear-in-output';
|
||||||
|
|
||||||
|
function runScenario({ token = '' } = {}) {
|
||||||
|
const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'stoke-publish-deb-test-'));
|
||||||
|
try {
|
||||||
|
const home = path.join(dir, 'home');
|
||||||
|
const bin = path.join(dir, 'bin');
|
||||||
|
const deb = path.join(dir, 'stoke_2.0.0_all.deb');
|
||||||
|
fs.mkdirSync(home);
|
||||||
|
fs.mkdirSync(bin);
|
||||||
|
fs.writeFileSync(deb, 'package');
|
||||||
|
fs.writeFileSync(path.join(bin, 'curl'), '#!/usr/bin/env bash\nprintf 201\n');
|
||||||
|
fs.chmodSync(path.join(bin, 'curl'), 0o755);
|
||||||
|
|
||||||
|
return spawnSync('bash', [SCRIPT, deb], {
|
||||||
|
encoding: 'utf8',
|
||||||
|
env: {
|
||||||
|
HOME: home,
|
||||||
|
PATH: `${bin}:${process.env.PATH}`,
|
||||||
|
STOKE_CONFIG_FILE: path.join(dir, 'missing-config.json'),
|
||||||
|
STOKE_TOKEN: token,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} finally {
|
||||||
|
fs.rmSync(dir, { recursive: true, force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
test('empty token identifies the CI secret before offering the local remedy', () => {
|
||||||
|
const result = runScenario();
|
||||||
|
|
||||||
|
assert.equal(result.status, 1);
|
||||||
|
assert.equal(result.stdout, '');
|
||||||
|
assert.match(result.stderr, /^error: no token\./);
|
||||||
|
assert.match(result.stderr, /STOKE_TOKEN/);
|
||||||
|
assert.match(result.stderr, /RELEASE_TOKEN/);
|
||||||
|
assert.match(result.stderr, /empty value.*secret/is);
|
||||||
|
assert.ok(result.stderr.indexOf('RELEASE_TOKEN') < result.stderr.indexOf('stoke auth login'));
|
||||||
|
});
|
||||||
|
|
||||||
|
test('non-empty environment token passes the guard without exposing the token', () => {
|
||||||
|
const result = runScenario({ token: TOKEN });
|
||||||
|
|
||||||
|
assert.equal(result.status, 0, result.stderr);
|
||||||
|
assert.match(result.stdout, /Published\./);
|
||||||
|
assert.doesNotMatch(result.stdout, new RegExp(TOKEN));
|
||||||
|
assert.doesNotMatch(result.stderr, new RegExp(TOKEN));
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue