Skip to content

feat(domain): migrate default swamp-club URL to swamp-club.com#1228

Merged
stack72 merged 1 commit intomainfrom
migrate-swamp-club-domain
Apr 27, 2026
Merged

feat(domain): migrate default swamp-club URL to swamp-club.com#1228
stack72 merged 1 commit intomainfrom
migrate-swamp-club-domain

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented Apr 27, 2026

Summary

  • Flip the default swamp-club registry/auth URL from https://swamp.club to https://swamp-club.com, plus the telemetry endpoint to https://telemetry.swamp-club.com.
  • Transparently migrate existing ~/.config/swamp/auth.json files: on load, if serverUrl === "https://swamp.club" exactly, rewrite to the new domain and re-save. API keys are domain-independent (verified manually), so users keep their session.
  • Consolidate eight duplicated DEFAULT_SERVER_URL definitions in src/cli and src/libswamp into a single import of DEFAULT_SWAMP_CLUB_URL from src/domain/auth/auth_credentials.ts so future domain changes land in one place.
  • The SWAMP_CLUB_URL env var and DEFAULT_SWAMP_CLUB_URL constant keep their names — only the URL value changed, so existing CI configs and shell exports keep working.

The migration is scoped to the exact legacy literal — custom servers (e.g. https://staging.swamp.club, self-hosted forks) are left alone.

Pre-merge DNS check

Host Status
swamp-club.com HTTP 200 (Cloudflare)
telemetry.swamp-club.com HTTP 200 (Cloudflare), DNS propagated

Both new hosts are live and reachable.

Notable behavior changes

  • extensions/models/_lib/swamp_club.ts (issue-lifecycle extension) cannot import from src/, so it carries its own https://swamp-club.com literal and a parallel read-time rewrite.
  • AuthRepository.load now writes to disk on first read of a legacy file, where it previously only read.

Test plan

  • deno check clean
  • deno lint clean
  • deno fmt applied
  • deno run test — 4928 passed, 0 failed
  • deno run compile succeeds
  • Sanity-check on a fresh checkout: swamp auth login writes the new URL
  • Sanity-check on an upgrade: auth.json with https://swamp.club is rewritten to https://swamp-club.com after the first command run, and whoami succeeds against the new domain

🤖 Generated with Claude Code

Switches the CLI's default registry/auth/telemetry endpoints from the
legacy swamp.club domain to swamp-club.com. Existing auth.json files
carrying https://swamp.club are transparently rewritten on load (and
persisted) so users keep their session without re-running auth login.
The SWAMP_CLUB_URL env var and DEFAULT_SWAMP_CLUB_URL constant keep
their names — only the URL value changed.

Consolidates eight previously-duplicated DEFAULT_SERVER_URL constants
in src/cli and src/libswamp into a single import of
DEFAULT_SWAMP_CLUB_URL from src/domain/auth/auth_credentials.ts so
future domain changes land in one place.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
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. Silent auth.json migrationAuthRepository.load() rewrites the user's ~/.config/swamp/auth.json on first read with no log message. This is correct behavior for a domain migration, but if a user has monitoring on that file or is debugging auth issues, the silent write could be surprising. A single logger.info("Migrated auth config to swamp-club.com") at the migration site would make this discoverable without being noisy. Not blocking.

Verdict

PASS — all user-facing strings (login prompt, security report notice, extension URL error guidance) consistently use swamp-club.com. JSON serverUrl field shape is unchanged. The transparent credential migration is scoped correctly to the exact legacy literal and leaves custom/self-hosted servers alone.

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.

CI Security Review

Critical / High

None.

Medium

None.

Low

None.

Verdict

PASS — The only workflow change (auto-response.yml) is a domain-literal migration from swamp.clubswamp-club.com across five string locations (job name, fetch endpoint, error messages, lab URL). No changes to triggers, permissions, action references, expression handling, or secret management. Existing security properties are preserved: user-supplied issue.title/issue.body remain safely serialized via JSON.stringify(), the labIssueNumber integer validation is untouched, secrets are correctly scoped via env:, and actions/github-script@v7 is an acceptable GitHub-owned action pin. Security-neutral 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.

Code Review

Blocking Issues

None.

Suggestions

  1. Stale skill examples: .claude/skills/swamp-issue/SKILL.md:55 and .claude/skills/swamp-issue/references/output_shapes.md:16 still show "serverUrl": "https://swamp.club" in their example JSON output. Not production code, but worth updating for consistency with the migration.

Notes

Well-executed migration. Key things I verified:

  • Consolidation is complete: all 8 duplicated DEFAULT_SERVER_URL constants are replaced by a single DEFAULT_SWAMP_CLUB_URL import from src/domain/auth/auth_credentials.ts. No remaining DEFAULT_SERVER_URL references in the codebase.
  • Migration scoping is correct: AuthRepository.load() rewrites only the exact legacy literal "https://swamp.club" — custom servers (e.g., https://staging.swamp.club) are left alone, confirmed by test at auth_repository_test.ts:292.
  • Migration persists on first read: the write-on-load behavior is tested (auth_repository_test.ts:263) and documented in the PR body. Subsequent loads skip the rewrite.
  • Extension boundary respected: extensions/models/_lib/swamp_club.ts carries its own hardcoded literals and read-time rewrite since it can't import from src/ — correct architectural boundary.
  • DDD alignment: domain constants live in the domain layer (auth_credentials.ts), persistence migration lives in infrastructure (AuthRepository). LEGACY_SWAMP_CLUB_URL is a proper domain concept.
  • libswamp import boundary: CLI commands import DEFAULT_SWAMP_CLUB_URL from the domain layer (src/domain/auth/auth_credentials.ts), not from libswamp internals. No violations.
  • No fire-and-forget promises: await this.save(parsed) in the migration path is properly awaited.
  • Test coverage: two new migration tests (rewrite + persist, leave custom alone), plus all existing tests updated to the new domain.

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 found.

Medium

  1. src/infrastructure/persistence/auth_repository.ts:71-74 — Migration save failure breaks load() entirely

    The migration logic at line 73 calls await this.save(parsed) inside the same try/catch that handles the read. If save() throws (e.g. read-only filesystem, disk full, permission denied on a file owned by a different user), the error falls through to the catch block at line 76, which only swallows Deno.errors.NotFound. Any other error is re-thrown.

    This means load() — which previously always succeeded when the file was readable — now throws on a valid, successfully-parsed auth file if the write-back fails. Callers expect load() to return AuthCredentials | null, not throw on a readable file.

    Breaking scenario: User runs swamp in a read-only container or on a filesystem mounted ro. They have a valid legacy auth.json. Before this PR, load() returns their credentials. After this PR, load() throws Deno.errors.PermissionDenied, and every command that loads auth breaks.

    Suggested fix: Wrap the save in its own try/catch so the migration is best-effort:

    if (parsed.serverUrl === LEGACY_SWAMP_CLUB_URL) {
      parsed.serverUrl = DEFAULT_SWAMP_CLUB_URL;
      try {
        await this.save(parsed);
      } catch {
        // Migration persistence is best-effort; the in-memory
        // rewrite still takes effect for this invocation.
      }
    }

Low

  1. extensions/models/_lib/swamp_club.ts:308 — Inline legacy URL literal instead of shared constant

    The extension file duplicates the legacy URL as a string literal ("https://swamp.club") rather than importing LEGACY_SWAMP_CLUB_URL. The PR description notes this is intentional (extension code cannot import from src/), so it's a maintenance concern rather than a bug — if the legacy domain check ever needs updating, this site could be missed. Not actionable, just noting for awareness.

  2. Trailing-slash variant not migrated — If any user's auth.json contains "https://swamp.club/" (with trailing slash), the exact-match migration won't fire. In practice this is unlikely since the CLI always stored the URL without a trailing slash, but a manual edit could produce it.

Verdict

PASS — The domain migration is well-scoped (exact legacy literal only), tests cover the happy path and the custom-server-left-alone case, and the consolidation of duplicated constants is clean. The save-failure-in-load issue (Medium #1) is worth addressing but not a blocker since it only affects the unlikely intersection of legacy auth files and read-only filesystems.

@stack72 stack72 merged commit 5a38448 into main Apr 27, 2026
11 checks passed
@stack72 stack72 deleted the migrate-swamp-club-domain branch April 27, 2026 11:37
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