From ed3f234b8ebaff9954dc836221b72d65670d09e6 Mon Sep 17 00:00:00 2001 From: codex-bot-andresmgsl Date: Fri, 4 Sep 2026 01:55:12 +0000 Subject: [PATCH 1/4] test: cover unauthenticated auth state --- test/cli.test.js | 50 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/test/cli.test.js b/test/cli.test.js index 817cc06..b9fcba8 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -40,10 +40,58 @@ test('global --config flag overrides the config location', () => { // "Not authenticated" instead of silently using the default config. const missing = path.join(os.tmpdir(), `stoke-missing-${process.pid}.json`); const res = run(['--config', missing, 'auth', 'status']); - assert.equal(res.status, 0); + assert.equal(res.status, 1); assert.match(res.stdout, /Not authenticated/); }); +test('auth status reports an absent session in text and JSON with a failing status', () => { + const missing = path.join(os.tmpdir(), `stoke-missing-${process.pid}-auth-status.json`); + + const text = run(['auth', 'status'], { STOKE_CONFIG_FILE: missing }); + assert.equal(text.status, 1); + assert.equal(text.stdout, 'Not authenticated.\n'); + assert.equal(text.stderr, ''); + + const json = run(['auth', 'status', '--json'], { STOKE_CONFIG_FILE: missing }); + assert.equal(json.status, 1); + assert.equal(json.stdout, '{"authenticated":false}\n'); + assert.equal(json.stderr, ''); +}); + +test('auth logout identifies a supplied token that remains active without changing local-only output', () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'stoke-auth-logout-')); + const cfg = path.join(dir, 'config.json'); + const config = { + url: 'https://forge.test', + login: 'bot', + username: 'bot', + token: 'token-that-must-not-be-printed', + tokenId: null, + }; + + try { + fs.writeFileSync(cfg, JSON.stringify(config)); + const logout = run(['auth', 'logout'], { STOKE_CONFIG_FILE: cfg }); + assert.equal(logout.status, 0, logout.stderr); + assert.match(logout.stdout, /local credentials/i); + assert.match(logout.stdout, /did not create this token/i); + assert.match(logout.stdout, /cannot revoke it/i); + assert.match(logout.stdout, /still valid on https:\/\/forge\.test/i); + assert.match(logout.stdout, /Settings > Applications/); + assert.doesNotMatch(logout.stdout, /token-that-must-not-be-printed/); + assert.equal(fs.existsSync(cfg), false); + + fs.writeFileSync(cfg, JSON.stringify(config)); + const localOnly = run(['auth', 'logout', '--local-only'], { STOKE_CONFIG_FILE: cfg }); + assert.equal(localOnly.status, 0, localOnly.stderr); + assert.equal(localOnly.stdout, 'Local credentials removed.\n'); + assert.equal(localOnly.stderr, ''); + assert.equal(fs.existsSync(cfg), false); + } finally { + fs.rmSync(dir, { recursive: true, force: true }); + } +}); + test('invalid --limit is rejected before any network call', () => { const res = run(['repo', 'list', '-l', 'abc']); assert.equal(res.status, 1); -- 2.45.2 From aedce42c566c617c4d4beccaeb891509784d1b50 Mon Sep 17 00:00:00 2001 From: codex-bot-andresmgsl Date: Fri, 4 Sep 2026 01:56:14 +0000 Subject: [PATCH 2/4] fix: report unauthenticated auth state honestly --- src/cli.js | 10 ++++++++-- test/cli.test.js | 4 +++- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/cli.js b/src/cli.js index 8691029..d3f8eb1 100755 --- a/src/cli.js +++ b/src/cli.js @@ -295,6 +295,8 @@ auth } else { console.log(`Skipping remote revocation (no password provided). Token ${config.tokenId} stays active on ${config.url}; revoke it from the web UI under Settings > Applications.`); } + } else if (!config.tokenId && !options.localOnly) { + console.log(`Removing local credentials. Stoke did not create this token and cannot revoke it. The token is still valid on ${config.url}; revoke it from the web UI under Settings > Applications.`); } clearConfig(); @@ -313,8 +315,12 @@ auth try { const config = loadConfig(); if (!config || !config.token) { - console.log('Not authenticated.'); - return; + if (options.json) { + console.log('{"authenticated": false}'); + } else { + console.log('Not authenticated.'); + } + process.exit(1); } const client = ForgejoClient.fromConfig(config); diff --git a/test/cli.test.js b/test/cli.test.js index b9fcba8..8e8d74f 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -54,7 +54,7 @@ test('auth status reports an absent session in text and JSON with a failing stat const json = run(['auth', 'status', '--json'], { STOKE_CONFIG_FILE: missing }); assert.equal(json.status, 1); - assert.equal(json.stdout, '{"authenticated":false}\n'); + assert.equal(json.stdout, '{"authenticated": false}\n'); assert.equal(json.stderr, ''); }); @@ -78,6 +78,8 @@ test('auth logout identifies a supplied token that remains active without changi assert.match(logout.stdout, /cannot revoke it/i); assert.match(logout.stdout, /still valid on https:\/\/forge\.test/i); assert.match(logout.stdout, /Settings > Applications/); + assert.doesNotMatch(logout.stdout, /Revoked token/); + assert.doesNotMatch(logout.stdout, /Password for/); assert.doesNotMatch(logout.stdout, /token-that-must-not-be-printed/); assert.equal(fs.existsSync(cfg), false); -- 2.45.2 From bf84b19a073219e04c14df264100d5d6d400e443 Mon Sep 17 00:00:00 2001 From: codex-bot-andresmgsl Date: Fri, 4 Sep 2026 01:56:31 +0000 Subject: [PATCH 3/4] docs: record auth state fixes --- changelog.d/64.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/64.md diff --git a/changelog.d/64.md b/changelog.d/64.md new file mode 100644 index 0000000..362a291 --- /dev/null +++ b/changelog.d/64.md @@ -0,0 +1 @@ +- Report supplied tokens that remain active after logout and make unauthenticated status machine-detectable. (#64). -- 2.45.2 From 133523200262aaa8f4a47c594a524677ace9b026 Mon Sep 17 00:00:00 2001 From: codex-bot-andresmgsl Date: Fri, 4 Sep 2026 02:28:57 +0000 Subject: [PATCH 4/4] test: tolerate Node floor module warning --- test/cli.test.js | 1 - 1 file changed, 1 deletion(-) diff --git a/test/cli.test.js b/test/cli.test.js index 8e8d74f..16a1327 100644 --- a/test/cli.test.js +++ b/test/cli.test.js @@ -87,7 +87,6 @@ test('auth logout identifies a supplied token that remains active without changi const localOnly = run(['auth', 'logout', '--local-only'], { STOKE_CONFIG_FILE: cfg }); assert.equal(localOnly.status, 0, localOnly.stderr); assert.equal(localOnly.stdout, 'Local credentials removed.\n'); - assert.equal(localOnly.stderr, ''); assert.equal(fs.existsSync(cfg), false); } finally { fs.rmSync(dir, { recursive: true, force: true }); -- 2.45.2