* fix: persist gh auth credentials to disk for interactive sessions
When GITHUB_TOKEN is in the environment, gh auth status returns success
(gh checks env vars first), so ensure_gh_auth() short-circuits before
gh auth login --with-token writes credentials to ~/.config/gh/hosts.yml.
The interactive session starts without GITHUB_TOKEN in env, so gh reports
"not logged into any GitHub hosts".
Fix: always run gh auth login --with-token when GITHUB_TOKEN is set,
persisting credentials to disk regardless of gh auth status.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: unset GITHUB_TOKEN env var before gh auth login --with-token
gh refuses to store credentials when GITHUB_TOKEN is already set in
the environment: "The value of the GITHUB_TOKEN environment variable
is being used for authentication." Save the value, unset the env var,
pipe it to gh auth login, then re-export.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address security review — validate token format, skip if already persisted
- Add GITHUB_TOKEN format validation (ghp_, gho_, ghu_, ghs_, ghr_, github_pat_)
- Add fast path: check gh auth status with env var unset before persisting
- Document plaintext credential store behavior (standard gh CLI behavior)
Agent: pr-maintainer
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: B <6723574+louisgv@users.noreply.github.com>
* docs: add spawn delete command to README
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden openclaw across all clouds — validation, reliability, performance
Fixes multiple issues causing openclaw to break on most clouds:
Bugs fixed:
- Double-prefixed model ID (openrouter/openrouter/auto) in config generation
- AWS gateway starting without env vars (missing .zshrc source)
- DigitalOcean sourcing .spawnrc instead of .zshrc for gateway
- Destructive rm -rf ~/.openclaw on re-runs (now mkdir -p)
Validation added:
- API key checked against OpenRouter /auth/key endpoint with re-prompt on failure
- Model ID verified against OpenRouter model list with re-prompt loop
- openrouter/auto and openrouter/free bypass model check
Reliability improvements:
- Standardized gateway launch with </dev/null & disown across all 9 clouds
- Gateway log auto-displayed on startup timeout for diagnostics
- 2GB swap added to cloud-init to prevent OOM on small VMs
- Portable install timeout (10 min) with macOS gtimeout fallback
Performance:
- Reordered spawn_agent: OAuth runs while VM provisions (saves 30-60s)
- Fly.io: bumped to 2GB RAM + 2 shared CPUs for openclaw
- Fly.io: tries bun first (faster), falls back to npm
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: skip sudo in gh install when running as root (Fly.io containers)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: address PR review — skip validation in tests, quote escaped cmd, escape model_id
- verify_openrouter_key and verify_openrouter_model skip network calls when
SPAWN_SKIP_API_VALIDATION, BUN_ENV=test, or NODE_ENV=test is set
- install_agent timeout wrapper now quotes the escaped command for defense in depth
- model_id in openclaw JSON now uses json_escape() for consistency
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove double-escaping in install_agent that broke shell operators
install_agent() was wrapping commands with printf '%q' + bash -c before
passing them to the run callback. But run callbacks (run_server, run_sprite,
ssh_run_server) already handle escaping for remote transport. The double-
escaping turned && || > | into literal characters, causing 'source' to
treat the entire command as a single filename.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Fixes GitHub CLI authentication on remote VMs by passing local token through to remote installation script. Uses printf '%q' for safe shell escaping to prevent command injection.
Extract platform-specific install logic from monolithic installer functions
into small, focused helpers. Both functions had nested OS/package-manager
cascades (depth 3-4) that made the control flow hard to follow.
ensure_jq (shared/common.sh):
- Extract _install_jq_brew, _install_jq_apt, _install_jq_dnf, _install_jq_apk
- Extract _report_jq_not_found for the fallthrough error message
- Main function becomes a clean dispatcher + verification
ensure_gh_cli + _install_gh_binary (shared/github-auth.sh):
- Extract _install_gh_brew, _install_gh_apt, _install_gh_dnf
- Extract _detect_gh_platform, _fetch_gh_latest_version, _download_and_install_gh
- _install_gh_binary drops from 71 to 12 lines as a clean orchestrator
- ensure_gh_cli drops from 57 to 29 lines
No behavior changes. All tests pass, bash -n passes.
Agent: complexity-hunter
Co-authored-by: A <6723574+louisgv@users.noreply.github.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Standalone, sourceable script that installs the gh CLI and runs
interactive gh auth login. Any agent script on any cloud can source
it and call ensure_github_auth to get authenticated with GitHub.
- ensure_gh_cli: installs via brew/apt/dnf/binary fallback
- ensure_gh_auth: uses GITHUB_TOKEN or interactive OAuth flow
- ensure_github_auth: combined convenience wrapper
- Idempotent, macOS bash 3.x compatible, curl|bash compatible
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>