Skip to content

feat: sync codex oauth into opencode auth/runtime#47

Open
jyuny1 wants to merge 1 commit intoLoongphy:mainfrom
jyuny1:feat-opencode-oauth-sync-notify
Open

feat: sync codex oauth into opencode auth/runtime#47
jyuny1 wants to merge 1 commit intoLoongphy:mainfrom
jyuny1:feat-opencode-oauth-sync-notify

Conversation

@jyuny1
Copy link
Copy Markdown

@jyuny1 jyuny1 commented Apr 5, 2026

What

  • Sync Codex active OAuth to opencode file-based auth:
    • ~/.local/share/opencode/auth.json
    • ~/.config/opencode/codex-accounts.json
  • Trigger sync after list/login/import/switch/remove.
  • Keep runtime server refresh as optional best-effort (non-blocking).

Why

  • opencode may not always run in server mode.
  • File-based OAuth sync ensures account switch is reflected even without runtime API.

Behavior

  • Preserve non-openai/codex providers in opencode auth.json.
  • If sync/refresh fails, main command still succeeds and logs warning only.

Validation

  • HOME=/tmp/codex-auth-pr ... zig build run -- list
  • HOME=/tmp/codex-auth-pr ... zig test src/main.zig -lc --test-filter opencode

Note

Sync Codex OAuth credentials into opencode auth files and running servers

  • Adds a new opencode_sync.zig module that writes codex-accounts.json and auth.json into the opencode config/data directories derived from the Codex registry and active auth snapshot.
  • After account switches (and other commands like login, import_auth, remove_account), running opencode servers are discovered via lsof and their auth state is updated via HTTP PUT/DELETE to /auth/openai.
  • Non-openai/codex providers in existing auth.json files are preserved during sync.
  • The switch command now prints a standardized success message including email, alias, and account name.
  • Risk: discoverRunningServers shells out to lsof and is a no-op on Windows; sync/refresh failures are downgraded to warnings so they never abort the main command.
📊 Macroscope summarized bc147dc. 3 files reviewed, 1 issue evaluated, 0 issues filtered, 1 comment posted

🗂️ Filtered Issues

Comment on lines +348 to +358
fn resolveOpencodeConfigDir(allocator: std.mem.Allocator, user_home: []const u8) ![]u8 {
if (@import("builtin").os.tag == .windows) {
if (try getNonEmptyEnvVarOwned(allocator, "APPDATA")) |app_data| return std.fs.path.join(allocator, &[_][]const u8{ app_data, "opencode" });
return std.fs.path.join(allocator, &[_][]const u8{ user_home, "AppData", "Roaming", "opencode" });
}

if (try getNonEmptyEnvVarOwned(allocator, "XDG_CONFIG_HOME")) |xdg| {
return std.fs.path.join(allocator, &[_][]const u8{ xdg, "opencode" });
}
return std.fs.path.join(allocator, &[_][]const u8{ user_home, ".config", "opencode" });
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Medium src/opencode_sync.zig:348

resolveOpencodeConfigDir and resolveOpencodeDataDir leak memory when getNonEmptyEnvVarOwned returns a non-null value. On Windows with APPDATA set, or on Unix with XDG_CONFIG_HOME/XDG_DATA_HOME set, the returned app_data or xdg string is never freed before the function returns. Each call to sync() leaks the environment variable's value. Add defer allocator.free(...) before returning the joined path.

 fn resolveOpencodeConfigDir(allocator: std.mem.Allocator, user_home: []const u8) ![]u8 {
     if (@import("builtin").os.tag == .windows) {
-        if (try getNonEmptyEnvVarOwned(allocator, "APPDATA")) |app_data| return std.fs.path.join(allocator, &[_][]const u8{ app_data, "opencode" });
+        if (try getNonEmptyEnvVarOwned(allocator, "APPDATA")) |app_data| {
+            defer allocator.free(app_data);
+            return std.fs.path.join(allocator, &[_][]const u8{ app_data, "opencode" });
+        }
         return std.fs.path.join(allocator, &[_][]const u8{ user_home, "AppData", "Roaming", "opencode" });
     }
 
-    if (try getNonEmptyEnvVarOwned(allocator, "XDG_CONFIG_HOME")) |xdg| {
+    if (try getNonEmptyEnvVarOwned(allocator, "XDG_CONFIG_HOME")) |xdg| {
+        defer allocator.free(xdg);
         return std.fs.path.join(allocator, &[_][]const u8{ xdg, "opencode" });
     }
     return std.fs.path.join(allocator, &[_][]const u8{ user_home, ".config", "opencode" });
🤖 Copy this AI Prompt to have your agent fix this:
In file src/opencode_sync.zig around lines 348-358:

`resolveOpencodeConfigDir` and `resolveOpencodeDataDir` leak memory when `getNonEmptyEnvVarOwned` returns a non-null value. On Windows with `APPDATA` set, or on Unix with `XDG_CONFIG_HOME`/`XDG_DATA_HOME` set, the returned `app_data` or `xdg` string is never freed before the function returns. Each call to `sync()` leaks the environment variable's value. Add `defer allocator.free(...)` before returning the joined path.

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