fix(host-core): make clawctl create truly idempotent#39
Merged
Conversation
`clawctl create --config <path>` against an existing instance was not truly idempotent: `bootstrapOpenclaw` re-ran `openclaw onboard`, rotated the gateway auth token on every invocation, and re-sent the bootstrap prompt. `patchAuthProfiles` also no-op'd when the configured provider differed from what was already on disk, leaving the prior provider's profile bound. Plan two narrow fixes in the existing path — gate first-run-only steps on the `data/config` sentinel and generalise `patchAuthProfiles` to converge on the configured provider — rather than adding a parallel reconfigure command. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extract the pure transformation as `applyAuthProfileSwap`. On first run it still migrates plaintext `token` → `tokenRef`. When the configured provider differs from what's already on disk it now evicts the prior provider's `:default` profile, adds the new one, resets `lastGood`, and drops orphaned `usageStats` entries. Previously the function looked up `<currentProviderType>:default` and patched it in place — when the provider type had changed relative to the existing file it would log "Profile not found — skipping" and leave the dead profile active. Conservative: only evicts `:default` profiles whose `provider` field is set and differs from the new provider. Unknown/legacy profile shapes are preserved. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`clawctl create` re-runs `bootstrapOpenclaw` on an existing instance
(provisionVM detects the VM exists and skips Lima creation but still
calls bootstrap). That meant:
- `openclaw onboard` ran every time — onboard issues the gateway auth
token and configures the daemon, so re-running it would rotate
credentials that may be wired into remote tooling.
- The gateway token was regenerated each run via `randomBytes(24)` and
pushed through `openclaw config set gateway.auth.token`, rotating it
on every reapply.
- The bootstrap prompt re-sent on every reapply.
Use `${PROJECT_MOUNT_POINT}/data/config` (the file onboard creates) as
the "already onboarded" sentinel. On reapply, skip onboard, read the
existing `gateway.auth.token` from data/config, and skip the bootstrap
prompt. Continue with all the apply-state steps (`openclaw config set`,
`models set`, channels, secret migration, daemon restart, doctor,
bootstrap-phase capability hooks) so a clawctl.json edit converges
state. Together with the patchAuthProfiles provider-switch fix this
makes `clawctl create` idempotent in the strong sense.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
dfe1729 to
6ed53cf
Compare
Direct editing of auth-profiles.json is the standing exception to bootstrap.ts's "delegate to openclaw" pattern. Document the rationale on the function itself, with links to the upstream issues that, once resolved, would let us replace the surgery with two delegate calls (openclaw/openclaw#16134, openclaw/openclaw#10244). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
bootstrapOpenclawon the existingdata/configsentinel, so re-runningclawctl create --config <path>against an existing instance no longer re-runsopenclaw onboard, rotates the gateway auth token, or re-sends the bootstrap prompt.patchAuthProfiles(now a thin IO wrapper around the new pureapplyAuthProfileSwap) to handle a provider change between runs: the prior:defaultprofile is evicted, the new one bound,lastGoodreset, and orphanedusageStatsdropped.Together these make
clawctl createidempotent in the strong sense the project conventions promise: first run bootstraps, subsequent runs apply the diff inclawctl.json. No new commands; no parallel reconfigure path.Motivation
The intended workflow when changing an instance's config is to edit
clawctl.jsonand re-runclawctl create. In practice the path was almost right — capabilities are idempotent andprovisionVMskips Lima VM creation if the VM exists — butbootstrapOpenclawconflated first-run-only steps with apply-state steps:openclaw onboardran unconditionally each invocation.randomBytes(24)every run and pushed throughopenclaw config set gateway.auth.token, rotating a token that may be wired into remote tooling.patchAuthProfileslooked up<currentProvider>:defaultand patched it in place — when the provider type had changed it logged "Profile not found — skipping" and the prior provider's profile stayed bound.Test plan
applyAuthProfileSwap: first-run plaintext→tokenRef migration, same-provider no-op re-apply, provider switch (removes old, adds new, resetslastGood, filtersusageStats), conservative handling of unknown/non-:defaultprofiles, no input mutation.bun test(266 pass, 0 fail),bun run lint,bun run format:checkclean.clawctl createagainst aclawctl.jsonwith a different provider, assertgateway.auth.tokenbyte-for-byte preserved against adata/config.bak.*snapshot, prior auth profile cleanly evicted,openclaw doctorgreen.🤖 Generated with Claude Code