[macOS][Upgrade] legacy credentials.json is kept after being used, but deleted when unused
- Dominant language
- TypeScript
- Stars
- 22.5k
- Forks
- 3.1k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 715
Description
## Description
NemoClaw's documented legacy-credential migration (moving a plaintext `~/.nemoclaw/credentials.json` from an earlier release into the OpenShell gateway store) does not behave as documented, in both directions: a credential that was actually consumed and worked is not migrated/deleted, and a file whose contents were never consumed at all gets deleted anyway.
Documented behavior (product docs, Credential Storage / Migration From Earlier Releases): on the first `nemoclaw onboard` after upgrading, NemoClaw reads the legacy file, re-registers each value with the OpenShell gateway, and "securely overwrites and deletes `~/.nemoclaw/credentials.json` only after every staged value has been verified as migrated to the gateway." Separately, the docs state that other credential-lookup paths such as rebuild "do not delete the plaintext file because they cannot prove every legacy value was registered with the gateway."
**Part A (under-deletion):** planting a legacy `credentials.json` with a real, working key and running onboard: onboard succeeds and inference ends up healthy (proving the key was read and used), but the output reports the credential as "not migrated verbatim" and the legacy file is never deleted — contradicting the documented "delete after verified migration" behavior for the onboard path specifically.
**Part B (over-deletion):** planting a legacy `credentials.json` containing only an unrelated, unrecognized key (nothing NemoClaw understands or migrates) and running a sandbox rebuild: the rebuild silently deletes the file anyway — directly contradicting the documented statement that rebuild-class paths never delete the plaintext file.
**Platform scope:** Reproduced on 1 macOS machine; not yet tested on a second platform.
**Regression:** Unknown — first time this specific migration path has been tested by us. A different, coarser-grained symptom on this general area (no migration/cleanup logic existed at all) was previously fixed on macOS under #3105 for a much older release range (pre-v0.0.30); the migration logic that #3105 asked for does now exist, so this report covers two newer, more specific defects within that now-existing logic rather than its absence.
**OpenShell issue:** No — this is NemoClaw-level onboard/credential-migration logic, not OpenShell CLI behavior.
## Environment
```text
Device: MacBook Pro (Apple Silicon, arm64)
OS: macOS (Darwin, arm64)
Architecture: arm64
Node.js: v23.10.0
npm: 11.3.0
Docker: Docker (via Colima), 27.x
OpenShell CLI: 0.0.85
NemoClaw: v0.0.90
OpenClaw: 2026.6.10
```
## Steps to Reproduce
**Part A:**
1. Plant a legacy credentials file with a real, working key:
```bash
echo '{"NVIDIA_API_KEY":"{a real working key}"}' > ~/.nemoclaw/credentials.json
chmod 600 ~/.nemoclaw/credentials.json
```
2. Unset the corresponding env vars so onboard must read the file:
```bash
unset NVIDIA_API_KEY NVIDIA_INFERENCE_API_KEY
```
3. Run a non-interactive onboard:
```bash
NEMOCLAW_NON_INTERACTIVE=1 NEMOCLAW_PROVIDER=build NEMOCLAW_SANDBOX_NAME=cred-mig nemoclaw onboard
```
4. Check whether the file was deleted and whether the credential shows as migrated:
```bash
ls ~/.nemoclaw/credentials.json
nemoclaw credentials list
```
**Part B:**
1. Plant a legacy credentials file with an unrelated key nothing consumes:
```bash
echo '{"FAKE_PROVIDER_TOKEN":"x"}' > ~/.nemoclaw/credentials.json
chmod 600 ~/.nemoclaw/credentials.json
```
2. Rebuild the same sandbox:
```bash
nemoclaw cred-mig rebuild
```
3. Check whether the file survived:
```bash
ls -la ~/.nemoclaw/credentials.json
```
## Expected Result
Part A: after a successful onboard that used the legacy credential, the credential is registered with the gateway and `~/.nemoclaw/credentials.json` is securely deleted, per the documented "delete only after every staged value has been verified as migrated to the gateway" behavior.
Part B: rebuild never deletes the legacy file, per the documented statement that rebuild-class credential-lookup paths cannot prove migration and so do not delete it — the file should be left untouched regardless of its contents.
## Actual Result
Part A: onboard succeeds (inference healthy, sandbox Ready), but reports "Kept ~/.nemoclaw/credentials.json: 1 legacy credential(s) were not migrated verbatim ... (NVIDIA_API_KEY)" and the file remains on disk afterward, still containing the credential in plaintext.
Part B: rebuild reports "Removed stale ~/.nemoclaw/credentials.json (no migratable credentials)" and the file is gone afterward — deleted despite containing content that was never read or migrated by anything.
## Logs
```text
Part A onboard output:
Kept ~/.nemoclaw/credentials.json: 1 legacy credential(s) were not
migrated verbatim ... (NVIDIA_API_KEY). Deployment verified, OpenClaw
version: 2026.6.10
Part A post-check: ls ~/.nemoclaw/credentials.json shows the file still present
Part B rebuild output:
Removed stale ~/.nemoclaw/credentials.json (no migratable credentials).
Sandbox 'cred-mig' rebuilt successfully
Part B post-check: ls -la ~/.nemoclaw/credentials.json reports No such file or
directory
```
Contributor guide
Assessment
This issue has not been assessed yet.