Skip to content

Cloud Sync: additional bugs found during code review #195

Description

@prefrontalsys

While investigating #194, I read through the cloud sync code and found three additional bugs. Grouping them here to keep noise low.


1. Gist search doesn't paginate — users with 100+ gists get duplicate sync gists

File: src-tauri/src/services/gist_sync.rs, line 225

let url = format!("{}/gists?per_page=100", self.api_base);

GitHub's Gist list API caps at per_page=100 with no pagination. If a user has more than 100 gists, find_or_create_gist will never find the existing sync gist and creates a new one every time "Connect" is pressed. Subsequent pushes go to an ephemeral gist that's abandoned on next connect.

Fix: Paginate using the Link header, or store the gist ID on first creation and skip the search entirely on subsequent connects.


2. disconnect_cloud_sync sets gist ID to empty string instead of deleting it

File: src-tauri/src/commands/cloud_sync.rs, lines 129–138

let _ = db.set_setting("sync_gist_id", "");

get_sync_auth_status (line 119) checks gist_id.is_some(). If get_setting returns Some("") for empty strings, is_authenticated stays true after disconnect. The GitHub token is also left in the DB, so a re-connect reuses it without re-validating — which fails silently if the token has expired.

Fix: Delete both keys instead of setting them to empty strings, or normalize empty strings to None in the auth check.


3. apply_pulled_payload uses wrong backup extension strategy

File: src-tauri/src/services/gist_sync.rs, line 551

let backup = path.with_extension("md.bak");

Path::with_extension replaces the existing extension rather than appending. For .md files this produces the correct result by coincidence (CLAUDE.mdCLAUDE.md.bak), but for .json files it would produce settings.md.bak instead of settings.json.bak.

The project's own utils/backup.rs handles this correctly using format!("{}.bak", file_name) with with_file_name. This code path should use the same approach.


4. gh auth token doesn't verify gist scope

File: src-tauri/src/commands/cloud_sync.rs, line 17

gh auth token returns whatever token is stored regardless of scopes. If a user authenticated gh for Git operations only (no gist scope), the connect step succeeds but all Gist API calls return 403. The error surfaces as a generic failure message.

Fix: Use gh auth token --scopes gist or check the token's scopes against the GitHub API before storing it.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions