Skip to content

fix(cli): allow swamp issue get to run without authentication (swamp-club#313)#1360

Merged
stack72 merged 1 commit into
mainfrom
paul/313-issue-get-no-auth
May 11, 2026
Merged

fix(cli): allow swamp issue get to run without authentication (swamp-club#313)#1360
stack72 merged 1 commit into
mainfrom
paul/313-issue-get-no-auth

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented May 11, 2026

Summary

  • Make swamp issue get work without authentication by making the auth
    check optional — when credentials exist the API key is sent for
    authenticated access; when absent the request is unauthenticated
  • SwampClubClient.fetchIssue now accepts apiKey: string | undefined
    and omits the x-api-key header when undefined
  • Falls back to SWAMP_CLUB_URL env var or DEFAULT_SWAMP_CLUB_URL
    when no stored credentials exist, matching the pattern used by
    extension search, extension list, and other unauthenticated commands

Closes swamp-club#313

Test Plan

  • Reproduced: swamp issue get 1 with no credentials fails with
    "Not logged in" error
  • Verified: compiled binary succeeds unauthenticated (confirmed API
    returns 200 without x-api-key)
  • Verified: authenticated path still works when credentials exist
  • deno check passes
  • deno lint passes
  • deno fmt --check passes
  • Full test suite passes (5781 tests, 0 failures)

🤖 Generated with Claude Code

…p-club#313)

The command unconditionally required credentials before making the API
request, even though the swamp-club endpoint supports unauthenticated
reads for public issues.  Make auth optional: when credentials exist the
API key is sent for authenticated access; when absent the request is
made without the x-api-key header, falling back to SWAMP_CLUB_URL or
the default server URL.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial Review

Critical / High

None.

Medium

None.

Low

  1. swamp_club_client.ts:276 — empty-string apiKey silently treated as unauthenticated. If AuthRepository.load() returns credentials where apiKey is "" (e.g. an SWAMP_API_KEY="" env var — technically truthy for the env check on line 90 of auth_repository.ts but wait, no: empty-string is falsy in the if (envApiKey) guard, so this path returns null). After tracing through AuthRepository.load(), credentials?.apiKey can only be undefined (when credentials is null) or a non-empty string (either from env-var with the falsy check, or from a deserialized auth.json where an empty apiKey would be a corrupted file). The if (apiKey) check is safe in practice. Purely theoretical.

  2. issue_get.ts:51-52SWAMP_CLUB_URL env var checked twice on the unauthenticated path. When credentials is null, AuthRepository.load() already checked SWAMP_CLUB_URL internally (and returned null because there was no SWAMP_API_KEY). The command then re-reads the same env var for serverUrl. This is harmless — consistent with extension_search.ts, extension_list.ts, and other commands using the identical pattern — but worth noting the env var is read redundantly. Not a bug.

Verdict

PASS. Clean, minimal change that correctly follows the established unauthenticated-access pattern used by extension search, extension list, extension outdated, and extension update. The fetchIssue signature widening from string to string | undefined is backwards-compatible, the ?? fallback chain has correct precedence, the UserError import is still used (line 47), and no callers are broken by the change.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLI UX Review

Blocking

None.

Suggestions

  1. ** — has no 401/403 handling.** If the server ever returns 401/403 for a protected issue (e.g., a private/internal issue), the error is Failed to fetch issue #N (HTTP 401): <raw server text>, with no hint to run swamp auth login. The removed "Not logged in" guard used to cover this. Since the PR author confirms the public API always returns 200 without an API key, this is unlikely to bite users today — but adding a res.status === 401 || res.status === 403 branch with a message like 'Issue #N requires authentication. Run "swamp auth login" first.' would close the gap cleanly.

Verdict

PASS — removes a spurious auth gate on a public endpoint, follows the same URL-fallback pattern as extension search / extension list, and causes no regression in help text, output format, or error messages.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CLI UX Review

Blocking

None.

Suggestions

  1. fetchIssue has no 401/403 handling (src/infrastructure/http/swamp_club_client.ts). If the server ever returns 401/403 for a protected issue, the error is Failed to fetch issue #N (HTTP 401): <raw server text>, with no hint to run swamp auth login. The removed "Not logged in" guard used to cover this path. Since the PR author confirms the public API returns 200 without an API key this is unlikely to bite users today, but a res.status === 401 || res.status === 403 branch with a message like Issue #N requires authentication. Run "swamp auth login" first. would close the gap cleanly.

Verdict

PASS — removes a spurious auth gate on a public endpoint, follows the same URL-fallback pattern as extension search / extension list, and causes no regression in help text, output format, or error messages.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

Clean, minimal change that correctly makes swamp issue get work without authentication. The approach is sound and well-implemented.

Blocking Issues

None.

Suggestions

  1. Test coverage for fetchIssue unauthenticated path: The swamp_club_client_test.ts has no tests for fetchIssue at all (pre-existing gap), and issue_get_test.ts only checks command metadata. A test verifying that the x-api-key header is omitted when apiKey is undefined would strengthen confidence, but this is a pre-existing gap not introduced by this PR.

Notes

  • Import boundary: All imports are correct. DEFAULT_SWAMP_CLUB_URL comes from ../../domain/auth/auth_credentials.ts and SwampClubClient from ../../infrastructure/http/swamp_club_client.ts — neither are libswamp-internal paths. This matches the pattern used by all other CLI commands (extension_search, extension_list, auth_login, etc.).
  • DDD: No domain model violations. Infrastructure changes are properly confined to the HTTP client layer. CLI command orchestration is clean.
  • Pattern consistency: The server URL fallback (credentials?.serverUrl ?? env var ?? default) is a slight improvement over other unauthenticated commands (which skip credential loading entirely) because it respects a logged-in user's configured server URL while still working without auth.
  • Security: API key is properly omitted (not sent as empty string) when credentials are absent. The headers object is cleanly constructed with a conditional property add.
  • No any types introduced, copyright headers present, no fire-and-forget promises.

@stack72 stack72 merged commit 8cd0da2 into main May 11, 2026
11 checks passed
@stack72 stack72 deleted the paul/313-issue-get-no-auth branch May 11, 2026 14:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant