akshitkrnagpal / akshitkrnagpal/revcat

LoadLocal walk-up collides with ~/.revcat/config.json, causing false 'profile block is empty' error

Đang mở
#68 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Go
Star
3
Fork
0
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

## Summary

`revcat auth login` succeeds and writes a valid `~/.revcat/config.json`, but every subsequent command (`auth status`, `doctor`, `projects list`, etc.) fails with:

```
/Users//.revcat/config.json: profile block is empty; rerun `revcat init`
```

This happens even immediately after a fresh login, with a config file that is valid JSON and contains a fully populated `profiles.default` block with non-expired tokens. Re-running `auth logout --all` + `auth login` reproduces the exact same error every time — it is not a stale-credential issue.

## Root cause

In `internal/auth/local_config.go`, `LoadLocal(startDir)` walks up from `cwd` looking for a file at the **relative** path `.revcat/config.json`, with no boundary check other than reaching filesystem root:

```go
func LoadLocal(startDir string) (*LocalConfig, error) {
dir, err := filepath.Abs(startDir)
...
for {
path := filepath.Join(dir, LocalConfigPath) // ".revcat/config.json"
if info, err := os.Stat(path); err == nil && !info.IsDir() {
return readLocalFile(path)
}
parent := filepath.Dir(dir)
if parent == dir {
return nil, ErrNoLocalConfig
}
dir = parent
}
}
```

Because the walk-up is not bounded at `$HOME`, for any working directory that is a descendant of the user's home directory (i.e. virtually everyone), the loop eventually reaches `$HOME` itself and checks for `$HOME/.revcat/config.json` — which **is** the global config file (see `globalFileName = ".revcat/config.json"` in `global_file.go`, joined with home in `resolve.go`'s fallback path construction).

`LoadLocal` finds this file and hands it to `readLocalFile`, which unmarshals it into `LocalConfig{ProjectID, Apps, Profile}` — a struct expecting a **singular** `"profile"` key. But the global file's actual shape (from `global_file.go`) is a **plural** `"profiles"` map:

```json
{
"profiles": {
"default": { "name": "default", "access_token": "...", ... }
}
}
```

Since the key doesn't match, `cfg.Profile` stays zero-valued, and `readLocalFile` hits:

```go
if cfg.Profile.AccessToken == "" && cfg.Profile.RefreshToken == "" {
return nil, fmt.Errorf("%s: profile block is empty; rerun `revcat init`", path)
}
```

...which is misleading, since the *global* profile block is not empty at all — it's just being parsed with the wrong schema entirely, and the code never reaches the correct `OpenGlobal()` branch in `Resolve()` (`resolve.go:98`) because the error from `LoadLocal` isn't `ErrNoLocalConfig`, so it's propagated as a hard failure (`resolve.go:94-96`).

## Repro

```sh
cd ~/some/project/nested/deep/enough # any dir under $HOME with no .revcat/ in the tree
revcat auth login # succeeds, writes ~/.revcat/config.json
revcat auth status # fails: "profile block is empty; rerun `revcat init`"
```

Confirmed the walk-up path collision directly:

```
/Users/aaa/Documents/Projects/InstaMail/.revcat/config.json
/Users/aaa/Documents/Projects/.revcat/config.json
/Users/aaa/Documents/.revcat/config.json
/Users/aaa/.revcat/config.json <-- $HOME, matches globalFileName, misparsed here
/Users/.revcat/config.json
/.revcat/config.json
```

Also confirmed the credential itself is valid: setting `REVCAT_REFRESH_TOKEN` (which short-circuits `Resolve()` before `LoadLocal` is ever called, per `resolve.go:64`) authenticates successfully and reaches the API.

## Suggested fix

Bound the walk-up in `LoadLocal` to stop before reaching `$HOME` (exclusive), e.g.:

```go
home, _ := os.UserHomeDir()
for {
if dir == home {
return nil, ErrNoLocalConfig
}
path := filepath.Join(dir, LocalConfigPath)
...
}
```

This preserves the intended precedence (repo-local `.revcat/config.json` found via walk-up, falling back to the global file) while preventing the walk-up from ever colliding with the global file's own path.

## Environment

- revcat 0.7.0 darwin/arm64 go1.26.2 (commit 7c8411d)
- macOS (Darwin 25.5.0)

Hướng dẫn đóng góp

Chưa lập chỉ mục được hướng dẫn đóng góp cho kho mã nguồn này

Đánh giá

Issue này chưa được đánh giá.

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.