hashgraph / hashgraph/solo-weaver

fix(migration): a non-semver `provisioner.version` in state.yaml aborts every CLI invocation

Open
#1,058 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
Go
Stars
3
Forks
0
Avg merge
3d 5h
Merged PRs (30d)
47

Description

## Problem

A `provisioner.version` of `"dev"` in `state.yaml` makes **every** subsequent CLI
invocation abort in the startup-migration pass, before the command runs:

```
x Error: failed to execute command
Cause: common.illegal_state: failed to check if migration
"cilium-disable-xdp-acceleration-v0.19.1" applies,
cause: common.illegal_state: invalid installed CLI version "dev",
cause: common.illegal_format: failed to parse major part "dev",
cause: strconv.ParseUint: parsing "dev": invalid syntax

Resolution:
1. Check error message for details or contact support
```

Both `install` and `daemon service install` are blocked, so the host cannot be
re-provisioned by the normal path and there is no operator-actionable hint.

## Mechanism

`RunStartupMigrations` (`cmd/cli/commands/common/run.go:333-347`) reads
`provisioner.version` from `state.yaml` and passes it through
`migration.ResolveInstalledCLIVersion`, which special-cases **only** the empty string:

```go
func ResolveInstalledCLIVersion(raw string) string {
if raw == "" {
return BaselineCLIVersion
}
return raw
}
```

`CLIVersionMigration.Applies` then calls `semver.NewSemver(installedCLIVersion)` and
returns `errorx.IllegalState` on a parse failure
(`internal/migration/cli_version_migration.go:73-75`), which aborts the whole
invocation.

`"dev"` is not an unexpected value: it is what `github.com/automa-saga/version`
reports for a binary built without `-ldflags`, and the repo already names it —
`devVersionPlaceholder = "dev"` in `cmd/cli/commands/block/node/daemon_offer.go:171`.
So one part of the codebase knows the placeholder exists and the migration path does
not. Any `go run` / `go build` / test-harness binary that reaches
`PersistProvisionerVersion` writes it and leaves the host wedged.

## Reproduction

Observed on the Debian UTM VM after `task vm:test:unit`, which runs as root and wipes
`/opt/solo/weaver`. Directly:

```bash
sudo yq -i '.state.provisioner.version = "dev"' /opt/solo/weaver/state/state.yaml
sudo solo-provisioner version # aborts as above
```

## Proposed fix

Treat an unparseable installed version the same as absent — both mean "no trustworthy
previous version", and the baseline already exists for exactly that case:

* `ResolveInstalledCLIVersion` returns `BaselineCLIVersion` when `raw` is empty **or**
not valid semver, so pending migrations still run rather than the host being bricked.
* Log the discarded value once at warn level so it is visible.
* If a hard failure is preferred over the baseline, it still must not be a bare
`IllegalState`: attach a reason code and a hint naming the file and field to correct
(`/opt/solo/weaver/state/state.yaml`, `state.provisioner.version`).

Worth checking whether the write side should refuse to persist a placeholder at all,
which would stop the state from being poisoned in the first place.

## Acceptance

- [ ] A `state.yaml` carrying `provisioner.version: dev` no longer aborts CLI startup.
- [ ] Startup migrations still run against the baseline in that case, rather than being
skipped as a fresh install.
- [ ] Unit coverage for `ResolveInstalledCLIVersion` with `""`, `"dev"`, a valid semver,
and an arbitrary non-semver string.
- [ ] A host in this state can be recovered with documented commands, or needs no
recovery at all.

Contributor guide

Open the contributing guide

Research direction

Start at RunStartupMigrations in cmd/cli/commands/common/run.go and follow ResolveInstalledCLIVersion into internal/migration/cli_version_migration.go. Check the existing devVersionPlaceholder in cmd/cli/commands/block/node/daemon_offer.go and add unit coverage for empty, dev, valid semver, and arbitrary non-semver values. Done means startup accepts dev state, runs migrations from the baseline, and logs or documents the recovery behavior.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
cli
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
76/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.